aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c996
1 files changed, 996 insertions, 0 deletions
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;
+}