diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:08:59 +0200 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:12:21 +0200 |
commit | 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a (patch) | |
tree | ab49cc16ed0b853452c5c2ed2d3042416d628986 /thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap | |
download | iot-sensors-master.tar.gz iot-sensors-master.tar.bz2 iot-sensors-master.tar.xz iot-sensors-master.zip |
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap')
22 files changed, 7240 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c new file mode 100644 index 0000000..4d58384 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c @@ -0,0 +1,854 @@ +/** + * Copyright (c) 2014 - 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 <stdbool.h> +#include <string.h> +#include "nordic_common.h" +#include "nrf.h" +#include "coap_api.h" +#include "coap.h" +#include "coap_queue.h" +#include "coap_transport.h" +#include "sdk_common.h" +#include "iot_common.h" +#include "mem_manager.h" +#include "coap_resource.h" +#include "coap_observe_api.h" +#include "coap_observe.h" + +#if IOT_COAP_CONFIG_LOG_ENABLED + +#define NRF_LOG_MODULE_NAME coap + +#define NRF_LOG_LEVEL IOT_COAP_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR IOT_COAP_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR IOT_COAP_CONFIG_DEBUG_COLOR + +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define COAP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */ +#define COAP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */ +#define COAP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */ + +#define COAP_ENTRY() COAP_TRC(">> %s", __func__) +#define COAP_EXIT() COAP_TRC("<< %s", __func__) +#define COAP_EXIT_WITH_RESULT(result) COAP_TRC("<< %s, result: %d", __func__, result) + +#else // IOT_COAP_CONFIG_LOG_ENABLED + +#define COAP_TRC(...) /**< Disables traces. */ +#define COAP_DUMP(...) /**< Disables dumping of octet streams. */ +#define COAP_ERR(...) /**< Disables error logs. */ + +#define COAP_ENTRY(...) +#define COAP_EXIT(...) +#define COAP_EXIT_WITH_RESULT(...) + +#endif // IOT_COAP_CONFIG_LOG_ENABLED + +#define COAP_REQUEST_ENTITY_MAX_SIZE (BLE_IPSP_RX_BUFFER_SIZE - (IPV6_IP_HEADER_SIZE + \ + UDP_HEADER_SIZE)) /** Maximum request entity size. */ + +SDK_MUTEX_DEFINE(m_coap_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */ + +static uint32_t m_token_seed; /**< Token seed provided by application to be used for generating token numbers. */ +static uint32_t m_message_id_counter; /**< Message ID counter, used to generate unique message IDs. */ +static coap_error_callback_t m_error_callback; /**< Function pointer to an application CoAP error handler. */ + +static coap_request_handler_t m_request_handler = NULL; /**< Request handler where to forward all incoming requests. */ + +#define COAP_MESSAGE_ACK_SET(REMOTE, LOCAL_PORT, MID) { \ + memcpy(&m_coap_empty_message.remote, (REMOTE), sizeof(coap_remote_t)); \ + m_coap_empty_message.port.port_number = (LOCAL_PORT); \ + m_coap_empty_message.header.id = (MID); \ + m_coap_empty_message.header.type = COAP_TYPE_ACK; \ +} + +#define COAP_MESSAGE_RST_SET(REMOTE, LOCAL_PORT, MID) { \ + memcpy(&m_coap_empty_message.remote, (REMOTE), sizeof(coap_remote_t)); \ + m_coap_empty_message.port.port_number = (LOCAL_PORT); \ + m_coap_empty_message.header.id = (MID); \ + m_coap_empty_message.header.type = COAP_TYPE_RST; \ +} + +static coap_message_t m_coap_empty_message = { + .header = { + .version = 1, + .type = COAP_TYPE_ACK, + .token_len = 0, + .code = COAP_CODE_EMPTY_MESSAGE, + .id = 0, + }, + .p_payload = NULL, + .payload_len = 0, + .options_count = 0, + .p_arg = NULL, + .response_callback = NULL, + .port = { + .port_number = 0 + }, + .options_len = 0, + .options_offset = 0, + .p_data = NULL, + .data_len = 0 +}; + +static inline bool is_ping(coap_message_t * p_message) +{ + return (p_message->header.code == COAP_CODE_EMPTY_MESSAGE) && + (p_message->header.type == COAP_TYPE_CON); +} + +static inline bool is_ack(coap_message_t * p_message) +{ + return (p_message->header.code == COAP_CODE_EMPTY_MESSAGE) && + (p_message->header.type == COAP_TYPE_ACK); +} + +static inline bool is_reset(coap_message_t * p_message) +{ + return (p_message->header.type == COAP_TYPE_RST); +} + +static inline bool is_con(coap_message_t * p_message) +{ + return (p_message->header.type == COAP_TYPE_CON); +} + +static inline bool is_non(coap_message_t * p_message) +{ + return (p_message->header.type == COAP_TYPE_NON); +} + +static inline bool is_request(uint8_t message_code) +{ + return (message_code >= 1) && (message_code < 32); +} + +static inline bool is_response(uint8_t message_code) +{ + return (message_code >= 64) && (message_code < 192); +} + +static inline void app_error_notify(uint32_t err_code, coap_message_t * p_message) +{ + if (m_error_callback != NULL) + { + COAP_MUTEX_UNLOCK(); + + m_error_callback(err_code, p_message); + + COAP_MUTEX_LOCK(); + } +} + +uint32_t coap_init(uint32_t token_rand_seed, coap_transport_init_t * p_transport_param) +{ + COAP_ENTRY(); + + uint32_t err_code; + + SDK_MUTEX_INIT(m_coap_mutex); + + COAP_MUTEX_LOCK(); + + internal_coap_observe_init(); + + m_error_callback = NULL; + + m_token_seed = token_rand_seed; + (void)m_token_seed; + + m_message_id_counter = 1; + + err_code = coap_transport_init(p_transport_param); + if (err_code != NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + return err_code; + } + + err_code = coap_queue_init(); + if (err_code != NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + return err_code; + } + + err_code = coap_resource_init(); + + COAP_MUTEX_UNLOCK(); + + COAP_EXIT(); + + return err_code; + +} + +uint32_t coap_error_handler_register(coap_error_callback_t error_callback) +{ + // TODO: error handling, null pointer, module initilized etc. + COAP_MUTEX_LOCK(); + + m_error_callback = error_callback; + + COAP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + +uint32_t internal_coap_message_send(uint32_t * p_handle, coap_message_t * p_message) +{ + if (p_message == NULL) + { + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); + } + + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_send_handle(p_message); + + COAP_ENTRY(); + + // Fetch the expected length of the packet serialized by passing length of 0. + uint16_t expected_length = 0; + uint32_t err_code = coap_message_encode(p_message, NULL, &expected_length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Allocate a buffer to serialize the message into. + uint8_t * p_buffer; + uint32_t request_length = expected_length; + err_code = nrf_mem_reserve(&p_buffer, &request_length); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("p_buffer alloc error = 0x%08lX!", err_code); + return err_code; + } + memset(p_buffer, 0, request_length); + COAP_TRC("Alloc mem, p_buffer = %p", (uint8_t *)p_buffer); + + // Serialize the message. + uint16_t buffer_length = (uint16_t)request_length; + err_code = coap_message_encode(p_message, p_buffer, &buffer_length); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("Encode error!"); + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + + return err_code; + } + + err_code = coap_transport_write(&p_message->port, &p_message->remote, p_buffer, buffer_length); + + if (err_code == NRF_SUCCESS) + { + if (is_con(p_message) || (is_non(p_message) && + is_request(p_message->header.code) && + (p_message->response_callback != NULL))) + { + coap_queue_item_t item; + item.p_arg = p_message->p_arg; + item.mid = p_message->header.id; + item.callback = p_message->response_callback; + item.p_buffer = p_buffer; + item.buffer_len = buffer_length; + item.timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR; + + if (p_message->header.type == COAP_TYPE_CON) + { + item.timeout = item.timeout_val; + item.retrans_count = 0; + } + else + { + item.timeout = COAP_MAX_TRANSMISSION_SPAN; + item.retrans_count = COAP_MAX_RETRANSMIT_COUNT; + } + + item.port = p_message->port; + item.token_len = p_message->header.token_len; + + memcpy(&item.remote, &p_message->remote, sizeof(coap_remote_t)); + memcpy(item.token, p_message->token, p_message->header.token_len); + + err_code = coap_queue_add(&item); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("Message queue error = 0x%08lX!", err_code); + + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + + return err_code; + } + + *p_handle = item.handle; + } + else + { + *p_handle = COAP_MESSAGE_QUEUE_SIZE; + + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + } + } + else + { + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + } + + COAP_EXIT(); + + return err_code; +} + + +static uint32_t create_response(coap_message_t ** pp_response, coap_message_t * p_request, uint16_t data_size) +{ + uint32_t err_code; + + // Allocate space for a new message. + uint32_t size = sizeof(coap_message_t); + err_code = nrf_mem_reserve((uint8_t **)pp_response, &size); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + coap_message_t * p_response = (*pp_response); + + memset(p_response, 0, sizeof(coap_message_t)); + COAP_TRC("Alloc mem, p_response = %p", (uint8_t *)p_response); + + if (data_size > 0) + { + // Allocate a scratch buffer for payload and options. + size = data_size; + err_code = nrf_mem_reserve(&(p_response->p_data), &size); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + memset(p_response->p_data, 0, size); + p_response->data_len = size; + COAP_TRC("Alloc mem, p_response->p_data = %p", p_response->p_data); + } + + coap_message_conf_t config; + memset (&config, 0, sizeof(coap_message_conf_t)); + + config.token_len = p_request->header.token_len; + config.id = p_request->header.id; + config.code = COAP_CODE_404_NOT_FOUND; + config.port.port_number = p_request->port.port_number; + + memcpy(config.token, p_request->token, p_request->header.token_len); + + if ((coap_msg_type_t)p_request->header.type == COAP_TYPE_CON) + { + config.type = COAP_TYPE_ACK; + } + else + { + config.type = (coap_msg_type_t)p_request->header.type; + } + + err_code = coap_message_create(p_response, &config); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + (void)coap_message_remote_addr_set(p_response, &p_request->remote); + + return NRF_SUCCESS; +} + + +/**@brief Common function for sending response error message + * + * @param[in] p_message Pointer to the original request message. + * @param[in] code CoAP message code to send in the reponse. + * + * @retval NRF_SUCCESS If the response was sent out successfully. + */ +static uint32_t send_error_response(coap_message_t * p_message, uint8_t code) +{ + coap_message_t * p_error_response = NULL; + + uint32_t err_code = create_response(&p_error_response, p_message, COAP_MESSAGE_DATA_MAX_SIZE); + if (err_code != NRF_SUCCESS) + { + // If message could not be created, notify the application. + app_error_notify(err_code, p_message); + return err_code; + } + + // Set the response code. + p_error_response->header.code = code; + + if (p_error_response != NULL) + { + uint32_t handle; + err_code = internal_coap_message_send(&handle, p_error_response); + + COAP_TRC("Free mem, p_response->p_data = %p", p_error_response->p_data); + UNUSED_VARIABLE(nrf_free(p_error_response->p_data)); + + COAP_TRC("Free mem, p_response = %p", (uint8_t *)p_error_response); + UNUSED_VARIABLE(nrf_free((uint8_t *)p_error_response)); + } + + return err_code; +} + +uint32_t coap_transport_read(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const coap_remote_t * p_local, + uint32_t result, + const uint8_t * p_data, + uint16_t datalen) +{ + COAP_ENTRY(); + + // Discard all packets if not success or truncated. + if (!(result == NRF_SUCCESS || result == UDP_TRUNCATED_PACKET)) + { + return NRF_SUCCESS; + } + + uint32_t err_code; + coap_message_t * p_message; + + // Allocate space for a new message. + uint32_t size = sizeof(coap_message_t); + err_code = nrf_mem_reserve((uint8_t **)&p_message, &size); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + memset(p_message, 0, sizeof(coap_message_t)); + COAP_TRC("Alloc mem, p_message = %p", (uint8_t *)p_message); + + err_code = coap_message_decode(p_message, p_data, datalen); + if (err_code != NRF_SUCCESS) + { + app_error_notify(err_code, p_message); + + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + return err_code; + } + + // Copy the remote address information. + memcpy(&p_message->remote, p_remote, sizeof(coap_remote_t)); + + // Copy the destination address information. + if (p_local) + { + memcpy(&p_message->local, p_local, sizeof(coap_remote_t)); + } + + // Copy the local port information. + memcpy(&p_message->port, p_port, sizeof(coap_port_t)); + + if (result == UDP_TRUNCATED_PACKET) + { + app_error_notify(result, p_message); + } + else if (is_ping(p_message)) + { + COAP_MESSAGE_RST_SET(&p_message->remote, p_message->port.port_number, p_message->header.id); + + uint32_t handle; + err_code = internal_coap_message_send(&handle, &m_coap_empty_message); + } + else if (is_ack(p_message) || + is_reset(p_message)) + { + // Populate the token with the one used sending, before passing it to the application. + coap_queue_item_t * p_item = NULL; + err_code = coap_queue_item_by_mid_get(&p_item, p_message->header.id); + + if (err_code == NRF_SUCCESS) + { + if (p_item->callback != NULL) + { + // As the token is missing from peer, it will be added before giving it to the application. + memcpy(p_message->token, p_item->token, p_item->token_len); + p_message->header.token_len = p_item->token_len; + + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_response_handle(p_message, p_item); + + COAP_TRC(">> application callback"); + + COAP_MUTEX_UNLOCK(); + + if (is_ack(p_message)) + { + p_item->callback(NRF_SUCCESS, p_item->p_arg, p_message); + } + else + { + p_item->callback(COAP_TRANSMISSION_RESET_BY_PEER, p_item->p_arg, p_message); + } + + COAP_MUTEX_LOCK(); + + COAP_TRC("<< application callback"); + } + + COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer); + UNUSED_VARIABLE(nrf_free(p_item->p_buffer)); + + // Remove the queue element, as a match occured. + err_code = coap_queue_remove(p_item); + } + } + else if (is_response(p_message->header.code)) + { + COAP_TRC("CoAP message type: RESPONSE"); + + coap_queue_item_t * p_item; + err_code = coap_queue_item_by_token_get(&p_item, p_message->token, p_message->header.token_len); + if (err_code != NRF_SUCCESS) + { + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_response_handle(p_message, NULL); + + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + + COAP_MUTEX_UNLOCK(); + + return err_code; + } + + if (p_item->callback != NULL) + { + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_response_handle(p_message, p_item); + + COAP_TRC(">> application callback"); + + COAP_MUTEX_UNLOCK(); + + p_item->callback(NRF_SUCCESS, p_item->p_arg, p_message); + + COAP_MUTEX_LOCK(); + + COAP_TRC("<< application callback"); + } + + COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer); + UNUSED_VARIABLE(nrf_free(p_item->p_buffer)); + + err_code = coap_queue_remove(p_item); + + } + else if (is_request(p_message->header.code)) + { + COAP_TRC("CoAP message type: REQUEST"); + + if (m_request_handler != NULL) + { + uint32_t return_code = m_request_handler(p_message); + + // If success, then all processing and any responses has been sent + // by the application callback. + + // If not success, then send an appropriate error message back to the + // origin with the return_code from the callback. + if (return_code != NRF_SUCCESS) + { + if (return_code == NRF_ERROR_NOT_FOUND) + { + // Send response with provided CoAP code. + (void)send_error_response(p_message, COAP_CODE_404_NOT_FOUND); + } + else if (return_code == NRF_ERROR_NULL) + { + (void)send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED); + } + else + { + (void)send_error_response(p_message, COAP_CODE_400_BAD_REQUEST); + } + } + } + else + { + uint8_t * uri_pointers[COAP_RESOURCE_MAX_DEPTH] = {0, }; + + uint8_t uri_path_count = 0; + uint16_t index; + + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_URI_PATH) + { + uri_pointers[uri_path_count++] = p_message->options[index].p_data; + } + } + + coap_resource_t * found_resource; + err_code = coap_resource_get(&found_resource, uri_pointers, uri_path_count); + + if (found_resource != NULL) + { + if (found_resource->callback != NULL) + { + if (((found_resource->permission) & (1 << ((p_message->header.code) - 1))) > 0) // Has permission for the requested CoAP method. + { + COAP_MUTEX_UNLOCK(); + + found_resource->callback(found_resource, p_message); + + COAP_MUTEX_LOCK(); + } + else + { + // Reply with Method Not Allowed. + err_code = send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED); + } + } + else + { + // Reply with Method Not Allowed. + err_code = send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED); + } + } + else + { + // Reply with NOT FOUND. + err_code = send_error_response(p_message, COAP_CODE_404_NOT_FOUND); + } + } + } + + COAP_TRC("Free mem, p_message = %p", (uint8_t *)p_message); + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + + COAP_EXIT(); + return err_code; +} + +uint32_t coap_message_send(uint32_t * p_handle, coap_message_t * p_message) +{ + COAP_MUTEX_LOCK(); + + uint32_t err_code = internal_coap_message_send(p_handle, p_message); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_message_abort(uint32_t handle) +{ + + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t coap_message_new(coap_message_t ** p_request, coap_message_conf_t * p_config) +{ + COAP_ENTRY(); + + uint32_t err_code; + + // If port is not configured, return error and skip initialization of the message. + if (p_config->port.port_number == 0) + { + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + + COAP_MUTEX_LOCK(); + + // Allocate space for a new message. + uint32_t size = sizeof(coap_message_t); + err_code = nrf_mem_reserve((uint8_t **)p_request, &size); + if (err_code != NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + return err_code; + } + + memset(*p_request, 0, sizeof(coap_message_t)); + COAP_TRC("Alloc mem, *p_request = %p", (uint8_t *)(*p_request)); + + // Allocate a scratch buffer for payload and options. + size = COAP_MESSAGE_DATA_MAX_SIZE; + err_code = nrf_mem_reserve(&((*p_request)->p_data), &size); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("Allocation of message data buffer failed!"); + + COAP_TRC("Free mem, *p_request = %p", (uint8_t *)(*p_request)); + UNUSED_VARIABLE(nrf_free((uint8_t *)(*p_request))); + + COAP_MUTEX_UNLOCK(); + return err_code; + } + + memset((*p_request)->p_data, 0, size); + (*p_request)->data_len = size; + + COAP_TRC("Alloc mem, (*p_request)->p_data = %p", (uint8_t *)((*p_request)->p_data)); + + if (p_config->id == 0) // Message id is not set, generate one. + { + p_config->id = m_message_id_counter++; + } + + err_code = coap_message_create(*p_request, p_config); + + COAP_MUTEX_UNLOCK(); + + COAP_EXIT_WITH_RESULT(err_code); + + return err_code; +} + +uint32_t coap_message_delete(coap_message_t * p_message) +{ + COAP_ENTRY(); + + COAP_MUTEX_LOCK(); + + //If this is a request free the coap_message_t and the data buffer. + + COAP_TRC("Free mem, p_message->p_data = %p", p_message->p_data); + UNUSED_VARIABLE(nrf_free(p_message->p_data)); + + COAP_TRC("Free mem, p_message = %p", (uint8_t *)p_message); + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + + + COAP_MUTEX_UNLOCK(); + + COAP_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t coap_time_tick(void) +{ + COAP_MUTEX_LOCK(); + + coap_transport_process(); + + // Loop through the message queue to see if any packets needs retransmission, or has timed out. + coap_queue_item_t * p_item = NULL; + while (coap_queue_item_next_get(&p_item, p_item) == NRF_SUCCESS) + { + if (p_item->timeout == 0) + { + // If there is still retransmission attempts left. + if (p_item->retrans_count < COAP_MAX_RETRANSMIT_COUNT) + { + p_item->timeout = p_item->timeout_val * 2; + p_item->timeout_val = p_item->timeout; + p_item->retrans_count++; + + // Retransmit the message. + uint32_t err_code = coap_transport_write(&p_item->port, &p_item->remote, p_item->p_buffer, p_item->buffer_len); + if (err_code != NRF_SUCCESS) + { + app_error_notify(err_code, NULL); + } + } + + // No more retransmission attempts left, or max transmit span reached. + if ((p_item->timeout > COAP_MAX_TRANSMISSION_SPAN) || + (p_item->retrans_count >= COAP_MAX_RETRANSMIT_COUNT)) + { + + COAP_MUTEX_UNLOCK(); + + p_item->callback(COAP_TRANSMISSION_TIMEOUT, p_item->p_arg, NULL); + + COAP_MUTEX_LOCK(); + + COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer); + UNUSED_VARIABLE(nrf_free(p_item->p_buffer)); + + (void)coap_queue_remove(p_item); + } + } + else + { + p_item->timeout--; + } + } + + COAP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + +uint32_t coap_request_handler_register(coap_request_handler_t p_request_handler) +{ + COAP_MUTEX_LOCK(); + + m_request_handler = p_request_handler; + + COAP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + +__WEAK void coap_transport_input(void) +{ + // By default not implemented. Transport specific. +} + +void coap_input(void) +{ + COAP_MUTEX_LOCK(); + + coap_transport_input(); + + COAP_MUTEX_UNLOCK(); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h new file mode 100644 index 0000000..09d9ecb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap.h + * + * @defgroup iot_sdk_coap_api CoAP interface + * @ingroup iot_sdk_coap + * @{ + * @brief Interface for the CoAP protocol. + */ + +#ifndef COAP_H__ +#define COAP_H__ + +#include "iot_errors.h" +#include "coap_api.h" +#include "sdk_os.h" + +/** + * @defgroup iot_coap_log Module's Log Macros + * @details Macros used for creating module logs which can be useful in understanding handling + * of events or actions on API requests. These are intended for debugging purposes and + * can be enabled by defining the COAP_ENABLE_LOGS to 1. + * @note If NRF_LOG_ENABLED is disabled, having COAP_ENABLE_LOGS has no effect. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Verify NULL parameters are not passed to API by application. */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } + +/**@brief Verify that parameter members has been set by the application. */ +#define NULL_PARAM_MEMBER_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); \ + } +#else + +#define NULL_PARAM_CHECK(PARAM) +#define NULL_PARAM_MEMBER_CHECK(PARAM) + +#endif // COAP_DISABLE_API_PARAM_CHECK + +/** + * @defgroup iot_coap_mutex_lock_unlock Module's Mutex Lock/Unlock Macros. + * + * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but + * framework is provided in case the need to use an alternative architecture arises. + * @{ + */ +#define COAP_MUTEX_LOCK() SDK_MUTEX_LOCK(m_coap_mutex) /**< Lock module using mutex */ +#define COAP_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_coap_mutex) /**< Unlock module using mutex */ + +SDK_MUTEX_DEFINE(m_coap_mutex) + +/** @} */ + +/**@brief Sends a CoAP message. + * + * @details Sends out a request using the underlying transport layer. Before sending, the + * \ref coap_message_t structure is serialized and added to an internal message queue + * in the library. The handle returned can be used to abort the message from being + * retransmitted at any time. + * + * @param[out] p_handle Handle to the message if CoAP CON/ACK messages has been used. Returned + * by reference. + * @param[in] p_message Message to be sent. + * + * @retval NRF_SUCCESS If the message was successfully encoded and scheduled for transmission. + */ +uint32_t internal_coap_message_send(uint32_t * p_handle, coap_message_t * p_message); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h new file mode 100644 index 0000000..9bc0222 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h @@ -0,0 +1,663 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_api.h + * + * @defgroup iot_sdk_coap_api CoAP Application Programming Interface + * @ingroup iot_sdk_coap + * @{ + * @brief Public API of Nordic's CoAP implementation. + * + */ + +#ifndef COAP_API_H__ +#define COAP_API_H__ + +#include <stdint.h> +#include "coap_transport.h" +#include "coap_codes.h" +#include "sdk_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@defgroup COAP_CONTENT_TYPE_MASK Resource content type bitmask values + * @{ */ +#define COAP_CT_MASK_PLAIN_TEXT 0x01 /**< Content type Plain text supported in the endpoint resource. */ +#define COAP_CT_MASK_CHARSET_UTF8 0x02 /**< Content type Charset-UTF8 supported in the endpoint resource. */ +#define COAP_CT_MASK_APP_LINK_FORMAT 0x04 /**< Content type Application/link-format supported in the endpoint resource. */ +#define COAP_CT_MASK_APP_XML 0x08 /**< Content type Application/xml supported in the endpoint resource. */ +#define COAP_CT_MASK_APP_OCTET_STREAM 0x10 /**< Content type Application/octet-stream supported in the endpoint resource. */ +#define COAP_CT_MASK_APP_EXI 0x20 /**< Content type Application/exi supported in the endpoint resource. */ +#define COAP_CT_MASK_APP_JSON 0x40 /**< Content type Application/json supported in the endpoint resource. */ +/**@} */ + +/**@defgroup COAP_METHOD_PERMISSION Resource method permission bitmask values + * @{ */ +#define COAP_PERM_NONE 0x0000 /**< Permission by default. Do not allow any method in the COAP/COAPS endpoint resource. */ +#define COAP_PERM_GET 0x0001 /**< Permission to allow GET method in the COAP endpoint resource. */ +#define COAP_PERM_POST 0x0002 /**< Permission to allow POST method in the COAP endpoint resource. */ +#define COAP_PERM_PUT 0x0004 /**< Permission to allow PUT method in the COAP endpoint resource. */ +#define COAP_PERM_DELETE 0x0008 /**< Permission to allow DELETE method in the COAP endpoint resource. */ +#define COAPS_PERM_GET 0x0010 /**< Permission to allow GET method in the COAPS endpoint resource. */ +#define COAPS_PERM_POST 0x0020 /**< Permission to allow POST method in the COAPS endpoint resource. */ +#define COAPS_PERM_PUT 0x0040 /**< Permission to allow PUT method in the COAPS endpoint resource. */ +#define COAPS_PERM_DELETE 0x0080 /**< Permission to allow DELETE method in the COAPS endpoint resource. */ +#define COAP_PERM_OBSERVE 0x0100 /**< Permission to allow OBSERVE of the endpoint resource. */ +/**@} */ + +/**@cond */ +// Forward declare structs. +typedef struct coap_message_t coap_message_t; +typedef struct coap_resource_t coap_resource_t; +/**@endcond */ + +/**@brief Callback function to call upon undefined behaviour. + * + * @param[in] error_code Error code from CoAP module. + * @param[in] p_message CoAP message processed when error ocoured. Could be NULL. + */ +typedef void (*coap_error_callback_t)(uint32_t error_code, coap_message_t * p_message); + +/**@brief Callback function to be registered with CoAP messages. + * + * @param[in] status Response status. Possible status codes: + * NRF_SUCCESS If response was successfully received, + * COAP_TRANSMISSION_RESET_BY_PEER if a reset response was recieved or, + * COAP_TRANSMISSION_TIMEOUT if transmission + * @param[in] p_arg Miscellaneous pointer to application provided data that is associated with + * the message. + * @param[in] p_message Pointer to a CoAP Response message. + */ +typedef void (*coap_response_callback_t)(uint32_t status, void * p_arg, coap_message_t * p_message); + +/**@brief Handler function for manually handling all incoming requests. + * + * @details If the function is set, the error code given back will trigger error messages + * to be sent back by CoAP to indicate failure. Default error message will be 4.00 + * BAD REQUEST. On success, it is expected that the callback has already sent a + * response message. + * + * @param[in] p_request Pointer to a CoAP Request message. + * + * @retval NRF_SUCCESS If the message was successfully has been handled. + * @retval NRF_ERROR_NOT_FOUND If the message did not match any recognized resources, and a + * 4.04 NOT FOUND error message should be sent back to the requester. + * @retval NRF_ERROR_NULL If the message resolved the resource and operation not permitted, + * and a 4.05 METHOD NOT ALLOWED error message should be sent back to + * the reqester. + * + */ +typedef uint32_t (*coap_request_handler_t)(coap_message_t * p_request); + +#ifdef COAP_AUTOMODE + +/**@brief Callback function to be registered with CoAP endpoint resources. in auto-mode. + * + * @details The callback needs to implement any action based on the request. The p_response message + * will automatically be sent as response when the callback function returns. The memory + * is allocated by the caller, so the application does not have to free up the memory used + * for the response. + * + * @param[in] p_resource Pointer to the request message's target resource. + * @param[in] p_request Pointer to the request message. + * @param[out] p_response Pointer to the prepared response message. The Application can override + * its values. + */ +typedef void (*coap_method_callback_t) (coap_resource_t * p_resource, coap_message_t * p_request, coap_message_t * p_response); + +#else // COAP_AUTOMODE + +/**@brief Callback function to be registered with CoAP endpoint resources. in auto-mode. + * + * @details The callback needs to implement any action based on the request. The callback is + * responsible of handling the sending of any response back to the requester. The memory + * for p_request will be freed up by the coap module after the callback has been + * completed. + * + * @param[in] p_resource Pointer to the request message's target resource. + * @param[in] p_request Pointer to the request message. + */ +typedef void (*coap_method_callback_t) (coap_resource_t * p_resource, coap_message_t * p_request); + +#endif // COAP_AUTOMODE + +/**@brief Enumeration of CoAP content types. */ +typedef enum +{ + COAP_CT_PLAIN_TEXT = 0, /**< Plain text content format number. Default. */ + COAP_CT_APP_LINK_FORMAT = 40, /**< Application/link-format content format number. */ + COAP_CT_APP_XML = 41, /**< Application/xml content format number. */ + COAP_CT_APP_OCTET_STREAM = 42, /**< Application/octet-stream content format number. */ + COAP_CT_APP_EXI = 47, /**< Application/exi content format number. */ + COAP_CT_APP_JSON = 50 /**< Application/json content format number. */ +} coap_content_type_t; + +/**@brief Enumeration of CoAP options numbers. */ + +#define COAP_OPT_RESERVED0 0 /**< Reserved option number. */ +#define COAP_OPT_IF_MATCH 1 /**< If-Match option number. */ +#define COAP_OPT_URI_HOST 3 /**< URI-Host option number. */ +#define COAP_OPT_ETAG 4 /**< ETag option number. */ +#define COAP_OPT_IF_NONE_MATCH 5 /**< If-None-Match option number. */ +#define COAP_OPT_URI_PORT 7 /**< URI-Port option number. */ +#define COAP_OPT_LOCATION_PATH 8 /**< Location-Path option number. */ +#define COAP_OPT_URI_PATH 11 /**< URI-Path option number. */ +#define COAP_OPT_CONTENT_FORMAT 12 /**< Content-Format option number. */ +#define COAP_OPT_MAX_AGE 14 /**< Max-Age option number. */ +#define COAP_OPT_URI_QUERY 15 /**< URI-Query option number. */ +#define COAP_OPT_ACCEPT 17 /**< Accept option number. */ +#define COAP_OPT_LOCATION_QUERY 20 /**< Location-Query option number. */ +#define COAP_OPT_BLOCK2 23 /**< Block2 option number. */ +#define COAP_OPT_BLOCK1 27 /**< Block1 option number. */ +#define COAP_OPT_SIZE2 28 /**< Size2 option number. */ +#define COAP_OPT_PROXY_URI 35 /**< Proxy-URI option number. */ +#define COAP_OPT_PROXY_SCHEME 39 /**< Proxy-Scheme option number. */ +#define COAP_OPT_SIZE1 60 /**< Size1 option number. */ +#define COAP_OPT_RESERVED1 128 /**< Reserved option number. */ +#define COAP_OPT_RESERVED2 132 /**< Reserved option number. */ +#define COAP_OPT_RESERVED3 136 /**< Reserved option number. */ +#define COAP_OPT_RESERVED4 140 /**< Reserved option number. */ + + +/**@brief Enumeration of CoAP message types. */ +typedef enum +{ + COAP_TYPE_CON = 0, /**< Confirmable Message type. */ + COAP_TYPE_NON, /**< Non-Confirmable Message type. */ + COAP_TYPE_ACK, /**< Acknowledge Message type. */ + COAP_TYPE_RST /**< Reset Message type. */ +} coap_msg_type_t; + +/**@brief Structure to hold a CoAP option. + */ +typedef struct +{ + uint16_t number; /**< Option number (including the extended delta value if any). */ + uint16_t length; /**< Option length (including the extended length value in any). */ + uint8_t * p_data; /**< Pointer to the memory where the data of the option is located. */ +} coap_option_t; + + + +/**@brief Structure to hold a CoAP message configuration. + * + * @details The structure is used when calling the \ref coap_message_new API function. + * All data supplied will be copied to the created message. + */ +typedef struct +{ + coap_response_callback_t response_callback; /**< Callback function to be called when a response matching the token is identified. */ + uint8_t token[8]; /**< Message token. token_len must be set to indicate how many of the bytes should be used in the token. */ + uint8_t token_len; /**< Token size in bytes. */ + uint16_t id; /**< Message ID. If 0 is given, the library will replace this number with an autogenerated value. */ + coap_msg_type_t type; /**< Message type: COAP_TYPE_CON, COAP_TYPE_NON, COAP_TYPE_ACK, or COAP_TYPE_RST. */ + coap_msg_code_t code; /**< Message code (definitions found in coap_msg_code_t). */ + coap_port_t port; /**< Transport layer variable to associate the message with an underlying Transport Layer socket descriptor. */ +} coap_message_conf_t; + +/**@brief Structure to hold a CoAP message header. + * + * @details This structure holds the 4-byte mandatory CoAP header. The structure uses bitfields + * to save memory footprint. + */ +typedef struct +{ + uint8_t version :2; /**< CoAP version number. The current specification RFC7252 mandates this to be version 1. The version number can be modified in sdk_config.h. */ + uint8_t type :2; /**< Message type: COAP_TYPE_CON, COAP_TYPE_NON, COAP_TYPE_ACK, or COAP_TYPE_RST. */ + uint8_t token_len :4; /**< Length of the message token. */ + uint8_t code; /**< Message code (definitions found in @ref coap_msg_code_t). */ + uint16_t id; /**< Message ID in little-endian format. Convertion to Network Byte Order will be handled by the library. */ +} coap_message_header_t; + +/**@brief Structure to hold a CoAP message. + * + * @details The CoAP message structure contains both internal and public members to + * serialize and deserialize data supplied from the application to a byte buffer sent + * over UDP. The message structure is used both in transmission and reception, which + * makes it easy to handle in an application. Updating the message should be done + * using the provided APIs, not by manually assigning new values to the members directly. + * Reading the members, on the other hand, is fine. + */ +struct coap_message_t +{ + coap_remote_t remote; /**< Public. Structure containing address information and port number to the remote. */ + coap_remote_t local; /**< Public. Structure containing local destination address information and port number. */ + coap_message_header_t header; /**< Public. Header structure containing the mandatory CoAP 4-byte header fields. */ + uint8_t * p_payload; /**< Public. Pointer to the payload buffer in the message. */ + uint16_t payload_len; /**< Public. Size of the payload in the message. */ + uint8_t options_count; /**< Public. The number of options in the message. */ + coap_option_t options[COAP_MAX_NUMBER_OF_OPTIONS]; /**< Public. Array options in the message. */ + void * p_arg; /**< Public. Miscellaneous pointer to application provided data that is associated with the message. */ + + coap_response_callback_t response_callback; /**< Internal. Function callback set by the application to be called when a response to this message is received. Should be set by the application through a configuration parameter. */ + uint8_t token[8]; /**< Internal. Array holding the variable-sized message token. Should be set by the application through a configuration parameter. */ + coap_port_t port; /**< Internal. Transport layer variable to associate the message with an underlying Transport Layer socket descriptor. */ + uint16_t options_len; /**< Internal. Length of the options including the mandatory header with extension bytes and option data. Accumulated every time a new options is added. */ + uint16_t options_offset; /**< Internal. Index to where the next option or payload can be added in the message's data buffer */ + uint16_t options_delta; /**< Internal. Current option number. Used to calculate the next option delta when adding new options to the message. */ + uint8_t * p_data; /**< Internal. Data buffer for adding dynamically sized options and payload. */ + uint16_t data_len; /**< Internal. Length of the provided data buffer for options and payload. */ +}; + + +/**@brief Structure to hold a CoAP endpoint resource. +*/ +struct coap_resource_t +{ + uint8_t child_count; /**< Number of children in the linked list. */ + uint16_t permission; /**< Bitmask to tell which methods are permitted on the resource. Bit values available can be seen in \ref COAP_METHOD_PERMISSION. */ + coap_resource_t * p_sibling; /**< Sibling pointer to the next element in the list. */ + coap_resource_t * p_front; /**< Pointer to the beginning of the linked list. */ + coap_resource_t * p_tail; /**< Pointer to the last added child in the list. */ + coap_method_callback_t callback; /**< Callback to the resource handler. */ + uint32_t ct_support_mask; /**< Bitmask to tell which content types are supported by the resource. Bit values available can be seen in \ref COAP_CONTENT_TYPE_MASK. */ + uint32_t max_age; /**< Max age of resource endpoint value. */ + uint32_t expire_time; /**< Number of seconds until expire. */ + char name[COAP_RESOURCE_MAX_NAME_LEN+1]; /**< Name of the resource. Must be zero terminated. */ +}; + +/**@brief Initializes the CoAP module. + * + * @details Initializes the library module and resets internal queues and resource registrations. + * + * @param[in] token_rand_seed Random number seed to be used to generate the token numbers. + * @param[in] p_transport_params Pointer to transport parameters. Providing the list of ports + * to be used by CoAP. + * + * @retval NRF_SUCCESS If initialization succeeded. + */ +uint32_t coap_init(uint32_t token_rand_seed, coap_transport_init_t * p_transport_params); + +/**@brief Register error handler callback to the CoAP module. + * + * @param[in] error_callback Function to be called upon unknown messages and failure. + * + * @retval NRF_SUCCESS If registration was successful. + */ +uint32_t coap_error_handler_register(coap_error_callback_t error_callback); + +/**@brief Register request handler which should handle all incoming requests. + * + * @details Setting this request handler redirects all requests to the application provided + * callback routine. The callback handler might be cleared by NULL, making coap + * module handle the requests and do resource lookup in order to process the + * requests. + * + * @param[in] p_request_handler Function pointer to the provided request handler. + * + * @retval NRF_SUCCESS If registration was successful. + */ +uint32_t coap_request_handler_register(coap_request_handler_t p_request_handler); + +/**@brief Sends a CoAP message. + * + * @details Sends out a request using the underlying transport layer. Before sending, the + * \ref coap_message_t structure is serialized and added to an internal message queue + * in the library. The handle returned can be used to abort the message from being + * retransmitted at any time. + * + * @param[out] p_handle Handle to the message if CoAP CON/ACK messages has been used. Returned + * by reference. + * @param[in] p_message Message to be sent. + * + * @retval NRF_SUCCESS If the message was successfully encoded and scheduled for transmission. + */ +uint32_t coap_message_send(uint32_t * p_handle, coap_message_t * p_message); + +/**@brief Abort a CoAP message. + * + * @details Aborts an ongoing transmission. If the message has not yet been sent, it will be + * deleted from the message queue as well as stop any ongoing re-transmission of the + * message. + * + * @param[in] handle Handle of the message to abort. + * + * @retval NRF_SUCCESS If the message was successfully aborted and removed from the + * message queue. + * @retval NRF_ERROR_NOT_FOUND If the message with the given handle was not located in the + * message queue. + */ +uint32_t coap_message_abort(uint32_t handle); + +/**@brief Creates CoAP message, initializes, and allocates the needed memory. + * + * @details Creates a CoAP message. This is an intermediate representation of the message, + * because the message will be serialized by the library before it is transmitted. The structure + * is verbose to facilitate configuring the message. Options, payload, and + * remote address information can be added using API function calls. + * + * @param[inout] p_request Pointer to be filled by the allocated CoAP message structures. + * @param[in] p_config Configuration for the message to be created. Manual configuration + * can be performed after the message creation, except for the CLIENT port + * association. + * + * @retval NRF_SUCCESS If the request was successfully allocated and initialized. + * @retval NRF_ERROR_INVALID_PARAM If local port number was not configured. + */ +uint32_t coap_message_new(coap_message_t ** p_request, coap_message_conf_t * p_config); + +/**@brief Deletes the CoAP request message. + * + * @details Frees up memory associated with the request message. + * + * @param[in] p_message Pointer to the request message to delete. + */ +uint32_t coap_message_delete(coap_message_t * p_message); + +/**@brief Adds a payload to a CoAP message. + * + * @details Sets a data payload to a request or response message. + * + * This function must be called after all CoAP options have been added. + * Due to internal buffers in the library, the payload will be added after any options + * in the buffer. If an option is added after the payload, this option will over-write + * the payload in the internal buffer. + * + * @param[inout] p_message Pointer to the message to add the payload to. + * @param[in] p_payload Pointer to the payload to be added. + * @param[in] payload_len Size of the payload to be added. + * + * @retval NRF_SUCCESS If the payload was successfully added to the message. + * @retval NRF_ERROR_NO_MEM If the payload could not fit within the allocated payload memory + * defined by sdk_config.h COAP_MESSAGE_DATA_MAX_SIZE. + */ +uint32_t coap_message_payload_set(coap_message_t * p_message, + void * p_payload, + uint16_t payload_len); + +/**@brief Adds an empty CoAP option to the message. + * + * Option numbers must be in ascending order, adding the one with the smallest number + * first and greatest last. If the order is incorrect, the delta number calculation will + * result in an invalid or wrong delta number for the option. + * + * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL. + * @param[in] option_num The option number to add to the message. + * + * @retval NRF_SUCCESS If the empty option was successfully added to the message. + * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size. + * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached. + */ +uint32_t coap_message_opt_empty_add(coap_message_t * p_message, uint16_t option_num); + +/**@brief Adds a uint CoAP option to the message. + * + * Option numbers must be in ascending order, adding the one with the smallest number + * first and greatest last. If the order is incorrect, the delta number calculation will + * result in an invalid or wrong delta number for the option. + * + * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL. + * @param[in] option_num The option number to add to the message. + * @param[in] data An unsigned value (8-bit, 16-bit, or 32-bit) casted to uint32_t. + * The value of the data is used to determine how many bytes + * CoAP must use to represent this option value. + * + * @retval NRF_SUCCESS If the unsigned integer option was successfully added to the message. + * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size. + * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached. + */ +uint32_t coap_message_opt_uint_add(coap_message_t * p_message, uint16_t option_num, uint32_t data); + +/**@brief Adds a string CoAP option to the message. + * + * Option numbers must be in ascending order, adding the one with the smallest number + * first and greatest last. If the order is incorrect, the delta number calculation will + * result in an invalid or wrong delta number for the option. + * + * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL. + * @param[in] option_num The option number to add to the message. + * @param[in] p_data Pointer to a string buffer to be used as value for the option. + * Should not be NULL. + * @param[in] length Length of the string buffer provided. + * + * @retval NRF_SUCCESS If the string option was successfully added to the message. + * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size. + * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached. + */ +uint32_t coap_message_opt_str_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length); + +/**@brief Adds an opaque CoAP option to the message. + * + * Option numbers must be in ascending order, adding the one with the smallest number + * first and greatest last. If the order is incorrect, the delta number calculation will + * result in an invalid or wrong delta number for the option. + * + * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL. + * @param[in] option_num The option number to add to the message. + * @param[in] p_data Pointer to an opaque buffer to be used as value for the option. + * Should not be NULL. + * @param[in] length Length of the opaque buffer provided. + * + * @retval NRF_SUCCESS If the opaque option was successfully added to the message. + * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size. + * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached. + */ +uint32_t coap_message_opt_opaque_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length); + +/**@brief Sets a remote address and port number to a CoAP message. + * + * @details Copies the content of the provided pointer into the CoAP message. + * + * @param[inout] p_message Pointer to the message to add the address information to. + * Should not be NULL. + * @param[in] p_address Pointer to a structure holding the address information for the remote server or client. + * Should not be NULL. + * + * @retval NRF_SUCCESS When copying the content has finished. + */ +uint32_t coap_message_remote_addr_set(coap_message_t * p_message, coap_remote_t * p_address); + +/**@brief Creates a CoAP endpoint resource. + * + * @details Initializes the \ref coap_resource_t members. + * + * The first resource that is created will be set as the root of the resource + * hierarchy. + * + * @param[in] p_resource Pointer to coap_resource_t passed in by reference. + * This variable must be stored in non-volatile memory. + * Should not be NULL. + * @param[in] name Verbose name of the service (zero-terminated + * string). The maximum length of a name is defined + * by COAP_RESOURCE_MAX_NAME_LEN in @c sdk_config.h + * and can be adjusted if needed. Should not be NULL. + * @retval NRF_ERROR_DATA_SIZE If the provided name is larger than the available name buffer. + * @retval NRF_ERROR_NULL If the pointer to the resource or the provided + * name buffer is NULL. + */ +uint32_t coap_resource_create(coap_resource_t * p_resource, const char * name); + +/**@brief Adds a child resource. + * + * @details The hierarchy is constructed as a linked list with a maximum number of children. + * COAP_RESOURCE_MAX_DEPTH in @c sdk_config.h sets the maximum depth. The maximum + * number of children can be adjusted if more levels are needed. + * + * @param[in] p_parent Resource to attach the child to. Should not be NULL. + * @param[in] p_child Child resource to attach. Should not be NULL. + * + * @retval NRF_SUCCESS If the child was successfully added. + * @retval COAP_ERROR_MAX_DEPTH_REACHED If the child is exceeding the maximum depth defined. + */ +uint32_t coap_resource_child_add(coap_resource_t * p_parent, coap_resource_t * p_child); + +/**@brief Generates .well-known/core string. + * + * @details This is a helper function for generating a CoRE link-format encoded string used for + * CoAP discovery. The function traverse the resource hierarchy recursively. + * The result will be resources listed in link-format. This function can be called when + * all resources have been added by the application. + * + * @param[inout] string Buffer to use for the .well-known/core string. Should not be NULL. + * @param[inout] length Length of the string buffer. Returns the used number of bytes from + * the provided buffer. + * + * @retval NRF_SUCCESS If string generation was successful. + * @retval NRF_ERROR_NULL If the string buffer was a NULL pointer. + * @retval NRF_ERROR_DATA_SIZE If the size of the generated string exceeds the given buffer size. + * @retval NRF_ERROR_INVALID_STATE If no resource has been registered. + */ +uint32_t coap_resource_well_known_generate(uint8_t * string, uint16_t * length); + +/**@brief Get the root resource pointer. + * + * @param[out] pp_resource Pointer to be filled with pointer to the root resource. + * + * @retval NRF_SUCCESS If root resource was located. + * @retval NRF_ERROR_NOT_FOUND If root resource was not located. + * @retval NRF_ERROR_NULL If output pointer was NULL. + */ +uint32_t coap_resource_root_get(coap_resource_t ** pp_resource); + +/**@brief Check whether a message contains a given CoAP Option. + * + * @param[in] p_message Pointer to the to check for the CoAP Option. + * Should not be NULL. + * @param[in] option CoAP Option to check for in the CoAP message. + * + * @retval NRF_SUCCESS If the CoAP Option is present in the message. + * @retval NRF_ERROR_NULL If the pointer to the message is NULL. + * @retval NRF_ERROR_NOT_FOUND If the CoAP Option is not present in the message. + */ +uint32_t coap_message_opt_present(coap_message_t * p_message, uint16_t option); + +/**@brief Check whether a message contains a given CoAP Option and return the index of the entry + * in the message option list. + * + * @param[in] p_index Value by reference to fill the resolved index into. Should not be NULL. + * @param[in] p_message Pointer to the to check for the CoAP Option. + * Should not be NULL. + * @param[in] option CoAP Option to check for in the CoAP message. + * + * @retval NRF_SUCCESS If the CoAP Option is present in the message. + * @retval NRF_ERROR_NULL If the pointer to the message or the p_index is NULL. + * @retval NRF_ERROR_NOT_FOUND If the CoAP Option is not present in the message. + */ +uint32_t coap_message_opt_index_get(uint8_t * p_index, coap_message_t * p_message, uint16_t option); + +/**@brief Find common content type between the CoAP message and the resource. + * + * @details The return value will be the first match between the ACCEPT options and the supported + * content types in the resource. The priority is by content-format ID starting going + * from the lowest value to the highest. + * + * @param[out] p_ct Resolved content type given by reference. Should not be NULL. + * @param[in] p_message Pointer to the message. Should not be NULL. + * @param[in] p_resource Pointer to the resource. Should not be NULL. + * + * @retval NRF_SUCCESS If match was found. + * @retval NRF_ERROR_NOT_FOUND If no match was found. + */ +uint32_t coap_message_ct_match_select(coap_content_type_t * p_ct, coap_message_t * p_message, coap_resource_t * p_resource); + +/**@brief CoAP time tick used for retransmitting any message in the queue if needed. + * + * @retval NRF_SUCCESS If time tick update was successfully handled. + */ +uint32_t coap_time_tick(void); + +#if (COAP_DISABLE_DTLS_API == 0) +/**@brief Setup secure DTLS session. + * + * @details For the client role, this API triggers a DTLS handshake. Until the handshake is complete + * with the remote, \ref coap_message_send will fail. + * For the server role, this API does not create any DTLS session. A DTLS session is + * created each time a new client remote endpoint sends a request on the local port of the + * server. + * + * @note The success of this function does not imply that the DTLS handshake is successfull. + * + * @note Only one DTLS session is permitted between a local and remote endpoint. Therefore, in case + * a DTLS session was established between the local and remote endpoint, the existing DTLS + * session will be reused irrespective of the role and number of times this API was called. + * In case the application desires a fresh security setup, it must first call the + * \ref coap_security_destroy to tear down the existing setup. + * + * @param[in] local_port Local port to bind the session to. + * @param[in] role Role of the session. DTLS server or client defined in the enumeration + * \ref nrf_tls_role_t. + * @param[in] p_remote Pointer to a structure holding the address information for the remote + * endpoint. If a the device is acting as a server, a NULL pointer shall be + * given as a parameter. Rationale: The server is not envisioned to be + * bound a pre-known client endpoint. Therefore, security server settings + * shall be setup irrespective of the remote client. + * @param[in] p_settings Pointer to a structure holding the DTLS credentials. + * + * @retval NRF_SUCCESS If setup of the secure DTLS session was successfull. + */ +uint32_t coap_security_setup(uint16_t local_port, + nrf_tls_role_t role, + coap_remote_t * const p_remote, + nrf_tls_key_settings_t * const p_settings); + + +/**@brief Destroy a secure DTLS session. + * + * @details Terminate and clean up any session associated with the local port and the remote. + * + * @param[in] local_port Local port to unbind the session from. + * @param[in] p_remote Pointer to a structure holding the address information for the remote + * endpoint. Providing a NULL as p_remote will clean up all DTLS sessions + * associated with the local port. + * + * @retval NRF_SUCCESS If the destruction of the secure DTLS session was successfull. + */ +uint32_t coap_security_destroy(uint16_t local_port, + coap_remote_t * const p_remote); + +#endif // COAP_DISABLE_DTLS_API + +/**@brief Process loop when using coap BSD socket transport implementation. + * + * @details This is blocking call. The function unblock is only + * triggered upon an socket event registered to select() by coap transport. + * This function must be called as often as possible in order to dispatch incoming + * socket events. Preferred to be put in the application's main loop or similar. + **/ +void coap_input(void); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_API_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c new file mode 100644 index 0000000..f915f54 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c @@ -0,0 +1,203 @@ +/** + * 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 <stdbool.h> +#include <stddef.h> + +#include "coap_block.h" +#include "nrf_error.h" +#include "iot_errors.h" +#include "sdk_config.h" + + +/** + * @defgroup api_param_check API Parameters check macros. + * + * @details Macros that verify parameters passed to the module in the APIs. These macros + * could be mapped to nothing in final versions of code to save execution and size. + * COAP_DISABLE_API_PARAM_CHECK should be defined to disable these checks. + * + * @{ + */ +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Verify NULL parameters are not passed to API by application. */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } +#else // COAP_DISABLE_API_PARAM_CHECK + +#define NULL_PARAM_CHECK(PARAM) + +#endif // COAP_DISABLE_API_PARAM_CHECK +/** @} */ + + +#define BLOCK_SIZE_BASE_CONSTANT 4 /**< Block size base exponent. 4 means a base block size of 2^4 = 16 bytes. */ + +#define BLOCK_SIZE_16 0 /**< Block size of 2^(4+0) = 16 bytes. */ +#define BLOCK_SIZE_32 1 /**< Block size of 2^(4+1) = 32 bytes. */ +#define BLOCK_SIZE_64 2 /**< Block size of 2^(4+2) = 64 bytes. */ +#define BLOCK_SIZE_128 3 /**< Block size of 2^(4+3) = 128 bytes. */ +#define BLOCK_SIZE_256 4 /**< Block size of 2^(4+4) = 256 bytes. */ +#define BLOCK_SIZE_512 5 /**< Block size of 2^(4+5) = 512 bytes. */ +#define BLOCK_SIZE_1024 6 /**< Block size of 2^(4+6) = 1024 bytes. */ +#define BLOCK_SIZE_2048_RESERVED 7 /**< Reserved. */ + +#define BLOCK_MORE_BIT_UNSET 0 /**< Value when more flag is set. */ +#define BLOCK_MORE_BIT_SET 1 /**< Value when more flag is not set. */ + +#define BLOCK_SIZE_POS 0 /**< Bit offset to the size. */ +#define BLOCK_MORE_BIT_POS 3 /**< Bit offset to the more bit. */ +#define BLOCK_NUMBER_POS 4 /**< Bit offset to the block number. */ + +#define BLOCK_SIZE_MASK 0x7 /**< Block size mask. */ +#define BLOCK_MORE_BIT_MASK (1 << BLOCK_MORE_BIT_POS) /**< More bit mask. */ +#define BLOCK_NUMBER_MASK (0xFFFFF << 4) /**< Block number mask. */ + +#define BLOCK_SIZE_MAX 0x7 /**< Maximum block size number. */ +#define BLOCK_MORE_BIT_MAX BLOCK_MORE_BIT_SET /**< Maximum more bit value. */ +#define BLOCK_NUMBER_MAX 0xFFFFF /**< Maximum block number. 20 bits max value is (1 << 20) - 1. */ + +static uint32_t block_opt_encode(uint8_t more, + uint16_t size, + uint32_t number, + uint32_t * p_encoded) +{ + if ((number > BLOCK_NUMBER_MAX) || (more > BLOCK_MORE_BIT_MAX)) + { + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + + uint32_t val = 0; + + switch (size) + { + case 16: + val = BLOCK_SIZE_16; + break; + + case 32: + val = BLOCK_SIZE_32; + break; + + case 64: + val = BLOCK_SIZE_64; + break; + + case 128: + val = BLOCK_SIZE_128; + break; + + case 256: + val = BLOCK_SIZE_256; + break; + + case 512: + val = BLOCK_SIZE_512; + break; + + case 1024: + val = BLOCK_SIZE_1024; + break; + + case 2048: + // Falltrough. + default: + // Break omitted. + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + + // Value has been initialized. + val |= (more) << BLOCK_MORE_BIT_POS; + val |= (number) << BLOCK_NUMBER_POS; + + *p_encoded = val; + return NRF_SUCCESS; +} + +static uint32_t block_opt_decode(uint32_t encoded, + uint8_t * p_more, + uint16_t * p_size, + uint32_t * p_number) +{ + if ((encoded & BLOCK_SIZE_MASK) == BLOCK_SIZE_2048_RESERVED) + { + return (NRF_ERROR_INVALID_DATA | IOT_COAP_ERR_BASE); + } + + if ((encoded >> BLOCK_NUMBER_POS) > BLOCK_NUMBER_MAX) + { + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + + *p_size = (1 << ((BLOCK_SIZE_BASE_CONSTANT + (encoded & BLOCK_SIZE_MASK)))); + *p_more = (encoded & BLOCK_MORE_BIT_MASK) >> BLOCK_MORE_BIT_POS; + *p_number = (encoded & BLOCK_NUMBER_MASK) >> BLOCK_NUMBER_POS; + + return NRF_SUCCESS; +} + +uint32_t coap_block_opt_block1_encode(uint32_t * p_encoded, coap_block_opt_block1_t * p_opt) +{ + NULL_PARAM_CHECK(p_encoded); + NULL_PARAM_CHECK(p_opt); + return block_opt_encode(p_opt->more, p_opt->size, p_opt->number, p_encoded); +} + +uint32_t coap_block_opt_block1_decode(coap_block_opt_block1_t * p_opt, uint32_t encoded) +{ + NULL_PARAM_CHECK(p_opt); + return block_opt_decode(encoded, &p_opt->more, &p_opt->size, &p_opt->number); +} + +uint32_t coap_block_opt_block2_encode(uint32_t * p_encoded, coap_block_opt_block2_t * p_opt) +{ + NULL_PARAM_CHECK(p_encoded); + NULL_PARAM_CHECK(p_opt); + return block_opt_encode(p_opt->more, p_opt->size, p_opt->number, p_encoded); +} + +uint32_t coap_block_opt_block2_decode(coap_block_opt_block2_t * p_opt, uint32_t encoded) +{ + NULL_PARAM_CHECK(p_opt); + return block_opt_decode(encoded, &p_opt->more, &p_opt->size, &p_opt->number); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h new file mode 100644 index 0000000..fa2e9ee --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h @@ -0,0 +1,126 @@ +/** + * 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. + * + */ +/** @file coap_block.h + * + * @defgroup iot_sdk_coap_block CoAP Block transfer + * @ingroup iot_sdk_coap + * @{ + * @brief CoAP block transfer options encoding and decoding interface and definitions. + * + */ + +#ifndef COAP_BLOCK_H__ +#define COAP_BLOCK_H__ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define COAP_BLOCK_OPT_BLOCK_MORE_BIT_UNSET 0 /**< Value when more flag is set. */ +#define COAP_BLOCK_OPT_BLOCK_MORE_BIT_SET 1 /**< Value when more flag is not set. */ + +typedef struct +{ + uint8_t more; /**< More bit value. */ + uint16_t size; /**< Size of the block in bytes. */ + uint32_t number; /**< Block number. */ +} coap_block_opt_block1_t; + +typedef coap_block_opt_block1_t coap_block_opt_block2_t; + +/**@brief Encode block1 option into its uint binary counter part. + * + * @param[out] p_encoded Encoded version of the coap block1 option value. Must not be NULL. + * @param[in] p_opt Pointer to block1 option structure to be decoded into uint format. Must + * not be NULL. + * + * @retval NRF_SUCCESS If encoding of option was successful. + * @retval NRF_ERROR_NULL If one of the parameters supplied is a null pointer. + * @retval NRF_ERROR_INVALID_PARAM If one of the fields in the option structure has an illegal + * value. + */ +uint32_t coap_block_opt_block1_encode(uint32_t * p_encoded, coap_block_opt_block1_t * p_opt); + +/**@brief Decode block1 option from a uint to its structure counter part. + * + * @param[out] p_opt Pointer to block1 option structure to be filled by the function. Must not + * be NULL. + * @param[in] encoded Encoded version of the coap block1 option value. + * + * @retval NRF_SUCCESS If decoding of the option was successful. + * @retval NRF_ERROR_NULL If p_opt parameter is NULL. + * @retval NRF_ERROR_INVALID_PARAM If the block number is higher then allowed by spec (more than + 20 bits). + * @retval NRF_ERROR_INVALID_DATA If the size has the value of the reserved 2048 value (7). + */ +uint32_t coap_block_opt_block1_decode(coap_block_opt_block1_t * p_opt, uint32_t encoded); + +/**@brief Encode block2 option into its uint binary counter part. + * + * @param[out] p_encoded Encoded version of the coap block2 option value. Must not be NULL. + * @param[in] p_opt Pointer to block2 option structure to be decoded into uint format. Must + * not be NULL. + * + * @retval NRF_SUCCESS If encoding of option was successful. + * @retval NRF_ERROR_NULL If one of the parameters supplied is a null pointer. + * @retval NRF_ERROR_INVALID_PARAM If one of the fields in the option structure has an illegal + * value. + */ +uint32_t coap_block_opt_block2_encode(uint32_t * p_encoded, coap_block_opt_block2_t * p_opt); + +/**@brief Decode block2 option from a uint to its structure counter part. + * + * @param[out] p_opt Pointer to block2 option structure to be filled by the function. Must not + * be NULL. + * @param[in] encoded Encoded version of the coap block2 option value. + * + * @retval NRF_SUCCESS If decoding of the option was successful. + * @retval NRF_ERROR_NULL If p_opt parameter is NULL. + * @retval NRF_ERROR_INVALID_PARAM If the block number is higher then allowed by spec (more than + 20 bits). + * @retval NRF_ERROR_INVALID_DATA If the size has the value of the reserved 2048 value (7). + */ +uint32_t coap_block_opt_block2_decode(coap_block_opt_block2_t * p_opt, uint32_t encoded); + +#endif // COAP_BLOCK_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h new file mode 100644 index 0000000..88b1d48 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_codes.h + * + * @defgroup iot_sdk_coap_codes CoAP Codes + * @ingroup iot_sdk_coap + * @{ + * @brief CoAP message and response codes. + */ + +#ifndef COAP_CODES_H__ +#define COAP_CODES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define COAP_CODE(c, dd) \ + ((((c) & 0x7) << 5) | (((1 ## dd) - 100) & 0x1F)) +/** + @note macro adds 1xx to the number in order to prevent dd from being + interpreted as octal. +*/ + +/*lint -save -e122 */ /* Suppress "Digit (8) too large for radix" */ + +/** @brief CoAP Message codes +*/ +typedef enum +{ + // CoAP Empty Message + COAP_CODE_EMPTY_MESSAGE = COAP_CODE(0,00), /**< CoAP code 0.00, Decimal: 0, Hex: 0x00. */ + + // CoAP Method Codes + COAP_CODE_GET = COAP_CODE(0,01), /**< CoAP code 0.01, Decimal: 1, Hex: 0x01. */ + COAP_CODE_POST = COAP_CODE(0,02), /**< CoAP code 0.02, Decimal: 2, Hex: 0x02. */ + COAP_CODE_PUT = COAP_CODE(0,03), /**< CoAP code 0.03, Decimal: 3, Hex: 0x03. */ + COAP_CODE_DELETE = COAP_CODE(0,04), /**< CoAP code 0.04, Decimal: 4, Hex: 0x04. */ + + // CoAP Success Response Codes + COAP_CODE_201_CREATED = COAP_CODE(2,01), /**< CoAP code 2.01, Decimal: 65, Hex: 0x41. */ + COAP_CODE_202_DELETED = COAP_CODE(2,02), /**< CoAP code 2.02, Decimal: 66, Hex: 0x42. */ + COAP_CODE_203_VALID = COAP_CODE(2,03), /**< CoAP code 2.03, Decimal: 67, Hex: 0x43. */ + COAP_CODE_204_CHANGED = COAP_CODE(2,04), /**< CoAP code 2.04, Decimal: 68, Hex: 0x44. */ + COAP_CODE_205_CONTENT = COAP_CODE(2,05), /**< CoAP code 2.05, Decimal: 69, Hex: 0x45. */ + COAP_CODE_231_CONTINUE = COAP_CODE(2,31), /**< CoAP code 2.31, Decimal: 95, Hex: 0x5F. */ + + // CoAP Client Error Response Codes + COAP_CODE_400_BAD_REQUEST = COAP_CODE(4,00), /**< CoAP code 4.00, Decimal: 128, Hex: 0x80. */ + COAP_CODE_401_UNAUTHORIZED = COAP_CODE(4,01), /**< CoAP code 4.01, Decimal: 129, Hex: 0x81. */ + COAP_CODE_402_BAD_OPTION = COAP_CODE(4,02), /**< CoAP code 4.02, Decimal: 130, Hex: 0x82. */ + COAP_CODE_403_FORBIDDEN = COAP_CODE(4,03), /**< CoAP code 4.03, Decimal: 131, Hex: 0x83. */ + COAP_CODE_404_NOT_FOUND = COAP_CODE(4,04), /**< CoAP code 4.04, Decimal: 132, Hex: 0x84. */ + COAP_CODE_405_METHOD_NOT_ALLOWED = COAP_CODE(4,05), /**< CoAP code 4.05, Decimal: 133, Hex: 0x85. */ + COAP_CODE_406_NOT_ACCEPTABLE = COAP_CODE(4,06), /**< CoAP code 4.06, Decimal: 134, Hex: 0x86. */ + COAP_CODE_408_REQUEST_ENTITY_INCOMPLETE = COAP_CODE(4,08), /**< CoAP code 4.08, Decimal: 136, Hex: 0x88. */ + COAP_CODE_412_PRECONDITION_FAILED = COAP_CODE(4,12), /**< CoAP code 4.12, Decimal: 140, Hex: 0x8C. */ + COAP_CODE_413_REQUEST_ENTITY_TOO_LARGE = COAP_CODE(4,13), /**< CoAP code 4.13, Decimal: 141, Hex: 0x8D. */ + COAP_CODE_415_UNSUPPORTED_CONTENT_FORMAT = COAP_CODE(4,15), /**< CoAP code 4.15, Decimal: 143, Hex: 0x8F. */ + + // CoAP Server Error Response Codes + COAP_CODE_500_INTERNAL_SERVER_ERROR = COAP_CODE(5,00), /**< CoAP code 5.00, Decimal: 160, Hex: 0xA0. */ + COAP_CODE_501_NOT_IMPLEMENTED = COAP_CODE(5,01), /**< CoAP code 5.01, Decimal: 161, Hex: 0xA1. */ + COAP_CODE_502_BAD_GATEWAY = COAP_CODE(5,02), /**< CoAP code 5.02, Decimal: 162, Hex: 0xA2. */ + COAP_CODE_503_SERVICE_UNAVAILABLE = COAP_CODE(5,03), /**< CoAP code 5.03, Decimal: 163, Hex: 0xA3. */ + COAP_CODE_504_GATEWAY_TIMEOUT = COAP_CODE(5,04), /**< CoAP code 5.04, Decimal: 164, Hex: 0xA4. */ + COAP_CODE_505_PROXYING_NOT_SUPPORTED = COAP_CODE(5,05) /**< CoAP code 5.05, Decimal: 165, Hex: 0xA5. */ +} coap_msg_code_t; + +/*lint -restore */ + +#ifdef __cplusplus +} +#endif + +#endif // COAP_CODES_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c new file mode 100644 index 0000000..db0f7bf --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c @@ -0,0 +1,804 @@ +/** + * Copyright (c) 2014 - 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 <stdlib.h> +#include <string.h> + +#include "nordic_common.h" +#include "coap_message.h" +#include "coap_api.h" +#include "iot_common.h" +#include "sdk_config.h" +#include "app_util.h" + +#define COAP_PAYLOAD_MARKER_SIZE 1 + +/**@brief Verify that there is a index available for a new option. */ +#define OPTION_INDEX_AVAIL_CHECK(COUNT) \ + if ((COUNT) >= COAP_MAX_NUMBER_OF_OPTIONS) \ + { \ + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); \ + } + +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Verify NULL parameters are not passed to API by application. */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } +#else + +#define NULL_PARAM_CHECK(PARAM) +#define OPTION_INDEX_AVAIL_CHECK(COUNT) + +#endif // COAP_DISABLE_API_PARAM_CHECK + +uint32_t coap_message_create(coap_message_t * p_message, coap_message_conf_t * p_init_config) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_init_config); + + // Setting default value for version. + p_message->header.version = COAP_VERSION; + + // Copy values from the init config. + p_message->header.type = p_init_config->type; + p_message->header.token_len = p_init_config->token_len; + p_message->header.code = p_init_config->code; + p_message->header.id = p_init_config->id; + p_message->response_callback = p_init_config->response_callback; + p_message->p_arg = NULL; + + if (p_init_config->port.port_number == 0) + { + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + memcpy(&p_message->port, &p_init_config->port, sizeof(coap_port_t)); + + memcpy(p_message->token, p_init_config->token, sizeof(p_init_config->token)); + return NRF_SUCCESS; +} + +/**@brief Decode CoAP option + * + * @param[in] p_raw_option Pointer to the memory buffer where the raw option is located. + * @param[inout] p_message Pointer to the current message. Used to retrieve information about + * where current option delta and the size of free memory to add the + * values of the option. Used as a container where to put + * the parsed option. + * @param[out] byte_count Number of bytes parsed. Used to indicate where the next option + * might be located (if any left) in the raw message buffer. + * + * @retval NRF_SUCCESS If the option parsing went successful. + * @retval NRF_ERROR_DATA_SIZE If there is no more space left in the free memory to add the + * option value to the p_message. + */ +static uint32_t decode_option(const uint8_t * p_raw_option, coap_message_t * p_message, uint16_t * byte_count) +{ + uint16_t byte_index = 0; + uint8_t option_num = p_message->options_count; + + // Calculate the option number. + uint16_t option_delta = (p_raw_option[byte_index] & 0xF0) >> 4; + // Calculate the option length. + uint16_t option_length = (p_raw_option[byte_index] & 0x0F); + byte_index++; + + uint16_t acc_option_delta = p_message->options_delta; + + if (option_delta == 13) + { + // read one additional byte to get the extended delta. + acc_option_delta += 13 + p_raw_option[byte_index++]; + + } + else if (option_delta == 14) + { + // read one additional byte to get the extended delta. + acc_option_delta += 269; + acc_option_delta += (p_raw_option[byte_index++] << 8); + acc_option_delta += (p_raw_option[byte_index++]); + } + else + { + acc_option_delta += option_delta; + } + + // Set the accumlated delta as the option number. + p_message->options[option_num].number = acc_option_delta; + + if (option_length == 13) + { + option_length = 13 + p_raw_option[byte_index++]; + } + else if (option_length == 14) + { + option_length = 269; + option_length += (p_raw_option[byte_index++] << 8); + option_length += p_raw_option[byte_index++]; + } + + // Set the option length including extended bytes. + p_message->options[option_num].length = option_length; + + // Point p_data to the memory where to find the option value. + p_message->options[option_num].p_data = (uint8_t *)&p_raw_option[byte_index]; + + // Update the delta counter with latest option number. + p_message->options_delta = p_message->options[option_num].number; + + byte_index += p_message->options[option_num].length; + *byte_count = byte_index; + + return NRF_SUCCESS; +} + + +/**@brief Encode CoAP option delta and length bytes. + * + * @param[inout] encoded_value Value to encode. In return the value after encoding. + * @param[out] encoded_value_ext The value of the encoded extended bytes. + * + * @return The size of the extended byte field. + */ +static inline uint8_t encode_extended_bytes(uint16_t * value, + uint16_t * value_ext) +{ + uint16_t raw_value = *value; + + uint8_t ext_size = 0; + + if (raw_value >= 269) + { + *value = 14; + *value_ext = raw_value - 269; + ext_size = 2; + } + else if (raw_value >= 13) + { + *value = 13; + *value_ext = raw_value - 13; + ext_size = 1; + } + else + { + *value = raw_value; + *value_ext = 0; + } + + return ext_size; +} + + +static uint32_t encode_option(uint8_t * p_buffer, coap_option_t * p_option, uint16_t * byte_count) +{ + uint16_t delta_ext = 0; + uint16_t delta = p_option->number; + + uint8_t delta_ext_size = encode_extended_bytes(&delta, + &delta_ext); + + uint16_t length = p_option->length; + uint16_t length_ext = 0; + + uint8_t length_ext_size = encode_extended_bytes(&length, + &length_ext); + + if (p_buffer == NULL) + { + uint16_t header_size = 1; + *byte_count = header_size + delta_ext_size + length_ext_size + p_option->length; + return NRF_SUCCESS; + } + + uint16_t byte_index = 0; + + // Add the option header. + p_buffer[byte_index++] = ((delta & 0x0F) << 4) | (length & 0x0F); + + // Add option delta extended bytes to the buffer. + if (delta_ext_size == 1) + { + // Add first byte of delta_ext to the option header. + p_buffer[byte_index++] = (uint8_t)delta_ext; + } + else if (delta_ext_size == 2) + { + // uint16 in Network Byte Order. + p_buffer[byte_index++] = (uint8_t)((delta_ext & 0xFF00) >> 8); + p_buffer[byte_index++] = (uint8_t)((delta_ext & 0x00FF)); + } + + if (length_ext_size == 1) + { + // Add first byte of length_ext to the option header. + p_buffer[byte_index++] = (uint8_t)length_ext; + } + else if (length_ext_size == 2) + { + // uint16 in Network Byte Order. + p_buffer[byte_index++] = (uint8_t)((length_ext & 0xFF00) >> 8); + p_buffer[byte_index++] = (uint8_t)((length_ext & 0x00FF)); + } + + memcpy(&p_buffer[byte_index], p_option->p_data, p_option->length); + *byte_count = byte_index + p_option->length; + + return NRF_SUCCESS; +} + +uint32_t coap_message_decode(coap_message_t * p_message, + const uint8_t * p_raw_message, + uint16_t message_len) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_raw_message); + + // Check that the raw message contains the mandatory header. + if (message_len < 4) + { + return (NRF_ERROR_INVALID_LENGTH | IOT_COAP_ERR_BASE); + } + + // Parse the content of the raw message buffer. + uint16_t byte_index = 0; + + // Parse the 4 byte CoAP header. + p_message->header.version = (p_raw_message[byte_index] >> 6); + p_message->header.type = (coap_msg_type_t)((p_raw_message[byte_index] >> 4) & 0x03); + p_message->header.token_len = (p_raw_message[byte_index] & 0x0F); + byte_index++; + + p_message->header.code = (coap_msg_code_t)p_raw_message[byte_index]; + byte_index++; + + p_message->header.id = p_raw_message[byte_index++] << 8; + p_message->header.id += p_raw_message[byte_index++]; + + // Parse the token, if any. + for (uint8_t index = 0; (byte_index < message_len) && (index < p_message->header.token_len); index++) + { + p_message->token[index] = p_raw_message[byte_index++]; + } + + p_message->options_count = 0; + p_message->options_delta = 0; + + // Parse the options if any. + while ((byte_index < message_len) && (p_raw_message[byte_index] != COAP_PAYLOAD_MARKER)) + { + + uint32_t err_code; + uint16_t byte_count = 0; + + err_code = decode_option(&p_raw_message[byte_index], p_message, &byte_count); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + p_message->options_count += 1; + + byte_index += byte_count; + } + + // If there any more bytes to parse this would be the payload. + if (byte_index < message_len) + { + // Verify that we have a payload marker. + if (p_raw_message[byte_index] == COAP_PAYLOAD_MARKER) + { + byte_index++; + } + else + { + return COAP_MESSAGE_INVALID_CONTENT; + } + + p_message->payload_len = message_len - byte_index; + p_message->p_payload = (uint8_t *)&p_raw_message[byte_index]; + } + + return NRF_SUCCESS; +} + + +uint32_t coap_message_encode(coap_message_t * p_message, + uint8_t * p_buffer, + uint16_t * p_length) +{ + NULL_PARAM_CHECK(p_length); + NULL_PARAM_CHECK(p_message); + + // calculated size + uint16_t total_packet_size = 4; + + if (p_message->payload_len > 0) + { + total_packet_size += p_message->payload_len; + total_packet_size += COAP_PAYLOAD_MARKER_SIZE; + } + + if (p_message->header.token_len > 8) + { + return (NRF_ERROR_INVALID_DATA | IOT_COAP_ERR_BASE); + } + total_packet_size += p_message->header.token_len; + total_packet_size += p_message->options_len; + + // If this was a length check, return after setting the length in the output parameter. + if (*p_length == 0) + { + *p_length = total_packet_size; + return NRF_SUCCESS; + } + + // Check that the buffer provided is sufficient. + if (*p_length < total_packet_size) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + if (((p_message->payload_len > 0 && p_message->p_payload == NULL)) || + (p_buffer == NULL)) + { + return COAP_MESSAGE_ERROR_NULL; + } + + // Start filling the bytes. + uint16_t byte_index = 0; + + // TODO: Verify the values of the header fields. + // if (version > 1) + // if (p_message->type > COAP_TYPE_RST) + // if (p_message->token_len > 8) + + + p_buffer[byte_index] = (((p_message->header.version & 0x3) << 6) | ((p_message->header.type & 0x3) << 4)) | (p_message->header.token_len & 0x0F); + byte_index++; + + p_buffer[byte_index] = p_message->header.code; + byte_index++; + + p_buffer[byte_index++] = (p_message->header.id & 0xFF00) >> 8; + p_buffer[byte_index++] = (p_message->header.id & 0x00FF); + + memcpy(&p_buffer[byte_index], p_message->token, p_message->header.token_len); + byte_index += p_message->header.token_len; + + //memcpy(&p_buffer[byte_index], &p_message->p_data[0], p_message->options_len); + for (uint8_t i = 0; i < p_message->options_count; i++) + { + uint32_t err_code; + + uint16_t byte_count = 0; + err_code = encode_option(&p_buffer[byte_index], &p_message->options[i], &byte_count); + if (err_code == NRF_SUCCESS) + { + byte_index += byte_count; + } + else + { + // Throw an error. + } + } + + if (p_message->payload_len > 0 && p_message->p_payload != NULL) + { + p_buffer[byte_index++] = 0xFF; + memcpy(&p_buffer[byte_index], p_message->p_payload, p_message->payload_len); + } + + *p_length = total_packet_size; + + return NRF_SUCCESS; +} + +uint32_t coap_message_opt_empty_add(coap_message_t * p_message, uint16_t option_num) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + uint32_t err_code; + uint16_t encoded_len = 0; + uint8_t current_option_index = p_message->options_count; + + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size + uint16_t option_byte_count = 0; + + // do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + + return err_code; +} + +uint32_t coap_message_opt_uint_add(coap_message_t * p_message, + uint16_t option_num, + uint32_t data) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + uint32_t err_code; + uint16_t encoded_len = p_message->data_len - p_message->options_offset; + uint8_t current_option_index = p_message->options_count; + uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset]; + + // If the value of the option is 0, do not encode the 0, as this can be omitted. (RFC7252 3.2) + if (data == 0) + { + encoded_len = 0; + } + else + { + err_code = coap_opt_uint_encode(p_next_option_data, &encoded_len, data); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + + p_message->options[current_option_index].p_data = p_next_option_data; + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size. + uint16_t option_byte_count = 0; + + // Do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + + // Increase the pointer offset for the next option data in the scratch buffer. + p_message->options_offset += encoded_len; + + return err_code; +} + +uint32_t coap_message_opt_str_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + uint32_t err_code; + + uint16_t encoded_len = length; + uint8_t current_option_index = p_message->options_count; + uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset]; + + + err_code = coap_opt_string_encode(p_next_option_data, &encoded_len, p_data, length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + p_message->options[current_option_index].p_data = p_next_option_data; + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size + uint16_t option_byte_count = 0; + + // do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + p_message->options_offset += encoded_len; + + return err_code; + +} + +uint32_t coap_message_opt_opaque_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + // Check if it is possible to add a new option of this length. + if ((p_message->data_len - p_message->options_offset) < length) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + uint32_t err_code = NRF_SUCCESS; + + uint16_t encoded_len = length; + uint8_t current_option_index = p_message->options_count; + uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset]; + + + memcpy(p_next_option_data, p_data, encoded_len); + + p_message->options[current_option_index].p_data = p_next_option_data; + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size + uint16_t option_byte_count = 0; + + // do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + p_message->options_offset += encoded_len; + + return err_code; +} + +uint32_t coap_message_payload_set(coap_message_t * p_message, + void * p_payload, + uint16_t payload_len) +{ + // Check that there is available memory in the p_message->p_data scratch buffer. + if (payload_len > (COAP_MESSAGE_DATA_MAX_SIZE - p_message->options_offset)) + { + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); + } + + p_message->p_payload = &p_message->p_data[p_message->options_offset]; + p_message->payload_len = payload_len; + memcpy(p_message->p_payload, p_payload, payload_len); + + return NRF_SUCCESS; +} + + +uint32_t coap_message_remote_addr_set(coap_message_t * p_message, coap_remote_t * p_address) +{ + memcpy(&p_message->remote, p_address, sizeof(coap_remote_t)); + return NRF_SUCCESS; +} + +uint32_t coap_message_opt_index_get(uint8_t * p_index, coap_message_t * p_message, uint16_t option) +{ + NULL_PARAM_CHECK(p_index); + NULL_PARAM_CHECK(p_message); + + uint8_t index; + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == option) + { + *p_index = index; + return NRF_SUCCESS; + } + } + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +uint32_t coap_message_opt_present(coap_message_t * p_message, uint16_t option) +{ + NULL_PARAM_CHECK(p_message); + + uint8_t index; + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == option) + { + return NRF_SUCCESS; + } + } + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +static uint32_t bit_to_content_format(coap_content_type_t * p_ct, uint32_t bit) +{ + switch (bit) + { + case COAP_CT_MASK_PLAIN_TEXT: + *p_ct = COAP_CT_PLAIN_TEXT; + break; + + case COAP_CT_MASK_APP_LINK_FORMAT: + *p_ct = COAP_CT_APP_LINK_FORMAT; + break; + + case COAP_CT_MASK_APP_XML: + *p_ct = COAP_CT_APP_XML; + break; + + case COAP_CT_MASK_APP_OCTET_STREAM: + *p_ct = COAP_CT_APP_OCTET_STREAM; + break; + + case COAP_CT_MASK_APP_EXI: + *p_ct = COAP_CT_APP_EXI; + break; + + case COAP_CT_MASK_APP_JSON: + *p_ct = COAP_CT_APP_JSON; + break; + + default: + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + return NRF_SUCCESS; +} + +static uint32_t content_format_to_bit(coap_content_type_t ct) +{ + uint32_t mask = 0; + switch (ct) + { + case COAP_CT_PLAIN_TEXT: + mask = COAP_CT_MASK_PLAIN_TEXT; + break; + + case COAP_CT_APP_LINK_FORMAT: + mask = COAP_CT_MASK_APP_LINK_FORMAT; + break; + + case COAP_CT_APP_XML: + mask = COAP_CT_MASK_APP_XML; + break; + + case COAP_CT_APP_OCTET_STREAM: + mask = COAP_CT_MASK_APP_OCTET_STREAM; + break; + + case COAP_CT_APP_EXI: + mask = COAP_CT_MASK_APP_EXI; + break; + + case COAP_CT_APP_JSON: + mask = COAP_CT_MASK_APP_JSON; + break; + + default: + break; + } + + return mask; +} + +uint32_t coap_message_ct_mask_get(coap_message_t * p_message, uint32_t * p_mask) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_mask); + + (*p_mask) = 0; + + for (uint8_t index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_CONTENT_FORMAT) + { + uint32_t value; + uint32_t err_code = coap_opt_uint_decode(&value, + p_message->options[index].length, + p_message->options[index].p_data); + if (err_code == NRF_SUCCESS) + { + coap_content_type_t ct = (coap_content_type_t)value; + *p_mask |= content_format_to_bit(ct); + } + else + { + return err_code; + } + } + } + return NRF_SUCCESS; +} + +uint32_t coap_message_accept_mask_get(coap_message_t * p_message, uint32_t * p_mask) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_mask); + + (*p_mask) = 0; + + for (uint8_t index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_ACCEPT) + { + uint32_t value; + uint32_t err_code = coap_opt_uint_decode(&value, + p_message->options[index].length, + p_message->options[index].p_data); + if (err_code == NRF_SUCCESS) + { + coap_content_type_t ct = (coap_content_type_t)value; + (*p_mask) |= content_format_to_bit(ct); + } + else + { + return err_code; + } + } + } + + return NRF_SUCCESS; +} + +uint32_t coap_message_ct_match_select(coap_content_type_t * p_ct, coap_message_t * p_message, coap_resource_t * p_resource) +{ + // Check ACCEPT options + uint32_t accept_mask = 0; + (void)coap_message_accept_mask_get(p_message, &accept_mask); + + if (accept_mask == 0) + { + // Default to plain text if option not set. + accept_mask = COAP_CT_MASK_PLAIN_TEXT; + } + + // Select the first common content-type between the resource and the CoAP client. + uint32_t common_ct = p_resource->ct_support_mask & accept_mask; + uint32_t bit_index; + for (bit_index = 0; bit_index < 32; bit_index++) + { + if (((common_ct >> bit_index) & 0x1 ) == 1) + { + break; + } + } + + uint32_t err_code = bit_to_content_format(p_ct, 1 << bit_index); + + return err_code; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h new file mode 100644 index 0000000..efd226b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h @@ -0,0 +1,158 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_message.h + * + * @defgroup iot_sdk_coap_msg CoAP Message + * @ingroup iot_sdk_coap + * @{ + * @brief TODO. + */ + +#ifndef COAP_MESSAGE_H__ +#define COAP_MESSAGE_H__ + +#include <stdint.h> +#include "coap_api.h" +#include "coap_codes.h" +#include "coap_transport.h" +#include "coap_option.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define COAP_PAYLOAD_MARKER 0xFF + +/**@brief Create a new CoAP message. + * + * @details The function will allocate memory for the message internally and return + * a CoAP message structure. The callback provided will be called if a matching + * message ID/Token occurs in a response message. + * @param[out] p_message Pointer to set the generated coap_message_t structure to. + * @param[in] p_init_config Initial configuration parameters of the message to generate. + * + * @retval NRF_SUCCESS If memory for the new message was allocated and the + * initialization of the message went successfully. + * @retval NRF_ERROR_NULL Either the message or init_config parameter was NULL. + * @retval NRF_ERROR_INVALID_PARAM If port number in the port field is set to 0. + */ +uint32_t coap_message_create(coap_message_t * p_message, coap_message_conf_t * p_init_config); + +/**@brief Decode a message from a raw buffer. + * + * @details When the underlying transport layer receives a message, it has to + * be decoded into a CoAP message type structure. This functions returns + * a decoded message if decoding was successfully, or NULL otherwise. + * + * @param[out] p_message The generated coap_message_t after decoding the raw message. + * @param[in] p_raw_message Pointer to the encoded message memory buffer. + * @param[in] message_len Length of the p_raw_message. + * + * @retval NRF_SUCCESS If the decoding of the message succeeds. + * @retval NRF_ERROR_NULL If pointer to the p_message or p_raw_message were NULL. + * @retval NRF_ERROR_INVALID_LENGTH If the message is less than 4 bytes, not containing a + * full header. + * @retval COAP_MESSAGE_INVALID_CONTENT If the message could not be decoded successfully. This + * could happen if message length provided is larger than + * what is possible to decode (ex. missing payload marker). + * + */ +uint32_t coap_message_decode(coap_message_t * p_message, + const uint8_t * p_raw_message, + uint16_t message_len); + +/**@brief Encode a CoAP message into a byte buffer. + * + * @details This functions has two operations. One is the actual encoding into a + * byte buffer. The other is to query the size of a potential encoding. + * If p_buffer variable is omitted, the return value will be the size of a + * potential serialized message. This can be used to get some persistent memory from + * transport layer. The message have to be kept until all potential + * retransmissions has been attempted. + * + * The p_message can be deleted after this point if the function succeeds. + * + * @param[in] p_message Message to encode. + * @param[in] p_buffer Pointer to the byte buffer where to put the encoded message. + * @param[inout] p_length Length of the provided byte buffer passed in by reference. + * If the value 0 is supplied, the encoding will not take place, + * but only the dry run calculating the expected length of the + * encoded message. + * + * @retval NRF_SUCCESS If the encoding of the message succeeds. + * @retval NRF_ERROR_NULL If message or length parameter is NULL pointer. + * @retval NRF_ERROR_NO_MEM If the provided buffer is not sufficient for + * the encoded message. + * @retval COAP_MESSAGE_ERROR_NULL If the message has indicated the length of data, + * but memory pointer is NULL. + */ +uint32_t coap_message_encode(coap_message_t * p_message, + uint8_t * p_buffer, + uint16_t * p_length); + +/**@brief Get the content format mask of the message. + * + * @param[in] p_message Pointer to the message which to generate the content format mask from. + * Should not be NULL. + * @param[out] p_mask Value by reference to the variable to fill the result mask into. + * + * @retval NRF_SUCCESS If the mask could be generated. + * @retval NRF_ERROR_NULL If the message pointer or the mask pointer given was NULL. + */ +uint32_t coap_message_ct_mask_get(coap_message_t * p_message, uint32_t * p_mask); + +/**@brief Get the accept mask of the message. + * + * @param[in] p_message Pointer to the message which to generate the accept mask from. + * Should not be NULL. + * @param[out] p_mask Value by reference to the variable to fill the result mask into. + * + * @retval NRF_SUCCESS If the mask could be generated. + * @retval NRF_ERROR_NULL If the message pointer or the mask pointer given was NULL. + */ +uint32_t coap_message_accept_mask_get(coap_message_t * p_message, uint32_t * p_mask); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_MESSAGE_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c new file mode 100644 index 0000000..b4c60aa --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c @@ -0,0 +1,688 @@ +/** + * Copyright (c) 2014 - 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 "coap_observe_api.h" +#include "coap_observe.h" +#include "nrf_error.h" +#include "iot_common.h" +#include "sdk_common.h" +#include "sdk_config.h" +#include "coap.h" + +#if IOT_COAP_CONFIG_LOG_ENABLED + +#define NRF_LOG_MODULE_NAME coapobs + +#define NRF_LOG_LEVEL IOT_COAP_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR IOT_COAP_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR IOT_COAP_CONFIG_DEBUG_COLOR + +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define COAP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */ +#define COAP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */ +#define COAP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */ + +#define COAP_ENTRY() COAP_TRC(">> %s", __func__) +#define COAP_EXIT() COAP_TRC("<< %s", __func__) + +#else // IOT_COAP_CONFIG_LOG_ENABLED + +#define COAP_TRC(...) /**< Disables traces. */ +#define COAP_DUMP(...) /**< Disables dumping of octet streams. */ +#define COAP_ERR(...) /**< Disables error logs. */ + +#define COAP_ENTRY(...) +#define COAP_EXIT(...) + +#endif // IOT_COAP_CONFIG_LOG_ENABLED + +#if (COAP_ENABLE_OBSERVE_SERVER == 1) +static coap_observer_t m_observers[COAP_OBSERVE_MAX_NUM_OBSERVERS]; + +static void observe_server_init(void) +{ + COAP_ENTRY(); + + // Loop through the observer array and clear the memory. + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++) + { + memset(&m_observers[i], 0, sizeof(coap_observer_t)); + } + + COAP_EXIT(); +} + +uint32_t internal_coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer) +{ + COAP_ENTRY(); + + NULL_PARAM_CHECK(p_handle); + NULL_PARAM_CHECK(p_observer); + + NULL_PARAM_MEMBER_CHECK(p_observer->p_resource_of_interest); + + // Check if there is already a registered observer in the list to be reused. + uint32_t handle; + uint32_t err_code = coap_observe_server_search(&handle, + &p_observer->remote, + p_observer->p_resource_of_interest); + if (err_code == NRF_SUCCESS) + { + memcpy(&m_observers[handle], p_observer, sizeof(coap_observer_t)); + *p_handle = handle; + return NRF_SUCCESS; + } + + // Check if there is an available spot in the observer list. + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++) + { + if (m_observers[i].p_resource_of_interest == NULL) + { + memcpy(&m_observers[i], p_observer, sizeof(coap_observer_t)); + + *p_handle = i; + return NRF_SUCCESS; + } + } + + + COAP_EXIT(); + + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); +} + + +uint32_t internal_coap_observe_server_unregister(uint32_t handle) +{ + COAP_ENTRY(); + + if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVERS) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + if (m_observers[handle].p_resource_of_interest == NULL) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + m_observers[handle].p_resource_of_interest = NULL; + + COAP_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t internal_coap_observe_server_search(uint32_t * p_handle, + coap_remote_t * p_observer_addr, + coap_resource_t * p_resource) +{ + NULL_PARAM_CHECK(p_handle); + NULL_PARAM_CHECK(p_observer_addr); + NULL_PARAM_CHECK(p_resource); + + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++) + { + if (m_observers[i].p_resource_of_interest == p_resource) + { + if (m_observers[i].remote.port_number == p_observer_addr->port_number) + { + if (memcmp(p_observer_addr->addr, m_observers[i].remote.addr, sizeof(p_observer_addr->addr)) == 0) + { + *p_handle = i; + return NRF_SUCCESS; + } + } + } + } + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + + +uint32_t internal_coap_observe_server_next_get(coap_observer_t ** pp_observer, + coap_observer_t * p_observer, + coap_resource_t * p_resource) +{ + NULL_PARAM_CHECK(p_resource); + NULL_PARAM_CHECK(pp_observer); + + if (p_observer == NULL) + { + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++) + { + if (m_observers[i].p_resource_of_interest == p_resource) + { + (*pp_observer) = &m_observers[i]; + return NRF_SUCCESS; + } + } + } + else + { + uint32_t index_to_previous = (uint8_t)(((uint32_t)p_observer - (uint32_t)m_observers) / (uint32_t)sizeof(coap_observer_t)); + + for (uint32_t i = index_to_previous + 1; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++) + { + if (m_observers[i].p_resource_of_interest == p_resource) + { + (*pp_observer) = &m_observers[i]; + return NRF_SUCCESS; + } + } + } + (*pp_observer) = NULL; + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +uint32_t internal_coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer) +{ + NULL_PARAM_CHECK(pp_observer); + + if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVERS) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + if (m_observers[handle].p_resource_of_interest == NULL) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + *pp_observer = &m_observers[handle]; + return NRF_SUCCESS; +} +#else +#define observe_server_init(...) +#endif + +#if (COAP_ENABLE_OBSERVE_CLIENT == 1) +static coap_observable_t m_observables[COAP_OBSERVE_MAX_NUM_OBSERVABLES]; + +static void observe_client_init(void) +{ + // Loop through the observable array and clear the memory. + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++) + { + memset(&m_observables[i], 0, sizeof(coap_observable_t)); + } +} + + +uint32_t internal_coap_observe_client_register(uint32_t * p_handle, + coap_observable_t * p_observable) +{ + COAP_ENTRY(); + + NULL_PARAM_CHECK(p_handle); + NULL_PARAM_CHECK(p_observable); + + NULL_PARAM_MEMBER_CHECK(p_observable->response_callback); + + // Check if there is an available spot in the observer list. + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++) + { + if (m_observables[i].response_callback == NULL) + { + memcpy(&m_observables[i], p_observable, sizeof(coap_observable_t)); + *p_handle = i; + return NRF_SUCCESS; + } + } + + COAP_EXIT(); + + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); +} + + +uint32_t internal_coap_observe_client_unregister(uint32_t handle) +{ + COAP_ENTRY(); + + if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVABLES) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + if (m_observables[handle].response_callback == NULL) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + m_observables[handle].response_callback = NULL; + + COAP_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t internal_coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len) +{ + NULL_PARAM_CHECK(p_handle); + NULL_PARAM_CHECK(p_token); + + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++) + { + if ((m_observables[i].response_callback != NULL) && + (0 != m_observables[i].token_len) && + (memcmp(m_observables[i].token, p_token, m_observables[i].token_len) == 0)) + { + *p_handle = i; + return NRF_SUCCESS; + } + } + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + + +uint32_t internal_coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable) +{ + NULL_PARAM_CHECK(pp_observable); + + if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVABLES) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + if (m_observables[handle].response_callback == NULL) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + *pp_observable = &m_observables[handle]; + + return NRF_SUCCESS; +} + +uint32_t internal_coap_observe_client_next_get(coap_observable_t ** pp_observable, + uint32_t * p_handle, + coap_observable_t * p_observable) +{ + NULL_PARAM_CHECK(pp_observable); + + if (p_observable == NULL) + { + for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++) + { + if (m_observables[i].response_callback != NULL) + { + (*pp_observable) = &m_observables[i]; + (*p_handle) = i; + return NRF_SUCCESS; + } + } + } + else + { + uint32_t index_to_previous = (uint8_t)(((uint32_t)p_observable - (uint32_t)m_observables) / (uint32_t)sizeof(coap_observable_t)); + + for (uint32_t i = index_to_previous + 1; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++) + { + if (m_observables[i].response_callback != NULL) + { + (*pp_observable) = &m_observables[i]; + (*p_handle) = i; + return NRF_SUCCESS; + } + } + } + (*pp_observable) = NULL; + + COAP_MUTEX_UNLOCK(); + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +static uint32_t observe_opt_present(coap_message_t * p_message) +{ + uint8_t index; + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_OBSERVE) + { + return NRF_SUCCESS; + } + } + return NRF_ERROR_NOT_FOUND; +} + +static void set_max_age(coap_observable_t * observable, coap_message_t * p_response) +{ + uint8_t index; + for (index = 0; index < p_response->options_count; index++) + { + if (p_response->options[index].number == COAP_OPT_MAX_AGE) + { + uint32_t max_age; + observable->max_age = coap_opt_uint_decode(&max_age, + p_response->options[index].length, + p_response->options[index].p_data); + observable->max_age = max_age; + return; + } + } + + // Max-Age option is not present, set default value to 60. + observable->max_age = 60; +} + +void coap_observe_client_send_handle(coap_message_t * p_request) +{ + COAP_ENTRY(); + + if (p_request->header.code == COAP_CODE_GET) + { + uint32_t observe_option = 0; + if (observe_opt_present(p_request) == NRF_SUCCESS) + { + // Locate option and check value. + uint8_t index; + for (index = 0; index < p_request->options_count; index++) + { + if (p_request->options[index].number == COAP_OPT_OBSERVE) + { + uint32_t err_code = coap_opt_uint_decode(&observe_option, + p_request->options[index].length, + p_request->options[index].p_data); + if (err_code != NRF_SUCCESS) + { + return; + } + break; + } + } + } + + if (observe_option == 1) + { + // Un-register observable instance. + uint32_t handle; + uint32_t err_code = internal_coap_observe_client_search(&handle, + p_request->token, + p_request->header.token_len); + if (err_code == NRF_SUCCESS) + { + (void)internal_coap_observe_client_unregister(handle); + COAP_TRC("OBSERVE=1 in request, client_unregister handle: %i", handle); + + } + } + } + + COAP_EXIT(); +} + +void coap_observe_client_response_handle(coap_message_t * p_response, coap_queue_item_t * p_item) +{ + COAP_ENTRY(); + + if (observe_opt_present(p_response) == NRF_SUCCESS) + { + if (p_item == NULL) + { + // Search for the token in the observable list. + uint32_t handle; + uint32_t err_code = internal_coap_observe_client_search(&handle, p_response->token, p_response->header.token_len); + if (err_code == NRF_SUCCESS) + { + // Fetch the observable. + coap_observable_t * p_observable; + err_code = internal_coap_observe_client_get(handle, &p_observable); + if (err_code == NRF_SUCCESS) + { + // Update max-age to the newly recieved message. + set_max_age(p_observable, p_response); + + COAP_MUTEX_UNLOCK(); + + // Callback to the application. + p_observable->response_callback(NRF_SUCCESS, NULL, p_response); + + COAP_MUTEX_LOCK(); + + COAP_TRC("Notification received on handle: %i", handle); + + #ifdef COAP_AUTOMODE + if (p_response->header.type == COAP_TYPE_CON) + { + // Reply an ACK upon CON message. + } + else if (p_response->header.type == COAP_TYPE_RST) + { + // Remove observable from list. + } + #endif + } + else + { + #ifdef COAP_AUTOMODE + if (p_response->header.type == COAP_TYPE_CON) + { + // Reply reset upon CON message when observer is not located. + } + #endif + } + } + else + { + // Send RST message back to server to indicate there is no one listening. + } + } + else // p_item set. + { + // If there is no observable instance created yet for thit token, add it. + uint32_t handle; + uint32_t err_code = internal_coap_observe_client_search(&handle, p_response->token, p_response->header.token_len); + if (err_code == (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE)) + { + // If the response is a valid response, add the observable resource. + if (p_response->header.code == COAP_CODE_205_CONTENT) + { + coap_observable_t observable; + // Token Length. + observable.token_len = p_response->header.token_len; + // Remote. + memcpy(&observable.remote, &p_response->remote, sizeof(coap_remote_t)); + // Token. + memcpy(observable.token, p_response->token, observable.token_len); + // Callback to be called upon notification. + observable.response_callback = p_item->callback; + + // Update max-age to the newly recieved message. + set_max_age(&observable, p_response); + + // Register the observable. + uint32_t observable_resource_handle; + (void)internal_coap_observe_client_register(&observable_resource_handle, &observable); + // TODO: error check + + COAP_TRC("Subscription response received, client_register handle: %i", observable_resource_handle); + } + } + } + } + else // COAP_OPT_OBSERVE not present + { + uint32_t handle; + uint32_t err_code = internal_coap_observe_client_search(&handle, p_response->token, p_response->header.token_len); + if (err_code == NRF_SUCCESS) + { + (void)internal_coap_observe_client_unregister(handle); + COAP_TRC("OBSERVE not present in notification, client_unregister handle: %i", handle); + } + } + + COAP_EXIT(); +} +#else +#define observe_client_init(...) +#endif + +void internal_coap_observe_init(void) +{ + observe_server_init(); + observe_client_init(); +} + +#if (COAP_ENABLE_OBSERVE_SERVER == 1) + +uint32_t coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_server_register(p_handle, p_observer); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_server_unregister(uint32_t handle) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_server_unregister(handle); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_server_search(uint32_t * p_handle, coap_remote_t * p_observer_addr, coap_resource_t * p_resource) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_server_search(p_handle, p_observer_addr, p_resource); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_server_next_get(coap_observer_t ** pp_observer, coap_observer_t * p_observer, coap_resource_t * p_resource) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_server_next_get(pp_observer, p_observer, p_resource); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_server_get(handle, pp_observer); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +#endif // COAP_ENABLE_OBSERVE_SERVER = 1 + +#if (COAP_ENABLE_OBSERVE_CLIENT == 1) + +uint32_t coap_observe_client_register(uint32_t * p_handle, coap_observable_t * p_observable) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_client_register(p_handle, p_observable); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_client_unregister(uint32_t handle) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_client_unregister(handle); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_client_search(p_handle, p_token, token_len); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_client_get(handle, pp_observable); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_observe_client_next_get(coap_observable_t ** pp_observable, uint32_t * p_handle, coap_observable_t * p_observable) +{ + COAP_MUTEX_UNLOCK(); + + uint32_t err_code = internal_coap_observe_client_next_get(pp_observable, p_handle, p_observable); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +#endif // COAP_ENABLE_OBSERVE_CLIENT == 1 diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h new file mode 100644 index 0000000..bb72b89 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h @@ -0,0 +1,248 @@ +/** + * 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. + * + */ +/** @file coap_observe.h + * + * @defgroup iot_sdk_coap_observe CoAP Observe + * @ingroup iot_sdk_coap + * @{ + * @brief Internal API of Nordic's CoAP Observe implementation. + */ +#ifndef COAP_OBSERVE_H__ +#define COAP_OBSERVE_H__ + +#include <stdint.h> + +#include "coap_observe_api.h" +#include "coap_api.h" +#include "coap_queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@cond NO_DOXYGEN */ + +/**@brief Register a new observer. + * + * @param[out] p_handle Handle to the observer instance registered. Returned by reference. + * Should not be NULL. + * @param[in] p_observer Pointer to the observer structure to register. The data will be + * copied. Should not be NULL. + * + * @retval NRF_SUCCESS If the observer was registered successfully. + * @retval NRF_ERROR_NO_MEM If the observer could not be added to the list. + * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer. + */ +uint32_t internal_coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer); + +/**@brief Unregister an observer. + * + * @details Unregister the observer and clear the memory used by this instance. + * + * @param[in] handle Handle to the observer instance registered. + * + * @retval NRF_SUCCESS If the observer was successfully unregistered. + * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observer list. + */ +uint32_t internal_coap_observe_server_unregister(uint32_t handle); + +/**@brief Search the observer list for an observer matching remote address and subject given. + * + * @param[out] p_handle Handle to the observer instance registered. Returned by reference. + * Should not be NULL. + * @param[in] p_observer_addr Pointer to an address structure giving remote address of the observer and port number. + * Should not be NULL. + * @param[in] p_resource Pointer to the resource the observer is registered to. Should not be NULL. + * + * @retval NRF_SUCCESS If observer was found in the observer list. + * @retval NRF_ERROR_NULL If one of the pointers are NULL. + * @retval NRF_ERROR_NOT_FOUND If observer was not found. + */ +uint32_t internal_coap_observe_server_search(uint32_t * p_handle, coap_remote_t * p_observer_addr, coap_resource_t * p_resource); + +/**@brief Iterate through observers subscribing to a specific resource. + * + * @param[out] pp_observer Pointer to be filled by the search function upon finding the next observer starting from + * from the p_observer pointer provided. Should not be NULL. + * @param[in] p_observer Pointer to the observer where to start the search. + * @param[in] p_resource Pointer to the resource of interest. Should not be NULL. + * + * @retval NRF_SUCCESS If observer was found. + * @retval NRF_ERROR_NULL If pp_observer or p_resource pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If next observer was not found. + */ +uint32_t internal_coap_observe_server_next_get(coap_observer_t ** pp_observer, coap_observer_t * p_observer, coap_resource_t * p_resource); + +/**@brief Retrieve the observer based on handle. + * + * @param[in] handle Handle to the coap_observer_t instance. + * @param[out] pp_observer Pointer to an observer return by reference. + * Should not be NULL. + * + * @retval NRF_SUCCESS If observer was found in the observer list. + * @retval NRF_ERROR_NULL If pp_observer pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If observer associated with the handle was not found. + */ +uint32_t internal_coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer); + +/**@brief Register a new observable resource. + * + * @param[out] p_handle Handle to the observable resource instance registered. Returned by + * reference. Should not be NULL. + * @param[in] p_observable Pointer to a observable resource structure to register. The structure + * will be copied. Should not be NULL. + * + * @retval NRF_SUCCESS If the observable resource was registered successfully. + * @retval NRF_ERROR_NO_MEM If the observable resource could not be added to the list. + * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer. + */ +uint32_t internal_coap_observe_client_register(uint32_t * p_handle, coap_observable_t * p_observable); + +/**@brief Unregister an observable resource. + * + * @details Unregister the observable resource and clear the memory used by this instance. + * + * @param[in] handle Handle to the observable resource instance registered. + * + * @retval NRF_SUCCESS If the observable resource was successfully unregistered. + * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observable + * resource list. + */ +uint32_t internal_coap_observe_client_unregister(uint32_t handle); + +/**@brief Search for a observable resource instance by token. + * + * @param[out] p_handle Handle to the observable resource instance registered. Returned by + * reference. Should not be NULL. + * @param[in] p_token Pointer to the byte array holding the token id. Should not be NULL. + * @param[in] token_len Length of the token. + * + * @retval NRF_SUCCESS If observable resource was found in the observable + * resource list. + * @retval NRF_ERROR_NULL If one of the pointers are NULL. + * @retval NRF_ERROR_NOT_FOUND If observable resource was not found in the observable + * resource list. + */ +uint32_t internal_coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len); + +/**@brief Retrieve the observable resource based on handle. + * + * @param[in] handle Handle to the coap_observable_t instance. + * @param[out] pp_observable Pointer to an observable resource return by reference. + * Should not be NULL. + * + * @retval NRF_SUCCESS If observable resource was found in the observable + * resource list. + * @retval NRF_ERROR_NULL If pp_observable pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If observable resource associated with the handle + * was not found. + */ +uint32_t internal_coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable); + +/**@brief Iterate through observable resources. + * + * @param[out] pp_observable Pointer to be filled by the search function upon finding the next + * observable resource starting from from the pointer provided. + * Should not be NULL. + * @param[out] p_handle Handler to the observable resource found returned by reference. Should + * not be NULL. + * @param[in] p_observable Pointer to the observable resource where to start the search. + * + * @retval NRF_SUCCESS If observer was found. + * @retval NRF_ERROR_NULL If pp_observer or p_observer pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If next observer was not found. + */ +uint32_t internal_coap_observe_client_next_get(coap_observable_t ** pp_observable, uint32_t * p_handle, coap_observable_t * p_observable); + + +#if (COAP_ENABLE_OBSERVE_SERVER == 1) || (COAP_ENABLE_OBSERVE_CLIENT == 1) + +/**@brief Internal function to initilize observer (client) and observable (server) lists. + * + * @retval NRF_SUCCESS If initialization was successful. + */ +void internal_coap_observe_init(void); + +#else // COAP_ENABLE_OBSERVE_SERVER || COAP_ENABLE_OBSERVE_CLIENT + +#define internal_coap_observe_init(...) + +#endif // COAP_ENABLE_OBSERVE_SERVER || COAP_ENABLE_OBSERVE_CLIENT + +#if (COAP_ENABLE_OBSERVE_CLIENT == 1) + +/**@brief Observe client function to be run when sending requests. + * + * @details The function will peek into the outgoing messages to see if any actions regarding + * subscription to observable resources has to be done. + * + * @param[in] p_request Pointer to the outgoing request. + */ +void coap_observe_client_send_handle(coap_message_t * p_request); + +/**@brief Observe client function to be run when response message has been received. + * + * @details The function will register and unregister observable resources based on the received + * response messages. Upon a notification max-age values will be updated, and the correct + * response callback will be called. If a notification is terminated by the peer, the function + * will automatically terminate the subscription from the client by unregistering the + * observable resource. + * + * @param[in] p_response Pointer to the response message received. + * @param[in] p_item Pointer to the queued element of the outgoing request. + */ +void coap_observe_client_response_handle(coap_message_t * p_response, coap_queue_item_t * p_item); + +#else // COAP_ENABLE_OBSERVE_CLIENT + +#define coap_observe_client_send_handle(...) +#define coap_observe_client_response_handle(...) + +#endif // COAP_ENABLE_OBSERVE_CLIENT + +/**@endcond */ + +#ifdef __cplusplus +} +#endif + +#endif // COAP_OBSERVE_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h new file mode 100644 index 0000000..3075e88 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h @@ -0,0 +1,222 @@ +/** + * 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. + * + */ +/** @file coap_observe_api.h + * + * @defgroup iot_sdk_coap_observe CoAP Observe + * @ingroup iot_sdk_coap + * @{ + * @brief Public API of Nordic's CoAP Observe implementation. + */ +#ifndef COAP_OBSERVE_API_H__ +#define COAP_OBSERVE_API_H__ + +#include <stdint.h> +#include "coap_api.h" +#include "coap_transport.h" +#include "coap_queue.h" +#include "compiler_abstraction.h" +#include "sdk_errors.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define COAP_OPT_OBSERVE 6 /**< Observe option number. */ + +/**@brief Struct for CoAP Server for holding an instance of a remote observer. */ +typedef struct +{ + coap_remote_t remote; /**< Remote address and port number. */ + uint8_t token[8]; /**< Message Token ID. */ + uint8_t token_len; /**< Length of the token. */ + coap_content_type_t ct; /**< Content type to use when sending notifications. */ + coap_resource_t * p_resource_of_interest; /**< Pointer to the resource of interest. */ +} coap_observer_t; + +/**@brief Struct for CoAP Client for holding an instance of a remote observable resource. */ +typedef struct +{ + coap_remote_t remote; /**< Remote address and port number. */ + uint8_t token[8]; /**< Message Token ID. */ + uint8_t token_len; /**< Length of the token. */ + coap_response_callback_t response_callback; /**< Function callback set by the application to be called when a notifications has been received. Should be set by the application. */ + uint32_t max_age; /**< Max-Age of the observable resources value. If timed out, the value is no longer valid as a representation of the observable resource. */ +} coap_observable_t; + + +/**@brief Register a new observer. + * + * @param[out] p_handle Handle to the observer instance registered. Returned by reference. + * Should not be NULL. + * @param[in] p_observer Pointer to the observer structure to register. The data will be + * copied. Should not be NULL. + * + * @retval NRF_SUCCESS If the observer was registered successfully. + * @retval NRF_ERROR_NO_MEM If the observer could not be added to the list. + * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer. + */ +uint32_t coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer); + +/**@brief Unregister an observer. + * + * @details Unregister the observer and clear the memory used by this instance. + * + * @param[in] handle Handle to the observer instance registered. + * + * @retval NRF_SUCCESS If the observer was successfully unregistered. + * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observer list. + */ +uint32_t coap_observe_server_unregister(uint32_t handle); + +/**@brief Search the observer list for an observer matching remote address and subject given. + * + * @param[out] p_handle Handle to the observer instance registered. Returned by reference. + * Should not be NULL. + * @param[in] p_observer_addr Pointer to an address structure giving remote address of the observer and port number. + * Should not be NULL. + * @param[in] p_resource Pointer to the resource the observer is registered to. Should not be NULL. + * + * @retval NRF_SUCCESS If observer was found in the observer list. + * @retval NRF_ERROR_NULL If one of the pointers are NULL. + * @retval NRF_ERROR_NOT_FOUND If observer was not found. + */ +uint32_t coap_observe_server_search(uint32_t * p_handle, coap_remote_t * p_observer_addr, coap_resource_t * p_resource); + +/**@brief Iterate through observers subscribing to a specific resource. + * + * @param[out] pp_observer Pointer to be filled by the search function upon finding the next observer starting from + * from the p_observer pointer provided. Should not be NULL. + * @param[in] p_observer Pointer to the observer where to start the search. + * @param[in] p_resource Pointer to the resource of interest. Should not be NULL. + * + * @retval NRF_SUCCESS If observer was found. + * @retval NRF_ERROR_NULL If pp_observer or p_resource pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If next observer was not found. + */ +uint32_t coap_observe_server_next_get(coap_observer_t ** pp_observer, coap_observer_t * p_observer, coap_resource_t * p_resource); + +/**@brief Retrieve the observer based on handle. + * + * @param[in] handle Handle to the coap_observer_t instance. + * @param[out] pp_observer Pointer to an observer return by reference. + * Should not be NULL. + * + * @retval NRF_SUCCESS If observer was found in the observer list. + * @retval NRF_ERROR_NULL If pp_observer pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If observer associated with the handle was not found. + */ +uint32_t coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer); + +/**@brief Register a new observable resource. + * + * @param[out] p_handle Handle to the observable resource instance registered. Returned by + * reference. Should not be NULL. + * @param[in] p_observable Pointer to a observable resource structure to register. The structure + * will be copied. Should not be NULL. + * + * @retval NRF_SUCCESS If the observable resource was registered successfully. + * @retval NRF_ERROR_NO_MEM If the observable resource could not be added to the list. + * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer. + */ +uint32_t coap_observe_client_register(uint32_t * p_handle, coap_observable_t * p_observable); + +/**@brief Unregister an observable resource. + * + * @details Unregister the observable resource and clear the memory used by this instance. + * + * @param[in] handle Handle to the observable resource instance registered. + * + * @retval NRF_SUCCESS If the observable resource was successfully unregistered. + * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observable + * resource list. + */ +uint32_t coap_observe_client_unregister(uint32_t handle); + +/**@brief Search for a observable resource instance by token. + * + * @param[out] p_handle Handle to the observable resource instance registered. Returned by + * reference. Should not be NULL. + * @param[in] p_token Pointer to the byte array holding the token id. Should not be NULL. + * @param[in] token_len Length of the token. + * + * @retval NRF_SUCCESS If observable resource was found in the observable + * resource list. + * @retval NRF_ERROR_NULL If one of the pointers are NULL. + * @retval NRF_ERROR_NOT_FOUND If observable resource was not found in the observable + * resource list. + */ +uint32_t coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len); + +/**@brief Retrieve the observable resource based on handle. + * + * @param[in] handle Handle to the coap_observable_t instance. + * @param[out] pp_observable Pointer to an observable resource return by reference. + * Should not be NULL. + * + * @retval NRF_SUCCESS If observable resource was found in the observable + * resource list. + * @retval NRF_ERROR_NULL If pp_observable pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If observable resource associated with the handle + * was not found. + */ +uint32_t coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable); + +/**@brief Iterate through observable resources. + * + * @param[out] pp_observable Pointer to be filled by the search function upon finding the next + * observable resource starting from from the pointer provided. + * Should not be NULL. + * @param[out] p_handle Handler to the observable resource found returned by reference. Should + * not be NULL. + * @param[in] p_observable Pointer to the observable resource where to start the search. + * + * @retval NRF_SUCCESS If observer was found. + * @retval NRF_ERROR_NULL If pp_observer or p_observer pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If next observer was not found. + */ +uint32_t coap_observe_client_next_get(coap_observable_t ** pp_observable, uint32_t * p_handle, coap_observable_t * p_observable); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_OBSERVE_API_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c new file mode 100644 index 0000000..0ae74be --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c @@ -0,0 +1,182 @@ +/** + * Copyright (c) 2014 - 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 <stdlib.h> +#include <string.h> + +#include "coap_option.h" +#include "iot_common.h" + +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } + +#else + +#define NULL_PARAM_CHECK(PARAM) + +#endif // COAP_DISABLE_API_PARAM_CHECK + +uint32_t coap_opt_string_encode(uint8_t * p_encoded, uint16_t * p_length, uint8_t * p_string, uint16_t str_len) +{ + NULL_PARAM_CHECK(p_encoded); + NULL_PARAM_CHECK(p_length); + NULL_PARAM_CHECK(p_string); + + if (str_len > *p_length) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + memcpy(p_encoded, p_string, str_len); + + *p_length = str_len; + + return NRF_SUCCESS; +} + +uint32_t coap_opt_string_decode(uint8_t * p_string, uint16_t * p_length, uint8_t * p_encoded) +{ + return NRF_SUCCESS; +} + +uint32_t coap_opt_uint_encode(uint8_t * p_encoded, uint16_t * p_length, uint32_t data) +{ + NULL_PARAM_CHECK(p_encoded); + NULL_PARAM_CHECK(p_length); + + uint16_t byte_index = 0; + + if (data <= UINT8_MAX) + { + if (*p_length < sizeof(uint8_t)) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + p_encoded[byte_index++] = (uint8_t)data; + } + else if (data <= UINT16_MAX) + { + if (*p_length < sizeof(uint16_t)) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + p_encoded[byte_index++] = (uint8_t)((data & 0xFF00) >> 8); + p_encoded[byte_index++] = (uint8_t)(data & 0x00FF); + } + else + { + if (*p_length < sizeof(uint32_t)) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + p_encoded[byte_index++] = (uint8_t)((data & 0xFF000000) >> 24); + p_encoded[byte_index++] = (uint8_t)((data & 0x00FF0000) >> 16); + p_encoded[byte_index++] = (uint8_t)((data & 0x0000FF00) >> 8); + p_encoded[byte_index++] = (uint8_t)(data & 0x000000FF); + } + + + + *p_length = byte_index; + + return NRF_SUCCESS; +} + +uint32_t coap_opt_uint_decode(uint32_t * p_data, uint16_t length, uint8_t * p_encoded) +{ + NULL_PARAM_CHECK(p_data); + NULL_PARAM_CHECK(p_encoded); + + uint8_t byte_index = 0; + switch (length) + { + case 0: + { + *p_data = 0; + } + break; + + case 1: + { + *p_data = 0; + *p_data |= p_encoded[byte_index++]; + } + break; + + case 2: + { + *p_data = 0; + *p_data |= (p_encoded[byte_index++] << 8); + *p_data |= (p_encoded[byte_index++]); + } + break; + + case 3: + { + *p_data = 0; + *p_data |= (p_encoded[byte_index++] << 16); + *p_data |= (p_encoded[byte_index++] << 8); + *p_data |= (p_encoded[byte_index++]); + } + break; + + case 4: + { + *p_data = 0; + *p_data |= (p_encoded[byte_index++] << 24); + *p_data |= (p_encoded[byte_index++] << 16); + *p_data |= (p_encoded[byte_index++] << 8); + *p_data |= (p_encoded[byte_index++]); + } + break; + + default: + return (NRF_ERROR_INVALID_LENGTH | IOT_COAP_ERR_BASE); + } + + return NRF_SUCCESS; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h new file mode 100644 index 0000000..3d5c5d9 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_option.h + * + * @defgroup iot_sdk_coap_option CoAP Option + * @ingroup iot_sdk_coap + * @{ + * @brief Nordic's CoAP Option APIs. + */ + +#ifndef COAP_OPTION_H__ +#define COAP_OPTION_H__ + +/* + +-----+---+---+---+---+----------------+--------+--------+----------+ + | No. | C | U | N | R | Name | Format | Length | Default | + +-----+---+---+---+---+----------------+--------+--------+----------+ + | 1 | x | | | x | If-Match | opaque | 0-8 | (none) | + | 3 | x | x | - | | Uri-Host | string | 1-255 | (see | + | | | | | | | | | below) | + | 4 | | | | x | ETag | opaque | 1-8 | (none) | + | 5 | x | | | | If-None-Match | empty | 0 | (none) | + | 7 | x | x | - | | Uri-Port | uint | 0-2 | (see | + | | | | | | | | | below) | + | 8 | | | | x | Location-Path | string | 0-255 | (none) | + | 11 | x | x | - | x | Uri-Path | string | 0-255 | (none) | + | 12 | | | | | Content-Format | uint | 0-2 | (none) | + | 14 | | x | - | | Max-Age | uint | 0-4 | 60 | + | 15 | x | x | - | x | Uri-Query | string | 0-255 | (none) | + | 17 | x | | | | Accept | uint | 0-2 | (none) | + | 20 | | | | x | Location-Query | string | 0-255 | (none) | + | 23 | x | x | - | - | Block2 | uint | 0-3 | (none) | + | 27 | x | x | - | - | Block1 | uint | 0-3 | (none) | + | 28 | | | x | | Size2 | uint | 0-4 | (none) | + | 35 | x | x | - | | Proxy-Uri | string | 1-1034 | (none) | + | 39 | x | x | - | | Proxy-Scheme | string | 1-255 | (none) | + | 60 | | | x | | Size1 | uint | 0-4 | (none) | + +-----+---+---+---+---+----------------+--------+--------+----------+ +*/ + +#include <stdint.h> +#include "coap_api.h" +#include "nrf_error.h" +#include "sdk_errors.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum +{ + COAP_OPT_FORMAT_EMPTY = 0, + COAP_OPT_FORMAT_STRING = 1, + COAP_OPT_FORMAT_OPAQUE = 2, + COAP_OPT_FORMAT_UINT = 3 + +} coap_opt_format_t; + + +/**@brief Encode zero-terminated string into utf-8 encoded string. + * + * @param[out] p_encoded Pointer to buffer that will be used to fill the + * encoded string into. + * @param[inout] p_length Length of the buffer provided. Will also be used to + * return the size of the used buffer. + * @param[in] p_string String to encode. + * @param[in] str_len Length of the string to encode. + * + * @retval NRF_SUCCESS Indicates that encoding was successful. + * @retval NRF_ERROR_DATA_SIZE Indicates that the buffer provided was not sufficient to + * successfully encode the data. + */ +uint32_t coap_opt_string_encode(uint8_t * p_encoded, uint16_t * p_length, uint8_t * p_string, uint16_t str_len); + +/**@brief Decode a utf-8 string into a zero-terminated string. + * + * @param[out] p_string Pointer to the string buffer where the decoded + * string will be placed. + * @param[inout] p_length p_length of the encoded string. Returns the size of the buffer + * used in bytes. + * @param[in] p_encoded Buffer to decode. + * + * @retval NRF_SUCCESS Indicates that decoding was successful. + * @retval NRF_ERROR_DATA_SIZE Indicates that the buffer provided was not sufficient to + * successfully dencode the data. + */ +uint32_t coap_opt_string_decode(uint8_t * p_string, uint16_t * p_length, uint8_t * p_encoded); + +/**@brief Encode a uint value into a uint8_t buffer in network byte order. + * + * @param[out] p_encoded Pointer to buffer that will be used to fill the + * encoded uint into. + * @param[inout] p_length Length of the buffer provided. Will also be used to + * return the size of the used buffer. + * @param[in] data uint value which could be anything from 1 to 4 bytes. + * + * @retval NRF_SUCCESS Indicates that encoding was successful. + * @retval NRF_ERROR_DATA_SIZE Indicates that the buffer provided was not sufficient to + * successfully encode the data. + */ +uint32_t coap_opt_uint_encode(uint8_t * p_encoded, uint16_t * p_length, uint32_t data); + +/**@brief Decode a uint encoded value in network byte order to a uint32_t value. + * + * @param[out] p_data Pointer to the uint32_t value where the decoded uint will + * be placed. + * @param[inout] length Size of the encoded value. + * @param[in] p_encoded uint value to be decoded into a uint32_t value. + * + * @retval NRF_SUCCESS Indicates that decoding was successful. + * @retval NRF_ERROR_NULL If p_data or p_encoded pointer is NULL. + * @retval NRF_ERROR_INVALID_LENGTH If buffer was greater than uint32_t. + */ +uint32_t coap_opt_uint_decode(uint32_t * p_data, uint16_t length, uint8_t * p_encoded); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_OPTION_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c new file mode 100644 index 0000000..4e12bb6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c @@ -0,0 +1,182 @@ +/** + * Copyright (c) 2014 - 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 "coap_queue.h" +#include "iot_common.h" +#include "sdk_config.h" + +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Verify NULL parameters are not passed to API by application. */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } +#else + +#define NULL_PARAM_CHECK(PARAM) + +#endif // COAP_DISABLE_API_PARAM_CHECK + +static coap_queue_item_t m_queue[COAP_MESSAGE_QUEUE_SIZE]; +static uint8_t m_message_queue_count = 0; + +uint32_t coap_queue_init(void) +{ + for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + memset(&m_queue[i], 0, sizeof(coap_queue_item_t)); + m_queue[i].handle = i; + } + m_message_queue_count = 0; + + return NRF_SUCCESS; +} + +uint32_t coap_queue_add(coap_queue_item_t * item) +{ + NULL_PARAM_CHECK(item); + + if (m_message_queue_count >= COAP_MESSAGE_QUEUE_SIZE) + { + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); + } + else + { + for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + if (m_queue[i].p_buffer == NULL) + { + // Free spot in message queue. Add message here... + memcpy(&m_queue[i], item, sizeof(coap_queue_item_t)); + + m_message_queue_count++; + + return NRF_SUCCESS; + } + } + + } + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); +} + +uint32_t coap_queue_remove(coap_queue_item_t * p_item) +{ + for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + if (p_item == (coap_queue_item_t *)&m_queue[i]) + { + memset(&m_queue[i], 0, sizeof(coap_queue_item_t)); + m_message_queue_count--; + return NRF_SUCCESS; + } + } + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +uint32_t coap_queue_item_by_token_get(coap_queue_item_t ** pp_item, uint8_t * p_token, uint8_t token_len) +{ + for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + if (m_queue[i].token_len == token_len) + { + if ((0 != m_queue[i].token_len) && + (memcmp(m_queue[i].token, p_token, m_queue[i].token_len) == 0)) + { + *pp_item = &m_queue[i]; + return NRF_SUCCESS; + } + } + } + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + + +uint32_t coap_queue_item_by_mid_get(coap_queue_item_t ** pp_item, uint16_t message_id) +{ + + + for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + if (m_queue[i].mid == message_id) + { + *pp_item = &m_queue[i]; + return NRF_SUCCESS; + } + } + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + + +uint32_t coap_queue_item_next_get(coap_queue_item_t ** pp_item, coap_queue_item_t * p_item) +{ + if (p_item == NULL) + { + for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + if (m_queue[i].p_buffer != NULL) + { + (*pp_item) = &m_queue[i]; + return NRF_SUCCESS; + } + } + } + else + { + uint8_t index_to_previous = (uint8_t)(((uint32_t)p_item - (uint32_t)m_queue) / (uint32_t)sizeof(coap_queue_item_t)); + + for (uint8_t i = index_to_previous + 1; i < COAP_MESSAGE_QUEUE_SIZE; i++) + { + if (m_queue[i].p_buffer != NULL) + { + (*pp_item) = &m_queue[i]; + return NRF_SUCCESS; + } + } + } + (*pp_item) = NULL; + + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h new file mode 100644 index 0000000..24c5db6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_queue.h + * + * @defgroup iot_sdk_coap_queue CoAP Message Queue + * @ingroup iot_sdk_coap + * @{ + * @brief TODO. + */ + +#ifndef COAP_QUEUE_H__ +#define COAP_QUEUE_H__ + +#include <stdint.h> + +#include "coap_transport.h" +#include "coap_message.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + void * p_arg; /**< Miscellaneous pointer to application provided data that is associated with the message. Copied from the coap_message_t when creating the item. */ + uint32_t handle; /**< Quick reference to the handle value of the current item. */ + uint16_t mid; /**< Message ID. */ + uint8_t token_len; /**< Message Token length. */ + uint8_t token[8]; /**< Message Token value up to 8 bytes. */ + uint8_t retrans_count; /**< Re-transmission attempt count. */ + uint16_t timeout; /**< Time until new re-transmission attempt. */ + uint16_t timeout_val; /**< Last timeout value used. */ + coap_port_t port; /**< Source port to use when re-transmitting. */ + uint8_t * p_buffer; /**< Pointer to the data buffer containing the encoded CoAP message. */ + uint32_t buffer_len; /**< Size of the data buffer containing the encoded CoAP message. */ + coap_remote_t remote; /**< Destination address and port number to the remote. */ + coap_response_callback_t callback; /**< Callback function to be called upon response or transmission timeout. */ +} coap_queue_item_t; + +/**@brief Initilize the CoAP message queue. + * + * @retval NRF_SUCCESS If initialization completed successfully. + */ +uint32_t coap_queue_init(void); + +/**@brief Add item to the queue. + * + * @param[in] p_item Pointer to an item which to add to the queue. The function will copy all + * data provided. + * + * @retval NRF_SUCCESS If adding the item was successful. + * @retval NRF_ERROR_NO_MEM If max number of queued elements has been reached. This is + * configured by COAP_MESSAGE_QUEUE_SIZE in sdk_config.h. + * @retval NRF_ERROR_DATA_SIZE If the element could not be added. + */ +uint32_t coap_queue_add(coap_queue_item_t * p_item); + +/**@brief Remove item from the queue. + * + * @param[in] p_item Pointer to an item which to remove from the queue. Should not be NULL. + * + * @retval NRF_SUCCESS If the item was successfully removed from the queue. + * @retval NRF_ERROR_NULL If p_item pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If the item was not located in the queue. + */ +uint32_t coap_queue_remove(coap_queue_item_t * p_item); + +/**@brief Search for item by token. + * + * @details Search the items for any item matching the token. + * + * @param[out] pp_item Pointer to be filled by the function if item matching the token + * has been found. Should not be NULL. + * @param[in] p_token Pointer to token array to be matched. + * @param[in] token_len Length of the token to be matched. + * + * @retval NRF_SUCCESS If an item was successfully located. + * @retval NRF_ERROR_NULL If pp_item pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If no item was found. + */ +uint32_t coap_queue_item_by_token_get(coap_queue_item_t ** pp_item, uint8_t * p_token, uint8_t token_len); + +/**@brief Search for item by message id. + * + * @details Search the items for any item matching the message id. + * + * @param[out] pp_item Pointer to be filled by the funciton if item matching the message id + * has been found. Should not be NULL. + * @param[in] message_id Message id to be matched. + * + * @retval NRF_SUCCESS If an item was successfully located. + * @retval NRF_ERROR_NULL If pp_item pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If no item was found. + */ +uint32_t coap_queue_item_by_mid_get(coap_queue_item_t ** pp_item, uint16_t message_id); + +/**@brief Iterate through items. + * + * @param[out] pp_item Pointer to be filled by the search function upon finding the next + * queued item starting from the p_item pointer provided. Should + * not be NULL. + * @param[in] p_item Pointer to the item where to start the search. + * + * @retval NRF_SUCCESS If item was found. + * @retval NRF_ERROR_NULL If pp_item pointer is NULL. + * @retval NRF_ERROR_NOT_FOUND If next item was not found. + */ +uint32_t coap_queue_item_next_get(coap_queue_item_t ** pp_item, coap_queue_item_t * p_item); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_QUEUE_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c new file mode 100644 index 0000000..b928e0c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c @@ -0,0 +1,274 @@ +/** + * Copyright (c) 2014 - 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 "coap_resource.h" +#include "coap_api.h" +#include "iot_common.h" +#include "sdk_config.h" + +#define COAP_RESOURCE_MAX_AGE_INIFINITE 0xFFFFFFFF + +static coap_resource_t * mp_root_resource = NULL; +static char m_scratch_buffer[(COAP_RESOURCE_MAX_NAME_LEN + 1) * COAP_RESOURCE_MAX_DEPTH + 6]; + +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Verify NULL parameters are not passed to API by application. */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } +#else + +#define NULL_PARAM_CHECK(PARAM) + +#endif // COAP_DISABLE_API_PARAM_CHECK + +uint32_t coap_resource_init(void) +{ + mp_root_resource = NULL; + return NRF_SUCCESS; +} + +uint32_t coap_resource_create(coap_resource_t * p_resource, const char * name) +{ + NULL_PARAM_CHECK(p_resource); + NULL_PARAM_CHECK(name); + + if (strlen(name) > COAP_RESOURCE_MAX_NAME_LEN) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + memcpy(p_resource->name, name, strlen(name)); + + if (mp_root_resource == NULL) + { + mp_root_resource = p_resource; + } + + p_resource->max_age = COAP_RESOURCE_MAX_AGE_INIFINITE; + + return NRF_SUCCESS; +} + +uint32_t coap_resource_child_add(coap_resource_t * p_parent, coap_resource_t * p_child) +{ + NULL_PARAM_CHECK(p_parent); + NULL_PARAM_CHECK(p_child); + + if (p_parent->child_count == 0) + { + p_parent->p_front = p_child; + p_parent->p_tail = p_child; + } + else + { + coap_resource_t * p_last_sibling = p_parent->p_tail; + p_last_sibling->p_sibling = p_child; + p_parent->p_tail = p_child; + } + + p_parent->child_count++; + + return NRF_SUCCESS; +} + +static uint32_t generate_path(uint16_t buffer_pos, coap_resource_t * p_current_resource, char * parent_path, uint8_t * string, uint16_t * length) +{ + uint32_t err_code = NRF_SUCCESS; + + if (parent_path == NULL) + { + m_scratch_buffer[buffer_pos++] = '<'; + + if (p_current_resource->p_front != NULL) + { + coap_resource_t * next_child = p_current_resource->p_front; + do + { + err_code = generate_path(buffer_pos, next_child, m_scratch_buffer, string, length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + next_child = next_child->p_sibling; + } while (next_child != NULL); + } + } + else + { + uint16_t size = strlen(p_current_resource->name); + m_scratch_buffer[buffer_pos++] = '/'; + + memcpy(&m_scratch_buffer[buffer_pos], p_current_resource->name, size); + buffer_pos += size; + + if (p_current_resource->p_front != NULL) + { + coap_resource_t * next_child = p_current_resource->p_front; + do + { + err_code = generate_path(buffer_pos, next_child, m_scratch_buffer, string, length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + next_child = next_child->p_sibling; + } while (next_child != NULL); + } + + m_scratch_buffer[buffer_pos++] = '>'; + + // If the resource is observable, append 'obs;' token. + if ((p_current_resource->permission & COAP_PERM_OBSERVE) > 0) + { + memcpy(&m_scratch_buffer[buffer_pos], ";obs", 4); + buffer_pos += 4; + } + + m_scratch_buffer[buffer_pos++] = ','; + + if (buffer_pos <= (*length)) + { + *length -= buffer_pos; + memcpy(&string[strlen((char *)string)], m_scratch_buffer, buffer_pos); + } + else + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + } + + return err_code; +} + +uint32_t coap_resource_well_known_generate(uint8_t * string, uint16_t * length) +{ + NULL_PARAM_CHECK(string); + NULL_PARAM_CHECK(length); + + if (mp_root_resource == NULL) + { + return (NRF_ERROR_INVALID_STATE | IOT_COAP_ERR_BASE); + } + + memset(string, 0, *length); + + uint32_t err_code = generate_path(0, mp_root_resource, NULL, string, length); + + string[strlen((char *)string) - 1] = '\0'; // remove the last comma + + return err_code; +} + +static coap_resource_t * coap_resource_child_resolve(coap_resource_t * p_parent, + char * p_path) +{ + coap_resource_t * result = NULL; + if (p_parent->p_front != NULL) + { + coap_resource_t * sibling_in_question = p_parent->p_front; + + do { + // Check if the sibling name match. + size_t size = strlen(sibling_in_question->name); + if (strncmp(sibling_in_question->name, p_path, size) == 0) + { + return sibling_in_question; + } + else + { + sibling_in_question = sibling_in_question->p_sibling; + } + } while (sibling_in_question != NULL); + } + return result; +} + +uint32_t coap_resource_get(coap_resource_t ** p_resource, uint8_t ** pp_uri_pointers, uint8_t num_of_uris) +{ + if (mp_root_resource == NULL) + { + // Make sure pointer is set to NULL before returning. + *p_resource = NULL; + return (NRF_ERROR_INVALID_STATE | IOT_COAP_ERR_BASE); + } + + coap_resource_t * p_current_resource = mp_root_resource; + + // Every node should start at root. + for (uint8_t i = 0; i < num_of_uris; i++) + { + p_current_resource = coap_resource_child_resolve(p_current_resource, (char *)pp_uri_pointers[i]); + + if (p_current_resource == NULL) + { + // Stop looping as this direction will not give anything more. + break; + } + } + + if (p_current_resource != NULL) + { + *p_resource = p_current_resource; + return NRF_SUCCESS; + } + + // If nothing has been found. + *p_resource = NULL; + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +uint32_t coap_resource_root_get(coap_resource_t ** pp_resource) +{ + NULL_PARAM_CHECK(pp_resource); + + if (mp_root_resource == NULL) + { + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + + *pp_resource = mp_root_resource; + + return NRF_SUCCESS; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h new file mode 100644 index 0000000..d73ef1f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_resource.h + * + * @defgroup iot_sdk_coap_resource CoAP Resource + * @ingroup iot_sdk_coap + * @{ + * @brief Private API of Nordic's CoAP Resource implementation. + */ + +#ifndef COAP_RESOURCE_H__ +#define COAP_RESOURCE_H__ + +#include <stdint.h> +#include "coap_api.h" +#include "sdk_config.h" +#include "coap_message.h" +#include "nrf_error.h" +#include "sdk_errors.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Initialize the CoAP resource module. + * + * @details This function will initialize the root element pointer to NULL. + * This way, a new root can be assigned registered. The first + * resource added will be set as the new root. + * + * @retval NRF_SUCCESS This function will always return success. + */ +uint32_t coap_resource_init(void); + +/**@brief Find a resource by traversing the resource names. + * + * @param[out] p_resource Located resource. + * @param[in] pp_uri_pointers Array of strings which forms the hierarchical path to the resource. + * @param[in] num_of_uris Number of URIs supplied through the path pointer list. + * + * @retval NRF_SUCCESS The resource was instance located. + * @retval NRF_ERROR_NOT_FOUND The resource was not located. + * @retval NRF_ERROR_INVALID_STATE If no resource has been registered. + */ +uint32_t coap_resource_get(coap_resource_t ** p_resource, + uint8_t ** pp_uri_pointers, + uint8_t num_of_uris); + + +/**@brief Process the request related to the resource. + * + * @details When a request is received and the resource has successfully been located it + * will pass on to this function. The method in the request will be matched against + * what the service provides of method handling callbacks. If the request expects a + * response this will be provided as output from this function. The memory provided + * for the response must be provided from outside. + * + * @param[in] p_resource Resource that will handle the request. + * @param[in] p_request The request to be handled. + * @param[inout] p_response Response message which can be used by the resource populate + * the response message. + */ +uint32_t coap_resource_process_request(coap_resource_t * p_resource, + coap_message_t * p_request, + coap_message_t * p_response); + +#ifdef __cplusplus +} +#endif + +#endif // COAP_MESSAGE_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h new file mode 100644 index 0000000..b9fd597 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2014 - 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. + * + */ +/** @file coap_transport.h + * + * @defgroup iot_sdk_coap_transport CoAP transport abstraction + * @ingroup iot_sdk_coap + * @{ + * @brief The transport interface that the CoAP depends on for sending and receiving CoAP messages. + * + * @details While the interface is well defined and should not be altered, the implementation of the + * interface depends on the choice of IP stack. The only exception to this is the + * \ref coap_transport_read API. This API is implemented in the CoAP, and the transport layer is + * expected to call this function when data is received on one of the CoAP ports. + */ + +#ifndef COAP_TRANSPORT_H__ +#define COAP_TRANSPORT_H__ + +#include <stdint.h> +#include <nrf_tls.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Port identification information. */ +typedef struct +{ + uint16_t port_number; /**< Port number. */ +} coap_port_t; + + +/**@brief Remote endpoint. */ +typedef struct +{ + uint8_t addr[16]; /**< Address of the remote device. */ + uint16_t port_number; /**< Remote port number. */ +} coap_remote_t; + + +/**@brief Transport initialization information. */ +typedef struct +{ + coap_port_t * p_port_table; /**< Information about the ports being registered. Count is assumed to be COAP_PORT_COUNT. */ + void * p_arg; /**< Public. Miscellaneous pointer to application provided data that should be passed to the transport. */ +} coap_transport_init_t; + + + +/**@brief Initializes the transport layer to have the data ports set up for CoAP. + * + * @param[in] p_param Port count and port numbers. + * + * @retval NRF_SUCCESS If initialization was successful. Otherwise, an error code that indicates the reason for the failure is returned. + */ +uint32_t coap_transport_init (const coap_transport_init_t * p_param); + + +/**@brief Sends data on a CoAP endpoint or port. + * + * @param[in] p_port Port on which the data is to be sent. + * @param[in] p_remote Remote endpoint to which the data is targeted. + * @param[in] p_data Pointer to the data to be sent. + * @param[in] datalen Length of the data to be sent. + * + * @retval NRF_SUCCESS If the data was sent successfully. Otherwise, an error code that indicates the reason for the failure is returned. + */ +uint32_t coap_transport_write(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const uint8_t * p_data, + uint16_t datalen); + + + +/**@brief Handles data received on a CoAP endpoint or port. + * + * This API is not implemented by the transport layer, but assumed to exist. This approach + * avoids unnecessary registering of callback and remembering it in the transport layer. + * + * @param[in] p_port Port on which the data is received. + * @param[in] p_remote Remote endpoint from which the data is received. + * @param[in] p_local Local endpoint on which the data is received. + * @param[in] result Indicates if the data was processed successfully by lower layers. + * Possible failures could be NRF_SUCCESS, + * UDP_BAD_CHECKSUM, + * UDP_TRUNCATED_PACKET, or + * UDP_MALFORMED_PACKET. + * @param[in] p_data Pointer to the data received. + * @param[in] datalen Length of the data received. + * + * @retval NRF_SUCCESS If the data was handled successfully. Otherwise, an error code that indicates the reason for the failure is returned. + * + */ +uint32_t coap_transport_read(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const coap_remote_t * p_local, + uint32_t result, + const uint8_t * p_data, + uint16_t datalen); + + +/**@brief Process loop to handle DTLS processing. + * + * @details The function handles any processing of encrypted packets. + * Some encryption libraries requires to be run in a processing + * loop. This function is called by the CoAP library everytime + * \ref coap_time_tick is issued from the library user. Any other process + * specific routines that should be done regularly could be added in + * this function. + */ +void coap_transport_process(void); + +/**@brief Process loop when using coap BSD socket transport implementation. + * + * @details This is blocking call. The function unblock is only + * triggered upon an socket event registered to select() by coap transport. + * This function must be called as often as possible in order to dispatch incomming + * socket events. Preferred to be put in the application's main loop or similar. + */ +void coap_transport_input(void); + +#ifdef __cplusplus +} +#endif + +#endif //COAP_TRANSPORT_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c new file mode 100644 index 0000000..b1fe138 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c @@ -0,0 +1,996 @@ +/** + * Copyright (c) 2014 - 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 "nrf_error.h" +#include "nrf_drv_rng.h" +#include "sdk_config.h" +#include "iot_common.h" +#include "iot_pbuffer.h" +#include "coap_transport.h" +#include "coap.h" +#include "udp_api.h" +#include "nrf_tls.h" +#include "mem_manager.h" +#include "iot_errors.h" + + +#if IOT_COAP_CONFIG_LOG_ENABLED + +#define NRF_LOG_MODULE_NAME coap_dtls + +#define NRF_LOG_LEVEL IOT_COAP_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR IOT_COAP_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR IOT_COAP_CONFIG_DEBUG_COLOR + +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define COAPT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */ +#define COAPT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */ +#define COAPT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */ + +#define COAPT_ENTRY() COAPT_TRC(">> %s", __func__) +#define COAPT_EXIT() COAPT_TRC("<< %s", __func__) +#define COAPT_ENTRY_WITH_READLEN(read_len) COAPT_TRC(">> %s, readlen %d", __func__, read_len) +#define COAPT_EXIT_WITH_RESULT(result) COAPT_TRC("<< %s, result 0x%08lX", __func__, result) + +#else // IOT_COAP_CONFIG_LOG_ENABLED + +#define COAPT_TRC(...) /**< Disables traces. */ +#define COAPT_DUMP(...) /**< Disables dumping of octet streams. */ +#define COAPT_ERR(...) /**< Disables error logs. */ + +#define COAPT_ENTRY(...) +#define COAPT_EXIT(...) +#define COAPT_ENTRY_WITH_READLEN(...) +#define COAPT_EXIT_WITH_RESULT(...) + +#endif // IOT_COAP_CONFIG_LOG_ENABLED + +/**@brief Max size to be requested from the DTLS library when polling for decoded CoAP data. */ +#define MAX_BUFFER_SIZE 1024 + + +/**@brief UDP port information. */ +typedef struct +{ + uint32_t socket_id; /**< Socket information provided by UDP. */ + uint16_t port_number; /**< Associated port number. */ + nrf_tls_key_settings_t * p_settings; /**< Key preferences. */ +} udp_port_t; + +/**@brief CoAP remote session. Encapsulates information needed for DTLS. */ +typedef struct +{ + nrf_tls_instance_t dtls_instance; /**< DTLS instance identifier. */ + coap_remote_t remote_endpoint; /**< Remote endoint indentification. */ + uint16_t local_port_index; /**< Identifies local endpoint assoicated with the session. */ +} coap_remote_session_t; + +/**@brief Possible CoAP transport types. Needed for internal handling of events and data. */ +typedef enum +{ + COAP_TRANSPORT_NON_SECURE_DATAGRAM = 0, /**< Non-secure transport, no DTLS procedures apply. */ + COAP_TRANSPORT_SECURE_DATAGRAM = 1, /**< Secure transport, DTLS procedures apply. */ + COAP_TRANSPORT_MAX_TYPES = 2 /**< Maximum transport types. Not a valid transport identifer used as max count. */ +} coap_transport_type_t; + +/** + * @brief Transport write handler signature. + * + * @param[in] p_remote Remote endpoint on which data is to be written. + * @param[in] local_port_index Local endpoint identifier writing the data. + * @param[in] p_data Data to be written. + * @param[in] datalen Length of data to be written. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +typedef uint32_t (* port_write_t) (const coap_remote_t * const p_remote, + uint32_t local_port_index, + const uint8_t * p_data, + uint16_t datalen); + +/** + * @brief Transport read handler signature. + * + * @param[in] p_remote Remote endpoint which sent data. + * @param[in] local_port_index Local endpoint identifier to which the data was sent. + * @param[in] p_data Data read on the transport. + * @param[in] datalen Length of data read on the transport. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +typedef uint32_t (* port_read_t) (const coap_remote_t * const p_remote, + uint32_t local_port_index, + uint32_t read_result, + const uint8_t * p_data, + uint16_t datalen); + +/** Forward declaration. */ +uint32_t non_secure_datagram_write (const coap_remote_t * const p_remote, + uint32_t local_port_index, + const uint8_t * p_data, + uint16_t datalen); + +/** Forward declaration. */ +uint32_t secure_datagram_write (const coap_remote_t * const p_remote, + uint32_t local_port_index, + const uint8_t * p_data, + uint16_t datalen); + +/** Forward declaration. */ +uint32_t non_secure_datagram_read (const coap_remote_t * const p_remote, + uint32_t local_port_index, + uint32_t read_result, + const uint8_t * p_data, + uint16_t datalen); + +/** Forward declaration. */ +uint32_t secure_datagram_read(const coap_remote_t * const p_remote, + uint32_t local_port_index, + uint32_t read_result, + const uint8_t * p_data, + uint16_t datalen); + +/** Forward declaration. */ +uint32_t dtls_output_handler(nrf_tls_instance_t const * p_instance, + uint8_t const * p_data, + uint32_t datalen); + +static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */ +static coap_remote_session_t m_remote_session[COAP_DTLS_MAX_REMOTE_SESSION]; /**< Table for managing security sessions with remote endpoints. */ + +/**@brief Table of transport write handlers. */ +const port_write_t port_write_fn[COAP_TRANSPORT_MAX_TYPES] = +{ + non_secure_datagram_write, + secure_datagram_write +}; + +/**@brief Table of transport read handlers. */ +const port_read_t port_read_fn[COAP_TRANSPORT_MAX_TYPES] = +{ + non_secure_datagram_read, + secure_datagram_read +}; + + +/** + * @brief Searches the local port reference based on the port number. + * + * @param[out] p_index Pointer where local port refernce should be provided (if found). + * @param[in] port_query Port number for which local port reference is requested. + * + * @retval NRF_SUCCESS if procedure succeeded else NRF_ERROR_NOT_FOUND. + */ +static uint32_t local_port_index_get(uint32_t * p_index, uint16_t port_query) +{ + uint32_t local_port_index; + + // Find local port index. + for (local_port_index = 0; local_port_index < COAP_PORT_COUNT; local_port_index++) + { + if (m_port_table[local_port_index].port_number == port_query) + { + break; + } + } + + // If we could not find the local port requested in the port table. + if (local_port_index >= COAP_PORT_COUNT) + { + return NRF_ERROR_NOT_FOUND; + } + + *p_index = local_port_index; + + return NRF_SUCCESS; +} + + +/** + * @brief Session to be initialized/freed. + * + * @param[in] p_session Session + */ +static void remote_session_init(coap_remote_session_t * p_session) +{ + memset(p_session, 0, sizeof(coap_remote_session_t)); + NRF_TLS_INTSANCE_INIT(&p_session->dtls_instance); +} + + +/** + * @brief Creates DTLS session between remote and local endpoint. + * + * @param[in] local_port_index Identifies local endpoint. + * @param[in] role Identifies DTLS role to be played (server or client). + * @param[in] p_remote Identifies remote endpoint. + * @param[in] p_settings Security settings to be used for the session. + * @param[out] pp_session Pointer to the session created (if any). + * + * @retval NRF_SUCCESS is procedure succeeded else an error code indicating reason for failure. + */ +static uint32_t session_create(uint32_t local_port_index, + nrf_tls_role_t role, + const coap_remote_t * const p_remote, + nrf_tls_key_settings_t * const p_settings, + coap_remote_session_t ** pp_session) +{ + uint32_t err_code = NRF_ERROR_NO_MEM; + + for (uint32_t index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++) + { + if (m_remote_session[index].remote_endpoint.port_number == 0) + { + // Found free session. + m_remote_session[index].remote_endpoint.port_number = p_remote->port_number; + memcpy(m_remote_session[index].remote_endpoint.addr, p_remote->addr, IPV6_ADDR_SIZE); + m_remote_session[index].local_port_index = local_port_index; + + // Attempt Allocate TLS session. + const nrf_tls_options_t dtls_options = + { + .output_fn = dtls_output_handler, + .transport_type = NRF_TLS_TYPE_DATAGRAM, + .role = role, + .p_key_settings = p_settings + }; + + m_remote_session[index].dtls_instance.transport_id = index; + + COAP_MUTEX_UNLOCK(); + + err_code = nrf_tls_alloc(&m_remote_session[index].dtls_instance, &dtls_options); + + COAP_MUTEX_LOCK(); + + COAPT_TRC("[%p]: nrf_tls_alloc result %08x", + &m_remote_session[index], + err_code); + + // TLS allocation succeeded, book keep information for endpoint. + if (err_code == NRF_SUCCESS) + { + (*pp_session) = &m_remote_session[index]; + break; + } + else + { + // If free the session and notify failure. + remote_session_init(&m_remote_session[index]); + } + } + } + + return err_code; +} + + +/** + * @brief API to free TLS session. + * + * @param[in] p_session Identifies the session to be freed. + */ +static __INLINE void session_free (coap_remote_session_t * p_session) +{ + // Free TLS session. + UNUSED_VARIABLE(nrf_tls_free(&p_session->dtls_instance)); + + // Free the session. + remote_session_init(p_session); +} + + +/** + * @brief Searches for DTLS session between remote and local endpoint. + * + * @param[in] local_port_index Identifies local endpoint. + * @param[in] p_remote Identifies remote endpoint. + * @param[out] pp_session Pointer to the session found (if any). + * + * @retval NRF_SUCCESS is procedure succeeded else NRF_ERROR_NOT_FOUND. + */ +uint32_t remote_session_search(uint32_t local_port_index, + const coap_remote_t * p_remote, + coap_remote_session_t ** pp_session) +{ + uint32_t err_code = NRF_ERROR_NOT_FOUND; + uint32_t index = 0; + + + for (index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++) + { + const coap_remote_session_t * session = &m_remote_session[index]; + if ((session->local_port_index == local_port_index) && + (session->remote_endpoint.port_number == p_remote->port_number) && + ((memcmp(session->remote_endpoint.addr, p_remote->addr, IPV6_ADDR_SIZE) == 0))) + { + // Entry exists. + (*pp_session) = (coap_remote_session_t *)session; + err_code = NRF_SUCCESS; + break; + } + } + + return err_code; +} + + +/** + * @brief Provides transport type to be used between remote and local endpoint. + * + * @param[in] local_port_index Identifies local endpoint. + * @param[in] p_remote Identifies remote endpoint. + * + * @retval COAP_TRANSPORT_SECURE_DATAGRAM if transport type to be used is secure. + * @retval COAP_TRANSPORT_NON_SECURE_DATAGRAM if transport type to be used is non-secure. + */ +uint8_t get_transport_type(uint32_t local_port_index, const coap_remote_t * p_remote) +{ + coap_remote_session_t * p_session; + uint8_t transport_type = COAP_TRANSPORT_NON_SECURE_DATAGRAM; + + uint32_t err_code = remote_session_search(local_port_index, p_remote, &p_session); + if (err_code == NRF_SUCCESS) + { + COAPT_TRC("Transport type = SECURE"); + transport_type = COAP_TRANSPORT_SECURE_DATAGRAM; + } + else if (m_port_table[local_port_index].p_settings != NULL) + { + COAPT_TRC("Transport type = SECURE"); + transport_type = COAP_TRANSPORT_SECURE_DATAGRAM; + } + else + { + COAPT_TRC("Transport type = NON-SECURE"); + } + + return transport_type; +} + + +/**@brief Callback handler to receive data on the UDP port. + * + * @details Callback handler to receive data on the UDP port. + * + * @param[in] p_socket Socket identifier. + * @param[in] p_ip_header IPv6 header containing source and destination addresses. + * @param[in] p_udp_header UDP header identifying local and remote endpoints. + * @param[in] process_result Result of data reception, there could be possible errors like + * invalid checksum etc. + * @param[in] iot_pbuffer_t Packet buffer containing the received data packet. + * + * @retval NRF_SUCCESS Indicates received data was handled successfully, else an an + * error code indicating reason for failure.. + */ +static uint32_t port_data_callback(const udp6_socket_t * p_socket, + const ipv6_header_t * p_ip_header, + const udp6_header_t * p_udp_header, + uint32_t process_result, + iot_pbuffer_t * p_rx_packet) +{ + uint32_t index; + uint32_t retval = NRF_ERROR_NOT_FOUND; + + COAPT_TRC("port_data_callback: Src Port %d Dest Port %d. Len %08lx", + p_udp_header->srcport, p_udp_header->destport, p_rx_packet->length); + + COAP_MUTEX_LOCK(); + + //Search for the port. + for (index = 0; index < COAP_PORT_COUNT; index++) + { + if (m_port_table[index].socket_id == p_socket->socket_id) + { + COAPT_TRC("port_data_callback->coap_transport_read"); + + //Matching port found. + coap_remote_t remote_endpoint; + + memcpy(remote_endpoint.addr, p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE); + remote_endpoint.port_number = p_udp_header->srcport; + + uint8_t transport_type = get_transport_type(index, &remote_endpoint); + + // Handle read data on scoket based on nature of transport. + retval = port_read_fn[transport_type](&remote_endpoint, + index, + process_result, + p_rx_packet->p_payload, + p_rx_packet->length); + break; + } + } + + COAP_MUTEX_UNLOCK(); + + return retval; +} + + +/** + * @brief Transport read handler for non secure transport type. + * + * @param[in] p_remote Remote endpoint which sent data. + * @param[in] local_port_index Local endpoint identifier to which the data was sent. + * @param[in] read_result Indicator result of data read on the transport. + * Likely failures include UDP checksum failure, truncated packet etc. + * @param[in] p_data Data read on the transport. + * @param[in] datalen Length of data read on the transport. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +uint32_t non_secure_datagram_read (const coap_remote_t * const p_remote, + uint32_t local_port_index, + uint32_t read_result, + const uint8_t * p_data, + uint16_t datalen) +{ + const coap_port_t port = + { + .port_number = m_port_table[local_port_index].port_number + }; + + return coap_transport_read(&port, + p_remote, + NULL, + read_result, + p_data, + datalen); +} + + +/** + * @brief Transport write handler for non secure transport type. + * + * @param[in] p_remote Remote endpoint on which data is to be written. + * @param[in] local_port_index Local endpoint identifier writing the data. + * @param[in] p_data Data to be written. + * @param[in] datalen Length of data to be written. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +uint32_t non_secure_datagram_write(const coap_remote_t * p_remote, + uint32_t index, + const uint8_t * p_data, + uint16_t datalen) +{ + uint32_t err_code; + udp6_socket_t socket; + ipv6_addr_t remote_addr; + iot_pbuffer_t * p_buffer; + iot_pbuffer_alloc_param_t buffer_param; + + buffer_param.type = UDP6_PACKET_TYPE; + buffer_param.flags = PBUFFER_FLAG_DEFAULT; + buffer_param.length = datalen; + + COAPT_TRC("[LP %04X]:[RP %04X]: port_write, datalen %d", + m_port_table[index].port_number, + p_remote->port_number, + datalen); + + memcpy(remote_addr.u8, p_remote->addr, IPV6_ADDR_SIZE); + + // Allocate buffer to send the data on port. + err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer); + + COAPT_TRC("port_write->iot_pbuffer_allocate result 0x%08X", err_code); + + if (err_code == NRF_SUCCESS) + { + socket.socket_id = m_port_table[index].socket_id; + + // Make a copy of the data onto the buffer. + memcpy(p_buffer->p_payload, p_data, datalen); + + // Send on UDP port. + err_code = udp6_socket_sendto(&socket, + &remote_addr, + p_remote->port_number, + p_buffer); + + COAPT_TRC("port_write->udp6_socket_sendto result 0x%08X", err_code); + if (err_code != NRF_SUCCESS) + { + // Free the allocated buffer as send procedure has failed. + UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true)); + } + } + + return err_code; +} + + +/** + * @brief Transport read handler for secure transport type. + * + * @param[in] p_remote Remote endpoint which sent data. + * @param[in] local_port_index Local endpoint identifier to which the data was sent. + * @param[in] read_result Indicator result of data read on the transport. + * Likely failures include UDP checksum failure, truncated packet etc. + * @param[in] p_data Data read on the transport. + * @param[in] datalen Length of data read on the transport. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +uint32_t secure_datagram_read(const coap_remote_t * const p_remote, + uint32_t local_port_index, + uint32_t read_result, + const uint8_t * p_data, + uint16_t datalen) +{ + const uint32_t read_len = datalen; + uint32_t err_code; + coap_remote_session_t * p_session = NULL; + + COAPT_ENTRY_WITH_READLEN(read_len); + + // Search is a session exists. + err_code = remote_session_search(local_port_index, p_remote, &p_session); + + if (err_code == NRF_SUCCESS) + { + COAPT_TRC("Remote session found, processing."); + + COAP_MUTEX_UNLOCK(); + + // Session exists, send data to DTLS for decryption. + err_code = nrf_tls_input(&p_session->dtls_instance, p_data, read_len); + + COAP_MUTEX_LOCK(); + } + else + { + COAPT_TRC("Remote session not found, look for server security settings."); + if (m_port_table[local_port_index].p_settings != NULL) + { + // Allocate a session for incoming client. + err_code = session_create(local_port_index, + NRF_TLS_ROLE_SERVER, + p_remote, + m_port_table[local_port_index].p_settings, + &p_session); + + if (err_code == NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + + COAPT_TRC("[%p]: New session created as DTLS server.", p_session); + + err_code = nrf_tls_input(&p_session->dtls_instance, p_data, read_len); + + COAP_MUTEX_LOCK(); + } + else + { + COAPT_TRC("New session creation failed, reason 0x%08x.", err_code); + } + } + else + { + COAPT_TRC("No remote session, no server settings, processing as raw"); + err_code = non_secure_datagram_read(p_remote, + local_port_index, + read_result, + p_data, + datalen); + } + } + + COAPT_EXIT_WITH_RESULT(err_code); + + return err_code; +} + + +/** + * @brief Transport write handler for secure transport type. + * + * @param[in] p_remote Remote endpoint on which data is to be written. + * @param[in] local_port_index Local endpoint identifier writing the data. + * @param[in] p_data Data to be written. + * @param[in] datalen Length of data to be written. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +uint32_t secure_datagram_write(const coap_remote_t * const p_remote, + uint32_t local_port_index, + const uint8_t * p_data, + uint16_t datalen) +{ + + uint32_t err_code; + coap_remote_session_t * p_session; + + // Search is a session exists. + err_code = remote_session_search(local_port_index, p_remote, &p_session); + + if (err_code == NRF_ERROR_NOT_FOUND) + { + // No session found, return error. + err_code = COAP_TRANSPORT_SECURITY_MISSING; + } + else + { + // Session exists, attempt a secure write. + uint32_t actual_len = datalen; + err_code = nrf_tls_write(&p_session->dtls_instance, p_data, &actual_len); + } + + return err_code; +} + + +/** + * @brief Handles DTLS output to be sent on the underlying UDP transport. + * + * @param[in] p_instance Identifies the TLS instance associated with the output. + * @param[in] p_data DTLS library output data to be written on the transport. + * @param[in] datalen Length of data. + * + * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for + * failure. + */ +uint32_t dtls_output_handler(nrf_tls_instance_t const * p_instance, + uint8_t const * p_data, + uint32_t datalen) +{ + const uint16_t transport_write_len = datalen; + + if (p_instance->transport_id >= COAP_DTLS_MAX_REMOTE_SESSION) + { + return NRF_ERROR_NOT_FOUND; + } + + COAP_MUTEX_LOCK(); + + coap_remote_session_t * p_session = &m_remote_session[p_instance->transport_id]; + uint32_t err_code = NRF_ERROR_NOT_FOUND; + + if (p_session->remote_endpoint.port_number != 0) + { + // Search for instance in remote sessions. + err_code = non_secure_datagram_write(&p_session->remote_endpoint, + p_session->local_port_index, + p_data, + transport_write_len); + } + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + + +/**@brief Creates port as requested in p_port. + * + * @details Creates port as requested in p_port. + * + * @param[in] index Index to the m_port_table where entry of the port created is to be made. + * @param[in] p_port Port information to be created. + * + * @retval NRF_SUCCESS Indicates if port was created successfully, else an an error code + * indicating reason for failure. + */ +static uint32_t port_create(uint32_t index, coap_port_t * p_port) +{ + uint32_t err_code; + udp6_socket_t socket; + + // Request new socket creation. + err_code = udp6_socket_allocate(&socket); + + if (err_code == NRF_SUCCESS) + { + // Bind the socket to the local port. + err_code = udp6_socket_bind(&socket, IPV6_ADDR_ANY, p_port->port_number); + + if (err_code == NRF_SUCCESS) + { + // Register data receive callback. + err_code = udp6_socket_recv(&socket, port_data_callback); + + if (err_code == NRF_SUCCESS) + { + // All procedure with respect to port creation succeeded, make entry in the table. + m_port_table[index].socket_id = socket.socket_id; + m_port_table[index].port_number = p_port->port_number; + m_port_table[index].p_settings = NULL; + + socket.p_app_data = &m_port_table[index]; + UNUSED_VARIABLE(udp6_socket_app_data_set(&socket)); + } + } + + if (err_code != NRF_SUCCESS) + { + // Not all procedures succeeded with allocated socket, hence free it. + UNUSED_VARIABLE(udp6_socket_free(&socket)); + } + } + return err_code; +} + + +uint32_t coap_transport_init(const coap_transport_init_t * p_param) +{ + uint32_t err_code = NRF_ERROR_NO_MEM; + uint32_t index; + + NULL_PARAM_CHECK(p_param); + NULL_PARAM_CHECK(p_param->p_port_table); + + err_code = nrf_tls_init(); + + if (err_code == NRF_SUCCESS) + { + for (index = 0; index < COAP_PORT_COUNT; index++) + { + // Create end point for each of the CoAP ports. + err_code = port_create(index, &p_param->p_port_table[index]); + if (err_code != NRF_SUCCESS) + { + break; + } + } + + for (index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++) + { + remote_session_init(&m_remote_session[index]); + } + } + + return err_code; +} + + +uint32_t coap_transport_write(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const uint8_t * p_data, + uint16_t datalen) +{ + uint32_t err_code = NRF_ERROR_NOT_FOUND; + uint32_t index; + + NULL_PARAM_CHECK(p_port); + NULL_PARAM_CHECK(p_remote); + NULL_PARAM_CHECK(p_data); + + COAP_MUTEX_LOCK(); + + //Search for the corresponding port. + for (index = 0; index < COAP_PORT_COUNT; index++) + { + if (m_port_table[index].port_number == p_port->port_number) + { + // Get transport type for remote and local. + uint8_t transport_type = get_transport_type(index, p_remote); + + err_code = port_write_fn[transport_type](p_remote, + index, + p_data, + datalen); + break; + } + } + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + + +void coap_transport_process(void) +{ + nrf_tls_process(); + + for (uint32_t index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++) + { + coap_remote_session_t * p_session = &m_remote_session[index]; + + if (p_session->remote_endpoint.port_number != 0x0000) + { + uint32_t datalen = MAX_BUFFER_SIZE; + + COAP_MUTEX_UNLOCK(); + + // Check if there is data to be processed/read. + uint32_t err_code = nrf_tls_read(&p_session->dtls_instance, NULL, &datalen); + + COAP_MUTEX_LOCK(); + + COAPT_TRC("nrf_tls_read result %d", err_code); + + if ((err_code == NRF_SUCCESS) && (datalen > 0)) + { + COAPT_TRC("nrf_tls_read datalen %d", datalen); + + // Allocate memory and fecth data from DTLS layer. + uint8_t * p_data = NULL; + uint32_t buffer_size = datalen; + + err_code = nrf_mem_reserve(&p_data, &buffer_size); + + if (p_data != NULL) + { + COAP_MUTEX_UNLOCK(); + + err_code = nrf_tls_read(&p_session->dtls_instance, p_data, &datalen); + + COAP_MUTEX_LOCK(); + + if ((err_code == NRF_SUCCESS) && (datalen > 0)) + { + UNUSED_VARIABLE(non_secure_datagram_read(&p_session->remote_endpoint, + p_session->local_port_index, + NRF_SUCCESS, + p_data, + datalen)); + } + + // Free the memory reserved for the incoming packet. + nrf_free(p_data); + } + } + } + } +} + + +uint32_t coap_security_setup(uint16_t local_port, + nrf_tls_role_t role, + coap_remote_t * const p_remote, + nrf_tls_key_settings_t * const p_settings) +{ + uint32_t err_code = NRF_ERROR_NO_MEM; + uint32_t local_port_index; + coap_remote_session_t * p_session; + + COAP_MUTEX_LOCK(); + + // Find local port index. + err_code = local_port_index_get(&local_port_index, local_port); + + if (err_code == NRF_SUCCESS) + { + if (role == NRF_TLS_ROLE_CLIENT) + { + if (p_remote == NULL) + { + // Clients can never register session with wildcard remote. + err_code = NRF_ERROR_NULL; + } + else + { + // Search is a session exists. + err_code = remote_session_search(local_port_index, p_remote, &p_session); + + if (err_code != NRF_SUCCESS) + { + // Session does not already exist, create one. + err_code = session_create(local_port_index, + role, p_remote, + p_settings, + &p_session); + } + } + } + else + { + // For server role, disallow client specific settings. + // This may not always be desired. But a constraint added in current design. + if (p_remote != NULL) + { + err_code = NRF_ERROR_INVALID_PARAM; + } + else + { + // Cannot overwrite settings. + if (m_port_table[local_port_index].p_settings != NULL) + { + err_code = NRF_ERROR_FORBIDDEN; + } + else + { + COAPT_TRC("[0x%08lx]: Server security setup successful", + local_port_index); + + m_port_table[local_port_index].p_settings = p_settings; + } + } + + } + } + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + + +uint32_t coap_security_destroy(uint16_t local_port, + coap_remote_t * const p_remote) +{ + uint32_t err_code; + coap_remote_session_t * p_session; + uint32_t local_port_index; + + COAP_MUTEX_LOCK(); + + // Find local port index. + err_code = local_port_index_get(&local_port_index, local_port); + + if (err_code == NRF_SUCCESS) + { + if (p_remote != NULL) + { + // Search is a session exists. + err_code = remote_session_search(local_port_index, p_remote, &p_session); + + if (err_code == NRF_SUCCESS) + { + session_free(p_session); + } + } + else + { + // Remove all session associated with the local port if p_remote is NULL. + for (uint32_t index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION ; index++) + { + if (m_remote_session[index].local_port_index == local_port_index) + { + session_free(&m_remote_session[index]); + } + } + } + } + + COAP_MUTEX_UNLOCK(); + + return err_code; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c new file mode 100644 index 0000000..9cf4bdb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2014 - 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 "sdk_errors.h" +#include "sdk_config.h" +#include "iot_common.h" +#include "iot_pbuffer.h" +#include "coap_transport.h" +#include "coap.h" +#include "udp_api.h" + + +/**@brief UDP port information. */ +typedef struct +{ + uint32_t socket_id; /**< Socket information provided by UDP. */ + uint16_t port_number; /**< Associated port number. */ +} udp_port_t; + +static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */ + + +/**@brief Callback handler to receive data on the UDP port. + * + * @details Callback handler to receive data on the UDP port. + * + * @param[in] p_socket Socket identifier. + * @param[in] p_ip_header IPv6 header containing source and destination addresses. + * @param[in] p_udp_header UDP header identifying local and remote endpoints. + * @param[in] process_result Result of data reception, there could be possible errors like + * invalid checksum etc. + * @param[in] iot_pbuffer_t Packet buffer containing the received data packet. + * + * @retval NRF_SUCCESS Indicates received data was handled successfully, else an an + * error code indicating reason for failure.. + */ +static uint32_t port_data_callback(const udp6_socket_t * p_socket, + const ipv6_header_t * p_ip_header, + const udp6_header_t * p_udp_header, + uint32_t process_result, + iot_pbuffer_t * p_rx_packet) +{ + uint32_t index; + uint32_t retval = NRF_ERROR_NOT_FOUND; + + //Search for the port. + for (index = 0; index < COAP_PORT_COUNT; index++) + { + //Matching port found. + if (m_port_table[index].socket_id == p_socket->socket_id) + { + coap_remote_t remote_endpoint; + coap_remote_t local_endpoint; + const coap_port_t port = {p_udp_header->destport}; + + memcpy (remote_endpoint.addr, p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE); + remote_endpoint.port_number = p_udp_header->srcport; + + memcpy (local_endpoint.addr, p_ip_header->destaddr.u8, IPV6_ADDR_SIZE); + local_endpoint.port_number = p_udp_header->destport; + + COAP_MUTEX_LOCK(); + + //Notify the module of received data. + retval = coap_transport_read(&port, + &remote_endpoint, + &local_endpoint, + process_result, + p_rx_packet->p_payload, + p_rx_packet->length); + + COAP_MUTEX_UNLOCK(); + } + } + + return retval; +} + + +/**@brief Creates port as requested in p_port. + * + * @details Creates port as requested in p_port. + * + * @param[in] index Index to the m_port_table where entry of the port created is to be made. + * @param[in] p_port Port information to be created. + * + * @retval NRF_SUCCESS Indicates if port was created successfully, else an an error code + * indicating reason for failure. + */ +static uint32_t port_create(uint32_t index, coap_port_t * p_port) +{ + uint32_t err_code; + udp6_socket_t socket; + + //Request new socket creation. + err_code = udp6_socket_allocate(&socket); + + if (err_code == NRF_SUCCESS) + { + // Bind the socket to the local port. + err_code = udp6_socket_bind(&socket, IPV6_ADDR_ANY, p_port->port_number); + if (err_code == NRF_SUCCESS) + { + //Register data receive callback. + err_code = udp6_socket_recv(&socket, port_data_callback); + if (err_code == NRF_SUCCESS) + { + //All procedure with respect to port creation succeeded, make entry in the table. + m_port_table[index].socket_id = socket.socket_id; + m_port_table[index].port_number = p_port->port_number; + socket.p_app_data = &m_port_table[index]; + UNUSED_VARIABLE(udp6_socket_app_data_set(&socket)); + } + } + + if (err_code != NRF_SUCCESS) + { + //Not all procedures succeeded with allocated socket, hence free it. + UNUSED_VARIABLE(udp6_socket_free(&socket)); + } + } + return err_code; +} + + +uint32_t coap_transport_init(const coap_transport_init_t * p_param) +{ + uint32_t err_code = NRF_ERROR_NO_MEM; + uint32_t index; + + NULL_PARAM_CHECK(p_param); + NULL_PARAM_CHECK(p_param->p_port_table); + + for (index = 0; index < COAP_PORT_COUNT; index++) + { + // Create end point for each of the CoAP ports. + err_code = port_create(index, &p_param->p_port_table[index]); + if (err_code != NRF_SUCCESS) + { + break; + } + } + + return err_code; +} + + +uint32_t coap_transport_write(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const uint8_t * p_data, + uint16_t datalen) +{ + uint32_t err_code = NRF_ERROR_NOT_FOUND; + uint32_t index; + udp6_socket_t socket; + ipv6_addr_t remote_addr; + iot_pbuffer_t * p_buffer; + iot_pbuffer_alloc_param_t buffer_param; + + NULL_PARAM_CHECK(p_port); + NULL_PARAM_CHECK(p_remote); + NULL_PARAM_CHECK(p_data); + + memcpy(remote_addr.u8, p_remote->addr, 16); + + + buffer_param.type = UDP6_PACKET_TYPE; + buffer_param.flags = PBUFFER_FLAG_DEFAULT; + buffer_param.length = datalen; + + //Search for the corresponding port. + for (index = 0; index < COAP_PORT_COUNT; index ++) + { + if (m_port_table[index].port_number == p_port->port_number) + { + //Allocate buffer to send the data on port. + err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer); + + if (err_code == NRF_SUCCESS) + { + socket.socket_id = m_port_table[index].socket_id; + + //Make a copy of the data onto the buffer. + memcpy (p_buffer->p_payload, p_data, datalen); + + COAP_MUTEX_UNLOCK(); + + //Send on UDP port. + err_code = udp6_socket_sendto(&socket, + &remote_addr, + p_remote->port_number, + p_buffer); + + COAP_MUTEX_LOCK(); + + if (err_code != NRF_SUCCESS) + { + //Free the allocated buffer as send procedure has failed. + UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true)); + } + } + break; + } + } + + return err_code; +} + + +void coap_transport_process(void) +{ + return; +} + +uint32_t coap_security_setup(uint16_t local_port, + nrf_tls_role_t role, + coap_remote_t * const p_remote, + nrf_tls_key_settings_t * const p_settings) +{ + return NRF_ERROR_API_NOT_IMPLEMENTED; +} + + +uint32_t coap_security_destroy(uint16_t local_port, + coap_remote_t * const p_remote) +{ + return NRF_ERROR_API_NOT_IMPLEMENTED; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c new file mode 100644 index 0000000..6245a97 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c @@ -0,0 +1,255 @@ +/** + * Copyright (c) 2014 - 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 <stdint.h> +#include "sdk_errors.h" +#include "sdk_config.h" +#include "iot_common.h" +#include "coap_transport.h" +#include "coap.h" +#include "lwip/ip6_addr.h" +/*lint -save -e607 Suppress warning 607 "Parameter p of macro found within string" */ +#include "lwip/udp.h" +/*lint -restore */ + + +/**@brief UDP port information. */ +typedef struct +{ + struct udp_pcb * p_socket; /**< Socket information provided by UDP. */ + uint16_t port_number; /**< Associated port number. */ +}udp_port_t; + +static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */ + + +/**@brief Callback handler to receive data on the UDP port. + * + * @details Callback handler to receive data on the UDP port. + * + * @param[in] p_arg Receive argument associated with the UDP socket. + * @param[in] p_socket Socket identifier. + * @param[in] p_ip_header IPv6 header containing source and destination addresses. + * @param[in] p_remote_addr IPv6 address of the remote device. + * @param[in] port Port number identifying the remote endpoint. + * + * @retval NRF_SUCCESS Indicates received data was handled successfully, else an an + * error code indicating reason for failure. + */ +static void udp_recv_data_handler(void * p_arg, + struct udp_pcb * p_socket, + struct pbuf * p_buffer, + const ip6_addr_t * p_remote_addr, + u16_t port) +{ + uint32_t index; + coap_remote_t remote_endpoint; + coap_port_t local_port = {p_socket->local_port}; + + for (index = 0; index < COAP_PORT_COUNT; index++) + { + if (m_port_table[index].p_socket == p_socket) + { + memcpy (remote_endpoint.addr, p_remote_addr, 16); + remote_endpoint.port_number = port; + + COAP_MUTEX_LOCK(); + + UNUSED_VARIABLE(coap_transport_read(&local_port, + &remote_endpoint, + NULL, + NRF_SUCCESS, + (uint8_t *)p_buffer->payload, + (uint32_t)p_buffer->len)); + + COAP_MUTEX_UNLOCK(); + + break; + } + } + + //Freeing packet (irrespective of matching p_socket is found or not + //to avoid memory leaks in the system. + UNUSED_VARIABLE(pbuf_free(p_buffer)); +} + + +/**@brief Creates port as requested in p_port. + * + * @details Creates port as requested in p_port. + * + * @param[in] index Index to the m_port_table where entry of the port created is to be made. + * @param[in] p_port Port information to be created. + * + * @retval NRF_SUCCESS Indicates if port was created successfully, else an an error code + * indicating reason for failure. + */ +static uint32_t port_create(uint32_t index, coap_port_t * p_port) +{ + err_t err = NRF_ERROR_NO_MEM; + ip6_addr_t any_addr; + struct udp_pcb * p_socket = m_port_table[index].p_socket; + + ip6_addr_set_any(&any_addr); + + //Request new socket creation. + p_socket = udp_new(); + + if (NULL != p_socket) + { + // Bind the socket to the local port. + err = udp_bind(p_socket, &any_addr, p_port->port_number); + if (err == ERR_OK) + { + //Register data receive callback. + udp_recv(p_socket, udp_recv_data_handler, &m_port_table[index]); + //All procedure with respect to port creation succeeded, make entry in the table. + m_port_table[index].port_number = p_port->port_number; + m_port_table[index].p_socket = p_socket; + } + else + { + //Not all procedures succeeded with allocated socket, hence free it. + err = NRF_ERROR_INVALID_PARAM; + udp_remove(p_socket); + } + } + + return err; +} + + +uint32_t coap_transport_init(const coap_transport_init_t * p_param) +{ + uint32_t err_code = NRF_SUCCESS; + uint32_t index; + + NULL_PARAM_CHECK(p_param); + NULL_PARAM_CHECK(p_param->p_port_table); + + for (index = 0; index < COAP_PORT_COUNT; index++) + { + // Create end point for each of the COAP ports. + err_code = port_create(index, &p_param->p_port_table[index]); + if (err_code != NRF_SUCCESS) + { + break; + } + } + + return err_code; +} + + +uint32_t coap_transport_write(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const uint8_t * p_data, + uint16_t datalen) +{ + + err_t err = NRF_ERROR_NOT_FOUND; + uint32_t index; + + NULL_PARAM_CHECK(p_port); + NULL_PARAM_CHECK(p_remote); + NULL_PARAM_CHECK(p_data); + + //Search for the corresponding port. + for (index = 0; index < COAP_PORT_COUNT; index++) + { + if (m_port_table[index].port_number == p_port->port_number) + { + //Allocate Buffer to send the data on port. + struct pbuf * lwip_buffer = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + + if (NULL != lwip_buffer) + { + //Make a copy of the data onto the buffer. + memcpy(lwip_buffer->payload, p_data, datalen); + + COAP_MUTEX_UNLOCK(); + + //Send on UDP port. + err = udp_sendto(m_port_table[index].p_socket, + lwip_buffer, + (ip6_addr_t *)p_remote->addr, + p_remote->port_number); + + COAP_MUTEX_LOCK(); + + + if (err != ERR_OK) + { + //Free the allocated buffer as send procedure has failed. + err = NRF_ERROR_INTERNAL; + } + UNUSED_VARIABLE(pbuf_free(lwip_buffer)); + } + else + { + //Buffer allocation failed, cannot send data. + err = NRF_ERROR_NO_MEM; + } + break; + } + } + return err; +} + + +void coap_transport_process(void) +{ + return; +} + + +uint32_t coap_security_setup(uint16_t local_port, + nrf_tls_role_t role, + coap_remote_t * const p_remote, + nrf_tls_key_settings_t * const p_settings) +{ + return NRF_ERROR_API_NOT_IMPLEMENTED; +} + + +uint32_t coap_security_destroy(uint16_t local_port, + coap_remote_t * const p_remote) +{ + return NRF_ERROR_API_NOT_IMPLEMENTED; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c new file mode 100644 index 0000000..d19737f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c @@ -0,0 +1,292 @@ +/** + * Copyright (c) 2014 - 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 <sys/socket.h> +#include <sys/select.h> +#include <netinet/in.h> +#ifdef UNIX +#include <fcntl.h> +#endif +#include <errno.h> +#include <stdint.h> +#include "mem_manager.h" +#include "sdk_errors.h" +#include "sdk_config.h" +#include "iot_common.h" +#include "nordic_common.h" +#include "coap_transport.h" +#include "coap.h" + +/**@brief UDP port information. */ +typedef struct +{ + int socket_fd; /**< Socket information provided by UDP. */ + uint16_t port_number; /**< Associated port number. */ +} udp_port_t; + +static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */ + +static fd_set m_readfds; +static int m_max_sd = 0; + +/**@brief Creates port as requested in p_port. + * + * @details Creates port as requested in p_port. + * + * @param[in] index Index to the m_port_table where entry of the port created is to be made. + * @param[in] p_port Port information to be created. + * + * @retval NRF_SUCCESS Indicates if port was created successfully, else an an error code + * indicating reason for failure. + */ +static uint32_t port_create(uint32_t index, coap_port_t * p_port) +{ + // Request new socket creation. + int socket_fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + if (socket_fd != -1) + { + // Bind the socket to the local port. + struct sockaddr_in6 sin6; + + memset(&sin6, 0, sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(p_port->port_number); + sin6.sin6_addr = in6addr_any; + + int retval = bind(socket_fd, (struct sockaddr *)&sin6, sizeof(sin6)); + if (retval != -1) + { + m_port_table[index].port_number = p_port->port_number; + m_port_table[index].socket_fd = socket_fd; + } + else + { + // Not all procedures succeeded with allocated socket, hence free it. + UNUSED_VARIABLE(close(socket_fd)); + return NRF_ERROR_INVALID_PARAM; + } + } + + // Configure socket to be non-blocking. + int flags = fcntl(socket_fd, F_GETFL, 0); + flags |= O_NONBLOCK; + UNUSED_VARIABLE(fcntl(m_port_table[index].socket_fd, F_SETFL, flags)); + + // Add socket to file descriptor set. + FD_SET(m_port_table[index].socket_fd, &m_readfds); + + // If enumeration is having a gap, increase the max fd count. + if (socket_fd >= m_max_sd) + { + m_max_sd = (socket_fd + 1); + } + + return NRF_SUCCESS; +} + + +uint32_t coap_transport_init(const coap_transport_init_t * p_param) +{ + uint32_t err_code = NRF_SUCCESS; + uint32_t index; + + NULL_PARAM_CHECK(p_param); + NULL_PARAM_CHECK(p_param->p_port_table); + + FD_ZERO(&m_readfds); + + err_code = nrf_mem_init(); + + if (err_code == NRF_SUCCESS) { + for (index = 0; index < COAP_PORT_COUNT; index++) + { + // Create end point for each of the COAP ports. + err_code = port_create(index, &p_param->p_port_table[index]); + if (err_code != NRF_SUCCESS) + { + break; + } + } + } + + return err_code; +} + + +uint32_t coap_transport_write(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const uint8_t * p_data, + uint16_t datalen) +{ + + uint32_t err_code = NRF_ERROR_NOT_FOUND; + uint32_t index; + + NULL_PARAM_CHECK(p_port); + NULL_PARAM_CHECK(p_remote); + NULL_PARAM_CHECK(p_data); + + // Search for the corresponding port. + for (index = 0; index < COAP_PORT_COUNT; index++) + { + if (m_port_table[index].port_number == p_port->port_number) + { + COAP_MUTEX_UNLOCK(); + + static struct sockaddr_in6 dest_address_in6; + + memset(&dest_address_in6, 0, sizeof(struct sockaddr_in6)); + dest_address_in6.sin6_family = AF_INET6; + dest_address_in6.sin6_port = htons(p_remote->port_number); + + memcpy(&dest_address_in6.sin6_addr, p_remote->addr, sizeof(struct in6_addr)); + + // Send on UDP port. + int retval = sendto(m_port_table[index].socket_fd, + p_data, + datalen, + 0, + (struct sockaddr *)&dest_address_in6, + sizeof(dest_address_in6)); + if (retval == -1) + { + // Error in sendto. + err_code = NRF_ERROR_INTERNAL; + } + else + { + err_code = NRF_SUCCESS; + } + + COAP_MUTEX_LOCK(); + break; + } + } + + return err_code; +} + + +void coap_transport_process(void) +{ + return; +} + + +uint32_t coap_security_setup(uint16_t local_port, + nrf_tls_role_t role, + coap_remote_t * const p_remote, + nrf_tls_key_settings_t * const p_settings) +{ + return SDK_ERR_API_NOT_IMPLEMENTED; +} + + +uint32_t coap_security_destroy(uint16_t local_port, + coap_remote_t * const p_remote) +{ + return SDK_ERR_API_NOT_IMPLEMENTED; +} + + +void coap_transport_input(void) +{ + int retval = select(m_max_sd, &m_readfds, NULL, NULL, NULL); + + if (retval == -1) + { + // Error in select(). + // Placeholder for debugging. + } + else if (retval >= 1) // Number of file descriptiors with activity. + { + uint32_t index = 0; + int socket_fd = m_port_table[index].socket_fd; + + // The descriptor has data. + if (FD_ISSET(socket_fd, &m_readfds)) // If socket_fd is set to read. + { + static uint8_t read_mem[COAP_MESSAGE_DATA_MAX_SIZE]; + static struct sockaddr_in6 client_address_in6; + socklen_t address_length = sizeof(struct sockaddr_in6); + + int bytes_read = recvfrom(socket_fd, + read_mem, + sizeof(read_mem), + 0, + (struct sockaddr *)&client_address_in6, + (socklen_t *)&address_length); // Blocking call, waiting for incoming transaction. + if (bytes_read >= 0) + { + coap_port_t port; + port.port_number = m_port_table[index].port_number; + + coap_remote_t remote_endpoint; + memcpy(remote_endpoint.addr, &client_address_in6.sin6_addr, sizeof(struct in6_addr)); + remote_endpoint.port_number = ntohs(client_address_in6.sin6_port); + + uint32_t result = NRF_SUCCESS; + + // Notify the CoAP module of received data. + retval = coap_transport_read(&port, + &remote_endpoint, + NULL, + result, + read_mem, + (uint16_t)bytes_read); + + // Nothing much to do if CoAP could not interpret the datagram. + UNUSED_VARIABLE(retval); + } + else + { + // Error in readfrom(). + // Placeholder for debugging. + // If select() indicated this socket file descriptor to have pending + // data, this case should not occur. + } + } + } + else + { + // In case of socket() returning 0, timeout. + // Not implemented. + } +} |