/** * 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; }