aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c1088
1 files changed, 1088 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c
new file mode 100644
index 0000000..6d7b641
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c
@@ -0,0 +1,1088 @@
+/**
+ * Copyright (c) 2013 - 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "ble_6lowpan.h"
+#include "mem_manager.h"
+#include "sdk_os.h"
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "iot_context_manager.h"
+#include "ipv6_api.h"
+#include "icmp6_api.h"
+#include "udp_api.h"
+#include "icmp6.h"
+#include "udp.h"
+
+#if IPV6_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME ipv6
+
+#define NRF_LOG_LEVEL IPV6_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IPV6_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IPV6_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define IPV6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define IPV6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define IPV6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define IPV6_ENTRY() IPV6_TRC(">> %s", __func__)
+#define IPV6_EXIT() IPV6_TRC("<< %s", __func__)
+
+#else // IPV6_CONFIG_LOG_ENABLED
+
+#define IPV6_TRC(...) /**< Disables traces. */
+#define IPV6_DUMP(...) /**< Disables dumping of octet streams. */
+#define IPV6_ERR(...) /**< Disables error logs. */
+
+#define IPV6_ENTRY(...)
+#define IPV6_EXIT(...)
+
+#endif // IPV6_CONFIG_LOG_ENABLED
+
+/**
+ * @defgroup ipv6_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 IPV6_MUTEX_LOCK() SDK_MUTEX_LOCK(m_ipv6_mutex) /**< Lock module using mutex */
+#define IPV6_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_ipv6_mutex) /**< Unlock module using mutex */
+/** @} */
+
+/**
+ * @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.
+ * IPV6_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+
+#if (IPV6_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_event_handler == NULL) \
+ { \
+ return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_IPV6_ERR_BASE); \
+ }
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_IPV6_ERR_BASE); \
+ }
+
+#else // IPV6_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // IPV6_DISABLE_API_PARAM_CHECK
+/** @} */
+
+#define PBUFFER_ICMP_PAYLOAD_OFFSET IPV6_IP_HEADER_SIZE + ICMP6_HEADER_SIZE /**< ICMP payload offset. */
+#define PBUFFER_UDP_PAYLOAD_OFFSET IPV6_IP_HEADER_SIZE + UDP_HEADER_SIZE /**< UDP payload offset. */
+#define PBUFFER_OTHER_PAYLOAD_OFFSET IPV6_IP_HEADER_SIZE /**< Raw IPv6 payload offset. */
+
+#define IPV6_MAX_ADDRESS_COUNT (IPV6_MAX_ADDRESS_PER_INTERFACE * IPV6_MAX_INTERFACE) /**< Maximum number of addresses. */
+#define IPV6_INVALID_ADDR_INDEX 0xFF /**< Invalid address representation. */
+
+#define DEST_ADDR_OFFSET 24 /**< Offset of destination address in IPv6 packet. */
+
+/**@brief Internal interface structure. */
+typedef struct
+{
+ iot_interface_t * p_interface; /**< Pointer to driver interface */
+ uint8_t addr_range[IPV6_MAX_ADDRESS_PER_INTERFACE]; /**< Indexes to m_address_table indicating the address. If an index is IPV6_INVALID_ADDR_INDEX, it means there is no address entry. */
+} ipv6_interface_t;
+
+/**@brief Application Event Handler. */
+static ipv6_evt_handler_t m_event_handler = NULL;
+
+/**@brief Table of addresses */
+static ipv6_addr_conf_t m_address_table[IPV6_MAX_ADDRESS_COUNT];
+
+/**@brief Network interfaces table. */
+static ipv6_interface_t m_interfaces[IPV6_MAX_INTERFACE];
+
+/**@brief Number of network interfaces. */
+static uint32_t m_interfaces_count = 0;
+
+/**@brief Global address for IPv6 any. */
+ipv6_addr_t ipv6_addr_any;
+
+/**@brief Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+SDK_MUTEX_DEFINE(m_ipv6_mutex)
+
+
+/**@brief Function for finding specific address in address table.
+ *
+ * @param[in] p_addr Checked address.
+ * @param[out] p_index Index of address.
+ *
+ * @return NRF_SUCCESS if success, NRF_ERROR_NOT_FOUND otherwise.
+ */
+static uint32_t addr_find(const ipv6_addr_t * p_addr, uint32_t * p_index)
+{
+ uint32_t index;
+ uint32_t err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NOT_FOUND);
+
+ for (index = 0; index < IPV6_MAX_ADDRESS_COUNT; index++)
+ {
+ if ((m_address_table[index].state != IPV6_ADDR_STATE_UNUSED) &&
+ (0 == IPV6_ADDRESS_CMP(&m_address_table[index].addr, p_addr)))
+ {
+ *p_index = index;
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+/**@brief Function for finding free place in address table.
+ *
+ * @param[out] p_index Index of address.
+ *
+ * @return NRF_SUCCESS if success, NRF_ERROR_NOT_FOUND otherwise.
+ */
+static uint32_t addr_find_free(uint32_t * p_index)
+{
+ uint32_t index;
+ uint32_t err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NO_MEM);
+
+ for (index = 0; index < IPV6_MAX_ADDRESS_COUNT; index++)
+ {
+ if (m_address_table[index].state == IPV6_ADDR_STATE_UNUSED)
+ {
+ *p_index = index;
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for freeing an address configuration entry in m_address_table.
+ *
+ * @param[in] index Index of address.
+ * @param[in] check_references Indicate that before remove references should be counted.
+ *
+ * @return None.
+ */
+static void addr_free(uint32_t addr_index, bool check_references)
+{
+ uint32_t if_index;
+ uint32_t index;
+
+ if (check_references)
+ {
+ for (if_index = 0; if_index < IPV6_MAX_INTERFACE; if_index++)
+ {
+ for (index = 0; index < IPV6_MAX_ADDRESS_PER_INTERFACE; index++)
+ {
+ if (m_interfaces[if_index].addr_range[index] == addr_index)
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ m_address_table[addr_index].state = IPV6_ADDR_STATE_UNUSED;
+ IPV6_ADDRESS_INITIALIZE(&m_address_table[addr_index].addr);
+}
+
+
+/**@brief Function for checking if received packet is for us.
+ * Currently only all-node, MLDv2 and solicited-node
+* multicast addresses are accepted.
+ *
+ * @param[in] interface_id Index of the interface.
+ * @param[in] p_addr Checked address.
+ * @param[in] check_multicast Define if multicast addresses have to be checked.
+ *
+ * @return NRF_SUCCESS if packet can be processing to IPv6 multiplexer.
+ */
+static uint32_t addr_check(uint32_t interface_id, const ipv6_addr_t * p_addr, bool check_multicast)
+{
+ ipv6_addr_conf_t * p_addr_conf;
+ uint32_t index;
+ uint32_t err_code = NRF_ERROR_NOT_FOUND;
+
+ // Check basic Multicast addresses.
+ if (check_multicast && (IPV6_ADDRESS_IS_MLDV2_MCAST(p_addr) || IPV6_ADDRESS_IS_ALL_NODE(p_addr)))
+ {
+ return NRF_SUCCESS;
+ }
+
+ for (index = 0; m_interfaces[interface_id].addr_range[index] != IPV6_INVALID_ADDR_INDEX; index++)
+ {
+ p_addr_conf = &m_address_table[m_interfaces[interface_id].addr_range[index]];
+
+ if (check_multicast && IPV6_ADDRESS_IS_MULTICAST_SOLICITED_NODE(p_addr))
+ {
+ // Solicited-node multicast address is formed by taking the low-order 24 bits of an address (unicast or anycast).
+ if (0 == memcmp(&p_addr_conf->addr.u8[13], &p_addr->u8[13], 3))
+ {
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+ else if (0 == IPV6_ADDRESS_CMP(&p_addr_conf->addr, p_addr))
+ {
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for adding/updating IPv6 address in table.
+ *
+ * @param[in] interface_id Index of interface.
+ * @param[in] p_addr Given address.
+ *
+ * @return NRF_SUCCESS if operation successful, NRF_ERROR_NO_MEM otherwise.
+ */
+static uint32_t addr_set(const iot_interface_t * p_interface,
+ const ipv6_addr_conf_t * p_addr)
+{
+ uint32_t index;
+ uint32_t addr_index;
+ uint32_t err_code;
+
+ uint32_t interface_id = (uint32_t)p_interface->p_upper_stack;
+
+ // Try to find address.
+ err_code = addr_find(&p_addr->addr, &addr_index);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Find first empty one.
+ err_code = addr_find_free(&addr_index);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = IOT_IPV6_ERR_ADDR_IF_MISMATCH;
+
+ // Check if this index entry exists in the p_interface for which API is requested.
+ for (index = 0; index < IPV6_MAX_ADDRESS_PER_INTERFACE; index++)
+ {
+ if (m_interfaces[interface_id].addr_range[index] == addr_index)
+ {
+ m_address_table[index].state = p_addr->state;
+
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+
+ if (err_code == IOT_IPV6_ERR_ADDR_IF_MISMATCH)
+ {
+ err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NO_MEM);
+
+ for (index = 0; index < IPV6_MAX_ADDRESS_PER_INTERFACE; index++)
+ {
+ if (m_interfaces[interface_id].addr_range[index] == IPV6_INVALID_ADDR_INDEX)
+ {
+ m_address_table[index].state = p_addr->state;
+ memcpy(&m_address_table[index].addr, p_addr, IPV6_ADDR_SIZE);
+ m_interfaces[interface_id].addr_range[index] = addr_index;
+
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for calculating how many bits of addresses are equal.
+ *
+ * @param[in] p_addr1 Base address.
+ * @param[in] p_addr2 Base address.
+ *
+ * @return Number of same bits.
+ */
+static uint32_t addr_bit_equal(const ipv6_addr_t * p_addr1,
+ const ipv6_addr_t * p_addr2)
+{
+ uint32_t index;
+ uint32_t match = 0;
+ uint8_t temp;
+ uint32_t index_tab;
+
+ for (index = 0; index < IPV6_ADDR_SIZE; index++)
+ {
+ if (p_addr1->u8[index] == p_addr2->u8[index])
+ {
+ // Add full 8bits to match
+ match += 8;
+ }
+ else
+ {
+ // Operation of XOR to detect differences
+ temp = p_addr1->u8[index] ^ p_addr2->u8[index];
+
+ // Check all single bits
+ for (index_tab = 0; index_tab < 8; index_tab++)
+ {
+ if ((temp & 0x80) == 0)
+ {
+ // If the oldest bits matched, add one more.
+ match++;
+
+ // Check next bit.
+ temp = temp << 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return match;
+}
+
+/**@brief Function for searching specific network interface by given address.
+ *
+ * @param[in] p_interface Pointer to IPv6 network interface.
+ * @param[in] p_dest_addr IPv6 address to be matched.
+ *
+ * @return NRF_SUCCESS if operation successful, NRF_ERROR_NOT_FOUND otherwise.
+ */
+static uint32_t interface_find(iot_interface_t ** pp_interface, const ipv6_addr_t * p_dest_addr)
+{
+ // Currently only host role is implemented, though no need to match addresses.
+ UNUSED_VARIABLE(p_dest_addr);
+
+ uint32_t index;
+ uint32_t err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NOT_FOUND);
+
+ if (m_interfaces_count == 1)
+ {
+ for (index = 0; index < IPV6_MAX_INTERFACE; index++)
+ {
+ if (m_interfaces[index].p_interface != NULL)
+ {
+ *pp_interface = m_interfaces[index].p_interface;
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+ }
+ else if (m_interfaces_count == 0)
+ {
+ err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NOT_FOUND);
+ }
+ else
+ {
+ // Not supported now.
+ err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NOT_SUPPORTED);
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for resetting specific network interface.
+ *
+ * @param[in] p_interface Pointer to IPv6 network interface.
+ *
+ * @return None.
+ */
+static void interface_reset(ipv6_interface_t * p_interface)
+{
+ uint32_t index;
+ uint8_t addr_index;
+
+ p_interface->p_interface = NULL;
+
+ for (index = 0; index < IPV6_MAX_ADDRESS_PER_INTERFACE; index++)
+ {
+ addr_index = p_interface->addr_range[index];
+
+ if (addr_index != IPV6_INVALID_ADDR_INDEX)
+ {
+ p_interface->addr_range[index] = IPV6_INVALID_ADDR_INDEX;
+ addr_free(index, true);
+ }
+ }
+}
+
+
+/**@brief Function for getting specific network interface by 6LoWPAN interface.
+ *
+ * @param[in] p_6lo_interface Pointer to 6LoWPAN interface.
+ *
+ * @return Pointer to internal network interface on success, otherwise NULL.
+ */
+static uint32_t interface_get_by_6lo(iot_interface_t * p_6lo_interface)
+{
+ return (uint32_t)(p_6lo_interface->p_upper_stack);
+}
+
+
+/**@brief Function for adding new 6lowpan interface to interface table.
+ *
+ * @param[in] p_6lo_interface Pointer to 6LoWPAN interface.
+ * @param[out] p_index Pointer to index of internal network interface.
+ *
+ * @return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
+ */
+static uint32_t interface_add(iot_interface_t * p_interface,
+ uint32_t * p_index )
+{
+ uint32_t index;
+ uint32_t err_code;
+ ipv6_addr_conf_t linklocal_addr;
+
+ for (index = 0; index < IPV6_MAX_INTERFACE; index++)
+ {
+ if (m_interfaces[index].p_interface == NULL)
+ {
+ m_interfaces[index].p_interface = p_interface;
+ p_interface->p_upper_stack = (void *) index;
+ (*p_index) = index;
+
+ // Add link local address.
+ IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&linklocal_addr.addr, p_interface->local_addr.identifier);
+ linklocal_addr.state = IPV6_ADDR_STATE_PREFERRED;
+
+ err_code = addr_set(p_interface, &linklocal_addr);
+ if (err_code != NRF_SUCCESS)
+ {
+ IPV6_ERR("Cannot add link-local address to interface!");
+ }
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NO_MEM;
+}
+
+
+/**@brief Function for removing 6lowpan interface from interface table.
+ *
+ * @param[in] p_interface Pointer to internal network interface.
+ *
+ * @return None.
+ */
+static void interface_delete(uint32_t index)
+{
+ interface_reset(&m_interfaces[index]);
+}
+
+/**@brief Function for notifying application of the new interface established.
+ *
+ * @param[in] p_interface Pointer to internal network interface.
+ *
+ * @return None.
+ */
+static void app_notify_interface_add(iot_interface_t * p_interface)
+{
+ ipv6_event_t event;
+
+ event.event_id = IPV6_EVT_INTERFACE_ADD;
+
+ IPV6_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ IPV6_MUTEX_LOCK();
+}
+
+
+/**@brief Function for notifying application of the interface disconnection.
+ *
+ * @param[in] p_interface Pointer to internal network interface.
+ *
+ * @return None.
+ */
+static void app_notify_interface_delete(iot_interface_t * p_interface)
+{
+ ipv6_event_t event;
+
+ event.event_id = IPV6_EVT_INTERFACE_DELETE;
+
+ IPV6_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ IPV6_MUTEX_LOCK();
+}
+
+
+#if (IPV6_ENABLE_USNUPORTED_PROTOCOLS_TO_APPLICATION == 1)
+/**@brief Function for notifying application of the received packet (e.g. with unsupported protocol).
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_pbuffer Pointer to packet buffer.
+ *
+ * @return None.
+ */
+static void app_notify_rx_data(iot_interface_t * p_interface, iot_pbuffer_t * p_pbuffer)
+{
+ ipv6_event_t event;
+
+ event.event_id = IPV6_EVT_INTERFACE_RX_DATA;
+
+ // RX Event parameter.
+ event.event_param.rx_event_param.p_rx_packet = p_pbuffer;
+ event.event_param.rx_event_param.p_ip_header = (ipv6_header_t *)p_pbuffer->p_memory;
+
+ IPV6_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ IPV6_MUTEX_LOCK();
+}
+#endif
+
+
+/**@brief Function for multiplexing transport protocol to different modules.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_pbuffer Pointer to packet buffer.
+ *
+ * @return NRF_SUCCESS if success, otherwise an error code.
+ */
+static uint32_t ipv6_input(iot_interface_t * p_interface, iot_pbuffer_t * p_pbuffer)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ ipv6_header_t * p_iphdr = (ipv6_header_t *)(p_pbuffer->p_payload - IPV6_IP_HEADER_SIZE);
+
+ // Change byte order of IP header given to application.
+ p_iphdr->length = NTOHS(p_iphdr->length);
+ p_iphdr->flowlabel = NTOHS(p_iphdr->flowlabel);
+
+ switch (p_iphdr->next_header)
+ {
+ case IPV6_NEXT_HEADER_ICMP6:
+ IPV6_TRC("Got ICMPv6 packet.");
+
+ IPV6_MUTEX_UNLOCK();
+ err_code = icmp6_input(p_interface, p_iphdr, p_pbuffer);
+ IPV6_MUTEX_LOCK();
+
+ break;
+
+ case IPV6_NEXT_HEADER_UDP:
+ IPV6_TRC("Got UDP packet.");
+
+ IPV6_MUTEX_UNLOCK();
+ err_code = udp_input(p_interface, p_iphdr, p_pbuffer);
+ IPV6_MUTEX_LOCK();
+
+ break;
+
+ default:
+ IPV6_ERR("Got unsupported protocol packet. Protocol ID = 0x%x!",
+ p_iphdr->next_header);
+
+#if (IPV6_ENABLE_USNUPORTED_PROTOCOLS_TO_APPLICATION == 1)
+ app_notify_rx_data(p_interface, p_pbuffer);
+#endif
+ break;
+ }
+
+ // Free packet buffer unless marked explicitly as pending
+ if (err_code != IOT_IPV6_ERR_PENDING)
+ {
+ UNUSED_VARIABLE(iot_pbuffer_free(p_pbuffer, true));
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for receiving 6LoWPAN module events.
+ *
+ * @param[in] p_6lo_interface Pointer to 6LoWPAN interface.
+ * @param[in] p_6lo_event Pointer to 6LoWPAN related event.
+ *
+ * @return None.
+ */
+static void ble_6lowpan_evt_handler(iot_interface_t * p_interface,
+ ble_6lowpan_event_t * p_6lo_event)
+{
+ bool rx_failure = false;
+ uint32_t err_code;
+ uint32_t interface_id;
+ iot_pbuffer_t * p_pbuffer;
+ iot_pbuffer_alloc_param_t pbuff_param;
+
+ IPV6_MUTEX_LOCK();
+
+ IPV6_ENTRY();
+ IPV6_TRC("In 6LoWPAN Handler:");
+
+ interface_id = interface_get_by_6lo(p_interface);
+
+ switch (p_6lo_event->event_id)
+ {
+ case BLE_6LO_EVT_ERROR:
+ {
+ IPV6_ERR("Got error, with result %08lx", p_6lo_event->event_result);
+ break;
+ }
+ case BLE_6LO_EVT_INTERFACE_ADD:
+ {
+ IPV6_TRC("New interface established!");
+
+ // Add interface to internal table.
+ err_code = interface_add(p_interface, &interface_id);
+
+ if (NRF_SUCCESS == err_code)
+ {
+ IPV6_TRC("Added new network interface to internal table.");
+
+ err_code = iot_context_manager_table_alloc(p_interface);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ IPV6_TRC("Successfully allocated context table!");
+ }
+ else
+ {
+ IPV6_ERR("Failed to allocate context table!");
+ }
+
+ // Increase number of up interfaces.
+ m_interfaces_count++;
+
+ // Notify application.
+ app_notify_interface_add(p_interface);
+ }
+ else
+ {
+ IPV6_ERR("Cannot add new interface. Table is full.");
+ }
+
+ break;
+ }
+ case BLE_6LO_EVT_INTERFACE_DELETE:
+ {
+ IPV6_TRC("Interface disconnected!");
+
+ if (interface_id < IPV6_MAX_INTERFACE)
+ {
+ IPV6_TRC("Removed network interface.");
+
+ // Notify application.
+ app_notify_interface_delete(p_interface);
+
+ err_code = iot_context_manager_table_free(p_interface);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ IPV6_TRC("Successfully freed context table!");
+ }
+
+ // Decrease number of up interfaces.
+ m_interfaces_count--;
+
+ // Remove interface from internal table.
+ interface_delete(interface_id);
+ }
+ break;
+ }
+ case BLE_6LO_EVT_INTERFACE_DATA_RX:
+ {
+ IPV6_TRC("Got data with size = %d!",
+ p_6lo_event->event_param.rx_event_param.packet_len);
+ IPV6_TRC("Data: ");
+ IPV6_DUMP(p_6lo_event->event_param.rx_event_param.p_packet,
+ p_6lo_event->event_param.rx_event_param.packet_len);
+
+ if (interface_id < IPV6_MAX_INTERFACE)
+ {
+ if (p_6lo_event->event_result == NRF_ERROR_NOT_FOUND)
+ {
+ IPV6_ERR("Cannot restore IPv6 addresses!");
+ IPV6_ERR("Source CID = 0x%x, Destination CID = 0x%x",
+ p_6lo_event->event_param.rx_event_param.rx_contexts.src_cntxt_id,
+ p_6lo_event->event_param.rx_event_param.rx_contexts.dest_cntxt_id);
+
+ // Indicates failure.
+ rx_failure = true;
+ break;
+ }
+
+ // Check if packet is for us.
+ ipv6_addr_t * p_addr =
+ (ipv6_addr_t *)&p_6lo_event->event_param.rx_event_param.p_packet[DEST_ADDR_OFFSET];
+
+ err_code = addr_check(interface_id, p_addr, true);
+
+ // If no address found - drop message.
+ if (err_code != NRF_SUCCESS)
+ {
+ IPV6_ERR("Packet received on unknown address!");
+ rx_failure = true;
+ break;
+ }
+
+ // Try to allocate pbuffer, with no memory.
+ pbuff_param.flags = PBUFFER_FLAG_NO_MEM_ALLOCATION;
+ pbuff_param.type = RAW_PACKET_TYPE;
+ pbuff_param.length = p_6lo_event->event_param.rx_event_param.packet_len;
+
+ // Try to allocate pbuffer for receiving data.
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_pbuffer->p_memory = p_6lo_event->event_param.rx_event_param.p_packet;
+ p_pbuffer->p_payload = p_pbuffer->p_memory + IPV6_IP_HEADER_SIZE;
+ p_pbuffer->length -= IPV6_IP_HEADER_SIZE;
+
+ // Execute multiplexer.
+ err_code = ipv6_input(p_interface, p_pbuffer);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ IPV6_ERR("Failed while processing packet, error = 0x%08lX!", err_code);
+ }
+ }
+ else
+ {
+ IPV6_ERR("Failed to allocate packet buffer!");
+ rx_failure = true;
+ }
+ }
+ else
+ {
+ IPV6_ERR("[6LOWPAN]: Got data to unknown interface!");
+ rx_failure = true;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (rx_failure == true)
+ {
+ UNUSED_VARIABLE(nrf_free(p_6lo_event->event_param.rx_event_param.p_packet));
+ }
+
+ IPV6_EXIT();
+
+ IPV6_MUTEX_UNLOCK();
+}
+
+
+uint32_t ipv6_init(const ipv6_init_t * p_init)
+{
+ uint32_t index;
+ uint32_t err_code;
+ ble_6lowpan_init_t init_params;
+
+ NULL_PARAM_CHECK(p_init);
+ NULL_PARAM_CHECK(p_init->p_eui64);
+ NULL_PARAM_CHECK(p_init->event_handler);
+
+ SDK_MUTEX_INIT(m_ipv6_mutex);
+ IPV6_MUTEX_LOCK();
+
+ IPV6_ENTRY();
+
+ // Initialize related modules.
+ UNUSED_VARIABLE(nrf_mem_init());
+ UNUSED_VARIABLE(iot_pbuffer_init());
+
+ // Initialize submodules of IPv6 stack.
+ UNUSED_VARIABLE(udp_init());
+ UNUSED_VARIABLE(icmp6_init());
+
+ // Initialize context manager.
+ UNUSED_VARIABLE(iot_context_manager_init());
+
+ IPV6_ADDRESS_INITIALIZE(IPV6_ADDR_ANY);
+
+ // Set application event handler.
+ m_event_handler = p_init->event_handler;
+
+ // Clear number of interfaces.
+ m_interfaces_count = 0;
+
+ // Clear network interfaces.
+ for (index = 0; index < IPV6_MAX_INTERFACE; index++)
+ {
+ interface_reset(&m_interfaces[index]);
+ }
+
+ // Clear all addresses.
+ for (index = 0; index < IPV6_MAX_ADDRESS_COUNT; index++)
+ {
+ addr_free(index, false);
+ }
+
+ // 6LoWPAN module initialization.
+ init_params.p_eui64 = p_init->p_eui64;
+ init_params.event_handler = ble_6lowpan_evt_handler;
+
+ err_code = ble_6lowpan_init(&init_params);
+
+ IPV6_EXIT();
+
+ IPV6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t ipv6_address_set(const iot_interface_t * p_interface,
+ const ipv6_addr_conf_t * p_addr)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_addr);
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t err_code;
+
+ IPV6_MUTEX_LOCK();
+
+ IPV6_ENTRY();
+
+ err_code = addr_set(p_interface, p_addr);
+
+ IPV6_EXIT();
+
+ IPV6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t ipv6_address_check(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_addr)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_addr);
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t err_code;
+
+ IPV6_MUTEX_LOCK();
+
+ IPV6_ENTRY();
+
+ uint32_t interface_id = (uint32_t)p_interface->p_upper_stack;
+
+ err_code = addr_check(interface_id, p_addr, false);
+
+ IPV6_EXIT();
+
+ IPV6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t ipv6_address_find_best_match(iot_interface_t ** pp_interface,
+ ipv6_addr_t * p_addr_r,
+ const ipv6_addr_t * p_addr_f)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_addr_f);
+ NULL_PARAM_CHECK(pp_interface);
+
+ uint32_t index;
+ uint32_t err_code;
+ uint32_t addr_index;
+ uint32_t match_temp = 0;
+ uint32_t match_best = 0;
+ ipv6_addr_t * p_best_addr = NULL;
+
+ IPV6_MUTEX_LOCK();
+
+ err_code = interface_find(pp_interface, p_addr_f);
+
+ if (err_code == NRF_SUCCESS && p_addr_r)
+ {
+ uint32_t interface_id = (uint32_t)(*pp_interface)->p_upper_stack;
+
+ for (index = 0; index < IPV6_MAX_ADDRESS_PER_INTERFACE; index++)
+ {
+ addr_index = m_interfaces[interface_id].addr_range[index];
+
+ if (addr_index != IPV6_INVALID_ADDR_INDEX)
+ {
+ if (m_address_table[addr_index].state == IPV6_ADDR_STATE_PREFERRED)
+ {
+ match_temp = addr_bit_equal(p_addr_f, &m_address_table[addr_index].addr);
+
+ if (match_temp >= match_best)
+ {
+ match_best = match_temp;
+ p_best_addr = &m_address_table[addr_index].addr;
+ }
+ }
+ }
+ }
+
+ // No address found.
+ if (p_best_addr == NULL)
+ {
+ // Set undefined :: address.
+ IPV6_ADDRESS_INITIALIZE(p_addr_r);
+ }
+ else
+ {
+ memcpy(p_addr_r->u8, p_best_addr->u8, IPV6_ADDR_SIZE);
+ }
+ }
+
+ IPV6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t ipv6_address_remove(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_addr)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_addr);
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t index;
+ uint32_t err_code;
+ uint32_t addr_index;
+
+ IPV6_MUTEX_LOCK();
+
+ IPV6_ENTRY();
+
+ uint32_t interface_id = (uint32_t)p_interface->p_upper_stack;
+
+ err_code = (IOT_IPV6_ERR_BASE | NRF_ERROR_NOT_FOUND);
+
+ for (index = 0; index < IPV6_MAX_ADDRESS_PER_INTERFACE; index++)
+ {
+ addr_index = m_interfaces[interface_id].addr_range[index];
+
+ if (addr_index != IPV6_INVALID_ADDR_INDEX)
+ {
+ if (0 == IPV6_ADDRESS_CMP(&m_address_table[addr_index].addr, p_addr))
+ {
+ m_interfaces[interface_id].addr_range[index] = IPV6_INVALID_ADDR_INDEX;
+
+ // Remove address if no reference to interface found.
+ addr_free(index, true);
+
+ err_code = NRF_SUCCESS;
+
+ break;
+ }
+ }
+ }
+
+ IPV6_EXIT();
+
+ IPV6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t ipv6_send(const iot_interface_t * p_interface, iot_pbuffer_t * p_packet)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_packet);
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t err_code;
+
+ IPV6_MUTEX_LOCK();
+
+ IPV6_ENTRY();
+
+ err_code = ble_6lowpan_interface_send(p_interface,
+ p_packet->p_payload,
+ p_packet->length);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ IPV6_ERR("Cannot send packet!");
+ }
+
+ // Free pbuffer, without freeing memory.
+ UNUSED_VARIABLE(iot_pbuffer_free(p_packet, false));
+
+ IPV6_EXIT();
+
+ IPV6_MUTEX_UNLOCK();
+
+ return err_code;
+}