From 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 23 Aug 2018 17:08:59 +0200 Subject: o Initial import. --- .../components/iot/ipv6_stack/udp/udp.h | 98 +++ .../components/iot/ipv6_stack/udp/udp6.c | 708 +++++++++++++++++++++ 2 files changed, 806 insertions(+) create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp6.c (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp') diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp.h new file mode 100644 index 0000000..ae316b0 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp.h @@ -0,0 +1,98 @@ +/** + * 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. + * + */ +/** @cond */ + /** @file udp.h + * + * @defgroup iot_udp UDP Module Header. + * @ingroup iot_sdk + * @{ + * @brief User Datagram Protocol module header defining interface between + * UDP and other IP stack layers which are not exposed to the application. + */ + +#ifndef UDP_H__ +#define UDP_H__ + +#include "sdk_config.h" +#include "sdk_common.h" +#include "ipv6_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Module initialization function called from ipv6_init(). This shall not be called by the + * application explicitly. + * + * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason + * for failure. + */ +uint32_t udp_init(void); + + +/** + * @brief Function to feed incoming UDP packets to the module. To be called by the IPv6 + * stack only and never by the application. + * + * @param[in] p_interface Identifies network interface on which the packet is received. + * @param[in] p_ip_header IP Header of the UDP packet being fed to the module. + * @param[in] p_packet UDP packet being notified to the module. p_packet->p_payload points the + * IPv6 payload and p_packet->length indicates total length of the payload. + * + * @note This routine is called by the stack with next header field value is set to UDP protocol + * value of 17. + * + * @retval NRF_SUCCESS on successful handling of the packet, else an error code indicating reason + * for failure. + */ +uint32_t udp_input(const iot_interface_t * p_interface, + const ipv6_header_t * p_ip_header, + iot_pbuffer_t * p_packet); + +#ifdef __cplusplus +} +#endif + +#endif //UDP_H__ + +/**@} */ + +/** @endcond */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp6.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp6.c new file mode 100644 index 0000000..0572c4a --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp6.c @@ -0,0 +1,708 @@ +/** + * 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 "nordic_common.h" +#include "sdk_common.h" +#include "sdk_config.h" +#include "iot_common.h" +#include "iot_pbuffer.h" +#include "udp_api.h" +#include "udp.h" +#include "ipv6_utils.h" + +#if UDP6_CONFIG_LOG_ENABLED + +#define NRF_LOG_MODULE_NAME udp6 + +#define NRF_LOG_LEVEL UDP6_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR UDP6_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR UDP6_CONFIG_DEBUG_COLOR + +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define UDP6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */ +#define UDP6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */ +#define UDP6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */ + +#define UDP6_ENTRY() UDP6_TRC(">> %s", __func__) +#define UDP6_EXIT() UDP6_TRC("<< %s", __func__) + +#else // UDP6_CONFIG_LOG_ENABLED + +#define UDP6_TRC(...) /**< Disables traces. */ +#define UDP6_DUMP(...) /**< Disables dumping of octet streams. */ +#define UDP6_ERR(...) /**< Disables error logs. */ + +#define UDP6_ENTRY(...) +#define UDP6_EXIT(...) + +#endif // UDP6_CONFIG_LOG_ENABLED + +/** + * @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. + * UDP_DISABLE_API_PARAM_CHECK should be set to 1 to disable these checks. + * + * @{ + */ +#if (UDP6_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Macro to check is module is initialized before requesting one of the module procedures. */ +#define VERIFY_MODULE_IS_INITIALIZED() \ + if (m_initialization_state == false) \ + { \ + return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_UDP6_ERR_BASE); \ + } + +/**@brief Macro to check is module is initialized before requesting one of the module + procedures but does not use any return code. */ +#define VERIFY_MODULE_IS_INITIALIZED_VOID() \ + if (m_initialization_state == false) \ + { \ + return; \ + } + +/** + * @brief Verify NULL parameters are not passed to API by application. + */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_UDP6_ERR_BASE); \ + } + +/** + * @brief Verify socket id passed on the API by application is valid. + */ +#define VERIFY_SOCKET_ID(ID) \ + if (((ID) >= UDP6_MAX_SOCKET_COUNT)) \ + { \ + return (NRF_ERROR_INVALID_ADDR | IOT_UDP6_ERR_BASE); \ + } + +/** + * @brief Verify socket id passed on the API by application is valid. + */ +#define VERIFY_PORT_NUMBER(PORT) \ + if ((PORT) == 0) \ + { \ + return (NRF_ERROR_INVALID_PARAM | IOT_UDP6_ERR_BASE); \ + } + +/** + * @brief Verify socket id passed on the API by application is valid. + */ +#define VERIFY_NON_ZERO_LENGTH(LEN) \ + if ((LEN) == 0) \ + { \ + return (NRF_ERROR_INVALID_LENGTH | IOT_UDP6_ERR_BASE); \ + } + +#else // UDP6_DISABLE_API_PARAM_CHECK + +#define VERIFY_MODULE_IS_INITIALIZED() +#define VERIFY_MODULE_IS_INITIALIZED_VOID() +#define NULL_PARAM_CHECK(PARAM) +#define VERIFY_SOCKET_ID(ID) +#endif //UDP6_DISABLE_API_PARAM_CHECK + +/** + * @defgroup ble_ipsp_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 need arises to use an alternative architecture. + * @{ + */ +#define UDP_MUTEX_LOCK() SDK_MUTEX_LOCK(m_udp_mutex) /**< Lock module using mutex */ +#define UDP_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_udp_mutex) /**< Unlock module using mutex */ +/** @} */ + +#define UDP_PORT_FREE 0 /**< Reserved port of the socket, indicates that port is free. */ + +/**@brief UDP Socket Data needed by the module to manage it. */ +typedef struct +{ + uint16_t local_port; /**< Local Port of the socket. */ + uint16_t remote_port; /**< Remote port of the socket. */ + ipv6_addr_t local_addr; /**< Local IPv6 Address of the socket. */ + ipv6_addr_t remote_addr; /**< Remote IPv6 Address of the socket. */ + udp6_handler_t rx_cb; /**< Callback registered by application to receive data on the socket. */ + void * p_app_data; /**< Application data mapped to the socket using the udp6_app_data_set. */ +} udp_socket_entry_t; + + +SDK_MUTEX_DEFINE(m_udp_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */ +static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */ +static udp_socket_entry_t m_socket[UDP6_MAX_SOCKET_COUNT]; /**< Table of sockets managed by the module. */ + + +/** @brief Initializes socket managed by the module. */ +static void udp_socket_init(udp_socket_entry_t * p_socket) +{ + p_socket->local_port = UDP_PORT_FREE; + p_socket->remote_port = UDP_PORT_FREE; + p_socket->rx_cb = NULL; + p_socket->p_app_data = NULL; + IPV6_ADDRESS_INITIALIZE(&p_socket->local_addr); + IPV6_ADDRESS_INITIALIZE(&p_socket->remote_addr); +} + +/** + * @brief Find UDP socket based on local port. If found its index to m_socket table is returned. + * else UDP6_MAX_SOCKET_COUNT is returned. + */ +static uint32_t socket_find(uint16_t port) +{ + uint32_t index; + + for (index = 0; index < UDP6_MAX_SOCKET_COUNT; index++) + { + if (m_socket[index].local_port == port) + { + break; + } + } + + return index; +} + + +uint32_t udp_init(void) +{ + uint32_t index; + + UDP6_ENTRY(); + + SDK_MUTEX_INIT(m_udp_mutex); + + UDP_MUTEX_LOCK(); + + for (index = 0; index < UDP6_MAX_SOCKET_COUNT; index++) + { + udp_socket_init(&m_socket[index]); + } + + m_initialization_state = true; + + UDP6_EXIT(); + + UDP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + + +uint32_t udp6_socket_allocate(udp6_socket_t * p_socket) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + //Search for an unassigned socket. + const uint32_t socket_id = socket_find(UDP_PORT_FREE); + uint32_t err_code = NRF_SUCCESS; + + if (socket_id != UDP6_MAX_SOCKET_COUNT) + { + UDP6_TRC("Assigned socket 0x%08lX", socket_id); + + // Found a free socket. Assign. + p_socket->socket_id = socket_id; + } + else + { + // No free socket found. + UDP6_ERR("No room for new socket."); + err_code = (NRF_ERROR_NO_MEM | IOT_UDP6_ERR_BASE); + } + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return err_code; +} + + +uint32_t udp6_socket_free(const udp6_socket_t * p_socket) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + VERIFY_SOCKET_ID(p_socket->socket_id); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + udp_socket_init(&m_socket[p_socket->socket_id]); + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t udp6_socket_recv(const udp6_socket_t * p_socket, + const udp6_handler_t callback) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + NULL_PARAM_CHECK(callback); + VERIFY_SOCKET_ID(p_socket->socket_id); + VERIFY_PORT_NUMBER(m_socket[p_socket->socket_id].local_port); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + m_socket[p_socket->socket_id].rx_cb = callback; + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t udp6_socket_bind(const udp6_socket_t * p_socket, + const ipv6_addr_t * p_src_addr, + uint16_t src_port) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + NULL_PARAM_CHECK(p_src_addr); + VERIFY_SOCKET_ID(p_socket->socket_id); + VERIFY_PORT_NUMBER(src_port); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + uint32_t err_code = NRF_SUCCESS; + + // Change Host Byte Order to Network Byte Order. + src_port = HTONS(src_port); + + //Check if port is already registered. + for (uint32_t index = 0; index < UDP6_MAX_SOCKET_COUNT; index ++) + { + if (m_socket[index].local_port == src_port) + { + err_code = UDP_PORT_IN_USE; + } + } + + if (err_code == NRF_SUCCESS) + { + m_socket[p_socket->socket_id].local_port = src_port; + m_socket[p_socket->socket_id].local_addr = (*p_src_addr); + + } + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return err_code; +} + + +uint32_t udp6_socket_connect(const udp6_socket_t * p_socket, + const ipv6_addr_t * p_dest_addr, + uint16_t dest_port) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + NULL_PARAM_CHECK(p_dest_addr); + VERIFY_SOCKET_ID(p_socket->socket_id); + VERIFY_PORT_NUMBER(dest_port); + VERIFY_PORT_NUMBER(m_socket[p_socket->socket_id].local_port); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + m_socket[p_socket->socket_id].remote_port = HTONS(dest_port); + m_socket[p_socket->socket_id].remote_addr = (*p_dest_addr); + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t udp6_socket_send(const udp6_socket_t * p_socket, + iot_pbuffer_t * p_packet) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + NULL_PARAM_CHECK(p_packet); + NULL_PARAM_CHECK(p_packet->p_payload); + VERIFY_NON_ZERO_LENGTH(p_packet->length); + VERIFY_SOCKET_ID(p_socket->socket_id); + VERIFY_PORT_NUMBER(m_socket[p_socket->socket_id].local_port); + VERIFY_PORT_NUMBER(m_socket[p_socket->socket_id].remote_port); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + uint32_t err_code; + const udp_socket_entry_t * p_skt = &m_socket[p_socket->socket_id]; + const uint32_t header_size = UDP_HEADER_SIZE + IPV6_IP_HEADER_SIZE; + udp6_header_t * p_header = (udp6_header_t *)(p_packet->p_payload - UDP_HEADER_SIZE); + ipv6_header_t * p_ip_header = (ipv6_header_t *)(p_packet->p_payload - header_size); + iot_interface_t * p_interface = NULL; + uint16_t checksum; + + p_header->srcport = p_skt->local_port; + p_header->destport = p_skt->remote_port; + p_header->checksum = 0; + + p_header->length = HTONS(p_packet->length + UDP_HEADER_SIZE); + + // Pack destination address. + p_ip_header->destaddr = p_skt->remote_addr; + + // Pack source address. + if ((0 == IPV6_ADDRESS_CMP(&p_skt->local_addr, IPV6_ADDR_ANY))) + { + err_code = ipv6_address_find_best_match(&p_interface, + &p_ip_header->srcaddr, + &p_ip_header->destaddr); + } + else + { + err_code = ipv6_address_find_best_match(&p_interface, + NULL, + &p_ip_header->destaddr); + + p_ip_header->srcaddr = p_skt->local_addr; + } + + if (err_code == NRF_SUCCESS) + { + // Pack next header. + p_ip_header->next_header = IPV6_NEXT_HEADER_UDP; + + //Pack HOP Limit. + p_ip_header->hoplimit = IPV6_DEFAULT_HOP_LIMIT; + + //Traffic class and flow label. + p_ip_header->version_traffic_class = 0x60; + p_ip_header->traffic_class_flowlabel = 0x00; + p_ip_header->flowlabel = 0x0000; + + // Length. + p_ip_header->length = HTONS(p_packet->length + UDP_HEADER_SIZE); + + checksum = p_packet->length + UDP_HEADER_SIZE + IPV6_NEXT_HEADER_UDP; + + ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false); + ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false); + ipv6_checksum_calculate(p_packet->p_payload - UDP_HEADER_SIZE, + p_packet->length + UDP_HEADER_SIZE, + &checksum, + true); + + p_header->checksum = HTONS((~checksum)); + + p_packet->p_payload -= header_size; + p_packet->length += header_size; + + err_code = ipv6_send(p_interface, p_packet); + } + else + { + err_code = UDP_INTERFACE_NOT_READY; + } + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return err_code; +} + + +uint32_t udp6_socket_sendto(const udp6_socket_t * p_socket, + const ipv6_addr_t * p_dest_addr, + uint16_t dest_port, + iot_pbuffer_t * p_packet) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + NULL_PARAM_CHECK(p_dest_addr); + NULL_PARAM_CHECK(p_packet); + NULL_PARAM_CHECK(p_packet->p_payload); + VERIFY_NON_ZERO_LENGTH(p_packet->length); + VERIFY_SOCKET_ID(p_socket->socket_id); + VERIFY_PORT_NUMBER(dest_port); + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + uint32_t err_code; + const udp_socket_entry_t * p_skt = &m_socket[p_socket->socket_id]; + const uint32_t header_size = UDP_HEADER_SIZE + IPV6_IP_HEADER_SIZE; + udp6_header_t * p_header = (udp6_header_t *)(p_packet->p_payload - UDP_HEADER_SIZE); + ipv6_header_t * p_ip_header = (ipv6_header_t *)(p_packet->p_payload - header_size); + iot_interface_t * p_interface = NULL; + uint16_t checksum; + + p_header->srcport = p_skt->local_port; + p_header->destport = HTONS(dest_port); + p_header->checksum = 0; + + checksum = p_packet->length + UDP_HEADER_SIZE + IPV6_NEXT_HEADER_UDP; + + p_header->length = HTONS(p_packet->length + UDP_HEADER_SIZE); + + //Pack destination address. + p_ip_header->destaddr = *p_dest_addr; + + // Pack source address. + if ((0 == IPV6_ADDRESS_CMP(&p_skt->local_addr, IPV6_ADDR_ANY))) + { + err_code = ipv6_address_find_best_match(&p_interface, + &p_ip_header->srcaddr, + &p_ip_header->destaddr); + } + else + { + err_code = ipv6_address_find_best_match(&p_interface, + NULL, + &p_ip_header->destaddr); + + p_ip_header->srcaddr = p_skt->local_addr; + } + + if (err_code == NRF_SUCCESS) + { + //Pack next header. + p_ip_header->next_header = IPV6_NEXT_HEADER_UDP; + + //Pack HOP Limit. + p_ip_header->hoplimit = IPV6_DEFAULT_HOP_LIMIT; + + //Traffic class and flow label. + p_ip_header->version_traffic_class = 0x60; + p_ip_header->traffic_class_flowlabel = 0x00; + p_ip_header->flowlabel = 0x0000; + + // Length. + p_ip_header->length = HTONS(p_packet->length + UDP_HEADER_SIZE); + + ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false); + ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false); + ipv6_checksum_calculate(p_packet->p_payload - UDP_HEADER_SIZE, + p_packet->length + UDP_HEADER_SIZE, + &checksum, + true); + + p_header->checksum = HTONS((~checksum)); + + p_packet->p_payload -= header_size; + p_packet->length += header_size; + + err_code = ipv6_send(p_interface, p_packet); + } + else + { + err_code = UDP_INTERFACE_NOT_READY; + } + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return err_code; +} + + +uint32_t udp6_socket_app_data_set(const udp6_socket_t * p_socket) +{ + VERIFY_MODULE_IS_INITIALIZED(); + NULL_PARAM_CHECK(p_socket); + VERIFY_SOCKET_ID(p_socket->socket_id); + + //Note: no null check is performed on the p_app_data as it is permissible + //to pass on a NULL value if need be. + + UDP6_ENTRY(); + + UDP_MUTEX_LOCK(); + + m_socket[p_socket->socket_id].p_app_data = p_socket->p_app_data; + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t udp_input(const iot_interface_t * p_interface, + const ipv6_header_t * p_ip_header, + iot_pbuffer_t * p_packet) +{ + NULL_PARAM_CHECK(p_interface); + NULL_PARAM_CHECK(p_ip_header); + NULL_PARAM_CHECK(p_packet); + + UNUSED_VARIABLE(p_interface); + + uint32_t err_code = (NRF_ERROR_NOT_FOUND | IOT_UDP6_ERR_BASE); + + if ((p_packet->length > UDP_HEADER_SIZE) && (p_ip_header->length > UDP_HEADER_SIZE)) + { + UDP_MUTEX_LOCK(); + + UDP6_ENTRY(); + + uint32_t index; + udp6_header_t * p_udp_header = (udp6_header_t *)(p_packet->p_payload); + + // Check to which UDP socket, port and address was bind. + for (index = 0; index < UDP6_MAX_SOCKET_COUNT; index ++) + { + if (m_socket[index].local_port == p_udp_header->destport) + { + if ((0 == IPV6_ADDRESS_CMP(&m_socket[index].local_addr, IPV6_ADDR_ANY)) || + (0 == IPV6_ADDRESS_CMP(&m_socket[index].local_addr, &p_ip_header->destaddr))) + { + // Check if connection was established. + if (m_socket[index].remote_port == 0 || m_socket[index].remote_port == p_udp_header->srcport) + { + if ((0 == IPV6_ADDRESS_CMP(&m_socket[index].remote_addr, IPV6_ADDR_ANY)) || + (0 == IPV6_ADDRESS_CMP(&m_socket[index].remote_addr, &p_ip_header->srcaddr))) + { + err_code = NRF_SUCCESS; + break; + } + } + } + } + } + + if (index < UDP6_MAX_SOCKET_COUNT) + { + uint16_t checksum = p_packet->length + IPV6_NEXT_HEADER_UDP; + uint32_t process_result = NRF_SUCCESS; + uint16_t udp_hdr_length = NTOHS(p_udp_header->length); + + if (udp_hdr_length > p_packet->length) + { + UDP6_ERR("Received truncated packet, " + "payload length 0x%08lX, length in header 0x%08X.", + p_packet->length, NTOHS(p_udp_header->length)); + process_result = UDP_TRUNCATED_PACKET; + } + else if (udp_hdr_length < p_packet->length) + { + UDP6_ERR("Received malformed packet, " + "payload length 0x%08lX, length in header 0x%08X.", + p_packet->length, NTOHS(p_udp_header->length)); + + process_result = UDP_MALFORMED_PACKET; + } + else + { + ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false); + ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false); + ipv6_checksum_calculate(p_packet->p_payload, p_packet->length, &checksum, false); + + if (checksum != 0 && checksum != 0xFFFF) + { + UDP6_ERR("Bad checksum detected."); + process_result = UDP_BAD_CHECKSUM; + } + } + + p_packet->p_payload = p_packet->p_payload + UDP_HEADER_SIZE; + p_packet->length -= UDP_HEADER_SIZE; + + //Found port for which data is intended. + const udp6_socket_t sock = {index, m_socket[index].p_app_data}; + + //Give application a callback if callback is registered. + if (m_socket[index].rx_cb != NULL) + { + UDP_MUTEX_UNLOCK(); + + // Change byte ordering given to application. + p_udp_header->destport = NTOHS(p_udp_header->destport); + p_udp_header->srcport = NTOHS(p_udp_header->srcport); + p_udp_header->length = NTOHS(p_udp_header->length); + p_udp_header->checksum = NTOHS(p_udp_header->checksum); + + err_code = m_socket[index].rx_cb(&sock, p_ip_header, p_udp_header, process_result, p_packet); + + UDP_MUTEX_LOCK(); + } + } + else + { + UDP6_ERR("Packet received on unknown port, dropping!"); + } + + UDP_MUTEX_UNLOCK(); + + UDP6_EXIT(); + } + else + { + UDP6_ERR("Packet of length less than UDP header size received!"); + err_code = (IOT_UDP6_ERR_BASE | NRF_ERROR_INVALID_LENGTH); + } + + return err_code; +} -- cgit v1.2.3