diff options
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.c | 996 |
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; +} |