aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c456
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h197
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c141
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h117
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c835
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h216
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h91
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c928
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h80
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.c1978
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.h168
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c854
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h125
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h663
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c203
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h126
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h115
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c804
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h158
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c688
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h248
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h222
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c182
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h161
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c182
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h153
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c274
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h110
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h165
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_dtls.c996
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c264
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c255
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c292
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_common.h95
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_defines.h321
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_errors.h290
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.c561
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.h155
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.c55
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.h76
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.c195
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.h175
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file_port.h147
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.c220
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.h86
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.c183
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.h175
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.c167
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.h75
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/dns6/dns6.c903
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.c1355
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.h101
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/dns6_api.h173
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/icmp6_api.h253
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/ipv6_api.h207
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/udp_api.h255
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/ipv6/ipv6.c1088
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.c467
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.h175
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.c607
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.h202
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.c2455
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.h245
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp.h98
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/udp/udp6.c708
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.c101
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.h93
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.c553
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.h628
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.c143
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.h94
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c885
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.h109
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_api.h426
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.c203
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.h69
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_coap_util.c166
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.c347
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.h443
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.c498
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.h124
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.c542
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.h69
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.c399
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.h207
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c516
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.h194
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.c1077
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.h207
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium.h238
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.c689
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.h100
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_platform_dummy.h54
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.c821
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.h506
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_decoder.c262
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_encoder.c457
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_internal.h446
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.c313
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.h74
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.c88
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.h233
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_lwip.c349
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_socket.c319
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_tls.c185
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/README.md28
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/arpa/inet.h45
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/netinet/in.h45
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/socket_api.h593
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/select.h45
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/socket.h45
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/unistd.h82
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/sleep.c53
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket.c746
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_common.h115
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_config.h81
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_trace.h102
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/transport_if.h161
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.c227
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.h120
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/addr_util/inet_pton.c60
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.c176
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.h170
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.c122
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.h146
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.c185
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.h123
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/platform/ble/socket_ble.c50
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/ipv6/transport_handler.c387
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c630
130 files changed, 42479 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c
new file mode 100644
index 0000000..8b08068
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c
@@ -0,0 +1,456 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_block background_dfu_block.c
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU block handling implementation.
+ *
+ */
+
+#include "background_dfu_block.h"
+
+#include <assert.h>
+
+#include "sdk_config.h"
+#include "app_scheduler.h"
+#include "background_dfu_operation.h"
+#include "compiler_abstraction.h"
+#include "nrf_dfu_handling_error.h"
+
+#define NRF_LOG_MODULE_NAME background_dfu
+
+#define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+#define BITMAP_BYTE_FROM_INDEX(index) ((index) / 8)
+#define BITMAP_BIT_FROM_INDEX(index) (7 - ((index) % 8))
+
+static void block_buffer_store(background_dfu_block_manager_t * p_bm);
+
+/**@brief Convert block number to bitmap index.
+ *
+ * @param[in] block_num Block number.
+ *
+ * @return Corresponding index.
+ */
+static __INLINE uint16_t block_num_to_index(uint32_t block_num)
+{
+ return block_num % BLOCKS_PER_BUFFER;
+}
+
+/**@brief Set a bit in a bitmap.
+ *
+ * @param[inout] p_bitmap A pointer to the bitmap.
+ * @param[in] index Bit index to set.
+ */
+static __INLINE void set_bitmap_bit(uint8_t * p_bitmap, uint16_t index)
+{
+ p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] |= (0x01 << BITMAP_BIT_FROM_INDEX(index));
+}
+
+/**@brief Clear a bit in a bitmap.
+ *
+ * @param[inout] p_bitmap A pointer to the bitmap.
+ * @param[in] index Bit index to clear.
+ */
+static __INLINE void clear_bitmap_bit(uint8_t * p_bitmap, uint16_t index)
+{
+ p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] &= ~((uint8_t)(0x01 << BITMAP_BIT_FROM_INDEX(index)));
+}
+
+/**@brief Check if a bit in a bitmap is set.
+ *
+ * @param[inout] p_bitmap A pointer to the bitmap.
+ * @param[in] index Bit index to check.
+ *
+ * @return True if bit is set, false otherwise.
+ */
+static __INLINE bool is_block_present(const uint8_t * p_bitmap, uint16_t index)
+{
+ return (p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] >> BITMAP_BIT_FROM_INDEX(index)) & 0x01;
+}
+
+/**
+ * @brief A callback function for DFU operation.
+ */
+static void dfu_operation_callback(nrf_dfu_response_t * p_res, void * p_context)
+{
+ background_dfu_block_manager_t * p_bm = (background_dfu_block_manager_t *)p_context;
+ ret_code_t res_code;
+
+ if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
+ {
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+ else
+ {
+ switch (p_res->request)
+ {
+ case NRF_DFU_OP_OBJECT_CREATE:
+ {
+ // Object created, write respective block.
+ uint32_t current_size = p_bm->currently_stored_block * DEFAULT_BLOCK_SIZE;
+ uint16_t data_offset = block_num_to_index(p_bm->currently_stored_block) * DEFAULT_BLOCK_SIZE;
+ uint16_t store_size = MIN(DEFAULT_BLOCK_SIZE, (p_bm->image_size - current_size));
+ res_code = background_dfu_op_write(p_bm->data + data_offset,
+ store_size,
+ dfu_operation_callback,
+ p_bm);
+
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
+ p_bm->currently_stored_block,
+ p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+
+ break;
+ }
+
+ case NRF_DFU_OP_OBJECT_WRITE:
+ if (!((p_bm->currently_stored_block + 1) % BLOCKS_PER_DFU_OBJECT) ||
+ ((p_bm->currently_stored_block + 1) == BLOCKS_PER_SIZE(p_bm->image_size)))
+ {
+ res_code = background_dfu_op_crc(dfu_operation_callback, p_bm);
+
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
+ p_bm->currently_stored_block,
+ p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+ }
+ else
+ {
+ p_bm->last_block_stored = p_bm->currently_stored_block;
+ clear_bitmap_bit(p_bm->bitmap, block_num_to_index(p_bm->currently_stored_block));
+ p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
+
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_SUCCESS, p_bm->p_context);
+
+ block_buffer_store(p_bm);
+ }
+
+ break;
+
+ case NRF_DFU_OP_CRC_GET:
+ res_code = background_dfu_op_execute(dfu_operation_callback, p_bm);
+
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
+ p_bm->currently_stored_block,
+ p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+
+ break;
+
+ case NRF_DFU_OP_OBJECT_EXECUTE:
+ p_bm->last_block_stored = p_bm->currently_stored_block;
+ clear_bitmap_bit(p_bm->bitmap, block_num_to_index(p_bm->currently_stored_block));
+ p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
+
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_SUCCESS, p_bm->p_context);
+
+ block_buffer_store(p_bm);
+
+ break;
+
+ default:
+ ASSERT(false);
+ }
+ }
+}
+
+/**@brief Store a block from the buffer in a flash.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] p_block A block number to store.
+ *
+ * @return NRF_SUCCESS on success, an error code is returned otherwise.
+ */
+static ret_code_t block_store(background_dfu_block_manager_t * p_bm, uint32_t block_num)
+{
+ p_bm->currently_stored_block = block_num;
+
+ ret_code_t res_code = NRF_SUCCESS;
+ uint32_t current_size = block_num * DEFAULT_BLOCK_SIZE;
+
+ do
+ {
+ // Initialize DFU object if needed.
+ if (!(block_num % BLOCKS_PER_DFU_OBJECT))
+ {
+ uint32_t object_size = MIN(DEFAULT_DFU_OBJECT_SIZE, (p_bm->image_size - current_size));
+
+ res_code = background_dfu_op_create(p_bm->image_type,
+ object_size,
+ dfu_operation_callback,
+ p_bm);
+ break;
+ }
+
+ // Store block.
+ uint16_t data_offset = block_num_to_index(block_num) * DEFAULT_BLOCK_SIZE;
+ uint16_t store_size = MIN(DEFAULT_BLOCK_SIZE, (p_bm->image_size - current_size));
+ res_code = background_dfu_op_write(p_bm->data + data_offset,
+ store_size,
+ dfu_operation_callback,
+ p_bm);
+
+ } while (0);
+ return res_code;
+}
+
+/**@brief Check if block manager is busy storing a block.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ *
+ */
+static bool is_block_manager_busy(background_dfu_block_manager_t * p_bm)
+{
+ return p_bm->currently_stored_block >= 0;
+}
+
+/**@brief Store any valid blocks from the buffer in a flash.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ *
+ */
+static void block_buffer_store(background_dfu_block_manager_t * p_bm)
+{
+ ret_code_t res_code = NRF_SUCCESS;
+
+ if (!is_block_manager_busy(p_bm))
+ {
+ if (p_bm->last_block_stored < p_bm->current_block)
+ {
+ int32_t block = p_bm->last_block_stored + 1;
+
+ if (is_block_present(p_bm->bitmap, block_num_to_index(block)))
+ {
+ NRF_LOG_INFO("Storing block (b:%d c:%d).", block, p_bm->current_block);
+
+ // There is a block to store.
+ res_code = block_store(p_bm, block);
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).", block, p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+ }
+ else
+ {
+ NRF_LOG_WARNING("Gap encountered - quit (b:%d c:%d).", block, p_bm->current_block);
+ }
+ }
+ }
+}
+
+/**
+ * @brief A callback function for scheduling DFU block operations.
+ */
+static void block_store_scheduled(void * p_evt, uint16_t event_length)
+{
+ UNUSED_PARAMETER(event_length);
+
+ background_dfu_block_manager_t * p_bm = *((background_dfu_block_manager_t **)p_evt);
+ block_buffer_store(p_bm);
+}
+
+/**@brief Copy block data to the buffer.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] p_block A pointer to the block.
+ */
+static void block_buffer_add(background_dfu_block_manager_t * p_bm,
+ const background_dfu_block_t * p_block)
+{
+ uint16_t index = block_num_to_index(p_block->number);
+
+ memcpy(p_bm->data + index * DEFAULT_BLOCK_SIZE, p_block->p_payload, DEFAULT_BLOCK_SIZE);
+ set_bitmap_bit(p_bm->bitmap, index);
+
+ if (p_bm->current_block < (int32_t)p_block->number)
+ {
+ p_bm->current_block = (int32_t)p_block->number;
+ }
+
+ // Schedule block store.
+ UNUSED_RETURN_VALUE(app_sched_event_put(&p_bm, sizeof(p_bm), block_store_scheduled));
+}
+
+/***************************************************************************************************
+ * @section Public
+ **************************************************************************************************/
+
+void block_manager_init(background_dfu_block_manager_t * p_bm,
+ uint32_t object_type,
+ uint32_t object_size,
+ int32_t initial_block,
+ block_manager_result_notify_t result_handler,
+ void * p_context)
+{
+ p_bm->image_type = object_type;
+ p_bm->image_size = object_size;
+ p_bm->last_block_stored = p_bm->current_block = initial_block - 1;
+ p_bm->result_handler = result_handler;
+ p_bm->p_context = p_context;
+ p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
+
+ memset(p_bm->bitmap, 0, sizeof(p_bm->bitmap));
+}
+
+background_dfu_block_result_t block_manager_block_process(background_dfu_block_manager_t * p_bm,
+ const background_dfu_block_t * p_block)
+{
+ /*
+ * Possible scenarios:
+ * 1) We receive a block older than our last stored block - simply ignore it.
+ * 2) We receive a block that fits within current buffer range - process it.
+ * 3) We receive a block that exceeds current buffer range - abort DFU as we won't be able to catch-up.
+ */
+
+ if (p_block->size != DEFAULT_BLOCK_SIZE)
+ {
+ NRF_LOG_WARNING("Block with incorrect size received (s:%d n:%d).",
+ p_block->size, p_block->number);
+ return BACKGROUND_DFU_BLOCK_IGNORE;
+ }
+
+ if ((int32_t)p_block->number <= p_bm->last_block_stored)
+ {
+ NRF_LOG_WARNING("Ignoring block that already was stored(o:%d n:%d).",
+ p_bm->last_block_stored, p_block->number);
+ return BACKGROUND_DFU_BLOCK_IGNORE;
+ }
+
+ if ((int32_t)p_block->number > p_bm->last_block_stored + BLOCKS_PER_BUFFER)
+ {
+ NRF_LOG_WARNING("Too many blocks missed - abort DFU (o:%d n:%d).",
+ p_bm->last_block_stored, p_block->number);
+ return BACKGROUND_DFU_BLOCK_INVALID;
+ }
+
+ // Block fits within current buffer - copy it into the buffer and update the current block if most
+ // recent block was received.
+ block_buffer_add(p_bm, p_block);
+
+ return BACKGROUND_DFU_BLOCK_SUCCESS;
+}
+
+bool block_manager_is_image_complete(const background_dfu_block_manager_t * p_bm)
+{
+ uint32_t image_blocks = BLOCKS_PER_SIZE(p_bm->image_size);
+
+ NRF_LOG_DEBUG("Is image complete (o:%d n:%d).", p_bm->last_block_stored, image_blocks);
+
+ if (p_bm->last_block_stored + 1 == image_blocks)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool block_manager_request_bitmap_get(const background_dfu_block_manager_t * p_bm,
+ background_dfu_request_bitmap_t * p_req_bmp)
+{
+ if (p_bm->current_block > p_bm->last_block_stored)
+ {
+ memset(p_req_bmp, 0, sizeof(*p_req_bmp));
+ p_req_bmp->offset = p_bm->last_block_stored + 1;
+ p_req_bmp->size = (p_bm->current_block - p_bm->last_block_stored + 7) / 8;
+
+ for (uint16_t block = p_req_bmp->offset; block <= p_bm->current_block; block++)
+ {
+ if (!is_block_present(p_bm->bitmap, block_num_to_index(block)))
+ {
+ set_bitmap_bit(p_req_bmp->bitmap, block - p_req_bmp->offset);
+ }
+ }
+
+ // Clip empty bytes at the end.
+ while ((p_req_bmp->size > 0) && (p_req_bmp->bitmap[p_req_bmp->size - 1] == 0))
+ {
+ p_req_bmp->size--;
+ }
+
+ if (p_req_bmp->size == 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool block_manager_increment_current_block(background_dfu_block_manager_t * p_bm)
+{
+ uint32_t image_blocks = BLOCKS_PER_SIZE(p_bm->image_size);
+
+ if (p_bm->current_block + 1 == image_blocks)
+ {
+ // Already on last block.
+ return false;
+ }
+ else
+ {
+ p_bm->current_block++;
+ }
+
+ return true;
+}
+
+int32_t block_manager_get_current_block(const background_dfu_block_manager_t * p_bm)
+{
+ return p_bm->current_block;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h
new file mode 100644
index 0000000..e1e468b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h
@@ -0,0 +1,197 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_block background_dfu_block.H
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU block handling.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_BLOCK_H_
+#define BACKGROUND_DFU_BLOCK_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "app_util_platform.h"
+#include "sdk_config.h"
+
+/** @brief Macro for calculating the number of blocks that fits in particular size. */
+#define BLOCKS_PER_SIZE(SIZE) ((SIZE + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE)
+
+/** @brief Default block size for background DFU blocks. */
+#define DEFAULT_BLOCK_SIZE BACKGROUND_DFU_DEFAULT_BLOCK_SIZE
+
+/** @brief Number of blocks in superblock. */
+#define BLOCKS_PER_BUFFER BACKGROUND_DFU_BLOCKS_PER_BUFFER
+
+/** @brief Size of the block buffer. Shall be a multiply of @ref DEFAULT_BLOCK_SIZE. */
+#define BLOCK_BUFFER_SIZE (BLOCKS_PER_BUFFER * DEFAULT_BLOCK_SIZE)
+
+/** @brief Size of the bitmap reflecting the state of the blocks in a superblock. */
+#define BITMAP_SIZE ((BLOCKS_PER_BUFFER + 7) / 8)
+
+/** @brief Default size of DFU object. Shall be a multiply of @ref DEFAULT_BLOCK_SIZE. */
+#define DEFAULT_DFU_OBJECT_SIZE 4096
+
+/** @brief Number of blocks in DFU object. */
+#define BLOCKS_PER_DFU_OBJECT (BLOCKS_PER_SIZE(DEFAULT_DFU_OBJECT_SIZE))
+
+/** @brief Value of invalid block number (for example to indicate that no block is being stored). */
+#define INVALID_BLOCK_NUMBER (-1)
+
+/** @brief Result of a DFU block operation. */
+typedef enum
+{
+ BACKGROUND_DFU_BLOCK_SUCCESS, /**< Block operation completed successfully. */
+ BACKGROUND_DFU_BLOCK_IGNORE, /**< Block was ignored in current DFU context (i.e. duplicated block). */
+ BACKGROUND_DFU_BLOCK_INVALID, /**< Block is invalid in current context, indicates that DFU shall be aborted. */
+ BACKGROUND_DFU_BLOCK_STORE_ERROR /**< Block was not stored due to internal store error. */
+} background_dfu_block_result_t;
+
+/**@brief A function that module can register to receive block manager error notifications. */
+typedef void (* block_manager_result_notify_t)(background_dfu_block_result_t result,
+ void * p_context);
+
+/**@brief Block information structure. */
+typedef struct
+{
+ uint16_t size; /**< Size of the block in bytes. */
+ uint32_t number; /**< Block number. */
+ uint8_t * p_payload; /**< Block payload. */
+} background_dfu_block_t;
+
+/**@brief Block manager structure.
+ *
+ * Block manager keeps track of received blocks, ensuring that they are written into flash in
+ * a correct order, and updates the missing blocks bitmap, so that they could be requested from
+ * the server.
+ */
+typedef struct
+{
+ uint32_t image_size; /**< Size of currently stored image. */
+ uint32_t image_type; /**< Image type (init command or firmware). */
+ int32_t last_block_stored; /**< Number of the last block written in the flash. */
+ int32_t current_block; /**< Last received (or expected) block. */
+ uint8_t data[BLOCK_BUFFER_SIZE]; /**< Block buffer. */
+ uint8_t bitmap[BITMAP_SIZE]; /**< A bitmap indicating which blocks have been received. */
+ block_manager_result_notify_t result_handler; /**< A callback function for error notification. */
+ void * p_context; /**< A context for result notification.*/
+ int32_t currently_stored_block; /**< Number of block that is currently being stored. */
+} background_dfu_block_manager_t;
+
+/**@brief Bitmap structure used in bitmap requests. */
+typedef struct
+{
+ uint16_t size; /**< Size of the bitmap, in bytes.*/
+ uint16_t offset; /**< Bitmap offset, indicating which block is referenced by first bit in bitmap. */
+ uint8_t bitmap[BITMAP_SIZE]; /**< Bitmap itself. One in specific bit indicates which block is missing. */
+} background_dfu_request_bitmap_t;
+
+/**@brief Initialize block manager.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] object_type Type of the image to store.
+ * @param[in] object_size Size of the image to store.
+ * @param[in] initial_block Number of the first block to receive. Typically it would be 0, but
+ * in case DFU restarted in the middle, it may differ.
+ * @param[in] error_handler A callback for error notification.
+ * @param[in] p_context A context for error notification.
+ */
+void block_manager_init(background_dfu_block_manager_t * p_bm,
+ uint32_t object_type,
+ uint32_t object_size,
+ int32_t initial_block,
+ block_manager_result_notify_t result_handler,
+ void * p_context);
+
+/**@brief Process a single block.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] p_block A pointer to the block structure containing information about the block.
+ *
+ * @retval BACKGROUND_DFU_BLOCK_SUCCESS Block stored successfully.
+ * @retval BACKGROUND_DFU_BLOCK_IGNORE Invalid block size or block already stored in flash.
+ * @retval BACKGROUND_DFU_BLOCK_INVALID Block number indicates that too many blocks were missed.
+ * @retval BACKGROUND_DFU_BLOCK_STORE_ERROR Block store in flash failed.
+ */
+background_dfu_block_result_t block_manager_block_process(background_dfu_block_manager_t * p_bm,
+ const background_dfu_block_t * p_block);
+
+/**@brief Check if an image managed by a block manager is complete.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ *
+ * @return True if image is complete, false otherwise.
+ */
+bool block_manager_is_image_complete(const background_dfu_block_manager_t * p_bm);
+
+/**@brief Get current block bitmap.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ * @param[out] p_req_bmp A pointer to the block bitmap structure.
+ *
+ * @return True if non-empty bitmap was generated, false otherwise.
+ */
+bool block_manager_request_bitmap_get(const background_dfu_block_manager_t * p_bm,
+ background_dfu_request_bitmap_t * p_req_bmp);
+
+/**@brief Increment current block, in case no blocks were received and block timeout shot.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ *
+ * @return True if block was incremented, false if block manager is already on a last block of the image.
+ */
+bool block_manager_increment_current_block(background_dfu_block_manager_t * p_bm);
+
+/**@brief Get current block number that block manager received/expects.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ *
+ * @return Current block number.
+ */
+int32_t block_manager_get_current_block(const background_dfu_block_manager_t * p_bm);
+
+#endif /* BACKGROUND_DFU_BLOCK_H_ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c
new file mode 100644
index 0000000..7aa6679
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_operation background_dfu_operation.c
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU operations implementation.
+ *
+ */
+
+#include "background_dfu_operation.h"
+
+#include "sdk_config.h"
+#include "nrf_dfu_req_handler.h"
+
+#define NRF_LOG_MODULE_NAME background_dfu
+
+#define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+ret_code_t background_dfu_op_select(uint32_t object_type,
+ nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_SELECT;
+ dfu_req.select.object_type = object_type;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_create(uint32_t object_type,
+ uint32_t object_size,
+ nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_CREATE;
+ dfu_req.create.object_size = object_size;
+ dfu_req.create.object_type = object_type;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_write(const uint8_t * p_payload,
+ uint16_t payload_length,
+ nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_WRITE;
+ dfu_req.write.p_data = (uint8_t *)p_payload;
+ dfu_req.write.len = payload_length;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_crc(nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_CRC_GET;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_execute(nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_EXECUTE;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h
new file mode 100644
index 0000000..b01d9b2
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_operation background_dfu_operation.h
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU operations.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_OPERATION_H_
+#define BACKGROUND_DFU_OPERATION_H_
+
+#include <stdint.h>
+
+#include "nrf_dfu_handling_error.h"
+
+/** @brief Select DFU object.
+ *
+ * @param[in] object_type Object type which should be selected.
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_select(uint32_t object_type,
+ nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Create DFU object.
+ *
+ * @param[in] object_type Object type which should be selected.
+ * @param[in] object_size Size of an object to create.
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_create(uint32_t object_type,
+ uint32_t object_size,
+ nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Write DFU object.
+ *
+ * @param[in] p_payload A pointer to data which should be written to the object.
+ * @param[in] payload_length Length, in bytes, of data which should be written to the object.
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_write(const uint8_t * p_payload,
+ uint16_t payload_length,
+ nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Calculate DFU object CRC.
+ *
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_crc(nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Execute selected DFU.
+ *
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_execute(nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+#endif /* BACKGROUND_DFU_OPERATION_H_ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c
new file mode 100644
index 0000000..5004558
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c
@@ -0,0 +1,835 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_state background_dfu_state.c
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU state management.
+ *
+ */
+
+#include "background_dfu_state.h"
+
+#include <string.h>
+
+#include "sdk_config.h"
+#include "app_timer.h"
+#include "compiler_abstraction.h"
+#include "nrf_dfu_types.h"
+#include "nrf_dfu_settings.h"
+#include "sha256.h"
+#include "background_dfu_transport.h"
+#include "background_dfu_operation.h"
+
+#define NRF_LOG_MODULE_NAME background_dfu
+
+#define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define BLOCK_REQUEST_JITTER_MIN 200 /**< Minimum jitter value when sending bitmap with requested blocks in multicast DFU. */
+#define BLOCK_REQUEST_JITTER_MAX 2000 /**< Maximum jitter value when sending bitmap with requested blocks in multicast DFU. */
+#define BLOCK_RECEIVE_TIMEOUT 2000 /**< Timeout value after which block is considered missing in multicast DFU. */
+
+#define DFU_DATE_TIME (__DATE__ " " __TIME__)
+
+/**@brief DFU trigger packet version. */
+#define TRIGGER_VERSION 1
+
+/**
+ * @defgroup background_dfu_trigger_flags Trigger flags and offsets.
+ * @{
+ */
+#define TRIGGER_FLAGS_VERSION_OFFSET 4
+#define TRIGGER_FLAGS_VERSION_MASK 0xF0
+#define TRIGGER_FLAGS_MODE_OFFSET 3
+#define TRIGGER_FLAGS_MODE_MASK 0x08
+#define TRIGGER_FLAGS_RESET_OFFSET 2
+#define TRIGGER_FLAGS_RESET_MASK 0x04
+/** @} */
+
+APP_TIMER_DEF(m_missing_block_timer);
+APP_TIMER_DEF(m_block_timeout_timer);
+
+/**@brief Defines how many retries are performed in case no response is received. */
+#define DEFAULT_RETRIES 3
+
+/**@brief DFU error handler.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void dfu_handle_error(background_dfu_context_t * p_dfu_ctx)
+{
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_ERROR;
+
+ background_dfu_handle_error();
+}
+
+/**@brief Get randomized jitter value.
+ *
+ * @return Randomized jitter value between BLOCK_REQUEST_JITTER_MIN and BLOCK_REQUEST_JITTER_MAX.
+ */
+static __INLINE uint32_t block_request_jitter_get(void)
+{
+ return BLOCK_REQUEST_JITTER_MIN + (background_dfu_random() %
+ (BLOCK_REQUEST_JITTER_MAX - BLOCK_REQUEST_JITTER_MIN));
+}
+
+/**@brief Starts block timeout timer.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void start_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
+{
+ uint32_t err_code = app_timer_start(m_block_timeout_timer,
+ APP_TIMER_TICKS(BLOCK_RECEIVE_TIMEOUT),
+ p_dfu_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
+ }
+}
+
+/**@brief Stops block timeout timer.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void stop_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
+{
+ UNUSED_PARAMETER(p_dfu_ctx);
+ uint32_t err_code = app_timer_stop(m_block_timeout_timer);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_stop (%d)", err_code);
+ }
+}
+
+/**@brief Restarts block timeout timer.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void restart_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
+{
+ stop_block_timeout_timer(p_dfu_ctx);
+ start_block_timeout_timer(p_dfu_ctx);
+}
+
+/***************************************************************************************************
+ * @section Handle DFU Trigger
+ **************************************************************************************************/
+
+/**@brief Parses trigger data and updates DFU client context accordingly.
+ *
+ * @param[inout] p_dfu_ctx A pointer to DFU Client context.
+ * @param[in] p_trigger A pointer to trigger data.
+ *
+ * @return True if parsing was successful, false otherwise.
+ */
+static bool parse_trigger(background_dfu_context_t * p_dfu_ctx,
+ const background_dfu_trigger_t * p_trigger)
+{
+ uint8_t trigger_version = (p_trigger->flags & TRIGGER_FLAGS_VERSION_MASK)
+ >> TRIGGER_FLAGS_VERSION_OFFSET;
+
+ if (trigger_version <= TRIGGER_VERSION)
+ {
+ // Base fields available from version 0.
+ p_dfu_ctx->init_cmd_size = uint32_big_decode((const uint8_t *)&p_trigger->init_length);
+ p_dfu_ctx->init_cmd_crc = uint32_big_decode((const uint8_t *)&p_trigger->init_crc);
+ p_dfu_ctx->firmware_size = uint32_big_decode((const uint8_t *)&p_trigger->image_length);
+ p_dfu_ctx->firmware_crc = uint32_big_decode((const uint8_t *)&p_trigger->image_crc);
+
+ // Mode flag was added in DFU Trigger version 1.
+ if (trigger_version >= 1)
+ {
+ p_dfu_ctx->dfu_mode = (background_dfu_mode_t)((p_trigger->flags
+ & TRIGGER_FLAGS_MODE_MASK) >> TRIGGER_FLAGS_MODE_OFFSET);
+ p_dfu_ctx->reset_suppress = (p_trigger->flags & TRIGGER_FLAGS_RESET_MASK) >>
+ TRIGGER_FLAGS_RESET_OFFSET;
+
+ }
+ else
+ {
+ p_dfu_ctx->dfu_mode = BACKGROUND_DFU_MODE_UNICAST;
+ }
+
+ NRF_LOG_INFO("DFU trigger: init (sz=%d, crc=%0X) image (sz=%d, crc=%0X)",
+ p_dfu_ctx->init_cmd_size,
+ p_dfu_ctx->init_cmd_crc,
+ p_dfu_ctx->firmware_size,
+ p_dfu_ctx->firmware_crc);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool background_dfu_validate_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len)
+{
+ if (payload_len != sizeof(background_dfu_trigger_t))
+ {
+ NRF_LOG_ERROR("Validate trigger: size mismatch");
+ return false;
+ }
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_IDLE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_TRIG))
+ {
+ NRF_LOG_ERROR("Validate trigger: DFU already in progress (s:%s).",
+ (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state));
+ return false;
+ }
+
+ uint8_t trigger_version = (((background_dfu_trigger_t *)p_payload)->flags
+ & TRIGGER_FLAGS_VERSION_MASK) >> TRIGGER_FLAGS_VERSION_OFFSET;
+ if (trigger_version > TRIGGER_VERSION)
+ {
+ NRF_LOG_ERROR("Validate trigger: invalid trigger version.");
+ return false;
+ }
+
+ return true;
+}
+
+bool background_dfu_process_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len)
+{
+ bool result = false;
+
+ do
+ {
+ if (!parse_trigger(p_dfu_ctx, (background_dfu_trigger_t *)p_payload))
+ {
+ NRF_LOG_ERROR("Process trigger: failed to parse payload");
+ break;
+ }
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
+
+ uint32_t err_code = background_dfu_handle_event(p_dfu_ctx,
+ BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+
+ result = true;
+ } while(0);
+
+ return result;
+}
+
+/***************************************************************************************************
+ * @section DFU checks
+ **************************************************************************************************/
+
+background_dfu_block_result_t background_dfu_process_block(background_dfu_context_t * p_dfu_ctx,
+ const background_dfu_block_t * p_block)
+{
+ background_dfu_block_result_t result = block_manager_block_process(&p_dfu_ctx->block_manager,
+ p_block);
+ uint32_t err_code = NRF_SUCCESS;
+
+ switch (result)
+ {
+ case BACKGROUND_DFU_BLOCK_IGNORE:
+ // Ignore.
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ restart_block_timeout_timer(p_dfu_ctx);
+ }
+
+ break;
+
+ case BACKGROUND_DFU_BLOCK_SUCCESS:
+ // Intentionally empty.
+ break;
+
+ default:
+ err_code = background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_PROCESSING_ERROR);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+
+ break;
+ }
+
+ return result;
+}
+
+/**@brief Check if installed image is different from the incoming one.
+ *
+ * @param[in] p_dfu_ctx A pointer to DFU client context.
+ *
+ * @return True if image different, false otherwise.
+ *
+ */
+static bool is_image_different(const background_dfu_context_t * p_dfu_ctx)
+{
+ if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_INVALID)
+ {
+ NRF_LOG_WARNING("No image in bank 0");
+ return true;
+ }
+
+ if (s_dfu_settings.bank_0.image_crc != p_dfu_ctx->firmware_crc)
+ {
+ NRF_LOG_WARNING("Installed image CRC is different");
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * @brief A callback function for block manager.
+ */
+static void dfu_block_manager_result_handler(background_dfu_block_result_t result, void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = p_context;
+ uint32_t err_code;
+
+ if (result == BACKGROUND_DFU_BLOCK_SUCCESS)
+ {
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ restart_block_timeout_timer(p_dfu_ctx);
+ }
+
+ if (block_manager_is_image_complete(&p_dfu_ctx->block_manager))
+ {
+ err_code = background_dfu_handle_event(p_dfu_ctx,
+ BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+ }
+ else
+ {
+ // FIXME I don't like it here.
+ p_dfu_ctx->block_num++;
+
+ err_code = background_dfu_handle_event(p_dfu_ctx,
+ BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+ }
+ }
+ else
+ {
+ err_code = background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_PROCESSING_ERROR);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+ }
+}
+
+/**
+ * @brief Prepare state machine to download init command.
+ */
+static void setup_download_init_command(background_dfu_context_t * p_dfu_ctx)
+{
+ p_dfu_ctx->p_resource_size = &p_dfu_ctx->init_cmd_size;
+ p_dfu_ctx->retry_count = DEFAULT_RETRIES;
+ p_dfu_ctx->block_num = 0;
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+
+ block_manager_init(&p_dfu_ctx->block_manager,
+ p_dfu_ctx->dfu_state,
+ *p_dfu_ctx->p_resource_size,
+ p_dfu_ctx->block_num,
+ dfu_block_manager_result_handler,
+ p_dfu_ctx);
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ NRF_LOG_INFO("Init complete. Multicast Mode.");
+ uint32_t jitter = block_request_jitter_get();
+ uint32_t err_code = app_timer_start(m_missing_block_timer,
+ APP_TIMER_TICKS(jitter),
+ p_dfu_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
+ }
+ }
+ else
+ {
+ NRF_LOG_INFO("Init complete. Unicast Mode.");
+ }
+}
+
+/**
+ * @brief A callback function for DFU command operations.
+ */
+static void dfu_init_check_callback(nrf_dfu_response_t * p_res, void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+
+ switch (p_res->request)
+ {
+ case NRF_DFU_OP_OBJECT_SELECT:
+ if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
+ {
+ NRF_LOG_ERROR("No valid init command - select failed");
+ setup_download_init_command((background_dfu_context_t *)p_context);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+ }
+
+ p_dfu_ctx->max_obj_size = p_res->select.max_size;
+ p_dfu_ctx->block_num = p_res->select.offset / DEFAULT_BLOCK_SIZE;
+
+ if (background_dfu_op_execute(dfu_init_check_callback, p_context) != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("No valid init command - execute error");
+ setup_download_init_command((background_dfu_context_t *)p_context);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+ }
+
+ break;
+
+ case NRF_DFU_OP_OBJECT_EXECUTE:
+ if ((p_res->result != NRF_DFU_RES_CODE_SUCCESS) ||
+ (s_dfu_settings.progress.command_crc != p_dfu_ctx->init_cmd_crc))
+ {
+ NRF_LOG_ERROR("Init commad has changed");
+ p_dfu_ctx->remaining_size = 0;
+ setup_download_init_command((background_dfu_context_t *)p_context);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+ }
+ else
+ {
+ // Valid init command stored, download firmware.
+ p_dfu_ctx->dfu_diag.state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE));
+ }
+
+ break;
+
+ default:
+ ASSERT(false);
+ }
+}
+
+/**
+ * @brief A callback function for DFU data operation.
+ */
+static void dfu_data_select_callback(nrf_dfu_response_t * p_res, void * p_context)
+{
+ ASSERT(p_res->request == NRF_DFU_OP_OBJECT_SELECT);
+
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+ if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
+ {
+ NRF_LOG_ERROR("Select failed");
+ dfu_handle_error(p_dfu_ctx);
+ return;
+ }
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
+ p_dfu_ctx->p_resource_size = &p_dfu_ctx->firmware_size;
+ p_dfu_ctx->retry_count = DEFAULT_RETRIES;
+ p_dfu_ctx->block_num = (p_res->select.offset / DEFAULT_BLOCK_SIZE);
+ p_dfu_ctx->max_obj_size = p_res->select.max_size;
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+
+ block_manager_init(&p_dfu_ctx->block_manager,
+ p_dfu_ctx->dfu_state,
+ *p_dfu_ctx->p_resource_size,
+ p_dfu_ctx->block_num,
+ dfu_block_manager_result_handler,
+ p_dfu_ctx);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+}
+
+/***************************************************************************************************
+ * @section Timer handlers
+ **************************************************************************************************/
+
+/**@brief Handler function for block request timer.
+ *
+ * @param[inout] p_context DFU context.
+ */
+static void block_request_handler(void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_FIRMWARE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_INIT_CMD))
+ {
+ return;
+ }
+
+ background_dfu_request_bitmap_t req_bmp;
+ if (block_manager_request_bitmap_get(&p_dfu_ctx->block_manager, &req_bmp) &&
+ (req_bmp.size > 0))
+ {
+ background_dfu_transport_block_request_send(p_dfu_ctx, &req_bmp);
+ }
+
+ // Reschedule the timer.
+ uint32_t jitter = block_request_jitter_get();
+ uint32_t err_code = app_timer_start(m_missing_block_timer, APP_TIMER_TICKS(jitter), p_dfu_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
+ }
+}
+
+/**@brief Handler function for block timeout timer.
+ *
+ * @param[inout] p_context DFU context.
+ */
+static void block_timeout_handler(void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+
+ NRF_LOG_INFO("Block timeout! (b: %d)",
+ block_manager_get_current_block(&p_dfu_ctx->block_manager));
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_FIRMWARE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_INIT_CMD))
+ {
+ return;
+ }
+
+ if (block_manager_increment_current_block(&p_dfu_ctx->block_manager))
+ {
+ start_block_timeout_timer(p_dfu_ctx);
+ }
+}
+
+/***************************************************************************************************
+ * @section API functions
+ **************************************************************************************************/
+
+/** @brief Helper function converting DFU state to string.
+ *
+ * @param[in] state DFU client state.
+ *
+ * @return A pointer to null terminated string with state name.
+ */
+const char * background_dfu_state_to_string(const background_dfu_state_t state)
+{
+ static const char * const names[] =
+ {
+ "DFU_DOWNLOAD_INIT_CMD",
+ "DFU_DOWNLOAD_FIRMWARE",
+ "DFU_DOWNLOAD_TRIG",
+ "DFU_WAIT_FOR_RESET",
+ "DFU_IDLE",
+ "DFU_ERROR",
+ };
+
+ return names[(uint32_t)state - BACKGROUND_DFU_DOWNLOAD_INIT_CMD];
+}
+
+/** @brief Helper function convering DFU event name to string.
+ *
+ * @param[in] state DFU client event.
+ *
+ * @return A pointer to null terminated string with event name.
+ */
+const char * background_dfu_event_to_string(const background_dfu_event_t event)
+{
+ static const char * const names[] = {
+ "DFU_EVENT_TRANSFER_COMPLETE",
+ "DFU_EVENT_TRANSFER_CONTINUE",
+ "DFU_EVENT_TRANSFER_ERROR",
+ "DFU_EVENT_PROCESSING_ERROR",
+ };
+
+ return names[event];
+}
+
+uint32_t background_dfu_handle_event(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_event_t event)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ NRF_LOG_INFO("state=%s event=%s",
+ (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state),
+ (uint32_t)background_dfu_event_to_string(event));
+
+ switch (p_dfu_ctx->dfu_state)
+ {
+ case BACKGROUND_DFU_IDLE:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_IDLE;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
+ p_dfu_ctx->block_num = 0;
+ p_dfu_ctx->retry_count = DEFAULT_RETRIES;
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+ }
+
+ break;
+ }
+
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ if (!is_image_different(p_dfu_ctx))
+ {
+ NRF_LOG_INFO("Image is already installed");
+ background_dfu_reset_state(p_dfu_ctx);
+ break;
+ }
+
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ // Initiate init command check procedure.
+ if (background_dfu_op_select(NRF_DFU_OBJ_TYPE_COMMAND,
+ dfu_init_check_callback,
+ p_dfu_ctx) != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("No valid init command - select error");
+ setup_download_init_command(p_dfu_ctx);
+ }
+ else
+ {
+ // We wait for dfu request to finish - do not send anything.
+ return NRF_SUCCESS;
+ }
+ }
+
+ break;
+ }
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ if (background_dfu_op_select(NRF_DFU_OBJ_TYPE_DATA,
+ dfu_data_select_callback,
+ p_dfu_ctx) != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Select failed");
+ dfu_handle_error(p_dfu_ctx);
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else
+ {
+ return NRF_SUCCESS;
+ }
+ }
+ else if (event == BACKGROUND_DFU_EVENT_PROCESSING_ERROR)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ NRF_LOG_ERROR("Processing error while downloading init command.");
+ dfu_handle_error(p_dfu_ctx);
+ }
+ break;
+ }
+
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_WAIT_FOR_RESET;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+ }
+ else if (event == BACKGROUND_DFU_EVENT_PROCESSING_ERROR)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ NRF_LOG_ERROR("Processing error while downloading firmware.");
+ dfu_handle_error(p_dfu_ctx);
+ }
+ break;
+ }
+
+ case BACKGROUND_DFU_WAIT_FOR_RESET:
+ NRF_LOG_WARNING("An event received in wait for reset state. This should not happen.");
+ break;
+
+ default:
+ NRF_LOG_ERROR("Unhandled state");
+ break;
+ }
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_IDLE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_ERROR) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_WAIT_FOR_RESET))
+ {
+ if (((p_dfu_ctx->dfu_state == BACKGROUND_DFU_DOWNLOAD_FIRMWARE) ||
+ (p_dfu_ctx->dfu_state == BACKGROUND_DFU_DOWNLOAD_INIT_CMD)) &&
+ (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST))
+ {
+ // In multicast DFU firmware download, client doesn't initiate block requests.
+ }
+ else
+ {
+ if ((event == BACKGROUND_DFU_EVENT_TRANSFER_ERROR) && (p_dfu_ctx->retry_count > 0))
+ {
+ p_dfu_ctx->retry_count -= 1;
+ }
+
+ if (p_dfu_ctx->retry_count > 0)
+ {
+ background_dfu_transport_send_request(p_dfu_ctx);
+ }
+ else
+ {
+ NRF_LOG_ERROR("No more retries");
+ dfu_handle_error(p_dfu_ctx);
+ }
+ }
+ }
+
+ return err_code;
+}
+
+void background_dfu_reset_state(background_dfu_context_t * p_dfu_ctx)
+{
+ sha256_context_t sha256_ctx;
+
+ uint8_t hash[32];
+ uint32_t err_code = NRF_SUCCESS;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_IDLE;
+ p_dfu_ctx->dfu_mode = BACKGROUND_DFU_MODE_UNICAST;
+ p_dfu_ctx->init_cmd_size = 0;
+ p_dfu_ctx->firmware_size = 0;
+ p_dfu_ctx->remaining_size = 0;
+
+ memset(&p_dfu_ctx->dfu_diag, 0, sizeof(p_dfu_ctx->dfu_diag));
+
+ err_code = sha256_init(&sha256_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in sha256_init (%d)", err_code);
+ }
+
+ err_code = sha256_update(&sha256_ctx, (const uint8_t *)DFU_DATE_TIME, strlen(DFU_DATE_TIME));
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in sha256_update (%d)", err_code);
+ }
+
+ err_code = sha256_final(&sha256_ctx, (uint8_t *)hash, false);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in sha256_final (%d)", err_code);
+ }
+
+ p_dfu_ctx->dfu_diag.build_id = uint32_big_decode(hash);
+ p_dfu_ctx->dfu_diag.state = BACKGROUND_DFU_IDLE;
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_IDLE;
+
+ NRF_LOG_INFO("Current DFU Diag version: %s, 0x%08x",
+ (uint32_t)DFU_DATE_TIME, p_dfu_ctx->dfu_diag.build_id);
+}
+
+void background_dfu_state_init(background_dfu_context_t * p_dfu_ctx)
+{
+ uint32_t err_code;
+
+ err_code = app_timer_create(&m_missing_block_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ block_request_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_create (%d)", err_code);
+ }
+
+ err_code = app_timer_create(&m_block_timeout_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ block_timeout_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_create (%d)", err_code);
+ }
+
+ background_dfu_reset_state(p_dfu_ctx);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h
new file mode 100644
index 0000000..8dd4395
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h
@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_state background_dfu_state.h
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU state management.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_STATE_H_
+#define BACKGROUND_DFU_STATE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "background_dfu_block.h"
+#include "nrf_dfu_req_handler.h"
+
+/** @brief DFU client state ID.
+ *
+ * We reuse DFU object type IDs as DFU process states IDs,
+ * so that current state can be used as the object type in
+ * function which expect one.
+ */
+typedef enum
+{
+ BACKGROUND_DFU_DOWNLOAD_INIT_CMD = NRF_DFU_OBJ_TYPE_COMMAND,
+ BACKGROUND_DFU_DOWNLOAD_FIRMWARE = NRF_DFU_OBJ_TYPE_DATA,
+ BACKGROUND_DFU_DOWNLOAD_TRIG,
+ BACKGROUND_DFU_WAIT_FOR_RESET,
+ BACKGROUND_DFU_IDLE,
+ BACKGROUND_DFU_ERROR,
+} background_dfu_state_t;
+
+/** @brief DFU event definitions. */
+typedef enum
+{
+ BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE,
+ BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE,
+ BACKGROUND_DFU_EVENT_TRANSFER_ERROR,
+ BACKGROUND_DFU_EVENT_PROCESSING_ERROR,
+} background_dfu_event_t;
+
+/** @brief DFU mode definitions. */
+typedef enum
+{
+ BACKGROUND_DFU_MODE_UNICAST,
+ BACKGROUND_DFU_MODE_MULTICAST
+} background_dfu_mode_t;
+
+/** @brief Trigger packet structure. */
+typedef PACKED_STRUCT
+{
+ uint8_t flags; /**< Trigger message flags. Bits 7:4 (oldest) - trigger version, bit 3 - DFU mode, bits 2:0 - reserved. */
+ uint32_t init_length;
+ uint32_t init_crc;
+ uint32_t image_length;
+ uint32_t image_crc;
+} background_dfu_trigger_t;
+
+/**@brief Structure with DFU diagnostic information. */
+typedef PACKED_STRUCT background_dfu_diagnostic
+{
+ uint32_t build_id; /**< Build identifier, based on compilation time. */
+ uint8_t state; /**< Current DFU state. */
+ uint8_t prev_state; /**< Previous DFU state. */
+ uint16_t init_blocks_requested; /**< Number of requested missing init blocks. */
+ uint16_t image_blocks_requested; /**< Number of requested missing image blocks. */
+ uint16_t triggers_received; /**< Number of triggers received. */
+ uint16_t total_init_blocks_received; /**< Total number of init blocks received, including retransmitted ones. */
+ uint16_t total_image_blocks_received; /**< Total number of image blocks received, including retransmitted ones. */
+} background_dfu_diagnostic_t;
+
+/** @brief DFU client state. */
+typedef struct dfu_context
+{
+ background_dfu_state_t dfu_state; /**< Current DFU client state. */
+ background_dfu_mode_t dfu_mode; /**< Current DFU mode. */
+ bool reset_suppress; /**< If set then device won't automatically reset after
+ downloading firmware. */
+ background_dfu_diagnostic_t dfu_diag; /**< DFU diagnostic information. */
+
+ uint32_t init_cmd_size; /**< Current init command size. */
+ uint32_t init_cmd_crc; /**< Current init command checksum. */
+ uint32_t firmware_size; /**< Current firmware command size. */
+ uint32_t firmware_crc; /**< Current firmware command checksum. */
+ uint32_t max_obj_size; /**< Maximum size of the DFU object. */
+ uint32_t remaining_size; /**< Remaining size, in bytes, of the resource which
+ is being downloaded. */
+ /* TODO Move the block num to the block manager. */
+ uint32_t block_num; /**< Currently requested block number. */
+ uint32_t * p_resource_size; /**< Downloaded resource size. */
+ background_dfu_block_manager_t block_manager; /**< An entity managing block reception and storage. */
+ uint8_t retry_count; /**< Number of remaining retires. */
+} background_dfu_context_t;
+
+/**@brief Check if payload contains valid trigger.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ * @param[in] p_payload A pointer to the message payload.
+ * @param[in[ payload_len Payload length.
+ *
+ * @return True if trigger was valid, false otherwise.
+ */
+bool background_dfu_validate_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len);
+
+/**@brief Process a payload with a DFU trigger.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ * @param[in] p_payload A pointer to the message payload.
+ * @param[in[ payload_len Payload length.
+ *
+ * @return True if trigger was successfully processed, false otherwise.
+ */
+bool background_dfu_process_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len);
+
+/**@brief Process the block and return CoAP result code corresponding to the result of operation.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ * @param[in] p_block A pointer to the block structure.
+ *
+ * @return True if init command is valid, false otherwise.
+ *
+ * @retval BACKGROUND_DFU_BLOCK_SUCCESS The block was processed correctly.
+ * @retval BACKGROUND_DFU_BLOCK_IGNORE The block was incorrect for this node, but did not
+ * indicate that the DFU shall be stopped.
+ * @retval BACKGROUND_DFU_BLOCK_INVALID The block indicated that the node would not catch-up with the DFU
+ * transfer or other error occured. Node aborted DFU.
+ * @retval BACKGROUND_DFU_BLOCK_STORE_ERROR DFU store error.
+ */
+background_dfu_block_result_t background_dfu_process_block(background_dfu_context_t * p_dfu_ctx,
+ const background_dfu_block_t * p_block);
+
+/**@brief DFU state machine handler.
+ *
+ * @param[in] p_dfu_ctx DFU context.
+ * @param[in] event DFU event.
+ *
+ * @return NRF_SUCCESS or error code
+ */
+uint32_t background_dfu_handle_event(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_event_t event);
+
+/**@brief Reset state machine state.
+ *
+ * @param[in] p_dfu_ctx A pointer to DFU client context.
+ */
+void background_dfu_reset_state(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Initialize state machine state.
+ *
+ * @param[in] p_dfu_ctx A pointer to DFU client context.
+ */
+void background_dfu_state_init(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Convert a DFU event enum value to a string description.
+ *
+ * @param[in] event A DFU event.
+ *
+ * @return String representing the event.
+ */
+const char * background_dfu_event_to_string(const background_dfu_event_t event);
+
+/**@brief Convert a DFU state enum value to a string description.
+ *
+ * @param[in] event A DFU state.
+ *
+ * @return String representing the state.
+ */
+const char * background_dfu_state_to_string(const background_dfu_state_t state);
+
+#endif /* BACKGROUND_DFU_STATE_H_ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h
new file mode 100644
index 0000000..061a921
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_transport background_dfu_state.h
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU transport API.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_TRANSPORT_H_
+#define BACKGROUND_DFU_TRANSPORT_H_
+
+#include "background_dfu_state.h"
+
+/**@brief Create and send DFU block request with missing blocks.
+ *
+ * This function is used in multicast DFU.
+ *
+ * @param[in] p_dfu_ctx A pointer to the background DFU context.
+ * @param[in] p_req_bmp A pointer to the bitmap structure that shall be sent.
+ */
+void background_dfu_transport_block_request_send(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_request_bitmap_t * p_req_bmp);
+
+/**@brief Send background DFU request, based on DFU state.
+ *
+ * @param[in] p_dfu_ctx A pointer to the background DFU context.
+ */
+void background_dfu_transport_send_request(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Update background DFU transport state.
+ *
+ * @param[in] p_dfu_ctx A pointer to the background DFU context.
+ */
+void background_dfu_transport_state_update(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Get random value.
+ *
+ * @returns A random value of uint32_t type.
+ */
+uint32_t background_dfu_random(void);
+
+/** @brief Handle DFU error.
+ *
+ * Notify transport about DFU error.
+ */
+void background_dfu_handle_error(void);
+
+#endif /* BACKGROUND_DFU_COAP_H_ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c
new file mode 100644
index 0000000..923d220
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c
@@ -0,0 +1,928 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file
+ *
+ * @brief TFTP DFU Example - Background DFU transport implementation.
+ *
+ */
+#include "tftp_dfu.h"
+
+#include "background_dfu_transport.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "app_timer.h"
+#include "background_dfu_block.h"
+#include "background_dfu_transport.h"
+#include "cJSON.h"
+#include "cJSON_iot_hooks.h"
+#include "crc16.h"
+#include "iot_file_static.h"
+#include "iot_tftp.h"
+#include "nrf.h"
+#include "nrf_assert.h"
+#include "nrf_delay.h"
+#include "nrf_dfu_req_handler.h"
+#include "nrf_dfu_settings.h"
+#include "nrf_dfu_utils.h"
+#include "nrf_log_ctrl.h"
+
+#define NRF_LOG_LEVEL 4
+#define NRF_LOG_MODULE_NAME TFTP_DFU
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MAX_LENGTH_FILENAME 32 /**< Maximum length of the filename. */
+#define MAX_CONFIG_SIZE 1024 /**< Maximum DFU of the config size. */
+
+#define CONFIG_APP_KEY "app"
+#define CONFIG_SD_KEY "sd"
+#define CONFIG_APPSD_KEY "appsd"
+#define CONFIG_BL_KEY "bl"
+#define CONFIG_PATH_KEY "p"
+#define CONFIG_INIT_PATH_KEY "i"
+#define CONFIG_SIZE_KEY "s"
+#define CONFIG_ID_KEY "id"
+#define CONFIG_INIT_SIZE_KEY "is"
+#define CONFIG_INIT_ID_KEY "iid"
+
+#define APP_TFTP_BLOCK_SIZE 512 /**< Maximum or negotiated size of data block. */
+#define APP_TFTP_RETRANSMISSION_TIME 3 /**< Number of milliseconds between retransmissions. */
+
+#define BOOTLOADER_REGION_START 0x0007D000 /**< This field should correspond to start address of the bootloader, found in UICR.RESERVED, 0x10001014, register.
+ This value is used for sanity check, so the bootloader will fail immediately if this value differs from runtime value.
+ The value is used to determine max application size for updating. */
+
+#define TFTP_SOFTDEVICE_UPGRADE_SUPPORT false /**< Upgrade of softdevice or bootloader is not supported with current version of Background DFU module. */
+
+/** The device info offset can be modified to place the device info settings at a different location.
+ * If the customer reserved UICR location is used for other application specific data, the offset
+ * must be updated to avoid collision with that data.:
+ */
+/** [DFU UICR DEV offset] */
+#define UICR_CUSTOMER_DEVICE_INFO_OFFSET 0x0 /**< Device info offset inside the customer UICR reserved area. Customers may change this value to place the device information in a user-preferred location. */
+/** [DFU UICR DEV offset] */
+#define UICR_CUSTOMER_RESERVED_OFFSET 0x80 /**< Customer reserved area in the UICR. The area from UICR + 0x80 is reserved for customer usage. */
+#define DFU_DEVICE_INFO_BASE (NRF_UICR_BASE + \
+ UICR_CUSTOMER_RESERVED_OFFSET + \
+ UICR_CUSTOMER_DEVICE_INFO_OFFSET) /**< The device information base address inside of UICR. */
+#define DFU_DEVICE_INFO ((dfu_device_info_t *)DFU_DEVICE_INFO_BASE) /**< The memory mapped structure for device information data. */
+
+
+/**@brief Structure holding basic device information settings.
+ */
+typedef struct
+{
+ uint16_t device_type; /**< Device type (2 bytes), for example Heart Rate. This number must be defined by the customer before production. It can be located in UICR or FICR. */
+ uint16_t device_rev; /**< Device revision (2 bytes), for example major revision 1, minor revision 0. This number must be defined by the customer before production. It can be located in UICR or FICR. */
+} dfu_device_info_t;
+
+/**@brief Description of single block of firmware. */
+typedef struct
+{
+ uint32_t size; /**< Size of firmware block. */
+ uint32_t crc; /**< CRC of firmware block. Set to 0 if no checksum checking is needed. */
+ uint32_t init_size; /**< Size of init file. */
+ uint32_t init_crc; /**< CRC of init file. */
+} iot_dfu_firmware_block_t;
+
+
+/**@brief Description of the new firmware that has been written into flash memory. */
+typedef struct
+{
+ iot_dfu_firmware_block_t application; /**< Description of Application block in firmware image. */
+ iot_dfu_firmware_block_t softdevice; /**< Description of SoftDevice block in firmware image. */
+ iot_dfu_firmware_block_t bootloader; /**< Description of Bootloader block in firmware image. */
+} iot_dfu_firmware_desc_t;
+
+/**@brief Type of image being updated by the DFU module. */
+typedef enum
+{
+ TFTP_DFU_IMAGE_TYPE_APPLICATION, /**< DFU updates application. */
+ TFTP_DFU_IMAGE_TYPE_SOFTDEVICE, /**< DFU updates softdevice and application. */
+ TFTP_DFU_IMAGE_TYPE_BOOTLOADER, /**< DFU updates bootloader. */
+} tftp_dfu_image_type_t;
+
+/**@brief Static data used by TFTP DFU module. */
+typedef struct
+{
+ iot_tftp_t tftp; /**< TFTP instance. */
+ char resource_path[MAX_LENGTH_FILENAME]; /**< Path of remote resource to get. */
+ uint32_t block_number; /**< Number of block that will be passed to background DFU module. */
+ uint8_t block[DEFAULT_BLOCK_SIZE]; /**< Buffer for parts of blocks to pass to background DFU module. */
+ uint16_t block_size; /**< Size of data in block buffer. */
+ tftp_dfu_image_type_t image_type; /**< Type of image that is currently updated. */
+ iot_file_t config_file; /**< Pointer to the file used for config of DFU. */
+ uint8_t config_mem[MAX_CONFIG_SIZE]; /**< Static memory for configuration file. */
+ cJSON * p_config_json; /**< Pointer of cJSON instance. */
+ iot_dfu_firmware_desc_t firmware_desc; /**< Details from configuration file. */
+} tftp_dfu_context_t;
+
+static background_dfu_context_t m_dfu_ctx; /**< Background DFU context. */
+static tftp_dfu_context_t m_tftp_dfu_ctx; /**< TFTP DFU context. */
+
+/***************************************************************************************************
+ * @section Common operations
+ **************************************************************************************************/
+
+/**@brief Set resource path to trigger (config) file. */
+static void trigger_path_set(void)
+{
+ int retval = snprintf(m_tftp_dfu_ctx.resource_path,
+ sizeof(m_tftp_dfu_ctx.resource_path),
+ "/dfu/c/%d/%d",
+ DFU_DEVICE_INFO->device_type,
+ DFU_DEVICE_INFO->device_rev);
+ if (retval < 0) {
+ NRF_LOG_ERROR("Failed to set path using snprintf, retval: %d", retval);
+ }
+}
+
+/**@brief Function for reading binary path from JSON configuration.
+ *
+ * @param[out] p_dst_str Pointer to memory, where path should be stored.
+ * @param[in] p_key Key inside JSON configuration file, describing firmware.
+ *
+ * @return NRF_SUCCESS if path found and stored in p_dst_str, otherwise error code.
+ */
+static uint32_t get_path(char * p_dst_str, const char * p_key)
+{
+ cJSON * p_cursor;
+
+ if ((m_tftp_dfu_ctx.p_config_json == NULL) || (p_dst_str == NULL))
+ {
+ NRF_LOG_ERROR("Invalid parameters");
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_cursor = cJSON_GetObjectItem(m_tftp_dfu_ctx.p_config_json, CONFIG_PATH_KEY);
+ if (p_cursor != NULL)
+ {
+ p_cursor = cJSON_GetObjectItem(p_cursor, (const char *)p_key);
+ if ((p_cursor != NULL) && (p_cursor->type == cJSON_String))
+ {
+ memcpy(p_dst_str, p_cursor->valuestring, strlen(p_cursor->valuestring));
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for reading init binary path from JSON configuration.
+ *
+ * @param[out] p_dst_str Pointer to memory, where path should be stored.
+ * @param[in] p_key Key inside JSON configuration file, describing firmware.
+ *
+ * @return NRF_SUCCESS if path found and stored in p_dst_str, otherwise error code.
+ */
+static uint32_t get_init_path(char * p_dst_str, const char * p_key)
+{
+ cJSON * p_cursor;
+
+ if ((m_tftp_dfu_ctx.p_config_json == NULL) || (p_dst_str == NULL))
+ {
+ NRF_LOG_ERROR("Invalid parameters");
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_cursor = cJSON_GetObjectItem(m_tftp_dfu_ctx.p_config_json, CONFIG_INIT_PATH_KEY);
+ if (p_cursor != NULL)
+ {
+ p_cursor = cJSON_GetObjectItem(p_cursor, (const char *)p_key);
+ if ((p_cursor != NULL) && (p_cursor->type == cJSON_String))
+ {
+ memcpy(p_dst_str, p_cursor->valuestring, strlen(p_cursor->valuestring));
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for parsing JSON file to get details of an application.
+ *
+ * @param[in] p_key Key inside JSON configuration file, describing firmware.
+ * @param[out] p_block Pointer to structure containing description of single block of firmware.
+ *
+ * @returns NRF_SUCCESS if correctly parsed data. Otherwise an error code indicating failure reason.
+ */
+static uint32_t details_parse(const char * p_key, iot_dfu_firmware_block_t * p_block)
+{
+ cJSON * p_cursor;
+ cJSON * p_cursor_back;
+
+ // Clear output parameters.
+ memset(p_block, 0, sizeof(*p_block));
+
+ if (m_tftp_dfu_ctx.p_config_json == NULL)
+ {
+ NRF_LOG_ERROR("Invalid JSON file");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = cJSON_GetObjectItem(m_tftp_dfu_ctx.p_config_json, (const char *)p_key);
+ if (p_cursor != NULL)
+ {
+ p_cursor_back = p_cursor;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_ID_KEY);
+ if (p_cursor != NULL)
+ {
+ if (p_cursor->type != cJSON_Number)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->crc = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No binary ID inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = p_cursor_back;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_INIT_SIZE_KEY);
+ if (p_cursor != NULL)
+ {
+ if (p_cursor->type != cJSON_Number)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->init_size = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No init SIZE inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = p_cursor_back;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_INIT_ID_KEY);
+ if (p_cursor != NULL)
+ {
+ if (p_cursor->type != cJSON_Number)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->init_crc = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No init ID inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = p_cursor_back;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_SIZE_KEY);
+ if (p_cursor != NULL)
+ {
+ if ((p_cursor->type != cJSON_Number) || (p_cursor->valueint == 0))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->size = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No binary SIZE inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+ }
+ else
+ {
+ NRF_LOG_ERROR("No binary KEY inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for parsing and processing config file.
+ *
+ * @param[out] p_dfu_firmware_desc Details of available firmware images (size and CRC)
+ * @param[out] p_filename Remote path to init file that should be downloaded in DFU process
+ *
+ * @return NRF_SUCCESS If config file is valid. Otherwise an error code indicating failure reason.
+ */
+static uint32_t app_dfu_config_process(iot_dfu_firmware_desc_t * p_dfu_firmware_desc,
+ char * p_filename)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ iot_dfu_firmware_block_t app;
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ iot_dfu_firmware_block_t sd;
+ iot_dfu_firmware_block_t bl;
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ bool app_present = false;
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ bool sd_present = false;
+ bool bl_present = false;
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+
+ // Clear global parameters before parsing a new one.
+ memset(p_filename, 0, MAX_LENGTH_FILENAME);
+
+ m_tftp_dfu_ctx.p_config_json = cJSON_Parse((const char *)m_tftp_dfu_ctx.config_mem);
+ if (m_tftp_dfu_ctx.p_config_json == NULL)
+ {
+ NRF_LOG_ERROR("JSON parse failed.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ if (details_parse(CONFIG_SD_KEY, &sd) == NRF_SUCCESS)
+ {
+ sd_present = true;
+ }
+
+ if (details_parse(CONFIG_BL_KEY, &bl) == NRF_SUCCESS)
+ {
+ bl_present = true;
+ }
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+
+ if (details_parse(CONFIG_APP_KEY, &app) == NRF_SUCCESS)
+ {
+ app_present = true;
+ }
+
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ // Background DFU does not support SoftDevice or bootloader update yet.
+ if ((sd_present) && (app_present))
+ {
+ NRF_LOG_INFO("Update Softdevice with Application.");
+ m_tftp_dfu_ctx.image_type = TFTP_DFU_IMAGE_TYPE_SOFTDEVICE;
+ }
+ else if (bl_present)
+ {
+ NRF_LOG_INFO("Update Bootloader.");
+ m_tftp_dfu_ctx.image_type = TFTP_DFU_IMAGE_TYPE_BOOTLOADER;
+ }
+ else
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ {
+ if (app_present)
+ {
+ NRF_LOG_INFO("Update Application only.");
+ m_tftp_dfu_ctx.image_type = TFTP_DFU_IMAGE_TYPE_APPLICATION;
+ }
+ else
+ {
+ // This example application does not implement SoftDevice with Bootloader update
+ NRF_LOG_INFO("Device firmware up to date.");
+ err_code = NRF_ERROR_NOT_FOUND;
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ switch (m_tftp_dfu_ctx.image_type)
+ {
+ case TFTP_DFU_IMAGE_TYPE_APPLICATION:
+ err_code = get_init_path(p_filename, CONFIG_APP_KEY);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_dfu_firmware_desc->application = app;
+ }
+
+ break;
+
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ case TFTP_DFU_IMAGE_TYPE_BOOTLOADER:
+ err_code = get_init_path(p_filename, CONFIG_BL_KEY);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_dfu_firmware_desc->bootloader = bl;
+ }
+
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_SOFTDEVICE:
+ err_code = get_init_path(p_filename, CONFIG_APPSD_KEY);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_dfu_firmware_desc->softdevice = sd;
+ p_dfu_firmware_desc->application = app;
+ }
+
+ break;
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+
+ default:
+ ASSERT(false);
+ }
+ }
+
+ if (p_filename[0] == '\0')
+ {
+ NRF_LOG_ERROR("File name has not be found.");
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+
+ cJSON_Delete(m_tftp_dfu_ctx.p_config_json);
+
+ return err_code;
+}
+
+/** @brief Set resource path to point to firmware binary file.
+ *
+ * @param [out] p_filename Pointer to resource path.
+ *
+ * @return NRF_SUCCESS if setting firmware path succeeded or error code indicating failure reason.
+ */
+static uint32_t set_firmware_path(char * p_filename)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ m_tftp_dfu_ctx.p_config_json = cJSON_Parse((const char *)m_tftp_dfu_ctx.config_mem);
+ if (m_tftp_dfu_ctx.p_config_json == NULL)
+ {
+ NRF_LOG_ERROR("JSON parse failed.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ switch (m_tftp_dfu_ctx.image_type)
+ {
+ case TFTP_DFU_IMAGE_TYPE_APPLICATION:
+ err_code = get_path(p_filename, CONFIG_APP_KEY);
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_BOOTLOADER:
+ err_code = get_path(p_filename, CONFIG_BL_KEY);
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_SOFTDEVICE:
+ err_code = get_path(p_filename, CONFIG_APPSD_KEY);
+ break;
+
+ default:
+ ASSERT(false);
+ }
+
+ if (p_filename[0] == '\0')
+ {
+ NRF_LOG_ERROR("File name has not be found.");
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+
+ cJSON_Delete(m_tftp_dfu_ctx.p_config_json);
+
+ return err_code;
+}
+
+/** @brief Send download request to the TFTP server.
+ *
+ * @param[in] p_file Pointer to file instance used to store file. May be NULL if file is not
+ * stored by TFTP module.
+ */
+static void send_request(iot_file_t * p_file)
+{
+ uint32_t err_code;
+ iot_tftp_trans_params_t trans_params;
+
+ trans_params.block_size = APP_TFTP_BLOCK_SIZE;
+ trans_params.next_retr = APP_TFTP_RETRANSMISSION_TIME;
+
+ err_code = iot_tftp_set_params(&m_tftp_dfu_ctx.tftp, &trans_params);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ err_code = iot_tftp_get(&m_tftp_dfu_ctx.tftp, p_file, m_tftp_dfu_ctx.resource_path);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ UNUSED_VARIABLE(err_code);
+}
+
+/***************************************************************************************************
+ * @section TFTP handler
+ **************************************************************************************************/
+
+/**
+ * @brief Process retrieved config file
+ *
+ * @param[in] p_file Pointer to retrieved config file.
+ */
+static void config_file_retrieved(iot_file_t * p_file)
+{
+ uint32_t err_code;
+ background_dfu_trigger_t trigger;
+ iot_dfu_firmware_block_t * p_firmware_block = NULL;
+
+ NRF_LOG_INFO("Config file successfully downloaded.");
+
+ m_tftp_dfu_ctx.config_mem[p_file->file_size] = 0;
+ memset(&m_tftp_dfu_ctx.firmware_desc, 0, sizeof(m_tftp_dfu_ctx.firmware_desc));
+
+ err_code = app_dfu_config_process(&m_tftp_dfu_ctx.firmware_desc, m_tftp_dfu_ctx.resource_path);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_INFO("New sofware available. Starting downloading procedure.");
+
+ switch(m_tftp_dfu_ctx.image_type)
+ {
+ case TFTP_DFU_IMAGE_TYPE_APPLICATION:
+ p_firmware_block = &m_tftp_dfu_ctx.firmware_desc.application;
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_BOOTLOADER:
+ p_firmware_block = &m_tftp_dfu_ctx.firmware_desc.bootloader;
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_SOFTDEVICE:
+ p_firmware_block = &m_tftp_dfu_ctx.firmware_desc.softdevice;
+ break;
+ }
+
+ memset(&trigger, 0, sizeof(trigger));
+ trigger.init_length = uint32_big_decode((const uint8_t *)&p_firmware_block->init_size);
+ trigger.init_crc = uint32_big_decode((const uint8_t *)&p_firmware_block->init_crc);
+ trigger.image_length = uint32_big_decode((const uint8_t *)&p_firmware_block->size);
+ trigger.image_crc = uint32_big_decode((const uint8_t *)&p_firmware_block->crc);
+
+ if (background_dfu_validate_trigger(&m_dfu_ctx, (uint8_t *)&trigger, sizeof(trigger)))
+ {
+ if (!background_dfu_process_trigger(&m_dfu_ctx, (uint8_t *)&trigger, sizeof(trigger)))
+ {
+ NRF_LOG_ERROR("Error in TFTP background_dfu_process_trigger");
+ }
+
+ if (m_dfu_ctx.dfu_state == BACKGROUND_DFU_IDLE)
+ {
+ // State in DFU_IDLE, nothing to download.
+ err_code = iot_tftp_uninit(&m_tftp_dfu_ctx.tftp);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in TFTP uninit (%d)", err_code);
+ }
+ }
+ }
+ }
+ else
+ {
+ NRF_LOG_INFO("No new sofware available or incorrect JSON file.");
+ }
+}
+
+/**
+ * @brief Pass block of retrieved data to background DFU module.
+ *
+ * @param[in] p_block Pointer to block of retrieved data.
+ */
+static void process_block(uint8_t * p_block)
+{
+ background_dfu_block_t block;
+ background_dfu_block_result_t result;
+
+ block.number = m_tftp_dfu_ctx.block_number;
+ block.size = DEFAULT_BLOCK_SIZE;
+ block.p_payload = p_block;
+
+ m_tftp_dfu_ctx.block_number++;
+
+ result = background_dfu_process_block(&m_dfu_ctx, &block);
+ if (result != BACKGROUND_DFU_BLOCK_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in TFTP background_dfu_process_block (%d)", result);
+ }
+}
+
+/**
+ * @brief Process retrieved data chunk.
+ *
+ * Split retrieved data to blocks of DEFAULT_BLOCK_SIZE bytes and pass to DFU module.
+ *
+ * @param[in] p_data_received Pointer to structure describing received data chunk.
+ */
+static void data_chunk_retrieved(iot_tftp_evt_data_received_t * p_data_received)
+{
+ uint16_t processed_bytes = 0;
+
+ // Process part of block from previous chunk
+ if (m_tftp_dfu_ctx.block_size)
+ {
+ uint16_t first_block_missing_size = DEFAULT_BLOCK_SIZE - m_tftp_dfu_ctx.block_size;
+
+ if (p_data_received->size < first_block_missing_size)
+ {
+ first_block_missing_size = p_data_received->size;
+ }
+
+ memcpy(&m_tftp_dfu_ctx.block[m_tftp_dfu_ctx.block_size],
+ p_data_received->p_data,
+ first_block_missing_size);
+
+ process_block(m_tftp_dfu_ctx.block);
+
+ processed_bytes = first_block_missing_size;
+ }
+
+ // Process received chunks
+ while (p_data_received->size - processed_bytes >= DEFAULT_BLOCK_SIZE)
+ {
+ process_block(&p_data_received->p_data[processed_bytes]);
+ processed_bytes += DEFAULT_BLOCK_SIZE;
+ }
+
+ m_tftp_dfu_ctx.block_size = p_data_received->size - processed_bytes;
+
+ // Leave not processed data
+ if (p_data_received->size > processed_bytes)
+ {
+ memcpy(m_tftp_dfu_ctx.block,
+ &p_data_received->p_data[processed_bytes],
+ m_tftp_dfu_ctx.block_size);
+ }
+}
+
+/**
+ * @brief Process data left from previous chunk.
+ */
+static void preserved_block_process(void)
+{
+ process_block(m_tftp_dfu_ctx.block);
+ m_tftp_dfu_ctx.block_size = 0;
+}
+
+/**
+ * @brief Handler of TFTP events.
+ */
+static void tftp_dfu_tftp_handler(iot_tftp_t * p_tftp, iot_tftp_evt_t * p_evt)
+{
+ switch (p_evt->id)
+ {
+ case IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED:
+ switch (m_dfu_ctx.dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ data_chunk_retrieved(&p_evt->param.data_received);
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+ break;
+
+ case IOT_TFTP_EVT_TRANSFER_GET_COMPLETE:
+ switch (m_dfu_ctx.dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ config_file_retrieved(p_evt->p_file);
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ preserved_block_process();
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+ break;
+
+ case IOT_TFTP_EVT_ERROR:
+ background_dfu_handle_error();
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+}
+
+static void dfu_observer(nrf_dfu_evt_type_t evt_type)
+{
+ switch (evt_type)
+ {
+ case NRF_DFU_EVT_DFU_COMPLETED:
+ NRF_LOG_FINAL_FLUSH();
+
+#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
+ // To allow the buffer to be flushed by the host.
+ nrf_delay_ms(100);
+#endif
+
+ NVIC_SystemReset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/***************************************************************************************************
+ * @section Private API
+ **************************************************************************************************/
+
+void background_dfu_transport_block_request_send(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_request_bitmap_t * p_req_bmp)
+{
+ // Intentionally empty: multicast DFU not implemented.
+}
+
+void background_dfu_transport_send_request(background_dfu_context_t * p_dfu_ctx)
+{
+ switch (m_dfu_ctx.dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ send_request(&m_tftp_dfu_ctx.config_file);
+ break;
+
+ default:
+ // In other states download operation is triggered by state_update() notification.
+ break;
+ }
+}
+
+void background_dfu_transport_state_update(background_dfu_context_t * p_dfu_ctx)
+{
+ switch (p_dfu_ctx->dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ trigger_path_set();
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ m_tftp_dfu_ctx.block_number = 0;
+ m_tftp_dfu_ctx.block_size = 0;
+ send_request(NULL);
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ m_tftp_dfu_ctx.block_number = 0;
+ m_tftp_dfu_ctx.block_size = 0;
+ UNUSED_RETURN_VALUE(set_firmware_path(m_tftp_dfu_ctx.resource_path));
+ send_request(NULL);
+ break;
+
+ case BACKGROUND_DFU_WAIT_FOR_RESET:
+ // Do nothing.
+ break;
+
+ default:
+ NRF_LOG_WARNING("Unhandled state in background_dfu_transport_state_update (s: %s).",
+ (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state));
+ }
+}
+
+uint32_t background_dfu_random(void)
+{
+ // Intentionally empty: multicast DFU not implemented.
+ return 0;
+}
+
+/***************************************************************************************************
+ * @section Public API
+ **************************************************************************************************/
+
+uint32_t tftp_dfu_init(void)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ memset(&m_tftp_dfu_ctx, 0, sizeof(m_tftp_dfu_ctx));
+
+ err_code = nrf_dfu_settings_init(true);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = nrf_dfu_req_handler_init(dfu_observer);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ background_dfu_state_init(&m_dfu_ctx);
+
+ cJSON_Init();
+
+ // Initialize file static instance.
+ IOT_FILE_STATIC_INIT(&m_tftp_dfu_ctx.config_file,
+ m_tftp_dfu_ctx.resource_path,
+ m_tftp_dfu_ctx.config_mem,
+ MAX_CONFIG_SIZE);
+
+ return err_code;
+}
+
+uint32_t tftp_dfu_trigger(const ipv6_addr_t * p_host_ipv6, uint16_t src_port, uint16_t dst_port)
+{
+ uint32_t err_code;
+ iot_tftp_init_t tftp_init_params;
+
+ NRF_LOG_INFO("Triggering DFU");
+
+ if (p_host_ipv6 == NULL)
+ {
+ NRF_LOG_WARNING("NULL IPv6 address");
+ return NRF_ERROR_NULL;
+ }
+
+ if (m_dfu_ctx.dfu_state != BACKGROUND_DFU_IDLE)
+ {
+ NRF_LOG_WARNING("Invalid state");
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ // Set TFTP configuration
+ memset(&tftp_init_params, 0, sizeof(iot_tftp_init_t));
+ tftp_init_params.p_ipv6_addr = (ipv6_addr_t *)p_host_ipv6;
+ tftp_init_params.src_port = src_port;
+ tftp_init_params.dst_port = dst_port;
+ tftp_init_params.callback = tftp_dfu_tftp_handler;
+
+ // Initialize instance, bind socket, check parameters.
+ err_code = iot_tftp_init(&m_tftp_dfu_ctx.tftp, &tftp_init_params);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in TFTP init (%d)", err_code);
+ return err_code;
+ }
+
+ trigger_path_set();
+
+ // Transition from DFU_IDLE to DFU_DOWNLOAD_TRIG.
+ return background_dfu_handle_event(&m_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
+}
+
+void background_dfu_handle_error(void)
+{
+ UNUSED_RETURN_VALUE(iot_tftp_uninit(&m_tftp_dfu_ctx.tftp));
+ tftp_dfu_handle_error();
+}
+
+__WEAK void tftp_dfu_handle_error(void)
+{
+
+}
+
+bool nrf_dfu_button_enter_check(void)
+{
+ // Dummy function for Keil compilation. This should not be called.
+ return false;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h
new file mode 100644
index 0000000..6c8370b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2017 - 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.
+ *
+ */
+
+/** @file tftp_dfu.h
+ *
+ * @defgroup tftp_dfu TFTP transport for Background DFU
+ * @ingroup iot_tftp_dfu
+ * @{
+ * @brief TFTP transport for Background DFU.
+ *
+ */
+
+#ifndef TFTP_DFU_H_
+#define TFTP_DFU_H_
+
+#include <stdint.h>
+#include "iot_defines.h"
+
+/** @brief Initialize DFU client.
+ *
+ * @returns NRF_SUCCESS if DFU procedure started. Otherwise an error code indicating problem.
+ */
+uint32_t tftp_dfu_init(void);
+
+/** @brief Trigger DFU.
+ *
+ * @param[in] p_host_ipv6 IPv6 address of TFTP host.
+ * @param[in] src_port Source UDP port used by TFTP service.
+ * @param[in] dst_port Destination UDP port used by TFTP service.
+ *
+ * @returns NRF_SUCCESS if DFU procedure started. Otherwise an error code indicating problem.
+ */
+uint32_t tftp_dfu_trigger(const ipv6_addr_t * p_host_ipv6, uint16_t src_port, uint16_t dst_port);
+
+/** @brief Handle DFU error.
+ *
+ * This function can be implemented in the application to undertake application-specific action on DFU error.
+ */
+extern void tftp_dfu_handle_error(void);
+
+#endif /* TFTP_DFU_H_ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.c
new file mode 100644
index 0000000..b7bf6fa
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.c
@@ -0,0 +1,1978 @@
+/**
+ * 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_6lowpan 6LoWPAN Adaptation Layer
+ * @{
+ * @ingroup ble_sdk_iot
+ * @brief 6LoWPAN Adaptation Layer
+ *
+ * @details This module enables 6LoWPAN over Bluetooth Low Energy.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "nrf_soc.h"
+#include "nordic_common.h"
+#include "ble_ipsp.h"
+#include "ble_6lowpan.h"
+#include "iot_common.h"
+#include "iot_context_manager.h"
+#include "app_util_platform.h"
+#include "mem_manager.h"
+
+/**
+ * @defgroup ble_sdk_6lowpan Module's Log Macros
+ * @details Macros used for creating module logs which can be useful in understanding handling
+ * of events or actions on API requests. These are intended for debugging purposes and
+ * can be enabled by defining the IOT_BLE_6LOWPAN_CONFIG_LOG_ENABLED.
+ * @note If NRF_LOG_ENABLED is disabled, having IOT_BLE_6LOWPAN_CONFIG_LOG_ENABLED
+ * has no effect.
+ * @{
+ */
+
+#if IOT_BLE_6LOWPAN_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME 6lowpan
+
+#define NRF_LOG_LEVEL IOT_BLE_6LOWPAN_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IOT_BLE_6LOWPAN_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IOT_BLE_6LOWPAN_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define BLE_6LOWPAN_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define BLE_6LOWPAN_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define BLE_6LOWPAN_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define BLE_6LOWPAN_ENTRY() BLE_6LOWPAN_TRC(">> %s", __func__)
+#define BLE_6LOWPAN_EXIT() BLE_6LOWPAN_TRC("<< %s", __func__)
+
+#else // IOT_BLE_6LOWPAN_CONFIG_LOG_ENABLED
+
+#define BLE_6LOWPAN_TRC(...) /**< Disables traces. */
+#define BLE_6LOWPAN_DUMP(...) /**< Disables dumping of octet streams. */
+#define BLE_6LOWPAN_ERR(...) /**< Disables error logs. */
+
+#define BLE_6LOWPAN_ENTRY(...)
+#define BLE_6LOWPAN_EXIT(...)
+
+#endif // IOT_BLE_6LOWPAN_CONFIG_LOG_ENABLED
+
+
+
+/** @} */
+
+/**
+ * @defgroup ble_6lowpan_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 BLE_6LOWPAN_MUTEX_LOCK() SDK_MUTEX_LOCK(m_6lowpan_mutex) /**< Lock module using mutex */
+#define BLE_6LOWPAN_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_6lowpan_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.
+ * BLE_6LOWPAN_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+
+#if (BLE_6LOWPAN_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 | BLE_6LOWPAN_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 | BLE_6LOWPAN_ERR_BASE); \
+ }
+
+/**@brief Check if packet has at least IP Header in it (40 bytes). */
+#define PACKET_LENGTH_CHECK(PARAM) \
+ if ((PARAM) < IPV6_IP_HEADER_SIZE) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | BLE_6LOWPAN_ERR_BASE); \
+ }
+
+#else // BLE_6LOWPAN_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define NULL_PARAM_CHECK(PARAM)
+#define PACKET_LENGTH_CHECK(PARAM)
+
+#endif // BLE_6LOWPAN_DISABLE_API_PARAM_CHECK
+
+/** @} */
+
+/**@brief Maximum different between compressed and uncompressed packet. */
+#define IPHC_MAX_COMPRESSED_DIFF (IPV6_IP_HEADER_SIZE + UDP_HEADER_SIZE - 7)
+
+/**@brief Transmit FIFO mask. */
+#define TX_FIFO_MASK (BLE_6LOWPAN_TX_FIFO_SIZE - 1)
+
+/**@brief Value and position of IPHC dispatch. */
+#define IPHC_START_DISPATCH 0x03
+#define IPHC_START_DISPATCH_POS 5
+
+/**@brief Values and positions of IPHC fields. */
+#define IPHC_TF_MASK 0x18
+#define IPHC_TF_POS 3
+#define IPHC_NH_MASK 0x04
+#define IPHC_NH_POS 2
+#define IPHC_HLIM_MASK 0x03
+#define IPHC_HLIM_POS 0
+#define IPHC_CID_MASK 0x80
+#define IPHC_CID_POS 7
+#define IPHC_SAC_MASK 0x40
+#define IPHC_SAC_POS 6
+#define IPHC_SAM_MASK 0x30
+#define IPHC_SAM_POS 4
+#define IPHC_M_MASK 0x08
+#define IPHC_M_POS 3
+#define IPHC_DAC_MASK 0x04
+#define IPHC_DAC_POS 2
+#define IPHC_DAM_MASK 0x03
+#define IPHC_DAM_POS 0
+
+/**@brief IPHC Traffic Flow compression. */
+#define IPHC_TF_DSCP_MASK 0x3F
+#define IPHC_TF_ECN_MASK 0xC0
+#define IPHC_TF_ECN_POS 6
+
+/**@brief IPHC values of fields. */
+#define IPHC_TF_00 0x00
+#define IPHC_TF_01 0x01
+#define IPHC_TF_10 0x02
+#define IPHC_TF_11 0x03
+#define IPHC_NH_0 0x00
+#define IPHC_NH_1 0x01
+#define IPHC_HLIM_00 0x00
+#define IPHC_HLIM_01 0x01
+#define IPHC_HLIM_10 0x02
+#define IPHC_HLIM_11 0x03
+#define IPHC_CID_0 0x00
+#define IPHC_CID_1 0x01
+#define IPHC_SAC_0 0x00
+#define IPHC_SAC_1 0x01
+#define IPHC_SAM_00 0x00
+#define IPHC_SAM_01 0x01
+#define IPHC_SAM_10 0x02
+#define IPHC_SAM_11 0x03
+#define IPHC_M_0 0x00
+#define IPHC_M_1 0x01
+#define IPHC_DAC_0 0x00
+#define IPHC_DAC_1 0x01
+#define IPHC_DAM_00 0x00
+#define IPHC_DAM_01 0x01
+#define IPHC_DAM_10 0x02
+#define IPHC_DAM_11 0x03
+
+/**@brief IPHC Context Identifier compression. */
+#define IPHC_CID_SOURCE_MASK 0xF0
+#define IPHC_CID_SOURCE_POS 4
+#define IPHC_CID_DESTINATION_MASK 0x0F
+#define IPHC_CID_DESTINATION_POS 0
+
+/**@brief IPHC Next Header Compression dispatches. */
+#define IPHC_NHC_UDP_DISPATCH 0xF0
+#define IPHC_NHC_UDP_MASK 0xF8
+#define IPHC_NHC_EXT_DISPATCH 0xE0
+#define IPHC_NHC_EXT_MASK 0xF0
+
+/**@brief IPHC Next Header Compression UDP fields. */
+#define IPHC_NHC_UDP_CSUM_MASK 0x04
+#define IPHC_NHC_UDP_CSUM_POS 0x02
+#define IPHC_NHC_UDP_PORTS_MASK 0x03
+#define IPHC_NHC_UDP_PORTS_POS 0x00
+#define IPHC_NHC_UDP_PORTS_00 0x00
+#define IPHC_NHC_UDP_PORTS_01 0x01
+#define IPHC_NHC_UDP_PORTS_10 0x02
+#define IPHC_NHC_UDP_PORTS_11 0x03
+
+#define IPHC_NHC_UDP_COMPRESSION_MAX_MASK 0xFFF0
+#define IPHC_NHC_UDP_COMPRESSION_MAX 0xF0B0
+#define IPHC_NHC_UDP_COMPRESSION_MIN_MASK 0xFF00
+#define IPHC_NHC_UDP_COMPRESSION_MIN 0xF000
+
+/**@brief IPHC Next Header Compression Extended Header fields. */
+#define IPHC_NHC_EXT_EID_MASK 0x0E
+#define IPHC_NHC_EXT_EID_POS 0x01
+#define IPHC_NHC_EXT_EID_HOP_BY_HOP 0x00
+#define IPHC_NHC_EXT_EID_ROUTING 0x01
+#define IPHC_NHC_EXT_EID_FRAGMENT 0x02
+#define IPHC_NHC_EXT_EID_DESTINATION 0x03
+#define IPHC_NHC_EXT_EID_MOBILITY 0x04
+#define IPHC_NHC_EXT_EID_IPV6 0x07
+
+/**@brief IPHC default value of IPv6 Header fields. */
+#define IPHC_IPHEADER_VER_TC 0x60
+#define IPHC_IPHEADER_TC_FL 0x00
+#define IPHC_IPHEADER_FL 0x00
+
+/**@brief Check if address can be fully elidable. */
+#define IPV6_ADDRESS_IS_FULLY_ELIDABLE(ll_addr, addr) \
+ (((addr)->u8[8] == (((ll_addr[0]) ^ IPV6_IID_FLIP_VALUE))) && \
+ ((addr)->u8[9] == ll_addr[1]) && \
+ ((addr)->u8[10] == ll_addr[2]) && \
+ ((addr)->u8[11] == ll_addr[3]) && \
+ ((addr)->u8[12] == ll_addr[4]) && \
+ ((addr)->u8[11] == 0xff) && \
+ ((addr)->u8[12] == 0xfe) && \
+ ((addr)->u8[13] == ll_addr[5]) && \
+ ((addr)->u8[14] == ll_addr[6]) && \
+ ((addr)->u8[15] == ll_addr[7]) \
+ )
+
+/**@brief Check if address is 16-bit and can be compressed.
+ * 16-bit COMPRESSABLE format: ::0000:00ff:fe00:XXXX.
+ */
+#define IPV6_ADDRESS_IS_16_BIT_COMPRESSABLE(addr) \
+ (((addr)->u8[8] == 0) && \
+ ((addr)->u8[9] == 0) && \
+ ((addr)->u8[10] == 0) && \
+ ((addr)->u8[11] == 0xff) && \
+ ((addr)->u8[12] == 0xfe) && \
+ ((addr)->u8[13] == 0) \
+ )
+
+/**@brief Check if address is 48-bit multi-cast and can be compressed.
+ * 48-bit COMPRESSABLE format: FFXX::00XX:XXXX:XXXX.
+ */
+#define IPV6_ADDRESS_IS_48_BIT_MCAST_COMPRESSABLE(addr) \
+ (((addr)->u16[1] == 0) && \
+ ((addr)->u16[2] == 0) && \
+ ((addr)->u16[3] == 0) && \
+ ((addr)->u16[4] == 0) && \
+ ((addr)->u8[10] == 0) \
+ )
+
+/**@brief Check if address is 32-bit multi-cast and can be compressed.
+ * 32-bit COMPRESSABLE format: FFXX::00XX:XXXX.
+ */
+#define IPV6_ADDRESS_IS_32_BIT_MCAST_COMPRESSABLE(addr) \
+ (((addr)->u16[1] == 0) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == 0) && \
+ ((addr)->u8[12] == 0) \
+ )
+
+/**@brief Check if address is 8-bit multi-cast and can be compressed.
+ * 8-bit COMPRESSABLE format: FF02::XX.
+ */
+#define IPV6_ADDRESS_IS_8_BIT_MCAST_COMPRESSABLE(addr) \
+ (((addr)->u8[1] == 2) && \
+ ((addr)->u16[1] == 0) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == 0) && \
+ ((addr)->u16[6] == 0) && \
+ ((addr)->u8[14] == 0) \
+ )
+
+/******************************************************************************
+ * 6LoWPAN Core and Transport structures.
+ ******************************************************************************/
+
+/**@brief Element of TX Queue. */
+typedef struct
+{
+ uint8_t * p_mem_block; /**< Base address of memory block, using for release the buffer. */
+ uint8_t * p_data; /**< Pointer to TX Data. */
+ uint16_t data_len; /**< Size of TX data. */
+} tx_packet_t;
+
+/**@brief A TX Queue (FIFO) structure. */
+typedef struct
+{
+ tx_packet_t packets[BLE_6LOWPAN_TX_FIFO_SIZE]; /**< Array of TX packet in FIFO. */
+ volatile uint32_t read_pos; /**< Next read position in the FIFO buffer. */
+ volatile uint32_t write_pos; /**< Next write position in the FIFO buffer. */
+} tx_fifo_t;
+
+/**@brief Transport instance structure. */
+typedef struct
+{
+ iot_interface_t interface;
+ ble_ipsp_handle_t handle;
+ tx_fifo_t tx_fifo;
+ tx_packet_t * p_tx_cur_packet;
+} transport_instance_t;
+
+/******************************************************************************
+ * @name Global variables
+ *****************************************************************************/
+
+/**@brief Application Event Handler. */
+static ble_6lowpan_evt_handler_t m_event_handler = NULL;
+
+/**@brief Hop Limit options. */
+static const uint8_t m_hop_limit[] = {0, 1, 64, 255};
+
+/**@brief Link-local prefix. */
+static const uint8_t m_link_local_prefix[] = {0xFE, 0x80};
+
+/**@brief Additional extenders for EUI-48. */
+static const uint8_t m_link_local_16_middle[] = {0xFF, 0xFE};
+
+/**@brief nRF EUI-64 link-layer address */
+static eui64_t m_ll_addr = {{0, 0, 0, 0, 0, 0, 0, 0}};
+
+/**@brief Transport interfaces table. */
+static transport_instance_t m_instances[BLE_6LOWPAN_MAX_INTERFACE];
+
+/**@brief Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+SDK_MUTEX_DEFINE(m_6lowpan_mutex)
+
+/******************************************************************************
+ * @name 6LoWPAN core functions
+ *****************************************************************************/
+
+/**@brief Function for checking if IID can be completely elided. This situation
+ * may happen when receiver can still reconstruct IPv6 address by using context
+ * prefix and Link Layer address.
+ *
+ * @param[in] p_addr Pointer to IPv6 address.
+ * @param[in] p_context Pointer to context entry that is compressed with.
+ * @param[in] p_ll_addr Pointer to link layer address of BT-LE device.
+ *
+ * @return True if IID can be elided, False otherwise.
+ */
+static bool is_context_cover_iid(const ipv6_addr_t * p_addr,
+ const iot_context_t * p_context,
+ const eui64_t * p_ll_addr)
+{
+ uint32_t start_byte, offset;
+
+ // Context covers IPv6 address by its size.
+ if (p_context->prefix_len == 128)
+ {
+ return true;
+ }
+
+ // Check if IID can be retrieved in case of longer prefix than 64 bits.
+ if (p_context->prefix_len > 64)
+ {
+ // Check only IID fields that are not covered by context prefix.
+ start_byte = p_context->prefix_len >> 3;
+ offset = p_context->prefix_len % 8;
+
+ // Check all bytes from the second one.
+ if (start_byte == 15 ||
+ 0 == memcmp(&p_addr->u8[start_byte+1], &p_ll_addr->identifier[start_byte-7], 15-start_byte))
+ {
+ // Then check first byte.
+ return (p_addr->u8[start_byte] << offset) == (p_ll_addr->identifier[start_byte-8] << offset);
+ }
+ }
+
+ return false;
+}
+
+/**@brief Function for decoding Next Header Compression.
+ * It supports UDP header decompression.
+ *
+ * @param[in] p_iphc Pointer to currently process IPHC field.
+ * @param[in] p_data Pointer to constructing uncompressed IP packet.
+ * @param[in] p_length Place of UDP header in case of Extension Header.
+ * @param[out] p_length Length of the constructed uncompressed header.
+ *
+ * @return Number of processed IPHC field.
+ */
+static uint32_t iphc_nhc_decode(uint8_t * p_iphc, uint8_t * p_data, uint16_t * p_length)
+{
+ uint8_t nhc_dispatch = *p_iphc;
+ uint8_t * p_nhc = p_iphc;
+
+ ipv6_header_t * iphdr = (ipv6_header_t *)&p_data[0];
+
+ // UDP Next Header Compression.
+ if ((nhc_dispatch & IPHC_NHC_UDP_MASK) == IPHC_NHC_UDP_DISPATCH)
+ {
+ udp6_header_t * udphdr = (udp6_header_t * )&p_data[IPV6_IP_HEADER_SIZE + *p_length];
+
+ iphdr->next_header = IPV6_NEXT_HEADER_UDP;
+
+ // Start length from UDP Header Size.
+ *p_length += UDP_HEADER_SIZE;
+ p_nhc += 1;
+
+ switch ((nhc_dispatch & IPHC_NHC_UDP_PORTS_MASK) >> IPHC_NHC_UDP_PORTS_POS)
+ {
+ case IPHC_NHC_UDP_PORTS_00:
+ memcpy(&udphdr->srcport, p_nhc, 2);
+ memcpy(&udphdr->destport, p_nhc + 2, 2);
+ p_nhc += 4;
+ break;
+
+ case IPHC_NHC_UDP_PORTS_01:
+ memcpy(&udphdr->srcport, p_nhc, 2);
+ udphdr->destport = HTONS(IPHC_NHC_UDP_COMPRESSION_MIN | *(p_nhc + 2));
+ p_nhc += 3;
+ break;
+
+ case IPHC_NHC_UDP_PORTS_10:
+ udphdr->srcport = HTONS(IPHC_NHC_UDP_COMPRESSION_MIN | *p_nhc);
+ memcpy(&udphdr->destport, p_nhc + 1, 2);
+ p_nhc += 3;
+ break;
+
+ case IPHC_NHC_UDP_PORTS_11:
+ udphdr->srcport = HTONS((IPHC_NHC_UDP_COMPRESSION_MAX | ((*p_nhc & 0xf0) >> 4)));
+ udphdr->destport = HTONS((IPHC_NHC_UDP_COMPRESSION_MAX | ((*p_nhc & 0x0f))));
+ p_nhc += 1;
+ break;
+ }
+
+ if ((nhc_dispatch & IPHC_NHC_UDP_CSUM_MASK) >> IPHC_NHC_UDP_CSUM_POS)
+ {
+ udphdr->checksum = 0;
+ }
+ else
+ {
+ memcpy(&udphdr->checksum, p_nhc, 2);
+ p_nhc += 2;
+ }
+ }
+
+ return (p_nhc - p_iphc);
+}
+
+/**@brief Function for encoding Next Header Compression.
+ * It supports UDP header compression.
+ *
+ * @param[in] p_iphc Pointer to currently process IPHC field.
+ * @param[in] p_data Pointer to constructing uncompressed IP packet.
+ * @param[in] p_length Place of UDP header in case of Extension Header.
+ * @param[out] p_length Length of the constructed uncompressed header.
+ *
+ * @return Number of processed IPHC field.
+ */
+static uint32_t iphc_nhc_encode(uint8_t * p_iphc, const uint8_t * p_data, uint16_t * p_length)
+{
+ uint8_t * p_nhc = p_iphc;
+ ipv6_header_t * iphdr = (ipv6_header_t *)p_data;
+
+ switch (iphdr->next_header)
+ {
+ case IPV6_NEXT_HEADER_UDP:
+ {
+ udp6_header_t * udphdr = (udp6_header_t * )&p_data[IPV6_IP_HEADER_SIZE + *p_length];
+ *p_iphc = IPHC_NHC_UDP_DISPATCH;
+ p_nhc += 1;
+
+ // Full 4-bit compression for source and destination ports.
+ if ( ((HTONS(udphdr->srcport) & IPHC_NHC_UDP_COMPRESSION_MAX_MASK) ==
+ IPHC_NHC_UDP_COMPRESSION_MAX) &&
+ ((HTONS(udphdr->destport) & IPHC_NHC_UDP_COMPRESSION_MAX_MASK) ==
+ IPHC_NHC_UDP_COMPRESSION_MAX))
+ {
+ *p_iphc |= (IPHC_NHC_UDP_PORTS_11 >> IPHC_NHC_UDP_PORTS_POS);
+
+ *p_nhc =
+ (((HTONS(udphdr->srcport) & 0x0f) << 4) | (HTONS(udphdr->destport) & 0x0f));
+ p_nhc += 1;
+ }
+ // Source port compressed, destination in-line.
+ else if ((HTONS(udphdr->srcport) & IPHC_NHC_UDP_COMPRESSION_MIN_MASK) ==
+ IPHC_NHC_UDP_COMPRESSION_MIN)
+ {
+ *p_iphc |= (IPHC_NHC_UDP_PORTS_10 >> IPHC_NHC_UDP_PORTS_POS);
+
+ *p_nhc = (HTONS(udphdr->srcport) & 0xff);
+ p_nhc += 1;
+
+ memcpy(p_nhc, &udphdr->destport, 2);
+ p_nhc += 2;
+ }
+ // Source port in-line, destination compressed.
+ else if ((HTONS(udphdr->destport) & IPHC_NHC_UDP_COMPRESSION_MIN_MASK) ==
+ IPHC_NHC_UDP_COMPRESSION_MIN)
+ {
+ *p_iphc |= (IPHC_NHC_UDP_PORTS_01 >> IPHC_NHC_UDP_PORTS_POS);
+
+ memcpy(p_nhc, &udphdr->srcport, 2);
+ p_nhc += 2;
+
+ *p_nhc = (HTONS(udphdr->destport) & 0xff);
+ p_nhc += 1;
+ }
+ // Source and destination port in-line.
+ else
+ {
+ *p_iphc |= (IPHC_NHC_UDP_PORTS_00 >> IPHC_NHC_UDP_PORTS_POS);
+
+ memcpy(p_nhc, &udphdr->srcport, 2);
+ memcpy(p_nhc + 2, &udphdr->destport, 2);
+ p_nhc += 4;
+ }
+
+ // Checksum always in-line, [RFC4944] disallows the compression of the
+ // UDP checksum. The compressor MUST NOT set the C bit unless it has received
+ // authorization.
+ memcpy(p_nhc, &udphdr->checksum, 2);
+ p_nhc += 2;
+
+ // Set UDP ext header size.
+ *p_length = UDP_HEADER_SIZE;
+
+ break;
+ }
+ }
+
+ return (p_nhc - p_iphc);
+}
+
+
+ /**@brief Function for checking if it's possible to use NHC.
+ *
+ * @param[in] next_header Value of Next Header field in IPv6 packet.
+ *
+ * @return Returns 1 if header can be compressed, otherwise 0.
+ */
+static uint32_t iphc_nhc_compressable(uint8_t next_header)
+{
+ switch (next_header)
+ {
+ case IPV6_NEXT_HEADER_UDP:
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**@brief Function for decoding IPHC (IP Header Compression) defined in
+ * IETF RFC 6282.
+ *
+ * @param[in] p_instance Transport instance from where packet came.
+ * @param[in] p_input Pointer to received packet from IPSP module.
+ * @param[in] input_len Length of received packet.
+ * @param[in] p_output Pointer to allocated buffer for decompressed packet.
+ * @param[out] p_output Pointer to decompressed IPv6 packet.
+ * @param[out] p_output_len Length of decompressed IPv6 packet.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t iphc_decode(iot_interface_t * p_interface,
+ uint8_t * p_output,
+ uint16_t * p_output_len,
+ uint8_t * p_input,
+ uint16_t input_len,
+ iot_context_id_t * p_rx_contexts)
+{
+ uint32_t retval = NRF_SUCCESS;
+ uint32_t err_code = NRF_SUCCESS;
+ uint8_t * p_iphc = p_input;
+ uint8_t sci = IPV6_CONTEXT_IDENTIFIER_NONE;
+ uint8_t dci = IPV6_CONTEXT_IDENTIFIER_NONE;
+ uint16_t nhc_length = 0;
+ iot_context_t * p_ctx = NULL;
+
+ // IPv6 headers used in decompression.
+ ipv6_header_t * p_iphdr = (ipv6_header_t *)p_output;
+ udp6_header_t * p_udphdr = (udp6_header_t *)&p_output[IPV6_IP_HEADER_SIZE];
+
+ // Check if format of packet is correct.
+ if ((p_input[0] >> IPHC_START_DISPATCH_POS) != IPHC_START_DISPATCH)
+ {
+ BLE_6LOWPAN_ERR("[6LoWPAN] Packet has incorrect IPHC structure!");
+
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // IPHC basic form has 2 bytes.
+ p_iphc += 2;
+
+ // RFC6282: An additional 8-bit Context Identifier Extension field
+ // immediately follows the Destination Address Mode (DAM) field.
+ if ((p_input[1] & IPHC_CID_MASK))
+ {
+ sci = ((*p_iphc & IPHC_CID_SOURCE_MASK) >> IPHC_CID_SOURCE_POS);
+ dci = ((*p_iphc & IPHC_CID_DESTINATION_MASK) >> IPHC_CID_DESTINATION_POS);
+ p_iphc += 1;
+ }
+
+ // Set proper context identifiers.
+ p_rx_contexts->src_cntxt_id = sci;
+ p_rx_contexts->dest_cntxt_id = dci;
+
+ switch ((p_input[0] & IPHC_TF_MASK) >> IPHC_TF_POS)
+ {
+ case IPHC_TF_11:
+ // Elide Traffic Class and Flow Label.
+ p_iphdr->version_traffic_class = IPHC_IPHEADER_VER_TC;
+ p_iphdr->traffic_class_flowlabel = IPHC_IPHEADER_TC_FL;
+ p_iphdr->flowlabel = IPHC_IPHEADER_FL;
+ break;
+
+ case IPHC_TF_10:
+ // Elide Flow Label.
+ p_iphdr->version_traffic_class = IPHC_IPHEADER_VER_TC | ((*p_iphc & IPHC_TF_DSCP_MASK) >> 2);
+ p_iphdr->traffic_class_flowlabel = ((*p_iphc & 0x03) << 6) |
+ ((*p_iphc & IPHC_TF_ECN_MASK) >> 2);
+ p_iphdr->flowlabel = IPHC_IPHEADER_FL;
+ p_iphc += 1;
+ break;
+
+ case IPHC_TF_01:
+ // Elide DSCP, carry ECN and Flow Label.
+ p_iphdr->version_traffic_class = IPHC_IPHEADER_VER_TC;
+ p_iphdr->traffic_class_flowlabel = ((*p_iphc & IPHC_TF_ECN_MASK) >> 2) |
+ ((*p_iphc & 0x0f));
+ memcpy(&p_iphdr->flowlabel, p_iphc + 1, 2);
+ p_iphc += 3;
+ break;
+
+ case IPHC_TF_00:
+ // Flow Label and Traffic Class in-line.
+ p_iphdr->version_traffic_class = IPHC_IPHEADER_VER_TC | ((*p_iphc & IPHC_TF_DSCP_MASK) >> 2);
+ p_iphdr->traffic_class_flowlabel = ((*p_iphc & 0x03) << 6) |
+ ((*p_iphc & IPHC_TF_ECN_MASK) >> 2) |
+ ((*(p_iphc + 1) & 0x0f));
+ memcpy(&p_iphdr->flowlabel, p_iphc + 2, 2);
+ p_iphc += 4;
+ break;
+ }
+
+ if (!((p_input[0] & IPHC_NH_MASK)))
+ {
+ // Set next header.
+ p_iphdr->next_header = *p_iphc++;
+ }
+
+ if ((p_input[0] & IPHC_HLIM_MASK))
+ {
+ p_iphdr->hoplimit = m_hop_limit[((p_input[0] & IPHC_HLIM_MASK) >> IPHC_HLIM_POS)];
+ }
+ else
+ {
+ p_iphdr->hoplimit = *p_iphc++;
+ }
+
+ // Clear IPv6 addresses.
+ memset(p_iphdr->srcaddr.u8, 0, IPV6_ADDR_SIZE);
+ memset(p_iphdr->destaddr.u8, 0, IPV6_ADDR_SIZE);
+
+ // Source address decompression.
+ if ((p_input[1] & IPHC_SAC_MASK) >> IPHC_SAC_POS)
+ {
+ if ( ((p_input[1] & IPHC_SAM_MASK) >> IPHC_SAM_POS) == IPHC_SAM_00 )
+ {
+ // Unspecified address.
+ memset(p_iphdr->srcaddr.u8, 0, IPV6_ADDR_SIZE);
+ }
+ else
+ {
+ switch ((p_input[1] & IPHC_SAM_MASK) >> IPHC_SAM_POS)
+ {
+ case IPHC_SAM_01:
+ // 64 bits in-line, first IID then prefix in case prefix > 64.
+ memcpy(p_iphdr->srcaddr.u8 + 8, p_iphc, 8);
+ p_iphc += 8;
+ break;
+
+ case IPHC_SAM_10:
+ // 16 bits in-line.
+ memcpy(p_iphdr->srcaddr.u8 + 14, p_iphc, 2);
+ memcpy(p_iphdr->srcaddr.u8 + 11, m_link_local_16_middle, 2);
+ p_iphc += 2;
+ break;
+
+ case IPHC_SAM_11:
+ // Take the address from lower layer.
+ memcpy(p_iphdr->srcaddr.u8 + 8, p_interface->peer_addr.identifier, 8);
+ p_iphdr->srcaddr.u8[8] ^= IPV6_IID_FLIP_VALUE;
+ break;
+ }
+
+ /* Look up for context */
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+ err_code = iot_context_manager_get_by_cid(p_interface, sci, &p_ctx);
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ if (err_code == NRF_SUCCESS)
+ {
+ /* Add prefix */
+ IPV6_ADDRESS_PREFIX_SET(p_iphdr->srcaddr.u8, p_ctx->prefix.u8, p_ctx->prefix_len);
+ }
+ else
+ {
+ /* Set error and continue decompression. */
+ retval = BLE_6LOWPAN_CID_NOT_FOUND;
+
+ BLE_6LOWPAN_ERR("Cannot find context identifier in the context table.");
+ }
+ }
+ }
+ else
+ {
+ switch ((p_input[1] & IPHC_SAM_MASK) >> IPHC_SAM_POS)
+ {
+ case IPHC_SAM_00:
+ // Full 128-bits in-line.
+ memcpy(p_iphdr->srcaddr.u8, p_iphc, IPV6_ADDR_SIZE);
+ p_iphc += IPV6_ADDR_SIZE;
+ break;
+
+ case IPHC_SAM_01:
+ // 64 bits in-line, first IID then prefix in case prefix > 64.
+ memcpy(p_iphdr->srcaddr.u8, m_link_local_prefix, 2);
+ memcpy(p_iphdr->srcaddr.u8 + 8, p_iphc, 8);
+ p_iphc += 8;
+ break;
+
+ case IPHC_SAM_10:
+ // 16 bits in-line.
+ memcpy(p_iphdr->srcaddr.u8, m_link_local_prefix, 2);
+ memcpy(p_iphdr->srcaddr.u8 + 11, m_link_local_16_middle, 2);
+ memcpy(p_iphdr->srcaddr.u8 + 14, p_iphc, 2);
+ p_iphc += 2;
+ break;
+
+ case IPHC_SAM_11:
+ memcpy(p_iphdr->srcaddr.u8, m_link_local_prefix, 2);
+ memcpy(p_iphdr->srcaddr.u8 + 8, p_interface->peer_addr.identifier, 8);
+ p_iphdr->srcaddr.u8[8] ^= IPV6_IID_FLIP_VALUE;
+ break;
+ }
+ }
+
+ // Destination address decompression.
+ if ((p_input[1] & IPHC_DAC_MASK) >> IPHC_DAC_POS)
+ {
+ if ((p_input[1] & IPHC_M_MASK) >> IPHC_M_POS)
+ {
+ switch ((p_input[1] & IPHC_DAM_MASK) >> IPHC_DAM_POS)
+ {
+ case IPHC_DAM_00:
+ // 48-bits in-line.
+ p_iphdr->destaddr.u8[0] = 0xff;
+ memcpy(p_iphdr->destaddr.u8 + 1, p_iphc, 2);
+ memcpy(p_iphdr->destaddr.u8 + 12, p_iphc + 2, 4);
+ p_iphc += 6;
+ break;
+
+ default:
+ BLE_6LOWPAN_ERR("Reserved value in IPHC header!");
+ return NRF_ERROR_INVALID_DATA;
+ }
+ }
+ else
+ {
+ switch ((p_input[1] & IPHC_DAM_MASK) >> IPHC_DAM_POS)
+ {
+ case IPHC_DAM_01:
+ // 64 bits in-line.
+ memcpy(p_iphdr->destaddr.u8 + 8, p_iphc, 8);
+ p_iphc += 8;
+ break;
+
+ case IPHC_DAM_10:
+ // 16 bits in-line.
+ memcpy(p_iphdr->destaddr.u8 + 11, m_link_local_16_middle, 2);
+ memcpy(p_iphdr->destaddr.u8 + 14, p_iphc, 2);
+ p_iphc += 2;
+ break;
+
+ case IPHC_DAM_11:
+ // Take the address from lower layer.
+ memcpy(p_iphdr->destaddr.u8 + 8, p_interface->local_addr.identifier, 8);
+ p_iphdr->destaddr.u8[8] ^= IPV6_IID_FLIP_VALUE;
+ break;
+
+ default:
+ BLE_6LOWPAN_ERR("Reserved value in IPHC header!");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ /* Look up for context */
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+ err_code = iot_context_manager_get_by_cid(p_interface, dci, &p_ctx);
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ if (err_code == NRF_SUCCESS)
+ {
+ /* Add prefix */
+ IPV6_ADDRESS_PREFIX_SET(p_iphdr->destaddr.u8, p_ctx->prefix.u8, p_ctx->prefix_len);
+ }
+ else
+ {
+ /* Set error and continue decompression. */
+ retval = BLE_6LOWPAN_CID_NOT_FOUND;
+
+ BLE_6LOWPAN_ERR("Cannot find context identifier in the context table.");
+ }
+ }
+ }
+ else
+ {
+ if ((p_input[1] & IPHC_M_MASK) >> IPHC_M_POS)
+ {
+ switch ((p_input[1] & IPHC_DAM_MASK) >> IPHC_DAM_POS)
+ {
+ case IPHC_DAM_00:
+ // 128 bits in-line.
+ memcpy(p_iphdr->destaddr.u8, p_iphc, IPV6_ADDR_SIZE);
+ p_iphc += IPV6_ADDR_SIZE;
+ break;
+
+ case IPHC_DAM_01:
+ // 48 bits in-line.
+ p_iphdr->destaddr.u8[0] = 0xFF;
+ p_iphdr->destaddr.u8[1] = *p_iphc;
+ memcpy(p_iphdr->destaddr.u8 + 11, p_iphc + 1, 5);
+ p_iphc += 6;
+ break;
+
+ case IPHC_DAM_10:
+ // 32 bits in-line.
+ p_iphdr->destaddr.u8[0] = 0xFF;
+ p_iphdr->destaddr.u8[1] = *p_iphc;
+ memcpy(p_iphdr->destaddr.u8 + 13, p_iphc + 1, 3);
+ p_iphc += 4;
+ break;
+
+ case IPHC_DAM_11:
+ // 8 bits in-line.
+ p_iphdr->destaddr.u8[0] = 0xFF;
+ p_iphdr->destaddr.u8[1] = 0x02;
+ p_iphdr->destaddr.u8[15] = *p_iphc;
+ p_iphc += 1;
+ break;
+ }
+ }
+ else
+ {
+ switch ((p_input[1] & IPHC_DAM_MASK) >> IPHC_DAM_POS)
+ {
+ case IPHC_DAM_00:
+ // 128 bits in-line.
+ memcpy(p_iphdr->destaddr.u8, p_iphc, IPV6_ADDR_SIZE);
+ p_iphc += IPV6_ADDR_SIZE;
+ break;
+
+ case IPHC_DAM_01:
+ // 64 bits in-line, first IID then prefix in case prefix > 64.
+ memcpy(p_iphdr->destaddr.u8, m_link_local_prefix, 2);
+ memcpy(p_iphdr->destaddr.u8 + 8, p_iphc, 8);
+ p_iphc += 8;
+ break;
+
+ case IPHC_DAM_10:
+ // 16 bits in-line.
+ memcpy(p_iphdr->destaddr.u8, m_link_local_prefix, 2);
+ memcpy(p_iphdr->destaddr.u8 + 11, m_link_local_16_middle, 2);
+ memcpy(p_iphdr->destaddr.u8 + 14, p_iphc, 2);
+ p_iphc += 2;
+ break;
+
+ case IPHC_DAM_11:
+ // Take the address from lower layer.
+ memcpy(p_iphdr->destaddr.u8, m_link_local_prefix, 2);
+ memcpy(p_iphdr->destaddr.u8 + 8, p_interface->local_addr.identifier, 8);
+ p_iphdr->destaddr.u8[8] ^= IPV6_IID_FLIP_VALUE;
+ break;
+ }
+ }
+ }
+
+ // Perform next header compression.
+ if (((p_input[0] & IPHC_NH_MASK) >> IPHC_NH_POS))
+ {
+ p_iphc += iphc_nhc_decode(p_iphc, p_output, &nhc_length);
+
+ if (nhc_length == 0)
+ {
+ // Unknown NHC field.
+ BLE_6LOWPAN_ERR("IPHC contains unsupported NHC header!");
+
+ return NRF_ERROR_INVALID_DATA;
+ }
+ }
+
+ // Calculate IPv6 Header Length.
+ p_iphdr->length = input_len - (p_iphc - p_input);
+
+ // Check if IPHC contains more bytes than whole packet.
+ if (p_iphdr->length > input_len)
+ {
+ // We cannot decompress it.
+ BLE_6LOWPAN_ERR("IPHC contains more bytes than expected!");
+
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Copy the data.
+ memcpy(p_output + IPV6_IP_HEADER_SIZE + nhc_length, p_iphc, p_iphdr->length);
+
+ // Add uncompressed headers length if any.
+ p_iphdr->length += nhc_length;
+
+ // Return length of whole IPv6 packet.
+ *p_output_len = p_iphdr->length + IPV6_IP_HEADER_SIZE;
+
+ // Keep proper endianness.
+ p_iphdr->length = HTONS(p_iphdr->length);
+
+ // Restore UDP length if compression was used.
+ if ( p_iphdr->next_header == IPV6_NEXT_HEADER_UDP )
+ {
+ memcpy(&p_udphdr->length, &p_iphdr->length, 2);
+ }
+
+ return retval;
+}
+
+
+/**@brief Function for encoding IPHC (IP Header Compression) defined in
+ * IETF RFC 6282. Instead of having separate buffer for compression,
+ * needed compression is performed on the IPv6 packet and buffer holding
+ * the packet is reused to overwrite the headers compressed.
+ *
+ * @param[in] p_interface IoT interface where packet must be sent.
+ * @param[in] p_input Pointer to full IPv6 packet.
+ * @param[in] input_len Length of IPv6 packet.
+ * @param[out] p_output Pointer to place of start IPHC packet.
+ * @param[out] p_output_len Length of compressed packet.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t iphc_encode(const iot_interface_t * p_interface,
+ uint8_t ** p_output,
+ uint16_t * p_output_len,
+ const uint8_t * p_input,
+ uint16_t input_len)
+{
+ // Create a buffer with maximum of IPHC value.
+ uint32_t err_code;
+ uint8_t iphc_buff[IPV6_IP_HEADER_SIZE + UDP_HEADER_SIZE];
+ uint8_t traffic_class;
+ uint8_t * p_iphc = &iphc_buff[2];
+ uint16_t iphc_len = 0;
+ uint16_t nhc_length = 0;
+ iot_context_t * p_ctx = NULL;
+ uint8_t sci = p_interface->tx_contexts.src_cntxt_id;
+ uint8_t dci = p_interface->tx_contexts.dest_cntxt_id;
+ bool sci_cover = false;
+ bool dci_cover = false;
+
+ // IPv6 header.
+ ipv6_header_t * p_iphdr = (ipv6_header_t *)p_input;
+
+ *p_iphc = 0;
+
+ // Set IPHC dispatch.
+ iphc_buff[0] = IPHC_START_DISPATCH << IPHC_START_DISPATCH_POS;
+
+ // Check if address can be compressed using context identifier.
+ if (sci == IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+ err_code = iot_context_manager_get_by_addr(p_interface, &p_iphdr->srcaddr, &p_ctx);
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ if (err_code == NRF_SUCCESS)
+ {
+ sci_cover = is_context_cover_iid(&p_iphdr->srcaddr, p_ctx, &p_interface->local_addr);
+ sci = p_ctx->context_id;
+ }
+ }
+
+ if (dci == IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+ err_code = iot_context_manager_get_by_addr(p_interface, &p_iphdr->destaddr, &p_ctx);
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ if (err_code == NRF_SUCCESS)
+ {
+ dci_cover = is_context_cover_iid(&p_iphdr->destaddr, p_ctx, &p_interface->peer_addr);
+ dci = p_ctx->context_id;
+ }
+ }
+
+ if (((sci != IPV6_CONTEXT_IDENTIFIER_NONE) || dci != IPV6_CONTEXT_IDENTIFIER_NONE))
+ {
+ iphc_buff[1] = (IPHC_CID_1 << IPHC_CID_POS);
+
+ // Add Source Context if exists.
+ if (sci != IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ *p_iphc |= (sci << 4);
+ }
+
+ // Add Destination Context if exists.
+ if (dci != IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ *p_iphc |= dci;
+ }
+
+ p_iphc += 1;
+ }
+ else
+ {
+ // Unset Context Identifier bit.
+ iphc_buff[1] = (IPHC_CID_0 << IPHC_CID_POS);
+ }
+
+ // Change ECN with DSCP in Traffic Class.
+ traffic_class = (p_iphdr->version_traffic_class & 0x0f) << 4;
+ traffic_class |= ((p_iphdr->traffic_class_flowlabel & 0xf0) >> 4);
+ traffic_class = (((traffic_class & 0x03) << 6) | (traffic_class >> 2));
+
+ if ((p_iphdr->flowlabel == 0) && ((p_iphdr->traffic_class_flowlabel & 0x0f) == 0))
+ {
+ if (traffic_class == 0)
+ {
+ // Elide Flow Label and Traffic Class.
+ iphc_buff[0] |= (IPHC_TF_11 << IPHC_TF_POS);
+ }
+ else
+ {
+ // Elide Flow Label and carry Traffic Class in-line.
+ iphc_buff[0] |= (IPHC_TF_10 << IPHC_TF_POS);
+
+ *p_iphc++ = traffic_class;
+ }
+ }
+ else
+ {
+ if (traffic_class & IPHC_TF_DSCP_MASK)
+ {
+ // Carry Flow Label and Traffic Class in-line.
+ iphc_buff[0] |= (IPHC_TF_00 << IPHC_TF_POS);
+
+ *p_iphc++ = traffic_class;
+ *p_iphc++ = (p_iphdr->traffic_class_flowlabel & 0x0f);
+ memcpy(p_iphc, &p_iphdr->flowlabel, 2);
+ p_iphc += 2;
+ }
+ else
+ {
+ // Carry Flow Label and ECN only with 2-bit padding.
+ iphc_buff[0] |= (IPHC_TF_01 << IPHC_TF_POS);
+
+ *p_iphc++ =
+ ((traffic_class & IPHC_TF_ECN_MASK) | (p_iphdr->traffic_class_flowlabel & 0x0f));
+ memcpy(p_iphc, &p_iphdr->flowlabel, 2);
+ p_iphc += 2;
+ }
+ }
+
+ // Checks if next header is compressed.
+ if (iphc_nhc_compressable(p_iphdr->next_header))
+ {
+ iphc_buff[0] |= (IPHC_NH_1 << IPHC_NH_POS);
+ }
+ else
+ {
+ iphc_buff[0] |= (IPHC_NH_0 << IPHC_NH_POS);
+ *p_iphc++ = p_iphdr->next_header;
+ }
+
+ // Hop limit compression.
+ switch (p_iphdr->hoplimit)
+ {
+ case 1:
+ iphc_buff[0] |= (IPHC_HLIM_01 << IPHC_HLIM_POS);
+ break;
+
+ case 64:
+ iphc_buff[0] |= (IPHC_HLIM_10 << IPHC_HLIM_POS);
+ break;
+
+ case 255:
+ iphc_buff[0] |= (IPHC_HLIM_11 << IPHC_HLIM_POS);
+ break;
+
+ default:
+ // Carry Hop Limit in-line.
+ iphc_buff[0] |= (IPHC_HLIM_00 << IPHC_HLIM_POS);
+ *p_iphc++ = p_iphdr->hoplimit;
+ break;
+ }
+
+ // Source address compression.
+ if (IPV6_ADDRESS_IS_UNSPECIFIED(&p_iphdr->srcaddr))
+ {
+ iphc_buff[1] |= (IPHC_SAC_1 << IPHC_SAC_POS);
+ iphc_buff[1] |= (IPHC_SAM_00 << IPHC_SAM_POS);
+ }
+ else if (sci != IPV6_CONTEXT_IDENTIFIER_NONE || IPV6_ADDRESS_IS_LINK_LOCAL(&p_iphdr->srcaddr))
+ {
+ if (sci != IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ // Set stateful source address compression.
+ iphc_buff[1] |= (IPHC_SAC_1 << IPHC_SAC_POS);
+ }
+
+ if (IPV6_ADDRESS_IS_FULLY_ELIDABLE(p_interface->local_addr.identifier,
+ &p_iphdr->srcaddr)
+ ||
+ sci_cover == true)
+ {
+ iphc_buff[1] |= (IPHC_SAM_11 << IPHC_SAM_POS);
+ }
+ else if (IPV6_ADDRESS_IS_16_BIT_COMPRESSABLE(&p_iphdr->srcaddr))
+ {
+ iphc_buff[1] |= (IPHC_SAM_10 << IPHC_SAM_POS);
+ memcpy(p_iphc, &p_iphdr->srcaddr.u8[14], 2);
+ p_iphc += 2;
+ }
+ else
+ {
+ iphc_buff[1] |= (IPHC_SAM_01 << IPHC_SAM_POS);
+ memcpy(p_iphc, &p_iphdr->srcaddr.u8[8], 8);
+ p_iphc += 8;
+ }
+ }
+ else
+ {
+ // Carry full source address in-line.
+ iphc_buff[1] |= (IPHC_SAC_0 << IPHC_SAC_POS);
+ iphc_buff[1] |= (IPHC_SAM_00 << IPHC_SAM_POS);
+ memcpy(p_iphc, p_iphdr->srcaddr.u8, IPV6_ADDR_SIZE);
+ p_iphc += IPV6_ADDR_SIZE;
+ }
+
+ // Destination compression.
+ if (IPV6_ADDRESS_IS_MULTICAST(&p_iphdr->destaddr))
+ {
+ iphc_buff[1] |= (IPHC_M_1 << IPHC_M_POS);
+
+ if (dci != IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ iphc_buff[1] |= (IPHC_DAC_1 << IPHC_DAC_POS);
+ iphc_buff[1] |= (IPHC_DAM_00 << IPHC_DAM_POS);
+
+ p_iphdr->destaddr.u8[0] = 0xff;
+ memcpy(p_iphc, &p_iphdr->destaddr.u8[1], 2);
+ memcpy(p_iphc + 2, &p_iphdr->destaddr.u8[12], 4);
+ p_iphc += 6;
+ }
+ else if (IPV6_ADDRESS_IS_8_BIT_MCAST_COMPRESSABLE(&p_iphdr->destaddr))
+ {
+ iphc_buff[1] |= (IPHC_DAC_0 << IPHC_DAC_POS);
+ iphc_buff[1] |= (IPHC_DAM_11 << IPHC_DAM_POS);
+ *p_iphc++ = p_iphdr->destaddr.u8[15];
+
+ }
+ else if (IPV6_ADDRESS_IS_32_BIT_MCAST_COMPRESSABLE(&p_iphdr->destaddr))
+ {
+ iphc_buff[1] |= (IPHC_DAC_0 << IPHC_DAC_POS);
+ iphc_buff[1] |= (IPHC_DAM_10 << IPHC_DAM_POS);
+
+ *p_iphc = p_iphdr->destaddr.u8[1];
+ memcpy(p_iphc + 1, &p_iphdr->destaddr.u8[13], 3);
+ p_iphc += 4;
+ }
+ else if (IPV6_ADDRESS_IS_48_BIT_MCAST_COMPRESSABLE(&p_iphdr->destaddr))
+ {
+ iphc_buff[1] |= (IPHC_DAC_0 << IPHC_DAC_POS);
+ iphc_buff[1] |= (IPHC_DAM_01 << IPHC_DAM_POS);
+
+ *p_iphc = p_iphdr->destaddr.u8[1];
+ memcpy(p_iphc + 1, &p_iphdr->destaddr.u8[11], 5);
+ p_iphc += 6;
+ }
+ else
+ {
+ // Carry full destination multi-cast address in-line.
+ iphc_buff[1] |= (IPHC_DAC_0 << IPHC_DAC_POS);
+ iphc_buff[1] |= (IPHC_DAM_00 << IPHC_DAM_POS);
+ memcpy(p_iphc, p_iphdr->destaddr.u8, IPV6_ADDR_SIZE);
+ p_iphc += IPV6_ADDR_SIZE;
+ }
+ }
+ else
+ {
+ iphc_buff[1] |= (IPHC_M_0 << IPHC_M_POS);
+
+ if (dci != IPV6_CONTEXT_IDENTIFIER_NONE || IPV6_ADDRESS_IS_LINK_LOCAL(&p_iphdr->destaddr))
+ {
+ if (dci != IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ iphc_buff[1] |= (IPHC_DAC_1 << IPHC_DAC_POS);
+ }
+
+ if (IPV6_ADDRESS_IS_FULLY_ELIDABLE(p_interface->peer_addr.identifier,
+ &p_iphdr->destaddr)
+ ||
+ dci_cover == true)
+ {
+ iphc_buff[1] |= (IPHC_DAM_11 << IPHC_DAM_POS);
+ }
+ else if (IPV6_ADDRESS_IS_16_BIT_COMPRESSABLE(&p_iphdr->destaddr))
+ {
+ iphc_buff[1] |= (IPHC_DAM_10 << IPHC_DAM_POS);
+ memcpy(p_iphc, &p_iphdr->destaddr.u8[14], 2);
+ p_iphc += 2;
+ }
+ else
+ {
+ iphc_buff[1] |= (IPHC_DAM_01 << IPHC_DAM_POS);
+ memcpy(p_iphc, &p_iphdr->destaddr.u8[8], 8);
+ p_iphc += 8;
+ }
+ }
+ else
+ {
+ // Carry full destination address in-line.
+ iphc_buff[1] |= (IPHC_DAC_0 << IPHC_DAC_POS);
+ iphc_buff[1] |= (IPHC_DAM_00 << IPHC_DAM_POS);
+ memcpy(p_iphc, p_iphdr->destaddr.u8, IPV6_ADDR_SIZE);
+ p_iphc += IPV6_ADDR_SIZE;
+ }
+ }
+
+ if ( iphc_buff[0] & IPHC_NH_MASK)
+ {
+ p_iphc += iphc_nhc_encode(p_iphc, p_input, &nhc_length);
+ }
+
+ // Calculate IPHC size.
+ iphc_len = (p_iphc - iphc_buff);
+
+ // Calculate IPv6 packet size.
+ *p_output_len = input_len - (IPV6_IP_HEADER_SIZE - iphc_len + nhc_length);
+
+ // Use p_data as final buffer (since IPHC+NHC <= IPv6 Header + NHC (UDP)).
+ memcpy((uint8_t *)&p_input[IPV6_IP_HEADER_SIZE + nhc_length - iphc_len], iphc_buff, iphc_len);
+
+ // Set correct address of output data.
+ *p_output = (uint8_t *) &p_input[IPV6_IP_HEADER_SIZE + nhc_length - iphc_len];
+
+ return NRF_SUCCESS;
+}
+
+
+/******************************************************************************
+ * @name 6LoWPAN transport functions
+ *****************************************************************************/
+
+/**@brief Function for notifying application of an error in an ongoing procedure.
+ *
+ * @param[in] p_interface Pointer to 6LoWPAN interface.
+ * @param[in] err_code Internally error code.
+ *
+ * @return None.
+ */
+static void app_notify_error(iot_interface_t * p_interface,
+ uint32_t err_code)
+{
+ ble_6lowpan_event_t event;
+
+ event.event_id = BLE_6LO_EVT_ERROR;
+ event.event_result = err_code;
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+}
+
+
+/**@brief Function for notifying application of the new packet received.
+ *
+ * @param[in] p_interface Pointer to iot interface.
+ * @param[in] p_packet Pointer to decompressed IPv6 packet.
+ * @param[in] packet_len Length of IPv6 packet.
+ * @param[in] result Processing result of packet. Could be NRF_SUCCESS, or
+ * NRF_ERROR_NOT_FOUND if context identifier is unknown.
+ * @param[in] p_rx_contexts Received contexts if any.
+ *
+ * @return None.
+ */
+static void app_notify_rx_data(iot_interface_t * p_interface,
+ uint8_t * p_packet,
+ uint16_t packet_len,
+ uint32_t result,
+ iot_context_id_t * p_rx_contexts)
+{
+ ble_6lowpan_event_t event;
+
+ event.event_id = BLE_6LO_EVT_INTERFACE_DATA_RX;
+ event.event_result = result;
+ event.event_param.rx_event_param.p_packet = p_packet;
+ event.event_param.rx_event_param.packet_len = packet_len;
+ event.event_param.rx_event_param.rx_contexts = *(p_rx_contexts);
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+}
+
+
+/**@brief Function for notifying application of the new interface established.
+ *
+ * @param[in] p_interface Pointer to new iot interface.
+ *
+ * @return None.
+ */
+static void app_notify_interface_add(iot_interface_t * p_interface)
+{
+ ble_6lowpan_event_t event;
+
+ event.event_id = BLE_6LO_EVT_INTERFACE_ADD;
+ event.event_result = NRF_SUCCESS;
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+}
+
+
+/**@brief Function for notifying application of the interface disconnection.
+ *
+ * @param[in] p_interface Pointer to removed iot interface.
+ *
+ * @return None.
+ */
+static void app_notify_interface_delete(iot_interface_t * p_interface)
+{
+ ble_6lowpan_event_t event;
+
+ event.event_id = BLE_6LO_EVT_INTERFACE_DELETE;
+ event.event_result = NRF_SUCCESS;
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ m_event_handler(p_interface, &event);
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+}
+
+
+/**@brief Function for initialize transmit FIFO.
+ *
+ * @param[in] p_fifo Pointer to transmit FIFO instance.
+ *
+ * @return None.
+ */
+static void tx_fifo_init(tx_fifo_t * p_fifo)
+{
+ memset(p_fifo->packets, 0, BLE_6LOWPAN_TX_FIFO_SIZE * sizeof (tx_packet_t));
+ p_fifo->read_pos = 0;
+ p_fifo->write_pos = 0;
+}
+
+
+/**@brief Function for putting new packet to transmit FIFO.
+ *
+ * @param[in] p_fifo Pointer to transmit FIFO instance.
+ * @param[in] p_packet Pointer to new packet.
+ *
+ * @return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
+ */
+static uint32_t tx_fifo_put(tx_fifo_t * p_fifo, tx_packet_t * p_packet)
+{
+ uint32_t err_code = BLE_6LOWPAN_TX_FIFO_FULL;
+
+ // To prevent "The order of volatile accesses is undefined in this statement"
+ // in subsequent conditional statement.
+ uint32_t write_pos = p_fifo->write_pos;
+ uint32_t read_pos = p_fifo->read_pos;
+
+ if ((write_pos - read_pos) <= TX_FIFO_MASK)
+ {
+ p_fifo->packets[p_fifo->write_pos & TX_FIFO_MASK].p_data = p_packet->p_data;
+ p_fifo->packets[p_fifo->write_pos & TX_FIFO_MASK].data_len = p_packet->data_len;
+ p_fifo->packets[p_fifo->write_pos & TX_FIFO_MASK].p_mem_block = p_packet->p_mem_block;
+
+ p_fifo->write_pos++;
+
+ err_code = NRF_SUCCESS;
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for popping currently processed packet in transmit FIFO.
+ * It releases element on FIFO only when processing of the element is done.
+ *
+ * @param[in] p_fifo Pointer to transmit FIFO instance.
+ *
+ * @return None.
+ */
+static void tx_fifo_release(tx_fifo_t * p_fifo)
+{
+ p_fifo->read_pos++;
+}
+
+
+/**@brief Function for reading front element of transmit FIFO.
+ * After finish processing element in queue, it must be
+ * released using tx_fifo_release function.
+ *
+ * @param[in] p_fifo Pointer to transmit FIFO instance.
+ * @param[in] pp_packet Pointer to front packet.
+ *
+ * @return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
+ */
+static uint32_t tx_fifo_get(tx_fifo_t * p_fifo, tx_packet_t * * pp_packet)
+{
+ uint32_t err_code = NRF_ERROR_NOT_FOUND;
+
+ // To prevent "The order of volatile accesses is undefined in this statement"
+ // in subsequent conditional statement.
+ uint32_t write_pos = p_fifo->write_pos;
+ uint32_t read_pos = p_fifo->read_pos;
+
+ if ((write_pos - read_pos) != 0)
+ {
+ *pp_packet = &p_fifo->packets[p_fifo->read_pos & TX_FIFO_MASK];
+ err_code = NRF_SUCCESS;
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for searching transport interface by given IPSP handle.
+ *
+ * @param[in] p_ipsp_handle Pointer to IPSP handle.
+ *
+ * @return Transport interface related with IPSP handle, or NULL if not found.
+ */
+static transport_instance_t * interface_get_by_handle(const ble_ipsp_handle_t * p_ipsp_handle)
+{
+ uint32_t index;
+
+ for (index = 0; index < BLE_6LOWPAN_MAX_INTERFACE; index++)
+ {
+ if (m_instances[index].handle.cid == p_ipsp_handle->cid &&
+ m_instances[index].handle.conn_handle == p_ipsp_handle->conn_handle)
+ {
+ return &m_instances[index];
+ }
+ }
+
+ return NULL;
+}
+
+
+/**@brief Function for initializing transport instance.
+ *
+ * @param[in] index Index of instance.
+ *
+ * @return None.
+ */
+static void instance_init(uint32_t index)
+{
+ memset(&m_instances[index], 0, sizeof (transport_instance_t));
+ m_instances[index].handle.cid = BLE_L2CAP_CID_INVALID;
+ m_instances[index].p_tx_cur_packet = NULL;
+ m_instances[index].interface.p_transport = (void *) index;
+}
+
+
+/**@brief Function for resetting specific 6lowpan interface.
+ *
+ * @param[in] p_interface Pointer to transport interface.
+ *
+ * @return None.
+ */
+static void interface_reset(transport_instance_t * p_instance)
+{
+ uint32_t index;
+ uint32_t instance_id = (uint32_t) p_instance->interface.p_transport;
+
+ // Free all queued packets.
+ for (index = 0; index < BLE_6LOWPAN_TX_FIFO_SIZE; index++)
+ {
+ if (m_instances[instance_id].tx_fifo.packets[index].p_mem_block != NULL)
+ {
+ nrf_free(m_instances[instance_id].tx_fifo.packets[index].p_mem_block);
+ }
+ }
+
+ instance_init (instance_id);
+}
+
+
+/**@brief Function for adding new transport instance.
+ *
+ * @param[in] p_peer_addr Pointer EUI-64 of peer address.
+ * @param[in] p_ipsp_handle Pointer IPSP handle, related with L2CAP CoC channel.
+ * @param[out] pp_instance Pointer to added transport instances, if operation succeeded.
+ *
+ * @return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
+ */
+static uint32_t interface_add(const eui64_t * p_peer_addr,
+ const ble_ipsp_handle_t * p_ipsp_handle,
+ transport_instance_t ** pp_instance)
+{
+ uint32_t index;
+
+ for (index = 0; index < BLE_6LOWPAN_MAX_INTERFACE; index++)
+ {
+ if (m_instances[index].handle.cid == BLE_L2CAP_CID_INVALID)
+ {
+ m_instances[index].handle.cid = p_ipsp_handle->cid;
+ m_instances[index].handle.conn_handle = p_ipsp_handle->conn_handle;
+ m_instances[index].interface.tx_contexts.src_cntxt_id = IPV6_CONTEXT_IDENTIFIER_NONE;
+ m_instances[index].interface.tx_contexts.dest_cntxt_id = IPV6_CONTEXT_IDENTIFIER_NONE;
+
+ memcpy(&m_instances[index].interface.peer_addr, p_peer_addr, sizeof (eui64_t));
+ memcpy(&m_instances[index].interface.local_addr, &m_ll_addr, sizeof (eui64_t));
+
+ // Initialize TX FIFO.
+ tx_fifo_init(&m_instances[index].tx_fifo);
+
+ *pp_instance = &m_instances[index];
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NO_MEM;
+}
+
+
+/**@brief Function for checking if any transmission is currently processing on specific interface.
+ * Current version of L2CAP CoC in SoftDevice has limitation to send one packet at same
+ * time.
+ *
+ * @param[in] p_instance Pointer to transport instance.
+ *
+ * @return TRUE if interface not sending any packets, FALSE if busy.
+ */
+static bool tx_is_free(transport_instance_t * p_instance)
+{
+ return (NULL == p_instance->p_tx_cur_packet);
+}
+
+
+/**@brief Function uses for indicating transmission complete on specific interface.
+ *
+ * @param[in] p_instance Pointer to transport instance.
+ *
+ * @return None.
+ */
+static void tx_complete(transport_instance_t * p_instance)
+{
+ BLE_6LOWPAN_TRC("[CID 0x%04X]: Transmission complete.",
+ p_instance->handle.cid);
+
+ // Free the transmit buffer.
+ nrf_free(p_instance->p_tx_cur_packet->p_mem_block);
+ p_instance->p_tx_cur_packet = NULL;
+
+ // Release last processed packet.
+ tx_fifo_release(&p_instance->tx_fifo);
+}
+
+
+/**@brief Function for sending front packet from transmit FIFO on specific interface.
+ *
+ * @param[in] p_instance Pointer to transport instance.
+ *
+ * @return None.
+ */
+static void tx_send(transport_instance_t * p_instance)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (NRF_SUCCESS == tx_fifo_get(&p_instance->tx_fifo,
+ &p_instance->p_tx_cur_packet))
+ {
+ err_code = ble_ipsp_send(&p_instance->handle,
+ p_instance->p_tx_cur_packet->p_data,
+ p_instance->p_tx_cur_packet->data_len);
+
+ if (NRF_SUCCESS != err_code)
+ {
+ BLE_6LOWPAN_TRC("Cannot send the packet, error = 0x%08lX", err_code);
+
+ app_notify_error(&p_instance->interface, err_code);
+
+ tx_complete(p_instance);
+
+ // Try to send another packet.
+ tx_send(p_instance);
+ }
+ }
+}
+
+/**@brief Callback registered with IPSP to receive asynchronous events from the module.
+ *
+ * @param[in] p_handle Pointer to IPSP handle.
+ * @param[in] p_evt Pointer to specific event, generated by IPSP module.
+ *
+ * @return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
+ */
+static uint32_t ipsp_evt_handler(ble_ipsp_handle_t const * p_handle, ble_ipsp_evt_t const * p_evt)
+{
+ BLE_6LOWPAN_ENTRY();
+
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ uint32_t mem_size;
+ uint16_t buff_len;
+ eui64_t peer_addr;
+ iot_context_id_t rx_contexts;
+ uint32_t retval = NRF_SUCCESS;
+ transport_instance_t * p_instance = NULL;
+ uint8_t * p_buff = NULL;
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ p_instance = interface_get_by_handle(p_handle);
+
+ switch (p_evt->evt_id)
+ {
+ case BLE_IPSP_EVT_CHANNEL_CONNECTED:
+ {
+ BLE_6LOWPAN_TRC("[CID 0x%04X]: >> BLE_IPSP_EVT_CHANNEL_CONNECTED",
+ p_handle->cid);
+ BLE_6LOWPAN_TRC("New channel established.");
+
+ if (p_instance == NULL)
+ {
+ IPV6_EUI64_CREATE_FROM_EUI48(peer_addr.identifier,
+ p_evt->p_evt_param->p_peer->addr,
+ p_evt->p_evt_param->p_peer->addr_type);
+
+ // Add interface to internal table.
+ retval = interface_add(&peer_addr, p_handle, &p_instance);
+
+ if (NRF_SUCCESS == retval)
+ {
+ BLE_6LOWPAN_TRC("Added new IPSP interface.");
+
+ // Notify application.
+ app_notify_interface_add(&p_instance->interface);
+ }
+ else
+ {
+ BLE_6LOWPAN_ERR("Cannot add new interface. Table is full.");
+ UNUSED_VARIABLE(ble_ipsp_disconnect(p_handle));
+ }
+ }
+ else
+ {
+ // Got a connection event, when already connected.
+ UNUSED_VARIABLE(ble_ipsp_disconnect(p_handle));
+ }
+
+ break;
+ }
+
+ case BLE_IPSP_EVT_CHANNEL_DISCONNECTED:
+ {
+ BLE_6LOWPAN_TRC("[CID 0x%04X]: >> BLE_IPSP_EVT_CHANNEL_DISCONNECTED",
+ p_handle->cid);
+ BLE_6LOWPAN_TRC("Channel disconnection.");
+
+ if (NULL != p_instance)
+ {
+ BLE_6LOWPAN_TRC("Removed IPSP interface.");
+
+ // Notify application.
+ app_notify_interface_delete(&p_instance->interface);
+
+ // Remove interface from internal table.
+ interface_reset(p_instance);
+ }
+
+ break;
+ }
+
+ case BLE_IPSP_EVT_CHANNEL_DATA_RX:
+ {
+
+ if (NULL != p_instance)
+ {
+ const uint16_t packet_len = MIN(p_evt->p_evt_param->p_l2cap_evt->params.rx.sdu_buf.len,
+ p_evt->p_evt_param->p_l2cap_evt->params.rx.sdu_len);
+
+ BLE_6LOWPAN_TRC("[CID 0x%04X]: >> BLE_IPSP_EVT_CHANNEL_DATA_RX",
+ p_handle->cid);
+
+ BLE_6LOWPAN_DUMP(p_evt->p_evt_param->p_l2cap_evt->params.rx.sdu_buf.p_data,
+ packet_len);
+
+ BLE_6LOWPAN_TRC("Processing received data.");
+
+ mem_size = packet_len + IPHC_MAX_COMPRESSED_DIFF;
+
+ // Try to allocate memory for incoming data.
+ retval = nrf_mem_reserve(&p_buff, &mem_size);
+
+ if (retval == NRF_SUCCESS)
+ {
+ // Decompress IPHC data into IPv6 packet.
+ retval = iphc_decode(&p_instance->interface,
+ p_buff,
+ &buff_len,
+ p_evt->p_evt_param->p_l2cap_evt->params.rx.sdu_buf.p_data,
+ packet_len,
+ &rx_contexts);
+
+ // Do not discard if packet decompressed successfully,
+ // otherwise error in Context based decompression.
+ if (retval == NRF_SUCCESS || retval == BLE_6LOWPAN_CID_NOT_FOUND)
+ {
+ if ((p_evt->evt_result == NRF_ERROR_BLE_IPSP_RX_PKT_TRUNCATED) &&
+ (retval == NRF_SUCCESS))
+ {
+ // Inform the application that the packet is truncated.
+ retval = NRF_ERROR_BLE_IPSP_RX_PKT_TRUNCATED;
+ }
+
+ BLE_6LOWPAN_TRC("Decompressed packet:");
+ BLE_6LOWPAN_DUMP(p_buff, buff_len);
+
+ // Notify application.
+ app_notify_rx_data(&p_instance->interface,
+ p_buff,
+ buff_len,
+ retval,
+ &rx_contexts);
+ }
+ else
+ {
+ BLE_6LOWPAN_ERR("Decompression failed!");
+
+ nrf_free(p_buff);
+ }
+ }
+ else
+ {
+ BLE_6LOWPAN_ERR(
+ "No buffer in memory pool available, packet dropped!");
+ }
+ }
+ else
+ {
+ BLE_6LOWPAN_ERR("Got data to unknown interface!");
+ }
+
+ break;
+ }
+
+ case BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE:
+ {
+ BLE_6LOWPAN_TRC("[CID 0x%04X]: >> BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE",
+ p_handle->cid);
+
+ // Free TX buffer.
+ tx_complete(p_instance);
+
+ // Try to send another packet.
+ tx_send(p_instance);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ BLE_6LOWPAN_EXIT();
+
+ return retval;
+}
+
+/******************************************************************************
+ * @name 6LoWPAN API functions
+ *****************************************************************************/
+
+uint32_t ble_6lowpan_init(const ble_6lowpan_init_t * p_init)
+{
+ BLE_6LOWPAN_ENTRY();
+
+ uint32_t index;
+ uint32_t retval = NRF_SUCCESS;
+ ble_ipsp_init_t ipsp_init_params;
+
+ NULL_PARAM_CHECK(p_init);
+ NULL_PARAM_CHECK(p_init->p_eui64);
+ NULL_PARAM_CHECK(p_init->event_handler);
+
+ // Check if the transmit FIFO size is a power of two.
+ if (!IS_POWER_OF_TWO(BLE_6LOWPAN_TX_FIFO_SIZE))
+ {
+ return NRF_ERROR_INVALID_LENGTH | BLE_6LOWPAN_ERR_BASE;
+ }
+
+ SDK_MUTEX_INIT(m_6lowpan_mutex);
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ // Store EUI64 in internal variable.
+ memcpy(m_ll_addr.identifier, p_init->p_eui64->identifier, EUI_64_ADDR_SIZE);
+
+ // Set application event handler.
+ m_event_handler = p_init->event_handler;
+
+ // Clear transport interfaces table.
+ for (index = 0; index < BLE_6LOWPAN_MAX_INTERFACE; index++)
+ {
+ instance_init(index);
+ }
+
+ // IPSP module initialization.
+ ipsp_init_params.evt_handler = ipsp_evt_handler;
+
+ // Initialize the IPSP module.
+ retval = ble_ipsp_init(&ipsp_init_params);
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ BLE_6LOWPAN_EXIT();
+
+ return retval;
+}
+
+
+uint32_t ble_6lowpan_interface_disconnect(const iot_interface_t * p_interface)
+{
+ BLE_6LOWPAN_ENTRY();
+
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t retval;
+ transport_instance_t * p_instance = &m_instances[(uint32_t)p_interface->p_transport];
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ retval = ble_ipsp_disconnect(&p_instance->handle);
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ BLE_6LOWPAN_EXIT();
+
+ return retval;
+}
+
+
+uint32_t ble_6lowpan_interface_send(const iot_interface_t * p_interface,
+ const uint8_t * p_packet,
+ uint16_t packet_len)
+{
+ BLE_6LOWPAN_ENTRY();
+
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_packet);
+ NULL_PARAM_CHECK(p_interface);
+ PACKET_LENGTH_CHECK(packet_len);
+
+ uint32_t retval = NRF_SUCCESS;
+ uint8_t * p_output_buff = NULL;
+ uint16_t output_len;
+ tx_packet_t tx_packet;
+ transport_instance_t * p_instance = &m_instances[(uint32_t)p_interface->p_transport];
+
+ BLE_6LOWPAN_MUTEX_LOCK();
+
+ BLE_6LOWPAN_TRC("Uncompressed packet:");
+ BLE_6LOWPAN_DUMP((uint8_t *)p_packet, packet_len);
+
+ // Encode IP packet into IPHC.
+ retval = iphc_encode(p_interface,
+ &p_output_buff,
+ &output_len,
+ p_packet,
+ packet_len);
+
+ if (NRF_SUCCESS == retval)
+ {
+ BLE_6LOWPAN_TRC("Successfully compressed packet.");
+
+ tx_packet.p_data = p_output_buff;
+ tx_packet.data_len = output_len;
+ tx_packet.p_mem_block = (uint8_t *)p_packet;
+
+ retval = tx_fifo_put(&p_instance->tx_fifo, &tx_packet);
+
+ if (NRF_SUCCESS == retval)
+ {
+ BLE_6LOWPAN_TRC("Compressed packet:");
+ BLE_6LOWPAN_DUMP(p_output_buff, output_len);
+
+ // Send packet immediately if transport interface is not busy.
+ if (tx_is_free(p_instance))
+ {
+ tx_send(p_instance);
+ }
+ }
+ else
+ {
+ BLE_6LOWPAN_ERR("No place in TX queue!");
+ }
+ }
+ else
+ {
+ BLE_6LOWPAN_ERR("Error while compression!");
+ }
+
+ BLE_6LOWPAN_MUTEX_UNLOCK();
+
+ BLE_6LOWPAN_EXIT();
+
+ return retval;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.h
new file mode 100644
index 0000000..267ff30
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ble_6lowpan/ble_6lowpan.h
@@ -0,0 +1,168 @@
+/**
+ * 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.
+ *
+ */
+/** @file ble_6lowpan.h
+ *
+ * @defgroup ble_6lowpan BLE 6LoWPAN library
+ * @ingroup iot_sdk_6lowpan
+ * @{
+ * @brief 6LoWPAN techniques defined for BLE.
+ *
+ * @details This module implements 6LoWPAN techniques defined for BLE, including
+ * IP and UDP header compression and decompression and conversion of EUI-48 BLE
+ * addresses to EUI-64 and on to IPv6 addresses. This layer does not implement IP level
+ * functionality of neighbor discovery etc.
+ * @note Currently, only the 6LoWPAN node (host) role is supported.
+ */
+
+#ifndef BLE_6LOWPAN_H__
+#define BLE_6LOWPAN_H__
+
+#include <stdint.h>
+#include "iot_defines.h"
+#include "iot_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Maximum 6LoWPAN interface supported by module. */
+#define BLE_6LOWPAN_MAX_INTERFACE 1
+
+/**@brief Maximum transmit packets that are buffered per interface.
+ *
+ * @details FIFO size must be a power of 2.
+ */
+#define BLE_6LOWPAN_TX_FIFO_SIZE 16
+
+/**@brief Asynchronous event identifiers type. */
+typedef enum
+{
+ BLE_6LO_EVT_ERROR, /**< Notification of an error in the module. */
+ BLE_6LO_EVT_INTERFACE_ADD, /**< Notification of a new 6LoWPAN interface added. */
+ BLE_6LO_EVT_INTERFACE_DELETE, /**< Notification of a 6LoWPAN interface deleted. */
+ BLE_6LO_EVT_INTERFACE_DATA_RX, /**< Notification of an IP packet received on the interface. */
+} ble_6lowpan_event_id_t;
+
+/**@brief Event parameters associated with the BLE_6LO_EVT_INTERFACE_DATA_RX event. */
+typedef struct
+{
+ uint8_t * p_packet; /**< Uncompressed IPv6 packet received. This memory is available to the application until it is freed by the application using mem_free. */
+ uint16_t packet_len; /**< Length of IPv6 packet. */
+ iot_context_id_t rx_contexts; /**< RX contexts used in stateful decompression. IPV6_CONTEXT_IDENTIFIER_NONE if not used. */
+} ble_6lowpan_data_rx_t;
+
+/**@brief Asynchronous event parameter type. */
+typedef union
+{
+ ble_6lowpan_data_rx_t rx_event_param; /**< Parameters notified with the received packet. */
+} ble_6lowpan_event_param_t;
+
+/**@brief Asynchronous event type. */
+typedef struct
+{
+ ble_6lowpan_event_id_t event_id; /**< Event identifier. */
+ ble_6lowpan_event_param_t event_param; /**< Event parameters. */
+ uint32_t event_result; /**< Result of event being notified. */
+} ble_6lowpan_event_t;
+
+/**@brief Asynchronous event notification callback type. */
+typedef void (*ble_6lowpan_evt_handler_t)(iot_interface_t * p_interface,
+ ble_6lowpan_event_t * p_event);
+
+
+/**@brief Initialization parameters type. */
+typedef struct
+{
+ eui64_t * p_eui64; /**< EUI-64 address. */
+ ble_6lowpan_evt_handler_t event_handler; /**< Asynchronous event notification callback registered to receive 6LoWPAN events. */
+} ble_6lowpan_init_t;
+
+
+/**@brief Initializes the module.
+ *
+ * @param[in] p_init Initialization parameters.
+ *
+ * @retval NRF_SUCCESS If initialization was successful. Otherwise, an error code is returned.
+ */
+uint32_t ble_6lowpan_init(const ble_6lowpan_init_t * p_init);
+
+
+/**@brief Disconnects 6LoWPAN interface.
+ *
+ * @details This function is used to terminate connection on the L2CAP CoC layer. It calls
+ * \ref ble_ipsp_disconnect to perform disconnection procedure. The registered callback
+ * from 6LoWPAN module propagates \ref BLE_6LO_EVT_INTERFACE_DELETE event after
+ * operation is finished.
+ *
+ * @param[in] p_interface Identifies the interface on which the disconnection has to be performed.
+ *
+ * @retval NRF_SUCCESS If disconnection was successful. Otherwise, an error code is returned.
+ */
+uint32_t ble_6lowpan_interface_disconnect(const iot_interface_t * p_interface);
+
+
+/**@brief Sends IPv6 packet on the 6LoWPAN interface.
+ *
+ * @details This function is used to send an IPv6 packet on the interface. 6LoWPAN compression
+ * techniques are applied on the packet before the packet is transmitted. The packet might
+ * not be transferred to the peer immediately based on the flow control on the BLE Link.
+ * In this case, the packet is queued to be transferred later.
+ *
+ * @param[in] p_interface Identifies the interface on which the packet is to be sent.
+ * @param[in] p_packet IPv6 packet to be sent. Memory for the packet should be allocated
+ * using mem_alloc and should not be freed. The module is responsible for
+ * freeing the memory using mem_free. The module will free the packet once
+ * the transmission is complete or the packet can no longer be transmitted
+ * (in case of link disconnection.)
+ * @param[in] packet_len Length of the IPv6 packet.
+ *
+ * @retval NRF_SUCCESS If the send request was successful.
+ */
+uint32_t ble_6lowpan_interface_send(const iot_interface_t * p_interface,
+ const uint8_t * p_packet,
+ uint16_t packet_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //BLE_6LOWPAN_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c
new file mode 100644
index 0000000..4d58384
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c
@@ -0,0 +1,854 @@
+/**
+ * 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 <stdbool.h>
+#include <string.h>
+#include "nordic_common.h"
+#include "nrf.h"
+#include "coap_api.h"
+#include "coap.h"
+#include "coap_queue.h"
+#include "coap_transport.h"
+#include "sdk_common.h"
+#include "iot_common.h"
+#include "mem_manager.h"
+#include "coap_resource.h"
+#include "coap_observe_api.h"
+#include "coap_observe.h"
+
+#if IOT_COAP_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME coap
+
+#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 COAP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define COAP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define COAP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define COAP_ENTRY() COAP_TRC(">> %s", __func__)
+#define COAP_EXIT() COAP_TRC("<< %s", __func__)
+#define COAP_EXIT_WITH_RESULT(result) COAP_TRC("<< %s, result: %d", __func__, result)
+
+#else // IOT_COAP_CONFIG_LOG_ENABLED
+
+#define COAP_TRC(...) /**< Disables traces. */
+#define COAP_DUMP(...) /**< Disables dumping of octet streams. */
+#define COAP_ERR(...) /**< Disables error logs. */
+
+#define COAP_ENTRY(...)
+#define COAP_EXIT(...)
+#define COAP_EXIT_WITH_RESULT(...)
+
+#endif // IOT_COAP_CONFIG_LOG_ENABLED
+
+#define COAP_REQUEST_ENTITY_MAX_SIZE (BLE_IPSP_RX_BUFFER_SIZE - (IPV6_IP_HEADER_SIZE + \
+ UDP_HEADER_SIZE)) /** Maximum request entity size. */
+
+SDK_MUTEX_DEFINE(m_coap_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+
+static uint32_t m_token_seed; /**< Token seed provided by application to be used for generating token numbers. */
+static uint32_t m_message_id_counter; /**< Message ID counter, used to generate unique message IDs. */
+static coap_error_callback_t m_error_callback; /**< Function pointer to an application CoAP error handler. */
+
+static coap_request_handler_t m_request_handler = NULL; /**< Request handler where to forward all incoming requests. */
+
+#define COAP_MESSAGE_ACK_SET(REMOTE, LOCAL_PORT, MID) { \
+ memcpy(&m_coap_empty_message.remote, (REMOTE), sizeof(coap_remote_t)); \
+ m_coap_empty_message.port.port_number = (LOCAL_PORT); \
+ m_coap_empty_message.header.id = (MID); \
+ m_coap_empty_message.header.type = COAP_TYPE_ACK; \
+}
+
+#define COAP_MESSAGE_RST_SET(REMOTE, LOCAL_PORT, MID) { \
+ memcpy(&m_coap_empty_message.remote, (REMOTE), sizeof(coap_remote_t)); \
+ m_coap_empty_message.port.port_number = (LOCAL_PORT); \
+ m_coap_empty_message.header.id = (MID); \
+ m_coap_empty_message.header.type = COAP_TYPE_RST; \
+}
+
+static coap_message_t m_coap_empty_message = {
+ .header = {
+ .version = 1,
+ .type = COAP_TYPE_ACK,
+ .token_len = 0,
+ .code = COAP_CODE_EMPTY_MESSAGE,
+ .id = 0,
+ },
+ .p_payload = NULL,
+ .payload_len = 0,
+ .options_count = 0,
+ .p_arg = NULL,
+ .response_callback = NULL,
+ .port = {
+ .port_number = 0
+ },
+ .options_len = 0,
+ .options_offset = 0,
+ .p_data = NULL,
+ .data_len = 0
+};
+
+static inline bool is_ping(coap_message_t * p_message)
+{
+ return (p_message->header.code == COAP_CODE_EMPTY_MESSAGE) &&
+ (p_message->header.type == COAP_TYPE_CON);
+}
+
+static inline bool is_ack(coap_message_t * p_message)
+{
+ return (p_message->header.code == COAP_CODE_EMPTY_MESSAGE) &&
+ (p_message->header.type == COAP_TYPE_ACK);
+}
+
+static inline bool is_reset(coap_message_t * p_message)
+{
+ return (p_message->header.type == COAP_TYPE_RST);
+}
+
+static inline bool is_con(coap_message_t * p_message)
+{
+ return (p_message->header.type == COAP_TYPE_CON);
+}
+
+static inline bool is_non(coap_message_t * p_message)
+{
+ return (p_message->header.type == COAP_TYPE_NON);
+}
+
+static inline bool is_request(uint8_t message_code)
+{
+ return (message_code >= 1) && (message_code < 32);
+}
+
+static inline bool is_response(uint8_t message_code)
+{
+ return (message_code >= 64) && (message_code < 192);
+}
+
+static inline void app_error_notify(uint32_t err_code, coap_message_t * p_message)
+{
+ if (m_error_callback != NULL)
+ {
+ COAP_MUTEX_UNLOCK();
+
+ m_error_callback(err_code, p_message);
+
+ COAP_MUTEX_LOCK();
+ }
+}
+
+uint32_t coap_init(uint32_t token_rand_seed, coap_transport_init_t * p_transport_param)
+{
+ COAP_ENTRY();
+
+ uint32_t err_code;
+
+ SDK_MUTEX_INIT(m_coap_mutex);
+
+ COAP_MUTEX_LOCK();
+
+ internal_coap_observe_init();
+
+ m_error_callback = NULL;
+
+ m_token_seed = token_rand_seed;
+ (void)m_token_seed;
+
+ m_message_id_counter = 1;
+
+ err_code = coap_transport_init(p_transport_param);
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ err_code = coap_queue_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ err_code = coap_resource_init();
+
+ COAP_MUTEX_UNLOCK();
+
+ COAP_EXIT();
+
+ return err_code;
+
+}
+
+uint32_t coap_error_handler_register(coap_error_callback_t error_callback)
+{
+ // TODO: error handling, null pointer, module initilized etc.
+ COAP_MUTEX_LOCK();
+
+ m_error_callback = error_callback;
+
+ COAP_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+uint32_t internal_coap_message_send(uint32_t * p_handle, coap_message_t * p_message)
+{
+ if (p_message == NULL)
+ {
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE);
+ }
+
+ // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1.
+ coap_observe_client_send_handle(p_message);
+
+ COAP_ENTRY();
+
+ // Fetch the expected length of the packet serialized by passing length of 0.
+ uint16_t expected_length = 0;
+ uint32_t err_code = coap_message_encode(p_message, NULL, &expected_length);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Allocate a buffer to serialize the message into.
+ uint8_t * p_buffer;
+ uint32_t request_length = expected_length;
+ err_code = nrf_mem_reserve(&p_buffer, &request_length);
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_TRC("p_buffer alloc error = 0x%08lX!", err_code);
+ return err_code;
+ }
+ memset(p_buffer, 0, request_length);
+ COAP_TRC("Alloc mem, p_buffer = %p", (uint8_t *)p_buffer);
+
+ // Serialize the message.
+ uint16_t buffer_length = (uint16_t)request_length;
+ err_code = coap_message_encode(p_message, p_buffer, &buffer_length);
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_TRC("Encode error!");
+ COAP_TRC("Free mem, p_buffer = %p", p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_buffer));
+
+ return err_code;
+ }
+
+ err_code = coap_transport_write(&p_message->port, &p_message->remote, p_buffer, buffer_length);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (is_con(p_message) || (is_non(p_message) &&
+ is_request(p_message->header.code) &&
+ (p_message->response_callback != NULL)))
+ {
+ coap_queue_item_t item;
+ item.p_arg = p_message->p_arg;
+ item.mid = p_message->header.id;
+ item.callback = p_message->response_callback;
+ item.p_buffer = p_buffer;
+ item.buffer_len = buffer_length;
+ item.timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR;
+
+ if (p_message->header.type == COAP_TYPE_CON)
+ {
+ item.timeout = item.timeout_val;
+ item.retrans_count = 0;
+ }
+ else
+ {
+ item.timeout = COAP_MAX_TRANSMISSION_SPAN;
+ item.retrans_count = COAP_MAX_RETRANSMIT_COUNT;
+ }
+
+ item.port = p_message->port;
+ item.token_len = p_message->header.token_len;
+
+ memcpy(&item.remote, &p_message->remote, sizeof(coap_remote_t));
+ memcpy(item.token, p_message->token, p_message->header.token_len);
+
+ err_code = coap_queue_add(&item);
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_TRC("Message queue error = 0x%08lX!", err_code);
+
+ COAP_TRC("Free mem, p_buffer = %p", p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_buffer));
+
+ return err_code;
+ }
+
+ *p_handle = item.handle;
+ }
+ else
+ {
+ *p_handle = COAP_MESSAGE_QUEUE_SIZE;
+
+ COAP_TRC("Free mem, p_buffer = %p", p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_buffer));
+ }
+ }
+ else
+ {
+ COAP_TRC("Free mem, p_buffer = %p", p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_buffer));
+ }
+
+ COAP_EXIT();
+
+ return err_code;
+}
+
+
+static uint32_t create_response(coap_message_t ** pp_response, coap_message_t * p_request, uint16_t data_size)
+{
+ uint32_t err_code;
+
+ // Allocate space for a new message.
+ uint32_t size = sizeof(coap_message_t);
+ err_code = nrf_mem_reserve((uint8_t **)pp_response, &size);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ coap_message_t * p_response = (*pp_response);
+
+ memset(p_response, 0, sizeof(coap_message_t));
+ COAP_TRC("Alloc mem, p_response = %p", (uint8_t *)p_response);
+
+ if (data_size > 0)
+ {
+ // Allocate a scratch buffer for payload and options.
+ size = data_size;
+ err_code = nrf_mem_reserve(&(p_response->p_data), &size);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ memset(p_response->p_data, 0, size);
+ p_response->data_len = size;
+ COAP_TRC("Alloc mem, p_response->p_data = %p", p_response->p_data);
+ }
+
+ coap_message_conf_t config;
+ memset (&config, 0, sizeof(coap_message_conf_t));
+
+ config.token_len = p_request->header.token_len;
+ config.id = p_request->header.id;
+ config.code = COAP_CODE_404_NOT_FOUND;
+ config.port.port_number = p_request->port.port_number;
+
+ memcpy(config.token, p_request->token, p_request->header.token_len);
+
+ if ((coap_msg_type_t)p_request->header.type == COAP_TYPE_CON)
+ {
+ config.type = COAP_TYPE_ACK;
+ }
+ else
+ {
+ config.type = (coap_msg_type_t)p_request->header.type;
+ }
+
+ err_code = coap_message_create(p_response, &config);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ (void)coap_message_remote_addr_set(p_response, &p_request->remote);
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Common function for sending response error message
+ *
+ * @param[in] p_message Pointer to the original request message.
+ * @param[in] code CoAP message code to send in the reponse.
+ *
+ * @retval NRF_SUCCESS If the response was sent out successfully.
+ */
+static uint32_t send_error_response(coap_message_t * p_message, uint8_t code)
+{
+ coap_message_t * p_error_response = NULL;
+
+ uint32_t err_code = create_response(&p_error_response, p_message, COAP_MESSAGE_DATA_MAX_SIZE);
+ if (err_code != NRF_SUCCESS)
+ {
+ // If message could not be created, notify the application.
+ app_error_notify(err_code, p_message);
+ return err_code;
+ }
+
+ // Set the response code.
+ p_error_response->header.code = code;
+
+ if (p_error_response != NULL)
+ {
+ uint32_t handle;
+ err_code = internal_coap_message_send(&handle, p_error_response);
+
+ COAP_TRC("Free mem, p_response->p_data = %p", p_error_response->p_data);
+ UNUSED_VARIABLE(nrf_free(p_error_response->p_data));
+
+ COAP_TRC("Free mem, p_response = %p", (uint8_t *)p_error_response);
+ UNUSED_VARIABLE(nrf_free((uint8_t *)p_error_response));
+ }
+
+ return err_code;
+}
+
+uint32_t coap_transport_read(const coap_port_t * p_port,
+ const coap_remote_t * p_remote,
+ const coap_remote_t * p_local,
+ uint32_t result,
+ const uint8_t * p_data,
+ uint16_t datalen)
+{
+ COAP_ENTRY();
+
+ // Discard all packets if not success or truncated.
+ if (!(result == NRF_SUCCESS || result == UDP_TRUNCATED_PACKET))
+ {
+ return NRF_SUCCESS;
+ }
+
+ uint32_t err_code;
+ coap_message_t * p_message;
+
+ // Allocate space for a new message.
+ uint32_t size = sizeof(coap_message_t);
+ err_code = nrf_mem_reserve((uint8_t **)&p_message, &size);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ memset(p_message, 0, sizeof(coap_message_t));
+ COAP_TRC("Alloc mem, p_message = %p", (uint8_t *)p_message);
+
+ err_code = coap_message_decode(p_message, p_data, datalen);
+ if (err_code != NRF_SUCCESS)
+ {
+ app_error_notify(err_code, p_message);
+
+ UNUSED_VARIABLE(nrf_free((uint8_t *)p_message));
+ return err_code;
+ }
+
+ // Copy the remote address information.
+ memcpy(&p_message->remote, p_remote, sizeof(coap_remote_t));
+
+ // Copy the destination address information.
+ if (p_local)
+ {
+ memcpy(&p_message->local, p_local, sizeof(coap_remote_t));
+ }
+
+ // Copy the local port information.
+ memcpy(&p_message->port, p_port, sizeof(coap_port_t));
+
+ if (result == UDP_TRUNCATED_PACKET)
+ {
+ app_error_notify(result, p_message);
+ }
+ else if (is_ping(p_message))
+ {
+ COAP_MESSAGE_RST_SET(&p_message->remote, p_message->port.port_number, p_message->header.id);
+
+ uint32_t handle;
+ err_code = internal_coap_message_send(&handle, &m_coap_empty_message);
+ }
+ else if (is_ack(p_message) ||
+ is_reset(p_message))
+ {
+ // Populate the token with the one used sending, before passing it to the application.
+ coap_queue_item_t * p_item = NULL;
+ err_code = coap_queue_item_by_mid_get(&p_item, p_message->header.id);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (p_item->callback != NULL)
+ {
+ // As the token is missing from peer, it will be added before giving it to the application.
+ memcpy(p_message->token, p_item->token, p_item->token_len);
+ p_message->header.token_len = p_item->token_len;
+
+ // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1.
+ coap_observe_client_response_handle(p_message, p_item);
+
+ COAP_TRC(">> application callback");
+
+ COAP_MUTEX_UNLOCK();
+
+ if (is_ack(p_message))
+ {
+ p_item->callback(NRF_SUCCESS, p_item->p_arg, p_message);
+ }
+ else
+ {
+ p_item->callback(COAP_TRANSMISSION_RESET_BY_PEER, p_item->p_arg, p_message);
+ }
+
+ COAP_MUTEX_LOCK();
+
+ COAP_TRC("<< application callback");
+ }
+
+ COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_item->p_buffer));
+
+ // Remove the queue element, as a match occured.
+ err_code = coap_queue_remove(p_item);
+ }
+ }
+ else if (is_response(p_message->header.code))
+ {
+ COAP_TRC("CoAP message type: RESPONSE");
+
+ coap_queue_item_t * p_item;
+ err_code = coap_queue_item_by_token_get(&p_item, p_message->token, p_message->header.token_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1.
+ coap_observe_client_response_handle(p_message, NULL);
+
+ UNUSED_VARIABLE(nrf_free((uint8_t *)p_message));
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+ }
+
+ if (p_item->callback != NULL)
+ {
+ // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1.
+ coap_observe_client_response_handle(p_message, p_item);
+
+ COAP_TRC(">> application callback");
+
+ COAP_MUTEX_UNLOCK();
+
+ p_item->callback(NRF_SUCCESS, p_item->p_arg, p_message);
+
+ COAP_MUTEX_LOCK();
+
+ COAP_TRC("<< application callback");
+ }
+
+ COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_item->p_buffer));
+
+ err_code = coap_queue_remove(p_item);
+
+ }
+ else if (is_request(p_message->header.code))
+ {
+ COAP_TRC("CoAP message type: REQUEST");
+
+ if (m_request_handler != NULL)
+ {
+ uint32_t return_code = m_request_handler(p_message);
+
+ // If success, then all processing and any responses has been sent
+ // by the application callback.
+
+ // If not success, then send an appropriate error message back to the
+ // origin with the return_code from the callback.
+ if (return_code != NRF_SUCCESS)
+ {
+ if (return_code == NRF_ERROR_NOT_FOUND)
+ {
+ // Send response with provided CoAP code.
+ (void)send_error_response(p_message, COAP_CODE_404_NOT_FOUND);
+ }
+ else if (return_code == NRF_ERROR_NULL)
+ {
+ (void)send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED);
+ }
+ else
+ {
+ (void)send_error_response(p_message, COAP_CODE_400_BAD_REQUEST);
+ }
+ }
+ }
+ else
+ {
+ uint8_t * uri_pointers[COAP_RESOURCE_MAX_DEPTH] = {0, };
+
+ uint8_t uri_path_count = 0;
+ uint16_t index;
+
+ for (index = 0; index < p_message->options_count; index++)
+ {
+ if (p_message->options[index].number == COAP_OPT_URI_PATH)
+ {
+ uri_pointers[uri_path_count++] = p_message->options[index].p_data;
+ }
+ }
+
+ coap_resource_t * found_resource;
+ err_code = coap_resource_get(&found_resource, uri_pointers, uri_path_count);
+
+ if (found_resource != NULL)
+ {
+ if (found_resource->callback != NULL)
+ {
+ if (((found_resource->permission) & (1 << ((p_message->header.code) - 1))) > 0) // Has permission for the requested CoAP method.
+ {
+ COAP_MUTEX_UNLOCK();
+
+ found_resource->callback(found_resource, p_message);
+
+ COAP_MUTEX_LOCK();
+ }
+ else
+ {
+ // Reply with Method Not Allowed.
+ err_code = send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED);
+ }
+ }
+ else
+ {
+ // Reply with Method Not Allowed.
+ err_code = send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED);
+ }
+ }
+ else
+ {
+ // Reply with NOT FOUND.
+ err_code = send_error_response(p_message, COAP_CODE_404_NOT_FOUND);
+ }
+ }
+ }
+
+ COAP_TRC("Free mem, p_message = %p", (uint8_t *)p_message);
+ UNUSED_VARIABLE(nrf_free((uint8_t *)p_message));
+
+ COAP_EXIT();
+ return err_code;
+}
+
+uint32_t coap_message_send(uint32_t * p_handle, coap_message_t * p_message)
+{
+ COAP_MUTEX_LOCK();
+
+ uint32_t err_code = internal_coap_message_send(p_handle, p_message);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_message_abort(uint32_t handle)
+{
+
+ return NRF_ERROR_NOT_SUPPORTED;
+}
+
+uint32_t coap_message_new(coap_message_t ** p_request, coap_message_conf_t * p_config)
+{
+ COAP_ENTRY();
+
+ uint32_t err_code;
+
+ // If port is not configured, return error and skip initialization of the message.
+ if (p_config->port.port_number == 0)
+ {
+ return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE);
+ }
+
+ COAP_MUTEX_LOCK();
+
+ // Allocate space for a new message.
+ uint32_t size = sizeof(coap_message_t);
+ err_code = nrf_mem_reserve((uint8_t **)p_request, &size);
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ memset(*p_request, 0, sizeof(coap_message_t));
+ COAP_TRC("Alloc mem, *p_request = %p", (uint8_t *)(*p_request));
+
+ // Allocate a scratch buffer for payload and options.
+ size = COAP_MESSAGE_DATA_MAX_SIZE;
+ err_code = nrf_mem_reserve(&((*p_request)->p_data), &size);
+ if (err_code != NRF_SUCCESS)
+ {
+ COAP_TRC("Allocation of message data buffer failed!");
+
+ COAP_TRC("Free mem, *p_request = %p", (uint8_t *)(*p_request));
+ UNUSED_VARIABLE(nrf_free((uint8_t *)(*p_request)));
+
+ COAP_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ memset((*p_request)->p_data, 0, size);
+ (*p_request)->data_len = size;
+
+ COAP_TRC("Alloc mem, (*p_request)->p_data = %p", (uint8_t *)((*p_request)->p_data));
+
+ if (p_config->id == 0) // Message id is not set, generate one.
+ {
+ p_config->id = m_message_id_counter++;
+ }
+
+ err_code = coap_message_create(*p_request, p_config);
+
+ COAP_MUTEX_UNLOCK();
+
+ COAP_EXIT_WITH_RESULT(err_code);
+
+ return err_code;
+}
+
+uint32_t coap_message_delete(coap_message_t * p_message)
+{
+ COAP_ENTRY();
+
+ COAP_MUTEX_LOCK();
+
+ //If this is a request free the coap_message_t and the data buffer.
+
+ COAP_TRC("Free mem, p_message->p_data = %p", p_message->p_data);
+ UNUSED_VARIABLE(nrf_free(p_message->p_data));
+
+ COAP_TRC("Free mem, p_message = %p", (uint8_t *)p_message);
+ UNUSED_VARIABLE(nrf_free((uint8_t *)p_message));
+
+
+ COAP_MUTEX_UNLOCK();
+
+ COAP_EXIT();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t coap_time_tick(void)
+{
+ COAP_MUTEX_LOCK();
+
+ coap_transport_process();
+
+ // Loop through the message queue to see if any packets needs retransmission, or has timed out.
+ coap_queue_item_t * p_item = NULL;
+ while (coap_queue_item_next_get(&p_item, p_item) == NRF_SUCCESS)
+ {
+ if (p_item->timeout == 0)
+ {
+ // If there is still retransmission attempts left.
+ if (p_item->retrans_count < COAP_MAX_RETRANSMIT_COUNT)
+ {
+ p_item->timeout = p_item->timeout_val * 2;
+ p_item->timeout_val = p_item->timeout;
+ p_item->retrans_count++;
+
+ // Retransmit the message.
+ uint32_t err_code = coap_transport_write(&p_item->port, &p_item->remote, p_item->p_buffer, p_item->buffer_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ app_error_notify(err_code, NULL);
+ }
+ }
+
+ // No more retransmission attempts left, or max transmit span reached.
+ if ((p_item->timeout > COAP_MAX_TRANSMISSION_SPAN) ||
+ (p_item->retrans_count >= COAP_MAX_RETRANSMIT_COUNT))
+ {
+
+ COAP_MUTEX_UNLOCK();
+
+ p_item->callback(COAP_TRANSMISSION_TIMEOUT, p_item->p_arg, NULL);
+
+ COAP_MUTEX_LOCK();
+
+ COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer);
+ UNUSED_VARIABLE(nrf_free(p_item->p_buffer));
+
+ (void)coap_queue_remove(p_item);
+ }
+ }
+ else
+ {
+ p_item->timeout--;
+ }
+ }
+
+ COAP_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_request_handler_register(coap_request_handler_t p_request_handler)
+{
+ COAP_MUTEX_LOCK();
+
+ m_request_handler = p_request_handler;
+
+ COAP_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+__WEAK void coap_transport_input(void)
+{
+ // By default not implemented. Transport specific.
+}
+
+void coap_input(void)
+{
+ COAP_MUTEX_LOCK();
+
+ coap_transport_input();
+
+ COAP_MUTEX_UNLOCK();
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h
new file mode 100644
index 0000000..09d9ecb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.h
@@ -0,0 +1,125 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap.h
+ *
+ * @defgroup iot_sdk_coap_api CoAP interface
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief Interface for the CoAP protocol.
+ */
+
+#ifndef COAP_H__
+#define COAP_H__
+
+#include "iot_errors.h"
+#include "coap_api.h"
+#include "sdk_os.h"
+
+/**
+ * @defgroup iot_coap_log Module's Log Macros
+ * @details Macros used for creating module logs which can be useful in understanding handling
+ * of events or actions on API requests. These are intended for debugging purposes and
+ * can be enabled by defining the COAP_ENABLE_LOGS to 1.
+ * @note If NRF_LOG_ENABLED is disabled, having COAP_ENABLE_LOGS has no effect.
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (COAP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
+ }
+
+/**@brief Verify that parameter members has been set by the application. */
+#define NULL_PARAM_MEMBER_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); \
+ }
+#else
+
+#define NULL_PARAM_CHECK(PARAM)
+#define NULL_PARAM_MEMBER_CHECK(PARAM)
+
+#endif // COAP_DISABLE_API_PARAM_CHECK
+
+/**
+ * @defgroup iot_coap_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 the need to use an alternative architecture arises.
+ * @{
+ */
+#define COAP_MUTEX_LOCK() SDK_MUTEX_LOCK(m_coap_mutex) /**< Lock module using mutex */
+#define COAP_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_coap_mutex) /**< Unlock module using mutex */
+
+SDK_MUTEX_DEFINE(m_coap_mutex)
+
+/** @} */
+
+/**@brief Sends a CoAP message.
+ *
+ * @details Sends out a request using the underlying transport layer. Before sending, the
+ * \ref coap_message_t structure is serialized and added to an internal message queue
+ * in the library. The handle returned can be used to abort the message from being
+ * retransmitted at any time.
+ *
+ * @param[out] p_handle Handle to the message if CoAP CON/ACK messages has been used. Returned
+ * by reference.
+ * @param[in] p_message Message to be sent.
+ *
+ * @retval NRF_SUCCESS If the message was successfully encoded and scheduled for transmission.
+ */
+uint32_t internal_coap_message_send(uint32_t * p_handle, coap_message_t * p_message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h
new file mode 100644
index 0000000..9bc0222
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_api.h
@@ -0,0 +1,663 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_api.h
+ *
+ * @defgroup iot_sdk_coap_api CoAP Application Programming Interface
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief Public API of Nordic's CoAP implementation.
+ *
+ */
+
+#ifndef COAP_API_H__
+#define COAP_API_H__
+
+#include <stdint.h>
+#include "coap_transport.h"
+#include "coap_codes.h"
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@defgroup COAP_CONTENT_TYPE_MASK Resource content type bitmask values
+ * @{ */
+#define COAP_CT_MASK_PLAIN_TEXT 0x01 /**< Content type Plain text supported in the endpoint resource. */
+#define COAP_CT_MASK_CHARSET_UTF8 0x02 /**< Content type Charset-UTF8 supported in the endpoint resource. */
+#define COAP_CT_MASK_APP_LINK_FORMAT 0x04 /**< Content type Application/link-format supported in the endpoint resource. */
+#define COAP_CT_MASK_APP_XML 0x08 /**< Content type Application/xml supported in the endpoint resource. */
+#define COAP_CT_MASK_APP_OCTET_STREAM 0x10 /**< Content type Application/octet-stream supported in the endpoint resource. */
+#define COAP_CT_MASK_APP_EXI 0x20 /**< Content type Application/exi supported in the endpoint resource. */
+#define COAP_CT_MASK_APP_JSON 0x40 /**< Content type Application/json supported in the endpoint resource. */
+/**@} */
+
+/**@defgroup COAP_METHOD_PERMISSION Resource method permission bitmask values
+ * @{ */
+#define COAP_PERM_NONE 0x0000 /**< Permission by default. Do not allow any method in the COAP/COAPS endpoint resource. */
+#define COAP_PERM_GET 0x0001 /**< Permission to allow GET method in the COAP endpoint resource. */
+#define COAP_PERM_POST 0x0002 /**< Permission to allow POST method in the COAP endpoint resource. */
+#define COAP_PERM_PUT 0x0004 /**< Permission to allow PUT method in the COAP endpoint resource. */
+#define COAP_PERM_DELETE 0x0008 /**< Permission to allow DELETE method in the COAP endpoint resource. */
+#define COAPS_PERM_GET 0x0010 /**< Permission to allow GET method in the COAPS endpoint resource. */
+#define COAPS_PERM_POST 0x0020 /**< Permission to allow POST method in the COAPS endpoint resource. */
+#define COAPS_PERM_PUT 0x0040 /**< Permission to allow PUT method in the COAPS endpoint resource. */
+#define COAPS_PERM_DELETE 0x0080 /**< Permission to allow DELETE method in the COAPS endpoint resource. */
+#define COAP_PERM_OBSERVE 0x0100 /**< Permission to allow OBSERVE of the endpoint resource. */
+/**@} */
+
+/**@cond */
+// Forward declare structs.
+typedef struct coap_message_t coap_message_t;
+typedef struct coap_resource_t coap_resource_t;
+/**@endcond */
+
+/**@brief Callback function to call upon undefined behaviour.
+ *
+ * @param[in] error_code Error code from CoAP module.
+ * @param[in] p_message CoAP message processed when error ocoured. Could be NULL.
+ */
+typedef void (*coap_error_callback_t)(uint32_t error_code, coap_message_t * p_message);
+
+/**@brief Callback function to be registered with CoAP messages.
+ *
+ * @param[in] status Response status. Possible status codes:
+ * NRF_SUCCESS If response was successfully received,
+ * COAP_TRANSMISSION_RESET_BY_PEER if a reset response was recieved or,
+ * COAP_TRANSMISSION_TIMEOUT if transmission
+ * @param[in] p_arg Miscellaneous pointer to application provided data that is associated with
+ * the message.
+ * @param[in] p_message Pointer to a CoAP Response message.
+ */
+typedef void (*coap_response_callback_t)(uint32_t status, void * p_arg, coap_message_t * p_message);
+
+/**@brief Handler function for manually handling all incoming requests.
+ *
+ * @details If the function is set, the error code given back will trigger error messages
+ * to be sent back by CoAP to indicate failure. Default error message will be 4.00
+ * BAD REQUEST. On success, it is expected that the callback has already sent a
+ * response message.
+ *
+ * @param[in] p_request Pointer to a CoAP Request message.
+ *
+ * @retval NRF_SUCCESS If the message was successfully has been handled.
+ * @retval NRF_ERROR_NOT_FOUND If the message did not match any recognized resources, and a
+ * 4.04 NOT FOUND error message should be sent back to the requester.
+ * @retval NRF_ERROR_NULL If the message resolved the resource and operation not permitted,
+ * and a 4.05 METHOD NOT ALLOWED error message should be sent back to
+ * the reqester.
+ *
+ */
+typedef uint32_t (*coap_request_handler_t)(coap_message_t * p_request);
+
+#ifdef COAP_AUTOMODE
+
+/**@brief Callback function to be registered with CoAP endpoint resources. in auto-mode.
+ *
+ * @details The callback needs to implement any action based on the request. The p_response message
+ * will automatically be sent as response when the callback function returns. The memory
+ * is allocated by the caller, so the application does not have to free up the memory used
+ * for the response.
+ *
+ * @param[in] p_resource Pointer to the request message's target resource.
+ * @param[in] p_request Pointer to the request message.
+ * @param[out] p_response Pointer to the prepared response message. The Application can override
+ * its values.
+ */
+typedef void (*coap_method_callback_t) (coap_resource_t * p_resource, coap_message_t * p_request, coap_message_t * p_response);
+
+#else // COAP_AUTOMODE
+
+/**@brief Callback function to be registered with CoAP endpoint resources. in auto-mode.
+ *
+ * @details The callback needs to implement any action based on the request. The callback is
+ * responsible of handling the sending of any response back to the requester. The memory
+ * for p_request will be freed up by the coap module after the callback has been
+ * completed.
+ *
+ * @param[in] p_resource Pointer to the request message's target resource.
+ * @param[in] p_request Pointer to the request message.
+ */
+typedef void (*coap_method_callback_t) (coap_resource_t * p_resource, coap_message_t * p_request);
+
+#endif // COAP_AUTOMODE
+
+/**@brief Enumeration of CoAP content types. */
+typedef enum
+{
+ COAP_CT_PLAIN_TEXT = 0, /**< Plain text content format number. Default. */
+ COAP_CT_APP_LINK_FORMAT = 40, /**< Application/link-format content format number. */
+ COAP_CT_APP_XML = 41, /**< Application/xml content format number. */
+ COAP_CT_APP_OCTET_STREAM = 42, /**< Application/octet-stream content format number. */
+ COAP_CT_APP_EXI = 47, /**< Application/exi content format number. */
+ COAP_CT_APP_JSON = 50 /**< Application/json content format number. */
+} coap_content_type_t;
+
+/**@brief Enumeration of CoAP options numbers. */
+
+#define COAP_OPT_RESERVED0 0 /**< Reserved option number. */
+#define COAP_OPT_IF_MATCH 1 /**< If-Match option number. */
+#define COAP_OPT_URI_HOST 3 /**< URI-Host option number. */
+#define COAP_OPT_ETAG 4 /**< ETag option number. */
+#define COAP_OPT_IF_NONE_MATCH 5 /**< If-None-Match option number. */
+#define COAP_OPT_URI_PORT 7 /**< URI-Port option number. */
+#define COAP_OPT_LOCATION_PATH 8 /**< Location-Path option number. */
+#define COAP_OPT_URI_PATH 11 /**< URI-Path option number. */
+#define COAP_OPT_CONTENT_FORMAT 12 /**< Content-Format option number. */
+#define COAP_OPT_MAX_AGE 14 /**< Max-Age option number. */
+#define COAP_OPT_URI_QUERY 15 /**< URI-Query option number. */
+#define COAP_OPT_ACCEPT 17 /**< Accept option number. */
+#define COAP_OPT_LOCATION_QUERY 20 /**< Location-Query option number. */
+#define COAP_OPT_BLOCK2 23 /**< Block2 option number. */
+#define COAP_OPT_BLOCK1 27 /**< Block1 option number. */
+#define COAP_OPT_SIZE2 28 /**< Size2 option number. */
+#define COAP_OPT_PROXY_URI 35 /**< Proxy-URI option number. */
+#define COAP_OPT_PROXY_SCHEME 39 /**< Proxy-Scheme option number. */
+#define COAP_OPT_SIZE1 60 /**< Size1 option number. */
+#define COAP_OPT_RESERVED1 128 /**< Reserved option number. */
+#define COAP_OPT_RESERVED2 132 /**< Reserved option number. */
+#define COAP_OPT_RESERVED3 136 /**< Reserved option number. */
+#define COAP_OPT_RESERVED4 140 /**< Reserved option number. */
+
+
+/**@brief Enumeration of CoAP message types. */
+typedef enum
+{
+ COAP_TYPE_CON = 0, /**< Confirmable Message type. */
+ COAP_TYPE_NON, /**< Non-Confirmable Message type. */
+ COAP_TYPE_ACK, /**< Acknowledge Message type. */
+ COAP_TYPE_RST /**< Reset Message type. */
+} coap_msg_type_t;
+
+/**@brief Structure to hold a CoAP option.
+ */
+typedef struct
+{
+ uint16_t number; /**< Option number (including the extended delta value if any). */
+ uint16_t length; /**< Option length (including the extended length value in any). */
+ uint8_t * p_data; /**< Pointer to the memory where the data of the option is located. */
+} coap_option_t;
+
+
+
+/**@brief Structure to hold a CoAP message configuration.
+ *
+ * @details The structure is used when calling the \ref coap_message_new API function.
+ * All data supplied will be copied to the created message.
+ */
+typedef struct
+{
+ coap_response_callback_t response_callback; /**< Callback function to be called when a response matching the token is identified. */
+ uint8_t token[8]; /**< Message token. token_len must be set to indicate how many of the bytes should be used in the token. */
+ uint8_t token_len; /**< Token size in bytes. */
+ uint16_t id; /**< Message ID. If 0 is given, the library will replace this number with an autogenerated value. */
+ coap_msg_type_t type; /**< Message type: COAP_TYPE_CON, COAP_TYPE_NON, COAP_TYPE_ACK, or COAP_TYPE_RST. */
+ coap_msg_code_t code; /**< Message code (definitions found in coap_msg_code_t). */
+ coap_port_t port; /**< Transport layer variable to associate the message with an underlying Transport Layer socket descriptor. */
+} coap_message_conf_t;
+
+/**@brief Structure to hold a CoAP message header.
+ *
+ * @details This structure holds the 4-byte mandatory CoAP header. The structure uses bitfields
+ * to save memory footprint.
+ */
+typedef struct
+{
+ uint8_t version :2; /**< CoAP version number. The current specification RFC7252 mandates this to be version 1. The version number can be modified in sdk_config.h. */
+ uint8_t type :2; /**< Message type: COAP_TYPE_CON, COAP_TYPE_NON, COAP_TYPE_ACK, or COAP_TYPE_RST. */
+ uint8_t token_len :4; /**< Length of the message token. */
+ uint8_t code; /**< Message code (definitions found in @ref coap_msg_code_t). */
+ uint16_t id; /**< Message ID in little-endian format. Convertion to Network Byte Order will be handled by the library. */
+} coap_message_header_t;
+
+/**@brief Structure to hold a CoAP message.
+ *
+ * @details The CoAP message structure contains both internal and public members to
+ * serialize and deserialize data supplied from the application to a byte buffer sent
+ * over UDP. The message structure is used both in transmission and reception, which
+ * makes it easy to handle in an application. Updating the message should be done
+ * using the provided APIs, not by manually assigning new values to the members directly.
+ * Reading the members, on the other hand, is fine.
+ */
+struct coap_message_t
+{
+ coap_remote_t remote; /**< Public. Structure containing address information and port number to the remote. */
+ coap_remote_t local; /**< Public. Structure containing local destination address information and port number. */
+ coap_message_header_t header; /**< Public. Header structure containing the mandatory CoAP 4-byte header fields. */
+ uint8_t * p_payload; /**< Public. Pointer to the payload buffer in the message. */
+ uint16_t payload_len; /**< Public. Size of the payload in the message. */
+ uint8_t options_count; /**< Public. The number of options in the message. */
+ coap_option_t options[COAP_MAX_NUMBER_OF_OPTIONS]; /**< Public. Array options in the message. */
+ void * p_arg; /**< Public. Miscellaneous pointer to application provided data that is associated with the message. */
+
+ coap_response_callback_t response_callback; /**< Internal. Function callback set by the application to be called when a response to this message is received. Should be set by the application through a configuration parameter. */
+ uint8_t token[8]; /**< Internal. Array holding the variable-sized message token. Should be set by the application through a configuration parameter. */
+ coap_port_t port; /**< Internal. Transport layer variable to associate the message with an underlying Transport Layer socket descriptor. */
+ uint16_t options_len; /**< Internal. Length of the options including the mandatory header with extension bytes and option data. Accumulated every time a new options is added. */
+ uint16_t options_offset; /**< Internal. Index to where the next option or payload can be added in the message's data buffer */
+ uint16_t options_delta; /**< Internal. Current option number. Used to calculate the next option delta when adding new options to the message. */
+ uint8_t * p_data; /**< Internal. Data buffer for adding dynamically sized options and payload. */
+ uint16_t data_len; /**< Internal. Length of the provided data buffer for options and payload. */
+};
+
+
+/**@brief Structure to hold a CoAP endpoint resource.
+*/
+struct coap_resource_t
+{
+ uint8_t child_count; /**< Number of children in the linked list. */
+ uint16_t permission; /**< Bitmask to tell which methods are permitted on the resource. Bit values available can be seen in \ref COAP_METHOD_PERMISSION. */
+ coap_resource_t * p_sibling; /**< Sibling pointer to the next element in the list. */
+ coap_resource_t * p_front; /**< Pointer to the beginning of the linked list. */
+ coap_resource_t * p_tail; /**< Pointer to the last added child in the list. */
+ coap_method_callback_t callback; /**< Callback to the resource handler. */
+ uint32_t ct_support_mask; /**< Bitmask to tell which content types are supported by the resource. Bit values available can be seen in \ref COAP_CONTENT_TYPE_MASK. */
+ uint32_t max_age; /**< Max age of resource endpoint value. */
+ uint32_t expire_time; /**< Number of seconds until expire. */
+ char name[COAP_RESOURCE_MAX_NAME_LEN+1]; /**< Name of the resource. Must be zero terminated. */
+};
+
+/**@brief Initializes the CoAP module.
+ *
+ * @details Initializes the library module and resets internal queues and resource registrations.
+ *
+ * @param[in] token_rand_seed Random number seed to be used to generate the token numbers.
+ * @param[in] p_transport_params Pointer to transport parameters. Providing the list of ports
+ * to be used by CoAP.
+ *
+ * @retval NRF_SUCCESS If initialization succeeded.
+ */
+uint32_t coap_init(uint32_t token_rand_seed, coap_transport_init_t * p_transport_params);
+
+/**@brief Register error handler callback to the CoAP module.
+ *
+ * @param[in] error_callback Function to be called upon unknown messages and failure.
+ *
+ * @retval NRF_SUCCESS If registration was successful.
+ */
+uint32_t coap_error_handler_register(coap_error_callback_t error_callback);
+
+/**@brief Register request handler which should handle all incoming requests.
+ *
+ * @details Setting this request handler redirects all requests to the application provided
+ * callback routine. The callback handler might be cleared by NULL, making coap
+ * module handle the requests and do resource lookup in order to process the
+ * requests.
+ *
+ * @param[in] p_request_handler Function pointer to the provided request handler.
+ *
+ * @retval NRF_SUCCESS If registration was successful.
+ */
+uint32_t coap_request_handler_register(coap_request_handler_t p_request_handler);
+
+/**@brief Sends a CoAP message.
+ *
+ * @details Sends out a request using the underlying transport layer. Before sending, the
+ * \ref coap_message_t structure is serialized and added to an internal message queue
+ * in the library. The handle returned can be used to abort the message from being
+ * retransmitted at any time.
+ *
+ * @param[out] p_handle Handle to the message if CoAP CON/ACK messages has been used. Returned
+ * by reference.
+ * @param[in] p_message Message to be sent.
+ *
+ * @retval NRF_SUCCESS If the message was successfully encoded and scheduled for transmission.
+ */
+uint32_t coap_message_send(uint32_t * p_handle, coap_message_t * p_message);
+
+/**@brief Abort a CoAP message.
+ *
+ * @details Aborts an ongoing transmission. If the message has not yet been sent, it will be
+ * deleted from the message queue as well as stop any ongoing re-transmission of the
+ * message.
+ *
+ * @param[in] handle Handle of the message to abort.
+ *
+ * @retval NRF_SUCCESS If the message was successfully aborted and removed from the
+ * message queue.
+ * @retval NRF_ERROR_NOT_FOUND If the message with the given handle was not located in the
+ * message queue.
+ */
+uint32_t coap_message_abort(uint32_t handle);
+
+/**@brief Creates CoAP message, initializes, and allocates the needed memory.
+ *
+ * @details Creates a CoAP message. This is an intermediate representation of the message,
+ * because the message will be serialized by the library before it is transmitted. The structure
+ * is verbose to facilitate configuring the message. Options, payload, and
+ * remote address information can be added using API function calls.
+ *
+ * @param[inout] p_request Pointer to be filled by the allocated CoAP message structures.
+ * @param[in] p_config Configuration for the message to be created. Manual configuration
+ * can be performed after the message creation, except for the CLIENT port
+ * association.
+ *
+ * @retval NRF_SUCCESS If the request was successfully allocated and initialized.
+ * @retval NRF_ERROR_INVALID_PARAM If local port number was not configured.
+ */
+uint32_t coap_message_new(coap_message_t ** p_request, coap_message_conf_t * p_config);
+
+/**@brief Deletes the CoAP request message.
+ *
+ * @details Frees up memory associated with the request message.
+ *
+ * @param[in] p_message Pointer to the request message to delete.
+ */
+uint32_t coap_message_delete(coap_message_t * p_message);
+
+/**@brief Adds a payload to a CoAP message.
+ *
+ * @details Sets a data payload to a request or response message.
+ *
+ * This function must be called after all CoAP options have been added.
+ * Due to internal buffers in the library, the payload will be added after any options
+ * in the buffer. If an option is added after the payload, this option will over-write
+ * the payload in the internal buffer.
+ *
+ * @param[inout] p_message Pointer to the message to add the payload to.
+ * @param[in] p_payload Pointer to the payload to be added.
+ * @param[in] payload_len Size of the payload to be added.
+ *
+ * @retval NRF_SUCCESS If the payload was successfully added to the message.
+ * @retval NRF_ERROR_NO_MEM If the payload could not fit within the allocated payload memory
+ * defined by sdk_config.h COAP_MESSAGE_DATA_MAX_SIZE.
+ */
+uint32_t coap_message_payload_set(coap_message_t * p_message,
+ void * p_payload,
+ uint16_t payload_len);
+
+/**@brief Adds an empty CoAP option to the message.
+ *
+ * Option numbers must be in ascending order, adding the one with the smallest number
+ * first and greatest last. If the order is incorrect, the delta number calculation will
+ * result in an invalid or wrong delta number for the option.
+ *
+ * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL.
+ * @param[in] option_num The option number to add to the message.
+ *
+ * @retval NRF_SUCCESS If the empty option was successfully added to the message.
+ * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size.
+ * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached.
+ */
+uint32_t coap_message_opt_empty_add(coap_message_t * p_message, uint16_t option_num);
+
+/**@brief Adds a uint CoAP option to the message.
+ *
+ * Option numbers must be in ascending order, adding the one with the smallest number
+ * first and greatest last. If the order is incorrect, the delta number calculation will
+ * result in an invalid or wrong delta number for the option.
+ *
+ * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL.
+ * @param[in] option_num The option number to add to the message.
+ * @param[in] data An unsigned value (8-bit, 16-bit, or 32-bit) casted to uint32_t.
+ * The value of the data is used to determine how many bytes
+ * CoAP must use to represent this option value.
+ *
+ * @retval NRF_SUCCESS If the unsigned integer option was successfully added to the message.
+ * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size.
+ * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached.
+ */
+uint32_t coap_message_opt_uint_add(coap_message_t * p_message, uint16_t option_num, uint32_t data);
+
+/**@brief Adds a string CoAP option to the message.
+ *
+ * Option numbers must be in ascending order, adding the one with the smallest number
+ * first and greatest last. If the order is incorrect, the delta number calculation will
+ * result in an invalid or wrong delta number for the option.
+ *
+ * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL.
+ * @param[in] option_num The option number to add to the message.
+ * @param[in] p_data Pointer to a string buffer to be used as value for the option.
+ * Should not be NULL.
+ * @param[in] length Length of the string buffer provided.
+ *
+ * @retval NRF_SUCCESS If the string option was successfully added to the message.
+ * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size.
+ * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached.
+ */
+uint32_t coap_message_opt_str_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length);
+
+/**@brief Adds an opaque CoAP option to the message.
+ *
+ * Option numbers must be in ascending order, adding the one with the smallest number
+ * first and greatest last. If the order is incorrect, the delta number calculation will
+ * result in an invalid or wrong delta number for the option.
+ *
+ * @param[inout] p_message Pointer to the message to add the option to. Should not be NULL.
+ * @param[in] option_num The option number to add to the message.
+ * @param[in] p_data Pointer to an opaque buffer to be used as value for the option.
+ * Should not be NULL.
+ * @param[in] length Length of the opaque buffer provided.
+ *
+ * @retval NRF_SUCCESS If the opaque option was successfully added to the message.
+ * @retval NRF_ERROR_DATA_SIZE If the data exceeds the available message buffer data size.
+ * @retval NRF_ERROR_NO_MEM If the maximum number of options that can be added to a message has been reached.
+ */
+uint32_t coap_message_opt_opaque_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length);
+
+/**@brief Sets a remote address and port number to a CoAP message.
+ *
+ * @details Copies the content of the provided pointer into the CoAP message.
+ *
+ * @param[inout] p_message Pointer to the message to add the address information to.
+ * Should not be NULL.
+ * @param[in] p_address Pointer to a structure holding the address information for the remote server or client.
+ * Should not be NULL.
+ *
+ * @retval NRF_SUCCESS When copying the content has finished.
+ */
+uint32_t coap_message_remote_addr_set(coap_message_t * p_message, coap_remote_t * p_address);
+
+/**@brief Creates a CoAP endpoint resource.
+ *
+ * @details Initializes the \ref coap_resource_t members.
+ *
+ * The first resource that is created will be set as the root of the resource
+ * hierarchy.
+ *
+ * @param[in] p_resource Pointer to coap_resource_t passed in by reference.
+ * This variable must be stored in non-volatile memory.
+ * Should not be NULL.
+ * @param[in] name Verbose name of the service (zero-terminated
+ * string). The maximum length of a name is defined
+ * by COAP_RESOURCE_MAX_NAME_LEN in @c sdk_config.h
+ * and can be adjusted if needed. Should not be NULL.
+ * @retval NRF_ERROR_DATA_SIZE If the provided name is larger than the available name buffer.
+ * @retval NRF_ERROR_NULL If the pointer to the resource or the provided
+ * name buffer is NULL.
+ */
+uint32_t coap_resource_create(coap_resource_t * p_resource, const char * name);
+
+/**@brief Adds a child resource.
+ *
+ * @details The hierarchy is constructed as a linked list with a maximum number of children.
+ * COAP_RESOURCE_MAX_DEPTH in @c sdk_config.h sets the maximum depth. The maximum
+ * number of children can be adjusted if more levels are needed.
+ *
+ * @param[in] p_parent Resource to attach the child to. Should not be NULL.
+ * @param[in] p_child Child resource to attach. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the child was successfully added.
+ * @retval COAP_ERROR_MAX_DEPTH_REACHED If the child is exceeding the maximum depth defined.
+ */
+uint32_t coap_resource_child_add(coap_resource_t * p_parent, coap_resource_t * p_child);
+
+/**@brief Generates .well-known/core string.
+ *
+ * @details This is a helper function for generating a CoRE link-format encoded string used for
+ * CoAP discovery. The function traverse the resource hierarchy recursively.
+ * The result will be resources listed in link-format. This function can be called when
+ * all resources have been added by the application.
+ *
+ * @param[inout] string Buffer to use for the .well-known/core string. Should not be NULL.
+ * @param[inout] length Length of the string buffer. Returns the used number of bytes from
+ * the provided buffer.
+ *
+ * @retval NRF_SUCCESS If string generation was successful.
+ * @retval NRF_ERROR_NULL If the string buffer was a NULL pointer.
+ * @retval NRF_ERROR_DATA_SIZE If the size of the generated string exceeds the given buffer size.
+ * @retval NRF_ERROR_INVALID_STATE If no resource has been registered.
+ */
+uint32_t coap_resource_well_known_generate(uint8_t * string, uint16_t * length);
+
+/**@brief Get the root resource pointer.
+ *
+ * @param[out] pp_resource Pointer to be filled with pointer to the root resource.
+ *
+ * @retval NRF_SUCCESS If root resource was located.
+ * @retval NRF_ERROR_NOT_FOUND If root resource was not located.
+ * @retval NRF_ERROR_NULL If output pointer was NULL.
+ */
+uint32_t coap_resource_root_get(coap_resource_t ** pp_resource);
+
+/**@brief Check whether a message contains a given CoAP Option.
+ *
+ * @param[in] p_message Pointer to the to check for the CoAP Option.
+ * Should not be NULL.
+ * @param[in] option CoAP Option to check for in the CoAP message.
+ *
+ * @retval NRF_SUCCESS If the CoAP Option is present in the message.
+ * @retval NRF_ERROR_NULL If the pointer to the message is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If the CoAP Option is not present in the message.
+ */
+uint32_t coap_message_opt_present(coap_message_t * p_message, uint16_t option);
+
+/**@brief Check whether a message contains a given CoAP Option and return the index of the entry
+ * in the message option list.
+ *
+ * @param[in] p_index Value by reference to fill the resolved index into. Should not be NULL.
+ * @param[in] p_message Pointer to the to check for the CoAP Option.
+ * Should not be NULL.
+ * @param[in] option CoAP Option to check for in the CoAP message.
+ *
+ * @retval NRF_SUCCESS If the CoAP Option is present in the message.
+ * @retval NRF_ERROR_NULL If the pointer to the message or the p_index is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If the CoAP Option is not present in the message.
+ */
+uint32_t coap_message_opt_index_get(uint8_t * p_index, coap_message_t * p_message, uint16_t option);
+
+/**@brief Find common content type between the CoAP message and the resource.
+ *
+ * @details The return value will be the first match between the ACCEPT options and the supported
+ * content types in the resource. The priority is by content-format ID starting going
+ * from the lowest value to the highest.
+ *
+ * @param[out] p_ct Resolved content type given by reference. Should not be NULL.
+ * @param[in] p_message Pointer to the message. Should not be NULL.
+ * @param[in] p_resource Pointer to the resource. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If match was found.
+ * @retval NRF_ERROR_NOT_FOUND If no match was found.
+ */
+uint32_t coap_message_ct_match_select(coap_content_type_t * p_ct, coap_message_t * p_message, coap_resource_t * p_resource);
+
+/**@brief CoAP time tick used for retransmitting any message in the queue if needed.
+ *
+ * @retval NRF_SUCCESS If time tick update was successfully handled.
+ */
+uint32_t coap_time_tick(void);
+
+#if (COAP_DISABLE_DTLS_API == 0)
+/**@brief Setup secure DTLS session.
+ *
+ * @details For the client role, this API triggers a DTLS handshake. Until the handshake is complete
+ * with the remote, \ref coap_message_send will fail.
+ * For the server role, this API does not create any DTLS session. A DTLS session is
+ * created each time a new client remote endpoint sends a request on the local port of the
+ * server.
+ *
+ * @note The success of this function does not imply that the DTLS handshake is successfull.
+ *
+ * @note Only one DTLS session is permitted between a local and remote endpoint. Therefore, in case
+ * a DTLS session was established between the local and remote endpoint, the existing DTLS
+ * session will be reused irrespective of the role and number of times this API was called.
+ * In case the application desires a fresh security setup, it must first call the
+ * \ref coap_security_destroy to tear down the existing setup.
+ *
+ * @param[in] local_port Local port to bind the session to.
+ * @param[in] role Role of the session. DTLS server or client defined in the enumeration
+ * \ref nrf_tls_role_t.
+ * @param[in] p_remote Pointer to a structure holding the address information for the remote
+ * endpoint. If a the device is acting as a server, a NULL pointer shall be
+ * given as a parameter. Rationale: The server is not envisioned to be
+ * bound a pre-known client endpoint. Therefore, security server settings
+ * shall be setup irrespective of the remote client.
+ * @param[in] p_settings Pointer to a structure holding the DTLS credentials.
+ *
+ * @retval NRF_SUCCESS If setup of the secure DTLS session was successfull.
+ */
+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);
+
+
+/**@brief Destroy a secure DTLS session.
+ *
+ * @details Terminate and clean up any session associated with the local port and the remote.
+ *
+ * @param[in] local_port Local port to unbind the session from.
+ * @param[in] p_remote Pointer to a structure holding the address information for the remote
+ * endpoint. Providing a NULL as p_remote will clean up all DTLS sessions
+ * associated with the local port.
+ *
+ * @retval NRF_SUCCESS If the destruction of the secure DTLS session was successfull.
+ */
+uint32_t coap_security_destroy(uint16_t local_port,
+ coap_remote_t * const p_remote);
+
+#endif // COAP_DISABLE_DTLS_API
+
+/**@brief Process loop when using coap BSD socket transport implementation.
+ *
+ * @details This is blocking call. The function unblock is only
+ * triggered upon an socket event registered to select() by coap transport.
+ * This function must be called as often as possible in order to dispatch incoming
+ * socket events. Preferred to be put in the application's main loop or similar.
+ **/
+void coap_input(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_API_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c
new file mode 100644
index 0000000..f915f54
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.c
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) 2015 - 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 <stdbool.h>
+#include <stddef.h>
+
+#include "coap_block.h"
+#include "nrf_error.h"
+#include "iot_errors.h"
+#include "sdk_config.h"
+
+
+/**
+ * @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.
+ * COAP_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
+ *
+ * @{
+ */
+#if (COAP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
+ }
+#else // COAP_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // COAP_DISABLE_API_PARAM_CHECK
+/** @} */
+
+
+#define BLOCK_SIZE_BASE_CONSTANT 4 /**< Block size base exponent. 4 means a base block size of 2^4 = 16 bytes. */
+
+#define BLOCK_SIZE_16 0 /**< Block size of 2^(4+0) = 16 bytes. */
+#define BLOCK_SIZE_32 1 /**< Block size of 2^(4+1) = 32 bytes. */
+#define BLOCK_SIZE_64 2 /**< Block size of 2^(4+2) = 64 bytes. */
+#define BLOCK_SIZE_128 3 /**< Block size of 2^(4+3) = 128 bytes. */
+#define BLOCK_SIZE_256 4 /**< Block size of 2^(4+4) = 256 bytes. */
+#define BLOCK_SIZE_512 5 /**< Block size of 2^(4+5) = 512 bytes. */
+#define BLOCK_SIZE_1024 6 /**< Block size of 2^(4+6) = 1024 bytes. */
+#define BLOCK_SIZE_2048_RESERVED 7 /**< Reserved. */
+
+#define BLOCK_MORE_BIT_UNSET 0 /**< Value when more flag is set. */
+#define BLOCK_MORE_BIT_SET 1 /**< Value when more flag is not set. */
+
+#define BLOCK_SIZE_POS 0 /**< Bit offset to the size. */
+#define BLOCK_MORE_BIT_POS 3 /**< Bit offset to the more bit. */
+#define BLOCK_NUMBER_POS 4 /**< Bit offset to the block number. */
+
+#define BLOCK_SIZE_MASK 0x7 /**< Block size mask. */
+#define BLOCK_MORE_BIT_MASK (1 << BLOCK_MORE_BIT_POS) /**< More bit mask. */
+#define BLOCK_NUMBER_MASK (0xFFFFF << 4) /**< Block number mask. */
+
+#define BLOCK_SIZE_MAX 0x7 /**< Maximum block size number. */
+#define BLOCK_MORE_BIT_MAX BLOCK_MORE_BIT_SET /**< Maximum more bit value. */
+#define BLOCK_NUMBER_MAX 0xFFFFF /**< Maximum block number. 20 bits max value is (1 << 20) - 1. */
+
+static uint32_t block_opt_encode(uint8_t more,
+ uint16_t size,
+ uint32_t number,
+ uint32_t * p_encoded)
+{
+ if ((number > BLOCK_NUMBER_MAX) || (more > BLOCK_MORE_BIT_MAX))
+ {
+ return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE);
+ }
+
+ uint32_t val = 0;
+
+ switch (size)
+ {
+ case 16:
+ val = BLOCK_SIZE_16;
+ break;
+
+ case 32:
+ val = BLOCK_SIZE_32;
+ break;
+
+ case 64:
+ val = BLOCK_SIZE_64;
+ break;
+
+ case 128:
+ val = BLOCK_SIZE_128;
+ break;
+
+ case 256:
+ val = BLOCK_SIZE_256;
+ break;
+
+ case 512:
+ val = BLOCK_SIZE_512;
+ break;
+
+ case 1024:
+ val = BLOCK_SIZE_1024;
+ break;
+
+ case 2048:
+ // Falltrough.
+ default:
+ // Break omitted.
+ return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE);
+ }
+
+ // Value has been initialized.
+ val |= (more) << BLOCK_MORE_BIT_POS;
+ val |= (number) << BLOCK_NUMBER_POS;
+
+ *p_encoded = val;
+ return NRF_SUCCESS;
+}
+
+static uint32_t block_opt_decode(uint32_t encoded,
+ uint8_t * p_more,
+ uint16_t * p_size,
+ uint32_t * p_number)
+{
+ if ((encoded & BLOCK_SIZE_MASK) == BLOCK_SIZE_2048_RESERVED)
+ {
+ return (NRF_ERROR_INVALID_DATA | IOT_COAP_ERR_BASE);
+ }
+
+ if ((encoded >> BLOCK_NUMBER_POS) > BLOCK_NUMBER_MAX)
+ {
+ return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE);
+ }
+
+ *p_size = (1 << ((BLOCK_SIZE_BASE_CONSTANT + (encoded & BLOCK_SIZE_MASK))));
+ *p_more = (encoded & BLOCK_MORE_BIT_MASK) >> BLOCK_MORE_BIT_POS;
+ *p_number = (encoded & BLOCK_NUMBER_MASK) >> BLOCK_NUMBER_POS;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_block_opt_block1_encode(uint32_t * p_encoded, coap_block_opt_block1_t * p_opt)
+{
+ NULL_PARAM_CHECK(p_encoded);
+ NULL_PARAM_CHECK(p_opt);
+ return block_opt_encode(p_opt->more, p_opt->size, p_opt->number, p_encoded);
+}
+
+uint32_t coap_block_opt_block1_decode(coap_block_opt_block1_t * p_opt, uint32_t encoded)
+{
+ NULL_PARAM_CHECK(p_opt);
+ return block_opt_decode(encoded, &p_opt->more, &p_opt->size, &p_opt->number);
+}
+
+uint32_t coap_block_opt_block2_encode(uint32_t * p_encoded, coap_block_opt_block2_t * p_opt)
+{
+ NULL_PARAM_CHECK(p_encoded);
+ NULL_PARAM_CHECK(p_opt);
+ return block_opt_encode(p_opt->more, p_opt->size, p_opt->number, p_encoded);
+}
+
+uint32_t coap_block_opt_block2_decode(coap_block_opt_block2_t * p_opt, uint32_t encoded)
+{
+ NULL_PARAM_CHECK(p_opt);
+ return block_opt_decode(encoded, &p_opt->more, &p_opt->size, &p_opt->number);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h
new file mode 100644
index 0000000..fa2e9ee
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_block.h
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file coap_block.h
+ *
+ * @defgroup iot_sdk_coap_block CoAP Block transfer
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief CoAP block transfer options encoding and decoding interface and definitions.
+ *
+ */
+
+#ifndef COAP_BLOCK_H__
+#define COAP_BLOCK_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COAP_BLOCK_OPT_BLOCK_MORE_BIT_UNSET 0 /**< Value when more flag is set. */
+#define COAP_BLOCK_OPT_BLOCK_MORE_BIT_SET 1 /**< Value when more flag is not set. */
+
+typedef struct
+{
+ uint8_t more; /**< More bit value. */
+ uint16_t size; /**< Size of the block in bytes. */
+ uint32_t number; /**< Block number. */
+} coap_block_opt_block1_t;
+
+typedef coap_block_opt_block1_t coap_block_opt_block2_t;
+
+/**@brief Encode block1 option into its uint binary counter part.
+ *
+ * @param[out] p_encoded Encoded version of the coap block1 option value. Must not be NULL.
+ * @param[in] p_opt Pointer to block1 option structure to be decoded into uint format. Must
+ * not be NULL.
+ *
+ * @retval NRF_SUCCESS If encoding of option was successful.
+ * @retval NRF_ERROR_NULL If one of the parameters supplied is a null pointer.
+ * @retval NRF_ERROR_INVALID_PARAM If one of the fields in the option structure has an illegal
+ * value.
+ */
+uint32_t coap_block_opt_block1_encode(uint32_t * p_encoded, coap_block_opt_block1_t * p_opt);
+
+/**@brief Decode block1 option from a uint to its structure counter part.
+ *
+ * @param[out] p_opt Pointer to block1 option structure to be filled by the function. Must not
+ * be NULL.
+ * @param[in] encoded Encoded version of the coap block1 option value.
+ *
+ * @retval NRF_SUCCESS If decoding of the option was successful.
+ * @retval NRF_ERROR_NULL If p_opt parameter is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If the block number is higher then allowed by spec (more than
+ 20 bits).
+ * @retval NRF_ERROR_INVALID_DATA If the size has the value of the reserved 2048 value (7).
+ */
+uint32_t coap_block_opt_block1_decode(coap_block_opt_block1_t * p_opt, uint32_t encoded);
+
+/**@brief Encode block2 option into its uint binary counter part.
+ *
+ * @param[out] p_encoded Encoded version of the coap block2 option value. Must not be NULL.
+ * @param[in] p_opt Pointer to block2 option structure to be decoded into uint format. Must
+ * not be NULL.
+ *
+ * @retval NRF_SUCCESS If encoding of option was successful.
+ * @retval NRF_ERROR_NULL If one of the parameters supplied is a null pointer.
+ * @retval NRF_ERROR_INVALID_PARAM If one of the fields in the option structure has an illegal
+ * value.
+ */
+uint32_t coap_block_opt_block2_encode(uint32_t * p_encoded, coap_block_opt_block2_t * p_opt);
+
+/**@brief Decode block2 option from a uint to its structure counter part.
+ *
+ * @param[out] p_opt Pointer to block2 option structure to be filled by the function. Must not
+ * be NULL.
+ * @param[in] encoded Encoded version of the coap block2 option value.
+ *
+ * @retval NRF_SUCCESS If decoding of the option was successful.
+ * @retval NRF_ERROR_NULL If p_opt parameter is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If the block number is higher then allowed by spec (more than
+ 20 bits).
+ * @retval NRF_ERROR_INVALID_DATA If the size has the value of the reserved 2048 value (7).
+ */
+uint32_t coap_block_opt_block2_decode(coap_block_opt_block2_t * p_opt, uint32_t encoded);
+
+#endif // COAP_BLOCK_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h
new file mode 100644
index 0000000..88b1d48
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_codes.h
@@ -0,0 +1,115 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_codes.h
+ *
+ * @defgroup iot_sdk_coap_codes CoAP Codes
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief CoAP message and response codes.
+ */
+
+#ifndef COAP_CODES_H__
+#define COAP_CODES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COAP_CODE(c, dd) \
+ ((((c) & 0x7) << 5) | (((1 ## dd) - 100) & 0x1F))
+/**
+ @note macro adds 1xx to the number in order to prevent dd from being
+ interpreted as octal.
+*/
+
+/*lint -save -e122 */ /* Suppress "Digit (8) too large for radix" */
+
+/** @brief CoAP Message codes
+*/
+typedef enum
+{
+ // CoAP Empty Message
+ COAP_CODE_EMPTY_MESSAGE = COAP_CODE(0,00), /**< CoAP code 0.00, Decimal: 0, Hex: 0x00. */
+
+ // CoAP Method Codes
+ COAP_CODE_GET = COAP_CODE(0,01), /**< CoAP code 0.01, Decimal: 1, Hex: 0x01. */
+ COAP_CODE_POST = COAP_CODE(0,02), /**< CoAP code 0.02, Decimal: 2, Hex: 0x02. */
+ COAP_CODE_PUT = COAP_CODE(0,03), /**< CoAP code 0.03, Decimal: 3, Hex: 0x03. */
+ COAP_CODE_DELETE = COAP_CODE(0,04), /**< CoAP code 0.04, Decimal: 4, Hex: 0x04. */
+
+ // CoAP Success Response Codes
+ COAP_CODE_201_CREATED = COAP_CODE(2,01), /**< CoAP code 2.01, Decimal: 65, Hex: 0x41. */
+ COAP_CODE_202_DELETED = COAP_CODE(2,02), /**< CoAP code 2.02, Decimal: 66, Hex: 0x42. */
+ COAP_CODE_203_VALID = COAP_CODE(2,03), /**< CoAP code 2.03, Decimal: 67, Hex: 0x43. */
+ COAP_CODE_204_CHANGED = COAP_CODE(2,04), /**< CoAP code 2.04, Decimal: 68, Hex: 0x44. */
+ COAP_CODE_205_CONTENT = COAP_CODE(2,05), /**< CoAP code 2.05, Decimal: 69, Hex: 0x45. */
+ COAP_CODE_231_CONTINUE = COAP_CODE(2,31), /**< CoAP code 2.31, Decimal: 95, Hex: 0x5F. */
+
+ // CoAP Client Error Response Codes
+ COAP_CODE_400_BAD_REQUEST = COAP_CODE(4,00), /**< CoAP code 4.00, Decimal: 128, Hex: 0x80. */
+ COAP_CODE_401_UNAUTHORIZED = COAP_CODE(4,01), /**< CoAP code 4.01, Decimal: 129, Hex: 0x81. */
+ COAP_CODE_402_BAD_OPTION = COAP_CODE(4,02), /**< CoAP code 4.02, Decimal: 130, Hex: 0x82. */
+ COAP_CODE_403_FORBIDDEN = COAP_CODE(4,03), /**< CoAP code 4.03, Decimal: 131, Hex: 0x83. */
+ COAP_CODE_404_NOT_FOUND = COAP_CODE(4,04), /**< CoAP code 4.04, Decimal: 132, Hex: 0x84. */
+ COAP_CODE_405_METHOD_NOT_ALLOWED = COAP_CODE(4,05), /**< CoAP code 4.05, Decimal: 133, Hex: 0x85. */
+ COAP_CODE_406_NOT_ACCEPTABLE = COAP_CODE(4,06), /**< CoAP code 4.06, Decimal: 134, Hex: 0x86. */
+ COAP_CODE_408_REQUEST_ENTITY_INCOMPLETE = COAP_CODE(4,08), /**< CoAP code 4.08, Decimal: 136, Hex: 0x88. */
+ COAP_CODE_412_PRECONDITION_FAILED = COAP_CODE(4,12), /**< CoAP code 4.12, Decimal: 140, Hex: 0x8C. */
+ COAP_CODE_413_REQUEST_ENTITY_TOO_LARGE = COAP_CODE(4,13), /**< CoAP code 4.13, Decimal: 141, Hex: 0x8D. */
+ COAP_CODE_415_UNSUPPORTED_CONTENT_FORMAT = COAP_CODE(4,15), /**< CoAP code 4.15, Decimal: 143, Hex: 0x8F. */
+
+ // CoAP Server Error Response Codes
+ COAP_CODE_500_INTERNAL_SERVER_ERROR = COAP_CODE(5,00), /**< CoAP code 5.00, Decimal: 160, Hex: 0xA0. */
+ COAP_CODE_501_NOT_IMPLEMENTED = COAP_CODE(5,01), /**< CoAP code 5.01, Decimal: 161, Hex: 0xA1. */
+ COAP_CODE_502_BAD_GATEWAY = COAP_CODE(5,02), /**< CoAP code 5.02, Decimal: 162, Hex: 0xA2. */
+ COAP_CODE_503_SERVICE_UNAVAILABLE = COAP_CODE(5,03), /**< CoAP code 5.03, Decimal: 163, Hex: 0xA3. */
+ COAP_CODE_504_GATEWAY_TIMEOUT = COAP_CODE(5,04), /**< CoAP code 5.04, Decimal: 164, Hex: 0xA4. */
+ COAP_CODE_505_PROXYING_NOT_SUPPORTED = COAP_CODE(5,05) /**< CoAP code 5.05, Decimal: 165, Hex: 0xA5. */
+} coap_msg_code_t;
+
+/*lint -restore */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_CODES_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c
new file mode 100644
index 0000000..db0f7bf
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c
@@ -0,0 +1,804 @@
+/**
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "nordic_common.h"
+#include "coap_message.h"
+#include "coap_api.h"
+#include "iot_common.h"
+#include "sdk_config.h"
+#include "app_util.h"
+
+#define COAP_PAYLOAD_MARKER_SIZE 1
+
+/**@brief Verify that there is a index available for a new option. */
+#define OPTION_INDEX_AVAIL_CHECK(COUNT) \
+ if ((COUNT) >= COAP_MAX_NUMBER_OF_OPTIONS) \
+ { \
+ return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); \
+ }
+
+#if (COAP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
+ }
+#else
+
+#define NULL_PARAM_CHECK(PARAM)
+#define OPTION_INDEX_AVAIL_CHECK(COUNT)
+
+#endif // COAP_DISABLE_API_PARAM_CHECK
+
+uint32_t coap_message_create(coap_message_t * p_message, coap_message_conf_t * p_init_config)
+{
+ NULL_PARAM_CHECK(p_message);
+ NULL_PARAM_CHECK(p_init_config);
+
+ // Setting default value for version.
+ p_message->header.version = COAP_VERSION;
+
+ // Copy values from the init config.
+ p_message->header.type = p_init_config->type;
+ p_message->header.token_len = p_init_config->token_len;
+ p_message->header.code = p_init_config->code;
+ p_message->header.id = p_init_config->id;
+ p_message->response_callback = p_init_config->response_callback;
+ p_message->p_arg = NULL;
+
+ if (p_init_config->port.port_number == 0)
+ {
+ return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE);
+ }
+ memcpy(&p_message->port, &p_init_config->port, sizeof(coap_port_t));
+
+ memcpy(p_message->token, p_init_config->token, sizeof(p_init_config->token));
+ return NRF_SUCCESS;
+}
+
+/**@brief Decode CoAP option
+ *
+ * @param[in] p_raw_option Pointer to the memory buffer where the raw option is located.
+ * @param[inout] p_message Pointer to the current message. Used to retrieve information about
+ * where current option delta and the size of free memory to add the
+ * values of the option. Used as a container where to put
+ * the parsed option.
+ * @param[out] byte_count Number of bytes parsed. Used to indicate where the next option
+ * might be located (if any left) in the raw message buffer.
+ *
+ * @retval NRF_SUCCESS If the option parsing went successful.
+ * @retval NRF_ERROR_DATA_SIZE If there is no more space left in the free memory to add the
+ * option value to the p_message.
+ */
+static uint32_t decode_option(const uint8_t * p_raw_option, coap_message_t * p_message, uint16_t * byte_count)
+{
+ uint16_t byte_index = 0;
+ uint8_t option_num = p_message->options_count;
+
+ // Calculate the option number.
+ uint16_t option_delta = (p_raw_option[byte_index] & 0xF0) >> 4;
+ // Calculate the option length.
+ uint16_t option_length = (p_raw_option[byte_index] & 0x0F);
+ byte_index++;
+
+ uint16_t acc_option_delta = p_message->options_delta;
+
+ if (option_delta == 13)
+ {
+ // read one additional byte to get the extended delta.
+ acc_option_delta += 13 + p_raw_option[byte_index++];
+
+ }
+ else if (option_delta == 14)
+ {
+ // read one additional byte to get the extended delta.
+ acc_option_delta += 269;
+ acc_option_delta += (p_raw_option[byte_index++] << 8);
+ acc_option_delta += (p_raw_option[byte_index++]);
+ }
+ else
+ {
+ acc_option_delta += option_delta;
+ }
+
+ // Set the accumlated delta as the option number.
+ p_message->options[option_num].number = acc_option_delta;
+
+ if (option_length == 13)
+ {
+ option_length = 13 + p_raw_option[byte_index++];
+ }
+ else if (option_length == 14)
+ {
+ option_length = 269;
+ option_length += (p_raw_option[byte_index++] << 8);
+ option_length += p_raw_option[byte_index++];
+ }
+
+ // Set the option length including extended bytes.
+ p_message->options[option_num].length = option_length;
+
+ // Point p_data to the memory where to find the option value.
+ p_message->options[option_num].p_data = (uint8_t *)&p_raw_option[byte_index];
+
+ // Update the delta counter with latest option number.
+ p_message->options_delta = p_message->options[option_num].number;
+
+ byte_index += p_message->options[option_num].length;
+ *byte_count = byte_index;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Encode CoAP option delta and length bytes.
+ *
+ * @param[inout] encoded_value Value to encode. In return the value after encoding.
+ * @param[out] encoded_value_ext The value of the encoded extended bytes.
+ *
+ * @return The size of the extended byte field.
+ */
+static inline uint8_t encode_extended_bytes(uint16_t * value,
+ uint16_t * value_ext)
+{
+ uint16_t raw_value = *value;
+
+ uint8_t ext_size = 0;
+
+ if (raw_value >= 269)
+ {
+ *value = 14;
+ *value_ext = raw_value - 269;
+ ext_size = 2;
+ }
+ else if (raw_value >= 13)
+ {
+ *value = 13;
+ *value_ext = raw_value - 13;
+ ext_size = 1;
+ }
+ else
+ {
+ *value = raw_value;
+ *value_ext = 0;
+ }
+
+ return ext_size;
+}
+
+
+static uint32_t encode_option(uint8_t * p_buffer, coap_option_t * p_option, uint16_t * byte_count)
+{
+ uint16_t delta_ext = 0;
+ uint16_t delta = p_option->number;
+
+ uint8_t delta_ext_size = encode_extended_bytes(&delta,
+ &delta_ext);
+
+ uint16_t length = p_option->length;
+ uint16_t length_ext = 0;
+
+ uint8_t length_ext_size = encode_extended_bytes(&length,
+ &length_ext);
+
+ if (p_buffer == NULL)
+ {
+ uint16_t header_size = 1;
+ *byte_count = header_size + delta_ext_size + length_ext_size + p_option->length;
+ return NRF_SUCCESS;
+ }
+
+ uint16_t byte_index = 0;
+
+ // Add the option header.
+ p_buffer[byte_index++] = ((delta & 0x0F) << 4) | (length & 0x0F);
+
+ // Add option delta extended bytes to the buffer.
+ if (delta_ext_size == 1)
+ {
+ // Add first byte of delta_ext to the option header.
+ p_buffer[byte_index++] = (uint8_t)delta_ext;
+ }
+ else if (delta_ext_size == 2)
+ {
+ // uint16 in Network Byte Order.
+ p_buffer[byte_index++] = (uint8_t)((delta_ext & 0xFF00) >> 8);
+ p_buffer[byte_index++] = (uint8_t)((delta_ext & 0x00FF));
+ }
+
+ if (length_ext_size == 1)
+ {
+ // Add first byte of length_ext to the option header.
+ p_buffer[byte_index++] = (uint8_t)length_ext;
+ }
+ else if (length_ext_size == 2)
+ {
+ // uint16 in Network Byte Order.
+ p_buffer[byte_index++] = (uint8_t)((length_ext & 0xFF00) >> 8);
+ p_buffer[byte_index++] = (uint8_t)((length_ext & 0x00FF));
+ }
+
+ memcpy(&p_buffer[byte_index], p_option->p_data, p_option->length);
+ *byte_count = byte_index + p_option->length;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_message_decode(coap_message_t * p_message,
+ const uint8_t * p_raw_message,
+ uint16_t message_len)
+{
+ NULL_PARAM_CHECK(p_message);
+ NULL_PARAM_CHECK(p_raw_message);
+
+ // Check that the raw message contains the mandatory header.
+ if (message_len < 4)
+ {
+ return (NRF_ERROR_INVALID_LENGTH | IOT_COAP_ERR_BASE);
+ }
+
+ // Parse the content of the raw message buffer.
+ uint16_t byte_index = 0;
+
+ // Parse the 4 byte CoAP header.
+ p_message->header.version = (p_raw_message[byte_index] >> 6);
+ p_message->header.type = (coap_msg_type_t)((p_raw_message[byte_index] >> 4) & 0x03);
+ p_message->header.token_len = (p_raw_message[byte_index] & 0x0F);
+ byte_index++;
+
+ p_message->header.code = (coap_msg_code_t)p_raw_message[byte_index];
+ byte_index++;
+
+ p_message->header.id = p_raw_message[byte_index++] << 8;
+ p_message->header.id += p_raw_message[byte_index++];
+
+ // Parse the token, if any.
+ for (uint8_t index = 0; (byte_index < message_len) && (index < p_message->header.token_len); index++)
+ {
+ p_message->token[index] = p_raw_message[byte_index++];
+ }
+
+ p_message->options_count = 0;
+ p_message->options_delta = 0;
+
+ // Parse the options if any.
+ while ((byte_index < message_len) && (p_raw_message[byte_index] != COAP_PAYLOAD_MARKER))
+ {
+
+ uint32_t err_code;
+ uint16_t byte_count = 0;
+
+ err_code = decode_option(&p_raw_message[byte_index], p_message, &byte_count);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ p_message->options_count += 1;
+
+ byte_index += byte_count;
+ }
+
+ // If there any more bytes to parse this would be the payload.
+ if (byte_index < message_len)
+ {
+ // Verify that we have a payload marker.
+ if (p_raw_message[byte_index] == COAP_PAYLOAD_MARKER)
+ {
+ byte_index++;
+ }
+ else
+ {
+ return COAP_MESSAGE_INVALID_CONTENT;
+ }
+
+ p_message->payload_len = message_len - byte_index;
+ p_message->p_payload = (uint8_t *)&p_raw_message[byte_index];
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t coap_message_encode(coap_message_t * p_message,
+ uint8_t * p_buffer,
+ uint16_t * p_length)
+{
+ NULL_PARAM_CHECK(p_length);
+ NULL_PARAM_CHECK(p_message);
+
+ // calculated size
+ uint16_t total_packet_size = 4;
+
+ if (p_message->payload_len > 0)
+ {
+ total_packet_size += p_message->payload_len;
+ total_packet_size += COAP_PAYLOAD_MARKER_SIZE;
+ }
+
+ if (p_message->header.token_len > 8)
+ {
+ return (NRF_ERROR_INVALID_DATA | IOT_COAP_ERR_BASE);
+ }
+ total_packet_size += p_message->header.token_len;
+ total_packet_size += p_message->options_len;
+
+ // If this was a length check, return after setting the length in the output parameter.
+ if (*p_length == 0)
+ {
+ *p_length = total_packet_size;
+ return NRF_SUCCESS;
+ }
+
+ // Check that the buffer provided is sufficient.
+ if (*p_length < total_packet_size)
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ if (((p_message->payload_len > 0 && p_message->p_payload == NULL)) ||
+ (p_buffer == NULL))
+ {
+ return COAP_MESSAGE_ERROR_NULL;
+ }
+
+ // Start filling the bytes.
+ uint16_t byte_index = 0;
+
+ // TODO: Verify the values of the header fields.
+ // if (version > 1)
+ // if (p_message->type > COAP_TYPE_RST)
+ // if (p_message->token_len > 8)
+
+
+ p_buffer[byte_index] = (((p_message->header.version & 0x3) << 6) | ((p_message->header.type & 0x3) << 4)) | (p_message->header.token_len & 0x0F);
+ byte_index++;
+
+ p_buffer[byte_index] = p_message->header.code;
+ byte_index++;
+
+ p_buffer[byte_index++] = (p_message->header.id & 0xFF00) >> 8;
+ p_buffer[byte_index++] = (p_message->header.id & 0x00FF);
+
+ memcpy(&p_buffer[byte_index], p_message->token, p_message->header.token_len);
+ byte_index += p_message->header.token_len;
+
+ //memcpy(&p_buffer[byte_index], &p_message->p_data[0], p_message->options_len);
+ for (uint8_t i = 0; i < p_message->options_count; i++)
+ {
+ uint32_t err_code;
+
+ uint16_t byte_count = 0;
+ err_code = encode_option(&p_buffer[byte_index], &p_message->options[i], &byte_count);
+ if (err_code == NRF_SUCCESS)
+ {
+ byte_index += byte_count;
+ }
+ else
+ {
+ // Throw an error.
+ }
+ }
+
+ if (p_message->payload_len > 0 && p_message->p_payload != NULL)
+ {
+ p_buffer[byte_index++] = 0xFF;
+ memcpy(&p_buffer[byte_index], p_message->p_payload, p_message->payload_len);
+ }
+
+ *p_length = total_packet_size;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_message_opt_empty_add(coap_message_t * p_message, uint16_t option_num)
+{
+ OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
+
+ uint32_t err_code;
+ uint16_t encoded_len = 0;
+ uint8_t current_option_index = p_message->options_count;
+
+ p_message->options[current_option_index].number = option_num - p_message->options_delta;
+ p_message->options[current_option_index].length = encoded_len;
+
+ // Set accumulated option delta for next option.
+ p_message->options_delta = option_num;
+
+ // Calculate option size
+ uint16_t option_byte_count = 0;
+
+ // do a length check to encode_option to get the header length.
+ err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
+
+ // Accumulate expected size of all options with headers.
+ p_message->options_len += option_byte_count;
+
+ p_message->options_count += 1;
+
+ return err_code;
+}
+
+uint32_t coap_message_opt_uint_add(coap_message_t * p_message,
+ uint16_t option_num,
+ uint32_t data)
+{
+ OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
+
+ uint32_t err_code;
+ uint16_t encoded_len = p_message->data_len - p_message->options_offset;
+ uint8_t current_option_index = p_message->options_count;
+ uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset];
+
+ // If the value of the option is 0, do not encode the 0, as this can be omitted. (RFC7252 3.2)
+ if (data == 0)
+ {
+ encoded_len = 0;
+ }
+ else
+ {
+ err_code = coap_opt_uint_encode(p_next_option_data, &encoded_len, data);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ p_message->options[current_option_index].p_data = p_next_option_data;
+ p_message->options[current_option_index].number = option_num - p_message->options_delta;
+ p_message->options[current_option_index].length = encoded_len;
+
+ // Set accumulated option delta for next option.
+ p_message->options_delta = option_num;
+
+ // Calculate option size.
+ uint16_t option_byte_count = 0;
+
+ // Do a length check to encode_option to get the header length.
+ err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
+
+ // Accumulate expected size of all options with headers.
+ p_message->options_len += option_byte_count;
+
+ p_message->options_count += 1;
+
+ // Increase the pointer offset for the next option data in the scratch buffer.
+ p_message->options_offset += encoded_len;
+
+ return err_code;
+}
+
+uint32_t coap_message_opt_str_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length)
+{
+ OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
+
+ uint32_t err_code;
+
+ uint16_t encoded_len = length;
+ uint8_t current_option_index = p_message->options_count;
+ uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset];
+
+
+ err_code = coap_opt_string_encode(p_next_option_data, &encoded_len, p_data, length);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ p_message->options[current_option_index].p_data = p_next_option_data;
+ p_message->options[current_option_index].number = option_num - p_message->options_delta;
+ p_message->options[current_option_index].length = encoded_len;
+
+ // Set accumulated option delta for next option.
+ p_message->options_delta = option_num;
+
+ // Calculate option size
+ uint16_t option_byte_count = 0;
+
+ // do a length check to encode_option to get the header length.
+ err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
+
+ // Accumulate expected size of all options with headers.
+ p_message->options_len += option_byte_count;
+
+ p_message->options_count += 1;
+ p_message->options_offset += encoded_len;
+
+ return err_code;
+
+}
+
+uint32_t coap_message_opt_opaque_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length)
+{
+ OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
+
+ // Check if it is possible to add a new option of this length.
+ if ((p_message->data_len - p_message->options_offset) < length)
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ uint32_t err_code = NRF_SUCCESS;
+
+ uint16_t encoded_len = length;
+ uint8_t current_option_index = p_message->options_count;
+ uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset];
+
+
+ memcpy(p_next_option_data, p_data, encoded_len);
+
+ p_message->options[current_option_index].p_data = p_next_option_data;
+ p_message->options[current_option_index].number = option_num - p_message->options_delta;
+ p_message->options[current_option_index].length = encoded_len;
+
+ // Set accumulated option delta for next option.
+ p_message->options_delta = option_num;
+
+ // Calculate option size
+ uint16_t option_byte_count = 0;
+
+ // do a length check to encode_option to get the header length.
+ err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
+
+ // Accumulate expected size of all options with headers.
+ p_message->options_len += option_byte_count;
+
+ p_message->options_count += 1;
+ p_message->options_offset += encoded_len;
+
+ return err_code;
+}
+
+uint32_t coap_message_payload_set(coap_message_t * p_message,
+ void * p_payload,
+ uint16_t payload_len)
+{
+ // Check that there is available memory in the p_message->p_data scratch buffer.
+ if (payload_len > (COAP_MESSAGE_DATA_MAX_SIZE - p_message->options_offset))
+ {
+ return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE);
+ }
+
+ p_message->p_payload = &p_message->p_data[p_message->options_offset];
+ p_message->payload_len = payload_len;
+ memcpy(p_message->p_payload, p_payload, payload_len);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t coap_message_remote_addr_set(coap_message_t * p_message, coap_remote_t * p_address)
+{
+ memcpy(&p_message->remote, p_address, sizeof(coap_remote_t));
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_message_opt_index_get(uint8_t * p_index, coap_message_t * p_message, uint16_t option)
+{
+ NULL_PARAM_CHECK(p_index);
+ NULL_PARAM_CHECK(p_message);
+
+ uint8_t index;
+ for (index = 0; index < p_message->options_count; index++)
+ {
+ if (p_message->options[index].number == option)
+ {
+ *p_index = index;
+ return NRF_SUCCESS;
+ }
+ }
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+uint32_t coap_message_opt_present(coap_message_t * p_message, uint16_t option)
+{
+ NULL_PARAM_CHECK(p_message);
+
+ uint8_t index;
+ for (index = 0; index < p_message->options_count; index++)
+ {
+ if (p_message->options[index].number == option)
+ {
+ return NRF_SUCCESS;
+ }
+ }
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+static uint32_t bit_to_content_format(coap_content_type_t * p_ct, uint32_t bit)
+{
+ switch (bit)
+ {
+ case COAP_CT_MASK_PLAIN_TEXT:
+ *p_ct = COAP_CT_PLAIN_TEXT;
+ break;
+
+ case COAP_CT_MASK_APP_LINK_FORMAT:
+ *p_ct = COAP_CT_APP_LINK_FORMAT;
+ break;
+
+ case COAP_CT_MASK_APP_XML:
+ *p_ct = COAP_CT_APP_XML;
+ break;
+
+ case COAP_CT_MASK_APP_OCTET_STREAM:
+ *p_ct = COAP_CT_APP_OCTET_STREAM;
+ break;
+
+ case COAP_CT_MASK_APP_EXI:
+ *p_ct = COAP_CT_APP_EXI;
+ break;
+
+ case COAP_CT_MASK_APP_JSON:
+ *p_ct = COAP_CT_APP_JSON;
+ break;
+
+ default:
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+ return NRF_SUCCESS;
+}
+
+static uint32_t content_format_to_bit(coap_content_type_t ct)
+{
+ uint32_t mask = 0;
+ switch (ct)
+ {
+ case COAP_CT_PLAIN_TEXT:
+ mask = COAP_CT_MASK_PLAIN_TEXT;
+ break;
+
+ case COAP_CT_APP_LINK_FORMAT:
+ mask = COAP_CT_MASK_APP_LINK_FORMAT;
+ break;
+
+ case COAP_CT_APP_XML:
+ mask = COAP_CT_MASK_APP_XML;
+ break;
+
+ case COAP_CT_APP_OCTET_STREAM:
+ mask = COAP_CT_MASK_APP_OCTET_STREAM;
+ break;
+
+ case COAP_CT_APP_EXI:
+ mask = COAP_CT_MASK_APP_EXI;
+ break;
+
+ case COAP_CT_APP_JSON:
+ mask = COAP_CT_MASK_APP_JSON;
+ break;
+
+ default:
+ break;
+ }
+
+ return mask;
+}
+
+uint32_t coap_message_ct_mask_get(coap_message_t * p_message, uint32_t * p_mask)
+{
+ NULL_PARAM_CHECK(p_message);
+ NULL_PARAM_CHECK(p_mask);
+
+ (*p_mask) = 0;
+
+ for (uint8_t index = 0; index < p_message->options_count; index++)
+ {
+ if (p_message->options[index].number == COAP_OPT_CONTENT_FORMAT)
+ {
+ uint32_t value;
+ uint32_t err_code = coap_opt_uint_decode(&value,
+ p_message->options[index].length,
+ p_message->options[index].p_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ coap_content_type_t ct = (coap_content_type_t)value;
+ *p_mask |= content_format_to_bit(ct);
+ }
+ else
+ {
+ return err_code;
+ }
+ }
+ }
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_message_accept_mask_get(coap_message_t * p_message, uint32_t * p_mask)
+{
+ NULL_PARAM_CHECK(p_message);
+ NULL_PARAM_CHECK(p_mask);
+
+ (*p_mask) = 0;
+
+ for (uint8_t index = 0; index < p_message->options_count; index++)
+ {
+ if (p_message->options[index].number == COAP_OPT_ACCEPT)
+ {
+ uint32_t value;
+ uint32_t err_code = coap_opt_uint_decode(&value,
+ p_message->options[index].length,
+ p_message->options[index].p_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ coap_content_type_t ct = (coap_content_type_t)value;
+ (*p_mask) |= content_format_to_bit(ct);
+ }
+ else
+ {
+ return err_code;
+ }
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_message_ct_match_select(coap_content_type_t * p_ct, coap_message_t * p_message, coap_resource_t * p_resource)
+{
+ // Check ACCEPT options
+ uint32_t accept_mask = 0;
+ (void)coap_message_accept_mask_get(p_message, &accept_mask);
+
+ if (accept_mask == 0)
+ {
+ // Default to plain text if option not set.
+ accept_mask = COAP_CT_MASK_PLAIN_TEXT;
+ }
+
+ // Select the first common content-type between the resource and the CoAP client.
+ uint32_t common_ct = p_resource->ct_support_mask & accept_mask;
+ uint32_t bit_index;
+ for (bit_index = 0; bit_index < 32; bit_index++)
+ {
+ if (((common_ct >> bit_index) & 0x1 ) == 1)
+ {
+ break;
+ }
+ }
+
+ uint32_t err_code = bit_to_content_format(p_ct, 1 << bit_index);
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h
new file mode 100644
index 0000000..efd226b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.h
@@ -0,0 +1,158 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_message.h
+ *
+ * @defgroup iot_sdk_coap_msg CoAP Message
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief TODO.
+ */
+
+#ifndef COAP_MESSAGE_H__
+#define COAP_MESSAGE_H__
+
+#include <stdint.h>
+#include "coap_api.h"
+#include "coap_codes.h"
+#include "coap_transport.h"
+#include "coap_option.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COAP_PAYLOAD_MARKER 0xFF
+
+/**@brief Create a new CoAP message.
+ *
+ * @details The function will allocate memory for the message internally and return
+ * a CoAP message structure. The callback provided will be called if a matching
+ * message ID/Token occurs in a response message.
+ * @param[out] p_message Pointer to set the generated coap_message_t structure to.
+ * @param[in] p_init_config Initial configuration parameters of the message to generate.
+ *
+ * @retval NRF_SUCCESS If memory for the new message was allocated and the
+ * initialization of the message went successfully.
+ * @retval NRF_ERROR_NULL Either the message or init_config parameter was NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If port number in the port field is set to 0.
+ */
+uint32_t coap_message_create(coap_message_t * p_message, coap_message_conf_t * p_init_config);
+
+/**@brief Decode a message from a raw buffer.
+ *
+ * @details When the underlying transport layer receives a message, it has to
+ * be decoded into a CoAP message type structure. This functions returns
+ * a decoded message if decoding was successfully, or NULL otherwise.
+ *
+ * @param[out] p_message The generated coap_message_t after decoding the raw message.
+ * @param[in] p_raw_message Pointer to the encoded message memory buffer.
+ * @param[in] message_len Length of the p_raw_message.
+ *
+ * @retval NRF_SUCCESS If the decoding of the message succeeds.
+ * @retval NRF_ERROR_NULL If pointer to the p_message or p_raw_message were NULL.
+ * @retval NRF_ERROR_INVALID_LENGTH If the message is less than 4 bytes, not containing a
+ * full header.
+ * @retval COAP_MESSAGE_INVALID_CONTENT If the message could not be decoded successfully. This
+ * could happen if message length provided is larger than
+ * what is possible to decode (ex. missing payload marker).
+ *
+ */
+uint32_t coap_message_decode(coap_message_t * p_message,
+ const uint8_t * p_raw_message,
+ uint16_t message_len);
+
+/**@brief Encode a CoAP message into a byte buffer.
+ *
+ * @details This functions has two operations. One is the actual encoding into a
+ * byte buffer. The other is to query the size of a potential encoding.
+ * If p_buffer variable is omitted, the return value will be the size of a
+ * potential serialized message. This can be used to get some persistent memory from
+ * transport layer. The message have to be kept until all potential
+ * retransmissions has been attempted.
+ *
+ * The p_message can be deleted after this point if the function succeeds.
+ *
+ * @param[in] p_message Message to encode.
+ * @param[in] p_buffer Pointer to the byte buffer where to put the encoded message.
+ * @param[inout] p_length Length of the provided byte buffer passed in by reference.
+ * If the value 0 is supplied, the encoding will not take place,
+ * but only the dry run calculating the expected length of the
+ * encoded message.
+ *
+ * @retval NRF_SUCCESS If the encoding of the message succeeds.
+ * @retval NRF_ERROR_NULL If message or length parameter is NULL pointer.
+ * @retval NRF_ERROR_NO_MEM If the provided buffer is not sufficient for
+ * the encoded message.
+ * @retval COAP_MESSAGE_ERROR_NULL If the message has indicated the length of data,
+ * but memory pointer is NULL.
+ */
+uint32_t coap_message_encode(coap_message_t * p_message,
+ uint8_t * p_buffer,
+ uint16_t * p_length);
+
+/**@brief Get the content format mask of the message.
+ *
+ * @param[in] p_message Pointer to the message which to generate the content format mask from.
+ * Should not be NULL.
+ * @param[out] p_mask Value by reference to the variable to fill the result mask into.
+ *
+ * @retval NRF_SUCCESS If the mask could be generated.
+ * @retval NRF_ERROR_NULL If the message pointer or the mask pointer given was NULL.
+ */
+uint32_t coap_message_ct_mask_get(coap_message_t * p_message, uint32_t * p_mask);
+
+/**@brief Get the accept mask of the message.
+ *
+ * @param[in] p_message Pointer to the message which to generate the accept mask from.
+ * Should not be NULL.
+ * @param[out] p_mask Value by reference to the variable to fill the result mask into.
+ *
+ * @retval NRF_SUCCESS If the mask could be generated.
+ * @retval NRF_ERROR_NULL If the message pointer or the mask pointer given was NULL.
+ */
+uint32_t coap_message_accept_mask_get(coap_message_t * p_message, uint32_t * p_mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_MESSAGE_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c
new file mode 100644
index 0000000..b4c60aa
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.c
@@ -0,0 +1,688 @@
+/**
+ * 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 <string.h>
+
+#include "coap_observe_api.h"
+#include "coap_observe.h"
+#include "nrf_error.h"
+#include "iot_common.h"
+#include "sdk_common.h"
+#include "sdk_config.h"
+#include "coap.h"
+
+#if IOT_COAP_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME coapobs
+
+#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 COAP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define COAP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define COAP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define COAP_ENTRY() COAP_TRC(">> %s", __func__)
+#define COAP_EXIT() COAP_TRC("<< %s", __func__)
+
+#else // IOT_COAP_CONFIG_LOG_ENABLED
+
+#define COAP_TRC(...) /**< Disables traces. */
+#define COAP_DUMP(...) /**< Disables dumping of octet streams. */
+#define COAP_ERR(...) /**< Disables error logs. */
+
+#define COAP_ENTRY(...)
+#define COAP_EXIT(...)
+
+#endif // IOT_COAP_CONFIG_LOG_ENABLED
+
+#if (COAP_ENABLE_OBSERVE_SERVER == 1)
+static coap_observer_t m_observers[COAP_OBSERVE_MAX_NUM_OBSERVERS];
+
+static void observe_server_init(void)
+{
+ COAP_ENTRY();
+
+ // Loop through the observer array and clear the memory.
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++)
+ {
+ memset(&m_observers[i], 0, sizeof(coap_observer_t));
+ }
+
+ COAP_EXIT();
+}
+
+uint32_t internal_coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer)
+{
+ COAP_ENTRY();
+
+ NULL_PARAM_CHECK(p_handle);
+ NULL_PARAM_CHECK(p_observer);
+
+ NULL_PARAM_MEMBER_CHECK(p_observer->p_resource_of_interest);
+
+ // Check if there is already a registered observer in the list to be reused.
+ uint32_t handle;
+ uint32_t err_code = coap_observe_server_search(&handle,
+ &p_observer->remote,
+ p_observer->p_resource_of_interest);
+ if (err_code == NRF_SUCCESS)
+ {
+ memcpy(&m_observers[handle], p_observer, sizeof(coap_observer_t));
+ *p_handle = handle;
+ return NRF_SUCCESS;
+ }
+
+ // Check if there is an available spot in the observer list.
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++)
+ {
+ if (m_observers[i].p_resource_of_interest == NULL)
+ {
+ memcpy(&m_observers[i], p_observer, sizeof(coap_observer_t));
+
+ *p_handle = i;
+ return NRF_SUCCESS;
+ }
+ }
+
+
+ COAP_EXIT();
+
+ return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE);
+}
+
+
+uint32_t internal_coap_observe_server_unregister(uint32_t handle)
+{
+ COAP_ENTRY();
+
+ if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVERS)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ if (m_observers[handle].p_resource_of_interest == NULL)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ m_observers[handle].p_resource_of_interest = NULL;
+
+ COAP_EXIT();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t internal_coap_observe_server_search(uint32_t * p_handle,
+ coap_remote_t * p_observer_addr,
+ coap_resource_t * p_resource)
+{
+ NULL_PARAM_CHECK(p_handle);
+ NULL_PARAM_CHECK(p_observer_addr);
+ NULL_PARAM_CHECK(p_resource);
+
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++)
+ {
+ if (m_observers[i].p_resource_of_interest == p_resource)
+ {
+ if (m_observers[i].remote.port_number == p_observer_addr->port_number)
+ {
+ if (memcmp(p_observer_addr->addr, m_observers[i].remote.addr, sizeof(p_observer_addr->addr)) == 0)
+ {
+ *p_handle = i;
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+
+uint32_t internal_coap_observe_server_next_get(coap_observer_t ** pp_observer,
+ coap_observer_t * p_observer,
+ coap_resource_t * p_resource)
+{
+ NULL_PARAM_CHECK(p_resource);
+ NULL_PARAM_CHECK(pp_observer);
+
+ if (p_observer == NULL)
+ {
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++)
+ {
+ if (m_observers[i].p_resource_of_interest == p_resource)
+ {
+ (*pp_observer) = &m_observers[i];
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ uint32_t index_to_previous = (uint8_t)(((uint32_t)p_observer - (uint32_t)m_observers) / (uint32_t)sizeof(coap_observer_t));
+
+ for (uint32_t i = index_to_previous + 1; i < COAP_OBSERVE_MAX_NUM_OBSERVERS; i++)
+ {
+ if (m_observers[i].p_resource_of_interest == p_resource)
+ {
+ (*pp_observer) = &m_observers[i];
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ (*pp_observer) = NULL;
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+uint32_t internal_coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer)
+{
+ NULL_PARAM_CHECK(pp_observer);
+
+ if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVERS)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ if (m_observers[handle].p_resource_of_interest == NULL)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ *pp_observer = &m_observers[handle];
+ return NRF_SUCCESS;
+}
+#else
+#define observe_server_init(...)
+#endif
+
+#if (COAP_ENABLE_OBSERVE_CLIENT == 1)
+static coap_observable_t m_observables[COAP_OBSERVE_MAX_NUM_OBSERVABLES];
+
+static void observe_client_init(void)
+{
+ // Loop through the observable array and clear the memory.
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++)
+ {
+ memset(&m_observables[i], 0, sizeof(coap_observable_t));
+ }
+}
+
+
+uint32_t internal_coap_observe_client_register(uint32_t * p_handle,
+ coap_observable_t * p_observable)
+{
+ COAP_ENTRY();
+
+ NULL_PARAM_CHECK(p_handle);
+ NULL_PARAM_CHECK(p_observable);
+
+ NULL_PARAM_MEMBER_CHECK(p_observable->response_callback);
+
+ // Check if there is an available spot in the observer list.
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++)
+ {
+ if (m_observables[i].response_callback == NULL)
+ {
+ memcpy(&m_observables[i], p_observable, sizeof(coap_observable_t));
+ *p_handle = i;
+ return NRF_SUCCESS;
+ }
+ }
+
+ COAP_EXIT();
+
+ return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE);
+}
+
+
+uint32_t internal_coap_observe_client_unregister(uint32_t handle)
+{
+ COAP_ENTRY();
+
+ if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVABLES)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ if (m_observables[handle].response_callback == NULL)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ m_observables[handle].response_callback = NULL;
+
+ COAP_EXIT();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t internal_coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len)
+{
+ NULL_PARAM_CHECK(p_handle);
+ NULL_PARAM_CHECK(p_token);
+
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++)
+ {
+ if ((m_observables[i].response_callback != NULL) &&
+ (0 != m_observables[i].token_len) &&
+ (memcmp(m_observables[i].token, p_token, m_observables[i].token_len) == 0))
+ {
+ *p_handle = i;
+ return NRF_SUCCESS;
+ }
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+
+uint32_t internal_coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable)
+{
+ NULL_PARAM_CHECK(pp_observable);
+
+ if (handle >= COAP_OBSERVE_MAX_NUM_OBSERVABLES)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ if (m_observables[handle].response_callback == NULL)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ *pp_observable = &m_observables[handle];
+
+ return NRF_SUCCESS;
+}
+
+uint32_t internal_coap_observe_client_next_get(coap_observable_t ** pp_observable,
+ uint32_t * p_handle,
+ coap_observable_t * p_observable)
+{
+ NULL_PARAM_CHECK(pp_observable);
+
+ if (p_observable == NULL)
+ {
+ for (uint32_t i = 0; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++)
+ {
+ if (m_observables[i].response_callback != NULL)
+ {
+ (*pp_observable) = &m_observables[i];
+ (*p_handle) = i;
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ uint32_t index_to_previous = (uint8_t)(((uint32_t)p_observable - (uint32_t)m_observables) / (uint32_t)sizeof(coap_observable_t));
+
+ for (uint32_t i = index_to_previous + 1; i < COAP_OBSERVE_MAX_NUM_OBSERVABLES; i++)
+ {
+ if (m_observables[i].response_callback != NULL)
+ {
+ (*pp_observable) = &m_observables[i];
+ (*p_handle) = i;
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ (*pp_observable) = NULL;
+
+ COAP_MUTEX_UNLOCK();
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+static uint32_t observe_opt_present(coap_message_t * p_message)
+{
+ uint8_t index;
+ for (index = 0; index < p_message->options_count; index++)
+ {
+ if (p_message->options[index].number == COAP_OPT_OBSERVE)
+ {
+ return NRF_SUCCESS;
+ }
+ }
+ return NRF_ERROR_NOT_FOUND;
+}
+
+static void set_max_age(coap_observable_t * observable, coap_message_t * p_response)
+{
+ uint8_t index;
+ for (index = 0; index < p_response->options_count; index++)
+ {
+ if (p_response->options[index].number == COAP_OPT_MAX_AGE)
+ {
+ uint32_t max_age;
+ observable->max_age = coap_opt_uint_decode(&max_age,
+ p_response->options[index].length,
+ p_response->options[index].p_data);
+ observable->max_age = max_age;
+ return;
+ }
+ }
+
+ // Max-Age option is not present, set default value to 60.
+ observable->max_age = 60;
+}
+
+void coap_observe_client_send_handle(coap_message_t * p_request)
+{
+ COAP_ENTRY();
+
+ if (p_request->header.code == COAP_CODE_GET)
+ {
+ uint32_t observe_option = 0;
+ if (observe_opt_present(p_request) == NRF_SUCCESS)
+ {
+ // Locate option and check value.
+ uint8_t index;
+ for (index = 0; index < p_request->options_count; index++)
+ {
+ if (p_request->options[index].number == COAP_OPT_OBSERVE)
+ {
+ uint32_t err_code = coap_opt_uint_decode(&observe_option,
+ p_request->options[index].length,
+ p_request->options[index].p_data);
+ if (err_code != NRF_SUCCESS)
+ {
+ return;
+ }
+ break;
+ }
+ }
+ }
+
+ if (observe_option == 1)
+ {
+ // Un-register observable instance.
+ uint32_t handle;
+ uint32_t err_code = internal_coap_observe_client_search(&handle,
+ p_request->token,
+ p_request->header.token_len);
+ if (err_code == NRF_SUCCESS)
+ {
+ (void)internal_coap_observe_client_unregister(handle);
+ COAP_TRC("OBSERVE=1 in request, client_unregister handle: %i", handle);
+
+ }
+ }
+ }
+
+ COAP_EXIT();
+}
+
+void coap_observe_client_response_handle(coap_message_t * p_response, coap_queue_item_t * p_item)
+{
+ COAP_ENTRY();
+
+ if (observe_opt_present(p_response) == NRF_SUCCESS)
+ {
+ if (p_item == NULL)
+ {
+ // Search for the token in the observable list.
+ uint32_t handle;
+ uint32_t err_code = internal_coap_observe_client_search(&handle, p_response->token, p_response->header.token_len);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Fetch the observable.
+ coap_observable_t * p_observable;
+ err_code = internal_coap_observe_client_get(handle, &p_observable);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Update max-age to the newly recieved message.
+ set_max_age(p_observable, p_response);
+
+ COAP_MUTEX_UNLOCK();
+
+ // Callback to the application.
+ p_observable->response_callback(NRF_SUCCESS, NULL, p_response);
+
+ COAP_MUTEX_LOCK();
+
+ COAP_TRC("Notification received on handle: %i", handle);
+
+ #ifdef COAP_AUTOMODE
+ if (p_response->header.type == COAP_TYPE_CON)
+ {
+ // Reply an ACK upon CON message.
+ }
+ else if (p_response->header.type == COAP_TYPE_RST)
+ {
+ // Remove observable from list.
+ }
+ #endif
+ }
+ else
+ {
+ #ifdef COAP_AUTOMODE
+ if (p_response->header.type == COAP_TYPE_CON)
+ {
+ // Reply reset upon CON message when observer is not located.
+ }
+ #endif
+ }
+ }
+ else
+ {
+ // Send RST message back to server to indicate there is no one listening.
+ }
+ }
+ else // p_item set.
+ {
+ // If there is no observable instance created yet for thit token, add it.
+ uint32_t handle;
+ uint32_t err_code = internal_coap_observe_client_search(&handle, p_response->token, p_response->header.token_len);
+ if (err_code == (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE))
+ {
+ // If the response is a valid response, add the observable resource.
+ if (p_response->header.code == COAP_CODE_205_CONTENT)
+ {
+ coap_observable_t observable;
+ // Token Length.
+ observable.token_len = p_response->header.token_len;
+ // Remote.
+ memcpy(&observable.remote, &p_response->remote, sizeof(coap_remote_t));
+ // Token.
+ memcpy(observable.token, p_response->token, observable.token_len);
+ // Callback to be called upon notification.
+ observable.response_callback = p_item->callback;
+
+ // Update max-age to the newly recieved message.
+ set_max_age(&observable, p_response);
+
+ // Register the observable.
+ uint32_t observable_resource_handle;
+ (void)internal_coap_observe_client_register(&observable_resource_handle, &observable);
+ // TODO: error check
+
+ COAP_TRC("Subscription response received, client_register handle: %i", observable_resource_handle);
+ }
+ }
+ }
+ }
+ else // COAP_OPT_OBSERVE not present
+ {
+ uint32_t handle;
+ uint32_t err_code = internal_coap_observe_client_search(&handle, p_response->token, p_response->header.token_len);
+ if (err_code == NRF_SUCCESS)
+ {
+ (void)internal_coap_observe_client_unregister(handle);
+ COAP_TRC("OBSERVE not present in notification, client_unregister handle: %i", handle);
+ }
+ }
+
+ COAP_EXIT();
+}
+#else
+#define observe_client_init(...)
+#endif
+
+void internal_coap_observe_init(void)
+{
+ observe_server_init();
+ observe_client_init();
+}
+
+#if (COAP_ENABLE_OBSERVE_SERVER == 1)
+
+uint32_t coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_server_register(p_handle, p_observer);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_server_unregister(uint32_t handle)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_server_unregister(handle);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_server_search(uint32_t * p_handle, coap_remote_t * p_observer_addr, coap_resource_t * p_resource)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_server_search(p_handle, p_observer_addr, p_resource);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_server_next_get(coap_observer_t ** pp_observer, coap_observer_t * p_observer, coap_resource_t * p_resource)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_server_next_get(pp_observer, p_observer, p_resource);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_server_get(handle, pp_observer);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+#endif // COAP_ENABLE_OBSERVE_SERVER = 1
+
+#if (COAP_ENABLE_OBSERVE_CLIENT == 1)
+
+uint32_t coap_observe_client_register(uint32_t * p_handle, coap_observable_t * p_observable)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_client_register(p_handle, p_observable);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_client_unregister(uint32_t handle)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_client_unregister(handle);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_client_search(p_handle, p_token, token_len);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_client_get(handle, pp_observable);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t coap_observe_client_next_get(coap_observable_t ** pp_observable, uint32_t * p_handle, coap_observable_t * p_observable)
+{
+ COAP_MUTEX_UNLOCK();
+
+ uint32_t err_code = internal_coap_observe_client_next_get(pp_observable, p_handle, p_observable);
+
+ COAP_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+#endif // COAP_ENABLE_OBSERVE_CLIENT == 1
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h
new file mode 100644
index 0000000..bb72b89
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe.h
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file coap_observe.h
+ *
+ * @defgroup iot_sdk_coap_observe CoAP Observe
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief Internal API of Nordic's CoAP Observe implementation.
+ */
+#ifndef COAP_OBSERVE_H__
+#define COAP_OBSERVE_H__
+
+#include <stdint.h>
+
+#include "coap_observe_api.h"
+#include "coap_api.h"
+#include "coap_queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@cond NO_DOXYGEN */
+
+/**@brief Register a new observer.
+ *
+ * @param[out] p_handle Handle to the observer instance registered. Returned by reference.
+ * Should not be NULL.
+ * @param[in] p_observer Pointer to the observer structure to register. The data will be
+ * copied. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the observer was registered successfully.
+ * @retval NRF_ERROR_NO_MEM If the observer could not be added to the list.
+ * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer.
+ */
+uint32_t internal_coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer);
+
+/**@brief Unregister an observer.
+ *
+ * @details Unregister the observer and clear the memory used by this instance.
+ *
+ * @param[in] handle Handle to the observer instance registered.
+ *
+ * @retval NRF_SUCCESS If the observer was successfully unregistered.
+ * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observer list.
+ */
+uint32_t internal_coap_observe_server_unregister(uint32_t handle);
+
+/**@brief Search the observer list for an observer matching remote address and subject given.
+ *
+ * @param[out] p_handle Handle to the observer instance registered. Returned by reference.
+ * Should not be NULL.
+ * @param[in] p_observer_addr Pointer to an address structure giving remote address of the observer and port number.
+ * Should not be NULL.
+ * @param[in] p_resource Pointer to the resource the observer is registered to. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observer was found in the observer list.
+ * @retval NRF_ERROR_NULL If one of the pointers are NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observer was not found.
+ */
+uint32_t internal_coap_observe_server_search(uint32_t * p_handle, coap_remote_t * p_observer_addr, coap_resource_t * p_resource);
+
+/**@brief Iterate through observers subscribing to a specific resource.
+ *
+ * @param[out] pp_observer Pointer to be filled by the search function upon finding the next observer starting from
+ * from the p_observer pointer provided. Should not be NULL.
+ * @param[in] p_observer Pointer to the observer where to start the search.
+ * @param[in] p_resource Pointer to the resource of interest. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observer was found.
+ * @retval NRF_ERROR_NULL If pp_observer or p_resource pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If next observer was not found.
+ */
+uint32_t internal_coap_observe_server_next_get(coap_observer_t ** pp_observer, coap_observer_t * p_observer, coap_resource_t * p_resource);
+
+/**@brief Retrieve the observer based on handle.
+ *
+ * @param[in] handle Handle to the coap_observer_t instance.
+ * @param[out] pp_observer Pointer to an observer return by reference.
+ * Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observer was found in the observer list.
+ * @retval NRF_ERROR_NULL If pp_observer pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observer associated with the handle was not found.
+ */
+uint32_t internal_coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer);
+
+/**@brief Register a new observable resource.
+ *
+ * @param[out] p_handle Handle to the observable resource instance registered. Returned by
+ * reference. Should not be NULL.
+ * @param[in] p_observable Pointer to a observable resource structure to register. The structure
+ * will be copied. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the observable resource was registered successfully.
+ * @retval NRF_ERROR_NO_MEM If the observable resource could not be added to the list.
+ * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer.
+ */
+uint32_t internal_coap_observe_client_register(uint32_t * p_handle, coap_observable_t * p_observable);
+
+/**@brief Unregister an observable resource.
+ *
+ * @details Unregister the observable resource and clear the memory used by this instance.
+ *
+ * @param[in] handle Handle to the observable resource instance registered.
+ *
+ * @retval NRF_SUCCESS If the observable resource was successfully unregistered.
+ * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observable
+ * resource list.
+ */
+uint32_t internal_coap_observe_client_unregister(uint32_t handle);
+
+/**@brief Search for a observable resource instance by token.
+ *
+ * @param[out] p_handle Handle to the observable resource instance registered. Returned by
+ * reference. Should not be NULL.
+ * @param[in] p_token Pointer to the byte array holding the token id. Should not be NULL.
+ * @param[in] token_len Length of the token.
+ *
+ * @retval NRF_SUCCESS If observable resource was found in the observable
+ * resource list.
+ * @retval NRF_ERROR_NULL If one of the pointers are NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observable resource was not found in the observable
+ * resource list.
+ */
+uint32_t internal_coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len);
+
+/**@brief Retrieve the observable resource based on handle.
+ *
+ * @param[in] handle Handle to the coap_observable_t instance.
+ * @param[out] pp_observable Pointer to an observable resource return by reference.
+ * Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observable resource was found in the observable
+ * resource list.
+ * @retval NRF_ERROR_NULL If pp_observable pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observable resource associated with the handle
+ * was not found.
+ */
+uint32_t internal_coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable);
+
+/**@brief Iterate through observable resources.
+ *
+ * @param[out] pp_observable Pointer to be filled by the search function upon finding the next
+ * observable resource starting from from the pointer provided.
+ * Should not be NULL.
+ * @param[out] p_handle Handler to the observable resource found returned by reference. Should
+ * not be NULL.
+ * @param[in] p_observable Pointer to the observable resource where to start the search.
+ *
+ * @retval NRF_SUCCESS If observer was found.
+ * @retval NRF_ERROR_NULL If pp_observer or p_observer pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If next observer was not found.
+ */
+uint32_t internal_coap_observe_client_next_get(coap_observable_t ** pp_observable, uint32_t * p_handle, coap_observable_t * p_observable);
+
+
+#if (COAP_ENABLE_OBSERVE_SERVER == 1) || (COAP_ENABLE_OBSERVE_CLIENT == 1)
+
+/**@brief Internal function to initilize observer (client) and observable (server) lists.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ */
+void internal_coap_observe_init(void);
+
+#else // COAP_ENABLE_OBSERVE_SERVER || COAP_ENABLE_OBSERVE_CLIENT
+
+#define internal_coap_observe_init(...)
+
+#endif // COAP_ENABLE_OBSERVE_SERVER || COAP_ENABLE_OBSERVE_CLIENT
+
+#if (COAP_ENABLE_OBSERVE_CLIENT == 1)
+
+/**@brief Observe client function to be run when sending requests.
+ *
+ * @details The function will peek into the outgoing messages to see if any actions regarding
+ * subscription to observable resources has to be done.
+ *
+ * @param[in] p_request Pointer to the outgoing request.
+ */
+void coap_observe_client_send_handle(coap_message_t * p_request);
+
+/**@brief Observe client function to be run when response message has been received.
+ *
+ * @details The function will register and unregister observable resources based on the received
+ * response messages. Upon a notification max-age values will be updated, and the correct
+ * response callback will be called. If a notification is terminated by the peer, the function
+ * will automatically terminate the subscription from the client by unregistering the
+ * observable resource.
+ *
+ * @param[in] p_response Pointer to the response message received.
+ * @param[in] p_item Pointer to the queued element of the outgoing request.
+ */
+void coap_observe_client_response_handle(coap_message_t * p_response, coap_queue_item_t * p_item);
+
+#else // COAP_ENABLE_OBSERVE_CLIENT
+
+#define coap_observe_client_send_handle(...)
+#define coap_observe_client_response_handle(...)
+
+#endif // COAP_ENABLE_OBSERVE_CLIENT
+
+/**@endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_OBSERVE_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h
new file mode 100644
index 0000000..3075e88
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_observe_api.h
@@ -0,0 +1,222 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file coap_observe_api.h
+ *
+ * @defgroup iot_sdk_coap_observe CoAP Observe
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief Public API of Nordic's CoAP Observe implementation.
+ */
+#ifndef COAP_OBSERVE_API_H__
+#define COAP_OBSERVE_API_H__
+
+#include <stdint.h>
+#include "coap_api.h"
+#include "coap_transport.h"
+#include "coap_queue.h"
+#include "compiler_abstraction.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COAP_OPT_OBSERVE 6 /**< Observe option number. */
+
+/**@brief Struct for CoAP Server for holding an instance of a remote observer. */
+typedef struct
+{
+ coap_remote_t remote; /**< Remote address and port number. */
+ uint8_t token[8]; /**< Message Token ID. */
+ uint8_t token_len; /**< Length of the token. */
+ coap_content_type_t ct; /**< Content type to use when sending notifications. */
+ coap_resource_t * p_resource_of_interest; /**< Pointer to the resource of interest. */
+} coap_observer_t;
+
+/**@brief Struct for CoAP Client for holding an instance of a remote observable resource. */
+typedef struct
+{
+ coap_remote_t remote; /**< Remote address and port number. */
+ uint8_t token[8]; /**< Message Token ID. */
+ uint8_t token_len; /**< Length of the token. */
+ coap_response_callback_t response_callback; /**< Function callback set by the application to be called when a notifications has been received. Should be set by the application. */
+ uint32_t max_age; /**< Max-Age of the observable resources value. If timed out, the value is no longer valid as a representation of the observable resource. */
+} coap_observable_t;
+
+
+/**@brief Register a new observer.
+ *
+ * @param[out] p_handle Handle to the observer instance registered. Returned by reference.
+ * Should not be NULL.
+ * @param[in] p_observer Pointer to the observer structure to register. The data will be
+ * copied. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the observer was registered successfully.
+ * @retval NRF_ERROR_NO_MEM If the observer could not be added to the list.
+ * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer.
+ */
+uint32_t coap_observe_server_register(uint32_t * p_handle, coap_observer_t * p_observer);
+
+/**@brief Unregister an observer.
+ *
+ * @details Unregister the observer and clear the memory used by this instance.
+ *
+ * @param[in] handle Handle to the observer instance registered.
+ *
+ * @retval NRF_SUCCESS If the observer was successfully unregistered.
+ * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observer list.
+ */
+uint32_t coap_observe_server_unregister(uint32_t handle);
+
+/**@brief Search the observer list for an observer matching remote address and subject given.
+ *
+ * @param[out] p_handle Handle to the observer instance registered. Returned by reference.
+ * Should not be NULL.
+ * @param[in] p_observer_addr Pointer to an address structure giving remote address of the observer and port number.
+ * Should not be NULL.
+ * @param[in] p_resource Pointer to the resource the observer is registered to. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observer was found in the observer list.
+ * @retval NRF_ERROR_NULL If one of the pointers are NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observer was not found.
+ */
+uint32_t coap_observe_server_search(uint32_t * p_handle, coap_remote_t * p_observer_addr, coap_resource_t * p_resource);
+
+/**@brief Iterate through observers subscribing to a specific resource.
+ *
+ * @param[out] pp_observer Pointer to be filled by the search function upon finding the next observer starting from
+ * from the p_observer pointer provided. Should not be NULL.
+ * @param[in] p_observer Pointer to the observer where to start the search.
+ * @param[in] p_resource Pointer to the resource of interest. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observer was found.
+ * @retval NRF_ERROR_NULL If pp_observer or p_resource pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If next observer was not found.
+ */
+uint32_t coap_observe_server_next_get(coap_observer_t ** pp_observer, coap_observer_t * p_observer, coap_resource_t * p_resource);
+
+/**@brief Retrieve the observer based on handle.
+ *
+ * @param[in] handle Handle to the coap_observer_t instance.
+ * @param[out] pp_observer Pointer to an observer return by reference.
+ * Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observer was found in the observer list.
+ * @retval NRF_ERROR_NULL If pp_observer pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observer associated with the handle was not found.
+ */
+uint32_t coap_observe_server_get(uint32_t handle, coap_observer_t ** pp_observer);
+
+/**@brief Register a new observable resource.
+ *
+ * @param[out] p_handle Handle to the observable resource instance registered. Returned by
+ * reference. Should not be NULL.
+ * @param[in] p_observable Pointer to a observable resource structure to register. The structure
+ * will be copied. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the observable resource was registered successfully.
+ * @retval NRF_ERROR_NO_MEM If the observable resource could not be added to the list.
+ * @retval NRF_ERROR_NULL If one of the parameters is a NULL pointer.
+ */
+uint32_t coap_observe_client_register(uint32_t * p_handle, coap_observable_t * p_observable);
+
+/**@brief Unregister an observable resource.
+ *
+ * @details Unregister the observable resource and clear the memory used by this instance.
+ *
+ * @param[in] handle Handle to the observable resource instance registered.
+ *
+ * @retval NRF_SUCCESS If the observable resource was successfully unregistered.
+ * @retval NRF_ERROR_NOT_FOUND If the given handle was not found in the observable
+ * resource list.
+ */
+uint32_t coap_observe_client_unregister(uint32_t handle);
+
+/**@brief Search for a observable resource instance by token.
+ *
+ * @param[out] p_handle Handle to the observable resource instance registered. Returned by
+ * reference. Should not be NULL.
+ * @param[in] p_token Pointer to the byte array holding the token id. Should not be NULL.
+ * @param[in] token_len Length of the token.
+ *
+ * @retval NRF_SUCCESS If observable resource was found in the observable
+ * resource list.
+ * @retval NRF_ERROR_NULL If one of the pointers are NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observable resource was not found in the observable
+ * resource list.
+ */
+uint32_t coap_observe_client_search(uint32_t * p_handle, uint8_t * p_token, uint16_t token_len);
+
+/**@brief Retrieve the observable resource based on handle.
+ *
+ * @param[in] handle Handle to the coap_observable_t instance.
+ * @param[out] pp_observable Pointer to an observable resource return by reference.
+ * Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If observable resource was found in the observable
+ * resource list.
+ * @retval NRF_ERROR_NULL If pp_observable pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If observable resource associated with the handle
+ * was not found.
+ */
+uint32_t coap_observe_client_get(uint32_t handle, coap_observable_t ** pp_observable);
+
+/**@brief Iterate through observable resources.
+ *
+ * @param[out] pp_observable Pointer to be filled by the search function upon finding the next
+ * observable resource starting from from the pointer provided.
+ * Should not be NULL.
+ * @param[out] p_handle Handler to the observable resource found returned by reference. Should
+ * not be NULL.
+ * @param[in] p_observable Pointer to the observable resource where to start the search.
+ *
+ * @retval NRF_SUCCESS If observer was found.
+ * @retval NRF_ERROR_NULL If pp_observer or p_observer pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If next observer was not found.
+ */
+uint32_t coap_observe_client_next_get(coap_observable_t ** pp_observable, uint32_t * p_handle, coap_observable_t * p_observable);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_OBSERVE_API_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c
new file mode 100644
index 0000000..0ae74be
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.c
@@ -0,0 +1,182 @@
+/**
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "coap_option.h"
+#include "iot_common.h"
+
+#if (COAP_DISABLE_API_PARAM_CHECK == 0)
+
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
+ }
+
+#else
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // COAP_DISABLE_API_PARAM_CHECK
+
+uint32_t coap_opt_string_encode(uint8_t * p_encoded, uint16_t * p_length, uint8_t * p_string, uint16_t str_len)
+{
+ NULL_PARAM_CHECK(p_encoded);
+ NULL_PARAM_CHECK(p_length);
+ NULL_PARAM_CHECK(p_string);
+
+ if (str_len > *p_length)
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ memcpy(p_encoded, p_string, str_len);
+
+ *p_length = str_len;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_opt_string_decode(uint8_t * p_string, uint16_t * p_length, uint8_t * p_encoded)
+{
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_opt_uint_encode(uint8_t * p_encoded, uint16_t * p_length, uint32_t data)
+{
+ NULL_PARAM_CHECK(p_encoded);
+ NULL_PARAM_CHECK(p_length);
+
+ uint16_t byte_index = 0;
+
+ if (data <= UINT8_MAX)
+ {
+ if (*p_length < sizeof(uint8_t))
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ p_encoded[byte_index++] = (uint8_t)data;
+ }
+ else if (data <= UINT16_MAX)
+ {
+ if (*p_length < sizeof(uint16_t))
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ p_encoded[byte_index++] = (uint8_t)((data & 0xFF00) >> 8);
+ p_encoded[byte_index++] = (uint8_t)(data & 0x00FF);
+ }
+ else
+ {
+ if (*p_length < sizeof(uint32_t))
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ p_encoded[byte_index++] = (uint8_t)((data & 0xFF000000) >> 24);
+ p_encoded[byte_index++] = (uint8_t)((data & 0x00FF0000) >> 16);
+ p_encoded[byte_index++] = (uint8_t)((data & 0x0000FF00) >> 8);
+ p_encoded[byte_index++] = (uint8_t)(data & 0x000000FF);
+ }
+
+
+
+ *p_length = byte_index;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_opt_uint_decode(uint32_t * p_data, uint16_t length, uint8_t * p_encoded)
+{
+ NULL_PARAM_CHECK(p_data);
+ NULL_PARAM_CHECK(p_encoded);
+
+ uint8_t byte_index = 0;
+ switch (length)
+ {
+ case 0:
+ {
+ *p_data = 0;
+ }
+ break;
+
+ case 1:
+ {
+ *p_data = 0;
+ *p_data |= p_encoded[byte_index++];
+ }
+ break;
+
+ case 2:
+ {
+ *p_data = 0;
+ *p_data |= (p_encoded[byte_index++] << 8);
+ *p_data |= (p_encoded[byte_index++]);
+ }
+ break;
+
+ case 3:
+ {
+ *p_data = 0;
+ *p_data |= (p_encoded[byte_index++] << 16);
+ *p_data |= (p_encoded[byte_index++] << 8);
+ *p_data |= (p_encoded[byte_index++]);
+ }
+ break;
+
+ case 4:
+ {
+ *p_data = 0;
+ *p_data |= (p_encoded[byte_index++] << 24);
+ *p_data |= (p_encoded[byte_index++] << 16);
+ *p_data |= (p_encoded[byte_index++] << 8);
+ *p_data |= (p_encoded[byte_index++]);
+ }
+ break;
+
+ default:
+ return (NRF_ERROR_INVALID_LENGTH | IOT_COAP_ERR_BASE);
+ }
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h
new file mode 100644
index 0000000..3d5c5d9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_option.h
@@ -0,0 +1,161 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_option.h
+ *
+ * @defgroup iot_sdk_coap_option CoAP Option
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief Nordic's CoAP Option APIs.
+ */
+
+#ifndef COAP_OPTION_H__
+#define COAP_OPTION_H__
+
+/*
+ +-----+---+---+---+---+----------------+--------+--------+----------+
+ | No. | C | U | N | R | Name | Format | Length | Default |
+ +-----+---+---+---+---+----------------+--------+--------+----------+
+ | 1 | x | | | x | If-Match | opaque | 0-8 | (none) |
+ | 3 | x | x | - | | Uri-Host | string | 1-255 | (see |
+ | | | | | | | | | below) |
+ | 4 | | | | x | ETag | opaque | 1-8 | (none) |
+ | 5 | x | | | | If-None-Match | empty | 0 | (none) |
+ | 7 | x | x | - | | Uri-Port | uint | 0-2 | (see |
+ | | | | | | | | | below) |
+ | 8 | | | | x | Location-Path | string | 0-255 | (none) |
+ | 11 | x | x | - | x | Uri-Path | string | 0-255 | (none) |
+ | 12 | | | | | Content-Format | uint | 0-2 | (none) |
+ | 14 | | x | - | | Max-Age | uint | 0-4 | 60 |
+ | 15 | x | x | - | x | Uri-Query | string | 0-255 | (none) |
+ | 17 | x | | | | Accept | uint | 0-2 | (none) |
+ | 20 | | | | x | Location-Query | string | 0-255 | (none) |
+ | 23 | x | x | - | - | Block2 | uint | 0-3 | (none) |
+ | 27 | x | x | - | - | Block1 | uint | 0-3 | (none) |
+ | 28 | | | x | | Size2 | uint | 0-4 | (none) |
+ | 35 | x | x | - | | Proxy-Uri | string | 1-1034 | (none) |
+ | 39 | x | x | - | | Proxy-Scheme | string | 1-255 | (none) |
+ | 60 | | | x | | Size1 | uint | 0-4 | (none) |
+ +-----+---+---+---+---+----------------+--------+--------+----------+
+*/
+
+#include <stdint.h>
+#include "coap_api.h"
+#include "nrf_error.h"
+#include "sdk_errors.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum
+{
+ COAP_OPT_FORMAT_EMPTY = 0,
+ COAP_OPT_FORMAT_STRING = 1,
+ COAP_OPT_FORMAT_OPAQUE = 2,
+ COAP_OPT_FORMAT_UINT = 3
+
+} coap_opt_format_t;
+
+
+/**@brief Encode zero-terminated string into utf-8 encoded string.
+ *
+ * @param[out] p_encoded Pointer to buffer that will be used to fill the
+ * encoded string into.
+ * @param[inout] p_length Length of the buffer provided. Will also be used to
+ * return the size of the used buffer.
+ * @param[in] p_string String to encode.
+ * @param[in] str_len Length of the string to encode.
+ *
+ * @retval NRF_SUCCESS Indicates that encoding was successful.
+ * @retval NRF_ERROR_DATA_SIZE Indicates that the buffer provided was not sufficient to
+ * successfully encode the data.
+ */
+uint32_t coap_opt_string_encode(uint8_t * p_encoded, uint16_t * p_length, uint8_t * p_string, uint16_t str_len);
+
+/**@brief Decode a utf-8 string into a zero-terminated string.
+ *
+ * @param[out] p_string Pointer to the string buffer where the decoded
+ * string will be placed.
+ * @param[inout] p_length p_length of the encoded string. Returns the size of the buffer
+ * used in bytes.
+ * @param[in] p_encoded Buffer to decode.
+ *
+ * @retval NRF_SUCCESS Indicates that decoding was successful.
+ * @retval NRF_ERROR_DATA_SIZE Indicates that the buffer provided was not sufficient to
+ * successfully dencode the data.
+ */
+uint32_t coap_opt_string_decode(uint8_t * p_string, uint16_t * p_length, uint8_t * p_encoded);
+
+/**@brief Encode a uint value into a uint8_t buffer in network byte order.
+ *
+ * @param[out] p_encoded Pointer to buffer that will be used to fill the
+ * encoded uint into.
+ * @param[inout] p_length Length of the buffer provided. Will also be used to
+ * return the size of the used buffer.
+ * @param[in] data uint value which could be anything from 1 to 4 bytes.
+ *
+ * @retval NRF_SUCCESS Indicates that encoding was successful.
+ * @retval NRF_ERROR_DATA_SIZE Indicates that the buffer provided was not sufficient to
+ * successfully encode the data.
+ */
+uint32_t coap_opt_uint_encode(uint8_t * p_encoded, uint16_t * p_length, uint32_t data);
+
+/**@brief Decode a uint encoded value in network byte order to a uint32_t value.
+ *
+ * @param[out] p_data Pointer to the uint32_t value where the decoded uint will
+ * be placed.
+ * @param[inout] length Size of the encoded value.
+ * @param[in] p_encoded uint value to be decoded into a uint32_t value.
+ *
+ * @retval NRF_SUCCESS Indicates that decoding was successful.
+ * @retval NRF_ERROR_NULL If p_data or p_encoded pointer is NULL.
+ * @retval NRF_ERROR_INVALID_LENGTH If buffer was greater than uint32_t.
+ */
+uint32_t coap_opt_uint_decode(uint32_t * p_data, uint16_t length, uint8_t * p_encoded);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_OPTION_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c
new file mode 100644
index 0000000..4e12bb6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.c
@@ -0,0 +1,182 @@
+/**
+ * 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 <string.h>
+
+#include "coap_queue.h"
+#include "iot_common.h"
+#include "sdk_config.h"
+
+#if (COAP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
+ }
+#else
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // COAP_DISABLE_API_PARAM_CHECK
+
+static coap_queue_item_t m_queue[COAP_MESSAGE_QUEUE_SIZE];
+static uint8_t m_message_queue_count = 0;
+
+uint32_t coap_queue_init(void)
+{
+ for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ memset(&m_queue[i], 0, sizeof(coap_queue_item_t));
+ m_queue[i].handle = i;
+ }
+ m_message_queue_count = 0;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_queue_add(coap_queue_item_t * item)
+{
+ NULL_PARAM_CHECK(item);
+
+ if (m_message_queue_count >= COAP_MESSAGE_QUEUE_SIZE)
+ {
+ return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE);
+ }
+ else
+ {
+ for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ if (m_queue[i].p_buffer == NULL)
+ {
+ // Free spot in message queue. Add message here...
+ memcpy(&m_queue[i], item, sizeof(coap_queue_item_t));
+
+ m_message_queue_count++;
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ }
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+}
+
+uint32_t coap_queue_remove(coap_queue_item_t * p_item)
+{
+ for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ if (p_item == (coap_queue_item_t *)&m_queue[i])
+ {
+ memset(&m_queue[i], 0, sizeof(coap_queue_item_t));
+ m_message_queue_count--;
+ return NRF_SUCCESS;
+ }
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+uint32_t coap_queue_item_by_token_get(coap_queue_item_t ** pp_item, uint8_t * p_token, uint8_t token_len)
+{
+ for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ if (m_queue[i].token_len == token_len)
+ {
+ if ((0 != m_queue[i].token_len) &&
+ (memcmp(m_queue[i].token, p_token, m_queue[i].token_len) == 0))
+ {
+ *pp_item = &m_queue[i];
+ return NRF_SUCCESS;
+ }
+ }
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+
+uint32_t coap_queue_item_by_mid_get(coap_queue_item_t ** pp_item, uint16_t message_id)
+{
+
+
+ for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ if (m_queue[i].mid == message_id)
+ {
+ *pp_item = &m_queue[i];
+ return NRF_SUCCESS;
+ }
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+
+uint32_t coap_queue_item_next_get(coap_queue_item_t ** pp_item, coap_queue_item_t * p_item)
+{
+ if (p_item == NULL)
+ {
+ for (uint8_t i = 0; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ if (m_queue[i].p_buffer != NULL)
+ {
+ (*pp_item) = &m_queue[i];
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ uint8_t index_to_previous = (uint8_t)(((uint32_t)p_item - (uint32_t)m_queue) / (uint32_t)sizeof(coap_queue_item_t));
+
+ for (uint8_t i = index_to_previous + 1; i < COAP_MESSAGE_QUEUE_SIZE; i++)
+ {
+ if (m_queue[i].p_buffer != NULL)
+ {
+ (*pp_item) = &m_queue[i];
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ (*pp_item) = NULL;
+
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h
new file mode 100644
index 0000000..24c5db6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_queue.h
@@ -0,0 +1,153 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_queue.h
+ *
+ * @defgroup iot_sdk_coap_queue CoAP Message Queue
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief TODO.
+ */
+
+#ifndef COAP_QUEUE_H__
+#define COAP_QUEUE_H__
+
+#include <stdint.h>
+
+#include "coap_transport.h"
+#include "coap_message.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ void * p_arg; /**< Miscellaneous pointer to application provided data that is associated with the message. Copied from the coap_message_t when creating the item. */
+ uint32_t handle; /**< Quick reference to the handle value of the current item. */
+ uint16_t mid; /**< Message ID. */
+ uint8_t token_len; /**< Message Token length. */
+ uint8_t token[8]; /**< Message Token value up to 8 bytes. */
+ uint8_t retrans_count; /**< Re-transmission attempt count. */
+ uint16_t timeout; /**< Time until new re-transmission attempt. */
+ uint16_t timeout_val; /**< Last timeout value used. */
+ coap_port_t port; /**< Source port to use when re-transmitting. */
+ uint8_t * p_buffer; /**< Pointer to the data buffer containing the encoded CoAP message. */
+ uint32_t buffer_len; /**< Size of the data buffer containing the encoded CoAP message. */
+ coap_remote_t remote; /**< Destination address and port number to the remote. */
+ coap_response_callback_t callback; /**< Callback function to be called upon response or transmission timeout. */
+} coap_queue_item_t;
+
+/**@brief Initilize the CoAP message queue.
+ *
+ * @retval NRF_SUCCESS If initialization completed successfully.
+ */
+uint32_t coap_queue_init(void);
+
+/**@brief Add item to the queue.
+ *
+ * @param[in] p_item Pointer to an item which to add to the queue. The function will copy all
+ * data provided.
+ *
+ * @retval NRF_SUCCESS If adding the item was successful.
+ * @retval NRF_ERROR_NO_MEM If max number of queued elements has been reached. This is
+ * configured by COAP_MESSAGE_QUEUE_SIZE in sdk_config.h.
+ * @retval NRF_ERROR_DATA_SIZE If the element could not be added.
+ */
+uint32_t coap_queue_add(coap_queue_item_t * p_item);
+
+/**@brief Remove item from the queue.
+ *
+ * @param[in] p_item Pointer to an item which to remove from the queue. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the item was successfully removed from the queue.
+ * @retval NRF_ERROR_NULL If p_item pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If the item was not located in the queue.
+ */
+uint32_t coap_queue_remove(coap_queue_item_t * p_item);
+
+/**@brief Search for item by token.
+ *
+ * @details Search the items for any item matching the token.
+ *
+ * @param[out] pp_item Pointer to be filled by the function if item matching the token
+ * has been found. Should not be NULL.
+ * @param[in] p_token Pointer to token array to be matched.
+ * @param[in] token_len Length of the token to be matched.
+ *
+ * @retval NRF_SUCCESS If an item was successfully located.
+ * @retval NRF_ERROR_NULL If pp_item pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If no item was found.
+ */
+uint32_t coap_queue_item_by_token_get(coap_queue_item_t ** pp_item, uint8_t * p_token, uint8_t token_len);
+
+/**@brief Search for item by message id.
+ *
+ * @details Search the items for any item matching the message id.
+ *
+ * @param[out] pp_item Pointer to be filled by the funciton if item matching the message id
+ * has been found. Should not be NULL.
+ * @param[in] message_id Message id to be matched.
+ *
+ * @retval NRF_SUCCESS If an item was successfully located.
+ * @retval NRF_ERROR_NULL If pp_item pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If no item was found.
+ */
+uint32_t coap_queue_item_by_mid_get(coap_queue_item_t ** pp_item, uint16_t message_id);
+
+/**@brief Iterate through items.
+ *
+ * @param[out] pp_item Pointer to be filled by the search function upon finding the next
+ * queued item starting from the p_item pointer provided. Should
+ * not be NULL.
+ * @param[in] p_item Pointer to the item where to start the search.
+ *
+ * @retval NRF_SUCCESS If item was found.
+ * @retval NRF_ERROR_NULL If pp_item pointer is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If next item was not found.
+ */
+uint32_t coap_queue_item_next_get(coap_queue_item_t ** pp_item, coap_queue_item_t * p_item);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_QUEUE_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c
new file mode 100644
index 0000000..b928e0c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.c
@@ -0,0 +1,274 @@
+/**
+ * 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 <string.h>
+
+#include "coap_resource.h"
+#include "coap_api.h"
+#include "iot_common.h"
+#include "sdk_config.h"
+
+#define COAP_RESOURCE_MAX_AGE_INIFINITE 0xFFFFFFFF
+
+static coap_resource_t * mp_root_resource = NULL;
+static char m_scratch_buffer[(COAP_RESOURCE_MAX_NAME_LEN + 1) * COAP_RESOURCE_MAX_DEPTH + 6];
+
+#if (COAP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
+ }
+#else
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // COAP_DISABLE_API_PARAM_CHECK
+
+uint32_t coap_resource_init(void)
+{
+ mp_root_resource = NULL;
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_resource_create(coap_resource_t * p_resource, const char * name)
+{
+ NULL_PARAM_CHECK(p_resource);
+ NULL_PARAM_CHECK(name);
+
+ if (strlen(name) > COAP_RESOURCE_MAX_NAME_LEN)
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+
+ memcpy(p_resource->name, name, strlen(name));
+
+ if (mp_root_resource == NULL)
+ {
+ mp_root_resource = p_resource;
+ }
+
+ p_resource->max_age = COAP_RESOURCE_MAX_AGE_INIFINITE;
+
+ return NRF_SUCCESS;
+}
+
+uint32_t coap_resource_child_add(coap_resource_t * p_parent, coap_resource_t * p_child)
+{
+ NULL_PARAM_CHECK(p_parent);
+ NULL_PARAM_CHECK(p_child);
+
+ if (p_parent->child_count == 0)
+ {
+ p_parent->p_front = p_child;
+ p_parent->p_tail = p_child;
+ }
+ else
+ {
+ coap_resource_t * p_last_sibling = p_parent->p_tail;
+ p_last_sibling->p_sibling = p_child;
+ p_parent->p_tail = p_child;
+ }
+
+ p_parent->child_count++;
+
+ return NRF_SUCCESS;
+}
+
+static uint32_t generate_path(uint16_t buffer_pos, coap_resource_t * p_current_resource, char * parent_path, uint8_t * string, uint16_t * length)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (parent_path == NULL)
+ {
+ m_scratch_buffer[buffer_pos++] = '<';
+
+ if (p_current_resource->p_front != NULL)
+ {
+ coap_resource_t * next_child = p_current_resource->p_front;
+ do
+ {
+ err_code = generate_path(buffer_pos, next_child, m_scratch_buffer, string, length);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ next_child = next_child->p_sibling;
+ } while (next_child != NULL);
+ }
+ }
+ else
+ {
+ uint16_t size = strlen(p_current_resource->name);
+ m_scratch_buffer[buffer_pos++] = '/';
+
+ memcpy(&m_scratch_buffer[buffer_pos], p_current_resource->name, size);
+ buffer_pos += size;
+
+ if (p_current_resource->p_front != NULL)
+ {
+ coap_resource_t * next_child = p_current_resource->p_front;
+ do
+ {
+ err_code = generate_path(buffer_pos, next_child, m_scratch_buffer, string, length);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ next_child = next_child->p_sibling;
+ } while (next_child != NULL);
+ }
+
+ m_scratch_buffer[buffer_pos++] = '>';
+
+ // If the resource is observable, append 'obs;' token.
+ if ((p_current_resource->permission & COAP_PERM_OBSERVE) > 0)
+ {
+ memcpy(&m_scratch_buffer[buffer_pos], ";obs", 4);
+ buffer_pos += 4;
+ }
+
+ m_scratch_buffer[buffer_pos++] = ',';
+
+ if (buffer_pos <= (*length))
+ {
+ *length -= buffer_pos;
+ memcpy(&string[strlen((char *)string)], m_scratch_buffer, buffer_pos);
+ }
+ else
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
+ }
+ }
+
+ return err_code;
+}
+
+uint32_t coap_resource_well_known_generate(uint8_t * string, uint16_t * length)
+{
+ NULL_PARAM_CHECK(string);
+ NULL_PARAM_CHECK(length);
+
+ if (mp_root_resource == NULL)
+ {
+ return (NRF_ERROR_INVALID_STATE | IOT_COAP_ERR_BASE);
+ }
+
+ memset(string, 0, *length);
+
+ uint32_t err_code = generate_path(0, mp_root_resource, NULL, string, length);
+
+ string[strlen((char *)string) - 1] = '\0'; // remove the last comma
+
+ return err_code;
+}
+
+static coap_resource_t * coap_resource_child_resolve(coap_resource_t * p_parent,
+ char * p_path)
+{
+ coap_resource_t * result = NULL;
+ if (p_parent->p_front != NULL)
+ {
+ coap_resource_t * sibling_in_question = p_parent->p_front;
+
+ do {
+ // Check if the sibling name match.
+ size_t size = strlen(sibling_in_question->name);
+ if (strncmp(sibling_in_question->name, p_path, size) == 0)
+ {
+ return sibling_in_question;
+ }
+ else
+ {
+ sibling_in_question = sibling_in_question->p_sibling;
+ }
+ } while (sibling_in_question != NULL);
+ }
+ return result;
+}
+
+uint32_t coap_resource_get(coap_resource_t ** p_resource, uint8_t ** pp_uri_pointers, uint8_t num_of_uris)
+{
+ if (mp_root_resource == NULL)
+ {
+ // Make sure pointer is set to NULL before returning.
+ *p_resource = NULL;
+ return (NRF_ERROR_INVALID_STATE | IOT_COAP_ERR_BASE);
+ }
+
+ coap_resource_t * p_current_resource = mp_root_resource;
+
+ // Every node should start at root.
+ for (uint8_t i = 0; i < num_of_uris; i++)
+ {
+ p_current_resource = coap_resource_child_resolve(p_current_resource, (char *)pp_uri_pointers[i]);
+
+ if (p_current_resource == NULL)
+ {
+ // Stop looping as this direction will not give anything more.
+ break;
+ }
+ }
+
+ if (p_current_resource != NULL)
+ {
+ *p_resource = p_current_resource;
+ return NRF_SUCCESS;
+ }
+
+ // If nothing has been found.
+ *p_resource = NULL;
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+}
+
+uint32_t coap_resource_root_get(coap_resource_t ** pp_resource)
+{
+ NULL_PARAM_CHECK(pp_resource);
+
+ if (mp_root_resource == NULL)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
+ }
+
+ *pp_resource = mp_root_resource;
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h
new file mode 100644
index 0000000..d73ef1f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_resource.h
@@ -0,0 +1,110 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_resource.h
+ *
+ * @defgroup iot_sdk_coap_resource CoAP Resource
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief Private API of Nordic's CoAP Resource implementation.
+ */
+
+#ifndef COAP_RESOURCE_H__
+#define COAP_RESOURCE_H__
+
+#include <stdint.h>
+#include "coap_api.h"
+#include "sdk_config.h"
+#include "coap_message.h"
+#include "nrf_error.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Initialize the CoAP resource module.
+ *
+ * @details This function will initialize the root element pointer to NULL.
+ * This way, a new root can be assigned registered. The first
+ * resource added will be set as the new root.
+ *
+ * @retval NRF_SUCCESS This function will always return success.
+ */
+uint32_t coap_resource_init(void);
+
+/**@brief Find a resource by traversing the resource names.
+ *
+ * @param[out] p_resource Located resource.
+ * @param[in] pp_uri_pointers Array of strings which forms the hierarchical path to the resource.
+ * @param[in] num_of_uris Number of URIs supplied through the path pointer list.
+ *
+ * @retval NRF_SUCCESS The resource was instance located.
+ * @retval NRF_ERROR_NOT_FOUND The resource was not located.
+ * @retval NRF_ERROR_INVALID_STATE If no resource has been registered.
+ */
+uint32_t coap_resource_get(coap_resource_t ** p_resource,
+ uint8_t ** pp_uri_pointers,
+ uint8_t num_of_uris);
+
+
+/**@brief Process the request related to the resource.
+ *
+ * @details When a request is received and the resource has successfully been located it
+ * will pass on to this function. The method in the request will be matched against
+ * what the service provides of method handling callbacks. If the request expects a
+ * response this will be provided as output from this function. The memory provided
+ * for the response must be provided from outside.
+ *
+ * @param[in] p_resource Resource that will handle the request.
+ * @param[in] p_request The request to be handled.
+ * @param[inout] p_response Response message which can be used by the resource populate
+ * the response message.
+ */
+uint32_t coap_resource_process_request(coap_resource_t * p_resource,
+ coap_message_t * p_request,
+ coap_message_t * p_response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COAP_MESSAGE_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h
new file mode 100644
index 0000000..b9fd597
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport.h
@@ -0,0 +1,165 @@
+/**
+ * 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.
+ *
+ */
+/** @file coap_transport.h
+ *
+ * @defgroup iot_sdk_coap_transport CoAP transport abstraction
+ * @ingroup iot_sdk_coap
+ * @{
+ * @brief The transport interface that the CoAP depends on for sending and receiving CoAP messages.
+ *
+ * @details While the interface is well defined and should not be altered, the implementation of the
+ * interface depends on the choice of IP stack. The only exception to this is the
+ * \ref coap_transport_read API. This API is implemented in the CoAP, and the transport layer is
+ * expected to call this function when data is received on one of the CoAP ports.
+ */
+
+#ifndef COAP_TRANSPORT_H__
+#define COAP_TRANSPORT_H__
+
+#include <stdint.h>
+#include <nrf_tls.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Port identification information. */
+typedef struct
+{
+ uint16_t port_number; /**< Port number. */
+} coap_port_t;
+
+
+/**@brief Remote endpoint. */
+typedef struct
+{
+ uint8_t addr[16]; /**< Address of the remote device. */
+ uint16_t port_number; /**< Remote port number. */
+} coap_remote_t;
+
+
+/**@brief Transport initialization information. */
+typedef struct
+{
+ coap_port_t * p_port_table; /**< Information about the ports being registered. Count is assumed to be COAP_PORT_COUNT. */
+ void * p_arg; /**< Public. Miscellaneous pointer to application provided data that should be passed to the transport. */
+} coap_transport_init_t;
+
+
+
+/**@brief Initializes the transport layer to have the data ports set up for CoAP.
+ *
+ * @param[in] p_param Port count and port numbers.
+ *
+ * @retval NRF_SUCCESS If initialization was successful. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t coap_transport_init (const coap_transport_init_t * p_param);
+
+
+/**@brief Sends data on a CoAP endpoint or port.
+ *
+ * @param[in] p_port Port on which the data is to be sent.
+ * @param[in] p_remote Remote endpoint to which the data is targeted.
+ * @param[in] p_data Pointer to the data to be sent.
+ * @param[in] datalen Length of the data to be sent.
+ *
+ * @retval NRF_SUCCESS If the data was sent successfully. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+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);
+
+
+
+/**@brief Handles data received on a CoAP endpoint or port.
+ *
+ * This API is not implemented by the transport layer, but assumed to exist. This approach
+ * avoids unnecessary registering of callback and remembering it in the transport layer.
+ *
+ * @param[in] p_port Port on which the data is received.
+ * @param[in] p_remote Remote endpoint from which the data is received.
+ * @param[in] p_local Local endpoint on which the data is received.
+ * @param[in] result Indicates if the data was processed successfully by lower layers.
+ * Possible failures could be NRF_SUCCESS,
+ * UDP_BAD_CHECKSUM,
+ * UDP_TRUNCATED_PACKET, or
+ * UDP_MALFORMED_PACKET.
+ * @param[in] p_data Pointer to the data received.
+ * @param[in] datalen Length of the data received.
+ *
+ * @retval NRF_SUCCESS If the data was handled successfully. Otherwise, an error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t coap_transport_read(const coap_port_t * p_port,
+ const coap_remote_t * p_remote,
+ const coap_remote_t * p_local,
+ uint32_t result,
+ const uint8_t * p_data,
+ uint16_t datalen);
+
+
+/**@brief Process loop to handle DTLS processing.
+ *
+ * @details The function handles any processing of encrypted packets.
+ * Some encryption libraries requires to be run in a processing
+ * loop. This function is called by the CoAP library everytime
+ * \ref coap_time_tick is issued from the library user. Any other process
+ * specific routines that should be done regularly could be added in
+ * this function.
+ */
+void coap_transport_process(void);
+
+/**@brief Process loop when using coap BSD socket transport implementation.
+ *
+ * @details This is blocking call. The function unblock is only
+ * triggered upon an socket event registered to select() by coap transport.
+ * This function must be called as often as possible in order to dispatch incomming
+ * socket events. Preferred to be put in the application's main loop or similar.
+ */
+void coap_transport_input(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //COAP_TRANSPORT_H__
+
+/** @} */
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;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c
new file mode 100644
index 0000000..9cf4bdb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_ipv6.c
@@ -0,0 +1,264 @@
+/**
+ * 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 "sdk_errors.h"
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "iot_pbuffer.h"
+#include "coap_transport.h"
+#include "coap.h"
+#include "udp_api.h"
+
+
+/**@brief UDP port information. */
+typedef struct
+{
+ uint32_t socket_id; /**< Socket information provided by UDP. */
+ uint16_t port_number; /**< Associated port number. */
+} udp_port_t;
+
+static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */
+
+
+/**@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;
+
+ //Search for the port.
+ for (index = 0; index < COAP_PORT_COUNT; index++)
+ {
+ //Matching port found.
+ if (m_port_table[index].socket_id == p_socket->socket_id)
+ {
+ coap_remote_t remote_endpoint;
+ coap_remote_t local_endpoint;
+ const coap_port_t port = {p_udp_header->destport};
+
+ memcpy (remote_endpoint.addr, p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE);
+ remote_endpoint.port_number = p_udp_header->srcport;
+
+ memcpy (local_endpoint.addr, p_ip_header->destaddr.u8, IPV6_ADDR_SIZE);
+ local_endpoint.port_number = p_udp_header->destport;
+
+ COAP_MUTEX_LOCK();
+
+ //Notify the module of received data.
+ retval = coap_transport_read(&port,
+ &remote_endpoint,
+ &local_endpoint,
+ process_result,
+ p_rx_packet->p_payload,
+ p_rx_packet->length);
+
+ COAP_MUTEX_UNLOCK();
+ }
+ }
+
+ return retval;
+}
+
+
+/**@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;
+ 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);
+
+ 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;
+ }
+ }
+
+ 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;
+ udp6_socket_t socket;
+ ipv6_addr_t remote_addr;
+ iot_pbuffer_t * p_buffer;
+ iot_pbuffer_alloc_param_t buffer_param;
+
+ NULL_PARAM_CHECK(p_port);
+ NULL_PARAM_CHECK(p_remote);
+ NULL_PARAM_CHECK(p_data);
+
+ memcpy(remote_addr.u8, p_remote->addr, 16);
+
+
+ buffer_param.type = UDP6_PACKET_TYPE;
+ buffer_param.flags = PBUFFER_FLAG_DEFAULT;
+ buffer_param.length = datalen;
+
+ //Search for the corresponding port.
+ for (index = 0; index < COAP_PORT_COUNT; index ++)
+ {
+ if (m_port_table[index].port_number == p_port->port_number)
+ {
+ //Allocate buffer to send the data on port.
+ err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
+
+ 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);
+
+ COAP_MUTEX_UNLOCK();
+
+ //Send on UDP port.
+ err_code = udp6_socket_sendto(&socket,
+ &remote_addr,
+ p_remote->port_number,
+ p_buffer);
+
+ COAP_MUTEX_LOCK();
+
+ if (err_code != NRF_SUCCESS)
+ {
+ //Free the allocated buffer as send procedure has failed.
+ UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true));
+ }
+ }
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+
+void coap_transport_process(void)
+{
+ return;
+}
+
+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)
+{
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+}
+
+
+uint32_t coap_security_destroy(uint16_t local_port,
+ coap_remote_t * const p_remote)
+{
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c
new file mode 100644
index 0000000..6245a97
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_lwip.c
@@ -0,0 +1,255 @@
+/**
+ * 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 <stdint.h>
+#include "sdk_errors.h"
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "coap_transport.h"
+#include "coap.h"
+#include "lwip/ip6_addr.h"
+/*lint -save -e607 Suppress warning 607 "Parameter p of macro found within string" */
+#include "lwip/udp.h"
+/*lint -restore */
+
+
+/**@brief UDP port information. */
+typedef struct
+{
+ struct udp_pcb * p_socket; /**< Socket information provided by UDP. */
+ uint16_t port_number; /**< Associated port number. */
+}udp_port_t;
+
+static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */
+
+
+/**@brief Callback handler to receive data on the UDP port.
+ *
+ * @details Callback handler to receive data on the UDP port.
+ *
+ * @param[in] p_arg Receive argument associated with the UDP socket.
+ * @param[in] p_socket Socket identifier.
+ * @param[in] p_ip_header IPv6 header containing source and destination addresses.
+ * @param[in] p_remote_addr IPv6 address of the remote device.
+ * @param[in] port Port number identifying the remote endpoint.
+ *
+ * @retval NRF_SUCCESS Indicates received data was handled successfully, else an an
+ * error code indicating reason for failure.
+ */
+static void udp_recv_data_handler(void * p_arg,
+ struct udp_pcb * p_socket,
+ struct pbuf * p_buffer,
+ const ip6_addr_t * p_remote_addr,
+ u16_t port)
+{
+ uint32_t index;
+ coap_remote_t remote_endpoint;
+ coap_port_t local_port = {p_socket->local_port};
+
+ for (index = 0; index < COAP_PORT_COUNT; index++)
+ {
+ if (m_port_table[index].p_socket == p_socket)
+ {
+ memcpy (remote_endpoint.addr, p_remote_addr, 16);
+ remote_endpoint.port_number = port;
+
+ COAP_MUTEX_LOCK();
+
+ UNUSED_VARIABLE(coap_transport_read(&local_port,
+ &remote_endpoint,
+ NULL,
+ NRF_SUCCESS,
+ (uint8_t *)p_buffer->payload,
+ (uint32_t)p_buffer->len));
+
+ COAP_MUTEX_UNLOCK();
+
+ break;
+ }
+ }
+
+ //Freeing packet (irrespective of matching p_socket is found or not
+ //to avoid memory leaks in the system.
+ UNUSED_VARIABLE(pbuf_free(p_buffer));
+}
+
+
+/**@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)
+{
+ err_t err = NRF_ERROR_NO_MEM;
+ ip6_addr_t any_addr;
+ struct udp_pcb * p_socket = m_port_table[index].p_socket;
+
+ ip6_addr_set_any(&any_addr);
+
+ //Request new socket creation.
+ p_socket = udp_new();
+
+ if (NULL != p_socket)
+ {
+ // Bind the socket to the local port.
+ err = udp_bind(p_socket, &any_addr, p_port->port_number);
+ if (err == ERR_OK)
+ {
+ //Register data receive callback.
+ udp_recv(p_socket, udp_recv_data_handler, &m_port_table[index]);
+ //All procedure with respect to port creation succeeded, make entry in the table.
+ m_port_table[index].port_number = p_port->port_number;
+ m_port_table[index].p_socket = p_socket;
+ }
+ else
+ {
+ //Not all procedures succeeded with allocated socket, hence free it.
+ err = NRF_ERROR_INVALID_PARAM;
+ udp_remove(p_socket);
+ }
+ }
+
+ return err;
+}
+
+
+uint32_t coap_transport_init(const coap_transport_init_t * p_param)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ uint32_t index;
+
+ NULL_PARAM_CHECK(p_param);
+ NULL_PARAM_CHECK(p_param->p_port_table);
+
+ 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;
+ }
+ }
+
+ 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)
+{
+
+ err_t err = NRF_ERROR_NOT_FOUND;
+ uint32_t index;
+
+ NULL_PARAM_CHECK(p_port);
+ NULL_PARAM_CHECK(p_remote);
+ NULL_PARAM_CHECK(p_data);
+
+ //Search for the corresponding port.
+ for (index = 0; index < COAP_PORT_COUNT; index++)
+ {
+ if (m_port_table[index].port_number == p_port->port_number)
+ {
+ //Allocate Buffer to send the data on port.
+ struct pbuf * lwip_buffer = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
+
+ if (NULL != lwip_buffer)
+ {
+ //Make a copy of the data onto the buffer.
+ memcpy(lwip_buffer->payload, p_data, datalen);
+
+ COAP_MUTEX_UNLOCK();
+
+ //Send on UDP port.
+ err = udp_sendto(m_port_table[index].p_socket,
+ lwip_buffer,
+ (ip6_addr_t *)p_remote->addr,
+ p_remote->port_number);
+
+ COAP_MUTEX_LOCK();
+
+
+ if (err != ERR_OK)
+ {
+ //Free the allocated buffer as send procedure has failed.
+ err = NRF_ERROR_INTERNAL;
+ }
+ UNUSED_VARIABLE(pbuf_free(lwip_buffer));
+ }
+ else
+ {
+ //Buffer allocation failed, cannot send data.
+ err = NRF_ERROR_NO_MEM;
+ }
+ break;
+ }
+ }
+ return err;
+}
+
+
+void coap_transport_process(void)
+{
+ return;
+}
+
+
+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)
+{
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+}
+
+
+uint32_t coap_security_destroy(uint16_t local_port,
+ coap_remote_t * const p_remote)
+{
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c
new file mode 100644
index 0000000..d19737f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_transport_socket.c
@@ -0,0 +1,292 @@
+/**
+ * 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 <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#ifdef UNIX
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <stdint.h>
+#include "mem_manager.h"
+#include "sdk_errors.h"
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "nordic_common.h"
+#include "coap_transport.h"
+#include "coap.h"
+
+/**@brief UDP port information. */
+typedef struct
+{
+ int socket_fd; /**< Socket information provided by UDP. */
+ uint16_t port_number; /**< Associated port number. */
+} udp_port_t;
+
+static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */
+
+static fd_set m_readfds;
+static int m_max_sd = 0;
+
+/**@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)
+{
+ // Request new socket creation.
+ int socket_fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+
+ if (socket_fd != -1)
+ {
+ // Bind the socket to the local port.
+ struct sockaddr_in6 sin6;
+
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(p_port->port_number);
+ sin6.sin6_addr = in6addr_any;
+
+ int retval = bind(socket_fd, (struct sockaddr *)&sin6, sizeof(sin6));
+ if (retval != -1)
+ {
+ m_port_table[index].port_number = p_port->port_number;
+ m_port_table[index].socket_fd = socket_fd;
+ }
+ else
+ {
+ // Not all procedures succeeded with allocated socket, hence free it.
+ UNUSED_VARIABLE(close(socket_fd));
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ }
+
+ // Configure socket to be non-blocking.
+ int flags = fcntl(socket_fd, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+ UNUSED_VARIABLE(fcntl(m_port_table[index].socket_fd, F_SETFL, flags));
+
+ // Add socket to file descriptor set.
+ FD_SET(m_port_table[index].socket_fd, &m_readfds);
+
+ // If enumeration is having a gap, increase the max fd count.
+ if (socket_fd >= m_max_sd)
+ {
+ m_max_sd = (socket_fd + 1);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t coap_transport_init(const coap_transport_init_t * p_param)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ uint32_t index;
+
+ NULL_PARAM_CHECK(p_param);
+ NULL_PARAM_CHECK(p_param->p_port_table);
+
+ FD_ZERO(&m_readfds);
+
+ err_code = nrf_mem_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;
+ }
+ }
+ }
+
+ 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);
+
+ // Search for the corresponding port.
+ for (index = 0; index < COAP_PORT_COUNT; index++)
+ {
+ if (m_port_table[index].port_number == p_port->port_number)
+ {
+ COAP_MUTEX_UNLOCK();
+
+ static struct sockaddr_in6 dest_address_in6;
+
+ memset(&dest_address_in6, 0, sizeof(struct sockaddr_in6));
+ dest_address_in6.sin6_family = AF_INET6;
+ dest_address_in6.sin6_port = htons(p_remote->port_number);
+
+ memcpy(&dest_address_in6.sin6_addr, p_remote->addr, sizeof(struct in6_addr));
+
+ // Send on UDP port.
+ int retval = sendto(m_port_table[index].socket_fd,
+ p_data,
+ datalen,
+ 0,
+ (struct sockaddr *)&dest_address_in6,
+ sizeof(dest_address_in6));
+ if (retval == -1)
+ {
+ // Error in sendto.
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else
+ {
+ err_code = NRF_SUCCESS;
+ }
+
+ COAP_MUTEX_LOCK();
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+
+void coap_transport_process(void)
+{
+ return;
+}
+
+
+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)
+{
+ return SDK_ERR_API_NOT_IMPLEMENTED;
+}
+
+
+uint32_t coap_security_destroy(uint16_t local_port,
+ coap_remote_t * const p_remote)
+{
+ return SDK_ERR_API_NOT_IMPLEMENTED;
+}
+
+
+void coap_transport_input(void)
+{
+ int retval = select(m_max_sd, &m_readfds, NULL, NULL, NULL);
+
+ if (retval == -1)
+ {
+ // Error in select().
+ // Placeholder for debugging.
+ }
+ else if (retval >= 1) // Number of file descriptiors with activity.
+ {
+ uint32_t index = 0;
+ int socket_fd = m_port_table[index].socket_fd;
+
+ // The descriptor has data.
+ if (FD_ISSET(socket_fd, &m_readfds)) // If socket_fd is set to read.
+ {
+ static uint8_t read_mem[COAP_MESSAGE_DATA_MAX_SIZE];
+ static struct sockaddr_in6 client_address_in6;
+ socklen_t address_length = sizeof(struct sockaddr_in6);
+
+ int bytes_read = recvfrom(socket_fd,
+ read_mem,
+ sizeof(read_mem),
+ 0,
+ (struct sockaddr *)&client_address_in6,
+ (socklen_t *)&address_length); // Blocking call, waiting for incoming transaction.
+ if (bytes_read >= 0)
+ {
+ coap_port_t port;
+ port.port_number = m_port_table[index].port_number;
+
+ coap_remote_t remote_endpoint;
+ memcpy(remote_endpoint.addr, &client_address_in6.sin6_addr, sizeof(struct in6_addr));
+ remote_endpoint.port_number = ntohs(client_address_in6.sin6_port);
+
+ uint32_t result = NRF_SUCCESS;
+
+ // Notify the CoAP module of received data.
+ retval = coap_transport_read(&port,
+ &remote_endpoint,
+ NULL,
+ result,
+ read_mem,
+ (uint16_t)bytes_read);
+
+ // Nothing much to do if CoAP could not interpret the datagram.
+ UNUSED_VARIABLE(retval);
+ }
+ else
+ {
+ // Error in readfrom().
+ // Placeholder for debugging.
+ // If select() indicated this socket file descriptor to have pending
+ // data, this case should not occur.
+ }
+ }
+ }
+ else
+ {
+ // In case of socket() returning 0, timeout.
+ // Not implemented.
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_common.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_common.h
new file mode 100644
index 0000000..58b653e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_common.h
@@ -0,0 +1,95 @@
+/**
+ * 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.
+ *
+ */
+/** @file iot_common.h
+ *
+ * @defgroup iot_common Common utils
+ * @ingroup iot_sdk_common
+ * @{
+ * @brief Common IoT macros that are needed by IoT modules.
+ *
+ * @details This module abstracts common macros related to IoT. These macros can be used by all IoT modules.
+ */
+
+#ifndef IOT_COMMON_H__
+#define IOT_COMMON_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "iot_defines.h"
+#include "iot_errors.h"
+#include "sdk_os.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Context identifiers used in stateful compression. */
+typedef struct
+{
+ uint8_t src_cntxt_id; /**< Source context identifier (if any). IPV6_CONTEXT_IDENTIFIER_NONE by default. IP Stack can set this on the interface if needed. */
+ uint8_t dest_cntxt_id; /**< Destination context identifier (if any). IPV6_CONTEXT_IDENTIFIER_NONE by default. IP Stack can set this on the interface if needed. */
+} iot_context_id_t;
+
+/**@brief Context structure used for efficient compression and decompression. */
+typedef struct
+{
+ uint8_t context_id; /**< Context identifier (CID) number. */
+ uint8_t prefix_len; /**< Length of prefix for CID. */
+ ipv6_addr_t prefix; /**< Prefix for CID. */
+ bool compression_flag; /**< Indicates if the context can be used for compression. */
+} iot_context_t;
+
+/**@brief Encapsulates all information of the 6LoWPAN interface. */
+typedef struct
+{
+ eui64_t local_addr; /**< Local EUI-64 address. */
+ eui64_t peer_addr; /**< Peer EUI-64 address. */
+ iot_context_id_t tx_contexts; /**< TX contexts can be used for effective compression. */
+ void * p_upper_stack; /**< Block to upper stack. */
+ void * p_transport; /**< Transport reference. */
+} iot_interface_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IOT_COMMON_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_defines.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_defines.h
new file mode 100644
index 0000000..e8c087a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_defines.h
@@ -0,0 +1,321 @@
+/**
+ * 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.
+ *
+ */
+/** @file iot_defines.h
+ *
+ * @defgroup iot_defines IoT Defines
+ * @ingroup iot_sdk_common
+ * @{
+ * @brief Common IoT definitions that are needed by IoT modules.
+ *
+ * @details This module abstracts common data structures and constants related to IoT.
+ * These definitions can be used by all the IoT modules.
+ */
+
+#ifndef IOT_DEFINES_H__
+#define IOT_DEFINES_H__
+
+#include <stdint.h>
+#include <sdk_config.h>
+#include <nrf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Host to network byte-orders on half word. */
+//lint -emacro((572),HTONS) // Suppress warning 572 "Excessive shift value"
+#define HTONS(val) ((uint16_t)((((val) & 0xff00) >> 8) | ((((val) & 0x00ff) << 8))))
+
+/**@brief Host to network byte-orders on full word. */
+//lint -emacro((572),HTONL) // Suppress warning 572 "Excessive shift value"
+#define HTONL(val) ((((uint32_t) (val) & 0xff000000) >> 24) | \
+ (((uint32_t) (val) & 0x00ff0000) >> 8) | \
+ (((uint32_t) (val) & 0x0000ff00) << 8) | \
+ (((uint32_t) (val) & 0x000000ff) << 24))
+
+/**@brief Network to host byte-orders on half word. */
+#define NTOHS(val) HTONS(val)
+
+/**@brief Network to host byte-orders on full word. */
+#define NTOHL(val) HTONL(val)
+
+#if defined(NRF52) || defined(NRF52_SERIES)
+
+#define EUI_64_ADDR_SIZE 8 /**< Size of EUI-64. */
+#define IPV6_ADDR_SIZE 16 /**< Size of IPv6 128-bit address. */
+#define IPV6_CONTEXT_IDENTIFIER_NONE 0xFF /**< No context identifier in use. */
+
+#if (BLE_6LOWPAN_LEGACY_MODE == 1)
+#define IPV6_IID_FLIP_VALUE 0x02 /**< Value XORed with the first byte of EUI-64 to get IID. In some older Linux implementation, this value could be 0x03. */
+#define IPV6_LL_ADDR_SIZE 8 /**< The link-layer address size used in Neighbor Discovery messages. */
+#else
+#define IPV6_IID_FLIP_VALUE 0x00 /**< RFC 7668 specifies that no bit is flipped when IID is generated from a Bluetooth Device Address. */
+#define IPV6_LL_ADDR_SIZE 6 /**< The link-layer address size used in Neighbor Discovery messages. */
+#endif
+
+#define IPV6_IP_HEADER_SIZE 40 /**< IPv6 header size. */
+#define ICMP6_HEADER_SIZE 8 /**< ICMP header size. */
+#define UDP_HEADER_SIZE 8 /**< UDP header size. */
+#define COAP_HEADER_SIZE 4 /**< CoAP header size. */
+
+#define IPV6_DEFAULT_VER_TC 0x60 /**< Default value of version and traffic class fields in IPv6 header. */
+#define IPV6_DEFAULT_TC_FL 0x00 /**< Default value of traffic class and flow label fields in IPv6 header. */
+#define IPV6_DEFAULT_FL 0x00 /**< Default value of the flow label's two last bytes in IPv6 header. */
+
+#define IPV6_NEXT_HEADER_TCP 6 /**< TCP: protocol number. */
+#define IPV6_NEXT_HEADER_UDP 17 /**< UDP: protocol number. */
+#define IPV6_NEXT_HEADER_ICMP6 58 /**< ICMPv6: protocol number. */
+#define IPV6_NEXT_HEADER_RESERVED 255 /**< Reserved value. */
+
+/**@defgroup icmp6_type ICMPv6 message types.
+ * @ingroup iot_defines
+ * @{
+ */
+
+/**@defgroup icmp6_error_type ICMPv6 error messages.
+ * @ingroup icmp6_type
+ * @{
+ */
+#define ICMP6_TYPE_DESTINATION_UNREACHABLE 1 /**< ICMPv6: Destination unreachable error message. */
+#define ICMP6_TYPE_PACKET_TOO_LONG 2 /**< ICMPv6: Packet too long error message. */
+#define ICMP6_TYPE_TIME_EXCEED 3 /**< ICMPv6: Time-out error message. */
+#define ICMP6_TYPE_PARAMETER_PROBLEM 4 /**< ICMPv6: Parameter problem error message. */
+/** @} */
+#define ICMP6_TYPE_ECHO_REQUEST 128 /**< ICMPv6: Echo request message. */
+#define ICMP6_TYPE_ECHO_REPLY 129 /**< ICMPv6: Echo reply message. */
+#define ICMP6_TYPE_ROUTER_SOLICITATION 133 /**< ICMPv6: Neighbor discovery, router solicitation message. */
+#define ICMP6_TYPE_ROUTER_ADVERTISEMENT 134 /**< ICMPv6: Neighbor discovery, router advertisement message. */
+#define ICMP6_TYPE_NEIGHBOR_SOLICITATION 135 /**< ICMPv6: Neighbor discovery, neighbor solicitation message. */
+#define ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT 136 /**< ICMPv6: Neighbor discovery, neighbor advertisement message. */
+/** @} */
+
+/**@brief Initializes IPv6 address. */
+#define IPV6_ADDRESS_INITIALIZE(ADDR) \
+ memset((ADDR)->u8, 0, IPV6_ADDR_SIZE)
+
+/**@brief Checks if prefixes match. Length in bits. */
+#define IPV6_ADDRESS_PREFIX_CMP(prefix, prefix2, length) \
+ ((0 == memcmp(prefix, prefix2, (length>>3) - ((length & 0x7) ? 1 : 0) )) && \
+ (((prefix[(length>>3)] & (((0xff00) >> (length & 0x7))))) == \
+ (prefix2[(length>>3)] & (((0xff00) >> (length & 0x7))))) \
+ )
+
+/**@brief Sets address prefix. Length in bits. */
+#define IPV6_ADDRESS_PREFIX_SET(pfx_to, pfx_from, length) \
+ do { \
+ memcpy(pfx_to, pfx_from, length>>3); \
+ if (length & 0x7) { \
+ uint8_t mask = ((0xff00) >> (length & 0x7)); \
+ uint8_t last = pfx_from[length>>3] & mask; \
+ pfx_to[length>>3] &= ~mask; \
+ pfx_to[length>>3] |= last; \
+ } \
+ } while (0)
+
+/**@brief Creates EUI-64 address from EUI-48.
+ */
+#define IPV6_EUI64_CREATE_FROM_EUI48(eui64, eui48, addr_type) \
+ eui64[0] = eui48[5]; \
+ eui64[1] = eui48[4]; \
+ eui64[2] = eui48[3]; \
+ eui64[3] = 0xFF; \
+ eui64[4] = 0xFE; \
+ eui64[5] = eui48[2]; \
+ eui64[6] = eui48[1]; \
+ eui64[7] = eui48[0]; \
+ if ((addr_type) == BLE_GAP_ADDR_TYPE_PUBLIC) \
+ { \
+ eui64[0] &= ~(IPV6_IID_FLIP_VALUE); \
+ } \
+ else \
+ { \
+ eui64[0] |= IPV6_IID_FLIP_VALUE; \
+ }
+
+/**@brief Creates link-local address from EUI-64. */
+#define IPV6_CREATE_LINK_LOCAL_FROM_EUI64(addr, eui64) \
+ (addr)->u32[0] = HTONL(0xFE800000); \
+ (addr)->u32[1] = 0; \
+ memcpy((addr)->u8 + 8, eui64, EUI_64_ADDR_SIZE); \
+ (addr)->u8[8] ^= IPV6_IID_FLIP_VALUE;
+
+/**@brief Checks if address is a link-local address. */
+#define IPV6_ADDRESS_IS_LINK_LOCAL(addr) \
+ ((addr)->u16[0] == HTONS(0xfe80))
+
+/**@brief Checks if address is a multicast address. */
+#define IPV6_ADDRESS_IS_MULTICAST(addr) \
+ ((addr)->u8[0] == 0xff)
+
+/**@brief Checks if address is a multicast all-node address. */
+#define IPV6_ADDRESS_IS_ALL_NODE(addr) \
+ (((addr)->u32[0] == HTONL(0xff020000)) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == 0) && \
+ ((addr)->u32[3] == HTONL(0x01)))
+
+/**@brief Checks if address is a multicast all-router address. */
+#define IPV6_ADDRESS_IS_ALL_ROUTER(addr) \
+ (((addr)->u32[0] == HTONL(0xff020000)) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == 0) && \
+ ((addr)->u32[3] == HTONL(0x02)))
+
+/**@brief Checks if address is a multicast MLDv2 address. */
+#define IPV6_ADDRESS_IS_MLDV2_MCAST(addr) \
+ (((addr)->u32[0] == HTONL(0xff020000)) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == 0) && \
+ ((addr)->u32[3] == HTONL(0x16)))
+
+/**@brief Checks if address is a multicast all-node address. */
+#define IPV6_ADDRESS_IS_MULTICAST_SOLICITED_NODE(addr) \
+ (((addr)->u32[0] == HTONL(0xff020000)) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == HTONL(0x00000001)) && \
+ ((addr)->u8[12] == 0xFF))
+
+/**@brief Checks if address is an unspecified address. */
+#define IPV6_ADDRESS_IS_UNSPECIFIED(addr) \
+ (((addr)->u32[0] == 0) && \
+ ((addr)->u32[1] == 0) && \
+ ((addr)->u32[2] == 0) && \
+ ((addr)->u32[3] == 0) \
+ )
+
+/**@brief Compares two IPv6 addresses. */
+#define IPV6_ADDRESS_CMP(addr1, addr2) \
+ memcmp((addr1)->u8, (addr2)->u8, IPV6_ADDR_SIZE)
+
+/**@brief Swaps two IPv6 addresses. */
+#define IPV6_ADDRESS_SWAP(addr1, addr2) \
+ do { \
+ ipv6_addr_t addr_temp; \
+ \
+ addr_temp = *addr1; \
+ *addr1 = *addr2; \
+ *addr2 = addr_temp; \
+ } while (0);
+
+/**@brief Prints an IPV6 address. */
+#define IPV6_ADDRESS_LOG(addr) \
+ NRF_LOG_RAW_INFO("%02x%02x:%02x%02x:",(addr).u8[0],(addr).u8[1],(addr).u8[2],(addr).u8[3]); \
+ NRF_LOG_RAW_INFO("%02x%02x:%02x%02x:",(addr).u8[4],(addr).u8[5],(addr).u8[6],(addr).u8[7]); \
+ NRF_LOG_RAW_INFO("%02x%02x:%02x%02x:",(addr).u8[8],(addr).u8[9],(addr).u8[10],(addr).u8[11]); \
+ NRF_LOG_RAW_INFO("%02x%02x:%02x%02x\r\n",(addr).u8[12],(addr).u8[13],(addr).u8[14],(addr).u8[15]);
+
+/**< EUI 64 data type. */
+typedef struct
+{
+ uint8_t identifier[EUI_64_ADDR_SIZE]; /**< 64-bit identifier. */
+} eui64_t;
+
+/**< IPv6 address data type. */
+typedef union
+{
+ uint8_t u8[16];
+ uint16_t u16[8];
+ uint32_t u32[4];
+} ipv6_addr_t;
+
+extern ipv6_addr_t ipv6_addr_any;
+#define IPV6_ADDR_ANY &ipv6_addr_any /**< IPV6 address represents any address. */
+
+extern eui64_t eui64_local_iid; /**< External variable assumed to be implemented in the application with desired EUI-64 to be used as the IID for SLAAC. */
+#define EUI64_LOCAL_IID &eui64_local_iid /**< EUI-64 IID of the device. */
+
+/** @brief IPv6 address states. */
+typedef enum
+{
+ IPV6_ADDR_STATE_UNUSED = 0, /**< IPv6 address is unused. */
+ IPV6_ADDR_STATE_TENTATIVE, /**< IPv6 tentative address; DUD must be performed. */
+ IPV6_ADDR_STATE_PREFERRED, /**< IPv6 preferred address; normal. state. */
+ IPV6_ADDR_STATE_DEPRECATED /**< IPv6 deprecated address. */
+} ipv6_addr_state_t;
+
+/**< IPv6 header structure. */
+typedef struct
+{
+ uint8_t version_traffic_class; /**< Version and traffic class field. */
+ uint8_t traffic_class_flowlabel; /**< Traffic class and flow label field. */
+ uint16_t flowlabel; /**< Flow label, 2nd part of field. */
+ uint16_t length; /**< Length of IPv6 payload field. */
+ uint8_t next_header; /**< Next header field. */
+ uint8_t hoplimit; /**< Hop limit field. */
+ ipv6_addr_t srcaddr; /**< IPv6 source address field. */
+ ipv6_addr_t destaddr; /**< IPv6 destination address field. */
+} ipv6_header_t;
+
+/**< IPv6 UDP header structure. */
+typedef struct
+{
+ uint16_t srcport; /**< Source port. */
+ uint16_t destport; /**< Destination port. */
+ uint16_t length; /**< Length of data with UDP header. */
+ uint16_t checksum; /**< UDP checksum field. */
+} udp6_header_t;
+
+/**< IPv6 ICMP header structure. */
+typedef struct
+{
+ uint8_t type; /**< Type of ICMP message. See @ref icmp6_type for possible values. */
+ uint8_t code; /**< Code related to the type field. */
+ uint16_t checksum; /**< ICMP6 checksum field. */
+ union /**< Message specific fields if any. */
+ {
+ uint32_t mtu; /**< MTU of next hop limit. Used only with Packet Too Big Error Message. */
+ uint32_t unused; /**< Unused fields for error messages that do not have any auxiliary information. */
+ uint32_t offset; /**< Offset field used only with Parameter Problem error message. */
+ struct { /**< Identifier and sequence number information specific associated with echo request and response. */
+ uint16_t id; /**< Identifier. */
+ uint16_t sequence; /**< Sequence number. */
+ } echo;
+ } sp;
+} icmp6_header_t;
+
+#endif // NRF52
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IOT_DEFINES_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_errors.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_errors.h
new file mode 100644
index 0000000..657004a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/common/iot_errors.h
@@ -0,0 +1,290 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file
+ *
+ * @defgroup iot_error IoT SDK error codes
+ * @{
+ * @ingroup iot_sdk_common
+ * @{
+ * @brief Error codes for the nRF5x IoT SDK.
+ *
+ * @details
+ * Error codes are 32-bit unsigned integers. The most significant 16 bits (MSB) are reserved for
+ * identifying the module where the error occurred. The least significant 16 bits (LSB)
+ * are used to provide the cause or nature of error. Each module is assigned a 16-bit
+ * unsigned integer, which it will use to identify all errors that occurred in the module.
+ * For example, if 0x8800 identifies a certain SDK module, all error codes from
+ * 0x88000000 to 0x8800FFFF are reserved for this module.
+ *
+ * Note that common error reasons have been assigned values to make it
+ * possible to decode error reasons easily. As an example, if a module is not initialized,
+ * this error is assigned the error code 0x000A0. If an application encounters an error code
+ * 0xZZZZ00A0, the application knows that it tried to access a certain module without
+ * initializing it.
+ *
+ * Each module can define error codes that are not covered by
+ * the common codes. These values must be defined in a range that does not conflict
+ * with the common error values. Such module-specific error values might be used by
+ * different modules to indicate errors of very different nature; so the same error code LSB
+ * does not necessarily indicate the same error. If an error is already defined by the NRF
+ * common error codes, however, these codes are reused.
+ *
+ * A specific range is also reserved for the application. The application can use this range
+ * to define application-specific errors.
+ *
+ * The success code NRF_SUCCESS does not include a module identifier.
+
+ */
+
+#ifndef IOT_ERRORS_H__
+#define IOT_ERRORS_H__
+
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup sdk_iot_err_base Base defined for IoT SDK Modules
+ * @{
+ */
+#define IOT_ERR_BASE NRF_ERROR_IOT_ERR_BASE_START
+/* @} */
+
+
+/**
+ * @defgroup sdk_iot_module_codes Module codes
+ * @brief Codes reserved as identification for the module where the error occurred.
+ * @{
+ */
+#define BLE_6LOWPAN_ERR_BASE (IOT_ERR_BASE+0x0200)
+
+#define IOT_PBUFFER_ERR_BASE (IOT_ERR_BASE+0x1000)
+#define IOT_CONTEXT_MANAGER_ERR_BASE (IOT_ERR_BASE+0x1100)
+#define IOT_TIMER_ERR_BASE (IOT_ERR_BASE+0x1200)
+#define IOT_FILE_ERR_BASE (IOT_ERR_BASE+0x1300)
+#define IOT_DFU_ERR_BASE (IOT_ERR_BASE+0x1400)
+#define IOT_IPV6_ERR_BASE (IOT_ERR_BASE+0x2000)
+#define IOT_ICMP6_ERR_BASE (IOT_ERR_BASE+0x2100)
+#define IOT_UDP6_ERR_BASE (IOT_ERR_BASE+0x2200)
+#define IOT_COAP_ERR_BASE (IOT_ERR_BASE+0x2300)
+#define IOT_DNS6_ERR_BASE (IOT_ERR_BASE+0x2400)
+#define IOT_NTP_ERR_BASE (IOT_ERR_BASE+0x2500)
+#define IOT_LWM2M_ERR_BASE (IOT_ERR_BASE+0x2600)
+#define IOT_SOCKET_ERR_BASE (IOT_ERR_BASE+0x2700)
+#define IOT_TFTP_ERR_BASE (IOT_ERR_BASE+0x2800)
+#define IOT_MQTT_ERR_BASE (IOT_ERR_BASE+0x2900)
+#define IOT_TLS_ERR_BASE (IOT_ERR_BASE+0x2A00)
+#define IOT_TRICKLE_ERR_BASE (IOT_ERR_BASE+0x2C00)
+/* @} */
+
+
+/**
+ * @defgroup iot_sdk_common_errors Common error codes
+ * @brief Codes reserved as identification for common errors.
+ * @{
+ */
+#define SDK_ERR_MODULE_NOT_INITIALIZED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0000)
+#define SDK_ERR_MUTEX_INIT_FAILED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0001)
+#define SDK_ERR_MUTEX_LOCK_FAILED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0002)
+#define SDK_ERR_MUTEX_UNLOCK_FAILED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0003)
+#define SDK_ERR_MUTEX_COND_INIT_FAILED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0004)
+#define SDK_ERR_MODULE_ALREADY_INITIALZED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0005)
+#define SDK_ERR_API_NOT_IMPLEMENTED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0010)
+#define SDK_ERR_FEATURE_NOT_ENABLED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0011)
+#define SDK_ERR_RX_PKT_TRUNCATED (NRF_ERROR_SDK_COMMON_ERROR_BASE+0x0012)
+/* @} */
+
+
+/**
+ * @defgroup ble_6lowpan_errors 6LoWPAN codes
+ * @brief Error and status codes specific to 6LoWPAN.
+ * @{
+ */
+#define BLE_6LOWPAN_CID_NOT_FOUND (BLE_6LOWPAN_ERR_BASE+0x0040)
+#define BLE_6LOWPAN_TX_FIFO_FULL (BLE_6LOWPAN_ERR_BASE+0x0041)
+/* @} */
+
+
+/**
+ * @defgroup iot_sdk_ipv6 IPv6 codes
+ * @brief Error and status codes specific to IPv6.
+ * @{
+ */
+#define IOT_IPV6_ERR_ADDR_IF_MISMATCH (IOT_IPV6_ERR_BASE+0x0040)
+#define IOT_IPV6_ERR_PENDING (IOT_IPV6_ERR_BASE+0x0041)
+/* @} */
+
+
+/**
+ * @defgroup iot_sdk_udp_errors UDP codes
+ * @brief Error and status codes specific to UDP.
+ * @{
+ */
+#define UDP_PORT_IN_USE (IOT_UDP6_ERR_BASE+0x0040)
+#define UDP_BAD_CHECKSUM (IOT_UDP6_ERR_BASE+0x0041)
+#define UDP_TRUNCATED_PACKET (IOT_UDP6_ERR_BASE+0x0042)
+#define UDP_MALFORMED_PACKET (IOT_UDP6_ERR_BASE+0x0043)
+#define UDP_INTERFACE_NOT_READY (IOT_UDP6_ERR_BASE+0x0044)
+/* @} */
+
+/**
+ * @defgroup iot_sdk_socket_errors socket error codes
+ * @brief Error and status codes specific to socket API.
+ * @{
+ */
+#define SOCKET_PORT_IN_USE (IOT_SOCKET_ERR_BASE + 0x0040)
+#define SOCKET_NO_AVAILABLE_PORTS (IOT_SOCKET_ERR_BASE + 0x0041)
+#define SOCKET_WOULD_BLOCK (IOT_SOCKET_ERR_BASE + 0x0042)
+#define SOCKET_NO_MEM (IOT_SOCKET_ERR_BASE + 0x0043)
+#define SOCKET_NO_ROUTE (IOT_SOCKET_ERR_BASE + 0x0044)
+#define SOCKET_TIMEOUT (IOT_SOCKET_ERR_BASE + 0x0045)
+#define SOCKET_INTERFACE_NOT_READY (IOT_SOCKET_ERR_BASE + 0x0046)
+#define SOCKET_INVALID_PARAM (IOT_SOCKET_ERR_BASE + 0x0047)
+#define SOCKET_UNSUPPORTED_PROTOCOL (IOT_SOCKET_ERR_BASE + 0x0048)
+#define SOCKET_ADDRESS_IN_USE (IOT_SOCKET_ERR_BASE + 0x0049)
+#define SOCKET_NOT_CONNECTED (IOT_SOCKET_ERR_BASE + 0x0050)
+/* @} */
+
+/**
+ * @defgroup iot_sdk_icmp6_errors ICMP codes
+ * @brief Error and status codes specific to ICMP.
+ * @{
+ */
+#define ICMP6_UNHANDLED_PACKET_TYPE (IOT_ICMP6_ERR_BASE+0x0040)
+#define ICMP6_BAD_CHECKSUM (IOT_ICMP6_ERR_BASE+0x0041)
+#define ICMP6_MALFORMED_PACKET (IOT_ICMP6_ERR_BASE+0x0042)
+#define ICMP6_INVALID_PACKET_DATA (IOT_ICMP6_ERR_BASE+0x0043)
+/* @} */
+
+
+/**
+ * @defgroup iot_sdk_coap_errros CoAP codes
+ * @brief Error and status codes specific to CoAP.
+ * @{
+ */
+#define COAP_MESSAGE_ERROR_NULL (IOT_COAP_ERR_BASE+0x0040)
+#define COAP_MESSAGE_ERROR_INVALID_CONF (IOT_COAP_ERR_BASE+0x0041)
+#define COAP_MESSAGE_INVALID_CONTENT (IOT_COAP_ERR_BASE+0x0042)
+#define COAP_TRANSMISSION_RESET_BY_PEER (IOT_COAP_ERR_BASE+0x0043)
+#define COAP_TRANSMISSION_TIMEOUT (IOT_COAP_ERR_BASE+0x0044)
+#define COAP_TRANSPORT_SECURITY_MISSING (IOT_COAP_ERR_BASE+0x0045)
+#define COAP_REQUEST_RESOURCE_NOT_FOUND (IOT_COAP_ERR_BASE+0x0046)
+#define COAP_REQUEST_HANDLER_NOT_FOUND (IOT_COAP_ERR_BASE+0x0047)
+/* @} */
+
+
+/**
+ * @defgroup iot_sdk_dns6_errors DNS codes.
+ * @brief Error and status codes specific to DNS.
+ * @{
+ */
+#define DNS6_SERVER_UNREACHABLE (IOT_DNS6_ERR_BASE+0x0040)
+#define DNS6_FORMAT_ERROR (IOT_DNS6_ERR_BASE+0x0041)
+#define DNS6_SERVER_FAILURE (IOT_DNS6_ERR_BASE+0x0042)
+#define DNS6_HOSTNAME_NOT_FOUND (IOT_DNS6_ERR_BASE+0x0043)
+#define DNS6_NOT_IMPLEMENTED (IOT_DNS6_ERR_BASE+0x0044)
+#define DNS6_REFUSED_ERROR (IOT_DNS6_ERR_BASE+0x0045)
+#define DNS6_RESPONSE_TRUNCATED (IOT_DNS6_ERR_BASE+0x0046)
+/* @} */
+
+
+/**
+ * @defgroup iot_sdk_ntp_errors NTP codes.
+ * @brief Error and status codes specific to NTP.
+ * @{
+ */
+#define NTP_SERVER_UNREACHABLE (IOT_NTP_ERR_BASE+0x0040)
+#define NTP_SERVER_BAD_RESPONSE (IOT_NTP_ERR_BASE+0x0041)
+#define NTP_SERVER_KOD_PACKET_RECEIVED (IOT_NTP_ERR_BASE+0x0042)
+/* @} */
+
+/**
+ * @defgroup iot_sdk_tftp_errors TFTP codes.
+ * @brief Error and status codes specific to TFTP.
+ * @{
+ */
+ /**@brief TFTP Error codes. */
+#define TFTP_UNDEFINED_ERROR (IOT_TFTP_ERR_BASE+0x0040)
+#define TFTP_FILE_NOT_FOUND (IOT_TFTP_ERR_BASE+0x0041)
+#define TFTP_ACCESS_DENIED (IOT_TFTP_ERR_BASE+0x0042)
+#define TFTP_FULL_STORAGE (IOT_TFTP_ERR_BASE+0x0043)
+#define TFTP_INVALID_OPCODE (IOT_TFTP_ERR_BASE+0x0044)
+#define TFTP_INVALID_TID (IOT_TFTP_ERR_BASE+0x0045)
+#define TFTP_FILE_EXSISTS (IOT_TFTP_ERR_BASE+0x0046)
+#define TFTP_WRONG_USERNAME (IOT_TFTP_ERR_BASE+0x0047)
+#define TFTP_OPTION_REJECT (IOT_TFTP_ERR_BASE+0x0048)
+#define TFTP_INVALID_PACKET (IOT_TFTP_ERR_BASE+0x0049)
+#define TFTP_REMOTE_UNREACHABLE (IOT_TFTP_ERR_BASE+0x004A)
+ /* @} */
+
+/**@defgroup iot_sdk_mqtt_err_code MQTT Error Codes
+ *@{
+ */
+#define MQTT_ERR_NOT_CONNECTED (IOT_MQTT_ERR_BASE+0x0040)
+#define MQTT_ERR_WRITE (IOT_MQTT_ERR_BASE+0x0041)
+#define MQTT_ERR_TCP_PROC_FAILED (IOT_MQTT_ERR_BASE+0x0042)
+#define MQTT_CONNECTION_FAILED (IOT_MQTT_ERR_BASE+0x0043)
+#define MQTT_ERR_TRANSPORT_CLOSED (IOT_MQTT_ERR_BASE+0x0044)
+/**@}
+ */
+
+
+/**@defgroup iot_sdk_tls_err_code NRF TLS Interface Error Codes
+ *@{
+ */
+#define NRF_TLS_CONFIGURATION_FAILED (IOT_TLS_ERR_BASE+0x0040)
+#define NRF_TLS_CONTEXT_SETUP_FAILED (IOT_TLS_ERR_BASE+0x0041)
+#define NRF_TLS_HANDSHAKE_IN_PROGRESS (IOT_TLS_ERR_BASE+0x0042)
+#define NRF_TLS_NO_FREE_INSTANCE (IOT_TLS_ERR_BASE+0x0043)
+#define NRF_TLS_INVALID_CA_CERTIFICATE (IOT_TLS_ERR_BASE+0x0044)
+#define NRF_TLS_OWN_CERT_SETUP_FAILED (IOT_TLS_ERR_BASE+0x0045)
+/**@}
+ */
+
+/** @} */
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_ERRORS_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.c
new file mode 100644
index 0000000..a0c66ac
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.c
@@ -0,0 +1,561 @@
+/**
+ * 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_context_manager.h"
+
+#if IOT_CONTEXT_MANAGER_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME context_manager
+
+#define NRF_LOG_LEVEL IOT_CONTEXT_MANAGER_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IOT_CONTEXT_MANAGER_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IOT_CONTEXT_MANAGER_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define CM_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define CM_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define CM_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define CM_ENTRY() CM_TRC(">> %s", __func__)
+#define CM_EXIT() CM_TRC("<< %s", __func__)
+
+#else // IOT_CONTEXT_MANAGER_CONFIG_LOG_ENABLED
+
+#define CM_TRC(...) /**< Disables traces. */
+#define CM_DUMP(...) /**< Disables dumping of octet streams. */
+#define CM_ERR(...) /**< Disables error logs. */
+
+#define CM_ENTRY(...)
+#define CM_EXIT(...)
+
+#endif // IOT_CONTEXT_MANAGER_CONFIG_LOG_ENABLED
+
+/**@brief Parameter maximum values. */
+#define CID_VALUE_MAX 15
+#define PREFIX_LENGTH_VALUE_MAX 128
+
+/**
+ * @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.
+ * IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
+ *
+ * @{
+ */
+#if (IOT_CONTEXT_MANAGER_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_CONTEXT_MANAGER_ERR_BASE); \
+ }
+
+/**@brief Macro to check is module is initialized before requesting one of the module procedures. */
+#define VERIFY_MODULE_IS_INITIALIZED_NULL() \
+ if (m_initialization_state == false) \
+ { \
+ return NULL; \
+ }
+
+/**
+ * @brief Verify NULL parameters are not passed to API by application.
+ */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_CONTEXT_MANAGER_ERR_BASE); \
+ }
+
+/**
+ * @brief Verify CID has valid value.
+ */
+#define VERIFY_CID_VALUE(CID) \
+ if (!((CID) <= CID_VALUE_MAX)) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_CONTEXT_MANAGER_ERR_BASE); \
+ }
+
+/**
+ * @brief Verify prefix length value.
+ */
+#define VERIFY_PREFIX_LEN_VALUE(PREFIX_LEN) \
+ if (!(PREFIX_LEN <= PREFIX_LENGTH_VALUE_MAX)) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_CONTEXT_MANAGER_ERR_BASE); \
+ }
+
+#else // IOT_IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define VERIFY_MODULE_IS_INITIALIZED_NULL()
+#define NULL_PARAM_CHECK(PARAM)
+#define VERIFY_CID_VALUE(CID)
+#define VERIFY_PREFIX_LEN_VALUE(PREFIX_LEN)
+
+#endif //IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK
+/** @} */
+
+/**
+ * @defgroup iot_context_manager_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 CM_MUTEX_LOCK() SDK_MUTEX_LOCK(m_iot_context_manager_mutex) /**< Lock module using mutex */
+#define CM_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_iot_context_manager_mutex) /**< Unlock module using mutex */
+/** @} */
+
+/**@brief Context table, managing by IPv6 stack. */
+typedef struct
+{
+ iot_interface_t * p_interface; /**< IoT interface pointer. */
+ uint8_t context_count; /**< Number of valid contexts in the table. */
+ iot_context_t contexts[IOT_CONTEXT_MANAGER_MAX_CONTEXTS]; /**< Array of valid contexts. */
+}iot_context_table_t;
+
+
+SDK_MUTEX_DEFINE(m_iot_context_manager_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 iot_context_table_t m_context_table[IOT_CONTEXT_MANAGER_MAX_TABLES]; /**< Array of contexts table managed by the module. */
+
+/**@brief Initializes context entry. */
+static void context_init(iot_context_t * p_context)
+{
+ p_context->context_id = IPV6_CONTEXT_IDENTIFIER_NONE;
+ p_context->prefix_len = 0;
+ p_context->compression_flag = false;
+
+ memset(p_context->prefix.u8, 0, IPV6_ADDR_SIZE);
+}
+
+
+/**@brief Initializes context table. */
+static void context_table_init(uint32_t table_id)
+{
+ uint32_t index;
+
+ for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS; index++)
+ {
+ context_init(&m_context_table[table_id].contexts[index]);
+ m_context_table[table_id].context_count = 0;
+ m_context_table[table_id].p_interface = NULL;
+ }
+}
+
+
+/**@brief Initializes context table. */
+static uint32_t context_table_find(const iot_interface_t * p_interface)
+{
+ uint32_t index;
+
+ for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_TABLES; index++)
+ {
+ if (m_context_table[index].p_interface == p_interface)
+ {
+ break;
+ }
+ }
+
+ return index;
+}
+
+
+/**@brief Looks up context table for specific context identifier. */
+static uint32_t context_find_by_cid(uint32_t table_id,
+ uint8_t context_id,
+ iot_context_t ** pp_context)
+{
+ uint32_t index;
+
+ for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS; index++)
+ {
+ if (m_context_table[table_id].contexts[index].context_id == context_id)
+ {
+ *pp_context = &m_context_table[table_id].contexts[index];
+ return NRF_SUCCESS;
+ }
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+}
+
+
+static uint32_t context_find_by_prefix(uint32_t table_id,
+ const ipv6_addr_t * p_prefix,
+ iot_context_t ** pp_context)
+{
+ uint32_t index;
+ uint32_t context_left;
+ uint16_t context_cmp_len;
+ iot_context_t * p_best_match = NULL;
+
+ context_left = m_context_table[table_id].context_count;
+
+ for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS && context_left; index++)
+ {
+ if (m_context_table[table_id].contexts[index].context_id != IPV6_CONTEXT_IDENTIFIER_NONE &&
+ m_context_table[table_id].contexts[index].compression_flag == true)
+ {
+ if ((context_cmp_len = m_context_table[table_id].contexts[index].prefix_len) < 64)
+ {
+ context_cmp_len = 64;
+ }
+
+ // Check if address have matched in CID table.
+ if (IPV6_ADDRESS_PREFIX_CMP(m_context_table[table_id].contexts[index].prefix.u8,
+ p_prefix->u8,
+ context_cmp_len))
+ {
+ if (p_best_match == NULL || p_best_match->prefix_len <
+ m_context_table[table_id].contexts[index].prefix_len)
+ {
+ p_best_match = &m_context_table[table_id].contexts[index];
+ }
+ }
+
+ // Decrease left context in table, to avoid too many checking.
+ context_left--;
+ }
+ }
+
+ if (p_best_match)
+ {
+ *pp_context = p_best_match;
+ return NRF_SUCCESS;
+ }
+
+ return (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+}
+
+
+/**@brief Looks up for first empty entry in the table. */
+static uint32_t context_find_free(uint32_t table_id, iot_context_t ** pp_context)
+{
+ uint32_t index;
+
+ for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS; index++)
+ {
+ if (m_context_table[table_id].contexts[index].context_id == IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ *pp_context = &m_context_table[table_id].contexts[index];
+ return NRF_SUCCESS;
+ }
+ }
+
+ return (NRF_ERROR_NO_MEM | IOT_CONTEXT_MANAGER_ERR_BASE);
+}
+
+
+uint32_t iot_context_manager_init(void)
+{
+ uint32_t index;
+
+ CM_ENTRY();
+
+ SDK_MUTEX_INIT(m_iot_context_manager_mutex);
+
+ CM_MUTEX_LOCK();
+
+ for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_TABLES; index++)
+ {
+ context_table_init(index);
+ }
+
+ m_initialization_state = true;
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t iot_context_manager_table_alloc(const iot_interface_t * p_interface)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t err_code = NRF_SUCCESS;
+
+ CM_ENTRY();
+
+ CM_MUTEX_LOCK();
+
+ const uint32_t table_id = context_table_find(NULL);
+
+ if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
+ {
+ // Found a free context table and assign to it.
+ CM_TRC("Assigned new context table.");
+ m_context_table[table_id].p_interface = (iot_interface_t *)p_interface;
+ }
+ else
+ {
+ // No free context table found.
+ CM_ERR("No context table found.");
+ err_code = (NRF_ERROR_NO_MEM | IOT_CONTEXT_MANAGER_ERR_BASE);
+ }
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_context_manager_table_free(const iot_interface_t * p_interface)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+
+ uint32_t err_code = NRF_SUCCESS;
+
+ CM_ENTRY();
+
+ SDK_MUTEX_INIT(m_iot_context_manager_mutex);
+
+ CM_MUTEX_LOCK();
+
+ const uint32_t table_id = context_table_find(p_interface);
+
+ if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
+ {
+ // Clear context table.
+ CM_TRC("Found context table assigned to interface.");
+ context_table_init(table_id);
+ }
+ else
+ {
+ // No free context table found.
+ CM_ERR("No context table found.");
+ err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+ }
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_context_manager_update(const iot_interface_t * p_interface,
+ iot_context_t * p_context)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_context);
+ VERIFY_CID_VALUE(p_context->context_id);
+ VERIFY_PREFIX_LEN_VALUE(p_context->prefix_len);
+
+ uint32_t retval = NRF_SUCCESS;
+ uint32_t err_code = NRF_SUCCESS;
+ iot_context_t * p_internal_context;
+
+ CM_ENTRY();
+
+ CM_MUTEX_LOCK();
+
+ const uint32_t table_id = context_table_find(p_interface);
+
+ if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
+ {
+ // Try to find context in context table.
+ retval = context_find_by_cid(table_id, p_context->context_id, &p_internal_context);
+
+ if (retval != NRF_SUCCESS)
+ {
+ err_code = context_find_free(table_id, &p_internal_context);
+
+ // Increase context count.
+ if (err_code == NRF_SUCCESS)
+ {
+ m_context_table[table_id].context_count++;
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Update context table, with parameters from application.
+ p_internal_context->context_id = p_context->context_id;
+ p_internal_context->prefix_len = p_context->prefix_len;
+ p_internal_context->compression_flag = p_context->compression_flag;
+ memset(p_internal_context->prefix.u8, 0, IPV6_ADDR_SIZE);
+ IPV6_ADDRESS_PREFIX_SET(p_internal_context->prefix.u8, p_context->prefix.u8, p_context->prefix_len);
+ }
+ else
+ {
+ CM_ERR("No place in context table.");
+ }
+ }
+ else
+ {
+ // No free context table found.
+ CM_ERR("No context table found.");
+ err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+ }
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_context_manager_remove(const iot_interface_t * p_interface,
+ iot_context_t * p_context)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_context);
+
+ uint32_t err_code = NRF_SUCCESS;
+
+ CM_ENTRY();
+
+ CM_MUTEX_LOCK();
+
+ const uint32_t table_id = context_table_find(p_interface);
+
+ if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
+ {
+ if (p_context->context_id != IPV6_CONTEXT_IDENTIFIER_NONE)
+ {
+ m_context_table[table_id].context_count--;
+ }
+
+ // Reinit context entry.
+ context_init(p_context);
+ }
+ else
+ {
+ // No free context table found.
+ CM_ERR("No context table found.");
+ err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+ }
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_context_manager_get_by_addr(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_addr,
+ iot_context_t ** pp_context)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_addr);
+ NULL_PARAM_CHECK(pp_context);
+
+ uint32_t err_code;
+
+ CM_ENTRY();
+
+ CM_MUTEX_LOCK();
+
+ const uint32_t table_id = context_table_find(p_interface);
+
+ if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
+ {
+ err_code = context_find_by_prefix(table_id, p_addr, pp_context);
+ }
+ else
+ {
+ // No free context table found.
+ CM_ERR("No context table found.");
+ err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+ }
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_context_manager_get_by_cid(const iot_interface_t * p_interface,
+ uint8_t context_id,
+ iot_context_t ** pp_context)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(pp_context);
+ VERIFY_CID_VALUE(context_id);
+
+ uint32_t err_code;
+
+ CM_ENTRY();
+
+ CM_MUTEX_LOCK();
+
+ const uint32_t table_id = context_table_find(p_interface);
+
+ if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
+ {
+ err_code = context_find_by_cid(table_id, context_id, pp_context);
+ }
+ else
+ {
+ // No free context table found.
+ CM_TRC("No context table found.");
+ err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
+ }
+
+ CM_MUTEX_UNLOCK();
+
+ CM_EXIT();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.h
new file mode 100644
index 0000000..7fec245
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/context_manager/iot_context_manager.h
@@ -0,0 +1,155 @@
+/**
+ * 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup iot_context_manager Context Manager
+ * @{
+ * @ingroup iot_sdk_common
+ * @brief Manages context identifiers and prefixes related to the identifiers.
+ *
+ * @details This module allows to handle context information throughout the IoT application.
+ * The module is used in the compression and decompression procedures of IPv6 addresses.
+ * It allows more efficient communication between two nodes using global addresses.
+ * The Context Manager contains tables of context, which can be accessed through API functions.
+ * The table is maintained by the IPv6 stack while is referenced by 6LoWPAN module to be able to
+ * compress and decompress packets.
+ *
+ * You can configure the module by changing the @c sdk_config.h configuration file.
+ */
+
+#ifndef IOT_CONTEXT_MANAGER__
+#define IOT_CONTEXT_MANAGER__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "iot_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Function for initializing the module.
+ *
+ * @retval NRF_SUCCESS If the module was successfully initialized. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_init(void);
+
+
+/**@brief Function for allocating the table for the specific interface.
+ *
+ * @param[in] p_interface Pointer to the IoT interface.
+ *
+ * @retval NRF_SUCCESS If the table was successfully allocated. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_table_alloc(const iot_interface_t * p_interface);
+
+
+/**@brief Function for freeing the table for the specific interface.
+ *
+ * @param[in] p_interface Pointer to the IoT interface.
+ *
+ * @retval NRF_SUCCESS If the table was successfully freed. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_table_free(const iot_interface_t * p_interface);
+
+
+/**@brief Function for updating the context table.
+ *
+ * Update requests are treated as follows:
+ * - If the context identifier already exists in the context table, the context
+ * is updated.
+ * - If the context identifier does not exist yet, a new entry is generated. If
+ * no memory is available, NRF_ERROR_NO_MEMORY is returned.
+ *
+ * The compression flag indicates if a context can be used for compression.
+ * The context table can hold up to 16 context's information.
+ *
+ * @param[in] p_interface Pointer to the IoT interface.
+ * @param[in] p_context Pointer to the context entry that shall be modified or added.
+ *
+ * @retval NRF_SUCCESS If the table was successfully updated. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_update(const iot_interface_t * p_interface, iot_context_t * p_context);
+
+
+/**@brief Function for removing context from the context table.
+ *
+ * @param[in] p_interface Pointer to the IoT interface.
+ * @param[in] p_context Pointer to the context entry, retrieved from @ref iot_context_manager_get_by_addr or
+ * @ref iot_context_manager_get_by_cid.
+ *
+ * @retval NRF_SUCCESS If the context was successfully removed. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_remove(const iot_interface_t * p_interface, iot_context_t * p_context);
+
+
+/**@brief Function for searching the proper entry in the context table by IPv6 address.
+ * Only contexts with compression flag set to true, may be returned.
+ *
+ * @param[in] p_interface Pointer to the IoT interface.
+ * @param[in] p_addr Pointer to IPv6 address to be compared with records in the context table.
+ * @param[out] pp_context Pointer to the context in the context table.
+ *
+ * @retval NRF_SUCCESS If the procedure succeeded. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_get_by_addr(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_addr,
+ iot_context_t ** pp_context);
+
+
+/**@brief Function for searching the proper entry in the context table by context identifier.
+ *
+ * @param[in] p_interface Pointer to the IoT interface.
+ * @param[in] context_id Context identifier to be compared with records in the context table.
+ * @param[out] pp_context Pointer to the context in the context table.
+ *
+ * @retval NRF_SUCCESS If the procedure succeeded. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_context_manager_get_by_cid(const iot_interface_t * p_interface,
+ uint8_t context_id,
+ iot_context_t ** pp_context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_CONTEXT_MANAGER__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.c
new file mode 100644
index 0000000..f1d79b5
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.c
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015 - 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 "errno.h"
+
+// TODO: Support multiple contexts
+static int m_errno_main;
+
+int *
+__error(void)
+{
+ return &m_errno_main;
+}
+
+void
+set_errno(int err_code)
+{
+ m_errno_main = err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.h
new file mode 100644
index 0000000..f2ec459
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/errno/errno.h
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+#ifndef ERRNO_H__
+#define ERRNO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EBADF 9
+#define ENOMEM 12
+#define EFAULT 14
+#define EINVAL 22
+#define EMFILE 24
+#define EAGAIN 35
+#define EPROTONOSUPPORT 43
+#define EOPNOTSUPP 45
+#define EAFNOSUPPORT 47
+#define EADDRINUSE 48
+#define ENETDOWN 50
+#define ENETUNREACH 51
+#define ECONNRESET 54
+#define EISCONN 56
+#define ENOTCONN 57
+#define ETIMEDOUT 60
+
+#define EINPROGRESS 115 /* Operation in progress. */
+#define ECANCELED 125 /* Operation canceled. */
+int * __error(void);
+void set_errno(int);
+
+#undef errno
+#define errno (* __error())
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ERRNO_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.c
new file mode 100644
index 0000000..285be29
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.c
@@ -0,0 +1,195 @@
+/**
+ * Copyright (c) 2015 - 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 "sdk_config.h"
+#include "iot_file.h"
+#include "iot_common.h"
+
+/**
+ * @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.
+ * IOT_FILE_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+#if (IOT_FILE_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_FILE_ERR_BASE); \
+ }
+
+#else // IOT_FILE_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // IOT_FILE_DISABLE_API_PARAM_CHECK
+/** @} */
+
+
+/**
+ * @brief Function to open IoT file. Depending on port, it should allocate required buffer.
+ */
+uint32_t iot_file_fopen(iot_file_t * p_file, uint32_t requested_size)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->open != NULL)
+ {
+ return p_file->open(p_file, requested_size);
+ }
+ else
+ {
+ p_file->buffer_size = requested_size;
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
+
+/**
+ * @brief Function to write data buffer into a file.
+ */
+uint32_t iot_file_fwrite(iot_file_t * p_file, const void * p_data, uint32_t size)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->write != NULL)
+ {
+ return p_file->write(p_file, p_data, size);
+ }
+ else
+ {
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
+
+/**
+ * @brief Function to read data buffer from file.
+ */
+uint32_t iot_file_fread(iot_file_t * p_file, void * p_data, uint32_t size)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->read != NULL)
+ {
+ return p_file->read(p_file, p_data, size);
+ }
+ else
+ {
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
+
+/**
+ * @brief Function to read current cursor position.
+ */
+uint32_t iot_file_ftell(iot_file_t * p_file, uint32_t * p_cursor)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->tell != NULL)
+ {
+ return p_file->tell(p_file, p_cursor);
+ }
+ else
+ {
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
+
+/**
+ * @brief Function to set current cursor position.
+ */
+uint32_t iot_file_fseek(iot_file_t * p_file, uint32_t cursor)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->seek != NULL)
+ {
+ return p_file->seek(p_file, cursor);
+ }
+ else
+ {
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
+
+/**
+ * @brief Function to rewind file cursor.
+ */
+uint32_t iot_file_frewind(iot_file_t * p_file)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->rewind != NULL)
+ {
+ return p_file->rewind(p_file);
+ }
+ else
+ {
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
+
+/**
+ * @brief Function to close IoT file. Depending on port, it should free used buffer.
+ */
+uint32_t iot_file_fclose(iot_file_t * p_file)
+{
+ NULL_PARAM_CHECK(p_file);
+
+ if (p_file->close != NULL)
+ {
+ return p_file->close(p_file);
+ }
+ else
+ {
+ return NRF_ERROR_API_NOT_IMPLEMENTED;
+ }
+}
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.h
new file mode 100644
index 0000000..c4afa7b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file.h
@@ -0,0 +1,175 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**
+ * @file iot_file.h
+ * @brief IoT File abstraction API.
+ */
+
+#ifndef IOT_FILE_H__
+#define IOT_FILE_H__
+
+#include "iot_common.h"
+#include "iot_file_port.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup iot_sdk_common
+ * @addtogroup iot_file IoT File
+ * @brief IoT File abstraction definition.
+ * @{
+ * @defgroup iot_file_abstraction IoT file abstraction
+ * @{
+ * @brief Structures and public API definition.
+ */
+
+/**
+ * @enum iot_file_evt_t
+ * @brief List of events returned in callback for file ports with asynchronous operation
+ * like open, read, write and close.
+ */
+typedef enum {
+ IOT_FILE_OPENED, /**< Event indicates that file has been opened.*/
+ IOT_FILE_WRITE_COMPLETE, /**< Event indicates that single write operation has been completed.*/
+ IOT_FILE_READ_COMPLETE, /**< Event indicates that single read operation has been completed.*/
+ IOT_FILE_CLOSED, /**< Event indicates that file has been closed.*/
+ IOT_FILE_ERROR /**< Event indicates that file encountered a problem.*/
+} iot_file_evt_t;
+
+/**
+ * @brief IoT File user callback type definition.
+ *
+ * @param[in] p_file Reference to an IoT file instance.
+ * @param[in] event Event structure describing what has happened.
+ * @param[in] result Result code (should be NRF_SUCCESS for all events except errors).
+ * @param[in] p_data Pointer to memory buffer.
+ * @param[in] size Size of data stored in memory buffer.
+ *
+ * @retval None.
+ */
+typedef void (*iot_file_callback_t) (iot_file_t * p_file, iot_file_evt_t event, uint32_t result, void * p_data, uint32_t size);
+
+/**
+ * @brief Function to open IoT file. Depending on port, it should allocate required buffer.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ * @param[in] requested_size Maximum number of bytes to be read/written.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_fopen(iot_file_t * p_file, uint32_t requested_size);
+
+/**
+ * @brief Function to write data buffer into a file.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ * @param[in] p_data Pointer to data block which will be written into the file.
+ * @param[in] size Number of bytes to be written.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_fwrite(iot_file_t * p_file, const void * p_data, uint32_t size);
+
+/**
+ * @brief Function to read data buffer from file.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ * @param[in] p_data Pointer to data block to be filled with read data.
+ * @param[in] size Number of bytes to be read.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_fread(iot_file_t * p_file, void * p_data, uint32_t size);
+
+/**
+ * @brief Function to read current cursor position.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ * @param[out] p_cursor Current value of a cursor.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_ftell(iot_file_t * p_file, uint32_t * p_cursor);
+
+/**
+ * @brief Function to set current cursor position.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ * @param[in] cursor New cursor value.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_fseek(iot_file_t * p_file, uint32_t cursor);
+
+/**
+ * @brief Function to rewind file cursor.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_frewind(iot_file_t * p_file);
+
+/**
+ * @brief Function to close IoT file. Depending on port, it should free used buffer.
+ *
+ * @param[in] p_file Pointer to an IoT file instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_file_fclose(iot_file_t * p_file);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_FILE_H__
+
+/** @} */
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file_port.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file_port.h
new file mode 100644
index 0000000..23e53d3
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/iot_file_port.h
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**
+ * @file iot_file_port.h
+ * @brief Types and definitions used while writing port.
+ */
+
+#ifndef IOT_FILE_PORT_H__
+#define IOT_FILE_PORT_H__
+
+/**
+ * @defgroup iot_file_port_defs IoT file definition for port libraries.
+ * @{
+ * @ingroup iot_file
+ * @brief Type definitions for port modules.
+ */
+#include <stdint.h>
+#include <string.h>
+#include "nordic_common.h"
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//NOTE: Port functions don't need to check if p_file exists, because call can be done only on a correct file instance.
+
+#define IOT_FILE_INVALID_CURSOR 0xFFFFFFFF
+
+/**
+ * @enum iot_file_type_t
+ * @brief Supported file type values.
+ */
+typedef enum
+{
+ IOT_FILE_TYPE_UNKNOWN = 0, /**< File type used for describing not initialized files. */
+ IOT_FILE_TYPE_PSTORAGE_RAW, /**< File type used for accessing flash memory. */
+ IOT_FILE_TYPE_STATIC /**< File type used for representing static buffers. */
+} iot_file_type_t;
+
+/**
+ * @brief iot_file_t structure forward definition.
+ */
+typedef struct iot_file_struct_t iot_file_t;
+
+/**
+ * @brief IoT File fopen() callback type definition.
+ */
+typedef uint32_t (*iot_fopen_t)(iot_file_t * p_file, uint32_t requested_size);
+
+/**
+ * @brief IoT File fwrite() callback type definition.
+ */
+typedef uint32_t (*iot_fwrite_t)(iot_file_t * p_file, const void * p_data, uint32_t size);
+
+/**
+ * @brief IoT File fread() callback type definition.
+ */
+typedef uint32_t (*iot_fread_t)(iot_file_t * p_file, void * p_data, uint32_t size);
+
+/**
+ * @brief IoT File ftell() callback type definition.
+ */
+typedef uint32_t (*iot_ftell_t)(iot_file_t * p_file, uint32_t * p_cursor);
+
+/**
+ * @brief IoT File fseek() callback type definition.
+ */
+typedef uint32_t (*iot_fseek_t)(iot_file_t * p_file, uint32_t cursor);
+
+/**
+ * @brief IoT File frewind() callback type definition.
+ */
+typedef uint32_t (*iot_frewind_t)(iot_file_t * p_file);
+
+/**
+ * @brief IoT File fclose() callback type definition.
+ */
+typedef uint32_t (*iot_fclose_t)(iot_file_t * p_file);
+
+/**
+ * @brief Generic IoT File instance structure.
+ */
+struct iot_file_struct_t
+{
+ const char * p_filename; /**< Public. String constant describing file name. */
+ iot_file_type_t type; /**< Public. Type of file. Each type should be added into iot_file_type_t enum. */
+ uint32_t file_size; /**< Public. Number of valid bytes inside file. */
+
+ uint32_t cursor; /**< Internal. Cursor describing which byte will be read/written. */
+ uint32_t buffer_size; /**< Internal. Size of data buffer. */
+ void * p_buffer; /**< Internal. Pointer to a data buffer set by calling fopen. */
+ void * p_callback; /**< Internal. User callback used in order to notify about finished file operations. */
+ void * p_arg; /**< Internal. User defined argument, used inside the port. */
+ iot_fopen_t open; /**< Internal. Callback for fopen operation assigned by particular port. */
+ iot_fwrite_t write; /**< Internal. Callback for fwrite operation assigned by particular port. */
+ iot_fread_t read; /**< Internal. Callback for fread operation assigned by particular port. */
+ iot_ftell_t tell; /**< Internal. Callback for ftell operation assigned by particular port. */
+ iot_fseek_t seek; /**< Internal. Callback for fseek operation assigned by particular port. */
+ iot_frewind_t rewind; /**< Internal. Callback for frewind operation assigned by particular port. */
+ iot_fclose_t close; /**< Internal. Callback for fclose operation assigned by particular port. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_FILE_PORT_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.c
new file mode 100644
index 0000000..4712992
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.c
@@ -0,0 +1,220 @@
+/**
+ * Copyright (c) 2015 - 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 "sdk_config.h"
+#include "iot_file_static.h"
+#include "iot_common.h"
+#include <string.h>
+
+#if IOT_FILE_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME iot_file_static
+
+#define NRF_LOG_LEVEL IOT_FILE_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IOT_FILE_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IOT_FILE_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define FSTATIC_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define FSTATIC_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define FSTATIC_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#else // IOT_FILE_CONFIG_LOG_ENABLED
+
+#define FSTATIC_TRC(...) /**< Disables traces. */
+#define FSTATIC_DUMP(...) /**< Disables dumping of octet streams. */
+#define FSTATIC_ERR(...) /**< Disables error logs. */
+
+#endif // IOT_FILE_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.
+ * IOT_FILE_STATIC_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+
+#if (IOT_FILE_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_FILE_ERR_BASE); \
+ }
+
+#else // IOT_FILE_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // IOT_FILE_DISABLE_API_PARAM_CHECK
+/** @} */
+
+#define CHECK_CURSOR(PARAM) \
+ if ((PARAM) == IOT_FILE_INVALID_CURSOR) \
+ { \
+ return (NRF_ERROR_INVALID_STATE | IOT_FILE_ERR_BASE); \
+ }
+
+/**@brief Static buffer fwrite port function definition. */
+static uint32_t internal_fwrite(iot_file_t * p_file, const void * p_data, uint32_t size)
+{
+ NULL_PARAM_CHECK(p_data);
+ CHECK_CURSOR(p_file->cursor);
+
+ if ((size + p_file->cursor) > p_file->buffer_size)
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_FILE_ERR_BASE);
+ }
+
+ memcpy(((uint8_t *)p_file->p_buffer + p_file->cursor), p_data, size);
+ p_file->cursor += size;
+
+ if (p_file->cursor > p_file->file_size)
+ {
+ p_file->file_size = p_file->cursor;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Static buffer fread port function definition. */
+static uint32_t internal_fread(iot_file_t * p_file, void * p_data, uint32_t size)
+{
+ NULL_PARAM_CHECK(p_data);
+ CHECK_CURSOR(p_file->cursor);
+
+ if (size + p_file->cursor > p_file->file_size)
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_FILE_ERR_BASE);
+ }
+
+ memcpy(p_data, (uint8_t *)p_file->p_buffer + p_file->cursor, size);
+ p_file->cursor += size;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Static ftell port function definition. */
+static uint32_t internal_ftell(iot_file_t * p_file, uint32_t * p_cursor)
+{
+ NULL_PARAM_CHECK(p_cursor);
+ CHECK_CURSOR(p_file->cursor);
+
+ *p_cursor = p_file->cursor;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Static fseek port function definition. */
+static uint32_t internal_fseek(iot_file_t * p_file, uint32_t cursor)
+{
+ CHECK_CURSOR(p_file->cursor);
+
+ if (cursor > p_file->buffer_size)
+ {
+ FSTATIC_ERR("Cursor outside file!");
+ return (NRF_ERROR_INVALID_PARAM | IOT_FILE_ERR_BASE);
+ }
+
+ p_file->cursor = cursor;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Static frewind port function definition. */
+static uint32_t internal_frewind(iot_file_t * p_file)
+{
+ CHECK_CURSOR(p_file->cursor);
+
+ p_file->cursor = 0;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Static fopen port function definition. */
+static uint32_t internal_fopen(iot_file_t * p_file, uint32_t requested_size)
+{
+ p_file->cursor = 0;
+
+ if (requested_size != 0)
+ {
+ p_file->file_size = requested_size;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Static fclose port function definition. */
+static uint32_t internal_fclose(iot_file_t * p_file)
+{
+ p_file->cursor = IOT_FILE_INVALID_CURSOR;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief This function is used to assign correct callbacks and file type to passed IoT File instance. */
+void iot_file_static_assign(iot_file_t * p_file)
+{
+ if (p_file == NULL)
+ {
+ return;
+ }
+
+ p_file->type = IOT_FILE_TYPE_STATIC;
+ p_file->write = internal_fwrite;
+ p_file->read = internal_fread;
+ p_file->tell = internal_ftell;
+ p_file->seek = internal_fseek;
+ p_file->rewind = internal_frewind;
+ p_file->open = internal_fopen;
+ p_file->close = internal_fclose;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.h
new file mode 100644
index 0000000..de3ea02
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_file/static/iot_file_static.h
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**
+ * @file iot_file_static.h
+ * @brief FILE port for static buffers.
+ */
+
+#ifndef IOT_FILE_STATIC_H__
+#define IOT_FILE_STATIC_H__
+
+#include "iot_file_port.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup iot_file_static IoT file port for static buffers
+ * @ingroup iot_file
+ * @{
+ * @brief Macro function which simplifies file setup process and file type assigning function.
+ */
+
+/**
+ * @brief This macro function configures passed file as a static buffer file.
+ */
+#define IOT_FILE_STATIC_INIT(p_iot_file, p_file_name, p_mem, size) \
+ do { \
+ (p_iot_file)->p_filename = p_file_name; \
+ (p_iot_file)->cursor = IOT_FILE_INVALID_CURSOR; \
+ (p_iot_file)->p_buffer = p_mem; \
+ (p_iot_file)->buffer_size = size; \
+ (p_iot_file)->file_size = 0; \
+ (p_iot_file)->p_callback = NULL; \
+ iot_file_static_assign(p_iot_file); \
+ } while (0)
+
+/**
+ * @brief This function is used to assign correct callbacks and file type to passed IoT File instance.
+ */
+void iot_file_static_assign(iot_file_t * p_file);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_FILE_STATIC_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.c
new file mode 100644
index 0000000..96af2a6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.c
@@ -0,0 +1,183 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include "iot_timer.h"
+#include "sdk_common.h"
+#include "sdk_config.h"
+#include "iot_errors.h"
+
+/**
+ * @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.
+ * IOT_TIMER_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
+ *
+ * @{
+ */
+#if (IOT_TIMER_DISABLE_API_PARAM_CHECK == 0)
+
+/**
+ * @brief Verify NULL parameters are not passed to API by application.
+ */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_TIMER_ERR_BASE); \
+ }
+
+#define VERIFY_CLIENT_LIST_IS_VALID(PARAM) \
+ if ((PARAM) != NULL) \
+ { \
+ uint8_t i; \
+ for (i = 0; i < (PARAM)->client_list_length; i++) \
+ { \
+ if (((PARAM)->p_client_list[i].iot_timer_callback) == NULL) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_TIMER_ERR_BASE); \
+ } \
+ if (((PARAM)->p_client_list[i].cb_interval == 0) || \
+ ((PARAM)->p_client_list[i].cb_interval < IOT_TIMER_RESOLUTION_IN_MS) || \
+ (((PARAM)->p_client_list[i].cb_interval % IOT_TIMER_RESOLUTION_IN_MS) != 0)) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_TIMER_ERR_BASE); \
+ } \
+ } \
+ }
+
+#define VERIFY_WALL_CLOCK_VALUE_IS_VALID(PARAM) \
+ if ((PARAM) != NULL) \
+ { \
+ if ((*PARAM % IOT_TIMER_RESOLUTION_IN_MS) != 0) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_TIMER_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_TIMER_ERR_BASE); \
+ }
+
+#else // IOT_TIMER_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+#define VERIFY_CLIENT_LIST_IS_VALID(PARAM)
+#define VERIFY_WALL_CLOCK_VALUE_IS_VALID(PARAM)
+
+#endif //IOT_TIMER_DISABLE_API_PARAM_CHECK
+/** @} */
+
+static iot_timer_time_in_ms_t m_wall_clock = 0;
+static const iot_timer_clients_list_t * m_clients = NULL;
+
+
+uint32_t iot_timer_client_list_set(const iot_timer_clients_list_t * p_list_of_clients)
+{
+ VERIFY_CLIENT_LIST_IS_VALID(p_list_of_clients);
+
+ m_clients = p_list_of_clients;
+ return NRF_SUCCESS;
+}
+
+
+uint32_t iot_timer_update(void)
+{
+ m_wall_clock += IOT_TIMER_RESOLUTION_IN_MS;
+ if ((0xFFFFFFFFUL - m_wall_clock) < IOT_TIMER_RESOLUTION_IN_MS)
+ {
+ m_wall_clock = IOT_TIMER_RESOLUTION_IN_MS;
+ }
+ if (m_clients != NULL)
+ {
+ uint8_t index;
+ for (index = 0; index < m_clients->client_list_length; index++)
+ {
+ if ((m_wall_clock % m_clients->p_client_list[index].cb_interval) == 0)
+ {
+ m_clients->p_client_list[index].iot_timer_callback(m_wall_clock);
+ }
+ }
+ }
+ return NRF_SUCCESS;
+}
+
+
+uint32_t iot_timer_wall_clock_get(iot_timer_time_in_ms_t * p_elapsed_time)
+{
+ NULL_PARAM_CHECK(p_elapsed_time);
+
+ *p_elapsed_time = m_wall_clock;
+ return NRF_SUCCESS;
+}
+
+
+uint32_t iot_timer_wall_clock_delta_get(iot_timer_time_in_ms_t * p_past_time, \
+ iot_timer_time_in_ms_t * p_delta_time)
+{
+ NULL_PARAM_CHECK(p_past_time);
+ NULL_PARAM_CHECK(p_delta_time);
+ VERIFY_WALL_CLOCK_VALUE_IS_VALID(p_past_time);
+
+ if (*p_past_time == m_wall_clock)
+ {
+ *p_delta_time = 0;
+ }
+ else if (*p_past_time < m_wall_clock)
+ {
+ *p_delta_time = m_wall_clock - *p_past_time;
+ }
+ else
+ {
+ // An integer overflow of the wall clock occured since *p_past_time.
+
+ iot_timer_time_in_ms_t max_wall_clock = (0xFFFFFFFFUL / IOT_TIMER_RESOLUTION_IN_MS) \
+ * IOT_TIMER_RESOLUTION_IN_MS;
+ *p_delta_time = max_wall_clock - *p_past_time; // Before overflow.
+ *p_delta_time += m_wall_clock; // After overflow.
+ *p_delta_time -= IOT_TIMER_RESOLUTION_IN_MS; // Because of handling of wall clock integer overflow, see above.
+ }
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.h
new file mode 100644
index 0000000..d7503b3
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/iot_timer/iot_timer.h
@@ -0,0 +1,175 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup iot_timer IoT Timer
+ * @{
+ * @ingroup iot_sdk_common
+ * @brief Timekeeping for other modules.
+ *
+ * @details The IoT Timer stores the value of the wall clock, which represents the time elapsed
+ * since startup (or an integer overflow). The unit of timekeeping is milliseconds.
+ * The IoT Timer module is conceived to be platform independent, therefore, it does not
+ * have an internal tick source. An external source has to update the wall clock of the
+ * IoT Timer at regular intervals.
+ * Other modules can query the current value of the wall clock and/or can act as clients
+ * of the IoT Timer by subscribing to callbacks that are repeated at regular intervals.
+ * You can configure the module by changing the @c sdk_config.h configuration file.
+ */
+
+#ifndef IOT_TIMER_H__
+#define IOT_TIMER_H__
+
+#include <stdint.h>
+#include "nrf_error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SEC_TO_MILLISEC(PARAM) (PARAM * 1000)
+
+/**@brief The type of an instant in milliseconds. */
+typedef uint32_t iot_timer_time_in_ms_t;
+
+/**@brief IoT Timer client callback type.
+ *
+ * @param[in] wall_clock_value The value of the wall clock that triggered the callback.
+ *
+ * @retval None.
+ *
+ */
+typedef void (*iot_timer_tick_cb)(iot_timer_time_in_ms_t wall_clock_value);
+
+/**@brief IoT Timer client structure.
+ *
+ * @note @ref cb_interval cannot be zero.
+ * @note @ref cb_interval must be greater or equal to @ref IOT_TIMER_RESOLUTION_IN_MS.
+ * @note If greater, @ref cb_interval must be an integral multiple of @ref IOT_TIMER_RESOLUTION_IN_MS.
+ */
+typedef struct
+{
+ iot_timer_tick_cb iot_timer_callback; /**< Callback procedure of the client. */
+ iot_timer_time_in_ms_t cb_interval; /**< Interval between repeated callbacks to the client. */
+} iot_timer_client_t;
+
+/**@brief IoT Timer client list structure. */
+typedef struct
+{
+ uint8_t client_list_length; /**< Total number of clients. */
+ const iot_timer_client_t * p_client_list; /**< Pointer to the constant array of clients or NULL. */
+} iot_timer_clients_list_t;
+
+/**@brief Function for setting the list of clients that subscribe for repeated callbacks from
+ * the module.
+ *
+ * @note To minimize drift between client callbacks, the callback function of each client
+ * should be designed in a way that the duration of execution does not vary and is as short
+ * as possible.
+ *
+ * @param[in] p_list_of_clients Address of the client list. Can be NULL to cancel all subscriptions.
+ * To see what parameters are valid, please see the description
+ * of @ref iot_timer_client_t.
+ *
+ * @retval NRF_SUCCESS Address of the list of clients successfully updated.
+ * @retval NRF_ERROR_INVALID_PARAM If any member of the client list has NULL as a callback
+ * procedure or the interval for repeated callbacks is smaller
+ * or equal to @ref IOT_TIMER_RESOLUTION_IN_MS or it is not
+ * an integral multiple of @ref IOT_TIMER_RESOLUTION_IN_MS.
+ *
+ */
+uint32_t iot_timer_client_list_set(const iot_timer_clients_list_t * p_list_of_clients);
+
+/**@brief Function for updating the wall clock.
+ *
+ * @details The application designer must ensure that this function is called at regular intervals,
+ * which is set in the @c sdk_config.h configuration file.
+ * If the updated value of the wall clock is an integral multiple of the callback interval
+ * of any clients of the module, the callback procedure of the client is executed.
+ *
+ * @note The interrupt that triggers the update of the wall clock should have a high relative
+ * priority to minimize inaccuracy.
+ *
+ * @retval NRF_SUCCESS Wall clock successfully updated.
+ *
+ */
+uint32_t iot_timer_update(void);
+
+/**@brief Function for getting the current wall clock value.
+ *
+ * @note The accuracy of timekeeping is limited by the resolution, as set in the @c sdk_config.h
+ * configuration file.
+ *
+ * @param[out] p_elapsed_time Value of the wall clock. Time in milliseconds elapsed since startup
+ * (or an integer overflow).
+ *
+ * @retval NRF_SUCCESS Query successful.
+ * @retval NRF_ERROR_NULL If @b p_elapsed_time is a NULL pointer.
+ *
+ */
+uint32_t iot_timer_wall_clock_get(iot_timer_time_in_ms_t * p_elapsed_time);
+
+/**@brief Function for getting the difference between the current and an older wall clock value.
+ *
+ * @note The accuracy of calculation is limited by the wall clock resolution, as set in
+ * the @c sdk_config.h configuration file.
+ * @note The time difference can only be calculated correctly if only at most one integer overflow
+ * of the wall clock has occured since the past wall clock value was obtained.
+ *
+ * @param[in] p_past_time Past value of the wall clock. Has to be an integral multiple of
+ * @ref IOT_TIMER_RESOLUTION_IN_MS or zero.
+ * @param[out] p_delta_time Time elapsed since @b p_past_time in milliseconds.
+ *
+ * @retval NRF_SUCCESS Query successful.
+ * @retval NRF_ERROR_NULL If @b p_past_time or @b p_delta_time is a NULL pointer.
+ * @retval NRF_ERROR_INVALID_PARAM If @b p_past_time points to a value that is not an integral
+ * multiple of @ref IOT_TIMER_RESOLUTION_IN_MS.
+ *
+ */
+uint32_t iot_timer_wall_clock_delta_get(iot_timer_time_in_ms_t * p_past_time, \
+ iot_timer_time_in_ms_t * p_delta_time);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_TIMER_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.c
new file mode 100644
index 0000000..0581763
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.c
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2015 - 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 <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "ipv6_parse.h"
+#include "nrf_error.h"
+
+static uint16_t ascii_to_hex(char * p_str)
+{
+ uint16_t res = 0;
+ sscanf(p_str, "%hx", &res);
+ return res;
+}
+
+static void reverse_string(char * p_str)
+{
+ uint32_t str_len = strlen(p_str);
+ for (uint32_t i = 0, j = str_len - 1; i < j; i++, j--)
+ {
+ char tmp = p_str[i];
+ p_str[i] = p_str[j];
+ p_str[j] = tmp;
+ }
+}
+
+uint32_t ipv6_parse_addr(uint8_t * p_addr, const char * p_uri, uint8_t uri_len)
+{
+ bool is_compressed = false;
+ uint8_t block_1_len = uri_len;
+
+ const char * compressed_position = strstr(&p_uri[0], "::");
+ if (compressed_position != NULL)
+ {
+ is_compressed = true;
+ block_1_len = compressed_position - &p_uri[0];
+ }
+ // Parse block 1.
+ uint8_t block_1_end = block_1_len;
+ char sub_addr_buf[5] = {'\0',};
+
+ uint8_t char_pos = 0;
+ uint8_t sub_addr_count_block_1 = 0;
+
+ for (uint8_t i = 0; i < block_1_end; i++)
+ {
+ if (p_uri[i] != ':')
+ {
+ sub_addr_buf[char_pos++] = p_uri[i];
+ }
+ else
+ {
+ // we have read all number bytes and hit a delimiter. Save the sub address.
+ uint16_t value = ascii_to_hex(sub_addr_buf);
+ p_addr[sub_addr_count_block_1++] = ((value & 0xFF00) >> 8);
+ p_addr[sub_addr_count_block_1++] = ((value & 0x00FF));
+
+ char_pos = 0;
+ memset(sub_addr_buf, '\0', 5);
+
+ }
+
+ // if we are at the end of block 1, save the last sub address.
+ if ((i + 1) == block_1_end)
+ {
+ uint16_t value = ascii_to_hex(sub_addr_buf);
+ p_addr[sub_addr_count_block_1++] = ((value & 0xFF00) >> 8);
+ p_addr[sub_addr_count_block_1++] = ((value & 0x00FF));
+
+
+ char_pos = 0;
+ memset(sub_addr_buf, '\0', 5);
+ }
+ }
+
+ if (is_compressed == true)
+ {
+ // NOTE: sub_addr_buf must be cleared in previous loop.
+
+ // lets parse backwards for second block.
+ uint8_t block_2_start = block_1_end + 2; // skip the '::' delimiter.
+ uint8_t block_2_len = uri_len - (block_1_len + 2);
+ uint8_t block_2_end = block_2_start + block_2_len;
+
+ uint8_t sub_addr_count_block_2 = 0;
+ uint8_t sub_addr_index = 15;
+
+ for (uint8_t i = block_2_end - 1; i > block_2_start - 1; i--)
+ {
+ if (p_uri[i] != ':')
+ {
+ sub_addr_buf[char_pos++] = p_uri[i];
+ }
+ else
+ {
+ // we have read all number bytes and hit a delimiter. Save the sub address.
+ reverse_string(sub_addr_buf);
+
+ uint16_t value = ascii_to_hex(sub_addr_buf);
+ p_addr[sub_addr_index--] = ((value & 0x00FF));
+ p_addr[sub_addr_index--] = ((value & 0xFF00) >> 8);
+ sub_addr_count_block_2 += 2;
+ char_pos = 0;
+ memset(sub_addr_buf, '\0', 5);
+
+ }
+
+ // if we are at the end of block 1, save the last sub address.
+ if (i == block_2_start)
+ {
+ reverse_string(sub_addr_buf);
+
+ uint16_t value = ascii_to_hex(sub_addr_buf);
+ p_addr[sub_addr_index--] = ((value & 0x00FF));
+ p_addr[sub_addr_index--] = ((value & 0xFF00) >> 8);
+ sub_addr_count_block_2 += 2;
+ char_pos = 0;
+ memset(sub_addr_buf, '\0', 5);
+ }
+ }
+
+ for (uint8_t i = sub_addr_count_block_1; i < (16 - sub_addr_count_block_2); i++)
+ {
+ p_addr[i] = 0x00;
+ }
+ }
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.h
new file mode 100644
index 0000000..218bfdf
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_parse/ipv6_parse.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file ipv6_parse.h
+ *
+ * @defgroup iot_tools IoT Utility tools
+ * @ingroup iot_sdk_common
+ * @{
+ * @brief Common IoT utility tools like parsing IPv6 address from a URI.
+ *
+ * @details This module provides utility functions like parsing IPv6 address from a URI.
+ */
+#ifndef IPV6_PARSE_H__
+#define IPV6_PARSE_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief IoT IPv6 address parsing.
+ *
+ * @details Supports parsing all legal IPv6 address formats as defined by the RFC.
+ *
+ * @param[out] p_addr Pointer to array large enough to hold parsed address. MUST be 16 bytes big.
+ * @param[in] p_uri String with address that should be parsed.
+ * @param[in] uri_len Length of p_uri string.
+ *
+ */
+uint32_t ipv6_parse_addr(uint8_t * p_addr, const char * p_uri, uint8_t uri_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IPV6_PARSE_H__
+ /** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/dns6/dns6.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/dns6/dns6.c
new file mode 100644
index 0000000..6c90ce3
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/dns6/dns6.c
@@ -0,0 +1,903 @@
+/**
+ * Copyright (c) 2015 - 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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "sdk_errors.h"
+#include "sdk_os.h"
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "iot_pbuffer.h"
+#include "mem_manager.h"
+#include "ipv6_api.h"
+#include "udp_api.h"
+#include "dns6_api.h"
+
+#if DNS6_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME dns6
+
+#define NRF_LOG_LEVEL DNS6_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR DNS6_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR DNS6_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define DNS6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define DNS6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define DNS6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define DNS6_ENTRY() DNS6_TRC(">> %s", __func__)
+#define DNS6_EXIT() DNS6_TRC("<< %s", __func__)
+
+#else // DNS6_CONFIG_LOG_ENABLED
+
+#define DNS6_TRC(...) /**< Disables traces. */
+#define DNS6_DUMP(...) /**< Disables dumping of octet streams. */
+#define DNS6_ERR(...) /**< Disables error logs. */
+
+#define DNS6_ENTRY(...)
+#define DNS6_EXIT(...)
+
+#endif // DNS6_CONFIG_LOG_ENABLED
+
+/**
+ * @defgroup dns6_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 DNS6_MUTEX_LOCK() SDK_MUTEX_LOCK(m_dns6_mutex) /**< Lock module using mutex */
+#define DNS6_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_dns6_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.
+ * DNS6_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+
+#if (DNS6_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_DNS6_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_DNS6_ERR_BASE); \
+ }
+
+/**@brief Verify that empty parameters are not passed to API by application. */
+#define EMPTY_PARAM_CHECK(PARAM) \
+ if (*PARAM == 0) \
+ { \
+ return (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE); \
+ }
+
+#else // DNS6_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define NULL_PARAM_CHECK(PARAM)
+#define EMPTY_PARAM_CHECK(PARAM)
+
+#endif // DNS6_DISABLE_API_PARAM_CHECK
+/** @} */
+
+/**@brief RFC1035 - DNS Header Fields and Values. */
+#define DNS_HEADER_FLAG1_QR_QUERY 0x00 /**< Bit specifies that message is a query. */
+#define DNS_HEADER_FLAG1_QR_RESPONSE 0x80 /**< Bit specifies that message is a response. */
+#define DNS_HEADER_FLAG1_OPCODE_STANDARD 0x00 /**< A standard type of query. */
+#define DNS_HEADER_FLAG1_OPCODE_INVERSE 0x08 /**< An inverse type of query. */
+#define DNS_HEADER_FLAG1_OPCODE_STATUS 0x10 /**< A server status request. */
+#define DNS_HEADER_FLAG1_AA 0x04 /**< Bit specifies that the responding name server is an authority for the domain name in question section. */
+#define DNS_HEADER_FLAG1_TC 0x02 /**< Bit specifies that message is truncated. */
+#define DNS_HEADER_FLAG1_RD 0x01 /**< Bit specifies that recursion is desired. */
+
+#define DNS_HEADER_FLAG2_RA 0x80 /**< Bit specifies if recursive query support is available in the name server. */
+#define DNS_HEADER_FLAG2_RCODE_NONE 0x00 /**< No error condition. */
+#define DNS_HEADER_FLAG2_RCODE_FORMAT_ERROR 0x01 /**< Error indicates that dns server is unable o interpret the query. */
+#define DNS_HEADER_FLAG2_RCODE_SERVER_FAILURE 0x02 /**< Error indicates that dns server has internal problem. */
+#define DNS_HEADER_FLAG2_RCODE_NAME_ERROR 0x03 /**< Error indicates that domain name referenced in the query does not exist. */
+#define DNS_HEADER_FLAG2_RCODE_NOT_IMPLEMENTED 0x04 /**< Error indicates that dns server does not support previously sent query. */
+#define DNS_HEADER_FLAG2_RCODE_REFUSED 0x05 /**< Error indicates that dns server refuses to perform operation. */
+#define DNS_HEADER_FLAG2_RCODE_MASK 0x0F /**< Bit mask of RCODE field. */
+
+#define DNS_QTYPE_A 0x0001 /**< QTYPE indicates IPv4 address. */
+#define DNS_QTYPE_CNAME 0x0005 /**< QTYPE indicates CNAME record. */
+#define DNS_QTYPE_AAAA 0x001C /**< QTYPE indicates IPv6 address. */
+
+#define DNS_QCLASS_IN 0x0001 /**< QCLASS indicates Internet type. */
+
+/**@brief DNS6 client module's defines. */
+#define DNS_LABEL_SEPARATOR '.' /**< Separator of hostname string. */
+#define DNS_LABEL_OFFSET 0xc0 /**< Byte indicates that offset is used to determine hostname. */
+
+#define DNS_HEADER_SIZE 12 /**< Size of DNS Header. */
+#define DNS_QUESTION_FOOTER_SIZE 4 /**< Size of DNS Question footer. */
+#define DNS_RR_BODY_SIZE 10 /**< Size of DNS Resource Record Body. */
+
+#define MESSAGE_ID_UNUSED 0 /**< Value indicates that record is unused and no request was performed yet. */
+#define MESSAGE_ID_INITIAL 0x0001 /**< Initial value of message id counter. */
+
+
+/**@brief DNS Header Format. */
+typedef struct
+{
+ uint16_t msg_id; /**< Query/Response message identifier. */
+ uint8_t flags_1; /**< Flags ( QR | Opcode | AA | TC | RD ). */
+ uint8_t flags_2; /**< Flags ( RA | Z | RCODE ). */
+ uint16_t qdcount; /**< The number of entries in the question section. */
+ uint16_t ancount; /**< The number of resource records in the answer section. */
+ uint16_t nscount; /**< The number of name server resource records in the authority records section. */
+ uint16_t arcount; /**< The number of resource records in the additional records section. */
+} dns_header_t;
+
+/**@brief DNS Question Footer Format. */
+typedef struct
+{
+ uint16_t qtype; /**< Type of the query. */
+ uint16_t qclass; /**< Class of the query. */
+} dns_question_footer_t;
+
+/**@brief DNS Resource AAAA Record Body Format. */
+typedef struct
+{
+ uint16_t rtype; /**< Type of the response. */
+ uint16_t rclass; /**< Class of the response. */
+ uint32_t rttl; /**< Time to Life field of the response. */
+ uint16_t rdlength; /**< Length of data in octets. */
+} dns_rr_body_t;
+
+/**@brief Structure holds pending query. */
+typedef struct
+{
+ uint16_t message_id; /**< Message id for DNS Query. */
+ uint8_t retries; /**< Number of already performed retries. */
+ uint8_t * p_hostname; /**< Pointer to hostname string in memory menager.*/
+ iot_timer_time_in_ms_t next_retransmission; /**< Time when next retransmission should be invoked. */
+ dns6_evt_handler_t evt_handler; /**< User registered callback. */
+} pending_query_t;
+
+SDK_MUTEX_DEFINE(m_dns6_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 pending_query_t m_pending_queries[DNS6_MAX_PENDING_QUERIES]; /**< Queue contains pending queries. */
+static uint16_t m_message_id_counter; /**< Message ID counter, used to generate unique message IDs. */
+static udp6_socket_t m_socket; /**< Socket information provided by UDP. */
+
+
+/**@brief Function for freeing query entry in pending queue.
+ *
+ * @param[in] index Index of query.
+ *
+ * @retval None.
+ */
+static void query_init(uint32_t index)
+{
+ if (m_pending_queries[index].p_hostname)
+ {
+ UNUSED_VARIABLE(nrf_free(m_pending_queries[index].p_hostname));
+ }
+
+ m_pending_queries[index].message_id = MESSAGE_ID_UNUSED;
+ m_pending_queries[index].retries = 0;
+ m_pending_queries[index].p_hostname = NULL;
+ m_pending_queries[index].evt_handler = NULL;
+ m_pending_queries[index].next_retransmission = 0;
+}
+
+
+/**@brief Function for adding new query to pending queue.
+ *
+ * @param[in] p_hostname Pointer to hostname string.
+ * @param[in] evt_handler User defined event to handle given query.
+ *
+ * @retval Index of element in pending queries' table or DNS6_MAX_PENDING_QUERIES if no memory.
+ */
+static uint32_t query_add(uint8_t * p_hostname, dns6_evt_handler_t evt_handler)
+{
+ uint32_t index;
+
+ for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
+ {
+ if (m_pending_queries[index].message_id == MESSAGE_ID_UNUSED)
+ {
+ m_pending_queries[index].message_id = m_message_id_counter++;
+ m_pending_queries[index].retries = 0;
+ m_pending_queries[index].p_hostname = p_hostname;
+ m_pending_queries[index].evt_handler = evt_handler;
+ m_pending_queries[index].next_retransmission = 0;
+
+ break;
+ }
+ }
+
+ return index;
+}
+
+
+/**@brief Function for finding element in pending queue with specific message_id.
+ *
+ * @param[in] message_id Message identifier to find.
+ *
+ * @retval Index of element in pending queue or DNS6_MAX_PENDING_QUERIES if nothing found.
+ */
+static uint32_t query_find(uint32_t message_id)
+{
+ uint32_t index;
+
+ for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
+ {
+ if (m_pending_queries[index].message_id == message_id)
+ {
+ break;
+ }
+ }
+
+ return index;
+}
+
+
+/**@brief Function for checking if retransmission time of DNS query has been expired.
+ *
+ * @param[in] index Index of pending query.
+ *
+ * @retval True if timer has been expired, False otherwise.
+ */
+static bool query_timer_is_expired(uint32_t index)
+{
+ uint32_t err_code;
+ iot_timer_time_in_ms_t wall_clock_value;
+
+ // Get wall clock time.
+ err_code = iot_timer_wall_clock_get(&wall_clock_value);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (wall_clock_value >= m_pending_queries[index].next_retransmission)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**@brief Function for setting retransmissions time of DNS query has been expired.
+ *
+ * @param[in] index Index of pending query.
+ *
+ * @retval None.
+ */
+static void query_timer_set(uint32_t index)
+{
+ uint32_t err_code;
+ iot_timer_time_in_ms_t wall_clock_value;
+
+ // Get wall clock time.
+ err_code = iot_timer_wall_clock_get(&wall_clock_value);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_pending_queries[index].next_retransmission =
+ wall_clock_value + (DNS6_RETRANSMISSION_INTERVAL * 1000);
+ }
+}
+
+
+/**@brief Function for creating compressed hostname from string.
+ *
+ * @param[inout] p_dest Pointer to place where hostname will be compressed.
+ * @param[in] p_hostname Pointer to hostname string.
+ *
+ * @retval Number of used bytes to compress a hostname.
+ */
+static uint32_t compress_hostname(uint8_t * p_dest, const uint8_t * p_hostname)
+{
+ uint32_t index = 0;
+ uint32_t label_pos = 0;
+ uint8_t * p_original = p_dest;
+
+ // Elide first byte in destination buffer to put label.
+ p_dest++;
+
+ // Parse until string termination is found.
+ for (index = 0; p_hostname[index] != 0; index++)
+ {
+ // Look for string separator.
+ if (p_hostname[index] == DNS_LABEL_SEPARATOR)
+ {
+ // Put number of subsequent string to last label.
+ p_original[label_pos] = index - label_pos;
+
+ // Protection to stop compressing after getting incorrect sequence.
+ if (index == label_pos)
+ {
+ return index + 1;
+ }
+
+ label_pos = index + 1;
+ }
+ else
+ {
+ // Copy character of hostname to destination buffer.
+ *p_dest = p_hostname[index];
+ }
+
+ p_dest++;
+ }
+
+ // Set last label.
+ p_original[label_pos] = index - label_pos;
+
+ // Terminate compressed hostname with 0.
+ *p_dest = 0;
+
+ // Return length of compressed string.
+ return index + 2;
+}
+
+
+/**@brief Function for finding end of compressed hostname.
+ *
+ * @param[in] p_hostname Pointer to compressed hostname string.
+ *
+ * @retval Pointer to the end of compressed hostname.
+ */
+static uint8_t * skip_compressed_hostname(uint8_t * p_hostname)
+{
+ while (*p_hostname != 0)
+ {
+ if ((*p_hostname & DNS_LABEL_OFFSET) == DNS_LABEL_OFFSET)
+ {
+ return p_hostname + 2;
+ }
+ else
+ {
+ p_hostname += *p_hostname + 1;
+ }
+ }
+
+ return p_hostname + 1;
+}
+
+
+/**@brief Function for sending DNS query.
+ *
+ * @param[in] index Index of query.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t query_send(uint32_t index)
+{
+ uint32_t length;
+ uint32_t err_code;
+ 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 = DNS_HEADER_SIZE + DNS_QUESTION_FOOTER_SIZE +
+ strlen((const char *)m_pending_queries[index].p_hostname) + 2;
+
+ // Allocate packet buffer.
+ err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const dns_question_footer_t question_footer =
+ {
+ .qtype = HTONS(DNS_QTYPE_AAAA),
+ .qclass = HTONS(DNS_QCLASS_IN)
+ };
+
+ dns_header_t * p_dns_header = (dns_header_t *)p_buffer->p_payload;
+
+ // Fill DNS header fields.
+ p_dns_header->msg_id = HTONS(m_pending_queries[index].message_id);
+ p_dns_header->flags_1 = DNS_HEADER_FLAG1_QR_QUERY | DNS_HEADER_FLAG1_RD;
+ p_dns_header->flags_2 = DNS_HEADER_FLAG2_RCODE_NONE;
+
+ // Send only one question.
+ p_dns_header->qdcount = HTONS(1);
+ p_dns_header->ancount = HTONS(0);
+ p_dns_header->nscount = HTONS(0);
+ p_dns_header->arcount = HTONS(0);
+
+ // Start indexing from the end of the DNS header.
+ length = DNS_HEADER_SIZE;
+
+ // Compress and put hostname.
+ length += compress_hostname(&p_buffer->p_payload[length],
+ m_pending_queries[index].p_hostname);
+
+ // Add question footer.
+ memcpy(&p_buffer->p_payload[length], (uint8_t *)&question_footer, DNS_QUESTION_FOOTER_SIZE);
+
+ length += DNS_QUESTION_FOOTER_SIZE;
+
+ // Update packet buffer's data length.
+ p_buffer->length = length;
+
+ // Set retransmission timer.
+ query_timer_set(index);
+
+ // Send DNS query using UDP socket.
+ err_code = udp6_socket_send(&m_socket, p_buffer);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ DNS6_ERR("Unable to send query on UDP socket. Reason %08lx.", err_code);
+
+ // Free the allocated buffer as send procedure has failed.
+ UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true));
+ }
+ }
+ else
+ {
+ DNS6_ERR("No memory to allocate packet buffer.");
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for notifying application of the DNS6 query status.
+ *
+ * @param[in] index Index of query.
+ * @param[in] process_result Variable indicates result of DNS query.
+ * @param[in] p_addr Pointer to memory that holds IPv6 addresses.
+ * @param[in] addr_count Number of found addresses.
+ *
+ * @retval None.
+ */
+static void app_notify(uint32_t index,
+ uint32_t process_result,
+ ipv6_addr_t * p_addr,
+ uint16_t addr_count)
+{
+ if (m_pending_queries[index].evt_handler)
+ {
+ DNS6_MUTEX_UNLOCK();
+
+ // Call handler of user request.
+ m_pending_queries[index].evt_handler(process_result,
+ (const char *)m_pending_queries[index].p_hostname,
+ p_addr,
+ addr_count);
+
+ DNS6_MUTEX_LOCK();
+ }
+}
+
+
+/**@brief 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] p_rx_packet 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 server_response(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 rr_index;
+ uint32_t err_code = NRF_SUCCESS;
+ ipv6_addr_t * p_addresses = NULL;
+ uint16_t addr_length = 0;
+
+ DNS6_MUTEX_LOCK();
+
+ DNS6_ENTRY();
+
+ // Check UDP process result and data length.
+ if ((process_result != NRF_SUCCESS) || p_rx_packet->length < DNS_HEADER_SIZE)
+ {
+ DNS6_ERR("Received erroneous response.");
+ err_code = (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE);
+ }
+ else
+ {
+ dns_header_t * p_dns_header = (dns_header_t *)p_rx_packet->p_payload;
+ uint8_t * p_data = &p_rx_packet->p_payload[DNS_HEADER_SIZE];
+ uint16_t qdcount = NTOHS(p_dns_header->qdcount);
+ uint16_t ancount = NTOHS(p_dns_header->ancount);
+
+ // Try to find a proper query for this response, else discard.
+ index = query_find(NTOHS(p_dns_header->msg_id));
+
+ if (index != DNS6_MAX_PENDING_QUERIES)
+ {
+ DNS6_TRC("Received response for hostname %s with %d answers.",
+ m_pending_queries[index].p_hostname, ancount);
+
+ // Check truncation error.
+ if (p_dns_header->flags_1 & DNS_HEADER_FLAG1_TC)
+ {
+ err_code = DNS6_RESPONSE_TRUNCATED;
+ }
+ else if (!(p_dns_header->flags_1 & DNS_HEADER_FLAG1_QR_RESPONSE))
+ {
+ err_code = (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE);
+ }
+ // Check response code.
+ else if (p_dns_header->flags_2 & DNS_HEADER_FLAG2_RCODE_MASK)
+ {
+ switch (p_dns_header->flags_2 & DNS_HEADER_FLAG2_RCODE_MASK)
+ {
+ case DNS_HEADER_FLAG2_RCODE_FORMAT_ERROR:
+ err_code = DNS6_FORMAT_ERROR;
+ break;
+
+ case DNS_HEADER_FLAG2_RCODE_SERVER_FAILURE:
+ err_code = DNS6_SERVER_FAILURE;
+ break;
+
+ case DNS_HEADER_FLAG2_RCODE_NAME_ERROR:
+ err_code = DNS6_HOSTNAME_NOT_FOUND;
+ break;
+
+ case DNS_HEADER_FLAG2_RCODE_NOT_IMPLEMENTED:
+ err_code = DNS6_NOT_IMPLEMENTED;
+ break;
+
+ case DNS_HEADER_FLAG2_RCODE_REFUSED:
+ err_code = DNS6_REFUSED_ERROR;
+ break;
+
+ default:
+ err_code = (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE);
+ break;
+ }
+ }
+ else if (ancount == 0)
+ {
+ // No answer found.
+ err_code = DNS6_HOSTNAME_NOT_FOUND;
+ }
+ else
+ {
+ dns_rr_body_t rr;
+
+ // Skip questions section.
+ for (rr_index = 0; rr_index < qdcount; rr_index++)
+ {
+ p_data = skip_compressed_hostname(p_data) + DNS_QUESTION_FOOTER_SIZE;
+ }
+
+ // Addresses are moved to beginning of the packet to ensure alignment is correct.
+ p_addresses = (ipv6_addr_t *)p_rx_packet->p_payload;
+
+ // Parse responses section.
+ for (rr_index = 0; rr_index < ancount; rr_index++)
+ {
+ p_data = skip_compressed_hostname(p_data);
+
+ // Fill resource record structure to fit alignment.
+ memcpy((uint8_t *)&rr, p_data, DNS_RR_BODY_SIZE);
+
+ if (NTOHS(rr.rtype) == DNS_QTYPE_AAAA && NTOHS(rr.rclass) == DNS_QCLASS_IN)
+ {
+ if (NTOHS(rr.rdlength) == IPV6_ADDR_SIZE)
+ {
+ DNS6_TRC("Found AAAA record with IPv6 address:");
+ DNS6_DUMP(p_data + DNS_RR_BODY_SIZE, IPV6_ADDR_SIZE);
+
+ // Move all addresses next to each other.
+ memmove(p_addresses[addr_length].u8,
+ p_data + DNS_RR_BODY_SIZE,
+ IPV6_ADDR_SIZE);
+
+ addr_length++;
+ }
+ }
+
+ p_data += DNS_RR_BODY_SIZE + NTOHS(rr.rdlength);
+ }
+
+ if (addr_length == 0)
+ {
+ DNS6_ERR("No IPv6 addresses was found.");
+
+ err_code = DNS6_HOSTNAME_NOT_FOUND;
+ }
+ }
+
+ // Notify application.
+ app_notify(index, err_code, p_addresses, addr_length);
+
+ // Initialize query entry.
+ query_init(index);
+ }
+ else
+ {
+ DNS6_ERR("Response with unknown message id.");
+ err_code = (NRF_ERROR_NOT_FOUND | IOT_DNS6_ERR_BASE);
+ }
+ }
+
+ DNS6_EXIT();
+
+ DNS6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t dns6_init(const dns6_init_t * p_dns_init)
+{
+ NULL_PARAM_CHECK(p_dns_init);
+
+ uint32_t index;
+ uint32_t err_code;
+
+ DNS6_ENTRY();
+
+ SDK_MUTEX_INIT(m_dns6_mutex);
+
+ DNS6_MUTEX_LOCK();
+
+ for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
+ {
+ query_init(index);
+ }
+
+ // Request new socket creation.
+ err_code = udp6_socket_allocate(&m_socket);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Bind the socket to the local port.
+ err_code = udp6_socket_bind(&m_socket, IPV6_ADDR_ANY, p_dns_init->local_src_port);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Connect to DNS server.
+ err_code = udp6_socket_connect(&m_socket,
+ &p_dns_init->dns_server.addr,
+ p_dns_init->dns_server.port);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Register data receive callback.
+ err_code = udp6_socket_recv(&m_socket, server_response);
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ DNS6_TRC("Module initialization is complete.");
+
+ // Set initialization state flag if all procedures succeeded.
+ m_initialization_state = true;
+ m_message_id_counter = 0x0001;
+ }
+ else
+ {
+ DNS6_ERR("UDP socket initialization failed. Reason %08lx.", err_code);
+
+ // Not all procedures succeeded with allocated socket, hence free it.
+ UNUSED_VARIABLE(udp6_socket_free(&m_socket));
+ }
+ }
+
+ DNS6_EXIT();
+
+ DNS6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t dns6_uninit(void)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ uint32_t index;
+
+ DNS6_ENTRY();
+
+ DNS6_MUTEX_LOCK();
+
+ for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
+ {
+ query_init(index);
+ }
+
+ // Free UDP socket.
+ UNUSED_VARIABLE(udp6_socket_free(&m_socket));
+
+ // Clear initialization state flag.
+ m_initialization_state = false;
+
+ DNS6_EXIT();
+
+ DNS6_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t dns6_query(const char * p_hostname, dns6_evt_handler_t evt_handler)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(evt_handler);
+ NULL_PARAM_CHECK(p_hostname);
+ EMPTY_PARAM_CHECK(p_hostname);
+
+ uint32_t index;
+ uint32_t err_code;
+ uint32_t hostname_length;
+ uint8_t * p_hostname_buff = NULL;
+
+ DNS6_ENTRY();
+
+ DNS6_MUTEX_LOCK();
+
+ // Calculate hostname length.
+ hostname_length = strlen(p_hostname) + 1;
+
+ // Allocate memory to make copy of hostname string.
+ err_code = nrf_mem_reserve(&p_hostname_buff, &hostname_length);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Copy hostname to cache buffer.
+ strcpy((char *)p_hostname_buff, p_hostname);
+
+ // Add query to pending queue.
+ index = query_add(p_hostname_buff, evt_handler);
+
+ if (index != DNS6_MAX_PENDING_QUERIES)
+ {
+ // Create and send DNS Query.
+ err_code = query_send(index);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Remove query from pending queue immediately.
+ query_init(index);
+ }
+ }
+ else
+ {
+ DNS6_ERR("No place in pending queue.");
+
+ // No place in pending queue.
+ err_code = (NRF_ERROR_NO_MEM | IOT_DNS6_ERR_BASE);
+ }
+
+ // Not all procedures succeeded with sending query, hence free buffer for hostname.
+ if (err_code != NRF_SUCCESS)
+ {
+ UNUSED_VARIABLE(nrf_free(p_hostname_buff));
+ }
+ }
+ else
+ {
+ DNS6_ERR("No memory to allocate buffer for hostname.");
+ }
+
+ DNS6_EXIT();
+
+ DNS6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+void dns6_timeout_process(iot_timer_time_in_ms_t wall_clock_value)
+{
+ uint32_t index;
+ uint32_t err_code;
+
+ UNUSED_PARAMETER(wall_clock_value);
+
+ DNS6_ENTRY();
+
+ DNS6_MUTEX_LOCK();
+
+ for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
+ {
+ if (m_pending_queries[index].message_id != MESSAGE_ID_UNUSED)
+ {
+ if (query_timer_is_expired(index))
+ {
+ err_code = NRF_SUCCESS;
+
+ if (m_pending_queries[index].retries < DNS6_MAX_RETRANSMISSION_COUNT)
+ {
+ DNS6_TRC("Query retransmission [%d] for hostname %s.",
+ m_pending_queries[index].retries, m_pending_queries[index].p_hostname);
+
+ // Increase retransmission number.
+ m_pending_queries[index].retries++;
+
+ // Send query again.
+ err_code = query_send(index);
+ }
+ else
+ {
+ DNS6_ERR("DNS server did not response on query for hostname %s.",
+ m_pending_queries[index].p_hostname);
+
+ // No response from server.
+ err_code = DNS6_SERVER_UNREACHABLE;
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Inform application that timeout occurs.
+ app_notify(index, err_code, NULL, 0);
+
+ // Remove query from pending queue.
+ query_init(index);
+ }
+ }
+ break;
+ }
+ }
+
+ DNS6_EXIT();
+
+ DNS6_MUTEX_UNLOCK();
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.c
new file mode 100644
index 0000000..8c136b8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.c
@@ -0,0 +1,1355 @@
+/**
+ * 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 <stdbool.h>
+#include <string.h>
+
+#include "icmp6_api.h"
+#include "ipv6_api.h"
+#include "icmp6.h"
+#include "iot_context_manager.h"
+#include "ipv6_utils.h"
+#include "iot_common.h"
+
+#if ICMP6_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME icmp6
+
+#define NRF_LOG_LEVEL ICMP6_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR ICMP6_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR ICMP6_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define ICMP6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define ICMP6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define ICMP6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define ICMP6_ENTRY() ICMP6_TRC(">> %s", __func__)
+#define ICMP6_EXIT() ICMP6_TRC("<< %s", __func__)
+
+#else // ICMP6_CONFIG_LOG_ENABLED
+
+#define ICMP6_TRC(...) /**< Disables traces. */
+#define ICMP6_DUMP(...) /**< Disables dumping of octet streams. */
+#define ICMP6_ERR(...) /**< Disables error logs. */
+
+#define ICMP6_ENTRY(...)
+#define ICMP6_EXIT(...)
+
+#endif // ICMP6_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.
+ * ICMP6_DISABLE_API_PARAM_CHECK should be set to 1 to disable these checks.
+ *
+ * @{
+ */
+#if (ICMP6_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_ICMP6_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_ICMP6_ERR_BASE); \
+ }
+
+/**
+ * @brief Verify packet buffer is of ICMP6 Type.
+ */
+#define PACKET_TYPE_CHECK(PACKET) \
+ if ((PACKET)->type != ICMP6_PACKET_TYPE) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_ICMP6_ERR_BASE); \
+ }
+
+
+#else // ICMP6_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define VERIFY_MODULE_IS_INITIALIZED_VOID()
+#define NULL_PARAM_CHECK(PARAM)
+#define PACKET_TYPE_CHECK(PACKET)
+
+#endif // ICMP6_DISABLE_API_PARAM_CHECK
+/** @} */
+
+/**
+ * @defgroup icmp6_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 ICMP6_MUTEX_LOCK() SDK_MUTEX_LOCK(m_icmp6_mutex) /**< Lock module using mutex */
+#define ICMP6_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_icmp6_mutex) /**< Unlock module using mutex */
+/** @} */
+
+#define ND_NS_HEADER_SIZE 20 /**< Size of Neighbour Solicitation message. */
+#define ND_NA_HEADER_SIZE 20 /**< Size of Neighbour Advertisement message. */
+#define ND_RS_HEADER_SIZE 4 /**< Size of Router Solicitation message. */
+#define ND_RA_HEADER_SIZE 12 /**< Size of Router Advertisement message. */
+#define ND_PAYLOAD_ADJUST_OFFSET 4 /**< Adjusting ND related payload offset as the general ICMP structure is not upheld. */
+
+#define ND_NA_R_FLAG 0x80 /**< Router flag. When set, the R-bit indicates that the sender is a router. */
+#define ND_NA_S_FLAG 0x40 /**< Solicited flag. When set, the S-bit indicates that the advertisement was sent in response
+ to a Neighbor Solicitation .*/
+#define ND_NA_O_FLAG 0x20 /**< Override flag. When set, the O-bit indicates that the advertisement should override
+ an existing cache entry and update the cached link-layer address .*/
+
+#define ND_OPT_TYPE_SLLAO 1 /**< Source Link Layer Address Option. */
+#define ND_OPT_TYPE_TLLAO 2 /**< Target Link Layer Address Option. */
+#define ND_OPT_TYPE_PIO 3 /**< Prefix Information Option. */
+#define ND_OPT_TYPE_RHO 4 /**< Redirected Header Option. */
+#define ND_OPT_TYPE_MTU 5 /**< Maximum Transmit Unit Option. */
+#define ND_OPT_TYPE_ARO 33 /**< Address Registration Option. */
+#define ND_OPT_TYPE_6CO 34 /**< 6LoWPAN Context Option. */
+#define ND_OPT_TYPE_6ABRO 35 /**< Authoritative Border Router Option. */
+
+#define ND_OPT_SLLAO_SIZE (8 * (((IPV6_LL_ADDR_SIZE) / 8) + 1)) /**< Size of SLLAO option. */
+#define ND_OPT_TLLAO_SIZE (8 * (((IPV6_LL_ADDR_SIZE) / 8) + 1)) /**< Size of TLLAO option. */
+#define ND_OPT_PIO_SIZE 32 /**< Size of PIO option. */
+#define ND_OPT_MTU_SIZE 8 /**< Size of MTU option. */
+#define ND_OPT_ARO_SIZE 16 /**< Size of ARO option. */
+#define ND_OPT_6CO_SIZE 24 /**< Size of 6CO option. */
+#define ND_OPT_6ABRO_SIZE 24 /**< Size of 6ABRO option. */
+
+#define ND_OPT_SLLAO_LENGTH ((ND_OPT_SLLAO_SIZE) / 8) /**< Value of length field in SLLAO option. */
+#define ND_OPT_TLLAO_LENGTH ((ND_OPT_TLLAO_SIZE) / 8) /**< Value of length field in SLLAO option. */
+#define ND_OPT_ARO_LENGTH 2 /**< Value of length field in ARO option. */
+
+#define ND_OPT_6CO_CID_MASK 0x0F
+#define ND_OPT_6CO_CID_POS 0
+#define ND_OPT_6CO_C_MASK 0x10
+#define ND_OPT_6CO_C_POS 4
+
+#define ND_OPT_PIO_L_MASK 0x80
+#define ND_OPT_PIO_L_POS 7
+#define ND_OPT_PIO_A_MASK 0x40
+#define ND_OPT_PIO_A_POS 6
+
+#define ND_HOP_LIMIT 255 /**< Value of Hop Limit used in Neighbour Discovery procedure. */
+
+#define ICMP6_OFFSET IPV6_IP_HEADER_SIZE + ICMP6_HEADER_SIZE /**< Offset of ICMPv6 packet type. */
+
+#define ERROR_ADDITIONAL_HEADER_SIZE 4 /**< Additional 4 bytes of information every ICMP error message contains. */
+#define ERROR_MESSAGE_HEADER_SIZE (ICMP6_HEADER_SIZE + ERROR_ADDITIONAL_HEADER_SIZE) /**< Error message header size including type, code, checksum and 32-bit parameter. */
+#define ICMP6_ERROR_OFFSET IPV6_IP_HEADER_SIZE + ERROR_MESSAGE_HEADER_SIZE /**< Offset for ICMPv6 error message. */
+
+/**@brief Neighbor Solicitation header. */
+typedef struct
+{
+ uint32_t reserved; /**< Reserved field. */
+ ipv6_addr_t target_addr; /**< Target Address field. */
+} icmp6_ns_header_t;
+
+/**@brief Neighbor Advertisement header. */
+typedef struct
+{
+ uint8_t flags; /**< Flags (R,S and O). */
+ uint8_t reserved; /**< Reserved field. */
+ ipv6_addr_t target_addr; /**< Target Address field. */
+} icmp6_na_header_t;
+
+/**@brief Router Solicitation message's header. */
+typedef struct
+{
+ uint32_t reserved; /**< Reserved field. */
+} icmp6_rs_header_t;
+
+/**@brief Option header of ICMPv6 packet. */
+typedef struct
+{
+ uint8_t type; /**< Option type. */
+ uint8_t length; /**< Length, in unit of 8 octets. */
+} nd_option_t;
+
+/**@brief Source Link Layer Address Option header format. */
+typedef struct
+{
+ uint8_t type; /**< Option type. */
+ uint8_t length; /**< Length, units of 8 octets. */
+ eui64_t addr; /**< Link-layer address. */
+ uint8_t padding[6]; /**< Padding. */
+} nd_option_sllao_t;
+
+/**@brief Target Link Layer Address Option header format. */
+typedef struct
+{
+ uint8_t type; /**< Option type. */
+ uint8_t length; /**< Length, units of 8 octets. */
+ eui64_t addr; /**< Link-layer address. */
+ uint8_t padding[6]; /**< Padding. */
+} nd_option_tllao_t;
+
+/**@brief Prefix Information Option header format. */
+typedef struct
+{
+ uint8_t type; /**< Option type. */
+ uint8_t length; /**< Length, units of 8 octets. */
+ uint8_t prefix_length; /**< Prefix length. */
+ uint8_t flags; /**< Flags (L/A) and reserved. */
+ uint32_t valid_lifetime; /**< Valid Lifetime. */
+ uint32_t preferred_lifetime; /**< Preferred Lifetime. */
+ uint32_t reserved; /**< Reserved field. */
+ ipv6_addr_t prefix; /**< Prefix address. */
+} nd_option_pio_t;
+
+/**@brief Address Registration Option header format. */
+typedef struct
+{
+ uint8_t type; /**< Option type. */
+ uint8_t length; /**< Length, units of 8 octets. */
+ uint8_t status; /**< Status of ARO. */
+ uint8_t reserved; /**< Reserved1, split to avoid alignment. */
+ uint16_t reserved2; /**< Reserved2, split to avoid alignment. */
+ uint16_t registration_lifetime; /**< Registration Lifetime. */
+ eui64_t eui64; /**< EUI-64 source address. */
+} nd_option_aro_t;
+
+/**@brief 6LoWPAN Context Option header format. */
+typedef struct
+{
+ uint8_t type; /**< Option type. */
+ uint8_t length; /**< Length, units of 8 octets. */
+ uint8_t context_length; /**< Context Length. */
+ uint8_t CID_C; /**< 4-bit Context and 1-bit context compression flag. */
+ uint16_t reserved; /**< Reserved. */
+ uint16_t valid_lifetime; /**< Valid Lifetime. */
+ ipv6_addr_t context; /**< Context IPv6 Prefix. */
+} nd_option_6co_t;
+
+static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */
+static uint16_t m_sequence_number = 0; /**< Sequence number from ICMPv6 packet. */
+static icmp6_receive_callback_t m_event_handler = NULL; /**< Application event handler. */
+SDK_MUTEX_DEFINE(m_icmp6_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+
+/**@brief Function for initializing default values of IP Header for ICMP.
+ *
+ * @param[in] p_ip_header Pointer to IPv6 header.
+ * @param[in] hoplimit Hop Limit in IPv6 header.
+ *
+ * @return None.
+ */
+static __INLINE void icmp_ip_header(ipv6_header_t * p_ip_header, uint8_t hoplimit)
+{
+ ipv6_header_init(p_ip_header);
+ p_ip_header->next_header = IPV6_NEXT_HEADER_ICMP6;
+ p_ip_header->hoplimit = hoplimit;
+}
+
+/**@brief Function for adding SLLAO option to the packet.
+ *
+ * @param[in] p_interface Pointer to IoT interface.
+ * @param[in] p_data Pointer to the memory where SLLAO option should be added.
+ *
+ * @return None.
+ */
+static __INLINE void add_sllao_opt(const iot_interface_t * p_interface, nd_option_sllao_t * p_sllao)
+{
+ p_sllao->type = ND_OPT_TYPE_SLLAO;
+ p_sllao->length = ND_OPT_SLLAO_LENGTH;
+
+#if (IPV6_LL_ADDR_SIZE == 6)
+ memcpy(p_sllao->addr.identifier, p_interface->local_addr.identifier, 3);
+ memcpy(p_sllao->addr.identifier + 3, p_interface->local_addr.identifier + 5, 3);
+#else
+ // Copy EUI-64 and add padding.
+ memcpy(p_sllao->addr.identifier, p_interface->local_addr.identifier, IPV6_LL_ADDR_SIZE);
+ memset(p_sllao->padding, 0, 6);
+#endif
+}
+
+/**@brief Function for adding TLLAO option to the packet.
+ *
+ * @param[in] p_interface Pointer to IoT interface.
+ * @param[in] p_data Pointer to the memory where TLLAO option should be added.
+ *
+ * @return None.
+ */
+static __INLINE void add_tllao_opt(const iot_interface_t * p_interface, nd_option_tllao_t * p_tllao)
+{
+ p_tllao->type = ND_OPT_TYPE_TLLAO;
+ p_tllao->length = ND_OPT_TLLAO_LENGTH;
+
+#if (IPV6_LL_ADDR_SIZE == 6)
+ memcpy(p_tllao->addr.identifier, p_interface->local_addr.identifier, 3);
+ memcpy(p_tllao->addr.identifier + 3, p_interface->local_addr.identifier + 5, 3);
+#else
+ // Copy EUI-64 and add padding.
+ memcpy(p_tllao->addr.identifier, p_interface->local_addr.identifier, IPV6_LL_ADDR_SIZE);
+ memset(p_tllao->padding, 0, 6);
+#endif
+}
+
+/**@brief Function for adding ARO option to packet.
+ *
+ * @param[in] p_interface Pointer to IoT interface.
+ * @param[in] p_data Pointer to the memory where ARO option should be added.
+ * @param[in] aro_lifetime Lifetime of registration.
+ *
+ * @return None.
+ */
+static __INLINE void add_aro_opt(const iot_interface_t * p_interface,
+ nd_option_aro_t * p_aro,
+ uint16_t aro_lifetime)
+{
+ p_aro->type = ND_OPT_TYPE_ARO;
+ p_aro->length = ND_OPT_ARO_LENGTH;
+ p_aro->status = 0x00;
+ p_aro->reserved = 0x00;
+ p_aro->reserved2 = 0x00;
+ p_aro->registration_lifetime = HTONS(aro_lifetime);
+
+ // Copy EUI-64 and add padding.
+ memcpy(p_aro->eui64.identifier, p_interface->local_addr.identifier, EUI_64_ADDR_SIZE);
+}
+
+#if (ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION == 1 || ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION == 1)
+
+/**@brief Function for notifying application of the ICMPv6 received packet.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_pbuffer Pointer to packet buffer of ICMP6_PACKET_TYPE.
+ * @param[in] process_result Result of internal processing packet.
+ *
+ * @return NRF_SUCCESS after successful processing, error otherwise.
+ */
+static uint32_t app_notify_icmp_data(iot_interface_t * p_interface,
+ iot_pbuffer_t * p_pbuffer,
+ uint32_t process_result)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (m_event_handler != NULL)
+ {
+
+ ipv6_header_t * p_ip_header = (ipv6_header_t *)
+ (p_pbuffer->p_payload - ICMP6_HEADER_SIZE - IPV6_IP_HEADER_SIZE);
+ icmp6_header_t * p_icmp_header = (icmp6_header_t *)
+ (p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
+
+ ICMP6_MUTEX_UNLOCK();
+
+ // Change byte order of ICMP header given to application.
+ p_icmp_header->checksum = NTOHS(p_icmp_header->checksum);
+
+ err_code = m_event_handler(p_interface,
+ p_ip_header,
+ p_icmp_header,
+ process_result,
+ p_pbuffer);
+
+ ICMP6_MUTEX_LOCK();
+ }
+
+ return err_code;
+}
+
+#endif
+
+#if (ICMP6_ENABLE_HANDLE_ECHO_REQUEST_TO_APPLICATION == 0)
+
+/**@brief Function for responding on ECHO REQUEST message.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_ip_header Pointer to IPv6 Header.
+ * @param[in] p_icmp_header Pointer to ICMPv6 header.
+ * @param[in] p_packet Pointer to packet buffer.
+ *
+ * @return NRF_SUCCESS after successful processing, error otherwise.
+ */
+static void echo_reply_send(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ icmp6_header_t * p_icmp_header,
+ iot_pbuffer_t * p_packet)
+{
+ uint32_t err_code;
+ uint16_t checksum;
+ iot_pbuffer_t * p_pbuffer;
+ iot_pbuffer_alloc_param_t pbuff_param;
+
+ // Headers of new packet.
+ ipv6_header_t * p_reply_ip_header;
+ icmp6_header_t * p_reply_icmp_header;
+
+ ICMP6_TRC("Sending reply on Echo Request.");
+
+ // Requesting buffer for reply
+ pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
+ pbuff_param.type = ICMP6_PACKET_TYPE;
+ pbuff_param.length = p_packet->length;
+
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_reply_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
+ IPV6_IP_HEADER_SIZE);
+ p_reply_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
+
+ // Change ICMP header.
+ p_reply_icmp_header->type = ICMP6_TYPE_ECHO_REPLY;
+ p_reply_icmp_header->code = 0;
+ p_reply_icmp_header->checksum = 0;
+
+ // IPv6 Header initialization.
+ icmp_ip_header(p_reply_ip_header, IPV6_DEFAULT_HOP_LIMIT);
+
+ p_reply_ip_header->destaddr = p_ip_header->srcaddr;
+ p_reply_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
+
+ if (IPV6_ADDRESS_IS_MULTICAST(&p_ip_header->destaddr))
+ {
+ IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&p_reply_ip_header->srcaddr,
+ p_interface->local_addr.identifier);
+ }
+ else
+ {
+ p_reply_ip_header->srcaddr = p_ip_header->destaddr;
+ }
+
+ // Set echo reply parameters.
+ p_reply_icmp_header->sp.echo.id = p_icmp_header->sp.echo.id;
+ p_reply_icmp_header->sp.echo.sequence = p_icmp_header->sp.echo.sequence;
+
+ // Copy user data.
+ memcpy(p_pbuffer->p_payload,
+ p_packet->p_payload,
+ p_packet->length);
+
+ // Calculate checksum.
+ checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
+
+ ipv6_checksum_calculate(p_reply_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
+ ipv6_checksum_calculate(p_reply_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
+ ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
+ p_pbuffer->length + ICMP6_HEADER_SIZE,
+ &checksum,
+ false);
+
+ p_reply_icmp_header->checksum = HTONS((~checksum));
+
+ p_pbuffer->p_payload -= ICMP6_OFFSET;
+ p_pbuffer->length += ICMP6_OFFSET;
+
+ // Send IPv6 packet.
+ err_code = ipv6_send(p_interface, p_pbuffer);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ ICMP6_ERR("Cannot send packet buffer!");
+ }
+ }
+ else
+ {
+ ICMP6_ERR("Failed to allocate packet buffer!");
+ }
+}
+#endif
+
+
+/**@brief Function for responding on Neighbor Advertisement message.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_ip_header Pointer to IPv6 Header.
+ * @param[in] p_icmp_header Pointer to ICMPv6 header.
+ * @param[in] p_target_addr Pointer to the IPv6 address.
+ *
+ * @return NRF_SUCCESS after successful processing, error otherwise.
+ */
+static uint32_t na_send(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ icmp6_header_t * p_icmp_header,
+ ipv6_addr_t * p_target_addr)
+{
+ uint32_t err_code;
+ uint16_t checksum;
+ iot_pbuffer_t * p_pbuffer;
+ iot_pbuffer_alloc_param_t pbuff_param;
+
+ // Headers of new packet.
+ ipv6_header_t * p_reply_ip_header;
+ icmp6_header_t * p_reply_icmp_header;
+ icmp6_na_header_t * p_reply_na_header;
+ nd_option_tllao_t * p_reply_opt_tllao_header;
+
+ ICMP6_TRC("Sending reply on Neighbor Solocitation.");
+
+ // Requesting buffer for reply
+ pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
+ pbuff_param.type = ICMP6_PACKET_TYPE;
+ pbuff_param.length = ND_NA_HEADER_SIZE + ND_OPT_TLLAO_SIZE - ND_PAYLOAD_ADJUST_OFFSET;
+
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_reply_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
+ IPV6_IP_HEADER_SIZE);
+ p_reply_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
+
+ p_pbuffer->p_payload -= ND_PAYLOAD_ADJUST_OFFSET;
+
+ p_reply_na_header = (icmp6_na_header_t *)(p_pbuffer->p_payload);
+ p_reply_opt_tllao_header = (nd_option_tllao_t *)(p_pbuffer->p_payload + ND_NA_HEADER_SIZE);
+
+ p_pbuffer->p_payload += ND_PAYLOAD_ADJUST_OFFSET;
+
+ // Change ICMP header.
+ p_reply_icmp_header->type = ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT;
+ p_reply_icmp_header->code = 0;
+ p_reply_icmp_header->checksum = 0;
+
+ // IPv6 Header initialization.
+ icmp_ip_header(p_reply_ip_header, ND_HOP_LIMIT);
+
+ p_reply_ip_header->srcaddr = *p_target_addr;
+ p_reply_ip_header->destaddr = p_ip_header->srcaddr;
+ p_reply_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
+
+ p_reply_na_header->flags = ND_NA_S_FLAG | ND_NA_O_FLAG ;
+ p_reply_na_header->reserved = 0;
+ p_reply_na_header->target_addr = *p_target_addr;
+
+ // Add TLLAO option.
+ add_tllao_opt(p_interface, p_reply_opt_tllao_header);
+
+ // Calculate checksum.
+ checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
+
+ ipv6_checksum_calculate(p_reply_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
+ ipv6_checksum_calculate(p_reply_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
+ ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
+ p_pbuffer->length + ICMP6_HEADER_SIZE,
+ &checksum,
+ false);
+
+ p_reply_icmp_header->checksum = HTONS((~checksum));
+
+ p_pbuffer->p_payload -= ICMP6_OFFSET;
+ p_pbuffer->length += ICMP6_OFFSET;
+
+ // Send IPv6 packet.
+ err_code = ipv6_send(p_interface, p_pbuffer);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ ICMP6_ERR("Cannot send packet buffer!");
+ }
+ }
+ else
+ {
+ ICMP6_ERR("Failed to allocate packet buffer!\r\n");
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for parsing Neighbor Solicitation message.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_ip_header Pointer to IPv6 Header.
+ * @param[in] p_icmp_header Pointer to ICMPv6 header.
+ * @param[in] p_packet Pointer to packet buffer.
+ *
+ * @return NRF_SUCCESS after successful processing, error otherwise.
+ */
+static uint32_t ns_input(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ icmp6_header_t * p_icmp_header,
+ iot_pbuffer_t * p_packet)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ // Read target address.
+ icmp6_ns_header_t * p_ns_header = (icmp6_ns_header_t *)p_packet->p_payload;
+
+ if (ipv6_address_check(p_interface, &p_ns_header->target_addr) == NRF_SUCCESS)
+ {
+ err_code = na_send(p_interface, p_ip_header, p_icmp_header, &p_ns_header->target_addr);
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for parsing Router Advertisement message.
+ * Because stack gives all control to application, internal RA parsing take care
+ * only on Context Identifier.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_ip_header Pointer to IPv6 Header.
+ * @param[in] p_icmp_header Pointer to ICMPv6 header.
+ * @param[in] p_packet Pointer to packet buffer.
+ *
+ * @return NRF_SUCCESS after successful processing, error otherwise.
+ */
+static uint32_t ra_input(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ icmp6_header_t * p_icmp_header,
+ iot_pbuffer_t * p_packet)
+{
+ uint32_t err_code;
+ iot_context_t context;
+ iot_context_t * p_context;
+ uint16_t curr_opt_offset = ND_RA_HEADER_SIZE;
+ nd_option_t * p_opt = NULL;
+ nd_option_6co_t * p_6co = NULL;
+ nd_option_pio_t * p_pio = NULL;
+
+ if (!IPV6_ADDRESS_IS_LINK_LOCAL(&p_ip_header->srcaddr))
+ {
+ return ICMP6_INVALID_PACKET_DATA;
+ }
+
+ // Read all option we get.
+ while (curr_opt_offset < p_packet->length)
+ {
+ p_opt = (nd_option_t *)(p_packet->p_payload + curr_opt_offset);
+
+ if (p_opt->length == 0)
+ {
+ ICMP6_ERR("Invalid zero length option!");
+ return ICMP6_INVALID_PACKET_DATA;
+ }
+
+ ICMP6_TRC("Option type = 0x%02x!", p_opt->type);
+
+ // Searching for handling options.
+ switch (p_opt->type)
+ {
+ case ND_OPT_TYPE_PIO:
+ {
+ p_pio = (nd_option_pio_t *)p_opt;
+
+ if (p_pio->prefix_length != 0 &&
+ (p_pio->flags & ND_OPT_PIO_A_MASK) &&
+ !(p_pio->flags & ND_OPT_PIO_L_MASK))
+ {
+ // Ignore Link-Local address
+ if (IPV6_ADDRESS_IS_LINK_LOCAL(&p_pio->prefix))
+ {
+ ICMP6_ERR("Ignore Link-Local prefix!");
+ break;
+ }
+
+ // For now address is automatically set as a preferred.
+ ipv6_addr_conf_t temp_address;
+
+ // Set IPv6 EUI-64
+ IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&temp_address.addr,
+ p_interface->local_addr.identifier);
+
+ // Add prefix
+ IPV6_ADDRESS_PREFIX_SET(temp_address.addr.u8,
+ p_pio->prefix.u8,
+ p_pio->prefix_length);
+
+ if (p_pio->valid_lifetime != 0)
+ {
+ temp_address.state = IPV6_ADDR_STATE_PREFERRED;
+
+ err_code = ipv6_address_set(p_interface, &temp_address);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ ICMP6_ERR("Cannot add new address! Address table full!");
+ }
+ }
+ else
+ {
+ err_code = ipv6_address_remove(p_interface, &temp_address.addr);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ ICMP6_ERR("Cannot remove address!");
+ }
+ }
+ }
+ else
+ {
+ ICMP6_ERR("Prefix option has incorrect parameters!");
+ return ICMP6_INVALID_PACKET_DATA;
+ }
+
+ break;
+ }
+ case ND_OPT_TYPE_6CO:
+ {
+ p_6co = (nd_option_6co_t *)p_opt;
+
+ memset(context.prefix.u8, 0, IPV6_ADDR_SIZE);
+
+ context.prefix = p_6co->context;
+ context.prefix_len = p_6co->context_length;
+ context.context_id = (p_6co->CID_C & ND_OPT_6CO_CID_MASK) >>
+ ND_OPT_6CO_CID_POS;
+ context.compression_flag = (p_6co->CID_C & ND_OPT_6CO_C_MASK) >>
+ ND_OPT_6CO_C_POS;
+
+ if (p_6co->valid_lifetime == 0)
+ {
+ err_code = iot_context_manager_get_by_cid(p_interface,
+ context.context_id,
+ &p_context);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = iot_context_manager_remove(p_interface, p_context);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ICMP6_TRC("Removed context! CID = 0x%02x", context.context_id);
+ }
+ }
+
+ }
+ else
+ {
+ err_code = iot_context_manager_update(p_interface, &context);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ICMP6_TRC("New context added! CID = 0x%02x", context.context_id);
+ }
+ }
+
+ break;
+ }
+ }
+
+ // Increment current offset option.
+ curr_opt_offset += 8 * p_opt->length;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for notifying application of the ICMPv6 received packet.
+ *
+ * @param[in] p_interface Pointer to external interface from which packet come.
+ * @param[in] p_ip_header Pointer to IPv6 Header.
+ * @param[in] p_icmp_header Pointer to ICMPv6 header.
+ * @param[in] p_packet Pointer to packet buffer.
+ *
+ * @return NRF_SUCCESS after successful processing, error otherwise.
+ */
+static uint32_t ndisc_input(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ icmp6_header_t * p_icmp_header,
+ iot_pbuffer_t * p_packet)
+{
+ uint32_t process_result;
+
+ switch (p_icmp_header->type)
+ {
+ case ICMP6_TYPE_ROUTER_SOLICITATION:
+ ICMP6_ERR("Got unsupported Router Solicitation message.");
+ process_result = ICMP6_UNHANDLED_PACKET_TYPE;
+ break;
+
+ case ICMP6_TYPE_ROUTER_ADVERTISEMENT:
+ ICMP6_TRC("Got Router Advertisement message.");
+ process_result = ra_input(p_interface, p_ip_header, p_icmp_header, p_packet);
+ break;
+
+ case ICMP6_TYPE_NEIGHBOR_SOLICITATION:
+ ICMP6_TRC("Got Neighbour Solicitation message.");
+ process_result = ns_input(p_interface, p_ip_header, p_icmp_header, p_packet);
+ break;
+
+ case ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
+ ICMP6_TRC("Got Neighbour Advertisement message.");
+ process_result = NRF_SUCCESS;
+ break;
+
+ default:
+ process_result = ICMP6_UNHANDLED_PACKET_TYPE;
+ break;
+ }
+
+ return process_result;
+}
+
+uint32_t icmp6_error_message(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr,
+ const icmp6_error_message_param_t * p_param)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_src_addr);
+ NULL_PARAM_CHECK(p_dest_addr);
+ NULL_PARAM_CHECK(p_param);
+ NULL_PARAM_CHECK(p_param->p_packet);
+
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ iot_pbuffer_t * p_pbuffer;
+ ipv6_header_t * p_ip_header;
+ icmp6_header_t * p_icmp_header;
+ iot_pbuffer_alloc_param_t pbuff_param;
+ uint16_t checksum;
+ uint32_t err_code = NRF_SUCCESS;
+ const uint32_t error_packet_length =
+ (MIN(p_param->packet_len,
+ ICMP6_ERROR_MESSAGE_MAX_SIZE - ICMP6_HEADER_SIZE));
+
+ // Requesting buffer for error message.
+ pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
+ pbuff_param.type = ICMP6_PACKET_TYPE;
+ pbuff_param.length = error_packet_length;
+
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
+ IPV6_IP_HEADER_SIZE);
+ p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
+
+ // Change ICMP header.
+ p_icmp_header->type = p_param->type;
+ p_icmp_header->code = p_param->code;
+ p_icmp_header->checksum = 0;
+
+ switch (p_param->type)
+ {
+ case ICMP6_TYPE_PACKET_TOO_LONG:
+ {
+ p_icmp_header->sp.mtu = HTONL(p_param->error_field.mtu);
+ break;
+ }
+ case ICMP6_TYPE_PARAMETER_PROBLEM:
+ {
+ p_icmp_header->sp.offset = HTONL(p_param->error_field.offset);
+ break;
+ }
+ default:
+ {
+ p_icmp_header->sp.unused = 0;
+ break;
+ }
+ }
+
+ // IPv6 Header initialization.
+ icmp_ip_header(p_ip_header, IPV6_DEFAULT_HOP_LIMIT);
+
+ p_ip_header->srcaddr = *p_src_addr;
+ p_ip_header->destaddr = *p_dest_addr;
+ p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
+
+ memcpy(p_pbuffer->p_payload, p_param->p_packet, error_packet_length);
+
+ // Calculate checksum.
+ checksum = error_packet_length + IPV6_NEXT_HEADER_ICMP6;
+
+ 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_pbuffer->p_payload - ICMP6_HEADER_SIZE,
+ p_pbuffer->length + ICMP6_HEADER_SIZE,
+ &checksum,
+ false);
+
+ // Update checksum in the packet.
+ p_icmp_header->checksum = HTONS((~checksum));
+
+ p_pbuffer->p_payload -= ICMP6_OFFSET;
+ p_pbuffer->length += ICMP6_OFFSET;
+
+ // Send IPv6 packet.
+ err_code = ipv6_send(p_interface, p_pbuffer);
+ }
+
+ ICMP6_EXIT();
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t icmp6_echo_request(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr,
+ iot_pbuffer_t * p_request)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_src_addr);
+ NULL_PARAM_CHECK(p_dest_addr);
+ NULL_PARAM_CHECK(p_request);
+ PACKET_TYPE_CHECK(p_request);
+
+ uint32_t err_code = NRF_SUCCESS;
+ uint16_t checksum;
+ ipv6_header_t * p_ip_header;
+ icmp6_header_t * p_icmp_header;
+
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ // Headers of IPv6 packet.
+ p_ip_header = (ipv6_header_t *)(p_request->p_payload - ICMP6_HEADER_SIZE -
+ IPV6_IP_HEADER_SIZE);
+ p_icmp_header = (icmp6_header_t *)(p_request->p_payload - ICMP6_HEADER_SIZE);
+
+ // Change ICMP header.
+ p_icmp_header->type = ICMP6_TYPE_ECHO_REQUEST;
+ p_icmp_header->code = 0;
+ p_icmp_header->checksum = 0;
+
+ // IPv6 Header initialization.
+ icmp_ip_header(p_ip_header, IPV6_DEFAULT_HOP_LIMIT);
+
+ p_ip_header->srcaddr = *p_src_addr;
+ p_ip_header->destaddr = *p_dest_addr;
+ p_ip_header->length = HTONS(p_request->length + ICMP6_HEADER_SIZE);
+
+ // Set echo reply parameters.
+ p_icmp_header->sp.echo.id = 0;
+ p_icmp_header->sp.echo.sequence = HTONS(m_sequence_number);
+
+ // Calculate checksum.
+ checksum = p_request->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
+
+ 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_request->p_payload - ICMP6_HEADER_SIZE,
+ p_request->length + ICMP6_HEADER_SIZE,
+ &checksum,
+ false);
+
+ p_icmp_header->checksum = HTONS((~checksum));
+
+ m_sequence_number++;
+ p_request->p_payload -= ICMP6_OFFSET;
+ p_request->length += ICMP6_OFFSET;
+
+ // Send IPv6 packet.
+ err_code = ipv6_send(p_interface, p_request);
+
+ ICMP6_EXIT();
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t icmp6_rs_send(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_src_addr);
+ NULL_PARAM_CHECK(p_dest_addr);
+
+ uint32_t err_code = NRF_SUCCESS;
+ uint16_t checksum;
+ iot_pbuffer_t * p_pbuffer;
+ iot_pbuffer_alloc_param_t pbuff_param;
+
+ // IPv6 Headers.
+ ipv6_header_t * p_ip_header;
+ icmp6_header_t * p_icmp_header;
+ icmp6_rs_header_t * p_rs_header;
+ nd_option_sllao_t * p_sllao_opt;
+
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ // Requesting buffer for RS message
+ pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
+ pbuff_param.type = ICMP6_PACKET_TYPE;
+ pbuff_param.length = ND_OPT_SLLAO_SIZE;
+
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
+ IPV6_IP_HEADER_SIZE);
+ p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
+ p_rs_header = (icmp6_rs_header_t *)(&p_icmp_header->sp.unused);
+ p_sllao_opt = (nd_option_sllao_t *)(p_pbuffer->p_payload);
+
+ // Change ICMP header.
+ p_icmp_header->type = ICMP6_TYPE_ROUTER_SOLICITATION;
+ p_icmp_header->code = 0;
+ p_icmp_header->checksum = 0;
+
+ // IPv6 Header initialization.
+ icmp_ip_header(p_ip_header, ND_HOP_LIMIT);
+
+ p_ip_header->srcaddr = *p_src_addr;
+ p_ip_header->destaddr = *p_dest_addr;
+ p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
+
+ // Set Router Solicitation parameter.
+ p_rs_header->reserved = 0;
+
+ // Add SLLAO option.
+ add_sllao_opt(p_interface, p_sllao_opt);
+
+ // Calculate checksum.
+ checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
+
+ 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_pbuffer->p_payload - ICMP6_HEADER_SIZE,
+ p_pbuffer->length + ICMP6_HEADER_SIZE,
+ &checksum,
+ false);
+
+ p_icmp_header->checksum = HTONS((~checksum));
+
+ p_pbuffer->p_payload -= ICMP6_OFFSET;
+ p_pbuffer->length += ICMP6_OFFSET;
+
+ // Send IPv6 packet.
+ err_code = ipv6_send(p_interface, p_pbuffer);
+ }
+ else
+ {
+ ICMP6_ERR("Failed to allocate packet buffer!");
+ }
+
+ ICMP6_EXIT();
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+uint32_t icmp6_ns_send(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr,
+ const icmp6_ns_param_t * p_param)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_src_addr);
+ NULL_PARAM_CHECK(p_dest_addr);
+ NULL_PARAM_CHECK(p_param);
+
+ uint32_t err_code = NRF_SUCCESS;
+ uint16_t aro_size = 0;
+ uint16_t checksum;
+ iot_pbuffer_t * p_pbuffer;
+ iot_pbuffer_alloc_param_t pbuff_param;
+
+ // IPv6 Headers.
+ ipv6_header_t * p_ip_header;
+ icmp6_header_t * p_icmp_header;
+ icmp6_ns_header_t * p_ns_header;
+ nd_option_sllao_t * p_sllao_opt;
+ nd_option_aro_t * p_aro_opt;
+
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ if (p_param->add_aro)
+ {
+ aro_size = ND_OPT_ARO_SIZE;
+ }
+
+ // Requesting buffer for NS message
+ pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
+ pbuff_param.type = ICMP6_PACKET_TYPE;
+ pbuff_param.length = ND_NS_HEADER_SIZE + ND_OPT_SLLAO_SIZE + \
+ aro_size - ND_PAYLOAD_ADJUST_OFFSET;
+
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
+ IPV6_IP_HEADER_SIZE);
+ p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
+ p_pbuffer->p_payload -= ND_PAYLOAD_ADJUST_OFFSET;
+ p_ns_header = (icmp6_ns_header_t *)(p_pbuffer->p_payload);
+ p_sllao_opt = (nd_option_sllao_t *)(p_pbuffer->p_payload + ND_NS_HEADER_SIZE);
+ p_aro_opt = (nd_option_aro_t *)(p_pbuffer->p_payload + ND_NS_HEADER_SIZE +
+ ND_OPT_SLLAO_SIZE);
+
+ p_pbuffer->p_payload += ND_PAYLOAD_ADJUST_OFFSET;
+
+ // Change ICMP header.
+ p_icmp_header->type = ICMP6_TYPE_NEIGHBOR_SOLICITATION;
+ p_icmp_header->code = 0;
+ p_icmp_header->checksum = 0;
+
+ // IPv6 Header initialization.
+ icmp_ip_header(p_ip_header, ND_HOP_LIMIT);
+
+ p_ip_header->srcaddr = *p_src_addr;
+ p_ip_header->destaddr = *p_dest_addr;
+ p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
+
+ // Set Neighbour Solicitation parameter.
+ p_ns_header->reserved = 0;
+ p_ns_header->target_addr = p_param->target_addr;
+
+ // Add SLLAO option.
+ add_sllao_opt(p_interface, p_sllao_opt);
+
+ if (p_param->add_aro)
+ {
+ add_aro_opt(p_interface, p_aro_opt, p_param->aro_lifetime);
+ }
+
+ // Calculate checksum.
+ checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
+
+ 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_pbuffer->p_payload - ICMP6_HEADER_SIZE,
+ p_pbuffer->length + ICMP6_HEADER_SIZE,
+ &checksum,
+ false);
+
+ p_icmp_header->checksum = HTONS((~checksum));
+
+ p_pbuffer->p_payload -= ICMP6_OFFSET;
+ p_pbuffer->length += ICMP6_OFFSET;
+
+ // Send IPv6 packet.
+ err_code = ipv6_send(p_interface, p_pbuffer);
+ }
+ else
+ {
+ ICMP6_ERR("Failed to allocate packet buffer!");
+ }
+
+ ICMP6_EXIT();
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t icmp6_receive_register(icmp6_receive_callback_t cb)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(cb);
+ UNUSED_VARIABLE(m_event_handler);
+
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ // Store application event handler.
+ m_event_handler = cb;
+
+ ICMP6_EXIT();
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t icmp6_init(void)
+{
+ SDK_MUTEX_INIT(m_icmp6_mutex);
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ // Set application event handler.
+ m_event_handler = NULL;
+
+ // Indicate initialization of module.
+ m_initialization_state = true;
+
+ ICMP6_EXIT();
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t icmp6_input(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ iot_pbuffer_t * p_packet)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ NULL_PARAM_CHECK(p_interface);
+ NULL_PARAM_CHECK(p_ip_header);
+ NULL_PARAM_CHECK(p_packet);
+
+ uint16_t checksum;
+ uint32_t process_result = NRF_SUCCESS;
+ bool is_ndisc = false;
+ icmp6_header_t * p_icmp_header = (icmp6_header_t *)p_packet->p_payload;
+ uint32_t err_code = NRF_SUCCESS;
+
+ ICMP6_MUTEX_LOCK();
+
+ ICMP6_ENTRY();
+
+ if (p_packet->length < ICMP6_HEADER_SIZE || p_ip_header->length < ICMP6_HEADER_SIZE)
+ {
+ ICMP6_ERR("Received malformed packet, which has 0x%08lX bytes.", p_packet->length);
+ process_result = ICMP6_MALFORMED_PACKET;
+ }
+ else
+ {
+ // Check checksum of packet.
+ checksum = p_packet->length + IPV6_NEXT_HEADER_ICMP6;
+
+ 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);
+ checksum = (uint16_t)~checksum;
+
+ // Change pbuffer type.
+ p_packet->type = ICMP6_PACKET_TYPE;
+ p_packet->p_payload = p_packet->p_payload + ICMP6_HEADER_SIZE;
+ p_packet->length -= ICMP6_HEADER_SIZE;
+
+ if (checksum != 0)
+ {
+ ICMP6_ERR("Bad checksum detected. Got 0x%08x but expected 0x%08x, 0x%08lX",
+ NTOHS(p_icmp_header->checksum), checksum, p_packet->length);
+ process_result = ICMP6_BAD_CHECKSUM;
+ }
+ else
+ {
+ switch (p_icmp_header->type)
+ {
+ case ICMP6_TYPE_DESTINATION_UNREACHABLE:
+ case ICMP6_TYPE_PACKET_TOO_LONG:
+ case ICMP6_TYPE_TIME_EXCEED:
+ case ICMP6_TYPE_PARAMETER_PROBLEM:
+ {
+ ICMP6_TRC("Got ICMPv6 error message with type = 0x%08x",
+ p_icmp_header->type);
+ p_icmp_header->sp.unused = NTOHL(p_icmp_header->sp.unused);
+ break;
+ }
+ case ICMP6_TYPE_ECHO_REQUEST:
+ case ICMP6_TYPE_ECHO_REPLY:
+ {
+ ICMP6_TRC("Got ICMPv6 Echo message with type = 0x%x.", p_icmp_header->type);
+ ICMP6_TRC("From IPv6 Address:");
+ ICMP6_DUMP(p_ip_header->srcaddr.u32, IPV6_ADDR_SIZE);
+ ICMP6_TRC("Identifier: 0x%04x, Sequence Number: 0x%04x",
+ NTOHS(p_icmp_header->sp.echo.id),
+ NTOHS(p_icmp_header->sp.echo.sequence));
+ break;
+ }
+ case ICMP6_TYPE_ROUTER_SOLICITATION:
+ case ICMP6_TYPE_ROUTER_ADVERTISEMENT:
+ case ICMP6_TYPE_NEIGHBOR_SOLICITATION:
+ case ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
+ {
+ p_packet->p_payload = p_packet->p_payload - ND_PAYLOAD_ADJUST_OFFSET;
+ p_packet->length += ND_PAYLOAD_ADJUST_OFFSET;
+ process_result = ndisc_input(p_interface,
+ p_ip_header,
+ p_icmp_header,
+ p_packet);
+ p_packet->p_payload = p_packet->p_payload + ND_PAYLOAD_ADJUST_OFFSET;
+ p_packet->length -= ND_PAYLOAD_ADJUST_OFFSET;
+ is_ndisc = true;
+ break;
+ }
+ default:
+ process_result = ICMP6_UNHANDLED_PACKET_TYPE;
+ break;
+ }
+
+#if (ICMP6_ENABLE_HANDLE_ECHO_REQUEST_TO_APPLICATION == 0)
+ if (p_icmp_header->type == ICMP6_TYPE_ECHO_REQUEST)
+ {
+ echo_reply_send(p_interface, p_ip_header, p_icmp_header, p_packet);
+ }
+#endif
+ }
+ }
+
+#if (ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION == 1)
+ err_code = app_notify_icmp_data(p_interface, p_packet, process_result);
+#elif (ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION == 1)
+ if (is_ndisc)
+ {
+ err_code = app_notify_icmp_data(p_interface, p_packet, process_result);
+ }
+#endif
+
+ ICMP6_EXIT();
+
+ UNUSED_VARIABLE(is_ndisc);
+ UNUSED_VARIABLE(process_result);
+
+ ICMP6_MUTEX_UNLOCK();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.h
new file mode 100644
index 0000000..7ce517b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/icmp6/icmp6.h
@@ -0,0 +1,101 @@
+/**
+ * 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 icmp6.h
+ *
+ * @defgroup iot_icmp6 ICMP Module Header.
+ * @ingroup iot_sdk
+ * @{
+ * @brief Internet Control Message Protocol module header defining interface between the ICMP6
+ * module and other IP stack layers. This interface is internal to the IPv6 stack and not
+ * available to the application. The application shall not explicitly use this interface.
+ *
+ */
+
+#ifndef ICMP6_H__
+#define ICMP6_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 icmp6_init(void);
+
+
+/**
+ * @brief Function to feed incoming ICMP 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 ICMP packet being fed to the module.
+ * @param[in] p_packet ICMP 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 transport
+ * protocol value of 58.
+ *
+ * @retval NRF_SUCCESS on successful handling of the packet, else an error code indicating reason
+ * for failure.
+ */
+uint32_t icmp6_input(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ iot_pbuffer_t * p_packet);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ICMP6_H__
+
+/**@} */
+
+/** @endcond */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/dns6_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/dns6_api.h
new file mode 100644
index 0000000..0f6ecd9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/dns6_api.h
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file dns6_api.h
+ *
+ * @defgroup iot_dns6 DNS Application Interface for Nordic's IPv6 stack
+ * @ingroup iot_sdk_stack
+ * @{
+ * @brief Domain Name System module provides implementation of DNS6 service.
+ *
+ */
+
+#ifndef DNS6_H__
+#define DNS6_H__
+
+#include "sdk_config.h"
+#include "sdk_common.h"
+#include "ipv6_api.h"
+#include "iot_timer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief DNS Server parameter. */
+typedef struct
+{
+ ipv6_addr_t addr; /**< The IPv6 address of the DNS Server. */
+ uint16_t port; /**< The default UDP port of the DNS Server. */
+} dns6_server_param_t;
+
+
+/**@brief Initialization parameters type. */
+typedef struct
+{
+ uint16_t local_src_port; /**< The local UDP port for reception the DNS responses. */
+ dns6_server_param_t dns_server; /**< Parameters of the DNS Server. */
+} dns6_init_t;
+
+
+/**
+ * @brief DNS event receive callback.
+ *
+ * @details API used to notify the application of DNS Response on specific hostname or of an error
+ * during resolving process. The process_result parameter indicates whether the DNS module
+ * was successfully processed. If the received DNS Response is malformed in a way that
+ * allow to assign response with specific callback (e.g. timeout occurs or hostname is not
+ * found), information about error is still notified to the application. The application
+ * should check process_result and number of IPv6 address before reading them.
+ *
+ * @param[in] process_result Notifies the application if the DNS module was processed successfully
+ * or if an error occurred, for example DNS server is unreachable.
+ * @param[in] p_hostname Identifies hostname (URL string) that was requested to bee resolved,
+ * e.g. "example.com".
+ * @param[in] p_addr Pointer to the IPv6 addresses being resolved for given hostname. In
+ * case addr_count variable is 0, p_addr gets NULL value and should not
+ * be used.
+ * @param[in] addr_count Number of IPv6 addresses being successfully resolved.
+ *
+ * @retval None.
+ */
+typedef void (* dns6_evt_handler_t) (uint32_t process_result,
+ const char * p_hostname,
+ ipv6_addr_t * p_addr,
+ uint16_t addr_count);
+
+/**
+ * @brief Function for initializing DNS6 module.
+ *
+ * @param[in] p_dns_init Initialization structure for DNS client. Should not be NULL.
+ *
+ * @note DNS protocol module uses UDP transport layer, therefore one UDP socket is allocated
+ * inside function and uses for further communication.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t dns6_init(const dns6_init_t * p_dns_init);
+
+
+/**
+ * @brief Function for uninitializing DNS6 module.
+ *
+ * @note Apart of DNS specific functionality, function frees previously allocated UDP socket.
+ * Function removes any pending queries from the sending queue, so registered user
+ * callbacks will not be executed.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t dns6_uninit(void);
+
+
+/**
+ * @brief Function for querying given URL string to DNS server, in order to get IPv6 address of
+ * given hostname.
+ *
+ * @param[in] p_hostname Identifies hostname (URL string) to be find, e.g. "example.com". Should
+ * not be NULL.
+ * @param[in] evt_handler Callback that is called once response is received, timeout occurred or
+ * internal error was detected. Should not be NULL.
+ *
+ * @note Function sends DNS Query to DNS Server to obtain all AAAA records (with IPv6 address)
+ * assigned to given hostname. In case DNS Server replies with more that one AAAA records
+ * DNS module call user defined evt_handler with addr_count indicates number of addresses.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure.
+ * @retval IOT_DNS6_ERR_BASE | NRF_ERROR_NO_MEM if there is no place in pending queries' queue.
+ * @retval IOT_PBUFFER_ERR_BASE | NRF_ERROR_NO_MEM if there is no memory for hostname allocation.
+ * @retval NRF_ERROR_MEMORY_MANAGER_ERR_BASE | NRF_ERROR_NO_MEM if there is no memory for packet allocation.
+ * @retval UDP_INTERFACE_NOT_READY if interface is not ready for sending packets e.g. interface is
+ * down.
+ * @retval Other errors indicates reason of failure.
+ */
+uint32_t dns6_query(const char * p_hostname, dns6_evt_handler_t evt_handler);
+
+
+/**@brief Function for performing retransmissions of DNS queries.
+ *
+ * @note DNS module implements the retransmission mechanism by invoking this function periodically.
+ * So that method has to be added to IoT Timer client list and has to be called with minimum of
+ * DNS6_RETRANSMISSION_INTERVAL resolution.
+ *
+ * @param[in] wall_clock_value The value of the wall clock that triggered the callback.
+ *
+ * @retval None.
+ */
+void dns6_timeout_process(iot_timer_time_in_ms_t wall_clock_value);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //DNS6_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/icmp6_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/icmp6_api.h
new file mode 100644
index 0000000..b13b4b6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/icmp6_api.h
@@ -0,0 +1,253 @@
+/**
+ * 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.
+ *
+ */
+/** @file icmp6_api.h
+ *
+ * @defgroup iot_icmp6 ICMP6 Application Interface for Nordic's IPv6 stack
+ * @ingroup iot_sdk_stack
+ * @{
+ * @brief Nordic Internet Control Message Protocol Application Interface for Nordic's IPv6 stack.
+ *
+ * @details This module provides basic features related to ICMPv6 support.
+ */
+
+#ifndef ICMP6_API_H__
+#define ICMP6_API_H__
+
+#include "sdk_config.h"
+#include "sdk_common.h"
+#include "iot_defines.h"
+#include "ipv6_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET 8 /**< Offset of echo request payload from ICMPv6 header. */
+
+
+/**@defgroup icmp6_code ICMPv6 codes per message type as defined in RFC 4443.
+ * @ingroup iot_icmp6
+ * @{
+ */
+#define ICMP6_DU_CODE_NO_ROUTE_TO_DESTINATION 0 /**< Code for Destination Unreachable Message when there is no route to destination. */
+#define ICMP6_DU_CODE_ADMINISTRATIVELY_PROHIBITED 1 /**< Code for Destination Unreachable Message when the communication to destination administratively prohibited. */
+#define ICMP6_DU_CODE_BEYOND_SCOPE_OF_SOURCE 2 /**< Code for Destination Unreachable Message when the destination is beyond the scope of source address. */
+#define ICMP6_DU_CODE_ADDRESS_UNREACHABLE 3 /**< Code for Destination Unreachable Message when the destination address is unreachable. */
+#define ICMP6_DU_CODE_PORT_UNREACHABLE 4 /**< Code for Destination Unreachable Message when the destination port is unreachable. */
+#define ICMP6_DU_CODE_FAILED_INGRESS_EGRESS_POLICY 5 /**< Code for Destination Unreachable Message when the source address failed on ingress/egress policy. */
+#define ICMP6_DU_CODE_REJECT_ROUTE_TO_DESTINATION 6 /**< Code for Destination Unreachable Message when the route to destination is rejected. */
+
+#define ICMP6_TE_CODE_EXCEEDED_HOP_LIMIT_TRANSIT 0 /**< Code for Time Exceeded Message when the packet received had hop limit of zero. */
+#define ICMP6_TE_CODE_FAR_TIME_EXCEEDED 1 /**< Code for Time Exceeded Message to report fragmentation and reassembly timeout. */
+
+#define ICMP6_PP_CODE_INVALID_HEADER 0 /**< Code for Parameter Problem Message when the header of the incoming packet was erroneous. */
+#define ICMP6_PP_CODE_UNKNOWN_NEXT_HEADER 1 /**< Code for Parameter Problem Message when the next header of the incoming packet was unrecognized. */
+#define ICMP6_PP_CODE_UNKNOWN_IPV6_OPTION 2 /**< Code for Parameter Problem Message when the option of the incoming packet was unrecognized. */
+
+#define ICMP6_ERROR_MESSAGE_INVOKING_PKT_OFFSET 8 /**< Offset in the received ICMPv6 payload where the packet (partial or complete) that invoked the error message is found. */
+/* @} */
+
+/** Neighbor solicitation parameters. */
+typedef struct
+{
+ ipv6_addr_t target_addr; /**< The IPv6 address of the target of the solicitation. MUST NOT be a multi-cast address. */
+ bool add_aro; /**< Indicates if ARO option should be added. */
+ uint16_t aro_lifetime; /**< The amount of time in units of 60 seconds that the router should retain the NCE for the sender of the NS. */
+} icmp6_ns_param_t;
+
+/**@brief Parameters associated with error message in receive and transmit paths. */
+typedef struct
+{
+ uint8_t type; /**< Identifies error message type, valid values as described in RFC 4443. See @ref icmp6_error_type for possible values. */
+ uint8_t code; /**< Identifies code, if any associated with the error. See \ref icmp6_code and RFC 4443 for details. */
+ union /**< Additional field like MTU, pointer or unused based on message type. See RFC 4443 for more details. If unused, application may ignore this field. */
+ {
+ uint32_t mtu; /**< MTU of next hop limit, used only with ICMP6_TYPE_PACKET_TOO_LONG type. */
+ uint32_t offset; /**< Offset pointing to the parameter that resulted in the ICMP6_TYPE_PARAMETER_PROBLEM error. Used only with ICMP6_TYPE_PARAMETER_PROBLEM. */
+ uint32_t unused; /**< Any other error message. Is always zero. */
+ } error_field;
+ uint8_t * p_packet; /**< Points to the start of IPv6 packet that has resulted in the error message. */
+ uint16_t packet_len; /**< Length of the packet that resulted in error. The module may truncate the packet and pack only partially the packet based on configuration of ICMP6_ERROR_MESSAGE_MAX_SIZE. */
+} icmp6_error_message_param_t;
+
+
+/**@brief ICMPv6 data RX callback.
+ *
+ * @details Asynchronous callback used to notify the application of ICMP packets received.
+ * By default, the application is not notified through ICMP of messages related to ECHO
+ * requests or any errors. However, these notifications can easily be enabled by defining
+ * either the ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION or the
+* ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION if the application should handle them.
+ *
+ * @param[in] p_interface Pointer to the IPv6 interface from where the ICMP packet was received.
+ * @param[in] p_ip_header Pointer to the IP header of the ICMP packet received.
+ * @param[in] p_icmp_header Pointer to the ICMP header of the received packet.
+ * @param[in] process_result Notifies the application if the ICMP packet was processed successfully or if
+ * an error occurred, for example, if the packet was malformed.
+ * @param[in] p_rx_packet Packet buffer containing the packet received. p_rx_packet->p_payload
+ * contains the ICMP payload.
+ *
+ * @retval A provision for the application to notify the module of whether the received packet was
+ * processed successfully by application. The application may take ownership of the received
+ * packet by returning IOT_IPV6_ERR_PENDING, in which case the application must take care to
+ * free it using @ref iot_pbuffer_free.
+ */
+typedef uint32_t (*icmp6_receive_callback_t)(iot_interface_t * p_interface,
+ ipv6_header_t * p_ip_header,
+ icmp6_header_t * p_icmp_header,
+ uint32_t process_result,
+ iot_pbuffer_t * p_rx_packet);
+
+
+/**@brief Sends ICMPv6 Error Message as defined in RFC 4443.
+ *
+ * @details API to send messages categorized under error messages. See @ref icmp6_error_type and
+ * RFC 4443 for valid types.
+ *
+ * @param[in] p_interface Identifies the interface on which the procedure was requested.
+ * Shall not be NULL.
+ * @param[in] p_src_addr Source IPv6 address to be used for the request. Shall not be NULL.
+ * @param[in] p_dest_addr Destination IPv6 address to which the message send is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Parameters describing Type, code, invoking packet information any
+ * additional details associated with the error message.
+ *
+ * @retval NRF_SUCCESS If the send request was successful, else, an error code indicating reason for
+ * failure.
+ */
+uint32_t icmp6_error_message(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr,
+ const icmp6_error_message_param_t * p_param);
+
+
+/**@brief Sends ICMPv6 echo request as defined in RFC4443.
+ *
+ * @details API used to send an ICMPv6 echo request packet to a specific destination address.
+ * The user can decide how much additional data must be sent.
+ *
+ * The application calling the function should allocate a packet before, with the type set to
+ * ICMP6_PACKET_TYPE in the allocation parameter.
+ *
+ * The application should pack the payload at ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET. ID,
+ * Sequence number, ICMP Code, type checksum, etc. are filled in by the module.
+ *
+ * The application shall not free the allocated packet buffer if the procedure was successful,
+ * to ensure that no data copies are needed when transmitting a packet.
+ *
+ * @param[in] p_interface Pointer to the IPv6 interface to send the ICMP packet.
+ * @param[in] p_src_addr IPv6 source address from where the echo request is sent.
+ * @param[in] p_dest_addr IPv6 destination address to where the echo request is sent.
+ * @param[in] p_request Packet buffer containing the echo request.
+ *
+ * @retval NRF_SUCCESS If the send request was successful.
+ */
+uint32_t icmp6_echo_request(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr,
+ iot_pbuffer_t * p_request);
+
+
+/**@brief Sends router solicitation message defined in RFC6775.
+ *
+ * @details API used to send a neighbor discovery message of type Router Solicitation to a specific
+ * destination address. If no address is known, the user should send the message to all
+ * routers' address (FF02::1).
+ *
+ * The function internally tries to allocate a packet buffer. EUI-64 used in the SLLAO option is
+ * taken from the interface parameter defined in the @ref ipv6_init() function.
+ *
+ * @param[in] p_interface Pointer to the IPv6 interface to send the ICMP packet.
+ * @param[in] p_src_addr IPv6 source address from where the router solicitation message is
+ * sent.
+ * @param[in] p_dest_addr IPv6 destination address to where the router solicitation message is
+ * sent.
+ *
+ * @retval NRF_SUCCESS If the send request was successful.
+ */
+uint32_t icmp6_rs_send(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr);
+
+
+/**@brief Sends neighbour solicitation message defined in RFC6775.
+ *
+ * @details API used to send a neighbor discovery message of type Neighbor Solicitation to a
+ * specific destination address.
+ *
+ * The function internally tries to allocate a packet buffer. EUI-64 used in the SLLAO and ARO
+ * options is taken from the interface parameter defined in the @ref ipv6_init() function.
+ *
+ * @param[in] p_interface Pointer to the IPv6 interface to send the ICMP packet.
+ * @param[in] p_src_addr IPv6 source address from where the neighbor solicitation message is
+ * sent.
+ * @param[in] p_dest_addr IPv6 destination address to where the neighbor solicitation message
+ * is sent.
+ * @param[in] p_ns_param Neighbor discovery parameters.
+ *
+ * @retval NRF_SUCCESS If the send request was successful.
+ */
+uint32_t icmp6_ns_send(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_src_addr,
+ const ipv6_addr_t * p_dest_addr,
+ const icmp6_ns_param_t * p_ns_param);
+
+
+/**@brief Registers the callback function for echo reply.
+ *
+ * @details API used to register callback to indicate the ICMP echo reply packet. Could be not used.
+ *
+ * Neighbor discovery related messages are not relayed to the application by default.
+ * However, this can be enabled by using the ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION
+ * configuration parameter.
+ *
+ * @param[in] cb Handler called when an ICMP packet is received.
+ *
+ * @retval NRF_SUCCESS If the registration was successful.
+ */
+uint32_t icmp6_receive_register(icmp6_receive_callback_t cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ICMP6_API_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/ipv6_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/ipv6_api.h
new file mode 100644
index 0000000..33b8ec9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/ipv6_api.h
@@ -0,0 +1,207 @@
+/**
+ * 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.
+ *
+ */
+/** @file ipv6_api.h
+ *
+ * @defgroup iot_ipv6 IPv6 Core Application Interface for Nordic's IPv6 stack
+ * @ingroup iot_sdk_stack
+ * @{
+ * @brief Nordic's IPv6 stack. Currently, only a Host role is supported.
+ *
+ * @details Nordic's IPv6 stack provides minimal implementations of ICMP, UDP for a Host, and
+ * IPv6 Neighbor Discovery for Host.
+ * Router, neighbor, and prefix cache are not maintained across BLE link disconnections or
+ * power cycles.
+ */
+
+#ifndef IPV6_API_H_
+#define IPV6_API_H_
+
+#include <stdint.h>
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "iot_pbuffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Asynchronous event identifiers type. */
+typedef enum
+{
+ IPV6_EVT_INTERFACE_ADD, /**< Notification of a new IPv6 interface added. */
+ IPV6_EVT_INTERFACE_DELETE, /**< Notification of IPv6 interface deleted. */
+ IPV6_EVT_INTERFACE_RX_DATA /**< Notification of IPv6 data, depending on configuration. For example, IPV6_ENABLE_USNUPORTED_PROTOCOLS_TO_APPLICATION. */
+} ipv6_event_id_t;
+
+/**@brief IPv6 address configuration. */
+typedef struct
+{
+ ipv6_addr_t addr;
+ ipv6_addr_state_t state;
+} ipv6_addr_conf_t;
+
+/**@brief Event parameters associated with the IPV6_EVT_INTERFACE_RX_DATA event. */
+typedef struct
+{
+ ipv6_header_t * p_ip_header; /**< IPv6 header of the packet. */
+ iot_pbuffer_t * p_rx_packet; /**< Packet buffer contains received data. */
+} ipv6_data_rx_t;
+
+/**@brief Asynchronous event parameter type. */
+typedef union
+{
+ ipv6_data_rx_t rx_event_param; /**< Parameters notified with the received IPv6 packet. */
+} ipv6_event_param_t;
+
+/**@brief Asynchronous event type. */
+typedef struct
+{
+ ipv6_event_id_t event_id; /**< Event identifier. */
+ ipv6_event_param_t event_param; /**< Event parameters. */
+} ipv6_event_t;
+
+/**@brief Asynchronous event notification callback type. */
+typedef void (* ipv6_evt_handler_t)(iot_interface_t * p_interface,
+ ipv6_event_t * p_event);
+
+/**@brief Initialization parameters type. */
+typedef struct
+{
+ eui64_t * p_eui64; /**< Global identifiers EUI-64 address of device. */
+ ipv6_evt_handler_t event_handler; /**< Asynchronous event notification callback registered to receive IPv6 events. */
+} ipv6_init_t;
+
+
+/**@brief Initializes the IPv6 stack module.
+ *
+ * @param[in] p_init Initialization parameters.
+ *
+ * @retval NRF_SUCCESS If initialization was successful. Otherwise, an error code is returned.
+ */
+uint32_t ipv6_init(const ipv6_init_t * p_init);
+
+/**@brief Sets address to specific interface.
+ *
+ * @details API used to add or update an IPv6 address on an interface. The address can have three specific
+ * states that determine transmitting capabilities.
+ *
+ * @param[in] p_interface The interface on which the address must be assigned.
+ * @param[in] p_addr IPv6 address and state to be assigned/updated.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NO_MEM If no memory was available.
+ */
+uint32_t ipv6_address_set(const iot_interface_t * p_interface,
+ const ipv6_addr_conf_t * p_addr);
+
+
+/**@brief Removes address from specific interface.
+ *
+ * @details API used to remove an IPv6 address from an interface.
+ *
+ * @param[in] p_interface The interface from which the address must be removed.
+ * @param[in] p_addr IPv6 address to remove.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NOT_FOUND If no address was found.
+ */
+uint32_t ipv6_address_remove(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_addr);
+
+
+/**@brief Checks if given unicast address has been registered.
+ *
+ * @param[in] p_interface The interface on which IPv6 address wil be checked.
+ * @param[in] p_addr IPv6 address to be checked.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NOT_FOUND If no address was found.
+ */
+uint32_t ipv6_address_check(const iot_interface_t * p_interface,
+ const ipv6_addr_t * p_addr);
+
+
+/**@brief Finds the best matched address and interface.
+ *
+ * @details API used to find the most suitable interface and address to a given destination address.
+ *
+ * To look only for the interface, set p_addr_r to NULL.
+ *
+ * To find the best matched address, IPV6_ADDR_STATE_PREFERRED state of address is required.
+ *
+ * @param[out] pp_interface Interface to be found.
+ * @param[out] p_addr_r Best matching address if procedure succeeded and this value was not NULL.
+ * @param[inout] p_addr_f IPv6 address for which best matching interface and/or address are requested.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NOT_FOUND If no interface was found.
+ * @retval NRF_ERROR_NOT_SUPPORTED If the operation was not supported.
+ */
+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);
+
+
+/**@brief Sends IPv6 packet.
+ *
+ * @details API used to send an IPv6 packet. Which interface that packet must be sent to is determined
+ * by analyzing the destination address.
+ *
+ * @param[in] p_interface The interface to which the packet is to be sent.
+ * @param[in] p_packet IPv6 packet to send. The packet should be allocated using
+ * @ref iot_pbuffer_allocate, to give stack control and to release
+ * the memory buffer.
+ *
+ * @retval NRF_SUCCESS If the send request was successful.
+ * @retval NRF_ERROR_NOT_FOUND If there was a failure while looking for the interface.
+ * @retval NRF_ERROR_INVALID_PARAM If there was an error in processing the IPv6 packet.
+ * @retval NRF_ERROR_NO_MEM If no memory was available in the transport
+ * interface.
+ */
+uint32_t ipv6_send(const iot_interface_t * p_interface, iot_pbuffer_t * p_packet);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IPV6_API_H_
+
+/** @} */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/udp_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/udp_api.h
new file mode 100644
index 0000000..8efa378
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/include/udp_api.h
@@ -0,0 +1,255 @@
+/**
+ * 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.
+ *
+ */
+/** @file udp_api.h
+ *
+ * @defgroup iot_udp UDP Application Interface for Nordic's IPv6 stack
+ * @ingroup iot_sdk_stack
+ * @{
+ * @brief Nordic User Datagram Protocol Application Interface for Nordic's IPv6 stack.
+ *
+ * @details This module provides basic features related to User Datagram Protocol (UDP) support.
+ */
+
+#ifndef UDP_API_H__
+#define UDP_API_H__
+
+#include "sdk_config.h"
+#include "sdk_common.h"
+#include "iot_defines.h"
+#include "ipv6_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief UDP socket reference.
+ */
+typedef struct
+{
+ uint32_t socket_id; /**< UDP socket identifier. */
+ void * p_app_data; /**< Pointer to application data mapped by the application to the socket. If no mapping is provided by the application using the @ref udp6_socket_app_data_set API, this pointer is NULL. */
+} udp6_socket_t;
+
+/**
+ * @brief UDP data receive callback.
+ *
+ * @details API used to notify the application of UDP packets received. If the received data is
+ * malformed (for example, a checksum error), the packet is still notified to the application.
+ * The process_result parameter indicates whether the packet was successfully processed by UDP.
+ * The application should check process_result before
+ * consuming the packet.
+ *
+ * @param[in] p_socket Reference to the socket on which the data is received.
+ * @param[in] p_ip6_header Pointer to the IP header of the received ICMP packet.
+ * @param[in] p_udp_header Pointer to the UDP header of the received packet.
+ * @param[in] process_result Notifies the application if the UDP packet was processed successfully success or
+ * if an error occurred, for example, the packet was malformed.
+ * @param[in] p_rx_packet Packet buffer containing the received packed. p_rx_packet->p_payload
+ * contains the UDP payload.
+ *
+ * @returns A provision for the application to notify the module of whether the received packet was
+ * processed successfully by application. The application may take ownership of the received
+ * packet by returning IOT_IPV6_ERR_PENDING, in which case the application must take care to
+ * free it using @ref iot_pbuffer_free.
+ */
+typedef uint32_t (* udp6_handler_t)(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);
+
+
+/**
+ * @brief Allocates a UDP socket.
+ *
+ * @details This API should be called to be assigned a UDP socket. The maximum number of sockets that can
+ * be allocated using the API is determined by the define UDP6_MAX_SOCKET_COUNT.
+ *
+ * @param[out] p_socket Reference to the allocated socket is provided in the pointer if the procedure
+ * was successful. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the socket was allocated successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ */
+uint32_t udp6_socket_allocate(udp6_socket_t * p_socket);
+
+
+/**
+ * @brief Frees an allocated UDP socket.
+ *
+ * @details API used to free a socket allocated using @ref udp6_socket_allocate.
+ *
+ * @param[in] p_socket Handle reference to the socket. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the socket was freed successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t udp6_socket_free(const udp6_socket_t * p_socket);
+
+
+/**
+ * @brief Registers callback to be notified of data received on a socket.
+ *
+ * @details API to register a callback to be notified of data received on a socket.
+ *
+ * @param[in] p_socket Handle reference to the socket. Should not be NULL.
+ * @param[in] callback Callback being registered to receive data. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS If the procedure was executed successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t udp6_socket_recv(const udp6_socket_t * p_socket,
+ const udp6_handler_t callback);
+
+
+/**
+ * @brief Binds a UDP socket to a specific port and address.
+ *
+ * @details API used to bind a UDP socket to a local port and an address.
+ *
+ * @param[in] p_socket Handle reference to the socket. Should not be NULL.
+ * @param[in] p_src_addr Local IPv6 address to be bound on specific socket.
+ * @param[in] src_port Local UDP port to be bound on specific socket.
+ *
+ * @retval NRF_SUCCESS If the procedure was executed successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t udp6_socket_bind(const udp6_socket_t * p_socket,
+ const ipv6_addr_t * p_src_addr,
+ uint16_t src_port);
+
+
+/**
+ * @brief Connects a UDP socket to aspecific port and address.
+ *
+ * @details API used to connect a UDP socket to a remote port and remote address.
+ *
+ * @param[in] p_socket Handle reference to the socket. Should not be NULL.
+ * @param[in] p_dest_addr IPv6 address of the remote destination.
+ * @param[in] dest_port Remote USP port to connect the socket to.
+ *
+ * @retval NRF_SUCCESS If the connection was established successfully.
+ */
+uint32_t udp6_socket_connect(const udp6_socket_t * p_socket,
+ const ipv6_addr_t * p_dest_addr,
+ uint16_t dest_port);
+
+
+/**
+ * @brief Sends a UDP packet on a specific socket.
+ *
+ * @details API used to send UDP data over a UDP socket. Remote port and address must be set with
+ * \ref udp6_socket_connect() before using this API.
+ *
+ * Applications that call this function should allocate a packet with type
+ * UDP6_PACKET_TYPE (set in the allocation
+ * parameter) before calling the function.
+ *
+ * The application shall not free the allocated packet buffer if the procedure was
+ * successful, to ensure that no data copies are needed when transmitting a packet.
+ *
+ * @param[in] p_socket Handle reference to the socket. Should not be NULL.
+ * @param[in] p_packet Data to be transmitted on the socket. The application should allocate a packet
+ * buffer with type UDP6_PACKET_TYPE using \ref iot_pbuffer_allocate.
+ * p_packet->p_payload and p_packet->length should be appropriately
+ * populated by the application to contain the payload and length of the UDP
+ * packet, respectively.
+ *
+ * @retval NRF_SUCCESS If the procedure was executed successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t udp6_socket_send(const udp6_socket_t * p_socket,
+ iot_pbuffer_t * p_packet);
+
+
+/**
+ * @brief Sends a UDP packet on a specific socket to a remote address and port.
+ *
+ * @details API used to send UDP data over a UDP socket.
+ *
+ * @param[in] p_socket Handle reference to the socket. Should not be NULL.
+ * @param[in] p_dest_addr IPv6 address of the remote destination.
+ * @param[in] dest_port Remote UDP port to which data transmission is requested.
+ * @param[in] p_packet Data to be transmitted on the socket. Application should allocate a
+ * packet buffer with type UDP6_PACKET_TYPE using \ref
+ * iot_pbuffer_allocate. p_packet->p_payload and p_packet->length should
+ * be appropriately populated by the application to contain the payload and
+ * length of the UDP packet, respectively.
+ *
+ * @retval NRF_SUCCESS If the procedure was executed successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ *
+ */
+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);
+
+
+/**
+ * @brief Sets application data for a socket.
+ *
+ * @details A utility API that allows the application to set any application specific mapping with the
+ * UDP Socket. The UDP module remembers the pointer provided by the application as long as the
+ * socket is not freed and if receive data callback is called each time as part of
+ * udp_socket_t.
+ *
+ * @param[in] p_socket Pointer to the socket for which the application data mapping is being set.
+ * A pointer to the application data should be provided by setting the
+ * p_socket->p_app_data field.
+ *
+ * @retval NRF_SUCCESS If the procedure was executed successfully. Otherwise, an
+ * error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t udp6_socket_app_data_set(const udp6_socket_t * p_socket);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //UDP_API_H__
+
+/**@} */
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;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.c
new file mode 100644
index 0000000..6611396
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.c
@@ -0,0 +1,467 @@
+/**
+ * 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_soc.h"
+#include "nordic_common.h"
+#include "sdk_common.h"
+#include "sdk_config.h"
+#include "iot_common.h"
+#include "iot_pbuffer.h"
+#include "mem_manager.h"
+
+#if IOT_PBUFFER_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME pbuffer
+
+#define NRF_LOG_LEVEL IOT_PBUFFER_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IOT_PBUFFER_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IOT_PBUFFER_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define PBUFFER_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define PBUFFER_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define PBUFFER_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define PBUFFER_ENTRY() PBUFFER_TRC(">> %s", __func__)
+#define PBUFFER_EXIT() PBUFFER_TRC("<< %s", __func__)
+
+#else // IOT_PBUFFER_CONFIG_LOG_ENABLED
+
+#define PBUFFER_TRC(...) /**< Disables traces. */
+#define PBUFFER_DUMP(...) /**< Disables dumping of octet streams. */
+#define PBUFFER_ERR(...) /**< Disables error logs. */
+
+#define PBUFFER_ENTRY(...)
+#define PBUFFER_EXIT(...)
+
+#endif // IOT_PBUFFER_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.
+ * BLE_HPS_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
+ *
+ * @{
+ */
+#if (IOT_PBUFFER_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_PBUFFER_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_PBUFFER_ERR_BASE); \
+ }
+
+/**
+ * @brief Verify Type field has valid value.
+ */
+#define VERIFY_PBUFFER_TYPE(TYPE) \
+ if (((TYPE) == 0) || ((TYPE) > COAP_PACKET_TYPE)) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_PBUFFER_ERR_BASE); \
+ }
+
+
+/**
+ * @brief Verify flags field has valid value.
+ */
+#define VERIFY_PBUFFER_FLAGS(FLAG) \
+ if ((uint32_t)(FLAG) > PBUFFER_FLAG_NO_MEM_ALLOCATION) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM | IOT_PBUFFER_ERR_BASE); \
+ }
+
+/**
+ * @brief Verify flags field has valid value.
+ */
+#define VERIFY_NON_ZERO_LENGTH(LEN) \
+ if ((LEN) ==0) \
+ { \
+ return (NRF_ERROR_INVALID_LENGTH | IOT_PBUFFER_ERR_BASE); \
+ }
+
+#else //IOT_PBUFFER_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define VERIFY_MODULE_IS_INITIALIZED_VOID()
+#define NULL_PARAM_CHECK(PARAM)
+#define VERIFY_PBUFFER_TYPE(TYPE)
+#define VERIFY_PBUFFER_FLAGS(FLAG)
+#define VERIFY_NON_ZERO_LENGTH(LEN)
+
+#endif //IOT_PBUFFER_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 PBUFFER_MUTEX_LOCK() SDK_MUTEX_LOCK(m_pbuffer_mutex) /**< Lock module using mutex */
+#define PBUFFER_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_pbuffer_mutex) /**< Unlock module using mutex */
+/** @} */
+
+/** @brief Packet buffer type managed by the module. */
+typedef struct
+{
+ iot_pbuffer_t buffer; /**< Packet buffer being managed. */
+ uint32_t allocated_length; /**< Length allocated for the buffer. */
+}pbuffer_t;
+
+SDK_MUTEX_DEFINE(m_pbuffer_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 pbuffer_t m_pbuffer[IOT_PBUFFER_MAX_COUNT]; /**< Table of packet buffers managed by the module. */
+
+
+/**@brief Initializes packet buffer. */
+static void pbuffer_init(pbuffer_t * p_buffer)
+{
+ p_buffer->buffer.p_memory = NULL;
+ p_buffer->buffer.p_payload = NULL;
+ p_buffer->buffer.length = 0;
+ p_buffer->buffer.type = UNASSIGNED_TYPE;
+ p_buffer->allocated_length = 0;
+}
+
+
+/**@brief Get size of offset to be used based on the requested type. */
+static uint32_t type_offset_get(iot_pbuffer_type_t type)
+{
+ uint32_t offset = 0;
+
+ switch (type)
+ {
+ case RAW_PACKET_TYPE:
+ {
+ offset = 0;
+ break;
+ }
+ case IPV6_PACKET_TYPE:
+ {
+ offset = IPV6_IP_HEADER_SIZE;
+ break;
+ }
+ case ICMP6_PACKET_TYPE:
+ {
+ offset = IPV6_IP_HEADER_SIZE + ICMP6_HEADER_SIZE;
+ break;
+ }
+ case UDP6_PACKET_TYPE: // Fall through.
+ {
+ offset = IPV6_IP_HEADER_SIZE + UDP_HEADER_SIZE;
+ break;
+ }
+ case COAP_PACKET_TYPE:
+ {
+ offset = IPV6_IP_HEADER_SIZE + UDP_HEADER_SIZE + COAP_HEADER_SIZE;
+ break;
+ }
+ default:
+ {
+ // Should never happen.
+ break;
+ }
+ }
+
+ return offset;
+}
+
+
+/**@brief Allocates 'length' sized packet buffer. */
+static uint32_t pbuffer_allocate(pbuffer_t ** pp_buffer, uint32_t length, iot_pbuffer_flags_t flags)
+{
+ uint32_t index;
+ uint32_t err_code = (NRF_ERROR_NO_MEM | IOT_PBUFFER_ERR_BASE);
+
+
+ for (index = 0; index < IOT_PBUFFER_MAX_COUNT; index ++)
+ {
+ if (m_pbuffer[index].allocated_length == 0)
+ {
+ // Found a free buffer, allocate.
+ PBUFFER_TRC("Found free buffer. Requesting memory allocation.");
+
+ m_pbuffer[index].allocated_length = length;
+
+ if (flags == PBUFFER_FLAG_DEFAULT)
+ {
+ err_code = nrf_mem_reserve(&m_pbuffer[index].buffer.p_memory, &m_pbuffer[index].allocated_length);
+ if (err_code == NRF_SUCCESS)
+ {
+ PBUFFER_TRC("Allocated pbuffer at index 0x%08lX", index);
+ (*pp_buffer) = &m_pbuffer[index];
+ }
+ else
+ {
+ PBUFFER_ERR("Failed to allocate memory for packet buffer of size %ld", length);
+ m_pbuffer[index].allocated_length = 0;
+ }
+ }
+ else
+ {
+ PBUFFER_TRC("Allocated pbuffer at index 0x%08lX without any memory allocation.", index);
+ (*pp_buffer) = &m_pbuffer[index];
+ err_code = NRF_SUCCESS;
+ }
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Finds the internal buffer based on the external iot_pbuffer_t. */
+static uint32_t pbuffer_find(pbuffer_t ** p_internal_buffer, iot_pbuffer_t * p_buffer)
+{
+ const uint32_t size = sizeof (pbuffer_t);
+ const uint32_t diff = (((uint32_t)p_buffer) - ((uint32_t)m_pbuffer));
+
+ if ((diff > (size * IOT_PBUFFER_MAX_COUNT)) ||
+ ((diff % size) != 0))
+ {
+ return (NRF_ERROR_INVALID_ADDR | IOT_PBUFFER_ERR_BASE);
+ }
+
+ (*p_internal_buffer) = (pbuffer_t *) p_buffer;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t iot_pbuffer_init(void)
+{
+ uint32_t index;
+
+ PBUFFER_ENTRY();
+
+ SDK_MUTEX_INIT(m_pbuffer_mutex);
+
+ PBUFFER_MUTEX_LOCK();
+
+ for (index = 0; index < IOT_PBUFFER_MAX_COUNT; index++)
+ {
+ pbuffer_init(&m_pbuffer[index]);
+ }
+
+ m_initialization_state = true;
+
+ PBUFFER_EXIT();
+
+ PBUFFER_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t iot_pbuffer_allocate(iot_pbuffer_alloc_param_t * p_param,
+ iot_pbuffer_t ** pp_pbuffer)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_param);
+ NULL_PARAM_CHECK(pp_pbuffer);
+ VERIFY_PBUFFER_TYPE(p_param->type);
+ VERIFY_PBUFFER_FLAGS(p_param->flags);
+ VERIFY_NON_ZERO_LENGTH(p_param->length);
+
+ PBUFFER_ENTRY();
+
+ PBUFFER_MUTEX_LOCK();
+
+ uint32_t err_code;
+ uint32_t offset;
+ pbuffer_t * p_alloc_buffer;
+
+ // Get offset to be added to length.
+ offset = type_offset_get(p_param->type);
+
+ err_code = pbuffer_allocate(&p_alloc_buffer, ((p_param->length) + offset), p_param->flags);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_alloc_buffer->buffer.length = p_param->length;
+ p_alloc_buffer->buffer.type = p_param->type;
+
+ if (p_param->flags != PBUFFER_FLAG_NO_MEM_ALLOCATION)
+ {
+ p_alloc_buffer->buffer.p_payload = ((p_alloc_buffer->buffer.p_memory) + offset);
+ }
+
+ (*pp_pbuffer) = &p_alloc_buffer->buffer;
+ }
+
+ PBUFFER_MUTEX_UNLOCK();
+
+ PBUFFER_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_pbuffer_reallocate(iot_pbuffer_alloc_param_t * p_param,
+ iot_pbuffer_t * p_pbuffer)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_param);
+ NULL_PARAM_CHECK(p_pbuffer);
+ VERIFY_PBUFFER_TYPE(p_param->type);
+ VERIFY_PBUFFER_FLAGS(p_param->flags);
+ VERIFY_NON_ZERO_LENGTH(p_param->length);
+
+ PBUFFER_ENTRY();
+
+ PBUFFER_MUTEX_LOCK();
+
+ uint32_t err_code;
+ uint32_t realloc_len;
+ pbuffer_t * p_alloc_buffer;
+
+ // Ensure pointer provided is in the ranged managed by the module.
+ err_code = pbuffer_find(&p_alloc_buffer, p_pbuffer);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Get realloc_len to be added to length.
+ const uint32_t offset = type_offset_get(p_param->type);
+ realloc_len = p_param->length + offset;
+
+ // Check if requested length cannot be accommodated in the allocated buffer.
+ if (realloc_len > p_alloc_buffer->allocated_length)
+ {
+ // No, it cannot be, request a new buffer.
+ uint8_t * p_new_mem;
+
+ if (p_param->flags != PBUFFER_FLAG_NO_MEM_ALLOCATION)
+ {
+ err_code = nrf_mem_reserve(&p_new_mem, &realloc_len);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Copy data into the new buffer.
+ memcpy (p_new_mem,
+ p_pbuffer->p_memory,
+ p_alloc_buffer->allocated_length);
+
+ // Now free the old buffer. Perform the free
+ nrf_free(p_alloc_buffer->buffer.p_memory);
+
+ p_alloc_buffer->allocated_length = realloc_len;
+ p_alloc_buffer->buffer.p_memory = p_new_mem;
+ p_alloc_buffer->buffer.length = p_param->length;
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_alloc_buffer->buffer.length = p_param->length;
+ p_alloc_buffer->buffer.type = p_param->type;
+
+ if (p_param->flags == PBUFFER_FLAG_DEFAULT)
+ {
+ p_alloc_buffer->buffer.p_payload = (p_alloc_buffer->buffer.p_memory + offset);
+ }
+ }
+ }
+ else
+ {
+ PBUFFER_ERR("Cannot find buffer to be freed.");
+ }
+
+ PBUFFER_MUTEX_UNLOCK();
+
+ PBUFFER_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t iot_pbuffer_free(iot_pbuffer_t * p_pbuffer, bool free_flag)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_pbuffer);
+
+ PBUFFER_ENTRY();
+
+ PBUFFER_MUTEX_LOCK();
+
+ uint32_t err_code;
+ pbuffer_t * p_alloc_buffer;
+
+ // Ensure pointer provided is in the ranged managed by the module.
+ err_code = pbuffer_find(&p_alloc_buffer, p_pbuffer);
+ if (err_code == NRF_SUCCESS)
+ {
+ if (free_flag == true)
+ {
+ nrf_free(p_alloc_buffer->buffer.p_memory);
+ }
+ pbuffer_init(p_alloc_buffer);
+ }
+ else
+ {
+ PBUFFER_ERR("Cannot find buffer to be freed.");
+ }
+
+ PBUFFER_MUTEX_UNLOCK();
+
+ PBUFFER_EXIT();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.h
new file mode 100644
index 0000000..e13da3a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/pbuffer/iot_pbuffer.h
@@ -0,0 +1,175 @@
+/**
+ * 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup iot_pbuffer Packet Buffer
+ * @{
+ * @ingroup iot_sdk_stack
+ * @brief Packet buffer management for IPv6 stack layers to minimize data copy across stack layers.
+ *
+ * @details This module interfaces with the Memory Manager to allocate packet buffers
+ * for the IPv6 stack layers, without each layer having to ensure
+ * sufficient header space for layers below.
+ */
+#ifndef IOT_PBUFFER__
+#define IOT_PBUFFER__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief IPv6 packet type identifiers that are needed to ensure that enough
+ * space is reserved for headers from layers below during memory allocation.
+ */
+typedef enum
+{
+ UNASSIGNED_TYPE = 0, /**< Indicates that the packet buffer is unassigned and not in use. */
+ RAW_PACKET_TYPE = 1, /**< Raw packet, with no room made for headers of any lower layer. */
+ IPV6_PACKET_TYPE = 2, /**< Indicates that the packet buffer is requested for an entire IPv6 packet; pbuffer provisions 40 bytes of IPv6 header. */
+ ICMP6_PACKET_TYPE = 3, /**< Indicates that the packet buffer is requested for an ICMPv6 packet, and provision for 40 bytes of IPv6 header is made by pbuffer. */
+ UDP6_PACKET_TYPE = 4, /**< Indicates that the packet buffer is requested for a UDP packet, and provision for 40 bytes of IPv6 header and UDP header is made by pbuffer. */
+ COAP_PACKET_TYPE = 5 /**< Indicates that the packet buffer is requested for a CoAP packet, and provision for 4 bytes of CoAP header, 8 bytes of UDP header, and 40 bytes of IPv6 header is made. */
+}iot_pbuffer_type_t;
+
+/**@brief Additional information that must be provided to the module during allocation
+ * or reallocation to ensure optimal utilization of memory and avoid unnecessary data
+ * copies.
+ */
+typedef enum
+{
+ PBUFFER_FLAG_DEFAULT = 0, /**< Default behavior with respect to memory allocation when allocating packet buffer. Memory will be allocated for the length indicated by this default.*/
+ PBUFFER_FLAG_NO_MEM_ALLOCATION = 1, /**< Only allocate packet buffer, not memory. This is needed when a packet already exists and the packet buffer is needed only to feed it to the IPv6 stack.*/
+}iot_pbuffer_flags_t;
+
+/**@brief Packet buffer used for exchanging IPv6 payload across layers in both receive and transmit
+ * paths.
+ */
+typedef struct
+{
+ iot_pbuffer_type_t type; /**< Determines if any offset for lower layers must be provisioned for in the stack. */
+ uint8_t * p_memory; /**< Pointer to actual memory allocated for the buffer. */
+ uint8_t * p_payload; /**< Pointer to memory where the payload for the layer that allocates the packet buffer should be contained. */
+ uint32_t length; /**< Length of the payload of the layer processing it. This value can be modified by each layer of the IPv6 stack based on the required header information added by each.*/
+}iot_pbuffer_t;
+
+
+/**@brief Parameters required to allocate the packet buffer. */
+typedef struct
+{
+ iot_pbuffer_type_t type; /**< Payload type for which the packet buffer is requested to be allocated or reallocated. */
+ iot_pbuffer_flags_t flags; /**< Flags that indicate if memory allocation is needed or not. */
+ uint32_t length; /**< Length of payload for which the packet buffer is requested. */
+}iot_pbuffer_alloc_param_t;
+
+
+/**@brief Function for initializing the module.
+ *
+ * @retval NRF_SUCCESS If the module was successfully initialized. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_pbuffer_init(void);
+
+
+/**@brief Function for allocating a packet buffer.
+ *
+ * @param[in] p_param Pointer to allocation parameters that indicate the length of the payload requested,
+ * the type of payload, and additional information using the flags. This
+ * parameter cannot be NULL.
+ * @param[out] pp_pbuffer Pointer to allocated packet buffer. This parameter shall
+ * not be NULL.
+ *
+ * @retval NRF_SUCCESS If the packet buffer was successfully allocated. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_pbuffer_allocate(iot_pbuffer_alloc_param_t * p_param,
+ iot_pbuffer_t ** pp_pbuffer);
+
+
+/**@brief Function for reallocating a packet buffer.
+ *
+ * Reallocation requests are treated as follows:
+ * - If the requested reallocation is less than or equal to the allocated size,
+ * no data is moved, and the function returns NRF_SUCCESS.
+ * - If the requested reallocation is more than what is allocated, the function
+ * requests new memory, backs up existing data, and then frees the previously
+ * allocated memory.
+ * - If reallocation is requested with the PBUFFER_FLAG_NO_MEM_ALLOCATION flag,
+ * the function does not free previously allocated memory or copy it to the
+ * new location. In this case, the application that uses the pbuffer must
+ * decide when to move previously allocated memory and when to free it and
+ * handle this.
+ *
+ * @param[in] p_param Pointer to reallocation parameters that indicate the length of the payload requested,
+ * the type of payload, and additional information using the flags. This
+ * parameter cannot be NULL.
+ * @param[in] p_pbuffer Pointer to the packet buffer being reallocated. This parameter shall
+ * not be NULL.
+ *
+ * @retval NRF_SUCCESS If the packet buffer was successfully reallocated. Otherwise, an error code that indicates the reason for the failure is returned.
+ */
+uint32_t iot_pbuffer_reallocate(iot_pbuffer_alloc_param_t * p_param,
+ iot_pbuffer_t * p_pbuffer);
+
+
+/**@brief Function for freeing a packet buffer.
+ *
+ * This function frees the packet buffer. If the parameter free_flag is set, the
+ * function tries to free the memory allocated as well. This action is performed
+ * irrespective of whether the memory was allocated using the PBUFFER_FLAG_DEFAULT or
+ * the PBUFFER_FLAG_NO_MEM_ALLOCATION flag.
+ *
+ * @param[in] p_pbuffer Pointer to the packet buffer requested to be freed. This parameter shall
+ * not be NULL.
+ * @param[in] free_flag Indicates if the allocated memory should be freed or not when freeing the
+ * packet buffer.
+ *
+ * @retval NRF_SUCCESS If the packet buffer was successfully freed. Otherwise, an error code that indicates the reason for the failure is returned.
+ *
+ */
+uint32_t iot_pbuffer_free(iot_pbuffer_t * p_pbuffer, bool free_flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_PBUFFER__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.c
new file mode 100644
index 0000000..2b79462
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.c
@@ -0,0 +1,607 @@
+/**
+ * Copyright (c) 2015 - 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 "udp_api.h"
+#include "ipv6_api.h"
+#include "app_error.h"
+#include "sdk_common.h"
+#include "sntp_client.h"
+
+#if SNTP_CLIENT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME sntp
+
+#define NRF_LOG_LEVEL SNTP_CLIENT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR SNTP_CLIENT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR SNTP_CLIENT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define SNTP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define SNTP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define SNTP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define SNTP_ENTRY() SNTP_TRC(">> %s", __func__)
+#define SNTP_EXIT() SNTP_TRC("<< %s", __func__)
+
+#else // SNTP_CLIENT_CONFIG_LOG_ENABLED
+
+#define SNTP_TRC(...) /**< Disables traces. */
+#define SNTP_DUMP(...) /**< Disables dumping of octet streams. */
+#define SNTP_ERR(...) /**< Disables error logs. */
+
+#define SNTP_ENTRY(...)
+#define SNTP_EXIT(...)
+
+#endif // SNTP_CLIENT_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.
+ * SNTP_CLIENT_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
+ *
+ * @{
+ */
+#if (SNTP_CLIENT_DISABLE_API_PARAM_CHECK == 0)
+
+/**
+ * @brief Verify NULL parameters are not passed to an API by application.
+ */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_NTP_ERR_BASE); \
+ }
+
+/**
+ * @brief Verify that not zero is passed to an API by application.
+ */
+#define ZERO_PARAM_CHECK(PARAM) \
+ if ((PARAM) == 0x00) \
+ { \
+ return (NRF_ERROR_NULL | IOT_NTP_ERR_BASE); \
+ }
+
+/**
+ * @brief Macro to check if module is initialized.
+ */
+#define VERIFY_MODULE_IS_INITIALIZED() \
+ if (m_sntp_client_state == SNTP_CLIENT_STATE_UNINITIALIZED) \
+ { \
+ return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_NTP_ERR_BASE); \
+ }
+
+#else // SNTP_CLIENT_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+#define ZERO_PARAM_CHECK(PARAM)
+#define VERIFY_MODULE_IS_INITIALIZED()
+
+#endif //SNTP_CLIENT_DISABLE_API_PARAM_CHECK
+/** @} */
+
+/**
+ * @defgroup ble_sntp_c_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 SNTP_C_MUTEX_LOCK() SDK_MUTEX_LOCK(m_sntp_c_mutex) /**< Lock module using mutex */
+#define SNTP_C_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_sntp_c_mutex) /**< Unlock module using mutex */
+/** @} */
+
+#define TIME_AT_1970 2208988800UL // Number of seconds between 1st Jan 1900 and 1st Jan 1970, for NTP<->Unix time conversion.
+#define PROTOCOL_MODE_SERVER 4
+
+/**@brief NTP Header Format. */
+typedef struct
+{
+ uint8_t flags; /**< Please see RFC 4330. */
+ uint8_t stratum; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint8_t poll_interval; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint8_t precision; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t root_delay; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t root_dispersion; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t reference_id; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t reference_timestamp[2]; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t originate_timestamp[2]; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t receive_timestamp[2]; /**< Please see RFC 4330. This field is significant only in SNTP server messages. */
+ uint32_t transmit_timestamp[2]; /**< Please see RFC 4330. */
+} ntp_header_t;
+
+typedef enum
+{
+ SNTP_CLIENT_STATE_UNINITIALIZED = 1,
+ SNTP_CLIENT_STATE_IDLE,
+ SNTP_CLIENT_STATE_BUSY
+} sntp_client_state_t;
+
+typedef struct
+{
+ time_t unix_time;
+ iot_timer_time_in_ms_t wall_clock_value;
+} local_timestamp_t;
+
+SDK_MUTEX_DEFINE(m_sntp_c_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+static sntp_client_state_t m_sntp_client_state = SNTP_CLIENT_STATE_UNINITIALIZED;
+static ipv6_addr_t * m_p_ntp_server_address;
+static uint16_t m_ntp_server_port;
+static bool m_do_sync_local_time;
+static iot_timer_time_in_ms_t m_time_of_last_transmission;
+static uint8_t m_retransmission_count;
+static sntp_evt_handler_t m_app_evt_handler;
+static udp6_socket_t m_udp_socket;
+static local_timestamp_t m_local_time;
+
+/**@brief Function for checking if a received NTP packet is valid.
+ *
+ * @param[in] p_ntp_response Pointer to the NTP packet header.
+ *
+ */
+static bool is_response_valid(ntp_header_t * p_ntp_response)
+{
+ if (((p_ntp_response->transmit_timestamp[0] == 0x00) && \
+ (p_ntp_response->transmit_timestamp[1] == 0x00)) || \
+ ((p_ntp_response->flags & 0x38) == 0x00) || \
+ ((p_ntp_response->flags & 0x07) != PROTOCOL_MODE_SERVER))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+/**@brief 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] p_rx_packet 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)
+{
+ SNTP_C_MUTEX_LOCK();
+
+ SNTP_ENTRY();
+
+ uint32_t err_code = NRF_SUCCESS;
+ ntp_header_t * p_ntp_header = (ntp_header_t *)p_rx_packet->p_payload;
+
+ if (m_sntp_client_state != SNTP_CLIENT_STATE_BUSY)
+ {
+ SNTP_ERR("Unexpected NTP response received.");
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ SNTP_EXIT();
+ return (NRF_ERROR_INVALID_STATE | IOT_NTP_ERR_BASE);
+ }
+ else
+ {
+ // Check UDP process result and data length.
+ if ((process_result != NRF_SUCCESS) || p_rx_packet->length < sizeof(ntp_header_t))
+ {
+ SNTP_ERR("Received erroneous NTP response.");
+
+ m_sntp_client_state = SNTP_CLIENT_STATE_IDLE;
+ m_retransmission_count = 0;
+ m_do_sync_local_time = false;
+ err_code = (NRF_ERROR_INVALID_DATA | IOT_NTP_ERR_BASE);
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ if (m_app_evt_handler != NULL)
+ {
+ m_app_evt_handler(&(p_ip_header->srcaddr), p_udp_header->srcport, err_code, \
+ (sntp_client_cb_param_t){ .callback_data = 0x00 });
+ }
+
+ SNTP_EXIT();
+ return err_code;
+ }
+ else
+ {
+ if (!is_response_valid(p_ntp_header))
+ {
+ SNTP_ERR("Received bad NTP response.");
+
+ m_sntp_client_state = SNTP_CLIENT_STATE_IDLE;
+ m_retransmission_count = 0;
+ m_do_sync_local_time = false;
+ err_code = NTP_SERVER_BAD_RESPONSE;
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ if (m_app_evt_handler != NULL)
+ {
+ m_app_evt_handler(&(p_ip_header->srcaddr), \
+ p_udp_header->srcport, \
+ err_code, \
+ (sntp_client_cb_param_t){ .callback_data = 0x00 });
+ }
+
+ SNTP_EXIT();
+ return err_code;
+ }
+ else
+ {
+ // Check if Kiss-o'-Death packet.
+ if (p_ntp_header->stratum == 0x00)
+ {
+ SNTP_TRC("Received Kiss-o'-Death packet.");
+
+ m_sntp_client_state = SNTP_CLIENT_STATE_IDLE;
+ m_retransmission_count = 0;
+ m_do_sync_local_time = false;
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ if (m_app_evt_handler != NULL)
+ {
+ m_app_evt_handler(&(p_ip_header->srcaddr), p_udp_header->srcport, \
+ NTP_SERVER_KOD_PACKET_RECEIVED, \
+ (sntp_client_cb_param_t){ .callback_data \
+ = p_ntp_header->reference_id });
+ }
+
+ SNTP_EXIT();
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ // Process decent NTP response.
+ time_t time_from_response = (HTONL(p_ntp_header->transmit_timestamp[0])) - \
+ TIME_AT_1970;
+
+ if (m_do_sync_local_time)
+ {
+ iot_timer_time_in_ms_t wall_clock_value;
+ UNUSED_VARIABLE(iot_timer_wall_clock_get(&wall_clock_value));
+ m_local_time.unix_time = time_from_response;
+ m_local_time.wall_clock_value = wall_clock_value;
+ m_do_sync_local_time = false;
+ }
+
+ m_sntp_client_state = SNTP_CLIENT_STATE_IDLE;
+ m_retransmission_count = 0;
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ if (m_app_evt_handler != NULL)
+ {
+ m_app_evt_handler(&(p_ip_header->srcaddr), \
+ p_udp_header->srcport, \
+ NRF_SUCCESS, \
+ (sntp_client_cb_param_t){ .time_from_server = \
+ time_from_response });
+ }
+
+ SNTP_EXIT();
+ return NRF_SUCCESS;
+ }
+ }
+ }
+ }
+}
+
+
+uint32_t sntp_client_init(const sntp_client_init_param_t * p_sntp_client_init_param)
+{
+ NULL_PARAM_CHECK(p_sntp_client_init_param);
+ ZERO_PARAM_CHECK(p_sntp_client_init_param->local_udp_port);
+
+ SNTP_ENTRY();
+
+ SDK_MUTEX_INIT(m_sntp_c_mutex);
+ SNTP_C_MUTEX_LOCK();
+
+ uint32_t err_code;
+
+ memset(&m_local_time, 0x00, sizeof(m_local_time));
+ m_app_evt_handler = p_sntp_client_init_param->app_evt_handler;
+
+ //Request new socket creation.
+ err_code = udp6_socket_allocate(&m_udp_socket);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Bind the socket to the local port.
+ err_code = udp6_socket_bind(&m_udp_socket, \
+ IPV6_ADDR_ANY, \
+ p_sntp_client_init_param->local_udp_port);
+ if (err_code == NRF_SUCCESS)
+ {
+ //Register data receive callback.
+ err_code = udp6_socket_recv(&m_udp_socket, port_data_callback);
+ }
+ if (err_code != NRF_SUCCESS)
+ {
+ //Not all procedures succeeded with allocated socket, hence free it.
+ UNUSED_VARIABLE(udp6_socket_free(&m_udp_socket));
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_sntp_client_state = SNTP_CLIENT_STATE_IDLE;
+ }
+
+ SNTP_EXIT();
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+static uint32_t local_time_get(time_t * p_local_time)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ iot_timer_time_in_ms_t delta_ms;
+ err_code = iot_timer_wall_clock_delta_get(&m_local_time.wall_clock_value, &delta_ms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ *p_local_time = m_local_time.unix_time + (delta_ms / 1000);
+
+ return err_code;
+}
+
+
+uint32_t sntp_client_local_time_get(time_t * p_current_time)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_current_time);
+
+ uint32_t err_code = NRF_SUCCESS;
+
+ SNTP_ENTRY();
+
+ SNTP_C_MUTEX_LOCK();
+
+ err_code = local_time_get(p_current_time);
+
+ SNTP_EXIT();
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+/**@brief Function for sending SNTP query.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, otherwise an error code indicating reason
+ * for failure.
+ */
+static uint32_t sntp_query_send()
+{
+ uint32_t err_code;
+ iot_pbuffer_t * p_buffer;
+ iot_pbuffer_alloc_param_t buffer_param;
+ time_t current_local_time;
+
+ err_code = local_time_get(&current_local_time);
+ if (err_code != NRF_SUCCESS)
+ {
+ SNTP_ERR("An error occurred while getting local time value!");
+ return err_code;
+ }
+
+ buffer_param.type = UDP6_PACKET_TYPE;
+ buffer_param.flags = PBUFFER_FLAG_DEFAULT;
+ buffer_param.length = sizeof(ntp_header_t);
+
+ UNUSED_VARIABLE(iot_timer_wall_clock_get(&m_time_of_last_transmission));
+
+ // Allocate packet buffer.
+ err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ntp_header_t * p_ntp_header = (ntp_header_t *)p_buffer->p_payload;
+ memset(p_ntp_header, 0x00, sizeof(ntp_header_t));
+
+ // Fill NTP header fields.
+ p_ntp_header->flags = 0x1B; // LI = 0; VN = 3; Mode = 3
+ p_ntp_header->transmit_timestamp[0] = HTONL((uint32_t)(current_local_time + TIME_AT_1970));
+
+ // Send NTP query using UDP socket.
+ err_code = udp6_socket_sendto(&m_udp_socket, \
+ m_p_ntp_server_address, \
+ m_ntp_server_port, \
+ p_buffer);
+ if (err_code != NRF_SUCCESS)
+ {
+ SNTP_ERR("Unable to send query on UDP socket. Reason %08lx.", err_code);
+
+ // Free the allocated buffer as send procedure has failed.
+ UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true));
+ }
+ }
+ else
+ {
+ SNTP_ERR("No memory to allocate packet buffer.");
+ }
+
+ return err_code;
+}
+
+
+uint32_t sntp_client_server_query(ipv6_addr_t * p_ntp_server_address, \
+ uint16_t ntp_server_udp_port, \
+ bool sync_local_time)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_ntp_server_address);
+ ZERO_PARAM_CHECK(ntp_server_udp_port);
+
+ uint32_t err_code = NRF_SUCCESS;
+ SNTP_ENTRY();
+
+ SNTP_C_MUTEX_LOCK();
+
+ if (m_sntp_client_state != SNTP_CLIENT_STATE_IDLE)
+ {
+ SNTP_EXIT();
+ return (NRF_ERROR_BUSY | IOT_NTP_ERR_BASE);
+ }
+
+ m_p_ntp_server_address = p_ntp_server_address;
+ m_ntp_server_port = ntp_server_udp_port;
+ m_do_sync_local_time = sync_local_time;
+
+ err_code = sntp_query_send();
+ if (err_code == NRF_SUCCESS)
+ {
+ m_sntp_client_state = SNTP_CLIENT_STATE_BUSY;
+ }
+
+ SNTP_EXIT();
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+/**@brief Function for determining whether it is time to retransmit a query.
+ *
+ */
+static bool is_it_time_to_retransmit()
+{
+ uint32_t err_code = NRF_SUCCESS;
+ iot_timer_time_in_ms_t delta_ms = 0;
+
+ err_code = iot_timer_wall_clock_delta_get(&m_time_of_last_transmission, &delta_ms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return true;
+ }
+ if (delta_ms >= (SNTP_RETRANSMISSION_INTERVAL * 1000))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void sntp_client_timeout_process(iot_timer_time_in_ms_t wall_clock_value)
+{
+ SNTP_C_MUTEX_LOCK();
+
+ UNUSED_PARAMETER(wall_clock_value);
+
+ if (m_sntp_client_state == SNTP_CLIENT_STATE_BUSY)
+ {
+ if (is_it_time_to_retransmit())
+ {
+ m_retransmission_count++;
+ if (m_retransmission_count > SNTP_MAX_RETRANSMISSION_COUNT)
+ {
+ m_sntp_client_state = SNTP_CLIENT_STATE_IDLE;
+ m_retransmission_count = 0;
+ m_do_sync_local_time = false;
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ if (m_app_evt_handler != NULL)
+ {
+ m_app_evt_handler(m_p_ntp_server_address, \
+ m_ntp_server_port, \
+ NTP_SERVER_UNREACHABLE, \
+ (sntp_client_cb_param_t){ .callback_data = 0x00 });
+ }
+
+ SNTP_TRC("NTP server did not respond to query.");
+ return;
+ }
+ else
+ {
+ SNTP_TRC("Query retransmission [%d].", m_retransmission_count);
+ UNUSED_VARIABLE(sntp_query_send());
+ }
+ }
+ }
+
+ SNTP_C_MUTEX_UNLOCK();
+ return;
+}
+
+
+uint32_t sntp_client_uninitialize()
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ SNTP_ENTRY();
+
+ SNTP_C_MUTEX_LOCK();
+
+ // Free UDP socket.
+ UNUSED_VARIABLE(udp6_socket_free(&m_udp_socket));
+
+ m_sntp_client_state = SNTP_CLIENT_STATE_UNINITIALIZED;
+ m_retransmission_count = 0;
+ m_do_sync_local_time = false;
+
+ SNTP_EXIT();
+
+ SNTP_C_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.h
new file mode 100644
index 0000000..d9cb7eb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client/sntp_client.h
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup sntp_client SNTP Client
+ * @{
+ * @ingroup iot_sdk_stack
+ * @brief Simple Network Time Protocol (SNTP) client for obtaining and storing local unix time.
+ *
+ * @details Concurrent queries are not supported. Exponential-backoff algorithm for
+ * retransmissions is not implemented, retransmissions are triggered at regular intervals.
+ *
+ */
+
+#ifndef SNTP_CLIENT_H__
+#define SNTP_CLIENT_H__
+
+#include <stdint.h>
+/*lint -save -e43 -e1504 */
+#include <time.h>
+/*lint -restore */
+#include "sdk_config.h"
+#include "nrf_error.h"
+#include "ipv6_api.h"
+#include "iot_timer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define KISS_CODE_LEN 4 /**< Kiss-o'-Death packets convey kiss codes as 4 character long @c ASCII messages. */
+
+/**@brief SNTP client callback parameter.
+ */
+typedef union
+{
+ time_t time_from_server; /**< Unix time if a proper proper response is received from an NTP server. */
+ uint32_t callback_data; /**< Data pertaining to the event triggering the callback. The kiss code from any Kiss-o'-Death packets. */
+} sntp_client_cb_param_t;
+
+/**@brief SNTP client callback type.
+ *
+ * @details Execution of the callback function marks the completion of an SNTP query.
+ * The callback will be executed if a response is received from the NTP server,
+ * or if the server remains unresponsive even after @ref SNTP_MAX_RETRANSMISSION_COUNT
+ * is reached.
+ *
+ * @param[in] p_ntp_srv_addr Pointer to the source IPv6 address of the NTP response, or to
+ * the IPv6 address of the NTP server targeted by the unsuccessful
+ * query.
+ * @param[in] ntp_srv_udp_port The source UDP port of the NTP response, or the UDP port of
+ * the NTP server targeted by the unsuccessful query.
+ * @param[in] process_result The value of this parameter reveals whether a response from the
+ * NTP server or a timeout triggered the callback.
+ * @param[in] callback_parameter This parameter holds the unix time from the server after a
+ * successful query, or the kiss code if a Kiss-o'-Death packet
+ * was received. Otherwise NULL.
+ *
+ * @retval None.
+ *
+ */
+typedef void (*sntp_evt_handler_t)(const ipv6_addr_t * p_ntp_srv_addr, \
+ uint16_t ntp_srv_udp_port, \
+ uint32_t process_result, \
+ sntp_client_cb_param_t callback_parameter);
+
+/**@brief SNTP client initialization structure.
+ *
+ * @note @ref app_evt_handler can be set to zero to disable callbacks.
+ */
+typedef struct
+{
+ sntp_evt_handler_t app_evt_handler; /**< Pointer to the event handler callback function. Triggered by a response from an NTP server to an SNTP query, or a retransmission timeout after @ref SNTP_MAX_RETRANSMISSION_COUNT is reached. */
+ uint16_t local_udp_port; /**< Local port used by the UDP socket allocated for the SNTP client module. Cannot be NULL. */
+} sntp_client_init_param_t;
+
+/**
+ * @brief Function for initializing the SNTP client module.
+ *
+ * @details The SNTP client uses UDP as transport layer, therefore, one UDP socket is allocated
+ * for the module and is used to transmit any future queries.
+ *
+ * @param[in] p_sntp_client_init_param Pointer to the initialization structure for the SNTP client.
+ * Should not be NULL.
+ *
+ * @note The event handler in the initialization structure can be set to NULL to disable callbacks
+ * from the module.
+ *
+ * @retval NRF_SUCCESS Module successfully initialized.
+ * @retval NRF_ERROR_NULL If @b p_sntp_client_init_param is NULL, or if it points to a local UDP
+ * port that is NULL.
+ *
+ */
+uint32_t sntp_client_init(const sntp_client_init_param_t * p_sntp_client_init_param);
+
+/**
+ * @brief Function for uninitializing the SNTP client module.
+ *
+ * @details This procedure frees up the UDP socket previously allocated to the module.
+ * Any pending retransmissions are cleared and no more callbacks will be executed.
+ *
+ * @retval NRF_SUCCESS Module successfully uninitialized.
+ * @retval SDK_ERR_MODULE_NOT_INITIALIZED The module was not initialized.
+ *
+ */
+uint32_t sntp_client_uninitialize(void);
+
+/**@brief Function for sending an SNTP query to the specified NTP server.
+ *
+ * @details The local unix time is set to zero (1-Jan-70) when the module is initialized. It can
+ * be updated by using the @ref sntp_client_server_query procedure. The accuracy of the
+ * output is depending on the wall clock of the IoT Timer module.
+ *
+ * @param[in] p_ntp_server_address Pointer to the IPv6 address of the NTP server. This memory must
+ * be resident until the query is completed.
+ * @param[in] ntp_server_udp_port Destination port of the NTP server. The UDP port number
+ * assigned by the IANA to NTP is 123.
+ * @param[in] sync_local_time A boolean value telling the module whether to synchronize its
+ * local clock with any response received from the NTP server.
+ *
+ * @retval NRF_SUCCESS SNTP query successfully sent.
+ * @retval SDK_ERR_MODULE_NOT_INITIALIZED The module was not initialized.
+ * @retval NRF_ERROR_NULL If @b p_ntp_server_address or @b ntp_server_udp_port
+ * is a NULL pointer.
+ *
+ */
+uint32_t sntp_client_server_query(ipv6_addr_t * p_ntp_server_address, \
+ uint16_t ntp_server_udp_port, \
+ bool sync_local_time);
+
+/**@brief Function for getting the local unix time from the module.
+ *
+ * @details The local unix time is set to zero (1-Jan-70) when the module is initialized. It can
+ * be updated by using @ref sntp_client_server_query procedure. The accuracy of the
+ * output is depending on the wall clock of the IoT Timer module.
+ *
+ * @param[out] p_current_time Local unix time.
+ *
+ * @retval NRF_SUCCESS Getting locally stored unix time successful.
+ * @retval SDK_ERR_MODULE_NOT_INITIALIZED The module was not initialized.
+ * @retval NRF_ERROR_NULL If @b p_current_time is a NULL pointer.
+ *
+ */
+uint32_t sntp_client_local_time_get(time_t * p_current_time);
+
+/**@brief Function for performing retransmissions of SNTP queries.
+ *
+ * @details The SNTP client module implements the retransmission mechanism by invoking this
+ * function periodically. This procedure is to be added to the IoT Timer client list
+ * and has to be called repeatedly with a minimum period of SNTP_RETRANSMISSION_INTERVAL.
+ *
+ * @param[in] wall_clock_value The value of the wall clock that triggered the callback.
+ *
+ * @retval None.
+ *
+ */
+void sntp_client_timeout_process(iot_timer_time_in_ms_t wall_clock_value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SNTP_CLIENT_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.c
new file mode 100644
index 0000000..65f0ec1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.c
@@ -0,0 +1,2455 @@
+/**
+ * Copyright (c) 2015 - 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 "sdk_config.h"
+#include "iot_tftp.h"
+#include "iot_common.h"
+#include "udp_api.h"
+#include "app_util.h"
+
+#if TFTP_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME tftp
+
+#define NRF_LOG_LEVEL TFTP_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR TFTP_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR TFTP_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define TFTP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define TFTP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define TFTP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define TFTP_ENTRY() TFTP_TRC(">> %s", __func__)
+#define TFTP_EXIT() TFTP_TRC("<< %s", __func__)
+
+#else // TFTP_CONFIG_LOG_ENABLED
+
+#define TFTP_TRC(...) /**< Disables traces. */
+#define TFTP_DUMP(...) /**< Disables dumping of octet streams. */
+#define TFTP_ERR(...) /**< Disables error logs. */
+
+#define TFTP_ENTRY(...)
+#define TFTP_EXIT(...)
+
+#endif // TFTP_CONFIG_LOG_ENABLED
+/**
+ * @defgroup tftp_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 TFTP_MUTEX_LOCK() SDK_MUTEX_LOCK(m_tftp_mutex) /**< Lock module using mutex. */
+#define TFTP_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_tftp_mutex) /**< Unlock module using mutex. */
+/** @} */
+
+#define TFTP_HEADER_SIZE 2 /**< uint16_t opcode number. */
+#define TFTP_BLOCK_ID_SIZE 2 /**< uint16_t block id number. */
+#define TFTP_ERR_CODE_SIZE 2 /**< uint16_t error code. */
+#define TFTP_DEFAULT_BLOCK_SIZE 512 /**< uint16_t default data block size. */
+#define TFTP_DEFAULT_PORT 69 /**< uint16_t default TFTP server port number. */
+
+/**@brief Supported TFTP options. */
+#define OPTION_MODE_ASCII "netascii" /**< NETASCII mode string defined inside RFC1350. */
+#define OPTION_MODE_OCTET "octet" /**< OCTET mode string defined inside RFC1350. */
+#define OPTION_BLKSIZE "blksize" /**< Block Size option string defined inside RFC2348. */
+#define OPTION_TIMEOUT "timeout" /**< Timeout option string defined inside RFC2349. */
+#define OPTION_SIZE "tsize" /**< Transfer Size option string defined inside RFC2348. */
+
+#define NEXT_RETR_MAX_LENGTH 4 /**< Maximum length of TFTP "timeout" option value. */
+#define BLKSIZE_MAX_LENGTH 10 /**< Maximum length of TFTP "blksize" option value. */
+#define FILE_SIZE_MAX_LENGTH 10 /**< Maximum length of TFTP "tsize" option value. */
+
+#define OPTION_ERROR_MESSAGE "Unsupported option(s) requested"
+#define UDP_ERROR_MSG "UDP Error!"
+#define LENGTH_ERROR_MSG "Invalid packet length!"
+#define UNINT_ERROR_MSG "Connection reset by peer"
+#define ACCESS_ERROR_MSG "Access denied (cannot read/write from file)"
+#define OPTION_SIZE_REQUEST_VALUE "0"
+
+/**@brief TFTP Error codes. */
+#define ERR_UNDEFINED 0 /**< Not defined, see error message (if any). */
+#define ERR_FILE_NOT_FOUND 1 /**< File not found. */
+#define ERR_ACCESS_ERROR 2 /**< Access violation. */
+#define ERR_STORAGE_FULL 3 /**< Disk full or allocation exceeded. */
+#define ERR_INVALID_OP 4 /**< Illegal TFTP operation. */
+#define ERR_INVALID_TID 5 /**< Unknown transfer ID. */
+#define ERR_FILE_EXISTS 6 /**< File already exists. */
+#define ERR_BAD_USER 7 /**< No such user. */
+#define ERR_OPTION_REJECT 8 /**< Reject proposed options. */
+
+/**@brief TFTP opcode's. This field specifies type of packet. */
+#define TYPE_RRQ 1 /**< Read request (RRQ). */
+#define TYPE_WRQ 2 /**< Write request (WRQ). */
+#define TYPE_DATA 3 /**< Data (DATA). */
+#define TYPE_ACK 4 /**< Acknowledgment (ACK). */
+#define TYPE_ERR 5 /**< Error (ERROR). */
+#define TYPE_OACK 6 /**< Option Acknowledgment (RRQ/WRQ ACK). */
+
+/**
+ * @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.
+ * DNS6_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+
+#if (TFTP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_TFTP_ERR_BASE); \
+ }
+
+#else // TFTP_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // DNS6_DISABLE_API_PARAM_CHECK
+
+/**@brief Check err_code, free p_buffer and return on error. */
+#define PBUFFER_FREE_IF_ERROR(err_code) \
+ if (err_code != NRF_SUCCESS) \
+ { \
+ (void)iot_pbuffer_free(p_buffer, true); \
+ return err_code; \
+ }
+
+/**@brief Convert TFTP error code into IOT error with appropriate base. */
+#define CONVERT_TO_IOT_ERROR(error_code) \
+ ((IOT_TFTP_ERR_BASE+0x0040) + NTOHS(error_code))
+
+/**@brief Convert IOT error into TFTP error code by removing TFTP error base. */
+#define CONVERT_TO_TFTP_ERROR(error_code) \
+ (HTONS(err_code - (IOT_TFTP_ERR_BASE+0x0040)))
+
+/**@brief Iterator for string list delimited with '\0'. */
+typedef struct
+{
+ char * p_start; /**< Pointer to the beginning of a string. */
+ char * p_end; /**< Pointer to the end of a string. */
+ struct curr_struct
+ {
+ char * p_key; /**< Pointer to the last, found key string. */
+ char * p_value; /**< Pointer to the last, found value string. */
+ } curr;
+} option_iter_t;
+
+/**@brief Allowed states of a single TFTP instance. */
+typedef enum
+{
+ STATE_FREE = 0, /**< Start state, after calling UDP to allocate socket. */
+ STATE_IDLE, /**< Socket is allocated, but not used. */
+ STATE_CONNECTING_RRQ, /**< RRQ packet sent. Waiting for response. */
+ STATE_CONNECTING_WRQ, /**< WRQ packet sent. Waiting for response. */
+ STATE_SENDING, /**< Sending file and receiving ACK. */
+ STATE_SEND_HOLD, /**< Sending held. Waiting for resume call. */
+ STATE_RECEIVING, /**< Receiving file and sending ACK. */
+ STATE_RECV_HOLD, /**< Receiving held. Waiting for resume call. */
+ STATE_RECV_COMPLETE /**< State after receiving last DATA, before sending last ACK packet. There won't be another UDP event to emit IOT_TFTP_EVT_TRANSFER_GET_COMPLETE event, so next resume() should emit that event. */
+} tftp_state_t;
+
+/**@brief Internal TFTP instance structure. */
+typedef struct
+{
+ iot_tftp_trans_params_t init_params; /**< Connection parameters set during initialization. */
+ iot_tftp_trans_params_t connect_params; /**< Negotiated Connection parameters. */
+ udp6_socket_t socket; /**< UDP socket assigned to single instance. */
+ tftp_state_t state; /**< Integer representing current state of an instance. */
+ iot_tftp_callback_t callback; /**< User defined callback (passed inside initial parameters structure). */
+ iot_file_t * p_file; /**< Pointer to destination/source file assigned in get/put call. */
+ const char * p_path; /**< Path of the file on the remote node. */
+ uint16_t block_id; /**< ID of last received/sent data block. */
+ uint16_t src_tid; /**< UDP port used for sending information to the server. */
+ uint16_t dst_tid; /**< UDP port on which all packets will be sent. At first - dst_port (see below), then reassigned. */
+ uint16_t dst_port; /**< UDP port on which request packets will be sent. Usually DEFAULT_PORT. */
+ const char * p_password; /**< Pointer to a constant string containing password passed inside Read/Write Requests. */
+ ipv6_addr_t addr; /**< IPv6 server address. */
+ iot_pbuffer_t * p_packet; /**< Reference to the temporary packet buffer. */
+ uint8_t retries; /**< Number of already performed retries. */
+ volatile iot_timer_time_in_ms_t request_timeout; /**< Number of milliseconds on which last request should be retransmitted. */
+} tftp_instance_t;
+
+SDK_MUTEX_DEFINE(m_tftp_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+static tftp_instance_t m_instances[TFTP_MAX_INSTANCES]; /**< Array of allowed TFTP instances. */
+
+/**@brief Function for finding free TFTP instance index.
+ *
+ * @param[out] p_index Index being found.
+ *
+ * @retval NRF_SUCCESS if passed instance was found, else NRF_ERROR_NO_MEM error code will
+ * be returned.
+ */
+static uint32_t find_free_instance(uint32_t * p_index)
+{
+ uint32_t index = 0;
+
+ for (index = 0; index < TFTP_MAX_INSTANCES; index++)
+ {
+ if (m_instances[index].state == STATE_FREE)
+ {
+ *p_index = index;
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return (NRF_ERROR_NO_MEM | IOT_TFTP_ERR_BASE);
+}
+
+/**@brief Function for resolving instance index by passed pointer.
+ *
+ * @param[in] p_tftp Pointer representing TFTP instance in user space.
+ * @param[out] p_index Index of passed TFTP instance.
+ *
+ * @retval NRF_SUCCESS if passed instance was found, else NRF_ERROR_INVALID_PARAM error code
+ * will be returned.
+ */
+static uint32_t find_instance(iot_tftp_t * p_tftp, uint32_t * p_index)
+{
+ if (*p_tftp > TFTP_MAX_INSTANCES)
+ {
+ return (NRF_ERROR_INVALID_PARAM | IOT_TFTP_ERR_BASE);
+ }
+
+ *p_index = *p_tftp;
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for notifying application of the TFTP events.
+ *
+ * @param[in] p_tftp TFTP instance.
+ * @param[in] p_evt Event description.
+ *
+ * @retval None.
+ */
+static void app_notify(iot_tftp_t * p_tftp, iot_tftp_evt_t * p_evt)
+{
+ uint32_t index;
+ uint32_t err_code;
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code != NRF_SUCCESS)
+ {
+ return;
+ }
+
+ if (m_instances[index].callback)
+ {
+ TFTP_MUTEX_UNLOCK();
+
+
+ // Call handler of user request.
+ m_instances[index].callback(p_tftp, p_evt);
+
+ TFTP_MUTEX_LOCK();
+ }
+}
+
+/**@brief Increment option iterator.
+ *
+ * @details The iterator will point to the next option or to p_end if it reaches the end.
+ *
+ * @param[in] p_iter Pointer to option iterator.
+ *
+ * @retval NRF_SUCCESS if iterator successfully moved to next option, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t op_get_next(option_iter_t * p_iter)
+{
+ uint32_t key_length;
+ uint32_t value_length;
+
+ NULL_PARAM_CHECK(p_iter->p_start);
+ NULL_PARAM_CHECK(p_iter->p_end);
+ NULL_PARAM_CHECK(p_iter->curr.p_key);
+ NULL_PARAM_CHECK(p_iter->curr.p_value);
+
+ // If reached end.
+ if ((p_iter->curr.p_value == p_iter->p_end) || (p_iter->curr.p_key == p_iter->p_end))
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_TFTP_ERR_BASE);
+ }
+
+ key_length = strlen(p_iter->curr.p_key);
+ value_length = strlen(p_iter->curr.p_value);
+
+ if ((p_iter->curr.p_value == p_iter->p_start) && (p_iter->curr.p_key == p_iter->p_start))
+ {
+ // First call. Check if [start] + [string] fits before [end] reached.
+ // This statement just checks if there is '\0' between start and end (passing single string as input).
+ if (p_iter->curr.p_key + key_length < p_iter->p_end)
+ {
+ p_iter->curr.p_value = p_iter->curr.p_key + key_length + 1;
+
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return (NRF_ERROR_DATA_SIZE | IOT_TFTP_ERR_BASE);
+ }
+ }
+ else if (p_iter->curr.p_value + value_length < p_iter->p_end)
+ {
+ p_iter->curr.p_key = p_iter->curr.p_value + value_length + 1;
+ p_iter->curr.p_value = p_iter->curr.p_key + strlen(p_iter->curr.p_key) + 1;
+
+ if ((*p_iter->curr.p_key == '\0') || (*p_iter->curr.p_value == '\0')) // If string list finishes before the end of the buffer.
+ {
+ p_iter->curr.p_key = p_iter->p_end;
+ p_iter->curr.p_value = p_iter->p_end;
+
+ return (NRF_ERROR_DATA_SIZE | IOT_TFTP_ERR_BASE);
+ }
+
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ p_iter->curr.p_key = p_iter->p_end;
+ p_iter->curr.p_value = p_iter->p_end;
+
+ return (NRF_ERROR_DATA_SIZE | IOT_TFTP_ERR_BASE);
+ }
+}
+
+/**@brief Set new (key, value) pair at the end of a string.
+ *
+ * @param[out] p_iter Pointer to iterator, which will be used to add (key, value) pair.
+ * @param[in] p_inp_key Pointer to the new key string. If p_key is NULL, then this function will insert just value.
+ * @param[in] p_inp_value Pointer to the new value string.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static __INLINE uint32_t op_set(option_iter_t * p_iter, const char * p_inp_key, const char * p_inp_value)
+{
+ char * p_last_key;
+ char * p_last_value;
+
+ NULL_PARAM_CHECK(p_iter->p_start);
+ NULL_PARAM_CHECK(p_iter->p_end);
+ NULL_PARAM_CHECK(p_iter->curr.p_key);
+ NULL_PARAM_CHECK(p_iter->curr.p_value);
+
+ p_last_key = p_iter->curr.p_key;
+ p_last_value = p_iter->curr.p_value;
+
+ // Print appropriate trace log.
+ if (p_inp_key != NULL)
+ {
+ TFTP_TRC("Set option: %s with value: %s.", p_inp_key, p_inp_value);
+ }
+ else
+ {
+ TFTP_TRC("Set value: %s.", p_inp_value);
+ }
+
+ // Set key & value pointers.
+ if ((p_iter->curr.p_key == p_iter->p_start) && (p_iter->curr.p_value == p_iter->p_start)) // Start condition.
+ {
+ if (p_inp_key != NULL)
+ {
+ p_iter->curr.p_value = p_iter->curr.p_key + strlen(p_inp_key) + 1;
+ }
+ else
+ {
+ p_iter->curr.p_value = p_iter->curr.p_key; // Insert only passed value.
+ p_iter->curr.p_key = p_iter->curr.p_value + strlen(p_iter->curr.p_value) + 1; // Just assign anything different that p_start and inside buffer.
+ }
+ }
+ else
+ {
+ p_iter->curr.p_key = p_iter->curr.p_value + strlen(p_iter->curr.p_value) + 1; // New key starts where last value ends.
+
+ if (p_inp_key != NULL)
+ {
+ p_iter->curr.p_value = p_iter->curr.p_key + strlen(p_inp_key) + 1; // If key not null - new value starts where new key ends.
+ }
+ else
+ {
+ p_iter->curr.p_value = p_iter->curr.p_key; // Otherwise - value is placed at the key position.
+ }
+ }
+
+ // Copy strings into set pointers.
+ if ((p_iter->curr.p_value + strlen(p_inp_value)) < p_iter->p_end)
+ {
+ if (p_inp_key != NULL)
+ {
+ memcpy(p_iter->curr.p_key, p_inp_key, strlen(p_inp_key) + 1);
+ }
+ memcpy(p_iter->curr.p_value, p_inp_value, strlen(p_inp_value) + 1);
+ }
+ else // If it is not possible to insert new key & value pair.
+ {
+ p_iter->curr.p_key = p_last_key;
+ p_iter->curr.p_value = p_last_value;
+
+ TFTP_ERR("Unable to set option (size error)!");
+
+ return (NRF_ERROR_DATA_SIZE | IOT_TFTP_ERR_BASE);
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Initializes new option iterator.
+ *
+ * @param[out] p_iter Pointer to iterator, which will be configured.
+ * @param[in] p_buf Pointer to the new string buffer which iterator will be modifying.
+ * @param[in] buf_len Length of passed buffer.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static __INLINE void op_init(option_iter_t * p_iter, char * p_buf, uint32_t buf_len)
+{
+ p_iter->p_start = p_buf;
+ p_iter->p_end = p_buf + buf_len;
+ p_iter->curr.p_key = p_buf;
+ p_iter->curr.p_value = p_buf;
+}
+
+/**@brief: Converts string containing unsigned number into uint32_t.
+ *
+ * @param[in] p_str Input string.
+ *
+ * @retval Integer number equal to read value. Reading process skips all non-digit characters.
+ */
+static uint32_t str_to_uint(char * p_str)
+{
+ uint32_t len;
+ uint32_t ret_val = 0;
+ uint32_t mul = 1;
+
+ if (p_str == NULL)
+ {
+ return 0;
+ }
+
+ len = strlen(p_str);
+
+ while (len)
+ {
+ len--;
+
+ if ((p_str[len] >= '0') && (p_str[len] <= '9')) // Skip unsupported characters.
+ {
+ ret_val += mul * (p_str[len] - '0');
+ mul *= 10;
+ }
+ }
+
+ return ret_val;
+}
+
+/**@brief: Converts unsigned number into string.
+ *
+ * @param[in] number Input number.
+ * @param[out] p_str Pointer to the output string.
+ * @param[in] len Length of the passed output string buffer.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t uint_to_str(uint32_t number, char * p_str, uint16_t len)
+{
+ uint32_t i = 0;
+ uint32_t temp = number;
+
+ if (len == 0)
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ // Check how many characters will be needed.
+ if (temp == 0)
+ {
+ i = 1;
+ }
+
+ while (temp)
+ {
+ i++;
+ temp /= 10;
+ }
+
+ // Set null character and check length.
+ if (i + 1 > len)
+ {
+ p_str[0] = '\0';
+
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ p_str[i] = '\0';
+
+ // Set digits.
+ while (i--)
+ {
+ p_str[i] = '0' + number % 10;
+ number /= 10;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Compare strings in a case insensitive way.
+ *
+ * @param[in] p_str1 Pointer to the first string.
+ * @param[in] p_str2 Pointer to the second String.
+ *
+ * @retval If strings are equal returns 0, otherwise number of common characters.
+ */
+static uint32_t strcmp_ci(char * p_str1, char* p_str2)
+{
+ uint32_t min_len = 0;
+ uint32_t str1_len;
+ uint32_t str2_len;
+ uint32_t i = 0;
+
+ str1_len = strlen(p_str1);
+ str2_len = strlen(p_str2);
+
+ min_len = str1_len;
+
+ if (str2_len < str1_len)
+ {
+ min_len = str2_len;
+ }
+
+ for (i = 0; i < min_len; i++)
+ {
+ char c1 = ((p_str1[i] >= 'a' && p_str1[i] <= 'z') ? p_str1[i] + 'A' - 'a' : p_str1[i]);
+ char c2 = ((p_str2[i] >= 'a' && p_str2[i] <= 'z') ? p_str2[i] + 'A' - 'a' : p_str2[i]);
+
+ if (c1 != c2)
+ {
+ return i + 1;
+ }
+ }
+
+ if (str1_len != str2_len)
+ {
+ return i + 1;
+ }
+
+ return 0;
+}
+
+/**@brief Allocates p_buffer and fills in common fields.
+ *
+ * @param[in] type First field describing packet type.
+ * @param[in] id Second field (Block ID / Error Code).
+ * @param[out] pp_buffer Sets pointer to the newly allocated buffer.
+ * @param[in] payload_len Length of payload (additional fields / data).
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t compose_packet(uint16_t type,
+ uint16_t id,
+ iot_pbuffer_t ** pp_buffer,
+ uint32_t payload_len)
+{
+ uint32_t err_code;
+ iot_pbuffer_alloc_param_t buffer_param;
+ iot_pbuffer_t * p_buffer;
+ uint32_t byte_index;
+
+ memset(&buffer_param, 0, sizeof(iot_pbuffer_alloc_param_t));
+ buffer_param.length = TFTP_HEADER_SIZE + TFTP_BLOCK_ID_SIZE + payload_len;
+ buffer_param.type = UDP6_PACKET_TYPE;
+ buffer_param.flags = PBUFFER_FLAG_DEFAULT;
+
+ err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ memset(p_buffer->p_payload, 0, buffer_param.length);
+ byte_index = 0;
+
+ // Insert type opcode.
+ byte_index += uint16_encode(HTONS(type), &p_buffer->p_payload[byte_index]);
+
+ if (type == TYPE_ERR)
+ {
+ // Insert err code.
+ byte_index += uint16_encode(CONVERT_TO_TFTP_ERROR(id), &p_buffer->p_payload[byte_index]);
+ }
+ else
+ {
+ // Insert block ID.
+ byte_index += uint16_encode(HTONS(id), &p_buffer->p_payload[byte_index]);
+ }
+
+ *pp_buffer = p_buffer;
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Reset instance request timer.
+ *
+ * @param[in] index Index of pending instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t retr_timer_reset(uint32_t index)
+{
+ uint32_t err_code;
+ iot_timer_time_in_ms_t wall_clock_value;
+
+ // Get wall clock time.
+ err_code = iot_timer_wall_clock_get(&wall_clock_value);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_instances[index].request_timeout = wall_clock_value + m_instances[index].connect_params.next_retr * 1000;
+ }
+
+ return err_code;
+}
+
+/**@brief Function for checking if retransmission time of TFTP instance request has been expired.
+ *
+ * @param[in] index Index of pending instance.
+ *
+ * @retval True if timer has been expired, False otherwise.
+ */
+static bool instance_timer_is_expired(uint32_t index)
+{
+ uint32_t err_code;
+ iot_timer_time_in_ms_t wall_clock_value;
+
+ // Get wall clock time.
+ err_code = iot_timer_wall_clock_get(&wall_clock_value);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (wall_clock_value >= m_instances[index].request_timeout)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**@brief Sets all instance values to defaults. */
+static void instance_reset(uint32_t index)
+{
+ m_instances[index].state = STATE_FREE;
+ m_instances[index].init_params.next_retr = 0;
+ m_instances[index].init_params.block_size = TFTP_DEFAULT_BLOCK_SIZE;
+ m_instances[index].connect_params.next_retr = 0;
+ m_instances[index].connect_params.block_size = TFTP_DEFAULT_BLOCK_SIZE;
+ m_instances[index].p_file = NULL;
+ m_instances[index].block_id = 0;
+ m_instances[index].p_packet = NULL;
+ m_instances[index].dst_port = TFTP_DEFAULT_PORT;
+ m_instances[index].dst_tid = TFTP_DEFAULT_PORT;
+ m_instances[index].retries = 0;
+ m_instances[index].request_timeout = 0;
+ m_instances[index].callback = NULL;
+ m_instances[index].src_tid = 0;
+ m_instances[index].p_password = NULL;
+ memset(&m_instances[index].addr, 0, sizeof(ipv6_addr_t));
+ memset(&m_instances[index].socket, 0, sizeof(udp6_socket_t));
+}
+
+/**@brief This function creates error packet for specified TFTP instance.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] p_err_evt Event data structure (message and code).
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t send_err_msg(uint32_t index, iot_tftp_evt_err_t * p_err_evt)
+{
+ iot_pbuffer_t * p_buffer;
+ uint8_t * p_resp_packet;
+ uint32_t msg_len = 0;
+ uint16_t byte_index = 0;
+ uint32_t err_code;
+
+ TFTP_TRC("Send ERROR packet.");
+
+ if (p_err_evt->p_msg != NULL)
+ {
+ msg_len = strlen(p_err_evt->p_msg) + 1;
+ }
+
+ err_code = compose_packet(TYPE_ERR, p_err_evt->code, &p_buffer, msg_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ p_resp_packet = p_buffer->p_payload;
+ byte_index = TFTP_HEADER_SIZE + TFTP_ERR_CODE_SIZE;
+
+ if (p_err_evt->p_msg != NULL)
+ {
+ memcpy(&p_resp_packet[byte_index], p_err_evt->p_msg, msg_len);
+ byte_index += msg_len;
+ }
+
+ p_buffer->length = byte_index;
+
+ TFTP_TRC("Send packet to UDP module.");
+
+ UNUSED_VARIABLE(retr_timer_reset(index));
+
+ err_code = udp6_socket_sendto(&m_instances[index].socket,
+ &m_instances[index].addr,
+ m_instances[index].dst_tid,
+ p_buffer);
+
+ TFTP_TRC("Recv code: %08lx.", err_code);
+
+ return err_code;
+}
+
+/**@brief This function creeates error packet for TID error, not being found.
+ *
+ * @param[in] p_socket Socket from which error message is sent.
+ * @param[in] p_addr IPv6 Address to where error message is sent.
+ * @param[in] tid Erronous TID from the sender.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t send_err_tid(const udp6_socket_t * p_socket, const ipv6_addr_t * p_addr, uint16_t tid)
+{
+ iot_pbuffer_t * p_buffer;
+ uint32_t msg_len = 0;
+ uint16_t byte_index = 0;
+ uint32_t err_code;
+
+ TFTP_TRC("Send TID ERROR packet.");
+
+ err_code = compose_packet(TYPE_ERR, ERR_INVALID_TID, &p_buffer, msg_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ byte_index = TFTP_HEADER_SIZE + TFTP_ERR_CODE_SIZE;
+ p_buffer->length = byte_index;
+
+ TFTP_TRC("Send packet to UDP module.");
+
+ err_code = udp6_socket_sendto(p_socket, p_addr, tid, p_buffer);
+
+ TFTP_TRC("Recv code: %08lx.", err_code);
+
+ return err_code;
+}
+
+/**@brief Sends ACK or next data chunk (block) after calling user callback or when hold timer expires.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance (from user space).
+ * @param[in] p_evt Pointer to the event structure. Used for sending error messages.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t send_response(iot_tftp_t * p_tftp)
+{
+ uint32_t index;
+ uint32_t err_code;
+
+ TFTP_TRC("Send packet.");
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Cannot find instance (send)!");
+
+ return err_code;
+ }
+
+ switch (m_instances[index].state)
+ {
+ case STATE_IDLE:
+ // Server should go to the CONNECTING state (request received).
+ TFTP_TRC("Inside IDLE state (send). ");
+ return NRF_SUCCESS;
+
+ case STATE_SENDING:
+ case STATE_RECEIVING:
+ case STATE_SEND_HOLD:
+ case STATE_RECV_HOLD:
+ case STATE_RECV_COMPLETE:
+ // Send DATA/ACK packet.
+ TFTP_TRC("Send packet to UDP module.");
+
+ UNUSED_VARIABLE(retr_timer_reset(index));
+ err_code = udp6_socket_sendto(&m_instances[index].socket,
+ &m_instances[index].addr,
+ m_instances[index].dst_tid,
+ m_instances[index].p_packet);
+ TFTP_TRC("Recv code: %08lx.", err_code);
+ return err_code;
+
+ default:
+ TFTP_ERR("Invalid state (send)!");
+ return (NRF_ERROR_INVALID_STATE | IOT_TFTP_ERR_BASE);
+ }
+}
+
+
+
+/**@brief Aborts TFTP client ongoing procedure.
+ *
+ * @param[in] index Index of TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+void instance_abort(uint32_t index)
+{
+ uint32_t internal_err;
+
+ switch (m_instances[index].state)
+ {
+ case STATE_SEND_HOLD:
+ case STATE_RECV_HOLD:
+ // Free pbuffer.
+ internal_err = iot_pbuffer_free(m_instances[index].p_packet, true);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Cannot free pbuffer - %p", m_instances[index].p_packet);
+ }
+
+ // Close file.
+ internal_err = iot_file_fclose(m_instances[index].p_file);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Cannot close file - %p", m_instances[index].p_file);
+ }
+
+ break;
+ case STATE_SENDING:
+ case STATE_RECEIVING:
+ // Close file.
+ internal_err = iot_file_fclose(m_instances[index].p_file);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Cannot close file - %p", m_instances[index].p_file);
+ }
+ break;
+ case STATE_CONNECTING_RRQ:
+ case STATE_CONNECTING_WRQ:
+ case STATE_IDLE:
+ case STATE_FREE:
+ default:
+ break;
+ }
+
+ TFTP_TRC("Reset instance %ld.", index);
+
+ m_instances[index].state = STATE_IDLE;
+ m_instances[index].block_id = 0;
+ m_instances[index].dst_tid = m_instances[index].dst_port;
+ m_instances[index].retries = 0;
+ m_instances[index].request_timeout = 0;
+ memcpy(&m_instances[index].connect_params,
+ &m_instances[index].init_params,
+ sizeof(iot_tftp_trans_params_t));
+}
+
+
+/**@brief Generates event for application.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] evt_id Id of generated event.
+ * @param[in] p_param Pointer to event parameter union.
+ */
+static void handle_evt(uint32_t index, iot_tftp_evt_id_t evt_id, iot_tftp_evt_param_t * p_param)
+{
+ uint32_t internal_err;
+ iot_tftp_evt_t evt;
+
+ memset(&evt, 0, sizeof(evt));
+ evt.id = evt_id;
+ evt.p_file = m_instances[index].p_file;
+
+ if (p_param != NULL)
+ {
+ evt.param = * p_param;
+ }
+
+ if (evt_id == IOT_TFTP_EVT_ERROR)
+ {
+ uint32_t err_code = evt.param.err.code;
+
+ TFTP_TRC("Raise an ERROR event.");
+
+ if ((err_code & IOT_TFTP_ERR_BASE) == IOT_TFTP_ERR_BASE)
+ {
+ evt.param.err.code = CONVERT_TO_TFTP_ERROR(err_code);
+
+ internal_err = send_err_msg(index, &evt.param.err);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_TRC("Cannot send error message to peer %08lx.", internal_err);
+ }
+ }
+
+ // Restore error code.
+ evt.param.err.code = err_code;
+
+ // Return to IDLE and notify.
+ instance_abort(index);
+
+ app_notify(&index, &evt);
+ }
+ else if ((evt_id == IOT_TFTP_EVT_TRANSFER_GET_COMPLETE) ||
+ (evt_id == IOT_TFTP_EVT_TRANSFER_PUT_COMPLETE))
+ {
+ TFTP_TRC("Raise TRANSFER COMPLETE event.");
+
+ if (m_instances[index].state == STATE_RECV_HOLD)
+ {
+ TFTP_TRC("Holding last ACK transfer.");
+ m_instances[index].state = STATE_RECV_COMPLETE;
+ }
+ else if (m_instances[index].state != STATE_RECV_COMPLETE)
+ {
+ // Skip into IDLE state.
+ instance_abort(index);
+
+ app_notify(&index, &evt);
+ }
+ }
+ else if (evt_id == IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED)
+ {
+ app_notify(&index, &evt);
+ }
+}
+
+/**@brief Generates error event for application.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] err_code Code of error event.
+ * @param[in] p_msg Character string containing error message.
+ */
+static void handle_evt_err(uint32_t index, uint32_t err_code, char * p_msg)
+{
+ iot_tftp_evt_param_t evt_param;
+
+ memset(&evt_param, 0, sizeof(evt_param));
+
+ evt_param.err.code = err_code;
+ evt_param.err.p_msg = p_msg;
+ evt_param.err.size_transfered = m_instances[index].block_id * m_instances[index].connect_params.block_size;
+
+ handle_evt(index, IOT_TFTP_EVT_ERROR, &evt_param);
+}
+
+/**@brief: Find instance number by Transmission ID (UDP source port).
+ *
+ * @param[in] port UDP port number on which new message was received.
+ * @param[out] p_index Index of found TFTP instance assigned to the passed UDP port.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static __INLINE uint32_t find_instance_by_tid(uint16_t port, uint32_t * p_index)
+{
+ uint32_t index;
+
+ for (index = 0; index < TFTP_MAX_INSTANCES; index++)
+ {
+ if (m_instances[index].src_tid == port)
+ {
+ break;
+ }
+ }
+
+ if (index == TFTP_MAX_INSTANCES)
+ {
+ return (NRF_ERROR_NOT_FOUND | IOT_TFTP_ERR_BASE);
+ }
+
+ *p_index = index;
+
+ return NRF_SUCCESS;
+}
+
+/**@brief: Negotiation procedure. This function skips through input option string and modifies instance parameters according to negotiated values.
+ *
+ * @param[in] p_iter Pointer to iterator configured to parse RQ/OACK packet.
+ * @param[out] p_instance Pointer to the instance, which parameters should be negotiated.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else TFTP_OPTION_REJECT error indicating
+ * that server/client requests unsupported option values.
+ */
+static uint32_t option_negotiate(option_iter_t * p_iter, tftp_instance_t * p_instance)
+{
+ uint32_t err_code;
+ bool op_size_set = false;
+ bool op_blksize_set = false;
+ bool op_time_set = false;
+
+ TFTP_TRC("Negotiate options:");
+
+ if (p_iter != NULL) // If NULL passed - reset option values to those defined by RFC.
+ {
+ UNUSED_VARIABLE(op_get_next(p_iter));
+
+ while (p_iter->curr.p_key != p_iter->p_end)
+ {
+ if (strcmp_ci(p_iter->curr.p_key, OPTION_TIMEOUT) == 0)
+ {
+ if (p_instance->init_params.next_retr != 0)
+ {
+ uint16_t server_time = str_to_uint(p_iter->curr.p_value);
+
+ if (server_time < p_instance->init_params.next_retr) // Take minimum.
+ {
+ p_instance->connect_params.next_retr = server_time;
+ }
+ else
+ {
+ p_instance->connect_params.next_retr = p_instance->init_params.next_retr;
+ }
+
+ op_time_set = true;
+
+ TFTP_TRC("TIMEOUT: %ld", p_instance->connect_params.next_retr);
+ }
+ }
+ else if (strcmp_ci(p_iter->curr.p_key, OPTION_SIZE) == 0)
+ {
+ if (p_instance->p_file != NULL)
+ {
+ uint32_t file_size = str_to_uint(p_iter->curr.p_value);
+
+ err_code = iot_file_fopen(p_instance->p_file, file_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_TRC(" TSIZE: REJECT!");
+ return TFTP_OPTION_REJECT;
+ }
+
+ op_size_set = true;
+ TFTP_TRC(" TSIZE: %ld", file_size);
+ }
+ }
+ else if (strcmp_ci(p_iter->curr.p_key, OPTION_BLKSIZE) == 0)
+ {
+ uint16_t block_size = str_to_uint(p_iter->curr.p_value);
+ op_blksize_set = true;
+
+ if (p_instance->init_params.block_size >= block_size)
+ {
+ p_instance->connect_params.block_size = block_size;
+ }
+ else
+ {
+ TFTP_TRC("BLKSIZE: REJECT!");
+ return TFTP_OPTION_REJECT;
+ }
+
+ TFTP_TRC("BLKSIZE: %d", p_instance->connect_params.block_size);
+ }
+ else if ((strlen(p_iter->curr.p_key) > 0) && (p_iter->curr.p_value == p_iter->p_end))
+ {
+ // Password option.
+ TFTP_TRC("PASSWORD FOUND: %s", p_iter->curr.p_key);
+ p_iter->curr.p_key = p_iter->p_end;
+ }
+ else
+ {
+ TFTP_TRC("UNKNOWN OPTION");
+ }
+
+ UNUSED_VARIABLE(op_get_next(p_iter));
+ }
+ }
+
+ // Set values of not negotiated options.
+ if (!op_size_set && p_instance->p_file != NULL)
+ {
+ err_code = iot_file_fopen(p_instance->p_file, 0);// Open with default file size (not known).
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_TRC("TSIZE: REJECT!");
+ return TFTP_OPTION_REJECT;
+ }
+
+ TFTP_TRC("TSIZE: %ld", p_instance->p_file->file_size);
+ }
+
+ if (!op_blksize_set)
+ {
+ if ((p_instance->init_params.block_size < TFTP_DEFAULT_BLOCK_SIZE) &&
+ (p_instance->init_params.block_size != 0))
+ {
+ TFTP_TRC("BLKSIZE: REJECT!");
+ return TFTP_OPTION_REJECT;
+ }
+ else
+ {
+ p_instance->connect_params.block_size = TFTP_DEFAULT_BLOCK_SIZE;
+ }
+
+ TFTP_TRC("BLKSIZE: %d", p_instance->connect_params.block_size);
+ }
+
+ if (!op_time_set)
+ {
+ p_instance->connect_params.next_retr = p_instance->init_params.next_retr;
+
+ TFTP_TRC("TIMEOUT: %ld", p_instance->connect_params.next_retr);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+
+/**@brief This function holds ongoing transmission of TFTP.
+ *
+ * @param[in] index Index of TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t transfer_hold(uint32_t index)
+{
+ if (m_instances[index].state == STATE_SENDING)
+ {
+ m_instances[index].state = STATE_SEND_HOLD;
+ }
+ else if (m_instances[index].state == STATE_RECEIVING)
+ {
+ m_instances[index].state = STATE_RECV_HOLD;
+ }
+ else if (m_instances[index].state == STATE_RECV_COMPLETE)
+ {
+ m_instances[index].state = STATE_RECV_COMPLETE;
+ }
+ else
+ {
+ TFTP_ERR("Hold called in invalid state.");
+
+ return (NRF_ERROR_INVALID_STATE | IOT_TFTP_ERR_BASE);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief This function resumes ongoing transmission of TFTP.
+ *
+ * @param[in] index Index of TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t transfer_resume(uint32_t index)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ if ((m_instances[index].state != STATE_SEND_HOLD) &&
+ (m_instances[index].state != STATE_RECV_HOLD) &&
+ (m_instances[index].state != STATE_RECV_COMPLETE))
+ {
+ TFTP_ERR("Failed due to invalid state.");
+ TFTP_EXIT();
+ return (NRF_ERROR_INVALID_STATE | IOT_TFTP_ERR_BASE);
+ }
+
+ err_code = send_response(&index);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to send packet after resume.");
+ }
+
+ if (m_instances[index].state == STATE_SEND_HOLD)
+ {
+ m_instances[index].state = STATE_SENDING;
+ }
+ else if (m_instances[index].state == STATE_RECV_HOLD)
+ {
+ m_instances[index].state = STATE_RECEIVING;
+ }
+ else if (m_instances[index].state == STATE_RECV_COMPLETE)
+ {
+ m_instances[index].state = STATE_RECEIVING;
+ TFTP_ERR("Complete due to STATE_RECV_COMPLETE state.");
+ handle_evt(index, IOT_TFTP_EVT_TRANSFER_GET_COMPLETE, NULL);
+ }
+
+ return err_code;
+}
+
+
+/**@brief This function creates ACK packet for specified TFTP instance.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] block_id Data block ID to be acknowledged.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t create_ack_packet(uint32_t index, uint16_t block_id)
+{
+ uint32_t err_code;
+
+ TFTP_ENTRY();
+
+ // Reuse p_packet pointer for a new (response) packet. Previous one will be automatically freed by IPv6 module.
+ err_code = compose_packet(TYPE_ACK,
+ block_id,
+ &m_instances[index].p_packet,
+ 0);
+
+ return err_code;
+}
+
+/**@brief This function creates data packet for specified TFTP instance.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] block_id Data block ID to be sent.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t create_data_packet(uint32_t index, uint16_t block_id)
+{
+ uint32_t err_code;
+ uint32_t internal_err;
+ uint32_t cursor;
+ uint32_t byte_index;
+ iot_pbuffer_t * p_buffer = NULL;
+
+ TFTP_ENTRY();
+
+ if (m_instances[index].p_file == NULL)
+ {
+ TFTP_ERR("[TFTP]: Error while sending response. Reason: Missing file to send.\r\n");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // If ACK block ID doesn't match last sent packet number.
+ if (m_instances[index].block_id != block_id)
+ {
+ // fseek on file to move to the right point. If fseek returns error - whole transmission will be dropped.
+ err_code = iot_file_fseek(m_instances[index].p_file,
+ (block_id) * m_instances[index].connect_params.block_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Unable to fseek on input data file!");
+ }
+ else
+ {
+ m_instances[index].block_id = block_id + 1;
+ }
+ }
+ else
+ {
+ m_instances[index].block_id = block_id + 1;
+ }
+
+ cursor = (m_instances[index].block_id - 1) * m_instances[index].connect_params.block_size;
+
+ // If previous DATA packet wasn't fully filled.
+ if (cursor > m_instances[index].p_file->file_size)
+ {
+ TFTP_TRC("Transfer complete. Don't send data.");
+ handle_evt(index, IOT_TFTP_EVT_TRANSFER_PUT_COMPLETE, NULL);
+ return NRF_SUCCESS;
+ }
+ else if (cursor + m_instances[index].connect_params.block_size >
+ m_instances[index].p_file->file_size) // If current sendto operation will send all remaining data.
+ {
+ TFTP_TRC("Send last data packet.");
+ err_code = compose_packet(TYPE_DATA,
+ m_instances[index].block_id,
+ &p_buffer,
+ m_instances[index].p_file->file_size - cursor);
+ }
+ else
+ {
+ TFTP_TRC("Send regular data packet.");
+ err_code = compose_packet(TYPE_DATA,
+ m_instances[index].block_id,
+ &p_buffer,
+ m_instances[index].connect_params.block_size);
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ TFTP_TRC("Created packet:");
+ TFTP_TRC("length: %ld", p_buffer->length);
+ TFTP_TRC(" type: %d", p_buffer->p_payload[0] * 256 + p_buffer->p_payload[1]);
+ TFTP_TRC(" ID: %d", p_buffer->p_payload[2] * 256 + p_buffer->p_payload[3]);
+
+ byte_index = TFTP_HEADER_SIZE + TFTP_BLOCK_ID_SIZE;
+
+ // Save reference to correctly filled packet buffer.
+ m_instances[index].p_packet = p_buffer;
+
+ if (p_buffer->length - TFTP_HEADER_SIZE - TFTP_BLOCK_ID_SIZE != 0)
+ {
+ TFTP_MUTEX_UNLOCK();
+
+ // Hold transfer.
+ internal_err = transfer_hold(index);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while holding the transfer. Reason: %08lx.", internal_err);
+ }
+
+ err_code = iot_file_fread(m_instances[index].p_file,
+ &(p_buffer->p_payload[byte_index]),
+ p_buffer->length - TFTP_HEADER_SIZE - TFTP_BLOCK_ID_SIZE);
+
+ // Unlock instance if file has not assigned callback (probably no needs more time to perform read/write).
+ if (m_instances[index].p_file->p_callback == NULL)
+ {
+ internal_err = transfer_resume(index);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while resuming the transfer. Reason: %08lx.", internal_err);
+ }
+ }
+ TFTP_MUTEX_LOCK();
+ }
+ else
+ {
+ // TFTP is going to send empty data packet, so file callback won't be called.
+ internal_err = send_response(&index);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while sending response. Reason: %08lx.", internal_err);
+ }
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to save received data (fread)!");
+ handle_evt_err(index, TFTP_ACCESS_DENIED, ACCESS_ERROR_MSG);
+ }
+
+ return err_code;
+}
+
+
+/**@brief 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] p_rx_packet 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 client_process(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;
+ iot_tftp_evt_t evt;
+ uint8_t * p_new_packet;
+ uint32_t byte_index;
+ uint32_t err_code;
+ uint32_t internal_err;
+ uint16_t packet_opcode;
+ option_iter_t oack_iter;
+ uint16_t recv_block_id;
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = find_instance_by_tid(p_udp_header->destport, &index);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Unable to find TFTP instance associated with given UDP port.");
+
+ // Send TID error to the server.
+ err_code = send_err_tid(p_socket, &p_ip_header->srcaddr, p_udp_header->destport);
+
+ TFTP_EXIT();
+ TFTP_MUTEX_UNLOCK();
+
+ return err_code;
+ }
+
+ // Check UDP status code.
+ if (process_result != NRF_SUCCESS)
+ {
+ TFTP_ERR("UDP error!");
+
+ evt.id = IOT_TFTP_EVT_ERROR;
+ evt.param.err.code = process_result;
+ evt.param.err.p_msg = UDP_ERROR_MSG;
+
+ // Call user callback (inform about error).
+ app_notify(&index, &evt);
+
+ TFTP_EXIT();
+
+ TFTP_MUTEX_UNLOCK();
+
+ return process_result;
+ }
+
+ // Check packet length.
+ if (p_rx_packet->length < TFTP_HEADER_SIZE + TFTP_BLOCK_ID_SIZE)
+ {
+ TFTP_ERR("Invalid packet length!");
+
+ evt.id = IOT_TFTP_EVT_ERROR;
+ evt.param.err.code = TFTP_INVALID_PACKET;
+ evt.param.err.p_msg = (char *)"Invalid packet length!";
+
+ app_notify(&index, &evt);
+
+ TFTP_EXIT();
+
+ TFTP_MUTEX_UNLOCK();
+
+ return evt.param.err.code;
+ }
+
+ // Read received packet type.
+ p_new_packet = p_rx_packet->p_payload;
+ packet_opcode = uint16_decode(p_new_packet);
+ packet_opcode = NTOHS(packet_opcode);
+ byte_index = TFTP_HEADER_SIZE;
+
+ if ((m_instances[index].state == STATE_SEND_HOLD) ||
+ (m_instances[index].state == STATE_RECV_HOLD) ||
+ (m_instances[index].state == STATE_IDLE))
+ {
+ TFTP_TRC("Ignore packets in HOLD/IDLE states.");
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return NRF_SUCCESS; // Ignore retransmission of other side.
+ }
+
+ switch (packet_opcode)
+ {
+ case TYPE_OACK:
+ if ((m_instances[index].state != STATE_CONNECTING_RRQ) &&
+ (m_instances[index].state != STATE_CONNECTING_WRQ) &&
+ (m_instances[index].state != STATE_IDLE && m_instances[index].retries > 0))
+ {
+ TFTP_ERR("Invalid TFTP instance state!");
+ break;
+ }
+
+ op_init(&oack_iter,
+ (char *)&p_new_packet[byte_index],
+ p_rx_packet->length - TFTP_HEADER_SIZE); // Options uses whole packet except opcode.
+
+ TFTP_TRC("Received OACK.");
+ err_code = option_negotiate(&oack_iter, &m_instances[index]);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to negotiate options!");
+ handle_evt_err(index, TFTP_OPTION_REJECT, OPTION_ERROR_MESSAGE);
+ break;
+ }
+
+ // Set server transmission id.
+ m_instances[index].dst_tid = p_udp_header->srcport;
+
+ if (m_instances[index].state == STATE_CONNECTING_RRQ)
+ {
+ m_instances[index].p_packet = p_rx_packet;
+ m_instances[index].state = STATE_RECEIVING;
+
+ err_code = create_ack_packet(index, 0);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = send_response(&index);
+ }
+ }
+ else if (m_instances[index].state == STATE_CONNECTING_WRQ)
+ {
+ m_instances[index].state = STATE_SENDING;
+
+ err_code = create_data_packet(index, 0);
+ }
+ else
+ {
+ TFTP_ERR("Incorrect state to receive OACK!");
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to create packet!");
+ handle_evt_err(index, err_code, NULL);
+ }
+ break;
+
+ case TYPE_ACK:
+ recv_block_id = uint16_decode(&p_new_packet[byte_index]);
+ recv_block_id = NTOHS(recv_block_id);
+
+ if (m_instances[index].state == STATE_CONNECTING_WRQ)
+ {
+ TFTP_TRC("Options not supported. Received ACK.");
+ err_code = option_negotiate(NULL, &m_instances[index]);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to negotiate default options!");
+ handle_evt_err(index, TFTP_OPTION_REJECT, OPTION_ERROR_MESSAGE);
+ break;
+ }
+
+ // Set server transmission id.
+ m_instances[index].dst_tid = p_udp_header->srcport;
+
+ // Set instance state.
+ m_instances[index].state = STATE_SENDING;
+ m_instances[index].block_id = 0;
+ }
+
+ if (m_instances[index].state == STATE_SENDING || m_instances[index].state == STATE_RECEIVING)
+ {
+ if (recv_block_id == m_instances[index].block_id)
+ {
+ m_instances[index].retries = 0;
+ }
+ TFTP_TRC("Received ACK. Send block %4d of %ld.", m_instances[index].block_id + 1,
+ CEIL_DIV(m_instances[index].p_file->file_size, m_instances[index].connect_params.block_size) +
+ ((m_instances[index].p_file->file_size % m_instances[index].connect_params.block_size == 0) ? 0 : 1));
+
+ err_code = create_data_packet(index, recv_block_id);
+ if ((err_code != (NRF_ERROR_DATA_SIZE | IOT_TFTP_ERR_BASE)) && (err_code != NRF_SUCCESS))
+ {
+ TFTP_ERR("Failed to create data packet.");
+ handle_evt_err(index, err_code, NULL);
+ }
+ }
+ else
+ {
+ TFTP_ERR("Invalid state to receive ACK packet.");
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return NRF_SUCCESS;
+ }
+ break;
+
+ case TYPE_DATA:
+ recv_block_id = uint16_decode(&p_new_packet[byte_index]);
+ recv_block_id = NTOHS(recv_block_id);
+ byte_index += TFTP_BLOCK_ID_SIZE;
+
+ if (m_instances[index].state == STATE_CONNECTING_RRQ)
+ {
+ TFTP_TRC("Options not supported. Received DATA.");
+ err_code = option_negotiate(NULL, &m_instances[index]);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to set default options.");
+ handle_evt_err(index, TFTP_OPTION_REJECT, OPTION_ERROR_MESSAGE);
+ break;
+ }
+
+ if (recv_block_id == 1) // Received first data block.
+ {
+ m_instances[index].block_id = 0;
+ m_instances[index].state = STATE_RECEIVING;
+ }
+
+ // Set server transmission id.
+ m_instances[index].dst_tid = p_udp_header->srcport;
+ }
+
+ if (m_instances[index].state == STATE_RECEIVING)
+ {
+ TFTP_TRC("Received DATA.");
+
+ m_instances[index].p_packet = p_rx_packet;
+
+ if (recv_block_id == m_instances[index].block_id + 1)
+ {
+ TFTP_TRC("Received next DATA (n+1).");
+
+ m_instances[index].retries = 0;
+
+ err_code = create_ack_packet(index, m_instances[index].block_id + 1);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to create ACK packet!");
+ handle_evt_err(index, err_code, NULL);
+ break;
+ }
+ }
+ else
+ {
+ TFTP_TRC("Skip current DATA packet. Try to request proper block ID by sending ACK.");
+
+ err_code = create_ack_packet(index, m_instances[index].block_id);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = send_response(&index);
+ }
+ else
+ {
+ TFTP_ERR("Failed to create ACK packet.");
+ handle_evt_err(index, err_code, NULL);
+ }
+ }
+
+ // Check if payload size is smaller than defined block size.
+ if ((p_rx_packet->length - TFTP_BLOCK_ID_SIZE - TFTP_HEADER_SIZE) <
+ m_instances[index].connect_params.block_size)
+ {
+ m_instances[index].state = STATE_RECV_COMPLETE;
+ }
+ else if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to create ACK packet.");
+ handle_evt_err(index, err_code, NULL);
+ break;
+ }
+
+ TFTP_TRC("Send block %4d of %ld ACK.", m_instances[index].block_id,
+ m_instances[index].p_file->file_size / m_instances[index].connect_params.block_size);
+
+ if (recv_block_id == m_instances[index].block_id + 1)
+ {
+ m_instances[index].block_id = recv_block_id;
+ TFTP_MUTEX_UNLOCK();
+
+ if (p_rx_packet->length - byte_index > 0)
+ {
+ iot_tftp_evt_param_t evt_param;
+ memset(&evt_param, 0, sizeof(evt_param));
+ evt_param.data_received.p_data = &p_new_packet[byte_index];
+ evt_param.data_received.size = p_rx_packet->length - byte_index;
+
+ internal_err = transfer_hold(index);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while holding the transfer. Reason: %08lx.", internal_err);
+ }
+
+ if (m_instances[index].p_file != NULL)
+ {
+ err_code = iot_file_fwrite(m_instances[index].p_file,
+ evt_param.data_received.p_data,
+ evt_param.data_received.size);
+ }
+
+ handle_evt(index, IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED, &evt_param);
+
+ // Unlock instance if file has not assigned callback (probably not needs more time to perform read/write).
+ if (m_instances[index].p_file == NULL || m_instances[index].p_file->p_callback == NULL)
+ {
+ internal_err = transfer_resume(index);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while resuming the transfer. Reason: %08lx.", internal_err);
+ }
+ }
+ }
+ else
+ {
+ if (m_instances[index].p_file != NULL)
+ {
+ err_code = iot_file_fclose(m_instances[index].p_file);
+ }
+
+ internal_err = send_response(&index);
+ if (internal_err != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while sending response. Reason: %08lx.", internal_err);
+ }
+
+ TFTP_ERR("Complete due to packet length. (%ld: %ld)", p_rx_packet->length, byte_index);
+ m_instances[index].state = STATE_RECEIVING;
+ handle_evt(index, IOT_TFTP_EVT_TRANSFER_GET_COMPLETE, NULL);
+ }
+
+ TFTP_MUTEX_LOCK();
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Failed to save received data (fwrite)!");
+ handle_evt_err(index, TFTP_ACCESS_DENIED, ACCESS_ERROR_MSG);
+ break;
+ }
+ }
+ }
+ else
+ {
+ TFTP_ERR("Invalid state to receive DATA packet.");
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return NRF_SUCCESS;
+ }
+ break;
+
+ case TYPE_ERR:
+ recv_block_id = uint16_decode(&p_new_packet[byte_index]);
+ recv_block_id = NTOHS(recv_block_id);
+ byte_index += TFTP_ERR_CODE_SIZE;
+
+ TFTP_ERR("Received error packet!");
+
+ evt.id = IOT_TFTP_EVT_ERROR;
+ evt.param.err.code = CONVERT_TO_IOT_ERROR(recv_block_id);
+
+ if (p_rx_packet->length > TFTP_HEADER_SIZE + TFTP_ERR_CODE_SIZE)
+ {
+ evt.param.err.p_msg = (char *) &p_new_packet[byte_index];
+ p_new_packet[p_rx_packet->length-1] = '\0';
+ }
+
+ app_notify(&index, &evt);
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ if (evt.param.err.code != TFTP_INVALID_TID)
+ {
+ instance_abort(index);
+ }
+
+ return evt.param.err.code;
+
+ default:
+ TFTP_ERR("Invalid TFTP packet opcode!");
+ handle_evt_err(index, TFTP_INVALID_PACKET, NULL);
+ break;
+ }
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Count how many bytes are required to store options inside request packet.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] type Type of TFTP request.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t count_options_length(uint32_t index, uint32_t type)
+{
+ uint32_t op_length = 0;
+ char next_retr_str[NEXT_RETR_MAX_LENGTH];
+ char block_size_str[BLKSIZE_MAX_LENGTH];
+ char file_size_str[FILE_SIZE_MAX_LENGTH];
+
+ if ((m_instances[index].init_params.next_retr > 0) &&
+ (m_instances[index].init_params.next_retr < 256))
+ {
+ UNUSED_VARIABLE(uint_to_str(m_instances[index].init_params.next_retr, next_retr_str, NEXT_RETR_MAX_LENGTH));
+ op_length += sizeof(OPTION_TIMEOUT); // Time out option length.
+ op_length += strlen(next_retr_str) + 1; // The '\0' character ate the end of a string.
+ }
+
+ if ((m_instances[index].init_params.block_size > 0) &&
+ (m_instances[index].init_params.block_size != TFTP_DEFAULT_BLOCK_SIZE))
+ {
+ UNUSED_VARIABLE(uint_to_str(m_instances[index].init_params.block_size, block_size_str, sizeof(block_size_str)));
+ op_length += sizeof(OPTION_BLKSIZE); // Time out option length.
+ op_length += strlen(block_size_str) + 1; // The '\0' character ate the end of a string.
+ }
+
+ op_length += sizeof(OPTION_SIZE); // TFTP tsize option length.
+
+ if (type == TYPE_RRQ)
+ {
+ op_length += sizeof(OPTION_SIZE_REQUEST_VALUE); // Just send 0 to inform other side that you support this option and would like to receive file size inside OptionACK.
+ }
+
+ if (type == TYPE_WRQ)
+ {
+ UNUSED_VARIABLE(uint_to_str(m_instances[index].p_file->file_size, file_size_str, sizeof(file_size_str)));
+ op_length += strlen(file_size_str) + 1;
+ }
+
+ if (m_instances[index].p_password != NULL)
+ {
+ if (m_instances[index].p_password[0] != '\0')
+ {
+ op_length += strlen(m_instances[index].p_password) + 1; // Password is always sent as last string without option name.
+ }
+ }
+
+ return op_length;
+}
+
+/**@brief This function inserts options into request packet payload using passed option iterator.
+ *
+ * @param[in] index Index of TFTP instance.
+ * @param[in] type Type of TFTP request.
+ * @param[in] p_iter Iterator which will be used to set options.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t insert_options(uint32_t index, uint32_t type, option_iter_t * p_iter)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ char next_retr_str[NEXT_RETR_MAX_LENGTH];
+ char block_size_str[BLKSIZE_MAX_LENGTH];
+ char file_size_str[FILE_SIZE_MAX_LENGTH];
+
+ if (type == TYPE_RRQ)
+ {
+ err_code = op_set(p_iter, OPTION_SIZE, OPTION_SIZE_REQUEST_VALUE);
+ }
+
+ if (type == TYPE_WRQ)
+ {
+ UNUSED_VARIABLE(uint_to_str(m_instances[index].p_file->file_size, file_size_str, FILE_SIZE_MAX_LENGTH));
+ err_code = op_set(p_iter, OPTION_SIZE, file_size_str);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if ((m_instances[index].init_params.next_retr > 0) &&
+ (m_instances[index].init_params.next_retr < 256))
+ {
+ UNUSED_VARIABLE(uint_to_str(m_instances[index].init_params.next_retr, next_retr_str, NEXT_RETR_MAX_LENGTH));
+ err_code = op_set(p_iter, OPTION_TIMEOUT, next_retr_str);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ if ((m_instances[index].init_params.block_size > 0) &&
+ (m_instances[index].init_params.block_size != TFTP_DEFAULT_BLOCK_SIZE))
+ {
+ UNUSED_VARIABLE(uint_to_str(m_instances[index].init_params.block_size, block_size_str, BLKSIZE_MAX_LENGTH));
+ err_code = op_set(p_iter, OPTION_BLKSIZE, block_size_str);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ if (m_instances[index].p_password != NULL)
+ {
+ if (m_instances[index].p_password[0] != '\0')
+ {
+ err_code = op_set(p_iter, NULL, m_instances[index].p_password);
+ }
+ }
+ }
+
+ return err_code;
+}
+
+/**@Sends Read/Write TFTP Request.
+ *
+ * @param[in] type Type of request (allowed values: TYPE_RRQ and TYPE_WRQ).
+ * @param[in] p_tftp Pointer to the TFTP instance (from user space).
+ * @param[in] p_file Pointer to the file, which should be assigned to passed instance.
+ * @param[in] p_params Pointer to transmission parameters structure (retransmission time, block size).
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+static uint32_t send_request(uint32_t type,
+ iot_tftp_t * p_tftp,
+ iot_file_t * p_file,
+ const char * p_path)
+{
+ uint32_t err_code;
+ iot_pbuffer_t * p_buffer;
+ iot_pbuffer_alloc_param_t buffer_param;
+ uint8_t * p_rrq_packet;
+ option_iter_t rrq_iter;
+ uint32_t index;
+ uint32_t byte_index;
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (p_path == NULL || p_path[0] == '\0')
+ {
+ TFTP_ERR("[TFTP]: Invalid path passed.\r\n");
+ return (NRF_ERROR_INVALID_PARAM | IOT_TFTP_ERR_BASE);
+ }
+
+ if (p_file != NULL && p_file->p_filename[0] == '\0')
+ {
+ TFTP_ERR("Invalid file name passed!");
+ return (NRF_ERROR_INVALID_PARAM | IOT_TFTP_ERR_BASE);
+ }
+
+ if (m_instances[index].state != STATE_IDLE)
+ {
+ TFTP_ERR("Invalid instance state!");
+ return (NRF_ERROR_INVALID_STATE | IOT_TFTP_ERR_BASE);
+ }
+
+ // Assign file with TFTP instance.
+ m_instances[index].p_file = p_file;
+ m_instances[index].p_path = p_path;
+ m_instances[index].block_id = 0;
+ m_instances[index].dst_tid = m_instances[index].dst_port;
+
+ memset(&buffer_param, 0, sizeof(buffer_param));
+ buffer_param.type = UDP6_PACKET_TYPE;
+ buffer_param.flags = PBUFFER_FLAG_DEFAULT;
+
+ // Calculate size of required packet.
+ buffer_param.length = TFTP_HEADER_SIZE; // Bytes reserved for TFTP opcode value.
+ buffer_param.length += strlen(p_path) + 1; // File name with '\0' character.
+ buffer_param.length += sizeof(OPTION_MODE_OCTET); // Mode option value length.
+
+ TFTP_TRC("Estimated packet length without options: %ld.", buffer_param.length);
+
+ buffer_param.length += count_options_length(index, type); // TFTP options.
+
+ TFTP_TRC("Estimated packet length with options: %ld.", buffer_param.length);
+
+ // Allocate packet buffer.
+ err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ memset(p_buffer->p_payload, 0, buffer_param.length);
+ byte_index = 0;
+
+ // Compose TFTP Read Request according to configuration.
+ p_rrq_packet = p_buffer->p_payload;
+ uint16_t size = uint16_encode(HTONS(type), &p_rrq_packet[byte_index]);
+ byte_index += size;
+
+ // Initialization of option iterator.
+ op_init(&rrq_iter, (char *)&p_rrq_packet[byte_index], buffer_param.length - TFTP_HEADER_SIZE); // Options uses whole packet except opcode.
+ rrq_iter.p_start[0] = '\0';
+
+ // Insert file path and mode strings.
+ err_code = op_set(&rrq_iter, NULL, p_path);
+ PBUFFER_FREE_IF_ERROR(err_code);
+
+ err_code = op_set(&rrq_iter, NULL, OPTION_MODE_OCTET);
+ PBUFFER_FREE_IF_ERROR(err_code);
+
+ // Insert TFTP options into packet.
+ err_code = insert_options(index, type, &rrq_iter);
+ PBUFFER_FREE_IF_ERROR(err_code);
+
+ // Change instance status to connecting.
+ if (type == TYPE_RRQ)
+ {
+ m_instances[index].state = STATE_CONNECTING_RRQ;
+ }
+ else
+ {
+ m_instances[index].state = STATE_CONNECTING_WRQ;
+ }
+
+ // Send read request.
+ UNUSED_VARIABLE(retr_timer_reset(index));
+ err_code = udp6_socket_sendto(&m_instances[index].socket,
+ &m_instances[index].addr,
+ m_instances[index].dst_tid,
+ p_buffer);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Unable to send request!");
+ m_instances[index].state = STATE_IDLE;
+ }
+
+ PBUFFER_FREE_IF_ERROR(err_code);
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function used in order to change initial connection parameters. */
+uint32_t iot_tftp_set_params(iot_tftp_t * p_tftp, iot_tftp_trans_params_t * p_params)
+{
+ uint32_t err_code;
+ uint32_t index;
+
+ NULL_PARAM_CHECK(p_params);
+ NULL_PARAM_CHECK(p_tftp);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Modifying connection parameters could be done only when TFTP instance is disconnected.
+ // NOTE: STATE_FREE is not allowed, because there have to be a moment (e.g. after calling iot_tftp_init()) when transmission parameters were set to default values.
+ if (m_instances[index].state == STATE_IDLE)
+ {
+ // Reset connection parameters to initial values. They will be set (negotiated) after get/put call.
+ memcpy(&m_instances[index].init_params, p_params, sizeof(iot_tftp_trans_params_t));
+ }
+ else
+ {
+ err_code = (NRF_ERROR_INVALID_STATE | IOT_TFTP_ERR_BASE);
+
+ TFTP_ERR("Cannot modify connection parameters inside %d state!", m_instances[index].state);
+ }
+ }
+ else
+ {
+ TFTP_ERR("Unable to find TFTP instance!");
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Function for performing retransmissions of TFTP acknowledgments. */
+void iot_tftp_timeout_process(iot_timer_time_in_ms_t wall_clock_value)
+{
+ uint32_t index;
+ uint32_t err_code;
+
+ UNUSED_PARAMETER(wall_clock_value);
+
+ TFTP_MUTEX_LOCK();
+
+ for (index = 0; index < TFTP_MAX_INSTANCES; index++)
+ {
+ if ((m_instances[index].state == STATE_CONNECTING_RRQ) ||
+ (m_instances[index].state == STATE_CONNECTING_WRQ) ||
+ (m_instances[index].state == STATE_SENDING) ||
+ (m_instances[index].state == STATE_RECEIVING))
+ {
+ TFTP_ENTRY();
+ TFTP_TRC("Current timer: %ld, %ld", m_instances[index].request_timeout, wall_clock_value);
+
+ if (instance_timer_is_expired(index))
+ {
+ err_code = NRF_SUCCESS;
+
+ if (m_instances[index].retries < TFTP_MAX_RETRANSMISSION_COUNT)
+ {
+ TFTP_TRC("Query retransmission [%d] for file %s.",
+ m_instances[index].retries, m_instances[index].p_file->p_filename);
+
+ // Increase retransmission number.
+ m_instances[index].retries++;
+
+ TFTP_TRC("Compose packet for retransmission.");
+ // Send packet again.
+ if (m_instances[index].state == STATE_RECEIVING)
+ {
+ TFTP_TRC("Retransmission of ACK packet.");
+ err_code = create_ack_packet(index, m_instances[index].block_id);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = send_response(&index);
+ }
+ else
+ {
+ TFTP_ERR("Failed to create packet!");
+ handle_evt_err(index, err_code, NULL);
+ }
+ }
+ else if (m_instances[index].state == STATE_SENDING)
+ {
+ TFTP_TRC("Retransmission of DATA packet.");
+ err_code = create_data_packet(index, m_instances[index].block_id - 1);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (m_instances[index].p_file->p_callback == NULL)
+ {
+ err_code = send_response(&index);
+ }
+ }
+ else
+ {
+ TFTP_ERR("Failed to create packet!");
+ handle_evt_err(index, err_code, NULL);
+ }
+ }
+ else if (m_instances[index].state == STATE_CONNECTING_RRQ)
+ {
+ TFTP_TRC("OACK time out. Retransmit RRQ.");
+ m_instances[index].state = STATE_IDLE;
+ err_code = send_request(TYPE_RRQ, &index, m_instances[index].p_file, m_instances[index].p_path);
+ }
+ else if (m_instances[index].state == STATE_CONNECTING_WRQ)
+ {
+ TFTP_TRC("OACK time out. Retransmit WRQ.");
+ m_instances[index].state = STATE_IDLE;
+ err_code = send_request(TYPE_WRQ, &index, m_instances[index].p_file, NULL);
+ }
+ else
+ {
+ TFTP_TRC("In idle state.");
+ }
+ }
+ else
+ {
+ TFTP_ERR("TFTP server did not response on query for file %s.",
+ m_instances[index].p_file->p_filename);
+
+ // No response from server.
+ err_code = TFTP_REMOTE_UNREACHABLE;
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Inform application that timeout occurs.
+ TFTP_ERR("Timeout error.");
+ handle_evt_err(index, err_code, NULL);
+ }
+ }
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return;
+ }
+ }
+
+ TFTP_MUTEX_UNLOCK();
+}
+
+/**@brief Initializes TFTP client. */
+uint32_t iot_tftp_init(iot_tftp_t * p_tftp, iot_tftp_init_t * p_init_params)
+{
+ uint32_t index = 0;
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_tftp);
+ NULL_PARAM_CHECK(p_init_params);
+ NULL_PARAM_CHECK(p_init_params->p_ipv6_addr);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ // Find first available instance.
+ err_code = find_free_instance(&index);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Reset instance values.
+ instance_reset(index);
+
+ // Assign new values.
+ *p_tftp = index;
+ m_instances[index].callback = p_init_params->callback;
+ m_instances[index].src_tid = p_init_params->src_port;
+ m_instances[index].dst_port = p_init_params->dst_port;
+ m_instances[index].p_password = p_init_params->p_password;
+ m_instances[index].dst_tid = m_instances[index].dst_port;
+ memcpy(&m_instances[index].addr, p_init_params->p_ipv6_addr, sizeof(ipv6_addr_t));
+
+ // Configure socket.
+ err_code = udp6_socket_allocate(&m_instances[index].socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = udp6_socket_bind(&m_instances[index].socket,
+ IPV6_ADDR_ANY,
+ p_init_params->src_port);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Attach callback.
+ err_code = udp6_socket_recv(&m_instances[index].socket, client_process);
+ if (err_code == NRF_SUCCESS)
+ {
+ m_instances[index].state = STATE_IDLE;
+ }
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ (void)udp6_socket_free(&m_instances[index].socket);
+
+ TFTP_ERR("UDP socket configuration failure!");
+ }
+ }
+ }
+ else
+ {
+ TFTP_ERR("No more free instances left!");
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Resets TFTP client instance, so it is possible to make another request after error. */
+uint32_t iot_tftp_abort(iot_tftp_t * p_tftp)
+{
+ uint32_t err_code;
+ uint32_t index;
+
+ NULL_PARAM_CHECK(p_tftp);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code == NRF_SUCCESS)
+ {
+ instance_abort(index);
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Frees assigned sockets. */
+uint32_t iot_tftp_uninit(iot_tftp_t * p_tftp)
+{
+ uint32_t err_code;
+ uint32_t index;
+
+ NULL_PARAM_CHECK(p_tftp);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code == NRF_SUCCESS)
+ {
+ if (m_instances[index].state == STATE_SEND_HOLD ||
+ m_instances[index].state == STATE_RECV_HOLD ||
+ m_instances[index].state == STATE_SENDING ||
+ m_instances[index].state == STATE_RECEIVING)
+ {
+ // Free pbuffer.
+ err_code = iot_pbuffer_free(m_instances[index].p_packet, true);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Cannot free pbuffer - %p", m_instances[index].p_packet);
+ }
+
+ err_code = iot_file_fclose(m_instances[index].p_file);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Cannot close file - %p", m_instances[index].p_file);
+ }
+ }
+
+ if (m_instances[index].state != STATE_IDLE)
+ {
+ handle_evt_err(index, TFTP_UNDEFINED_ERROR, UNINT_ERROR_MSG);
+ }
+
+ (void)udp6_socket_free(&m_instances[index].socket);
+ m_instances[index].state = STATE_FREE;
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Retrieves file from remote server into p_file. */
+uint32_t iot_tftp_get(iot_tftp_t * p_tftp, iot_file_t * p_file, const char * p_path)
+{
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_tftp);
+ NULL_PARAM_CHECK(p_path);
+ if (p_file != NULL)
+ {
+ NULL_PARAM_CHECK(p_file->p_filename);
+ }
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = send_request(TYPE_RRQ, p_tftp, p_file, p_path);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while sending read request. Reason: %08lx.", err_code);
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Sends local file p_file to a remote server. */
+uint32_t iot_tftp_put(iot_tftp_t * p_tftp, iot_file_t * p_file, const char * p_path)
+{
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_tftp);
+ NULL_PARAM_CHECK(p_file);
+ NULL_PARAM_CHECK(p_file->p_filename);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = send_request(TYPE_WRQ, p_tftp, p_file, p_path);
+ if (err_code != NRF_SUCCESS)
+ {
+ TFTP_ERR("Error while sending write request. Reason: %08lx.", err_code);
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Holds transmission of ACK (use in order to slow transmission). */
+uint32_t iot_tftp_hold(iot_tftp_t * p_tftp)
+{
+ uint32_t index;
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_tftp);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Hold transfer.
+ err_code = transfer_hold(index);
+ }
+ else
+ {
+ TFTP_ERR("Hold called on unknown TFTP instance.");
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
+
+/**@brief Resumes transmission. */
+uint32_t iot_tftp_resume(iot_tftp_t * p_tftp)
+{
+ uint32_t index;
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_tftp);
+
+ TFTP_ENTRY();
+
+ TFTP_MUTEX_LOCK();
+
+ err_code = find_instance(p_tftp, &index);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = transfer_resume(index);
+ }
+ else
+ {
+ TFTP_ERR("Failed to find instance.");
+ }
+
+ TFTP_MUTEX_UNLOCK();
+
+ TFTP_EXIT();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.h
new file mode 100644
index 0000000..0405af2
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/tftp/iot_tftp.h
@@ -0,0 +1,245 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file iot_tftp.h
+ *
+ * @defgroup iot_tftp TFTP Application Interface for Nordic's IPv6 stack
+ * @ingroup iot_sdk_stack
+ * @{
+ * @brief Trivial File Transfer Protocol module provides implementation of TFTP Client.
+ *
+ */
+
+#ifndef IOT_TFTP_H__
+#define IOT_TFTP_H__
+
+#include "sdk_common.h"
+#include "iot_common.h"
+#include "iot_timer.h"
+#include "iot_file.h"
+#include "iot_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief TFTP global instance number. */
+typedef uint32_t iot_tftp_t;
+
+/**@brief TFTP module Events. */
+typedef enum
+{
+ IOT_TFTP_EVT_ERROR, /**< Event code indicating that an error occurred. */
+ IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED, /**< Event code indicating that a data packet was received during read transfer. */
+ IOT_TFTP_EVT_TRANSFER_GET_COMPLETE, /**< Event code indicating that transfer read was completed. */
+ IOT_TFTP_EVT_TRANSFER_PUT_COMPLETE, /**< Event code indicating that transfer write was completed. */
+} iot_tftp_evt_id_t;
+
+/**@brief TFTP error event structure. */
+typedef struct
+{
+ uint32_t code; /**< Error code. */
+ char * p_msg; /**< Message describing the reason or NULL if no description is available. */
+ uint32_t size_transfered; /**< In case of an error, variable indicates a number of successfully read or write bytes. */
+} iot_tftp_evt_err_t;
+
+/**@brief TFTP data received event structure. */
+typedef struct
+{
+ uint8_t * p_data; /**< Pointer to received data chunk. */
+ uint16_t size; /**< Size of received data chunk. */
+} iot_tftp_evt_data_received_t;
+
+/**@brief TFTP event structure. */
+typedef union
+{
+ iot_tftp_evt_err_t err; /**< Error event structure. Used only in case of IOT_TFTP_EVT_ERROR error. */
+ iot_tftp_evt_data_received_t data_received; /**< Data received event structure. Used only in case of IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED event. */
+} iot_tftp_evt_param_t;
+
+/**@brief Asynchronous event type. */
+typedef struct
+{
+ iot_tftp_evt_id_t id; /**< Event code. */
+ iot_tftp_evt_param_t param; /**< Union to structures describing event. */
+ iot_file_t * p_file; /**< File associated with TFTP transfer. */
+} iot_tftp_evt_t;
+
+/**@brief TFTP Transmission initialization structure (both GET and PUT). */
+typedef struct
+{
+ uint32_t next_retr; /**< Number of seconds between retransmissions. */
+ uint16_t block_size; /**< Maximum or negotiated size of data block. */
+} iot_tftp_trans_params_t;
+
+/**@brief User callback from TFTP module.
+ *
+ * @note TFTP module user callback will be invoked even if user asks TFTP to abort (TFTP error event).
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ * @param[in] p_evt Pointer to the TFTP event structure, describing reason.
+ *
+ * @retval None.
+ */
+typedef void (*iot_tftp_callback_t)(iot_tftp_t * p_tftp, iot_tftp_evt_t * p_evt);
+
+
+/**@brief TFTP initialization structure. */
+typedef struct
+{
+ ipv6_addr_t * p_ipv6_addr; /**< IPv6 address of the server. */
+ uint16_t src_port; /**< Source port (local UDP port) from which all request and data will be sent. Should be choosen randomly. */
+ uint16_t dst_port; /**< Destination port - UDP port on which server listens for new connections. */
+ iot_tftp_callback_t callback; /**< Reference to the user callback. */
+ const char * p_password; /**< Server password for all requests. Shall be NULL if no password is required. */
+} iot_tftp_init_t;
+
+
+/**@brief Initializes TFTP client.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance. Should not be NULL.
+ * @param[in] p_init_params Initialization structure for TFTP client. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_init(iot_tftp_t * p_tftp, iot_tftp_init_t * p_init_params);
+
+
+/**@brief Function used in order to change initial connection parameters.
+ *
+ * @param[in] p_tftp Reference to the TFTP instance.
+ * @param[in] p_params Pointer to transmission parameters structure. Should not be NULL.
+ *
+ * @retval NRF_SUCCESS if parameters successfully set, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_set_params(iot_tftp_t * p_tftp, iot_tftp_trans_params_t * p_params);
+
+
+/**@brief Retrieves file from remote server into p_file.
+ *
+ * If @p p_file is a NULL pointer, the content of received file can be retrieved by handling
+ * @ref IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED event. This event is generated each time a data
+ * packet (containing a chunk of requested file) is received.
+ * IOT_TFTP_EVT_TRANSFER_GET_COMPLETE event is generated after download is complete.
+ *
+ * @note This function should not be called until previous download operation is completed.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ * @param[in] p_file Reference to the file from which data should be read.
+ * @param[in] p_path Path of the requested file on the remote server. Shall not be NULL.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_get(iot_tftp_t * p_tftp, iot_file_t * p_file, const char * p_path);
+
+
+/**@brief Sends local file p_file to a remote server.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ * @param[in] p_file Reference to the file to which data should be stored. Should not be NULL.
+ * @param[in] p_path Path of the file on the remote server. Shall not be NULL.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_put(iot_tftp_t * p_tftp, iot_file_t * p_file, const char * p_path);
+
+
+/**@brief Holds transmission of ACK (use in order to slow transmission).
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_hold(iot_tftp_t * p_tftp);
+
+
+/**@brief Resumes transmission.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_resume(iot_tftp_t * p_tftp);
+
+
+/**@brief Resets TFTP client instance, so it is possible to make another request after error.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_abort(iot_tftp_t * p_tftp);
+
+
+/**@brief Frees assigned sockets.
+ *
+ * @param[in] p_tftp Pointer to the TFTP instance.
+ *
+ * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
+ * for failure.
+ */
+uint32_t iot_tftp_uninit(iot_tftp_t * p_tftp);
+
+
+/**@brief Function for performing retransmissions of TFTP acknowledgments.
+ *
+ * @note TFTP module implements the retransmission mechanism by invoking this function periodically.
+ * So that method has to be added to IoT Timer client list and has to be called with minimum of
+ * TFTP_RETRANSMISSION_INTERVAL resolution.
+ *
+ * @param[in] wall_clock_value The value of the wall clock that triggered the callback.
+ *
+ * @retval None.
+ */
+void iot_tftp_timeout_process(iot_timer_time_in_ms_t wall_clock_value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IOT_TFTP_H__
+
+/** @} */
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;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.c
new file mode 100644
index 0000000..8b70cba
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.c
@@ -0,0 +1,101 @@
+/**
+ * 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 <stdint.h>
+#include <stdbool.h>
+#include "nordic_common.h"
+#include "sdk_common.h"
+#include "sdk_config.h"
+#include "ipv6_utils.h"
+
+void ipv6_checksum_calculate(const uint8_t * p_data, uint16_t len, uint16_t * p_checksum, bool flip_flag)
+{
+ uint16_t checksum_even = (((*p_checksum) & 0xFF00) >> 8);
+ uint16_t checksum_odd = ((*p_checksum) & 0x00FF);
+
+ while (len)
+ {
+ if ( len == 1 )
+ {
+ checksum_even += (*p_data);
+ len -= 1;
+ }
+ else
+ {
+ checksum_even += *p_data++;
+ checksum_odd += *p_data++;
+ len -= 2;
+ }
+
+ if (checksum_odd & 0xFF00)
+ {
+ checksum_even += ((checksum_odd & 0xFF00) >> 8);
+ checksum_odd = (checksum_odd & 0x00FF);
+ }
+
+ if (checksum_even & 0xFF00)
+ {
+ checksum_odd += ((checksum_even & 0xFF00) >> 8);
+ checksum_even = (checksum_even & 0x00FF);
+ }
+ }
+
+ checksum_even = (checksum_even << 8) + (checksum_odd & 0xFFFF);
+
+ if (flip_flag)
+ {
+ // We use 0xFFFF instead of 0x0000 because of not operator.
+ if (checksum_even == 0xFFFF)
+ {
+ checksum_even = 0x0000;
+ }
+ }
+
+ (*p_checksum) = (uint16_t)(checksum_even);
+}
+
+void ipv6_header_init(ipv6_header_t * p_ip_header)
+{
+ p_ip_header->version_traffic_class = IPV6_DEFAULT_VER_TC;
+ p_ip_header->traffic_class_flowlabel = IPV6_DEFAULT_TC_FL;
+ p_ip_header->flowlabel = IPV6_DEFAULT_FL;
+ p_ip_header->next_header = IPV6_NEXT_HEADER_RESERVED;
+ p_ip_header->hoplimit = IPV6_DEFAULT_HOP_LIMIT;
+ p_ip_header->length = 0;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.h
new file mode 100644
index 0000000..5cbdf15
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/utils/ipv6_utils.h
@@ -0,0 +1,93 @@
+/**
+ * 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.
+ *
+ */
+/** @file ipv6_utils.h
+ *
+ * @defgroup iot_utils Common utils
+ * @ingroup iot_sdk_common
+ * @{
+ * @brief Abstracts common IOT macros needed by IOT modules.
+ *
+ * @details Common macros related to IOT are defined here for use by all IOT modules.
+ */
+
+#ifndef IPV6_UTILS_H__
+#define IPV6_UTILS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "iot_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Function for calculating checksum using IPv6 algorithm.
+ *
+ * @param[in] p_data Pointer to the data needs to be checksummed.
+ * @param[in] len Length of the data.
+ * @param[in] p_checksum Pointer to actual value of checksum.
+ * @param[out] p_checksum Value of calculated checksum.
+ *
+ * @retval None.
+ */
+void ipv6_checksum_calculate(const uint8_t * p_data,
+ uint16_t len,
+ uint16_t * p_checksum,
+ bool flip_zero);
+
+
+/**@brief Function for initializing default values of IPv6 Header.
+ *
+ * @note Function initializes Version, Traffic Class, Flow Label, Next Header, Hop Limit and
+ * Length fields.
+ *
+ * @param[in] p_ip_header Pointer to the IPv6 Header.
+ *
+ * @retval None.
+ */
+void ipv6_header_init(ipv6_header_t * p_ip_header);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IPV6_UTILS_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.c
new file mode 100644
index 0000000..638277a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.c
@@ -0,0 +1,553 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include <stddef.h>
+
+#include "ipso_objects.h"
+#include "lwm2m.h"
+#include "lwm2m_tlv.h"
+
+//lint -e516 -save // Symbol '__INTADDR__()' has arg. type conflict
+#define LWM2M_INSTANCE_OFFSET_SET(instance, type) \
+ instance->proto.operations_offset = offsetof(type, operations); \
+ instance->proto.resource_ids_offset = offsetof(type, resource_ids);
+//lint -restore
+
+void ipso_instance_digital_input_init(ipso_digital_input_t * p_instance)
+{
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_digital_input_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_DIGITAL_INPUT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_digital_input_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[4] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[6] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_READ;
+
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_DIGITAL_INPUT_STATE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_DIGITAL_INPUT_COUNTER;
+ p_instance->resource_ids[2] = IPSO_RR_ID_DIGITAL_INPUT_POLARITY;
+ p_instance->resource_ids[3] = IPSO_RR_ID_DIGITAL_INPUT_DEBOUNCE_PERIOD;
+ p_instance->resource_ids[4] = IPSO_RR_ID_DIGITAL_INPUT_EDGE_SELECTION;
+ p_instance->resource_ids[5] = IPSO_RR_ID_DIGITAL_INPUT_COUNTER_RESET;
+ p_instance->resource_ids[6] = IPSO_RR_ID_APPLICATION_TYPE;
+ p_instance->resource_ids[7] = IPSO_RR_ID_SENSOR_TYPE;
+
+
+}
+
+void ipso_instance_digital_output_init(ipso_digital_output_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_digital_output_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_DIGITAL_OUTPUT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_digital_output_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_DIGITAL_OUTPUT_STATE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_DIGITAL_OUTPUT_POLARITY;
+ p_instance->resource_ids[2] = IPSO_RR_ID_APPLICATION_TYPE;
+}
+
+
+void ipso_instance_analog_input_init(ipso_analog_input_t * p_instance)
+{
+
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_analog_input_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_ANALOGUE_INPUT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_analog_input_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[6] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_ANALOG_INPUT_CURRENT_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_MIN_MEASURED_VALUE;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MAX_MEASURED_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+ p_instance->resource_ids[6] = IPSO_RR_ID_APPLICATION_TYPE;
+ p_instance->resource_ids[7] = IPSO_RR_ID_SENSOR_TYPE;
+}
+
+void ipso_instance_analog_output_init(ipso_analog_output_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_analog_output_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_ANALOGUE_OUTPUT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_analog_output_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_ANALOG_OUTPUT_CURRENT_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_APPLICATION_TYPE;
+}
+
+void ipso_instance_generic_sensor_init(ipso_generic_sensor_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_generic_sensor_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_GENERIC_SENSOR;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_generic_sensor_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[7] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[8] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_SENSOR_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MIN_MEASURED_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MAX_MEASURED_VALUE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[6] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+ p_instance->resource_ids[7] = IPSO_RR_ID_APPLICATION_TYPE;
+ p_instance->resource_ids[8] = IPSO_RR_ID_SENSOR_TYPE;
+}
+
+void ipso_instance_illuminance_init(ipso_illuminance_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_illuminance_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_ILLUMINANCE_SENSOR;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_illuminance_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_SENSOR_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MIN_MEASURED_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MAX_MEASURED_VALUE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[6] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+}
+
+void ipso_instance_presence_init(ipso_presence_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_presence_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_PRESENCE_SENSOR;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_presence_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[5] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_DIGITAL_INPUT_STATE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_DIGITAL_INPUT_COUNTER;
+ p_instance->resource_ids[2] = IPSO_RR_ID_DIGITAL_INPUT_COUNTER_RESET;
+ p_instance->resource_ids[3] = IPSO_RR_ID_SENSOR_TYPE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_BUSY_TO_CLEAR_DELAY;
+ p_instance->resource_ids[5] = IPSO_RR_ID_CLEAR_TO_BUSY_DELAY;
+}
+
+void ipso_instance_temperature_init(ipso_temperature_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_temperature_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_TEMPERATURE_SENSOR;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_temperature_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_SENSOR_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MIN_MEASURED_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MAX_MEASURED_VALUE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[6] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+}
+
+void ipso_instance_humidity_init(ipso_humidity_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_humidity_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_HUMIDITY_SENSOR;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_humidity_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_SENSOR_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MIN_MEASURED_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MAX_MEASURED_VALUE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[6] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+}
+
+void ipso_instance_power_measurement_init(ipso_power_measurement_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_power_measurement_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_POWER_MEASUREMENT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_power_measurement_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_WRITE;
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[8] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[9] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[10] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[11] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[12] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[13] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[14] = LWM2M_OPERATION_CODE_WRITE;
+ p_instance->operations[15] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[16] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[17] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_INSTANTANEOUS_ACTIVE_POWER;
+ p_instance->resource_ids[1] = IPSO_RR_ID_MIN_MEASURED_ACTIVE_POWER;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MAX_MEASURED_ACTIVE_POWER;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MIN_RANGE_ACTIVE_POWER;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MAX_RANGE_ACTIVE_POWER;
+ p_instance->resource_ids[5] = IPSO_RR_ID_CUMULATIVE_ACTIVE_POWER;
+ p_instance->resource_ids[6] = IPSO_RR_ID_ACTIVE_POWER_CALIBRATION;
+ p_instance->resource_ids[7] = IPSO_RR_ID_INSTANTANEOUS_REACTIVE_POWER;
+ p_instance->resource_ids[8] = IPSO_RR_ID_MIN_MEASURED_REACTIVE_POWER;
+ p_instance->resource_ids[9] = IPSO_RR_ID_MAX_MEASURED_REACTIVE_POWER;
+ p_instance->resource_ids[10] = IPSO_RR_ID_MIN_RANGE_REACTIVE_POWER;
+ p_instance->resource_ids[11] = IPSO_RR_ID_MAX_RANGE_REACTIVE_POWER;
+ p_instance->resource_ids[12] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+ p_instance->resource_ids[13] = IPSO_RR_ID_CUMULATIVE_REACTIVE_POWER;
+ p_instance->resource_ids[14] = IPSO_RR_ID_REACTIVE_POWER_CALIBRATION;
+ p_instance->resource_ids[15] = IPSO_RR_ID_POWER_FACTOR;
+ p_instance->resource_ids[16] = IPSO_RR_ID_CURRENT_CALIBRATION;
+ p_instance->resource_ids[17] = IPSO_RR_ID_RESET_CUMULATIVE_ENERGY;
+}
+
+void ipso_instance_actuation_init(ipso_actuation_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_actuation_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_ACTUATION;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_actuation_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[4] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_ON_OFF;
+ p_instance->resource_ids[1] = IPSO_RR_ID_DIMMER;
+ p_instance->resource_ids[2] = IPSO_RR_ID_ON_TIME;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MULTI_STATE_OUTPUT;
+ p_instance->resource_ids[4] = IPSO_RR_ID_APPLICATION_TYPE;
+}
+
+void ipso_instance_set_point_init(ipso_set_point_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_set_point_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_SET_POINT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_set_point_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_SETPOINT_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_COLOUR;
+ p_instance->resource_ids[2] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[3] = IPSO_RR_ID_APPLICATION_TYPE;
+}
+
+void ipso_instance_load_control_init(ipso_load_control_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_load_control_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_LOAD_CONTROL;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_load_control_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[4] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[5] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_EVENT_IDENTIFIER;
+ p_instance->resource_ids[1] = IPSO_RR_ID_START_TIME;
+ p_instance->resource_ids[2] = IPSO_RR_ID_DURATION_IN_MIN;
+ p_instance->resource_ids[3] = IPSO_RR_ID_CRITICALITY_LEVEL;
+ p_instance->resource_ids[4] = IPSO_RR_ID_AVG_LOAD_ADJPCT;
+ p_instance->resource_ids[5] = IPSO_RR_ID_DUTY_CYCLE;
+}
+
+void ipso_instance_light_control_init(ipso_light_control_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_light_control_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_LIGHT_CONTROL;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_light_control_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_ON_OFF;
+ p_instance->resource_ids[1] = IPSO_RR_ID_DIMMER;
+ p_instance->resource_ids[2] = IPSO_RR_ID_COLOUR;
+ p_instance->resource_ids[3] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[4] = IPSO_RR_ID_ON_TIME;
+ p_instance->resource_ids[5] = IPSO_RR_ID_CUMULATIVE_ACTIVE_POWER;
+ p_instance->resource_ids[6] = IPSO_RR_ID_POWER_FACTOR;
+}
+
+void ipso_instance_power_control_init(ipso_power_control_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_power_control_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_POWER_CONTROL;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_power_control_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_ON_OFF;
+ p_instance->resource_ids[1] = IPSO_RR_ID_DIMMER;
+ p_instance->resource_ids[2] = IPSO_RR_ID_ON_TIME;
+ p_instance->resource_ids[3] = IPSO_RR_ID_CUMULATIVE_ACTIVE_POWER;
+ p_instance->resource_ids[4] = IPSO_RR_ID_POWER_FACTOR;
+}
+
+void ipso_instance_accelerometer_init(ipso_accelerometer_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_accelerometer_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_ACCELEROMETER;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_accelerometer_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_X_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_Y_VALUE;
+ p_instance->resource_ids[2] = IPSO_RR_ID_Z_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_MAX_RANGE_VALUE;
+}
+
+void ipso_instance_magnetometer_init(ipso_magnetometer_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_magnetometer_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_MAGNETOMETER;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_magnetometer_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = IPSO_RR_ID_X_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_Y_VALUE;
+ p_instance->resource_ids[2] = IPSO_RR_ID_Z_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[4] = IPSO_RR_ID_COMPASS_DIRECTION;
+}
+
+void ipso_instance_barometer_init(ipso_barometer_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, ipso_barometer_t);
+
+ p_instance->proto.object_id = IPSO_SO_ID_BAROMETER;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((ipso_barometer_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+
+
+ p_instance->resource_ids[0] = IPSO_RR_ID_SENSOR_VALUE;
+ p_instance->resource_ids[1] = IPSO_RR_ID_SENSOR_UNITS;
+ p_instance->resource_ids[2] = IPSO_RR_ID_MIN_MEASURED_VALUE;
+ p_instance->resource_ids[3] = IPSO_RR_ID_MAX_MEASURED_VALUE;
+ p_instance->resource_ids[4] = IPSO_RR_ID_MIN_RANGE_VALUE;
+ p_instance->resource_ids[5] = IPSO_RR_ID_MAX_RANGE_VALUE;
+ p_instance->resource_ids[6] = IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.h
new file mode 100644
index 0000000..7a9ca8e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects.h
@@ -0,0 +1,628 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file lwm2m_objects.h
+ *
+ * @defgroup iot_sdk_ipso_objects IPSO Smart Object definititions and types
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief IPSO objects definitions and types.
+ *
+ * @note The definitions used in this module are from the IPSO Alliance
+ * "IPSO SmartOject Guideline - Smart Objects Starter Pack1.0".
+ * The specification could be found at http://www.ipso-alliance.org/.
+ */
+
+#ifndef IPSO_OBJECTS_H__
+#define IPSO_OBJECTS_H__
+
+#include "lwm2m_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IPSO_SO_ID_DIGITAL_INPUT 3200
+#define IPSO_SO_ID_DIGITAL_OUTPUT 3201
+#define IPSO_SO_ID_ANALOGUE_INPUT 3202
+#define IPSO_SO_ID_ANALOGUE_OUTPUT 3203
+#define IPSO_SO_ID_GENERIC_SENSOR 3300
+#define IPSO_SO_ID_ILLUMINANCE_SENSOR 3301
+#define IPSO_SO_ID_PRESENCE_SENSOR 3302
+#define IPSO_SO_ID_TEMPERATURE_SENSOR 3303
+#define IPSO_SO_ID_HUMIDITY_SENSOR 3304
+#define IPSO_SO_ID_POWER_MEASUREMENT 3305
+#define IPSO_SO_ID_ACTUATION 3306
+#define IPSO_SO_ID_SET_POINT 3308
+#define IPSO_SO_ID_LOAD_CONTROL 3310
+#define IPSO_SO_ID_LIGHT_CONTROL 3311
+#define IPSO_SO_ID_POWER_CONTROL 3312
+#define IPSO_SO_ID_ACCELEROMETER 3313
+#define IPSO_SO_ID_MAGNETOMETER 3314
+#define IPSO_SO_ID_BAROMETER 3315
+
+/** @brief IPSO Reusable Resource IDs (Section 21). */
+#define IPSO_RR_ID_DIGITAL_INPUT_STATE 5500
+#define IPSO_RR_ID_DIGITAL_INPUT_COUNTER 5501
+#define IPSO_RR_ID_DIGITAL_INPUT_POLARITY 5502
+#define IPSO_RR_ID_DIGITAL_INPUT_DEBOUNCE_PERIOD 5503
+#define IPSO_RR_ID_DIGITAL_INPUT_EDGE_SELECTION 5504
+#define IPSO_RR_ID_DIGITAL_INPUT_COUNTER_RESET 5505
+
+#define IPSO_RR_ID_DIGITAL_OUTPUT_STATE 5550
+#define IPSO_RR_ID_DIGITAL_OUTPUT_POLARITY 5551
+
+
+// Digital output polarity options.
+#define IPSO_RR_ID_DIGITAL_OUTPUT_POLARITY_NORMAL 0
+#define IPSO_RR_ID_DIGITAL_OUTPUT_POLARITY_REVERSED 1
+
+#define IPSO_RR_ID_ANALOG_INPUT_CURRENT_VALUE 5600
+#define IPSO_RR_ID_MIN_MEASURED_VALUE 5601
+#define IPSO_RR_ID_MAX_MEASURED_VALUE 5602
+#define IPSO_RR_ID_MIN_RANGE_VALUE 5603
+#define IPSO_RR_ID_MAX_RANGE_VALUE 5604
+#define IPSO_RR_ID_RESET_MIN_MAX_MEASURED_VALUES 5605
+
+#define IPSO_RR_ID_ANALOG_OUTPUT_CURRENT_VALUE 5650
+
+#define IPSO_RR_ID_SENSOR_VALUE 5700
+#define IPSO_RR_ID_SENSOR_UNITS 5701
+#define IPSO_RR_ID_X_VALUE 5702
+#define IPSO_RR_ID_Y_VALUE 5703
+#define IPSO_RR_ID_Z_VALUE 5704
+#define IPSO_RR_ID_COMPASS_DIRECTION 5705
+#define IPSO_RR_ID_COLOUR 5706
+
+#define IPSO_RR_ID_APPLICATION_TYPE 5750
+#define IPSO_RR_ID_SENSOR_TYPE 5751
+
+#define IPSO_RR_ID_INSTANTANEOUS_ACTIVE_POWER 5800
+#define IPSO_RR_ID_MIN_MEASURED_ACTIVE_POWER 5801
+#define IPSO_RR_ID_MAX_MEASURED_ACTIVE_POWER 5802
+#define IPSO_RR_ID_MIN_RANGE_ACTIVE_POWER 5803
+#define IPSO_RR_ID_MAX_RANGE_ACTIVE_POWER 5804
+#define IPSO_RR_ID_CUMULATIVE_ACTIVE_POWER 5805
+#define IPSO_RR_ID_ACTIVE_POWER_CALIBRATION 5806
+
+#define IPSO_RR_ID_INSTANTANEOUS_REACTIVE_POWER 5810
+#define IPSO_RR_ID_MIN_MEASURED_REACTIVE_POWER 5811
+#define IPSO_RR_ID_MAX_MEASURED_REACTIVE_POWER 5812
+#define IPSO_RR_ID_MIN_RANGE_REACTIVE_POWER 5813
+#define IPSO_RR_ID_MAX_RANGE_REACTIVE_POWER 5814
+#define IPSO_RR_ID_CUMULATIVE_REACTIVE_POWER 5815
+#define IPSO_RR_ID_REACTIVE_POWER_CALIBRATION 5816
+
+#define IPSO_RR_ID_POWER_FACTOR 5820
+#define IPSO_RR_ID_CURRENT_CALIBRATION 5821
+#define IPSO_RR_ID_RESET_CUMULATIVE_ENERGY 5822
+#define IPSO_RR_ID_EVENT_IDENTIFIER 5823
+#define IPSO_RR_ID_START_TIME 5824
+#define IPSO_RR_ID_DURATION_IN_MIN 5825
+#define IPSO_RR_ID_CRITICALITY_LEVEL 5826
+#define IPSO_RR_ID_AVG_LOAD_ADJPCT 5827
+#define IPSO_RR_ID_DUTY_CYCLE 5828
+
+#define IPSO_RR_ID_ON_OFF 5850
+#define IPSO_RR_ID_DIMMER 5851
+#define IPSO_RR_ID_ON_TIME 5852
+#define IPSO_RR_ID_MULTI_STATE_OUTPUT 5853
+
+#define IPSO_RR_ID_SETPOINT_VALUE 5900
+
+#define IPSO_RR_ID_BUSY_TO_CLEAR_DELAY 5903
+#define IPSO_RR_ID_CLEAR_TO_BUSY_DELAY 5904
+
+
+
+/* Digital input ID: 3200 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[8]; /* Internal. */
+ uint16_t resource_ids[8]; /* Internal. */
+
+ /* Public members. */
+ bool state;
+ uint32_t counter;
+ bool polarity;
+ uint32_t debounce_period; /* Unit: milliseconds */
+ uint8_t edge_selection; /* Range: 1-3 */
+ /* Counter reset is execute only */
+ lwm2m_string_t application_type;
+ lwm2m_string_t sensor_type;
+
+} ipso_digital_input_t;
+
+
+/* Digital output ID: 3201 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. MUST be first. */
+ uint8_t operations[3]; /* Internal. MUST be second. */
+ uint16_t resource_ids[3]; /* Internal. MUST be third. */
+
+ /* Public members. */
+ bool digital_output_state;
+ bool digital_output_polarity;
+ lwm2m_string_t application_type;
+
+} ipso_digital_output_t;
+
+/* Analog input ID: 3202 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[8]; /* Internal. */
+ uint16_t resource_ids[8]; /* Internal. */
+
+ /* Public members. */
+ float current_value;
+ float min_measured_value;
+ float max_measured_value;
+ float min_range_value;
+ float max_range_value;
+ /* Reset min and max measured values is execute only */
+ lwm2m_string_t application_type;
+ lwm2m_string_t sensor_type;
+} ipso_analog_input_t;
+
+/* Analog output ID: 3203 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[4]; /* Internal. */
+ uint16_t resource_ids[4]; /* Internal. */
+
+ /* Public members. */
+ float current_value;
+ float min_range_value;
+ float max_range_value;
+ lwm2m_string_t application_type;
+
+} ipso_analog_output_t;
+
+/* Generic sensor ID: 3300 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[9]; /* Internal. */
+ uint16_t resource_ids[9]; /* Internal. */
+
+ /* Public members. */
+ float sensor_value;
+ lwm2m_string_t units;
+ float min_measured_value;
+ float max_measured_value;
+ float min_range_value;
+ float max_range_value;
+ /* Reset min and max measured values is execute only */
+ lwm2m_string_t application_type;
+ lwm2m_string_t sensor_type;
+
+} ipso_generic_sensor_t;
+
+/* Illuminance ID: 3301 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[7]; /* Internal. */
+ uint16_t resource_ids[7]; /* Internal. */
+
+ /* Public members. */
+ float sensor_value;
+ lwm2m_string_t units;
+ float min_measured_value;
+ float max_measured_value;
+ float min_range_value;
+ float max_range_value;
+ /* Reset min and max measured values is execute only */
+
+} ipso_illuminance_t;
+
+/* Presence ID: 3302 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[8]; /* Internal. */
+ uint16_t resource_ids[8]; /* Internal. */
+
+ /* Public members. */
+ bool digital_input_state;
+ uint32_t digital_input_counter;
+ /* Digital input counter reset is execute only */
+ lwm2m_string_t sensor_type;
+ uint32_t busy_to_clear_delay; // Unit: ms
+ uint32_t clear_to_busy_delay; // Unit: ms
+
+
+} ipso_presence_t;
+
+/* Temperature ID: 3303 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[7]; /* Internal. */
+ uint16_t resource_ids[7]; /* Internal. */
+
+ /* Public members. */
+ float sensor_value;
+ lwm2m_string_t units;
+ float min_measured_value;
+ float max_measured_value;
+ float min_range_value;
+ float max_range_value;
+ /* Reset min and max measured values is execute only */
+
+
+} ipso_temperature_t;
+
+/* Humidity ID: 3304 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[8]; /* Internal. */
+ uint16_t resource_ids[8]; /* Internal. */
+
+ /* Public members. */
+ float sensor_value;
+ lwm2m_string_t units;
+ float min_measured_value;
+ float max_measured_value;
+ float min_range_value;
+ float max_range_value;
+ /* Reset min and max measured values is execute only */
+
+} ipso_humidity_t;
+
+/* Power measurement ID: 3305 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[18]; /* Internal. */
+ uint16_t resource_ids[18]; /* Internal. */
+
+ /* Public members. */
+ float instantaneous_active_power;
+ float min_measured_active_power;
+ float max_measured_active_power;
+ float min_range_active_power;
+ float max_range_active_power;
+ float cumulative_active_power;
+ float active_power_calibration;
+ float instantaneous_reactive_power;
+ float min_measured_reactive_power;
+ float max_measured_reactive_power;
+ float min_range_reactive_power;
+ float max_range_reactive_power;
+ /* Reset min and max measured values is execute only */
+ float cumulative_reactive_power;
+ float reactive_power_calibration;
+ float power_factor;
+ float current_calibration;
+ /* Reset cumulative is execute only */
+
+} ipso_power_measurement_t;
+
+/* Actuation ID: 3306 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[5]; /* Internal. */
+ uint16_t resource_ids[5]; /* Internal. */
+
+ /* Public members. */
+ bool on;
+ uint16_t dimmer; // Unit: % Range: 0 - 100
+ uint32_t on_time; // Unit: s
+ lwm2m_string_t multi_state_output;
+ lwm2m_string_t application_type;
+
+} ipso_actuation_t;
+
+/* Set point ID: 3308 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[4]; /* Internal. */
+ uint16_t resource_ids[4]; /* Internal. */
+
+ /* Public members. */
+ float set_point_value;
+ lwm2m_string_t colour;
+ lwm2m_string_t units;
+ lwm2m_string_t application_type;
+
+} ipso_set_point_t;
+
+/* Load control ID: 3310 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[6]; /* Internal. */
+ uint16_t resource_ids[6]; /* Internal. */
+
+ /* Public members. */
+ lwm2m_string_t event_identifier;
+ lwm2m_time_t start_time;
+ uint32_t duration_in_min;
+ uint8_t criticality_level; // Range: 0-3
+ uint16_t avg_load_adjpct; // Unit: % range: 0-100
+ uint16_t duty_cycle; // Unit: % range: 0-100
+
+
+} ipso_load_control_t;
+
+/* Light control ID: 3311 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[7]; /* Internal. */
+ uint16_t resource_ids[7]; /* Internal. */
+
+ /* Public members. */
+ bool on;
+ uint16_t dimmer; // Unit: % Range: 0 - 100
+ lwm2m_string_t colour;
+ lwm2m_string_t units;
+ uint32_t on_time; // Unit: s
+ float cumulative_active_power;
+ float power_factor;
+
+} ipso_light_control_t;
+
+/* Power control ID: 3312 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[5]; /* Internal. */
+ uint16_t resource_ids[5]; /* Internal. */
+
+ /* Public members. */
+ bool on;
+ uint16_t dimmer; // Unit: % Range: 0 - 100
+ uint32_t on_time; // Unit: s
+ float cumulative_active_power;
+ float power_factor;
+
+} ipso_power_control_t;
+
+/* Accelerometer ID: 3313 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[6]; /* Internal. */
+ uint16_t resource_ids[6]; /* Internal. */
+
+ /* Public members. */
+ float x_value;
+ float y_value;
+ float z_value;
+ lwm2m_string_t units;
+ float min_range_value;
+ float max_range_value;
+
+} ipso_accelerometer_t;
+
+/* Magnetometer ID: 3314 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[8]; /* Internal. */
+ uint16_t resource_ids[8]; /* Internal. */
+
+ /* Public members. */
+ float x_value;
+ float y_value;
+ float z_value;
+ lwm2m_string_t units;
+ float compass_direction; // Unit: deg Range: 0-360
+
+} ipso_magnetometer_t;
+
+/* Barometer ID: 3315 */
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. */
+ uint8_t operations[7]; /* Internal. */
+ uint16_t resource_ids[7]; /* Internal. */
+
+ /* Public members. */
+ float sensor_value;
+ lwm2m_string_t units;
+ float min_measured_value;
+ float max_measured_value;
+ float min_range_value;
+ float max_range_value;
+ /* Reset min and max measured values is execute only */
+
+} ipso_barometer_t;
+
+
+/**@brief Initialize an IPSO digital input object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_digital_input_init(ipso_digital_input_t * p_instance);
+
+/**@brief Initialize an IPSO digital output object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_digital_output_init(ipso_digital_output_t * p_instance);
+
+/**@brief Initialize an IPSO analog input object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_analog_input_init(ipso_analog_input_t * p_instance);
+
+/**@brief Initialize an IPSO analog output object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_analog_output_init(ipso_analog_output_t * p_instance);
+
+/**@brief Initialize an IPSO generic sensor object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_generic_sensor_init(ipso_generic_sensor_t * p_instance);
+
+/**@brief Initialize an IPSO illuminance object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_illuminance_init(ipso_illuminance_t * p_instance);
+
+/**@brief Initialize an IPSO presence object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_presence_init(ipso_presence_t * p_instance);
+
+/**@brief Initialize an IPSO temperature object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_temperature_init(ipso_temperature_t * p_instance);
+
+/**@brief Initialize an IPSO humidity object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_humidity_init(ipso_humidity_t * p_instance);
+
+/**@brief Initialize an IPSO power measurement object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_power_measurement_init(ipso_power_measurement_t * p_instance);
+
+/**@brief Initialize an IPSO actuation object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_actuation_init(ipso_actuation_t * p_instance);
+
+/**@brief Initialize an IPSO set point object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_set_point_init(ipso_set_point_t * p_instance);
+
+/**@brief Initialize an IPSO load control object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_load_control_init(ipso_load_control_t * p_instance);
+
+/**@brief Initialize an IPSO light control object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_light_control_init(ipso_light_control_t * p_instance);
+
+/**@brief Initialize an IPSO power control object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_power_control_init(ipso_power_control_t * p_instance);
+
+/**@brief Initialize an IPSO accelerometer object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_accelerometer_init(ipso_accelerometer_t * p_instance);
+
+/**@brief Initialize an IPSO magnetometer object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_magnetometer_init(ipso_magnetometer_t * p_instance);
+
+/**@brief Initialize an IPSO barometer object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void ipso_instance_barometer_init(ipso_barometer_t * p_instance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_OBJECTS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.c
new file mode 100644
index 0000000..5cb53ec
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.c
@@ -0,0 +1,143 @@
+/**
+ * Copyright (c) 2015 - 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 "ipso_objects_tlv.h"
+#include "lwm2m_tlv.h"
+
+static void index_buffer_len_update(uint32_t * index, uint32_t * buffer_len, uint32_t max_buffer)
+{
+ *index += *buffer_len;
+ *buffer_len = max_buffer - *index;
+}
+
+uint32_t ipso_tlv_ipso_digital_output_decode(ipso_digital_output_t * p_digital_output,
+ uint8_t * p_buffer,
+ uint32_t buffer_len)
+{
+ uint32_t err_code;
+ lwm2m_tlv_t tlv;
+
+ uint32_t index = 0;
+
+ while (index < buffer_len)
+ {
+ err_code = lwm2m_tlv_decode(&tlv, &index, p_buffer, buffer_len);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ switch (tlv.id)
+ {
+ case IPSO_RR_ID_DIGITAL_OUTPUT_STATE:
+ {
+ p_digital_output->digital_output_state = tlv.value[0];
+ break;
+ }
+
+ case IPSO_RR_ID_DIGITAL_OUTPUT_POLARITY:
+ {
+ p_digital_output->digital_output_polarity = tlv.value[0];
+ break;
+ }
+
+ case IPSO_RR_ID_APPLICATION_TYPE:
+ {
+ p_digital_output->application_type.p_val = (char *)tlv.value;
+ p_digital_output->application_type.len = tlv.length;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+uint32_t ipso_tlv_ipso_digital_output_encode(uint8_t * p_buffer,
+ uint32_t * p_buffer_len,
+ ipso_digital_output_t * p_digital_output)
+{
+ uint32_t err_code;
+ uint32_t max_buffer = *p_buffer_len;
+ uint32_t index = 0;
+
+ lwm2m_tlv_t tlv;
+ tlv.id_type = TLV_TYPE_RESOURCE_VAL; // type is the same for all.
+
+ // Encode state.
+ lwm2m_tlv_bool_set(&tlv, p_digital_output->digital_output_state, IPSO_RR_ID_DIGITAL_OUTPUT_STATE);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode polarity.
+ lwm2m_tlv_bool_set(&tlv, p_digital_output->digital_output_polarity, IPSO_RR_ID_DIGITAL_OUTPUT_POLARITY);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode application type.
+ lwm2m_tlv_string_set(&tlv, p_digital_output->application_type, IPSO_RR_ID_APPLICATION_TYPE);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ *p_buffer_len = index;
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.h
new file mode 100644
index 0000000..e2c1228
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/ipso_objects_tlv.h
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file lwm2m_objects_tlv.h
+ *
+ * @defgroup iot_sdk_ipso_objects_tlv IPSO Smart Object TLV encoder and decoder API
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief IPSO Smart Object TLV encoder and decoder API.
+ */
+
+#ifndef IPSO_OBJECTS_TLV_H__
+#define IPSO_OBJECTS_TLV_H__
+
+#include <stdint.h>
+#include "ipso_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Decode an IPSO digital output object from a TLV byte buffer.
+ *
+ * @note Resource values NOT found in the tlv will not be altered.
+ *
+ * @warning lwm2m_string_t and lwm2m_opaque_t values will point to the byte buffer and needs
+ * to be copied by the application before the byte buffer is freed.
+ *
+ * @param[out] p_digital_output Pointer to a LWM2M server object to be filled by the decoded TLVs.
+ * @param[in] p_buffer Pointer to the TLV byte buffer to be decoded.
+ * @param[in] buffer_len Size of the buffer to be decoded.
+ *
+ * @retval NRF_SUCCESS If decoding was successfull.
+ */
+uint32_t ipso_tlv_ipso_digital_output_decode(ipso_digital_output_t * p_digital_output,
+ uint8_t * p_buffer,
+ uint32_t buffer_len);
+
+/**@brief Encode an IPSO digital output object to a TLV byte buffer.
+ *
+ * @param[out] p_buffer Pointer to a byte buffer to be used to fill the encoded TLVs.
+ * @param[inout] p_buffer_len Value by reference inicating the size of the buffer provided.
+ * Will return the number of used bytes on return.
+ * @param[in] p_digital_output Pointer to the IPSO digital output object to be encoded into TLVs.
+ *
+ * @retval NRF_SUCCESS If the encoded was successfull.
+ */
+uint32_t ipso_tlv_ipso_digital_output_encode(uint8_t * p_buffer,
+ uint32_t * p_buffer_len,
+ ipso_digital_output_t * p_digital_output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IPSO_OBJECTS_TLV_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c
new file mode 100644
index 0000000..bc022f1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c
@@ -0,0 +1,885 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "lwm2m_api.h"
+#include "lwm2m_register.h"
+#include "lwm2m_bootstrap.h"
+#include "sdk_os.h"
+#include "lwm2m.h"
+#include "sdk_config.h"
+
+#if LWM2M_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME lwm2m
+
+#define NRF_LOG_LEVEL LWM2M_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR LWM2M_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR LWM2M_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define LWM2M_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define LWM2M_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define LWM2M_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define LWM2M_ENTRY() LWM2M_TRC(">> %s", __func__)
+#define LWM2M_EXIT() LWM2M_TRC("<< %s", __func__)
+
+#else // LWM2M_CONFIG_LOG_ENABLED
+
+#define LWM2M_TRC(...) /**< Disables traces. */
+#define LWM2M_DUMP(...) /**< Disables dumping of octet streams. */
+#define LWM2M_ERR(...) /**< Disables error logs. */
+
+#define LWM2M_ENTRY(...)
+#define LWM2M_EXIT(...)
+
+#endif // LWM2M_CONFIG_LOG_ENABLED
+
+#if (LWM2M_CONFIG_LOG_ENABLED != 0)
+
+static uint8_t op_desc_idx_lookup(uint8_t bitmask)
+{
+ for (uint8_t i = 0; i < 8; i++)
+ {
+ if ((bitmask > i) == 0x1)
+ {
+ return i;
+ }
+ }
+
+ // If no bits where set in the bitmask.
+ return 0;
+}
+
+static const char m_operation_desc[8][9] = {
+ "NONE",
+ "READ",
+ "WRITE",
+ "EXECUTE",
+ "DELETE",
+ "CREATE",
+ "DISCOVER",
+ "OBSERVE"
+};
+
+#endif
+
+SDK_MUTEX_DEFINE(m_lwm2m_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+
+static lwm2m_object_prototype_t * m_objects[LWM2M_COAP_HANDLER_MAX_OBJECTS];
+static lwm2m_instance_prototype_t * m_instances[LWM2M_COAP_HANDLER_MAX_INSTANCES];
+static uint16_t m_num_objects;
+static uint16_t m_num_instances;
+
+static void coap_error_handler(uint32_t error_code, coap_message_t * p_message)
+{
+ LWM2M_ERR("[CoAP]: Unhandled coap message recieved. Error code: %lu", error_code);
+}
+
+static void internal_coap_handler_init(void)
+{
+ memset(m_objects, 0, sizeof(m_objects));
+ memset(m_instances, 0, sizeof(m_instances));
+
+ m_num_objects = 0;
+ m_num_instances = 0;
+}
+
+
+static bool numbers_only(const char * p_str, uint16_t str_len)
+{
+ for (uint16_t i = 0; i < str_len; i++)
+ {
+ if (isdigit(p_str[i]) == 0)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static uint32_t instance_resolve(lwm2m_instance_prototype_t ** p_instance,
+ uint16_t object_id,
+ uint16_t instance_id)
+{
+ for (int i = 0; i < m_num_instances; ++i)
+ {
+ if (m_instances[i]->object_id == object_id &&
+ m_instances[i]->instance_id == instance_id)
+ {
+ if (m_instances[i]->callback == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ *p_instance = m_instances[i];
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+static uint32_t object_resolve(lwm2m_object_prototype_t ** p_instance,
+ uint16_t object_id)
+{
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ if (m_objects[i]->object_id == object_id)
+ {
+ if (m_objects[i]->callback == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ *p_instance = m_objects[i];
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+static uint32_t op_code_resolve(lwm2m_instance_prototype_t * p_instance,
+ uint16_t resource_id,
+ uint8_t * operation)
+{
+ uint8_t * operations = (uint8_t *) p_instance + p_instance->operations_offset;
+ uint16_t * operations_ids = (uint16_t *)((uint8_t *) p_instance +
+ p_instance->resource_ids_offset);
+
+ for (int j = 0; j < p_instance->num_resources; ++j)
+ {
+ if (operations_ids[j] == resource_id)
+ {
+ *operation = operations[j];
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+static uint32_t internal_request_handle(coap_message_t * p_request,
+ uint16_t * p_path,
+ uint8_t path_len)
+{
+ uint32_t err_code;
+ uint8_t operation = LWM2M_OPERATION_CODE_NONE;
+ uint32_t content_type = 0;
+
+ err_code = coap_message_ct_mask_get(p_request, &content_type);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ /**
+ * TODO: the methods should check if we have read / write / execute rights
+ * through ACL and resource operations
+ */
+
+ switch (p_request->header.code)
+ {
+ case COAP_CODE_GET:
+ {
+ LWM2M_TRC("[CoAP]: CoAP GET request");
+ if (content_type == COAP_CT_APP_LINK_FORMAT) // Discover
+ {
+ operation = LWM2M_OPERATION_CODE_DISCOVER;
+ }
+ else // Read
+ {
+ operation = LWM2M_OPERATION_CODE_READ;
+ }
+ break;
+ }
+
+ case COAP_CODE_PUT:
+ {
+ operation = LWM2M_OPERATION_CODE_WRITE;
+ break;
+ }
+
+ case COAP_CODE_POST:
+ {
+ operation = LWM2M_OPERATION_CODE_WRITE;
+ break;
+ }
+
+ case COAP_CODE_DELETE:
+ {
+ operation = LWM2M_OPERATION_CODE_DELETE;
+ break;
+ }
+
+ default:
+ break; // Maybe send response with unsupported method not allowed?
+ }
+
+ err_code = NRF_ERROR_NOT_FOUND;
+
+ switch (path_len)
+ {
+ case 0:
+ {
+ if (operation == LWM2M_OPERATION_CODE_DELETE)
+ {
+ LWM2M_TRC("[CoAP]: >> %s root /",
+ m_operation_desc[op_desc_idx_lookup(operation)]);
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = lwm2m_coap_handler_root(LWM2M_OPERATION_CODE_DELETE, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s root /",
+ m_operation_desc[op_desc_idx_lookup(operation)]);
+ }
+ break;
+ }
+
+ case 1:
+ {
+ LWM2M_TRC("[CoAP]: >> %s object /%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0]);
+
+ lwm2m_object_prototype_t * p_object;
+
+ err_code = object_resolve(&p_object, p_path[0]);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_object->callback(p_object, LWM2M_INVALID_INSTANCE, operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s object /%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+
+ break;
+ }
+
+ case 2:
+ {
+ LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1]);
+
+ lwm2m_instance_prototype_t * p_instance;
+
+ err_code = instance_resolve(&p_instance, p_path[0], p_path[1]);
+ if (err_code == NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_instance->callback(p_instance, LWM2M_INVALID_RESOURCE, operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s instance /%u/%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ break;
+ }
+
+ // Bootstrap can write to non-existing instances
+ if (err_code == NRF_ERROR_NOT_FOUND &&
+ operation == LWM2M_OPERATION_CODE_WRITE &&
+ p_request->header.code == COAP_CODE_PUT)
+ {
+ LWM2M_TRC("[CoAP]: >> %s object /%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1]);
+
+ lwm2m_object_prototype_t * p_object;
+
+ err_code = object_resolve(&p_object, p_path[0]);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_object->callback(p_object, p_path[1], operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s object /%u/%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ }
+
+ if (err_code == NRF_ERROR_NOT_FOUND &&
+ operation == LWM2M_OPERATION_CODE_WRITE &&
+ p_request->header.code == COAP_CODE_POST)
+ {
+ LWM2M_TRC("[CoAP]: >> CREATE object /%u/%u/",
+ p_path[0],
+ p_path[1]);
+
+ lwm2m_object_prototype_t * p_object;
+
+ err_code = object_resolve(&p_object, p_path[0]);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_object->callback(p_object, p_path[1], LWM2M_OPERATION_CODE_CREATE, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << CREATE object /%u/%u/, result: %s",
+ p_path[0],
+ p_path[1],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ break;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (operation == LWM2M_OPERATION_CODE_DELETE)
+ {
+ // Deleting resources within an instance not allowed.
+ break;
+ }
+
+ if (p_request->header.code == COAP_CODE_POST)
+ {
+ for (int i = 0; i < m_num_instances; ++i)
+ {
+ if ((m_instances[i]->object_id == p_path[0]) &&
+ (m_instances[i]->instance_id == p_path[1]))
+ {
+ if (m_instances[i]->callback == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+
+ uint8_t resource_operation = 0;
+ err_code = op_code_resolve(m_instances[i], p_path[2], &resource_operation);
+
+ if (err_code != NRF_SUCCESS)
+ break;
+
+ if ((resource_operation & LWM2M_OPERATION_CODE_EXECUTE) > 0)
+ {
+ operation = LWM2M_OPERATION_CODE_EXECUTE;
+ }
+
+ if ((resource_operation & LWM2M_OPERATION_CODE_WRITE) > 0)
+ {
+ operation = LWM2M_OPERATION_CODE_WRITE;
+ }
+
+ LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ m_instances[i]->object_id,
+ m_instances[i]->instance_id,
+ p_path[2]);
+
+ LWM2M_MUTEX_UNLOCK();
+
+ (void)m_instances[i]->callback(m_instances[i],
+ p_path[2],
+ operation,
+ p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ err_code = NRF_SUCCESS;
+
+ LWM2M_TRC("[CoAP]: << %s instance /%u/%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ m_instances[i]->object_id,
+ m_instances[i]->instance_id,
+ p_path[2]);
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ p_path[2]);
+
+ lwm2m_instance_prototype_t * p_instance;
+
+ err_code = instance_resolve(&p_instance, p_path[0], p_path[1]);
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_instance->callback(p_instance, p_path[2], operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s instance /%u/%u/%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ p_path[2],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return err_code;
+}
+
+
+static uint32_t lwm2m_coap_handler_handle_request(coap_message_t * p_request)
+{
+ LWM2M_ENTRY();
+
+ uint16_t index;
+ uint16_t path[3];
+ char * endptr;
+
+ bool is_numbers_only = true;
+ uint16_t path_index = 0;
+ uint32_t err_code = NRF_SUCCESS;
+
+ LWM2M_MUTEX_LOCK();
+
+ for (index = 0; index < p_request->options_count; index++)
+ {
+ if (p_request->options[index].number == COAP_OPT_URI_PATH)
+ {
+ uint16_t option_len = p_request->options[index].length;
+ bool numbers = numbers_only((char *)p_request->options[index].p_data,
+ option_len);
+
+ if (numbers)
+ {
+ // Declare a temporary array that is 1 byte longer than the
+ // option data in order to leave space for a terminating character.
+ uint8_t option_data[option_len + 1];
+ // Set the temporary array to zero.
+ memset(option_data, 0, sizeof(option_data));
+ // Copy the option data string to the temporary array.
+ memcpy(option_data, p_request->options[index].p_data, option_len);
+
+ // Convert the zero-terminated string to a long int value.
+ path[path_index] = strtol((char *)option_data, &endptr, 10);
+
+ ++path_index;
+
+ if (endptr == ((char *)option_data))
+ {
+ err_code = NRF_ERROR_NOT_FOUND;
+ break;
+ }
+
+ if (endptr != ((char *)option_data + option_len))
+ {
+ err_code = NRF_ERROR_NOT_FOUND;
+ break;
+ }
+ }
+ else
+ {
+ is_numbers_only = false;
+ break;
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (is_numbers_only == true)
+ {
+ err_code = internal_request_handle(p_request, path, path_index);
+ }
+ else
+ {
+ // If uri path did not consist of numbers only.
+ char * requested_uri = NULL;
+ for (index = 0; index < p_request->options_count; index++)
+ {
+ if (p_request->options[index].number == COAP_OPT_URI_PATH)
+ {
+ requested_uri = (char *)p_request->options[index].p_data;
+
+ // Stop on first URI hit.
+ break;
+ }
+ }
+
+ if (requested_uri == NULL)
+ {
+ err_code = NRF_ERROR_NOT_FOUND;
+ }
+ else
+ {
+ // Try to look up if there is a match with object with an alias name.
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ if (m_objects[i]->object_id == LWM2M_NAMED_OBJECT)
+ {
+ size_t size = strlen(m_objects[i]->p_alias_name);
+ if ((strncmp(m_objects[i]->p_alias_name, requested_uri, size) == 0))
+ {
+ if (m_objects[i]->callback == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = m_objects[i]->callback(m_objects[i],
+ LWM2M_INVALID_INSTANCE,
+ LWM2M_OPERATION_CODE_NONE,
+ p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ break;
+ }
+ }
+ else
+ {
+ // This is not a name object, return error code.
+ err_code = NRF_ERROR_NOT_FOUND;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ LWM2M_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t lwm2m_coap_handler_instance_add(lwm2m_instance_prototype_t * p_instance)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_instance);
+
+ LWM2M_MUTEX_LOCK();
+
+ if (m_num_instances == LWM2M_COAP_HANDLER_MAX_INSTANCES)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NO_MEM;
+ }
+
+ m_instances[m_num_instances] = p_instance;
+ ++m_num_instances;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_coap_handler_instance_delete(lwm2m_instance_prototype_t * p_instance)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_instance);
+
+ LWM2M_MUTEX_LOCK();
+
+ for (int i = 0; i < m_num_instances; ++i)
+ {
+ if ((m_instances[i]->object_id == p_instance->object_id) &&
+ (m_instances[i]->instance_id == p_instance->instance_id))
+ {
+ // Move current last entry into this index position, and trim down the length.
+ // If this is the last element, it cannot be accessed because the m_num_instances
+ // count is 0.
+ m_instances[i] = m_instances[m_num_instances - 1];
+ --m_num_instances;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+uint32_t lwm2m_coap_handler_object_add(lwm2m_object_prototype_t * p_object)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_object);
+
+ LWM2M_MUTEX_LOCK();
+
+ if (m_num_objects == LWM2M_COAP_HANDLER_MAX_INSTANCES)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NO_MEM;
+ }
+
+ m_objects[m_num_objects] = p_object;
+ ++m_num_objects;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_coap_handler_object_delete(lwm2m_object_prototype_t * p_object)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_object);
+
+ LWM2M_MUTEX_LOCK();
+
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ if ( m_objects[i]->object_id == p_object->object_id)
+ {
+ // Move current last entry into this index position, and trim down the length.
+ // If this is the last element, it cannot be accessed because the m_num_objects
+ // count is 0.
+ m_objects[i] = m_objects[m_num_objects - 1];
+ --m_num_objects;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+uint32_t lwm2m_coap_handler_gen_link_format(uint8_t * p_buffer, uint16_t * p_buffer_len)
+{
+
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_buffer_len);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint16_t buffer_index = 0;
+ uint8_t * p_string_buffer;
+ uint16_t buffer_max_size;
+
+ uint8_t dry_run_buffer[16];
+ bool dry_run = false;
+ uint16_t dry_run_size = 0;
+
+ if (p_buffer == NULL)
+ {
+ // Dry-run only, in order to calculate the size of the needed buffer.
+ dry_run = true;
+ p_string_buffer = dry_run_buffer;
+ buffer_max_size = sizeof(dry_run_buffer);
+ }
+ else
+ {
+ p_string_buffer = p_buffer;
+ buffer_max_size = *p_buffer_len;
+ }
+
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ // We need more than 3 chars to write a new link
+ if (buffer_max_size - buffer_index <= 3)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NO_MEM;
+ }
+
+ uint16_t curr_object = m_objects[i]->object_id;
+
+ if (curr_object == LWM2M_NAMED_OBJECT)
+ {
+ // Skip this object as it is a named object.
+ continue;
+ }
+
+ bool instance_present = false;
+ for (int j = 0; j < m_num_instances; ++j)
+ {
+ if (m_instances[j]->object_id == curr_object)
+ {
+ instance_present = true;
+
+ buffer_index += snprintf((char *)&p_string_buffer[buffer_index],
+ buffer_max_size - buffer_index,
+ "</%u/%u>,",
+ m_instances[j]->object_id,
+ m_instances[j]->instance_id);
+ if (dry_run == true)
+ {
+ dry_run_size += buffer_index;
+ buffer_index = 0;
+ }
+ }
+ }
+
+ if (!instance_present)
+ {
+ buffer_index += snprintf((char *)&p_string_buffer[buffer_index],
+ buffer_max_size - buffer_index,
+ "</%u>,",
+ curr_object);
+ if (dry_run == true)
+ {
+ dry_run_size += buffer_index;
+ buffer_index = 0;
+ }
+ }
+ }
+
+ if (dry_run == true)
+ {
+ *p_buffer_len = dry_run_size - 1;
+ }
+ else
+ {
+ *p_buffer_len = buffer_index - 1; // Remove the last comma
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_init(void)
+{
+ SDK_MUTEX_INIT(m_lwm2m_mutex);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint32_t err_code;
+
+ err_code = internal_lwm2m_register_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ err_code = internal_lwm2m_bootstrap_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ err_code = coap_error_handler_register(coap_error_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ internal_coap_handler_init();
+
+ err_code = coap_request_handler_register(lwm2m_coap_handler_handle_request);
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.h
new file mode 100644
index 0000000..fe03b4d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.h
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file lwm2m.h
+ *
+ * @defgroup iot_sdk_lwm2m_api LWM2M library private definitions.
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief LWM2M library private definitions.
+ */
+
+#ifndef LWM2M_H__
+#define LWM2M_H__
+
+#include "stdint.h"
+#include "stdbool.h"
+#include "coap_message.h"
+#include "coap_codes.h"
+#include "sdk_config.h"
+#include "sdk_os.h"
+#include "iot_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup iot_coap_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 the need to use an alternative architecture arises.
+ * @{
+ */
+#define LWM2M_MUTEX_LOCK() SDK_MUTEX_LOCK(m_lwm2m_mutex) /**< Lock module using mutex */
+#define LWM2M_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_lwm2m_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.
+ * LWM2M_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
+ *
+ * @{
+ */
+#if (LWM2M_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_LWM2M_ERR_BASE); \
+ }
+#else
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif // LWM2M_DISABLE_API_PARAM_CHECK
+
+#define LWM2M_REQUEST_TYPE_BOOTSTRAP 1
+#define LWM2M_REQUEST_TYPE_REGISTER 2
+#define LWM2M_REQUEST_TYPE_UPDATE 3
+#define LWM2M_REQUEST_TYPE_DEREGISTER 4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_api.h
new file mode 100644
index 0000000..444c3e5
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_api.h
@@ -0,0 +1,426 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file lwm2m_api.h
+*
+* @defgroup iot_sdk_lwm2m_api LWM2M Application Programming Interface
+* @ingroup iot_sdk_lwm2m
+* @{
+* @brief Public API of Nordic's LWM2M implementation.
+*/
+#ifndef LWM2M_API_H__
+#define LWM2M_API_H__
+
+#include <stdint.h>
+
+#include "lwm2m.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@addtogroup LWM2M_opcodes Types
+ * @{
+ * @brief LWMW2M Bootstrap type definitions.
+ */
+
+/**@brief LWM2M remote structure type. */
+typedef coap_remote_t lwm2m_remote_t;
+
+/**@brief LWM2M time type. */
+typedef uint32_t lwm2m_time_t;
+
+/**@brief LWM2M string type. */
+typedef struct
+{
+ char * p_val; /**< Pointer to the value of the string data. */
+ uint32_t len; /**< Length of p_val. */
+} lwm2m_string_t;
+
+/**@brief LWM2M opaque type. */
+typedef struct
+{
+ uint8_t * p_val; /**< Pointer to the value of the opaque data. */
+ uint32_t len; /**< Length of p_val. */
+} lwm2m_opaque_t;
+
+/**@brief Application notification callback types. */
+typedef enum
+{
+ LWM2M_NOTIFCATION_TYPE_BOOTSTRAP, /**< Notification from a bootstrap request. */
+ LWM2M_NOTIFCATION_TYPE_REGISTER, /**< Notification from a register request. */
+ LWM2M_NOTIFCATION_TYPE_UPDATE, /**< Notification from a update request. */
+ LWM2M_NOTIFCATION_TYPE_DEREGISTER /**< Notification from a deregister request. */
+} lwm2m_notification_type_t;
+
+/**@brief LWM2M server configuration type. */
+typedef struct
+{
+ uint32_t lifetime; /** Lifetime parameter **/
+ uint64_t msisdn; /** SMS number MSISDN **/
+ uint8_t lwm2m_version_major; /** LWM2M major version number **/
+ uint8_t lwm2m_version_minor; /** LWM2M miner version number **/
+ lwm2m_string_t binding;
+} lwm2m_server_config_t;
+
+/**@brief LWM2M client identity types. */
+typedef enum
+{
+ LWM2M_CLIENT_ID_TYPE_UUID = 36,
+ LWM2M_CLIENT_ID_TYPE_IMEI = 15,
+ LWM2M_CLIENT_ID_TYPE_ESN = 8,
+ LWM2M_CLIENT_ID_TYPE_MEID = 14
+} lwm2m_client_identity_type_t;
+
+/**@brief LWM2M identity string.
+ *
+ * @details Using the string representation of UUID/OPS/OS/IMEI/ESN/MEID.
+ *
+ * @note: OPS- and OS URN are not currently supported.
+ */
+typedef union
+{
+ char uuid[36];
+ char imei[15];
+ char esn[8];
+ char meid[14];
+} lwm2m_identity_string_t;
+
+/**@brief LWM2M client identity structure type. */
+typedef struct
+{
+ lwm2m_identity_string_t value;
+ lwm2m_client_identity_type_t type;
+} lwm2m_client_identity_t;
+/**@} */
+
+/**@addtogroup LWM2M_defines Defines
+ * @{
+ * @brief LWMW2M operation code and invalid object/instance definitions.
+ */
+
+/**
+ * @warning The invalid resource and instance are not stated by the lwm2m spec as reserved and will
+ * cause issues if instances or resources with these IDs is added.
+ */
+#define LWM2M_NAMED_OBJECT 65535 /**< Flag to indicate that the object does not use Integer as object id. */
+#define LWM2M_INVALID_RESOURCE 65535 /**< Invalid Resource ID. */
+#define LWM2M_INVALID_INSTANCE 65535 /**< Invalid Instance ID. */
+
+#define LWM2M_OPERATION_CODE_NONE 0x00 /**< Bit mask for LWM2M no operation. */
+#define LWM2M_OPERATION_CODE_READ 0x01 /**< Bit mask for LWM2M read operation. */
+#define LWM2M_OPERATION_CODE_WRITE 0x02 /**< Bit mask for LWM2M write operation. */
+#define LWM2M_OPERATION_CODE_EXECUTE 0x04 /**< Bit mask for LWM2M execute operation. */
+#define LWM2M_OPERATION_CODE_DELETE 0x08 /**< Bit mask for LWM2M delete operation. */
+#define LWM2M_OPERATION_CODE_CREATE 0x10 /**< Bit mask for LWM2M create operation. */
+#define LWM2M_OPERATION_CODE_DISCOVER 0x20 /**< Bit mask for LWM2M discover operation. */
+#define LWM2M_OPERATION_CODE_OBSERVE 0x40 /**< Bit mask for LWM2M observe operation. */
+/**@} */
+
+/**@cond */
+// Forward declare structs.
+typedef struct lwm2m_object_prototype_t lwm2m_object_prototype_t;
+typedef struct lwm2m_instance_prototype_t lwm2m_instance_prototype_t;
+/**@endcond */
+
+/**@brief Callback function upon requests on a given LWM2M resource instance.
+ *
+ * @details Will be called when the request is for an instance Ex. /0/1.
+ *
+ * If no instance could be located the object callback will be called.
+ * The instance_id corresponds to the one in the URI-patch in the CoAP request and may be used to
+ * create a new instance. If the value of resource_id is set to LWM2M_INVALID_RESOURCE the callback
+ * should treated it as a call to the instance instead of a resource inside of the instance.
+ *
+ * If a resource has been found p_instance pointer will be set, else it will be NULL.
+ *
+ * @param[in] p_instance Pointer to the located resource if it already exists.
+ * @param[in] resource_id Id of the resource requested.
+ * @param[in] op_code Opcode of the request. Values of the opcodes are defined
+ * in \ref LWM2M_opcodes.
+ * @param[in] p_request Pointer to the CoAP request message.
+ *
+ * @retval NRF_SUCCESS Will always return success.
+ */
+typedef uint32_t (*lwm2m_instance_callback_t)(lwm2m_instance_prototype_t * p_instance,
+ uint16_t resource_id,
+ uint8_t op_code,
+ coap_message_t * p_request);
+
+/**@brief Callback function upon request on a given LWM2M object or instance create.
+ *
+ * @details Will be called when the request is for an object Ex: /0 or /0/1 an instance and the
+ * op_code is CREATE. Depending on the CoAP request code the user might create an instance
+ * or just return the tlv of current instances. If the value of instance_id is set to
+ * LWM2M_INVALID_INSTANCE the callback should treated it as a call to the instance instead
+ * of an instance of the object.
+ *
+ * @param[in] p_object Pointer to the located object.
+ * @param[in] instance_id Id of the instance requested.
+ * @param[in] op_code Opcode of the request. Values of the opcodes are defined
+ * in \ref LWM2M_opcodes.
+ * @param[in] p_request Pointer to the CoAP request message.
+ *
+ * @retval NRF_SUCCESS Will always return success.
+ */
+typedef uint32_t (*lwm2m_object_callback_t)(lwm2m_object_prototype_t * p_object,
+ uint16_t instance_id,
+ uint8_t op_code,
+ coap_message_t * p_request);
+
+/**@brief LWM2M object prototype structure.
+ *
+ * @details Each instance will have this structure in the front of its instance structure.
+ * The object is used to have a common way of looking up its object id and callback
+ * structure for each of the inherited. As there is no instance of the objects themselves,
+ * the prototype is used as a meta object in order to have a common set of functions
+ * for all instances of a object kind.
+ */
+struct lwm2m_object_prototype_t
+{
+ uint16_t object_id; /**< Identifies the object. */
+ lwm2m_object_callback_t callback; /**< Called when for request to /0 (object) and /0/1 if instance 1 is not found. */
+ char * p_alias_name; /**< Alternative name of the resource, used when LWM2M_NAMED_OBJECT is set. */
+};
+
+/**@brief LWM2M instance structure.
+ *
+ * @details Prototype for the instance object, this enables us to search through the instances
+ * without knowing the type.
+ */
+struct lwm2m_instance_prototype_t
+{
+ uint16_t object_id; /**< Identifies what object this instance belongs to. */
+ uint16_t instance_id; /**< Used to identify the instance. */
+ uint16_t num_resources; /**< Number of resources MUST equal number of members in the lwm2m instance, sizeof resource_access and sizeof resource_ids. */
+ uint8_t operations_offset; /**< Internal use. */
+ uint8_t resource_ids_offset; /**< Internal use. */
+ lwm2m_instance_callback_t callback; /**< Called when an operation is done on this instance. */
+};
+
+/**@brief Callback interface from the enabler interface (bootstrap/register) to the application.
+ *
+ * @warning This is an interface function. MUST BE IMPLEMENTED BY APPLICATION.
+ *
+ * @param[in] type Notification type. The types are defined in \ref lwm2m_notification_type_t.
+ * @param[in] p_remote remote that answered the request
+ * @param[in] coap_code coap op code from the response
+ *
+ * @retval NRF_SUCCESS If the client application handled the notification successfully.
+ */
+uint32_t lwm2m_notification(lwm2m_notification_type_t type,
+ lwm2m_remote_t * p_remote,
+ uint8_t coap_code);
+
+/**@brief CoAP Request handler for the root of the object/instance/resource hierarchy.
+ *
+ * @details The function is called when a request is for the lwm2m root (ie no object instance
+ * or resource).
+ *
+ * @warning This is an interface function. MUST BE IMPLEMENTED BY APPLICATION.
+ *
+ * @param[in] op_code LWM2M operation code.
+ * @param[in] p_request Pointer to CoAP request message.
+ *
+ * @retval NRF_SUCCESS If the handler processed the request successfully.
+ */
+uint32_t lwm2m_coap_handler_root(uint8_t op_code, coap_message_t * p_request);
+
+/**@brief Initialize LWM2M library.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ */
+uint32_t lwm2m_init(void);
+
+/**@brief Send bootstrap request to a remote bootstrap server.
+ *
+ * @details Sends a bootstrap request with specified ID to the specified remote, calls the
+ * lwm2m_notification with answer from the bootstrap server.
+ *
+ * @param[in] p_remote Pointer to the structure holding connection information of the remote
+ * LWM2M bootstrap server.
+ * @param[in] p_id Pointer to the structure holding the Id of the client.
+ * @param[in] local_port Port number of the local port to be used to send the bootstrap request.
+ *
+ * @retval NRF_SUCCESS If bootstrap request to the LWM2M bootstrap server was sent successfully.
+ * @retval NRF_ERROR_NULL If one of the parameters was a NULL pointer.
+ */
+uint32_t lwm2m_bootstrap(lwm2m_remote_t * p_remote,
+ lwm2m_client_identity_t * p_id,
+ uint16_t local_port);
+
+/**@brief Register with a remote LWM2M server.
+ *
+ * @param[in] p_remote Pointer to the structure holding connection information
+ * of the remote LWM2M server.
+ * @param[in] p_id Pointer to the structure holding the Id of the client.
+ * @param[in] p_config Registration parameters.
+ * @param[in] local_port Port number of the local port to be used to send the
+ * register request.
+ * @param[in] p_link_format_string Pointer to a link format encoded string to send in the
+ * register request.
+ * @param[in] link_format_len Length of the link format string provided.
+ *
+ * @retval NRF_SUCCESS If registration request to the LWM2M server was sent out successfully.
+ */
+uint32_t lwm2m_register(lwm2m_remote_t * p_remote,
+ lwm2m_client_identity_t * p_id ,
+ lwm2m_server_config_t * p_config,
+ uint16_t local_port,
+ uint8_t * p_link_format_string,
+ uint16_t link_format_len);
+
+/**@brief Update a registration with a remote server.
+ *
+ * @param[in] p_remote Pointer to the structure holding connection information of the remote
+ * LWM2M server.
+ * @param[in] p_config Registration parameters.
+ * @param[in] local_port Port number of the local port to be used to send the update request.
+ *
+ * @retval NRF_SUCCESS If update request to the LWM2M server was sent out successfully.
+ */
+uint32_t lwm2m_update(lwm2m_remote_t * p_remote,
+ lwm2m_server_config_t * p_config,
+ uint16_t local_port);
+
+/**@brief Deregister from a remote server.
+ *
+ * @param[in] p_remote Pointer to the structure holding connection information of the remote
+ * LWM2M server.
+ * @param[in] local_port Port number of the local port to be used to send the deregister request.
+ *
+ * @retval NRF_SUCCESS If deregister request to the LWM2M server was sent out successfully.
+ */
+uint32_t lwm2m_deregister(lwm2m_remote_t * p_remote, uint16_t local_port);
+
+/**@brief Add an instance to coap_handler in order to match requests to the given instance.
+ *
+ * @details Add a new LWM2M instance to the coap_handler. The application MUST initialize
+ * and allocate the additional data in the struct.
+ *
+ * @param[in] p_instance Pointer to the instance to add.
+ *
+ * @retval NRF_SUCCESS If registration was successful.
+ * @retval NRF_ERROR_NO_MEM If the module was not able to add the instance. Verify that
+ * the LWM2M_COAP_HANDLER_MAX_INSTANCES setting in sdk_config.h
+ * has a correct value.
+ */
+uint32_t lwm2m_coap_handler_instance_add(lwm2m_instance_prototype_t * p_instance);
+
+/**@brief Delete an instance from coap_handler in order to stop matching requests to the given
+ * instance.
+ *
+ * @param[in] p_instance Pointer to the instance to delete.
+ *
+ * @retval NRF_SUCCESS If unregistration was a success.
+ * @retval NRF_ERROR_NOT_FOUND If the given instance was not located.
+ */
+uint32_t lwm2m_coap_handler_instance_delete(lwm2m_instance_prototype_t * p_instance);
+
+/**@brief Add an object to coap_handler in order to match requests to the given object.
+ *
+ * @details Add a new LWM2M object to the coap_handler. The application MUST initialize
+ * and allocate the additional data in the struct.
+ *
+ * @param[in] p_object Pointer to the object to add.
+ *
+ * @retval NRF_SUCCESS If registration was successful.
+ * @retval NRF_ERROR_NO_MEM If the module was not able to add the object. Verify that
+ * the LWM2M_COAP_HANDLER_MAX_OBJECTS setting in sdk_config.h
+ * has a correct value.
+ */
+uint32_t lwm2m_coap_handler_object_add(lwm2m_object_prototype_t * p_object);
+
+/**@brief Delete an object from coap_handler in order to stop matching requests to the given
+ * object.
+ *
+ * @param[in] p_object Pointer to the object to delete.
+ *
+ * @retval NRF_SUCCESS If unregistration was a success.
+ * @retval NRF_ERROR_NOT_FOUND If the given object was not located.
+ */
+uint32_t lwm2m_coap_handler_object_delete(lwm2m_object_prototype_t * p_object);
+
+/**@brief Generate link format string based on registered objects and instances.
+ *
+ * @note For generation of links to work properly it is required that objects is added
+ * before instances.
+ *
+ * @param[inout] p_buffer Pointer to a buffer to fill with link format encoded string. If
+ * a NULL pointer is provided the function will dry-run the function
+ * in order to calculate how much memory that is needed for the link
+ * format string.
+ * @param[inout] p_buffer_len As input used to indicate the length of the buffer. It will return the
+ * used amount of buffer length by reference in response. If NULL pointer
+ * is provided for p_buffer, the value by reference output will be the number
+ * of bytes needed to generate the link format string.
+ *
+ * @retval NRF_SUCCESS If generation of link format string was successful.
+ * @retval NRF_ERROR_NO_MEM If the provided memory was not large enough.
+ */
+uint32_t lwm2m_coap_handler_gen_link_format(uint8_t * p_buffer, uint16_t * p_buffer_len);
+
+/**@brief Send CoAP 2.05 Content response with the payload provided.
+ *
+ * @param[in] p_payload Pointer to the payload to send. Must not be NULL.
+ * @param[in] payload_len Size of the payload.
+ * @param[in] p_request Original CoAP request. Must not be NULL.
+ *
+ * @retval NRF_SUCCESS If the response was sent out successfully.
+ */
+uint32_t lwm2m_respond_with_payload(uint8_t * p_payload,
+ uint16_t payload_len,
+ coap_message_t * p_request);
+
+/**@brief Send CoAP response with a given CoAP message code.
+ *
+ * @param [in] code CoAP response code to send.
+ * @param [in] p_request Original CoAP request. Must not be NULL.
+ *
+ * @retval NRF_SUCCESS If the response was sent out successfully.
+ */
+uint32_t lwm2m_respond_with_code(coap_msg_code_t code, coap_message_t * p_request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_API_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.c
new file mode 100644
index 0000000..7724e10
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.c
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "lwm2m_api.h"
+#include "lwm2m_bootstrap.h"
+#include "lwm2m.h"
+#include "coap_api.h"
+#include "coap_message.h"
+#include "coap_codes.h"
+#include "sdk_config.h"
+#include "app_util.h"
+
+#if LWM2M_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME lwm2m
+
+#define NRF_LOG_LEVEL LWM2M_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR LWM2M_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR LWM2M_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+#define LWM2M_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define LWM2M_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define LWM2M_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define LWM2M_ENTRY() LWM2M_TRC(">> %s", __func__)
+#define LWM2M_EXIT() LWM2M_TRC("<< %s", __func__)
+
+#else // LWM2M_CONFIG_LOG_ENABLED
+
+#define LWM2M_TRC(...) /**< Disables traces. */
+#define LWM2M_DUMP(...) /**< Disables dumping of octet streams. */
+#define LWM2M_ERR(...) /**< Disables error logs. */
+
+#define LWM2M_ENTRY(...)
+#define LWM2M_EXIT(...)
+
+#endif // LWM2M_CONFIG_LOG_ENABLED
+
+#define LWM2M_BOOTSTRAP_URI_PATH "bs"
+
+#define TOKEN_START 0x012A
+
+static uint16_t m_token = TOKEN_START;
+
+static uint32_t internal_message_new(coap_message_t ** pp_msg,
+ coap_msg_code_t code,
+ coap_response_callback_t callback,
+ uint16_t local_port)
+{
+ uint32_t err_code;
+ coap_message_conf_t conf;
+ memset (&conf, 0, sizeof(coap_message_conf_t));
+
+ conf.type = COAP_TYPE_CON;
+ conf.code = code;
+ conf.response_callback = callback;
+ conf.port.port_number = local_port;
+
+ conf.token_len = uint16_encode(m_token, conf.token);
+
+ m_token++;
+
+ err_code = coap_message_new(pp_msg, &conf);
+
+ return err_code;
+}
+
+
+/**@brief Function to be used as callback function upon a bootstrap request. */
+static void lwm2m_bootstrap_cb(uint32_t status, void * p_arg, coap_message_t * p_message)
+{
+ LWM2M_TRC("[Bootstrap]: lwm2m_bootstrap_cb, status: %ul, coap code: %u",
+ status,
+ p_message->header.code);
+
+ (void)lwm2m_notification(LWM2M_NOTIFCATION_TYPE_BOOTSTRAP,
+ &p_message->remote,
+ p_message->header.code);
+}
+
+
+uint32_t internal_lwm2m_bootstrap_init(void)
+{
+ m_token = TOKEN_START;
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_bootstrap(lwm2m_remote_t * p_remote, lwm2m_client_identity_t * p_id, uint16_t local_port)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_remote);
+ NULL_PARAM_CHECK(p_id);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint32_t err_code;
+ coap_message_t * p_msg;
+
+ lwm2m_string_t endpoint;
+
+ endpoint.p_val = LWM2M_BOOTSTRAP_URI_PATH;
+ endpoint.len = 2;
+
+ err_code = internal_message_new(&p_msg, COAP_CODE_POST, lwm2m_bootstrap_cb, local_port);
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_remote_addr_set(p_msg, p_remote);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_opt_str_add(p_msg,
+ COAP_OPT_URI_PATH,
+ (uint8_t *)endpoint.p_val,
+ endpoint.len); // end_point length is always 2
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ char buffer[40];
+ buffer[0] = 'e';
+ buffer[1] = 'p';
+ buffer[2] = '=';
+ memcpy(buffer + 3, &p_id->value, p_id->type);
+
+ err_code = coap_message_opt_str_add(p_msg,
+ COAP_OPT_URI_QUERY,
+ (uint8_t *)buffer,
+ p_id->type + 3);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t msg_handle;
+ err_code = coap_message_send(&msg_handle, p_msg);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_delete(p_msg);
+ }
+ else
+ {
+ // If we have hit an error try to clean up.
+ // Return the original error code.
+ (void)coap_message_delete(p_msg);
+ }
+
+ LWM2M_EXIT();
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.h
new file mode 100644
index 0000000..68bdf6b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_bootstrap.h
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file lwm2m_bootstrap.h
+ *
+ * @defgroup iot_sdk_lwm2m_bootstrap_api LWM2M bootstrap API interface
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief Bootstrap API interface for the LWM2M protocol.
+ */
+
+#ifndef LWM2M_BOOTSTRAP_H__
+#define LWM2M_BOOTSTRAP_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Initialize the LWM2M register module.
+ *
+ * @details Calling this function will set the module in default state.
+ */
+uint32_t internal_lwm2m_bootstrap_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_BOOTSTRAP_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_coap_util.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_coap_util.c
new file mode 100644
index 0000000..bf7bece
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_coap_util.c
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include "coap_api.h"
+#include "coap_message.h"
+#include "coap_codes.h"
+#include "lwm2m.h"
+
+
+uint32_t lwm2m_respond_with_code(coap_msg_code_t code, coap_message_t * p_request)
+{
+ NULL_PARAM_CHECK(p_request);
+
+ // Application helper function, no need for mutex.
+ coap_message_conf_t response_config;
+ memset (&response_config, 0, sizeof(coap_message_conf_t));
+
+ if (p_request->header.type == COAP_TYPE_NON)
+ {
+ response_config.type = COAP_TYPE_NON;
+ }
+ else if (p_request->header.type == COAP_TYPE_CON)
+ {
+ response_config.type = COAP_TYPE_ACK;
+ }
+
+ // PIGGY BACKED RESPONSE
+ response_config.code = code;
+ response_config.id = p_request->header.id;
+ response_config.port.port_number = p_request->port.port_number;
+
+ // Copy token.
+ memcpy(&response_config.token[0], &p_request->token[0], p_request->header.token_len);
+ // Copy token length.
+ response_config.token_len = p_request->header.token_len;
+
+ coap_message_t * p_response;
+ uint32_t err_code = coap_message_new(&p_response, &response_config);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = coap_message_remote_addr_set(p_response, &p_request->remote);
+ if (err_code != NRF_SUCCESS)
+ {
+ (void)coap_message_delete(p_response);
+ return err_code;
+ }
+
+ memcpy(&p_response->remote, &p_request->remote, sizeof(coap_remote_t));
+
+ uint32_t msg_handle;
+ err_code = coap_message_send(&msg_handle, p_response);
+ if (err_code != NRF_SUCCESS)
+ {
+ (void)coap_message_delete(p_response);
+ return err_code;
+ }
+
+ err_code = coap_message_delete(p_response);
+
+ return err_code;
+}
+
+
+uint32_t lwm2m_respond_with_payload(uint8_t * p_payload, uint16_t payload_len, coap_message_t * p_request)
+{
+ NULL_PARAM_CHECK(p_request);
+ NULL_PARAM_CHECK(p_payload);
+
+ // Application helper function, no need for mutex.
+ coap_message_conf_t response_config;
+ memset (&response_config, 0, sizeof(coap_message_conf_t));
+
+ if (p_request->header.type == COAP_TYPE_NON)
+ {
+ response_config.type = COAP_TYPE_NON;
+ }
+ else if (p_request->header.type == COAP_TYPE_CON)
+ {
+ response_config.type = COAP_TYPE_ACK;
+ }
+
+ // PIGGY BACKED RESPONSE
+ response_config.code = COAP_CODE_205_CONTENT;
+ response_config.id = p_request->header.id;
+ response_config.port.port_number = p_request->port.port_number;
+
+ // Copy token.
+ memcpy(&response_config.token[0], &p_request->token[0], p_request->header.token_len);
+ // Copy token length.
+ response_config.token_len = p_request->header.token_len;
+
+ coap_message_t * p_response;
+ uint32_t err_code = coap_message_new(&p_response, &response_config);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = coap_message_payload_set(p_response, p_payload, payload_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ (void)coap_message_delete(p_response);
+ return err_code;
+ }
+
+ err_code = coap_message_remote_addr_set(p_response, &p_request->remote);
+ if (err_code != NRF_SUCCESS)
+ {
+ (void)coap_message_delete(p_response);
+ return err_code;
+ }
+
+ memcpy(&p_response->remote, &p_request->remote, sizeof(coap_remote_t));
+
+ uint32_t msg_handle;
+ err_code = coap_message_send(&msg_handle, p_response);
+ if (err_code != NRF_SUCCESS)
+ {
+ (void)coap_message_delete(p_response);
+ return err_code;
+ }
+
+ err_code = coap_message_delete(p_response);
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.c
new file mode 100644
index 0000000..e61a40e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.c
@@ -0,0 +1,347 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include <stddef.h>
+
+#include "lwm2m_objects.h"
+#include "lwm2m.h"
+
+//lint -e516 -save // Symbol '__INTADDR__()' has arg. type conflict
+#define LWM2M_INSTANCE_OFFSET_SET(instance, type) \
+ instance->proto.operations_offset = offsetof(type, operations); \
+ instance->proto.resource_ids_offset = offsetof(type, resource_ids);
+//lint -restore
+
+
+void lwm2m_instance_security_init(lwm2m_security_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_security_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_SECURITY;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_security_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[8] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[9] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[10] = LWM2M_OPERATION_CODE_NONE;
+ p_instance->operations[11] = LWM2M_OPERATION_CODE_NONE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_SECURITY_SERVER_URI;
+ p_instance->resource_ids[1] = LWM2M_SECURITY_BOOTSTRAP_SERVER;
+ p_instance->resource_ids[2] = LWM2M_SECURITY_SECURITY_MODE;
+ p_instance->resource_ids[3] = LWM2M_SECURITY_PUBLIC_KEY;
+ p_instance->resource_ids[4] = LWM2M_SECURITY_SERVER_PUBLIC_KEY;
+ p_instance->resource_ids[5] = LWM2M_SECURITY_SECRET_KEY;
+ p_instance->resource_ids[6] = LWM2M_SECURITY_SMS_SECURITY_MODE;
+ p_instance->resource_ids[7] = LWM2M_SECURITY_SMS_BINDING_KEY_PARAM;
+ p_instance->resource_ids[8] = LWM2M_SECURITY_SMS_BINDING_SECRET_KEY;
+ p_instance->resource_ids[9] = LWM2M_SECURITY_SERVER_SMS_NUMBER;
+ p_instance->resource_ids[10] = LWM2M_SECURITY_SHORT_SERVER_ID;
+ p_instance->resource_ids[11] = LWM2M_SECURITY_CLIENT_HOLD_OFF_TIME;
+}
+
+
+void lwm2m_instance_server_init(lwm2m_server_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_server_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_SERVER;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_server_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[5] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[6] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[7] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[8] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_SERVER_SHORT_SERVER_ID;
+ p_instance->resource_ids[1] = LWM2M_SERVER_LIFETIME;
+ p_instance->resource_ids[2] = LWM2M_SERVER_DEFAULT_MIN_PERIOD;
+ p_instance->resource_ids[3] = LWM2M_SERVER_DEFAULT_MAX_PERIOD;
+ p_instance->resource_ids[4] = LWM2M_SERVER_DISABLE;
+ p_instance->resource_ids[5] = LWM2M_SERVER_DISABLE_TIMEOUT;
+ p_instance->resource_ids[6] = LWM2M_SERVER_NOTIFY_WHEN_DISABLED;
+ p_instance->resource_ids[7] = LWM2M_SERVER_BINDING;
+ p_instance->resource_ids[8] = LWM2M_SERVER_REGISTRATION_UPDATE_TRIGGER;
+}
+
+
+void lwm2m_instance_firmware_init(lwm2m_firmware_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_firmware_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_FIRMWARE;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_firmware_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_WRITE;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_WRITE;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_FIRMWARE_PACKAGE;
+ p_instance->resource_ids[1] = LWM2M_FIRMWARE_PACKAGE_URI;
+ p_instance->resource_ids[2] = LWM2M_FIRMWARE_UPDATE;
+ p_instance->resource_ids[3] = LWM2M_FIRMWARE_STATE;
+ p_instance->resource_ids[4] = LWM2M_FIRMWARE_UPDATE_SUPPORTED_OBJECTS;
+ p_instance->resource_ids[5] = LWM2M_FIRMWARE_UPDATE_RESULT;
+}
+
+
+void lwm2m_instance_acl_init(lwm2m_acl_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_acl_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_ACL;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_acl_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[3] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_ACL_OBJECT_ID;
+ p_instance->resource_ids[1] = LWM2M_ACL_INSTANCE_ID;
+ p_instance->resource_ids[2] = LWM2M_ACL_ACL;
+ p_instance->resource_ids[3] = LWM2M_ACL_CONTROL_OWNER;
+}
+
+
+void lwm2m_instance_connectivity_monitoring_init(lwm2m_connectivity_monitoring_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_connectivity_monitoring_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_CONN_MON;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_connectivity_monitoring_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[8] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[9] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[10] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_CONN_MON_NETWORK_BEARER;
+ p_instance->resource_ids[1] = LWM2M_CONN_MON_AVAILABLE_NETWORK_BEARER;
+ p_instance->resource_ids[2] = LWM2M_CONN_MON_RADIO_SIGNAL_STRENGHT;
+ p_instance->resource_ids[3] = LWM2M_CONN_MON_LINK_QUALITY;
+ p_instance->resource_ids[4] = LWM2M_CONN_MON_IP_ADDRESSES;
+ p_instance->resource_ids[5] = LWM2M_CONN_MON_ROUTER_IP_ADRESSES;
+ p_instance->resource_ids[6] = LWM2M_CONN_MON_LINK_UTILIZATION;
+ p_instance->resource_ids[7] = LWM2M_CONN_MON_APN;
+ p_instance->resource_ids[8] = LWM2M_CONN_MON_CELL_ID;
+ p_instance->resource_ids[9] = LWM2M_CONN_MON_SMNC;
+ p_instance->resource_ids[10] = LWM2M_CONN_MON_SMCC;
+}
+
+
+void lwm2m_instance_connectivity_statistics_init(lwm2m_connectivity_statistics_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_connectivity_statistics_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_CONN_STAT;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_connectivity_statistics_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_CONN_STAT_SMS_TX_COUNTER;
+ p_instance->resource_ids[1] = LWM2M_CONN_STAT_SMS_RX_COUNTER;
+ p_instance->resource_ids[2] = LWM2M_CONN_STAT_TX_DATA;
+ p_instance->resource_ids[3] = LWM2M_CONN_STAT_RX_DATA;
+ p_instance->resource_ids[4] = LWM2M_CONN_STAT_MAX_MSG_SIZE;
+ p_instance->resource_ids[5] = LWM2M_CONN_STAT_AVG_MSG_SIZE;
+ p_instance->resource_ids[6] = LWM2M_CONN_STAT_START_RESET;
+}
+
+
+void lwm2m_instance_device_init(lwm2m_device_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_device_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_DEVICE;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_device_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[8] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[9] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[10] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[11] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[12] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[13] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[14] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[15] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+ p_instance->operations[16] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_DEVICE_MANUFACTURER;
+ p_instance->resource_ids[1] = LWM2M_DEVICE_MODEL_NUMBER;
+ p_instance->resource_ids[2] = LWM2M_DEVICE_SERIAL_NUMBER;
+ p_instance->resource_ids[3] = LWM2M_DEVICE_FIRMWARE_VERSION;
+ p_instance->resource_ids[4] = LWM2M_DEVICE_REBOOT;
+ p_instance->resource_ids[5] = LWM2M_DEVICE_FACTORY_RESET;
+ p_instance->resource_ids[6] = LWM2M_DEVICE_AVAILABLE_POWER_SOURCES;
+ p_instance->resource_ids[7] = LWM2M_DEVICE_POWER_SOURCE_VOLTAGE;
+ p_instance->resource_ids[8] = LWM2M_DEVICE_POWER_SOURCE_CURRENT;
+ p_instance->resource_ids[9] = LWM2M_DEVICE_BATTERY_LEVEL;
+ p_instance->resource_ids[10] = LWM2M_DEVICE_MEMORY_FREE;
+ p_instance->resource_ids[11] = LWM2M_DEVICE_ERROR_CODE;
+ p_instance->resource_ids[12] = LWM2M_DEVICE_RESET_ERROR_CODE;
+ p_instance->resource_ids[13] = LWM2M_DEVICE_CURRENT_TIME;
+ p_instance->resource_ids[14] = LWM2M_DEVICE_UTC_OFFSET;
+ p_instance->resource_ids[15] = LWM2M_DEVICE_TIMEZONE;
+ p_instance->resource_ids[16] = LWM2M_DEVICE_SUPPORTED_BINDINGS;
+}
+
+
+void lwm2m_instance_location_init(lwm2m_location_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_location_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_LOCATION;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_location_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_LOCATION_ALTITUDE;
+ p_instance->resource_ids[1] = LWM2M_LOCATION_LONGITUDE;
+ p_instance->resource_ids[2] = LWM2M_LOCATION_ALTITUDE;
+ p_instance->resource_ids[3] = LWM2M_LOCATION_UNCERTAINTY;
+ p_instance->resource_ids[4] = LWM2M_LOCATION_VELOCITY;
+ p_instance->resource_ids[5] = LWM2M_LOCATION_TIMESTAMP;
+}
+
+
+void lwm2m_instance_software_update_init(lwm2m_software_update_t * p_instance)
+{
+ // Set prototype variables.
+ LWM2M_INSTANCE_OFFSET_SET(p_instance, lwm2m_software_update_t);
+
+ p_instance->proto.object_id = LWM2M_OBJ_SOFTWARE_UPDATE;
+ p_instance->proto.instance_id = 0;
+ p_instance->proto.num_resources = sizeof(((lwm2m_software_update_t *)0)->operations);
+
+ // Set access types.
+ p_instance->operations[0] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[1] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[2] = LWM2M_OPERATION_CODE_WRITE;
+ p_instance->operations[3] = LWM2M_OPERATION_CODE_WRITE;
+ p_instance->operations[4] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[5] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[6] = LWM2M_OPERATION_CODE_EXECUTE;
+ p_instance->operations[7] = LWM2M_OPERATION_CODE_READ;
+ p_instance->operations[8] = (LWM2M_OPERATION_CODE_READ | LWM2M_OPERATION_CODE_WRITE);
+
+ // Set resource IDs.
+ p_instance->resource_ids[0] = LWM2M_SW_UPDATE_PKG_NAME;
+ p_instance->resource_ids[1] = LWM2M_SW_UPDATE_PKG_VERSION;
+ p_instance->resource_ids[2] = LWM2M_SW_UPDATE_PACKAGE;
+ p_instance->resource_ids[3] = LWM2M_SW_UPDATE_PACKAGE_URI;
+ p_instance->resource_ids[4] = LWM2M_SW_UPDATE_INSTALL;
+ p_instance->resource_ids[5] = LWM2M_SW_UPDATE_CHECKPOINT;
+ p_instance->resource_ids[6] = LWM2M_SW_UPDATE_UNINSTALL;
+ p_instance->resource_ids[7] = LWM2M_SW_UPDATE_UPDATE_STATE;
+ p_instance->resource_ids[8] = LWM2M_SW_UPDATE_SUPPORTED_OBJECTS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.h
new file mode 100644
index 0000000..c18917e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects.h
@@ -0,0 +1,443 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file lwm2m_objects.h
+ *
+ * @defgroup iot_sdk_lwm2m_objects OMA LWM2M objects definitions and types
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief OMA LWM2M objects definitions and types.
+ *
+ * @note The definitions used in this module are from the OMA LWM2M
+ * "Lightweight Machine to Machine Technical Specification - OMA_TS-LightweightM2M-V1_0-20131210-C".
+ * The specification could be found at http://openmobilealliance.org/.
+ */
+
+#ifndef LWM2M_OBJECTS_H__
+#define LWM2M_OBJECTS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "lwm2m_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @brief LWM2M Enabler Object IDs Appendix E */
+#define LWM2M_OBJ_SECURITY 0
+#define LWM2M_OBJ_SERVER 1
+#define LWM2M_OBJ_ACL 2
+#define LWM2M_OBJ_DEVICE 3
+#define LWM2M_OBJ_CONN_MON 4
+#define LWM2M_OBJ_FIRMWARE 5
+#define LWM2M_OBJ_LOCATION 6
+#define LWM2M_OBJ_CONN_STAT 7
+
+/* @brief LWM2M Registry Objects */
+#define LWM2M_OBJ_SOFTWARE_UPDATE 9
+
+/* LWM2M Security Resource IDs Appendix E.1 */
+#define LWM2M_SECURITY_SERVER_URI 0
+#define LWM2M_SECURITY_BOOTSTRAP_SERVER 1
+#define LWM2M_SECURITY_SECURITY_MODE 2
+#define LWM2M_SECURITY_PUBLIC_KEY 3
+#define LWM2M_SECURITY_SERVER_PUBLIC_KEY 4
+#define LWM2M_SECURITY_SECRET_KEY 5
+#define LWM2M_SECURITY_SMS_SECURITY_MODE 6
+#define LWM2M_SECURITY_SMS_BINDING_KEY_PARAM 7
+#define LWM2M_SECURITY_SMS_BINDING_SECRET_KEY 8
+#define LWM2M_SECURITY_SERVER_SMS_NUMBER 9
+#define LWM2M_SECURITY_SHORT_SERVER_ID 10
+#define LWM2M_SECURITY_CLIENT_HOLD_OFF_TIME 11
+
+
+/* LWM2M Server Resources Appendix E.2 */
+#define LWM2M_SERVER_SHORT_SERVER_ID 0
+#define LWM2M_SERVER_LIFETIME 1
+#define LWM2M_SERVER_DEFAULT_MIN_PERIOD 2
+#define LWM2M_SERVER_DEFAULT_MAX_PERIOD 3
+#define LWM2M_SERVER_DISABLE 4
+#define LWM2M_SERVER_DISABLE_TIMEOUT 5
+#define LWM2M_SERVER_NOTIFY_WHEN_DISABLED 6
+#define LWM2M_SERVER_BINDING 7
+#define LWM2M_SERVER_REGISTRATION_UPDATE_TRIGGER 8
+
+
+/* LWM2M Firmware update Resources Appendix E.6 */
+#define LWM2M_FIRMWARE_PACKAGE 0
+#define LWM2M_FIRMWARE_PACKAGE_URI 1
+#define LWM2M_FIRMWARE_UPDATE 2
+#define LWM2M_FIRMWARE_STATE 3
+#define LWM2M_FIRMWARE_UPDATE_SUPPORTED_OBJECTS 4
+#define LWM2M_FIRMWARE_UPDATE_RESULT 5
+
+#define LWM2M_FIRMWARE_STATE_IDLE 1
+#define LWM2M_FIRMWARE_STATE_DOWNLOADING 2
+#define LWM2M_FIRMWARE_STATE_DOWNLOADED 3
+
+#define LWM2M_FIRMWARE_UPDATE_RESULT_DEFAULT 0
+#define LWM2M_FIRMWARE_UPDATE_RESULT_SUCCESS 1
+#define LWM2M_FIRMWARE_UPDATE_RESULT_ERROR_STORAGE 2
+#define LWM2M_FIRMWARE_UPDATE_RESULT_ERROR_MEMORY 3
+#define LWM2M_FIRMWARE_UPDATE_RESULT_ERROR_CONN_LOST 4
+#define LWM2M_FIRMWARE_UPDATE_RESULT_ERROR_CRC 5
+#define LWM2M_FIRMWARE_UPDATE_RESULT_ERROR_UNSUPPORTED 6
+#define LWM2M_FIRMWARE_UPDATE_RESULT_ERROR_INVALID_URI 7
+
+
+/* LWM2M ACL Resources */
+#define LWM2M_ACL_OBJECT_ID 0
+#define LWM2M_ACL_INSTANCE_ID 1
+#define LWM2M_ACL_ACL 2
+#define LWM2M_ACL_CONTROL_OWNER 3
+
+/* LWM2M Connectivity Monitoring Resources */
+#define LWM2M_CONN_MON_NETWORK_BEARER 0
+#define LWM2M_CONN_MON_AVAILABLE_NETWORK_BEARER 1
+#define LWM2M_CONN_MON_RADIO_SIGNAL_STRENGHT 2
+#define LWM2M_CONN_MON_LINK_QUALITY 3
+#define LWM2M_CONN_MON_IP_ADDRESSES 4
+#define LWM2M_CONN_MON_ROUTER_IP_ADRESSES 5
+#define LWM2M_CONN_MON_LINK_UTILIZATION 6
+#define LWM2M_CONN_MON_APN 7
+#define LWM2M_CONN_MON_CELL_ID 8
+#define LWM2M_CONN_MON_SMNC 9
+#define LWM2M_CONN_MON_SMCC 10
+
+/* LWM2M Connectivity Statistics */
+#define LWM2M_CONN_STAT_SMS_TX_COUNTER 0
+#define LWM2M_CONN_STAT_SMS_RX_COUNTER 1
+#define LWM2M_CONN_STAT_TX_DATA 2
+#define LWM2M_CONN_STAT_RX_DATA 3
+#define LWM2M_CONN_STAT_MAX_MSG_SIZE 4
+#define LWM2M_CONN_STAT_AVG_MSG_SIZE 5
+#define LWM2M_CONN_STAT_START_RESET 6
+
+/* LWM2M Device */
+#define LWM2M_DEVICE_MANUFACTURER 0
+#define LWM2M_DEVICE_MODEL_NUMBER 1
+#define LWM2M_DEVICE_SERIAL_NUMBER 2
+#define LWM2M_DEVICE_FIRMWARE_VERSION 3
+#define LWM2M_DEVICE_REBOOT 4
+#define LWM2M_DEVICE_FACTORY_RESET 5
+#define LWM2M_DEVICE_AVAILABLE_POWER_SOURCES 6
+#define LWM2M_DEVICE_POWER_SOURCE_VOLTAGE 7
+#define LWM2M_DEVICE_POWER_SOURCE_CURRENT 8
+#define LWM2M_DEVICE_BATTERY_LEVEL 9
+#define LWM2M_DEVICE_MEMORY_FREE 10
+#define LWM2M_DEVICE_ERROR_CODE 11
+#define LWM2M_DEVICE_RESET_ERROR_CODE 12
+#define LWM2M_DEVICE_CURRENT_TIME 13
+#define LWM2M_DEVICE_UTC_OFFSET 14
+#define LWM2M_DEVICE_TIMEZONE 15
+#define LWM2M_DEVICE_SUPPORTED_BINDINGS 16
+
+/* LWM2M Location */
+#define LWM2M_LOCATION_LATITUDE 0
+#define LWM2M_LOCATION_LONGITUDE 1
+#define LWM2M_LOCATION_ALTITUDE 2
+#define LWM2M_LOCATION_UNCERTAINTY 3
+#define LWM2M_LOCATION_VELOCITY 4
+#define LWM2M_LOCATION_TIMESTAMP 5
+
+/* LWM2M Software update */
+#define LWM2M_SW_UPDATE_PKG_NAME 0
+#define LWM2M_SW_UPDATE_PKG_VERSION 1
+#define LWM2M_SW_UPDATE_PACKAGE 2
+#define LWM2M_SW_UPDATE_PACKAGE_URI 3
+#define LWM2M_SW_UPDATE_INSTALL 4
+#define LWM2M_SW_UPDATE_CHECKPOINT 5
+#define LWM2M_SW_UPDATE_UNINSTALL 6
+#define LWM2M_SW_UPDATE_UPDATE_STATE 7
+#define LWM2M_SW_UPDATE_SUPPORTED_OBJECTS 8
+
+/**
+ * LWM2M Enabler
+ */
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. MUST be first. */
+ uint8_t operations[12]; /* Internal. MUST be second. */
+ uint16_t resource_ids[12]; /* Internal. MUST be third. */
+
+ /* Public members. */
+ lwm2m_string_t server_uri;
+ bool bootstrap_server;
+ uint8_t security_mode;
+ lwm2m_opaque_t public_key;
+ lwm2m_opaque_t server_public_key;
+ lwm2m_opaque_t secret_key;
+ uint8_t sms_security_mode;
+ lwm2m_opaque_t sms_binding_key_param;
+ lwm2m_opaque_t sms_binding_secret_keys;
+ uint32_t sms_number;
+ uint16_t short_server_id;
+ lwm2m_time_t client_hold_off_time;
+
+} lwm2m_security_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. MUST be first. */
+ uint8_t operations[9]; /* Internal. MUST be second. */
+ uint16_t resource_ids[9]; /* Internal. MUST be third. */
+
+ /* Public members. */
+ uint16_t short_server_id;
+ lwm2m_time_t lifetime;
+ lwm2m_time_t default_minimum_period;
+ lwm2m_time_t default_maximum_period;
+ void * disable; // Function pointer.
+ lwm2m_time_t disable_timeout;
+ bool notification_storing_on_disabled;
+ lwm2m_string_t binding;
+ void * registration_update_trigger; // Function pointer.
+
+} lwm2m_server_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto; /* Internal. MUST be first. */
+ uint8_t operations[6]; /* Internal. MUST be second. */
+ uint16_t resource_ids[6]; /* Internal. MUST be third. */
+
+ /* Public members. */
+ lwm2m_opaque_t package;
+ lwm2m_string_t package_uri;
+ uint8_t state;
+ bool update_supported_objects;
+ uint8_t update_result;
+
+} lwm2m_firmware_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto;
+ uint8_t operations[4];
+ uint16_t resource_ids[4];
+
+ /* Public members. */
+ uint16_t acl_object_id;
+ uint16_t acl_instance_id;
+ uint16_t acl;
+ uint16_t control_owner;
+
+} lwm2m_acl_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto;
+ uint8_t operations[11];
+ uint16_t resource_ids[11];
+
+ /* Public members. */
+ uint32_t network_bearer;
+ uint32_t available_network_bearer;// TODO this is a list!
+ uint32_t radio_signal_strength; // Unit: dBm
+ uint32_t link_quality;
+ lwm2m_string_t ip_addresses; // TODO: this is a list!
+ lwm2m_string_t router_ip_addresses; // TODO: this is a list!
+ uint8_t link_utilization; // Unit: percent
+ lwm2m_string_t apn; // TODO: this is a list!
+ uint32_t cell_id;
+ uint8_t smnc; // Unit: percent
+ uint32_t smcc;
+
+} lwm2m_connectivity_monitoring_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto;
+ uint8_t operations[7];
+ uint16_t resource_ids[7];
+
+ /* Public members. */
+ uint32_t sms_tx_counter;
+ uint32_t sms_rx_counter;
+ uint32_t tx_data; // Unit: kilo-bytes
+ uint32_t rx_data; // Unit: kilo-bytes
+ uint32_t max_message_size; // Unit: byte
+ uint32_t average_message_size; // Unit: byte
+ /* StartOrReset is Execute only */
+
+} lwm2m_connectivity_statistics_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto;
+ uint8_t operations[17];
+ uint16_t resource_ids[17];
+
+ /* Public members. */
+ lwm2m_string_t manufacturer;
+ lwm2m_string_t model_number;
+ lwm2m_string_t serial_number;
+ lwm2m_string_t firmware_version;
+ /* Reboot is execute only */
+ /* Factory reset is execute only */
+ uint8_t avail_power_sources; // TODO: this is a list, Range: 0-7
+ uint32_t power_source_voltage; // TODO: this is a list, Unit: mV
+ uint32_t power_source_current; // TODO: this is a list, Unit: mA
+ uint8_t battery_level; // Unit: percent
+ uint32_t memory_free; // Unit: KB
+ uint32_t error_code; // TODO: this is a list
+ /* Reset Error code is execute only */
+ lwm2m_time_t current_time;
+ lwm2m_string_t utc_offset;
+ lwm2m_string_t timezone;
+ lwm2m_string_t supported_bindings; // TODO this is a list
+
+} lwm2m_device_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto;
+ uint8_t operations[6];
+ uint16_t resource_ids[6];
+
+ /* Public members. */
+ lwm2m_string_t latitude; // Unit: Deg
+ lwm2m_string_t longitude; // Unit: Deg
+ lwm2m_string_t altitude; // Unit: m
+ lwm2m_string_t uncertainty; // Unit: m
+ lwm2m_opaque_t velocity; // Unit: Refers to 3GPP GAD specs
+ lwm2m_time_t timestamp; // Range: 0-6
+
+} lwm2m_location_t;
+
+typedef struct
+{
+ lwm2m_instance_prototype_t proto;
+ uint8_t operations[9];
+ uint16_t resource_ids[9];
+
+ /* Public members. */
+ lwm2m_string_t pkg_name;
+ lwm2m_string_t pkg_version;
+ lwm2m_opaque_t package;
+ lwm2m_string_t package_uri;
+ /* Install is execute only */
+ uint16_t checkpoint; // TODO: this is of type Objlnk
+ /* Uninstall is execute only */
+ uint8_t update_state; // Range: 1-5
+ bool update_supported_objects;
+
+} lwm2m_software_update_t;
+
+/**@brief Initialize a LWM2M security object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_security_init(lwm2m_security_t * p_instance);
+
+/**@brief Initialize a LWM2M server object instance.
+ *
+ * @details Must be called before any use of the instance.
+
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_server_init(lwm2m_server_t * p_instance);
+
+/**@brief Initialize a LWM2M firmware object instance.
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_firmware_init(lwm2m_firmware_t * p_instance);
+
+/**@brief Initialize a LWM2M ACL object instance
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_acl_init(lwm2m_acl_t * p_instance);
+
+/**@brief Initialize a LWM2M connectivity monitoring object instance
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_connectivity_monitoring_init(lwm2m_connectivity_monitoring_t * p_instance);
+
+/**@brief Initialize a LWM2M connectivity statistics object instance
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_connectivity_statistics_init(lwm2m_connectivity_statistics_t * p_instance);
+
+/**@brief Initialize a LWM2M device object instance
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_device_init(lwm2m_device_t * p_instance);
+
+/**@brief Initialize a LWM2M location object instance
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_location_init(lwm2m_location_t * p_instance);
+
+/**@brief Initialize a LWM2M software update object instance
+ *
+ * @details Must be called before any use of the instance.
+ *
+ * @param[in] p_instance Pointer to instance structure to initialize.
+ */
+void lwm2m_instance_software_update_init(lwm2m_software_update_t * p_instance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_OBJECTS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.c
new file mode 100644
index 0000000..93cb6c1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.c
@@ -0,0 +1,498 @@
+/**
+ * Copyright (c) 2015 - 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 "lwm2m_objects_tlv.h"
+#include "lwm2m_tlv.h"
+
+static void index_buffer_len_update(uint32_t * index, uint32_t * buffer_len, uint32_t max_buffer)
+{
+ *index += *buffer_len;
+ *buffer_len = max_buffer - *index;
+}
+
+uint32_t lwm2m_tlv_server_decode(lwm2m_server_t * server, uint8_t * buffer, uint32_t buffer_len)
+{
+ uint32_t err_code;
+ lwm2m_tlv_t tlv;
+
+ uint32_t index = 0;
+
+ while (index < buffer_len)
+ {
+ err_code = lwm2m_tlv_decode(&tlv, &index, buffer, buffer_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ switch (tlv.id)
+ {
+ case LWM2M_SERVER_SHORT_SERVER_ID:
+ {
+ if (lwm2m_tlv_bytebuffer_to_uint16(tlv.value, tlv.length, &server->short_server_id) != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ break;
+ }
+
+ case LWM2M_SERVER_LIFETIME:
+ {
+ if (lwm2m_tlv_bytebuffer_to_uint32(tlv.value, tlv.length, &server->lifetime))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ case LWM2M_SERVER_DEFAULT_MIN_PERIOD:
+ {
+ if (lwm2m_tlv_bytebuffer_to_uint32(tlv.value, tlv.length, &server->default_minimum_period))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ case LWM2M_SERVER_DEFAULT_MAX_PERIOD:
+ {
+ if (lwm2m_tlv_bytebuffer_to_uint32(tlv.value, tlv.length, &server->default_maximum_period))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ case LWM2M_SERVER_DISABLE:
+ {
+ // Execute do nothing
+ break;
+ }
+
+ case LWM2M_SERVER_DISABLE_TIMEOUT:
+ {
+ if (lwm2m_tlv_bytebuffer_to_uint32(tlv.value, tlv.length, &server->disable_timeout))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ case LWM2M_SERVER_NOTIFY_WHEN_DISABLED:
+ {
+ server->notification_storing_on_disabled = tlv.value[0];
+ break;
+ }
+ case LWM2M_SERVER_BINDING:
+ {
+ // If original buffer is gone this will also be gone
+ server->binding.len = tlv.length;
+ server->binding.p_val = (char *) tlv.value;
+ break;
+ }
+
+ case LWM2M_SERVER_REGISTRATION_UPDATE_TRIGGER:
+ {
+ // Execute do nothing
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_tlv_security_decode(lwm2m_security_t * p_security,
+ uint8_t * p_buffer,
+ uint32_t buffer_len)
+{
+ uint32_t err_code;
+ lwm2m_tlv_t tlv;
+
+ uint32_t index = 0;
+
+ while (index < buffer_len)
+ {
+ err_code = lwm2m_tlv_decode(&tlv, &index, p_buffer, buffer_len);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ switch (tlv.id)
+ {
+ case LWM2M_SECURITY_SERVER_URI:
+ {
+ p_security->server_uri.p_val = (char *)tlv.value;
+ p_security->server_uri.len = tlv.length;
+ break;
+ }
+
+ case LWM2M_SECURITY_BOOTSTRAP_SERVER:
+ {
+ p_security->bootstrap_server = tlv.value[0];
+ break;
+ }
+
+ case LWM2M_SECURITY_SECURITY_MODE:
+ {
+ p_security->security_mode = tlv.value[0];
+ break;
+ }
+
+ case LWM2M_SECURITY_PUBLIC_KEY:
+ {
+ p_security->public_key.p_val = tlv.value;
+ p_security->public_key.len = tlv.length;
+ break;
+ }
+
+ case LWM2M_SECURITY_SERVER_PUBLIC_KEY:
+ {
+ p_security->server_public_key.p_val = tlv.value;
+ p_security->server_public_key.len = tlv.length;
+ break;
+ }
+
+ case LWM2M_SECURITY_SECRET_KEY:
+ {
+ p_security->secret_key.p_val = tlv.value;
+ p_security->secret_key.len = tlv.length;
+ break;
+ }
+
+ case LWM2M_SECURITY_SMS_SECURITY_MODE:
+ {
+ p_security->sms_security_mode = tlv.value[0];
+ break;
+ }
+
+ case LWM2M_SECURITY_SMS_BINDING_KEY_PARAM:
+ {
+ p_security->sms_binding_key_param.p_val = tlv.value;
+ p_security->sms_binding_key_param.len = tlv.length;
+ break;
+ }
+
+ case LWM2M_SECURITY_SMS_BINDING_SECRET_KEY:
+ {
+ p_security->sms_binding_secret_keys.p_val = tlv.value;
+ p_security->sms_binding_secret_keys.len = tlv.length;
+ break;
+ }
+
+ case LWM2M_SECURITY_SERVER_SMS_NUMBER:
+ {
+ uint32_t result = lwm2m_tlv_bytebuffer_to_uint32(tlv.value,
+ tlv.length,
+ &p_security->sms_number);
+ if (result != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ case LWM2M_SECURITY_SHORT_SERVER_ID:
+ {
+ uint32_t result = lwm2m_tlv_bytebuffer_to_uint16(tlv.value,
+ tlv.length,
+ &p_security->short_server_id);
+ if (result != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ case LWM2M_SECURITY_CLIENT_HOLD_OFF_TIME:
+ {
+ uint32_t result = lwm2m_tlv_bytebuffer_to_uint32(tlv.value,
+ tlv.length,
+ &p_security->client_hold_off_time);
+ if (result != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_tlv_server_encode(uint8_t * p_buffer,
+ uint32_t * p_buffer_len,
+ lwm2m_server_t * p_server)
+{
+ uint32_t err_code;
+ uint32_t max_buffer = *p_buffer_len;
+ uint32_t index = 0;
+
+ lwm2m_tlv_t tlv;
+ tlv.id_type = TLV_TYPE_RESOURCE_VAL; // Type is the same for all.
+
+ // Encode short server id.
+ lwm2m_tlv_uint16_set(&tlv, p_server->short_server_id, LWM2M_SERVER_SHORT_SERVER_ID);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode lifetime.
+ lwm2m_tlv_uint32_set(&tlv, p_server->lifetime, LWM2M_SERVER_LIFETIME);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode default minimum period.
+ lwm2m_tlv_uint32_set(&tlv, p_server->default_minimum_period, LWM2M_SERVER_DEFAULT_MIN_PERIOD);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode default maximum period.
+ lwm2m_tlv_uint32_set(&tlv, p_server->default_maximum_period, LWM2M_SERVER_DEFAULT_MAX_PERIOD);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode disable timeout.
+ lwm2m_tlv_uint32_set(&tlv, p_server->disable_timeout, LWM2M_SERVER_DISABLE_TIMEOUT);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode Notify when disabled.
+ lwm2m_tlv_bool_set(&tlv, p_server->notification_storing_on_disabled, LWM2M_SERVER_NOTIFY_WHEN_DISABLED);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ // Encode binding.
+ lwm2m_tlv_string_set(&tlv, p_server->binding, LWM2M_SERVER_BINDING);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ *p_buffer_len = index;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_tlv_security_encode(uint8_t * p_buffer,
+ uint32_t * p_buffer_len,
+ lwm2m_security_t * p_security)
+{
+ uint32_t err_code;
+ uint32_t max_buffer = *p_buffer_len;
+ uint32_t index = 0;
+
+ lwm2m_tlv_t tlv;
+ tlv.id_type = TLV_TYPE_RESOURCE_VAL; // type is the same for all.
+
+
+ lwm2m_tlv_string_set(&tlv, p_security->server_uri, LWM2M_SECURITY_SERVER_URI);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_bool_set(&tlv, p_security->bootstrap_server, LWM2M_SECURITY_BOOTSTRAP_SERVER);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_uint16_set(&tlv, p_security->security_mode, LWM2M_SECURITY_SECURITY_MODE);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_opaque_set(&tlv, p_security->public_key, LWM2M_SECURITY_PUBLIC_KEY);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_opaque_set(&tlv, p_security->server_public_key, LWM2M_SECURITY_SERVER_PUBLIC_KEY);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_opaque_set(&tlv, p_security->secret_key, LWM2M_SECURITY_SECRET_KEY);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_uint16_set(&tlv, p_security->sms_security_mode, LWM2M_SECURITY_SMS_SECURITY_MODE);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_opaque_set(&tlv, p_security->sms_binding_key_param, LWM2M_SECURITY_SMS_BINDING_KEY_PARAM);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_opaque_set(&tlv, p_security->sms_binding_secret_keys, LWM2M_SECURITY_SMS_BINDING_SECRET_KEY);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_uint32_set(&tlv, p_security->sms_number, LWM2M_SECURITY_SERVER_SMS_NUMBER);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_uint16_set(&tlv, p_security->short_server_id, LWM2M_SECURITY_SHORT_SERVER_ID);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ lwm2m_tlv_uint32_set(&tlv, p_security->client_hold_off_time, LWM2M_SECURITY_CLIENT_HOLD_OFF_TIME);
+ err_code = lwm2m_tlv_encode(p_buffer + index, p_buffer_len, &tlv);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ index_buffer_len_update(&index, p_buffer_len, max_buffer);
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.h
new file mode 100644
index 0000000..608ecef
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_objects_tlv.h
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file lwm2m_objects_tlv.h
+ *
+ * @defgroup iot_sdk_lwm2m_objects_tlv OMA LWM2M object TLV encoder and decoder API
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief OMA LWM2M object TLV encoder and decoder API.
+ */
+
+#ifndef LWM2M_OBJECTS_TLV_H__
+#define LWM2M_OBJECTS_TLV_H__
+
+#include <stdint.h>
+#include "lwm2m_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Decode a LWM2M server object from a TLV byte buffer.
+ *
+ * @note Resource values NOT found in the tlv will not be altered.
+ *
+ * @warning lwm2m_string_t and lwm2m_opaque_t values will point to the byte buffer and needs
+ * to be copied by the application before the byte buffer is freed.
+ *
+ * @param[out] p_server Pointer to a LWM2M server object to be filled by the decoded TLVs.
+ * @param[in] p_buffer Pointer to the TLV byte buffer to be decoded.
+ * @param[in] buffer_len Size of the buffer to be decoded.
+ *
+ * @retval NRF_SUCCESS If decoding was successful.
+ */
+uint32_t lwm2m_tlv_server_decode(lwm2m_server_t * p_server,
+ uint8_t * p_buffer,
+ uint32_t buffer_len);
+
+/**@brief Encode a LWM2M server object to a TLV byte buffer.
+ *
+ * @param[out] p_buffer Pointer to a byte buffer to be used to fill the encoded TLVs.
+ * @param[inout] p_buffer_len Value by reference indicating the size of the buffer provided.
+ * Will return the number of used bytes on return.
+ * @param[in] p_server Pointer to the LWM2M server object to be encoded into TLVs.
+ *
+ * @retval NRF_SUCCESS If the encoded was successful.
+ */
+uint32_t lwm2m_tlv_server_encode(uint8_t * p_buffer,
+ uint32_t * p_buffer_len,
+ lwm2m_server_t * p_server);
+
+/**@brief Decode a LWM2M security object from a TLV byte buffer.
+ *
+ * @note Resource values NOT found in the tlv will not be altered.
+ *
+ * @warning lwm2m_string_t and lwm2m_opaque_t values will point to the byte buffer and needs
+ * to be copied by the application before the byte buffer is freed.
+ *
+ * @param[out] p_security Pointer to a LWM2M server object to be filled by the decoded TLVs.
+ * @param[in] p_buffer Pointer to the TLV byte buffer to be decoded.
+ * @param[in] buffer_len Size of the buffer to be decoded.
+ *
+ * @retval NRF_SUCCESS If decoding was successful.
+ */
+uint32_t lwm2m_tlv_security_decode(lwm2m_security_t * p_security,
+ uint8_t * p_buffer,
+ uint32_t buffer_len);
+
+/**@brief Encode a LWM2M security object to a TLV byte buffer.
+ *
+ * @param[out] p_buffer Pointer to a byte buffer to be used to fill the encoded TLVs.
+ * @param[inout] p_buffer_len Value by reference indicating the size of the buffer provided.
+ * Will return the number of used bytes on return.
+ * @param[in] p_security Pointer to the LWM2M security object to be encoded into TLVs.
+ *
+ * @retval NRF_SUCCESS If the encoded was successful.
+ */
+uint32_t lwm2m_tlv_security_encode(uint8_t * p_buffer,
+ uint32_t * p_buffer_len,
+ lwm2m_security_t * p_security);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_OBJECTS_TLV_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.c
new file mode 100644
index 0000000..3c273ee
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.c
@@ -0,0 +1,542 @@
+/**
+ * Copyright (c) 2015 - 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 <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "lwm2m_api.h"
+#include "lwm2m_register.h"
+#include "lwm2m.h"
+#include "coap_api.h"
+#include "coap_message.h"
+#include "coap_codes.h"
+#include "sdk_config.h"
+#include "app_util.h"
+
+#if LWM2M_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME lwm2m
+
+#define NRF_LOG_LEVEL LWM2M_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR LWM2M_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR LWM2M_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+#define LWM2M_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define LWM2M_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define LWM2M_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define LWM2M_ENTRY() LWM2M_TRC(">> %s", __func__)
+#define LWM2M_EXIT() LWM2M_TRC("<< %s", __func__)
+
+#else // LWM2M_CONFIG_LOG_ENABLED
+
+#define LWM2M_TRC(...) /**< Disables traces. */
+#define LWM2M_DUMP(...) /**< Disables dumping of octet streams. */
+#define LWM2M_ERR(...) /**< Disables error logs. */
+
+#define LWM2M_ENTRY(...)
+#define LWM2M_EXIT(...)
+
+#endif // LWM2M_CONFIG_LOG_ENABLED
+
+#define LWM2M_REGISTER_URI_PATH "rd"
+
+#define TOKEN_START 0xAE1C
+
+typedef struct
+{
+ lwm2m_remote_t remote;
+ char location[LWM2M_REGISTER_MAX_LOCATION_LEN];
+ uint16_t location_len;
+} internal_lwm2m_remote_location_t;
+
+
+static internal_lwm2m_remote_location_t m_remote_to_location[LWM2M_MAX_SERVERS];
+
+static uint16_t num_servers = 0;
+static uint16_t m_token = TOKEN_START;
+
+static uint32_t internal_message_new(coap_message_t ** pp_msg,
+ coap_msg_code_t code,
+ coap_response_callback_t callback,
+ uint16_t local_port)
+{
+ uint32_t err_code;
+ coap_message_conf_t conf;
+ memset (&conf, 0, sizeof(coap_message_conf_t));
+
+ conf.type = COAP_TYPE_CON;
+ conf.code = code;
+ conf.response_callback = callback;
+ conf.port.port_number = local_port;
+
+ conf.token_len = uint16_encode(m_token, conf.token);
+
+ m_token++;
+
+ err_code = coap_message_new(pp_msg, &conf);
+
+ return err_code;
+}
+
+
+static uint32_t internal_location_find(lwm2m_string_t * p_location, lwm2m_remote_t * p_remote)
+{
+ for (uint16_t i = 0; i < num_servers; ++i)
+ {
+ if (memcmp(&m_remote_to_location[i].remote, p_remote, sizeof(lwm2m_remote_t)) == 0)
+ {
+ p_location->p_val = m_remote_to_location[i].location;
+ p_location->len = m_remote_to_location[i].location_len;
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+static uint32_t internal_remote_location_save(lwm2m_string_t * location, lwm2m_remote_t * remote)
+{
+ for (uint16_t i = 0; i < num_servers; ++i)
+ {
+ if (memcmp(&m_remote_to_location[i].remote, remote, sizeof(lwm2m_remote_t)) == 0)
+ {
+ memcpy(m_remote_to_location[i].location, location->p_val, location->len);
+ m_remote_to_location[i].location_len = location->len;
+ return NRF_SUCCESS;
+ }
+ }
+
+ if (num_servers == LWM2M_MAX_SERVERS)
+ return NRF_ERROR_NO_MEM;
+
+ memcpy(&m_remote_to_location[num_servers].remote, remote, sizeof(lwm2m_remote_t));
+
+ memcpy(m_remote_to_location[num_servers].location, location->p_val, location->len);
+
+ m_remote_to_location[num_servers].location_len = location->len;
+
+ ++num_servers;
+
+ return NRF_SUCCESS;
+}
+
+
+static uint32_t internal_server_config_set(coap_message_t * msg, lwm2m_server_config_t * p_config)
+{
+ char buffer[32];
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (p_config->lifetime > 0)
+ {
+ int retval = snprintf(buffer, sizeof(buffer), "lt=%lu", p_config->lifetime);
+ if (retval < 0)
+ {
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+ else
+ {
+ err_code = coap_message_opt_str_add(msg,
+ COAP_OPT_URI_QUERY,
+ (uint8_t *)buffer,
+ strlen(buffer));
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if ((p_config->lwm2m_version_major > 0) || (p_config->lwm2m_version_minor > 0))
+ {
+ int retval = snprintf(buffer,
+ sizeof(buffer),
+ "lwm2m=%d.%d",
+ p_config->lwm2m_version_major,
+ p_config->lwm2m_version_minor);
+ if (retval < 0)
+ {
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+ else
+ {
+ err_code = coap_message_opt_str_add(msg,
+ COAP_OPT_URI_QUERY,
+ (uint8_t *)buffer,
+ strlen(buffer));
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (p_config->msisdn > 0)
+ {
+ int retval = snprintf(buffer, sizeof(buffer), "sms=%llu" , p_config->msisdn);
+ if (retval < 0)
+ {
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+ else
+ {
+ err_code = coap_message_opt_str_add(msg,
+ COAP_OPT_URI_QUERY,
+ (uint8_t *)buffer,
+ strlen(buffer));
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (p_config->binding.len > 0)
+ {
+ if (p_config->binding.len < sizeof(buffer) - 2)
+ {
+ buffer[0] = 'b';
+ buffer[1] = '=';
+ memcpy(buffer + 2, p_config->binding.p_val, p_config->binding.len);
+
+ err_code = coap_message_opt_str_add(msg,
+ COAP_OPT_URI_QUERY,
+ (uint8_t *)buffer,
+ p_config->binding.len + 2);
+ }
+ else
+ {
+ err_code = NRF_ERROR_NO_MEM;
+ }
+ }
+ }
+
+ return err_code;
+}
+
+
+uint32_t internal_lwm2m_register_init(void)
+{
+ m_token = TOKEN_START;
+ num_servers = 0;
+ return NRF_SUCCESS;
+}
+
+
+static void lwm2m_register_cb(uint32_t status, void * p_arg, coap_message_t * p_message)
+{
+ LWM2M_TRC("[Register]: lwm2m_register_cb, status: %ul, coap code: %u",
+ status,
+ p_message->header.code);
+
+ LWM2M_MUTEX_LOCK();
+
+ for (uint16_t i = 0; i < p_message->options_count; ++i)
+ {
+ coap_option_t option = p_message->options[i];
+
+ if (option.number == COAP_OPT_LOCATION_PATH)
+ {
+ lwm2m_string_t location;
+ location.p_val = (char *) option.p_data;
+ location.len = option.length;
+ (void)internal_remote_location_save(&location, &p_message->remote);
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ (void)lwm2m_notification(LWM2M_NOTIFCATION_TYPE_REGISTER,
+ &p_message->remote,
+ p_message->header.code);
+}
+
+
+uint32_t lwm2m_register(lwm2m_remote_t * p_remote,
+ lwm2m_client_identity_t * p_id,
+ lwm2m_server_config_t * p_config,
+ uint16_t local_port,
+ uint8_t * p_link_format_string,
+ uint16_t link_format_len)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_remote);
+ NULL_PARAM_CHECK(p_id);
+ NULL_PARAM_CHECK(p_config);
+ NULL_PARAM_CHECK(p_link_format_string);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint32_t err_code;
+ char buffer[40];
+
+ lwm2m_string_t endpoint;
+
+ endpoint.p_val = LWM2M_REGISTER_URI_PATH;
+ endpoint.len = 2;
+
+ coap_message_t * p_msg;
+
+ err_code = internal_message_new(&p_msg, COAP_CODE_POST, lwm2m_register_cb, local_port);
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_remote_addr_set(p_msg, p_remote);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Set uri-path option
+ err_code = coap_message_opt_str_add(p_msg,
+ COAP_OPT_URI_PATH,
+ (uint8_t *)endpoint.p_val,
+ endpoint.len); // end_point length is always 2
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Set content format.
+ err_code = coap_message_opt_uint_add(p_msg, COAP_OPT_CONTENT_FORMAT, COAP_CT_APP_LINK_FORMAT);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Set queries.
+ buffer[0] = 'e';
+ buffer[1] = 'p';
+ buffer[2] = '=';
+ memcpy(buffer + 3, &p_id->value, p_id->type);
+
+ err_code = coap_message_opt_str_add(p_msg,
+ COAP_OPT_URI_QUERY,
+ (uint8_t *)buffer,
+ p_id->type + 3);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = internal_server_config_set(p_msg, p_config);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_payload_set(p_msg, p_link_format_string, link_format_len);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t msg_handle;
+ err_code = coap_message_send(&msg_handle, p_msg);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_delete(p_msg);
+ }
+ else
+ {
+ // If we have hit an error try to clean up.
+ // Return the original error code.
+ (void)coap_message_delete(p_msg);
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ LWM2M_EXIT();
+
+ return err_code;
+}
+
+void lwm2m_update_cb(uint32_t status, void * p_arg, coap_message_t * p_message)
+{
+ LWM2M_TRC("[Update]: lwm2m_update_cb, status: %ul, coap code: %u",
+ status,
+ p_message->header.code);
+
+ (void)lwm2m_notification(LWM2M_NOTIFCATION_TYPE_UPDATE,
+ &p_message->remote,
+ p_message->header.code);
+}
+
+
+uint32_t lwm2m_update(lwm2m_remote_t * p_remote, lwm2m_server_config_t * p_config, uint16_t local_port)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_remote);
+ NULL_PARAM_CHECK(p_config);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint32_t err_code;
+ coap_message_t * p_msg;
+
+ err_code = internal_message_new(&p_msg, COAP_CODE_POST, lwm2m_update_cb, local_port);
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_remote_addr_set(p_msg, p_remote);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ lwm2m_string_t location;
+ err_code = internal_location_find(&location, p_remote);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Sets URI PATH
+ err_code = coap_message_opt_str_add(p_msg,
+ COAP_OPT_URI_PATH,
+ (uint8_t *)location.p_val,
+ location.len);
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Sets CoAP queries
+ err_code = internal_server_config_set(p_msg, p_config);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t msg_handle;
+ err_code = coap_message_send(&msg_handle, p_msg);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_delete(p_msg);
+ }
+ else
+ {
+ // If we have hit an error try to clean up.
+ // Return the original error code.
+ (void)coap_message_delete(p_msg);
+ }
+
+ LWM2M_EXIT();
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+void lwm2m_deregister_cb(uint32_t status, void * p_arg, coap_message_t * p_message)
+{
+ LWM2M_TRC("[DeRegister]: lwm2m_deregister_cb, status: %ul, coap code: %u",
+ status,
+ p_message->header.code);
+
+ (void)lwm2m_notification(LWM2M_NOTIFCATION_TYPE_DEREGISTER,
+ &p_message->remote,
+ p_message->header.code);
+}
+
+uint32_t lwm2m_deregister(lwm2m_remote_t * p_remote, uint16_t local_port)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_remote);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint32_t err_code;
+ coap_message_t * p_msg;
+
+ err_code = internal_message_new(&p_msg, COAP_CODE_DELETE, lwm2m_deregister_cb, local_port);
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_remote_addr_set(p_msg, p_remote);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ lwm2m_string_t location;
+ err_code = internal_location_find(&location, p_remote);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_opt_str_add(p_msg,
+ COAP_OPT_URI_PATH,
+ (uint8_t *)location.p_val,
+ location.len);
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t msg_handle;
+ err_code = coap_message_send(&msg_handle, p_msg);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = coap_message_delete(p_msg);
+ }
+ else
+ {
+ // If we have hit an error try to clean up.
+ // Return the original error code.
+ (void)coap_message_delete(p_msg);
+ }
+
+ LWM2M_EXIT();
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.h
new file mode 100644
index 0000000..5daa950
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_register.h
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file lwm2m_register.h
+ *
+ * @defgroup iot_sdk_lwm2m_register_api LWM2M register API interface
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief Register API interface for the LWM2M protocol.
+ */
+
+#ifndef LWM2M_REGISTER_H__
+#define LWM2M_REGISTER_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Initialize the LWM2M register module.
+ *
+ * @details Calling this function will set the module in default state.
+ */
+uint32_t internal_lwm2m_register_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_REGISTER_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.c
new file mode 100644
index 0000000..047cdb7
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.c
@@ -0,0 +1,399 @@
+/**
+ * Copyright (c) 2015 - 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 <stdint.h>
+#include <string.h>
+#include "lwm2m_tlv.h"
+#include "lwm2m_objects.h"
+#include "iot_errors.h"
+#include "iot_defines.h"
+
+// Used for encoding
+// TODO: Remove this temp_buffer in order to allow to users to use the API at the same time.
+// Current implementation might fail if two different interrupt levels are executing
+// encode at the same time. The temp_buffer will be overwritten by the last user.
+static uint8_t temp_buffer[4];
+
+
+uint32_t lwm2m_tlv_bytebuffer_to_uint32(uint8_t * p_buffer, uint8_t val_len, uint32_t * p_result)
+{
+ uint32_t res;
+ switch (val_len)
+ {
+ case 0:
+ {
+ res = 0;
+ break;
+ }
+
+ case 1:
+ {
+ res = p_buffer[0];
+ break;
+ }
+
+ case 2:
+ {
+ res = ((uint32_t)p_buffer[0] << 8) |
+ p_buffer[1];
+ break;
+ }
+
+ case 3:
+ {
+ res = ((uint32_t)p_buffer[0] << 16) |
+ ((uint32_t)p_buffer[1] << 8) |
+ p_buffer[2];
+ break;
+ }
+
+ case 4:
+ {
+ res = ((uint32_t)p_buffer[0] << 24) |
+ ((uint32_t)p_buffer[1] << 16) |
+ ((uint32_t)p_buffer[2] << 8) |
+ p_buffer[3];
+ break;
+ }
+
+ default:
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ *p_result = res;
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_tlv_bytebuffer_to_uint16(uint8_t * p_buffer, uint8_t val_len, uint16_t * p_result)
+{
+ uint16_t res;
+ switch (val_len)
+ {
+ case 0:
+ {
+ res = 0;
+ break;
+ }
+
+ case 1:
+ {
+ res = p_buffer[0];
+ break;
+ }
+
+ case 2:
+ {
+ res = ((uint16_t)p_buffer[0] << 8) | p_buffer[1];
+ break;
+ }
+
+ default:
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ *p_result = res;
+ return NRF_SUCCESS;
+}
+
+
+void lwm2m_tlv_uint16_to_bytebuffer(uint8_t * p_buffer, uint8_t * p_len, uint16_t value)
+{
+ if (value == 0)
+ {
+ *p_len = 0;
+ }
+ else if (value <= UINT8_MAX)
+ {
+ p_buffer[0] = value;
+ *p_len = 1;
+ }
+ else
+ {
+
+ p_buffer[1] = value;
+ p_buffer[0] = value >> 8;
+ *p_len = 2;
+ }
+}
+
+
+void lwm2m_tlv_uint32_to_bytebuffer(uint8_t * p_buffer, uint8_t * p_len, uint32_t value)
+{
+ if (value == 0)
+ {
+ *p_len = 0;
+ }
+ else if (value <= UINT8_MAX)
+ {
+ p_buffer[0] = value;
+ *p_len = 1;
+ }
+ else if (value <= UINT16_MAX)
+ {
+
+ p_buffer[1] = value;
+ p_buffer[0] = value >> 8;
+ *p_len = 2;
+ }
+ else if (value <= 0xFFFFFF) // 24 bit
+ {
+ p_buffer[2] = value;
+ p_buffer[1] = value >> 8;
+ p_buffer[0] = value >> 16;
+ *p_len = 3;
+ }
+ else
+ {
+ p_buffer[3] = value;
+ p_buffer[2] = value >> 8;
+ p_buffer[1] = value >> 16;
+ p_buffer[0] = value >> 24;
+ *p_len = 4;
+ }
+}
+
+
+void lwm2m_tlv_uint16_set(lwm2m_tlv_t * p_tlv, uint16_t value, uint16_t id)
+{
+ uint8_t val_len;
+ lwm2m_tlv_uint16_to_bytebuffer(temp_buffer, &val_len, value);
+
+ p_tlv->length = val_len;
+ p_tlv->value = temp_buffer;
+ p_tlv->id = id;
+}
+
+
+void lwm2m_tlv_uint32_set(lwm2m_tlv_t * p_tlv, uint32_t value, uint16_t id)
+{
+ uint8_t val_len;
+ lwm2m_tlv_uint32_to_bytebuffer(temp_buffer, &val_len, value);
+
+ p_tlv->length = val_len;
+ p_tlv->value = temp_buffer;
+ p_tlv->id = id;
+}
+
+
+void lwm2m_tlv_bool_set(lwm2m_tlv_t * p_tlv, bool value, uint16_t id)
+{
+
+ if (value == true)
+ {
+ temp_buffer[0] = 1;
+ }
+ else
+ {
+ temp_buffer[0] = 0;
+ }
+
+ p_tlv->length = 1;
+ p_tlv->value = temp_buffer;
+ p_tlv->id = id;
+}
+
+
+void lwm2m_tlv_string_set(lwm2m_tlv_t * p_tlv, lwm2m_string_t string, uint16_t id)
+{
+ p_tlv->length = string.len;
+ p_tlv->value = (uint8_t *)string.p_val;
+ p_tlv->id = id;
+}
+
+
+void lwm2m_tlv_opaque_set(lwm2m_tlv_t * p_tlv, lwm2m_opaque_t opaque, uint16_t id)
+{
+ p_tlv->length = opaque.len;
+ p_tlv->value = opaque.p_val;
+ p_tlv->id = id;
+}
+
+
+uint32_t lwm2m_tlv_decode(lwm2m_tlv_t * p_tlv,
+ uint32_t * p_index,
+ uint8_t * p_buffer,
+ uint16_t buffer_len)
+{
+ uint32_t err_code;
+ uint16_t index = *p_index;
+
+ uint8_t type = (p_buffer[index] & TLV_TYPE_MASK) >> TLV_TYPE_BIT_POS;
+ uint8_t id_len = (p_buffer[index] & TLV_ID_LEN_MASK) >> TLV_ID_LEN_BIT_POS;
+ uint8_t length_len = (p_buffer[index] & TLV_LEN_TYPE_MASK) >> TLV_LEN_TYPE_BIT_POS;
+ uint32_t length = (p_buffer[index] & TLV_LEN_VAL_MASK) >> TLV_VAL_LEN_BIT_POS;
+
+ p_tlv->id_type = type;
+ p_tlv->length = 0;
+
+ // Jump to the byte following the "Type" at index 0.
+ ++index;
+
+ // Extract the Identifier based on the number of bytes indicated in id_len (bit 5).
+ // Adding one to the id_len will give the number of bytes used.
+ uint8_t id_len_size = id_len + 1;
+
+ err_code = lwm2m_tlv_bytebuffer_to_uint16(&p_buffer[index], id_len_size, &p_tlv->id);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ index += id_len_size;
+
+
+ // Extract the value length.
+ // The length_len tells how many bytes are being used.
+ if (length_len == TLV_LEN_TYPE_3BIT)
+ {
+ p_tlv->length = length;
+ }
+ else
+ {
+ err_code = lwm2m_tlv_bytebuffer_to_uint32(&p_buffer[index], length_len, &length);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ p_tlv->length = length;
+ index += length_len;
+ }
+
+ if (p_tlv->length > buffer_len)
+ {
+ return (IOT_LWM2M_ERR_BASE | NRF_ERROR_INVALID_DATA);
+ }
+
+ p_tlv->value = &p_buffer[index];
+
+ *p_index = index + p_tlv->length;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_tlv_encode(uint8_t * p_buffer, uint32_t * buffer_len, lwm2m_tlv_t * p_tlv)
+{
+ uint8_t length_len;
+ uint8_t id_len;
+
+ uint8_t id[2] = {0,};
+ uint8_t len[3] = {0,};
+ uint16_t index = 0;
+ uint8_t type = 0;
+
+ // Set Identifier type by copying the lwm2m_tlv_t->id_type into bit 7-6.
+ type = (p_tlv->id_type << TLV_TYPE_BIT_POS);
+
+ // Set length of Identifier in bit 5 in the TLV type byte.
+ if (p_tlv->id > UINT8_MAX)
+ {
+ type |= (TLV_ID_LEN_16BIT << TLV_ID_LEN_BIT_POS);
+ id[0] = p_tlv->id >> 8;
+ id[1] = p_tlv->id;
+ id_len = 2;
+ }
+ else
+ {
+ type |= (TLV_ID_LEN_8BIT << TLV_ID_LEN_BIT_POS);
+ id[0] = p_tlv->id;
+ id_len = 1;
+ }
+
+ // Set type of Length bit 4-3 in the TLV type byte.
+
+ // If the Length can fit into 3 bits.
+ if ((p_tlv->length & TLV_LEN_VAL_MASK) == p_tlv->length)
+ {
+ type |= (TLV_LEN_TYPE_3BIT << TLV_LEN_TYPE_BIT_POS);
+ length_len = 0;
+
+ // As Length type field is set to "No Length", set bit 2-0.
+ type |= (p_tlv->length & TLV_LEN_VAL_MASK);
+ }
+ else
+ {
+ lwm2m_tlv_uint32_to_bytebuffer(&len[0], &length_len, p_tlv->length);
+
+ // Length can not be larger than 24-bit.
+ if (length_len > TLV_LEN_TYPE_24BIT)
+ {
+ return (IOT_LWM2M_ERR_BASE | NRF_ERROR_INVALID_PARAM);
+ }
+
+ type |= (length_len << TLV_LEN_TYPE_BIT_POS);
+ }
+
+ // Check if the buffer is large enough.
+ if (*buffer_len < (p_tlv->length + id_len + length_len + 1)) // + 1 for the type byte
+ {
+ return (IOT_LWM2M_ERR_BASE | NRF_ERROR_DATA_SIZE);
+ }
+
+ // Copy the type to the buffer.
+ memcpy(p_buffer + index, &type, 1);
+ ++index;
+
+ // Copy the Identifier to the buffer.
+ memcpy(p_buffer + index, id, id_len);
+ index += id_len;
+
+ // Copy length to the buffer.
+ if (length_len != 0)
+ {
+ memcpy(p_buffer + index, len, length_len);
+ index += length_len;
+ }
+
+ // Copy the value to buffer, memcpy of 0 length is undefined behavior so lets avoid it.
+ if (p_tlv->length > 0)
+ {
+ memcpy(p_buffer + index, p_tlv->value, p_tlv->length);
+ }
+
+ // Set length of the output buffer.
+ *buffer_len = p_tlv->length + index;
+
+ return NRF_SUCCESS;
+}
+
+
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.h
new file mode 100644
index 0000000..8ac5784
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m_tlv.h
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file lwm2m_tlv.h
+ *
+ * @defgroup iot_sdk_lwm2m_tlv_api LWM2M TLV interface
+ * @ingroup iot_sdk_lwm2m
+ * @{
+ * @brief TLV encoding and decoding interface for the LWM2M protocol.
+ */
+
+#ifndef LWM2M_TLV_H__
+#define LWM2M_TLV_H__
+
+#include <stdint.h>
+#include "lwm2m_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+* TLV type masks
+*/
+#define TLV_TYPE_BIT_POS 6
+#define TLV_ID_LEN_BIT_POS 5
+#define TLV_LEN_TYPE_BIT_POS 3
+#define TLV_VAL_LEN_BIT_POS 0
+
+#define TLV_TYPE_MASK (0x3 << TLV_TYPE_BIT_POS) /**< Type bitmask, bit 7-6 (0b11000000). */
+#define TLV_ID_LEN_MASK (0x1 << TLV_ID_LEN_BIT_POS) /**< Length bitmask, bit 5 (0b00100000). */
+#define TLV_LEN_TYPE_MASK (0x3 << TLV_LEN_TYPE_BIT_POS) /**< Length type bitmask, bit 4-3 (0b00011000). */
+#define TLV_LEN_VAL_MASK (0x7 << TLV_VAL_LEN_BIT_POS) /**< Length of the value bitmask, bit 2-0 (0b00000111). */
+
+#define TLV_TYPE_OBJECT 0x00
+#define TLV_TYPE_RESOURCE_INSTANCE 0x01
+#define TLV_TYPE_MULTI_RESOURCE 0x02
+#define TLV_TYPE_RESOURCE_VAL 0x03
+
+#define TLV_ID_LEN_8BIT 0x00
+#define TLV_ID_LEN_16BIT 0x01
+
+#define TLV_LEN_TYPE_3BIT 0x00
+#define TLV_LEN_TYPE_8BIT 0x01
+#define TLV_LEN_TYPE_16BIT 0x02
+#define TLV_LEN_TYPE_24BIT 0x03
+
+typedef struct
+{
+ uint16_t id_type; /**< Identifier type. */
+ uint16_t id; /**< Identifier ID. */
+ uint32_t length; /**< Length of the value in the TLV. */
+ uint8_t * value; /**< Value of the TLV. */
+} lwm2m_tlv_t;
+
+/**@brief Decode a LWM2M TLV byte buffer into a TLV structure.
+ *
+ * @param[out] p_tlv This struct will be filled with id, length, type and pointer to value.
+ * @param[inout] p_index Index to start decoding from.
+ * @param[in] p_buffer The buffer to decode from.
+ * @param[in] buffer_len The length of the buffer.
+ *
+ * @retval NRF_SUCCESS If decoding was successful.
+ * @retval IOT_LWM2M_ERR_BASE | NRF_INVALID_DATA
+ */
+uint32_t lwm2m_tlv_decode(lwm2m_tlv_t * p_tlv, uint32_t * p_index, uint8_t * p_buffer, uint16_t buffer_len);
+
+/**@brief Encode a TLV structure into a LWM2M TLV byte buffer.
+ *
+ * @details Encode using the provided tlv, if the buffer provided is to small an NRF_ERROR_DATA_SIZE will be returned.
+ *
+ * Maximum buffer size requirement: value_length + 6 (1 for type byte, 2 for id bytes, 3 for length bytes).
+ *
+ * @param[out] p_buffer Buffer to put the encoded tlv into.
+ * @param[inout] buffer_len Length of input buffer out: length of the encoded buffer.
+ * @param[in] p_tlv The tlv to use.
+ *
+ * @retval NRF_SUCCESS If decoding was successful.
+ * @retval IOT_LWM2M_ERR_BASE | NRF_ERROR_DATA_SIZE
+ */
+uint32_t lwm2m_tlv_encode(uint8_t * p_buffer, uint32_t * p_buffer_len, lwm2m_tlv_t * p_tlv);
+
+/**@brief Encode a byte buffer into a uint32_t.
+ *
+ * @param[in] p_buffer Buffer which holds a serialized version of the uint32_t.
+ * @param[in] val_len Length of the value in the buffer.
+ * @param[out] p_result By reference pointer to the result uint32_t.
+ *
+ * @retval NRF_SUCCESS If the conversion from byte buffer to uint32_t value was successful.
+ */
+uint32_t lwm2m_tlv_bytebuffer_to_uint32(uint8_t * p_buffer, uint8_t val_len, uint32_t * p_result);
+
+/**@brief Encode a byte buffer into a uint16_t.
+ *
+ * @param[in] p_buffer Buffer which holds a serialized version of the uint16_t.
+ * @param[in] val_len Length of the value in the buffer.
+ * @param[out] p_result By reference pointer to the result uint16_t.
+ *
+ * @retval NRF_SUCCESS If the conversion from byte buffer to uint32_t value was successful.
+ */
+uint32_t lwm2m_tlv_bytebuffer_to_uint16(uint8_t * p_buffer, uint8_t val_len, uint16_t * p_result);
+
+/**@brief Decode a uint32_t into a byte buffer.
+ *
+ * @param[out] p_buffer Buffer which holds a serialized version of the uint32_t.
+ * @param[out] p_len By reference pointer to hold the length of the serialized value in the buffer.
+ * @param[in] value Value to convert serialize into a byte buffer.
+ *
+ * @retval NRF_SUCCESS If the conversion from uint32_t value to byte buffer was successful.
+ */
+void lwm2m_tlv_uint32_to_bytebuffer(uint8_t * p_buffer, uint8_t * p_len, uint32_t value);
+
+/**@brief Decode a uint16_t into a byte buffer.
+ *
+ * @param[out] p_buffer Buffer which holds a serialized version of the uint16_t.
+ * @param[out] p_len By reference pointer to hold the length of the serialized value in the buffer.
+ * @param[in] value Value to convert serialize into a byte buffer.
+ *
+ * @retval NRF_SUCCESS If the conversion from uint16_t value to byte buffer was successful.
+ */
+void lwm2m_tlv_uint16_to_bytebuffer(uint8_t * p_buffer, uint8_t * p_len, uint16_t value);
+
+/**@brief Set a uint32_t value to a lwm2m_tlv_t structure.
+ *
+ * @param[out] p_tlv TLV containing the uint32_t tlv.
+ * @param[in] value Value to set.
+ * @param[in] id Resource Id associated with the value.
+ */
+void lwm2m_tlv_uint32_set(lwm2m_tlv_t * p_tlv, uint32_t value, uint16_t id);
+
+
+/**@brief Set a uint16_t value to a lwm2m_tlv_t structure.
+ *
+ * @param[out] p_tlv TLV containing the uint16_t tlv.
+ * @param[in] value Value to set.
+ * @param[in] id Resource Id associated with the value.
+ */
+void lwm2m_tlv_uint16_set(lwm2m_tlv_t * p_tlv, uint16_t value, uint16_t id);
+
+
+/**@brief Set a boolean value to a lwm2m_tlv_t structure.
+ *
+ * @param[out] p_tlv TLV containing the boolean tlv.
+ * @param[in] value Value to set.
+ * @param[in] id Resource Id associated with the value.
+ */
+void lwm2m_tlv_bool_set(lwm2m_tlv_t * p_tlv, bool value, uint16_t id);
+
+/**@brief Set a string value to a lwm2m_tlv_t structure.
+ *
+ * @param[out] p_tlv TLV containing the string tlv.
+ * @param[in] value Value to set.
+ * @param[in] id Resource Id associated with the value.
+ */
+void lwm2m_tlv_string_set(lwm2m_tlv_t * p_tlv, lwm2m_string_t string, uint16_t id);
+
+/**@brief Set a opaque value to a lwm2m_tlv_t structure.
+ *
+ * @param[out] p_tlv TLV containing the opaque tlv.
+ * @param[in] value Value to set.
+ * @param[in] id Resource Id associated with the value.
+ */
+void lwm2m_tlv_opaque_set(lwm2m_tlv_t * p_tlv, lwm2m_opaque_t opaque, uint16_t id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LWM2M_TLV_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c
new file mode 100644
index 0000000..241ec48
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c
@@ -0,0 +1,516 @@
+/**
+ * Copyright (c) 2015-2017 - 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.
+ *
+ */
+#ifdef COMMISSIONING_ENABLED
+
+#include <string.h>
+#include "ble_ncfgs.h"
+#include "app_error.h"
+#include "ble.h"
+#include "nordic_common.h"
+
+/**@brief NCFGS database encapsulation. */
+typedef struct
+{
+ uint16_t service_handle;
+ ble_gatts_char_handles_t ssid_handles;
+ ble_gatts_char_handles_t keys_store_handles;
+ ble_gatts_char_handles_t ctrlp_handles;
+} ble_database_t;
+
+static ble_ncfgs_state_t m_service_state = NCFGS_STATE_IDLE; /**< Module state value. */
+static ble_ncfgs_evt_handler_t m_app_evt_handler; /**< Parent module callback function. */
+static ble_database_t m_database; /**< GATT handles database. */
+static uint8_t m_ctrlp_value_buffer[NCFGS_CTRLP_VALUE_LEN]; /**< Stores received Control Point value before parsing. */
+static ble_ncfgs_data_t m_ncfgs_data; /**< Stores all values written by the peer device. */
+
+#if NCFGS_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME ble_ncfgs
+
+#define NRF_LOG_LEVEL NCFGS_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR NCFGS_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR NCFGS_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define NCFGS_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define NCFGS_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define NCFGS_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define NCFGS_ENTRY() NCFGS_TRC(">> %s", __func__)
+#define NCFGS_EXIT() NCFGS_TRC("<< %s", __func__)
+
+#else // NCFGS_CONFIG_LOG_ENABLED
+
+#define NCFGS_TRC(...) /**< Disables traces. */
+#define NCFGS_DUMP(...) /**< Disables dumping of octet streams. */
+#define NCFGS_ERR(...) /**< Disables error logs. */
+
+#define NCFGS_ENTRY(...)
+#define NCFGS_EXIT(...)
+
+#endif // NCFGS_CONFIG_LOG_ENABLED
+
+/**@brief Function for adding the SSID Store characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t add_ssid_characteristic(ble_uuid_t * p_srv_uuid)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t char_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0x00, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+
+ memset(&attr_md, 0x00, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+ attr_md.wr_auth = 1;
+ attr_md.vloc = BLE_GATTS_VLOC_USER;
+
+ memset(&attr_char_value, 0x00, sizeof(attr_char_value));
+
+ char_uuid.type = p_srv_uuid->type;
+ char_uuid.uuid = BLE_UUID_NCFGS_SSID_CHAR;
+
+ attr_char_value.p_uuid = &char_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = NCFGS_SSID_MAX_LEN;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = NCFGS_SSID_MAX_LEN;
+ attr_char_value.p_value = &m_ncfgs_data.ssid_from_router.ssid[0];
+
+ return sd_ble_gatts_characteristic_add(m_database.service_handle,
+ &char_md,
+ &attr_char_value,
+ &m_database.ssid_handles);
+}
+
+
+/**@brief Function for adding the Keys Store characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t add_keys_store_characteristic(ble_uuid_t * p_srv_uuid)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t char_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0x00, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+
+ memset(&attr_md, 0x00, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+ attr_md.wr_auth = 1;
+ attr_md.vloc = BLE_GATTS_VLOC_USER;
+
+ memset(&attr_char_value, 0x00, sizeof(attr_char_value));
+
+ char_uuid.type = p_srv_uuid->type;
+ char_uuid.uuid = BLE_UUID_NCFGS_KEYS_STORE_CHAR;
+
+ attr_char_value.p_uuid = &char_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = NCFGS_KEYS_MAX_LEN;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = NCFGS_KEYS_MAX_LEN;
+ attr_char_value.p_value = &m_ncfgs_data.keys_from_router.keys[0];
+
+ return sd_ble_gatts_characteristic_add(m_database.service_handle,
+ &char_md,
+ &attr_char_value,
+ &m_database.keys_store_handles);
+}
+
+
+/**@brief Function for adding the Control Point characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t add_ip_cfg_cp_characteristic(ble_uuid_t * p_srv_uuid)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t char_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0x00, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+
+ memset(&attr_md, 0x00, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+ attr_md.wr_auth = 1;
+ attr_md.vloc = BLE_GATTS_VLOC_USER;
+
+ memset(&attr_char_value, 0x00, sizeof(attr_char_value));
+
+ char_uuid.type = p_srv_uuid->type;
+ char_uuid.uuid = BLE_UUID_NCFGS_CTRLPT_CHAR;
+
+ attr_char_value.p_uuid = &char_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = NCFGS_CTRLP_VALUE_LEN;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = NCFGS_CTRLP_VALUE_LEN;
+ attr_char_value.p_value = &m_ctrlp_value_buffer[0];
+
+ return sd_ble_gatts_characteristic_add(m_database.service_handle,
+ &char_md,
+ &attr_char_value,
+ &m_database.ctrlp_handles);
+}
+
+
+/**@brief Function for creating the GATT database.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t ble_ncfgs_create_database(void)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ // Add service.
+ ble_uuid_t service_uuid;
+
+ const ble_uuid128_t base_uuid128 =
+ {
+ {
+ 0x73, 0x3E, 0x2D, 0x02, 0xB7, 0x6B, 0xBE, 0xBE, \
+ 0xE5, 0x4F, 0x40, 0x8F, 0x00, 0x00, 0x20, 0x54
+ }
+ };
+
+ service_uuid.uuid = BLE_UUID_NODE_CFG_SERVICE;
+
+ err_code = sd_ble_uuid_vs_add(&base_uuid128, &(service_uuid.type));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, \
+ &service_uuid, \
+ &m_database.service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = add_ssid_characteristic(&service_uuid);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = add_keys_store_characteristic(&service_uuid);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = add_ip_cfg_cp_characteristic(&service_uuid);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ return err_code;
+}
+
+
+uint32_t ble_ncfgs_init(ble_ncfgs_evt_handler_t ble_ncfgs_cb)
+{
+ NCFGS_ENTRY();
+ uint32_t err_code;
+ memset(&m_ncfgs_data, 0x00, sizeof(m_ncfgs_data));
+
+ m_app_evt_handler = ble_ncfgs_cb;
+
+ err_code = ble_ncfgs_create_database();
+ NCFGS_EXIT();
+ return err_code;
+}
+
+
+/**@brief Function for decoding the Control Point characteristic value.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t ctrlp_value_decode(const ble_evt_t * p_ble_evt)
+{
+ uint16_t wr_req_value_len = \
+ p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.len;
+
+ memcpy(m_ctrlp_value_buffer, \
+ p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.data, \
+ wr_req_value_len);
+
+ m_ncfgs_data.ctrlp_value.opcode = \
+ (ble_ncfgs_opcode_t)m_ctrlp_value_buffer[0];
+ memcpy((void *)&m_ncfgs_data.ctrlp_value.delay_sec, \
+ &m_ctrlp_value_buffer[NCFGS_CTRLP_OPCODE_LEN], \
+ sizeof(uint32_t));
+ m_ncfgs_data.ctrlp_value.delay_sec = \
+ HTONL(m_ncfgs_data.ctrlp_value.delay_sec);
+ memcpy((void *)&m_ncfgs_data.ctrlp_value.duration_sec, \
+ &m_ctrlp_value_buffer[NCFGS_CTRLP_OPCODE_LEN+NCFGS_CTRLP_DELAY_LEN], \
+ sizeof(uint32_t));
+ m_ncfgs_data.ctrlp_value.duration_sec = \
+ HTONL(m_ncfgs_data.ctrlp_value.duration_sec);
+ m_ncfgs_data.ctrlp_value.state_on_failure = \
+ (state_on_failure_t)m_ctrlp_value_buffer[NCFGS_CTRLP_OPCODE_LEN+ \
+ NCFGS_CTRLP_DELAY_LEN+ \
+ NCFGS_CTRLP_DURATION_LEN];
+
+ if ((m_ncfgs_data.ctrlp_value.state_on_failure != NCFGS_SOF_NO_CHANGE) && \
+ (m_ncfgs_data.ctrlp_value.state_on_failure != NCFGS_SOF_PWR_OFF) && \
+ (m_ncfgs_data.ctrlp_value.state_on_failure != NCFGS_SOF_CONFIG_MODE))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ uint16_t id_data_len = wr_req_value_len - NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN;
+ if (id_data_len != 0)
+ {
+ m_ncfgs_data.id_data.identity_data_len = id_data_len;
+
+ memcpy(m_ncfgs_data.id_data.identity_data, \
+ &m_ctrlp_value_buffer[NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN], \
+ id_data_len);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+void ble_ncfgs_ble_evt_handler(const ble_evt_t * p_ble_evt)
+{
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ {
+ if (p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op == \
+ BLE_GATTS_OP_WRITE_REQ)
+ {
+ uint16_t wr_req_handle = \
+ p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.handle;
+ uint16_t wr_req_value_len = \
+ p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.len;
+
+ ble_gatts_rw_authorize_reply_params_t reply_params;
+ memset(&reply_params, 0x00, sizeof(reply_params));
+
+ reply_params.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ reply_params.params.write.update = 1;
+ reply_params.params.write.offset = p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.offset;
+ reply_params.params.write.len = p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.len;
+ reply_params.params.write.p_data = p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.data;
+
+ if (wr_req_handle == m_database.ssid_handles.value_handle)
+ {
+ NCFGS_TRC("> wr_req: ssid_handle");
+
+ if ((wr_req_value_len > NCFGS_SSID_MAX_LEN) || \
+ (wr_req_value_len < NCFGS_SSID_MIN_LEN))
+ {
+ reply_params.params.write.gatt_status = \
+ BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
+ }
+ else
+ {
+ m_ncfgs_data.ssid_from_router.ssid_len = wr_req_value_len;
+ m_service_state |= NCFGS_STATE_SSID_WRITTEN;
+
+ reply_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ }
+
+ UNUSED_RETURN_VALUE( \
+ sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle, \
+ &reply_params));
+ NCFGS_TRC("< wr_req: ssid_handle");
+ return;
+ }
+
+ else if (wr_req_handle == m_database.keys_store_handles.value_handle)
+ {
+ NCFGS_TRC("> wr_req: keys_store_handle");
+
+ if (wr_req_value_len > NCFGS_KEYS_MAX_LEN)
+ {
+ reply_params.params.write.gatt_status = \
+ BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
+ }
+ else
+ {
+ m_ncfgs_data.keys_from_router.keys_len = wr_req_value_len;
+ m_service_state |= NCFGS_STATE_KEYS_STORE_WRITTEN;
+ reply_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ }
+
+ UNUSED_RETURN_VALUE( \
+ sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle, \
+ &reply_params));
+ NCFGS_TRC("< wr_req: keys_store_handle");
+ return;
+ }
+
+ else if (wr_req_handle == m_database.ctrlp_handles.value_handle)
+ {
+ NCFGS_TRC("> wr_req: ctrlp_handle");
+
+ bool notify_app = false;
+
+ if ((wr_req_value_len > NCFGS_CTRLP_VALUE_LEN) || \
+ (wr_req_value_len < NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN))
+ {
+ reply_params.params.write.gatt_status = \
+ BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
+ }
+ else
+ {
+ ble_ncfgs_opcode_t opcode_in = (ble_ncfgs_opcode_t) \
+ p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.data[0];
+
+ reply_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ if ((opcode_in != NCFGS_OPCODE_GOTO_JOINING_MODE) && \
+ (opcode_in != NCFGS_OPCODE_GOTO_CONFIG_MODE) && \
+ (opcode_in != NCFGS_OPCODE_GOTO_IDENTITY_MODE))
+ {
+ reply_params.params.write.gatt_status = APP_GATTERR_UNKNOWN_OPCODE;
+ }
+
+ if (opcode_in == NCFGS_OPCODE_GOTO_JOINING_MODE)
+ {
+ if (!((m_service_state & NCFGS_STATE_SSID_WRITTEN) && \
+ (m_service_state & NCFGS_STATE_KEYS_STORE_WRITTEN)))
+ {
+ reply_params.params.write.gatt_status = APP_GATTERR_NOT_CONFIGURED;
+ }
+ }
+
+ if (reply_params.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ uint32_t err_code = ctrlp_value_decode(p_ble_evt);
+ if (err_code != NRF_SUCCESS)
+ {
+ reply_params.params.write.gatt_status = \
+ APP_GATTERR_INVALID_ATTR_VALUE;
+ }
+ else
+ {
+ notify_app = true;
+ }
+ }
+ }
+
+ UNUSED_RETURN_VALUE(sd_ble_gatts_rw_authorize_reply(
+ p_ble_evt->evt.gap_evt.conn_handle,
+ &reply_params));
+
+ if (notify_app == true)
+ {
+ NCFGS_TRC("> do notify parent");
+
+ m_app_evt_handler(&m_ncfgs_data);
+
+ NCFGS_TRC("< do notify parent");
+ }
+ NCFGS_TRC("< wr_req: ctrlp_handle");
+ }
+ else
+ {
+ // Invalid handle.
+ reply_params.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_HANDLE;
+ UNUSED_RETURN_VALUE(sd_ble_gatts_rw_authorize_reply(
+ p_ble_evt->evt.gap_evt.conn_handle, &reply_params));
+ }
+ }
+
+ break;
+ }
+
+ case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
+ {
+ ble_gap_data_length_params_t dl_params;
+
+ // Clearing the struct will effectively set members to @ref BLE_GAP_DATA_LENGTH_AUTO.
+ memset(&dl_params, 0, sizeof(ble_gap_data_length_params_t));
+ UNUSED_RETURN_VALUE(sd_ble_gap_data_length_update(p_ble_evt->evt.gap_evt.conn_handle, &dl_params, NULL));
+ break;
+ }
+
+ case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
+ {
+ NCFGS_TRC("> PHY update request.");
+
+ ble_gap_phys_t const phys =
+ {
+ .rx_phys = BLE_GAP_PHY_AUTO,
+ .tx_phys = BLE_GAP_PHY_AUTO,
+ };
+
+ UNUSED_RETURN_VALUE(sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
+
+ NCFGS_TRC("< PHY update request.");
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+#endif // COMMISSIONING_ENABLED
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.h
new file mode 100644
index 0000000..b59495d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.h
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_ncfgs Node Configuration Service
+ * @{
+ * @ingroup iot_sdk_common
+ * @brief Node Configuration Service module.
+ *
+ * @details The Node Configuration Service allows configuration of the node during commissioning.
+ * During initialization it adds the Node Configuration Service and the corresponding
+ * characteristics to the BLE GATT database. It decodes and checks the received values
+ * and then passes them to the parent module.
+ */
+
+#ifndef BLE_NODE_CFG_H__
+#define BLE_NODE_CFG_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "app_util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_UUID_NODE_CFG_SERVICE 0x7799
+#define BLE_UUID_NCFGS_SSID_CHAR 0x77A9
+#define BLE_UUID_NCFGS_KEYS_STORE_CHAR 0x77B9
+#define BLE_UUID_NCFGS_CTRLPT_CHAR 0x77C9
+
+#define APP_GATTERR_NOT_CONFIGURED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1 /**< ATT Error: Node configuration incomplete. */
+#define APP_GATTERR_UNKNOWN_OPCODE BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< ATT Error: Unknown opcode. */
+#define APP_GATTERR_INVALID_ATTR_VALUE BLE_GATT_STATUS_ATTERR_APP_BEGIN + 3 /**< ATT Error: Invalid attribute value. */
+
+#define NCFGS_SSID_MIN_LEN 6 /**< SSID minimum length. */
+#define NCFGS_SSID_MAX_LEN 16 /**< SSID maximum length. */
+#define NCFGS_KEYS_MAX_LEN 16 /**< Keys maximum length. */
+#define NCFGS_IDENTITY_DATA_MAX_LEN 8 /**< Identity data maximum length. */
+
+#define NCFGS_CTRLP_OPCODE_LEN 1 /**< Ctrlp: Opcode value length. */
+#define NCFGS_CTRLP_DELAY_LEN 4 /**< Ctrlp: Length of action delay value. */
+#define NCFGS_CTRLP_DURATION_LEN 4 /**< Ctrlp: Length of next mode duration value. */
+#define NCFGS_CTRLP_STATE_ON_FAILURE_LEN 1 /**< Ctrlp: Length of state-on-failure value. */
+
+#define NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN (NCFGS_CTRLP_OPCODE_LEN + \
+ NCFGS_CTRLP_DELAY_LEN + \
+ NCFGS_CTRLP_DURATION_LEN + \
+ NCFGS_CTRLP_STATE_ON_FAILURE_LEN) /**< Ctrlp: Total length of all values except identity data. */
+#define NCFGS_CTRLP_VALUE_LEN (NCFGS_CTRLP_OPCODE_LEN + \
+ NCFGS_CTRLP_DELAY_LEN + \
+ NCFGS_CTRLP_DURATION_LEN + \
+ NCFGS_CTRLP_STATE_ON_FAILURE_LEN + \
+ NCFGS_IDENTITY_DATA_MAX_LEN) /**< Ctrlp: Total length of all values. */
+
+#define HTONL(val) ((((uint32_t) (val) & 0xff000000) >> 24) | \
+ (((uint32_t) (val) & 0x00ff0000) >> 8) | \
+ (((uint32_t) (val) & 0x0000ff00) << 8) | \
+ (((uint32_t) (val) & 0x000000ff) << 24))
+
+/**@brief Node Configuration Service control point opcode values. */
+typedef enum
+{
+ NCFGS_OPCODE_GOTO_JOINING_MODE = 0x01,
+ NCFGS_OPCODE_GOTO_CONFIG_MODE = 0x02,
+ NCFGS_OPCODE_GOTO_IDENTITY_MODE = 0x03
+} ble_ncfgs_opcode_t;
+
+/**@brief Node Configuration Service configuration states. */
+typedef enum
+{
+ NCFGS_STATE_IDLE = 0x00,
+ NCFGS_STATE_SSID_WRITTEN = 0x01,
+ NCFGS_STATE_KEYS_STORE_WRITTEN = 0x02
+} ble_ncfgs_state_t;
+
+/**@brief Node Configuration Service state-on-failure values. */
+typedef enum
+{
+ NCFGS_SOF_NO_CHANGE = 0x00,
+ NCFGS_SOF_PWR_OFF = 0x01,
+ NCFGS_SOF_CONFIG_MODE = 0x02
+} state_on_failure_t;
+
+/**@brief Structure for storing keys received from the peer. */
+typedef struct __attribute__ ((__packed__))
+{
+ uint8_t keys_len;
+ uint8_t keys[NCFGS_KEYS_MAX_LEN]; // Keys received from the router.
+} keys_store_t;
+
+/**@brief Structure for storing the SSID received from the peer. */
+typedef struct __attribute__ ((__packed__))
+{
+ uint8_t ssid_len;
+ uint8_t ssid[NCFGS_SSID_MAX_LEN]; // SSID received from the router.
+} ssid_store_t;
+
+/**@brief Structure for storing the identity data from the peer. */
+typedef struct __attribute__ ((__packed__))
+{
+ uint8_t identity_data_len;
+ uint8_t identity_data[NCFGS_IDENTITY_DATA_MAX_LEN]; // Custom node identifier data.
+} id_data_store_t;
+
+/**@brief Structure for control point value. */
+typedef struct __attribute__ ((__packed__))
+{
+ ble_ncfgs_opcode_t opcode; // Mode to start.
+ uint32_t delay_sec; // Delay before entering >Opcode< mode.
+ uint32_t duration_sec; // General timeout for >Opcode< mode.
+ state_on_failure_t state_on_failure; // Mode to enter if >Opcode< mode fails (times out).
+} ble_ncfgs_ctrlp_value_t;
+
+/**@brief Structure for storing Node Configuration Service characteristic values. */
+typedef struct __attribute__ ((__packed__))
+{
+ ble_ncfgs_ctrlp_value_t ctrlp_value;
+ ssid_store_t ssid_from_router; // SSID received from the peer.
+ keys_store_t keys_from_router; // Keys received from the peer.
+ id_data_store_t id_data; // Identity data received from the peer.
+} ble_ncfgs_data_t;
+
+/**@brief Function for handling BLE events.
+ *
+ * @details This function must be called from the BLE stack event dispatcher
+ * to handle BLE events that are relevant for the Node Configuration Service module.
+ * It propagates an event to the parent layer if the Control Point characteristic
+ * was successfully written.
+ *
+ * @param[in] p_ble_evt BLE stack event.
+ */
+void ble_ncfgs_ble_evt_handler(const ble_evt_t * p_ble_evt);
+
+/**@brief Node Configuration Service event handler type. */
+typedef void (*ble_ncfgs_evt_handler_t) (ble_ncfgs_data_t * ncfgs_data);
+
+/**@brief Function for initializing the Node Configuration Service module.
+ *
+ * @details Interface for the Commissioning module to create a GATT database to
+ * allow for node configuration.
+ *
+ * @param[in] ble_ncfgs_cb Function to be called in case of an error.
+ *
+ * @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ble_ncfgs_init(ble_ncfgs_evt_handler_t ble_ncfgs_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_NODE_CFG_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.c
new file mode 100644
index 0000000..4ea6884
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.c
@@ -0,0 +1,1077 @@
+/**
+ * Copyright (c) 2015-2017 - 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.
+ *
+ */
+#ifdef COMMISSIONING_ENABLED
+
+#include <string.h>
+#include "boards.h"
+#include "ble_hci.h"
+#include "nrf_soc.h"
+#include "app_error.h"
+#include "fds.h"
+#include "ble_advdata.h"
+#include "commissioning.h"
+#include "nordic_common.h"
+#include "ble_srv_common.h"
+#include "sdk_config.h"
+
+#define MINIMUM_ACTION_DELAY 2 /**< Delay before executing an action after the control point was written (in seconds). */
+
+#define SEC_PARAM_BOND 0 /**< Perform bonding. */
+#define SEC_PARAM_MITM 1 /**< Man In The Middle protection required (applicable when display module is detected). */
+#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_KEYBOARD_ONLY /**< Display I/O capabilities. */
+#define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
+#define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
+#define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
+
+#define COMM_FDS_FILE_ID 0xCAFE /**< The ID of the file that the record belongs to. */
+#define COMM_FDS_RECORD_KEY 0xBEAF /**< The record key of FDS record that keeps node settings. */
+
+#define NUMBER_OF_COMMISSIONING_TIMERS 4
+#define TIMER_INDEX_DELAYED_ACTION 0
+#define TIMER_INDEX_CONFIG_MODE 1
+#define TIMER_INDEX_JOINING_MODE 2
+#define TIMER_INDEX_IDENTITY_MODE 3
+
+#define SEC_TO_MILLISEC(PARAM) (PARAM * 1000)
+
+static commissioning_settings_t m_node_settings; /**< All node settings as configured through the Node Configuration Service. */
+static commissioning_evt_handler_t m_commissioning_evt_handler; /**< Commissioning event handler of the parent layer. */
+static bool m_power_off_on_failure = false; /**< Power off on failure setting from the last NCFGS event. */
+static commissioning_timer_t m_commissioning_timers[NUMBER_OF_COMMISSIONING_TIMERS];
+
+static ipv6_medium_ble_gap_params_t m_config_mode_gap_params; /**< Advertising parameters in Config mode. */
+static ipv6_medium_ble_adv_params_t m_config_mode_adv_params; /**< GAP parameters in Config mode. */
+
+static ipv6_medium_ble_gap_params_t m_joining_mode_gap_params; /**< Advertising parameters in Joining mode. */
+static ipv6_medium_ble_adv_params_t m_joining_mode_adv_params; /**< GAP parameters in Joining mode. */
+
+static ble_uuid_t m_config_mode_adv_uuids[] = \
+ {
+ {BLE_UUID_NODE_CFG_SERVICE, \
+ BLE_UUID_TYPE_VENDOR_BEGIN}
+ }; /**< Config mode: List of available service UUIDs in advertisement data. */
+
+static ble_uuid_t m_joining_mode_adv_uuids[] = \
+ {
+ {BLE_UUID_IPSP_SERVICE, BLE_UUID_TYPE_BLE}
+ }; /**< Joining mode: List of available service UUIDs in advertisement data. */
+
+static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the active connection. */
+static uint8_t m_current_mode = NODE_MODE_NONE; /**< Current mode value. */
+static uint8_t m_next_mode = NODE_MODE_NONE; /**< Value of the mode the node will enter when the timeout handler of m_delayed_action_timer is triggered. */
+
+#if (FDS_ENABLED == 1)
+static fds_record_desc_t m_fds_record_desc; /**< Descriptor of FDS record. */
+#endif
+
+#define COMM_ENABLE_LOGS 1 /**< Set to 0 to disable debug trace in the module. */
+
+#if COMMISSIONING_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME commissioning
+
+#define NRF_LOG_LEVEL COMMISSIONING_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR COMMISSIONING_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR COMMISSIONING_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define COMM_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define COMM_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define COMM_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define COMM_ENTRY() COMM_TRC(">> %s", __func__)
+#define COMM_EXIT() COMM_TRC("<< %s", __func__)
+
+#else // COMMISSIONING_CONFIG_LOG_ENABLED
+
+#define COMM_TRC(...) /**< Disables traces. */
+#define COMM_DUMP(...) /**< Disables dumping of octet streams. */
+#define COMM_ERR(...) /**< Disables error logs. */
+
+#define COMM_ENTRY(...)
+#define COMM_EXIT(...)
+
+#endif // COMMISSIONING_CONFIG_LOG_ENABLED
+
+
+/**@brief Function for validating all node settings.
+ */
+static bool settings_are_valid()
+{
+ uint8_t tmp = m_node_settings.poweron_mode;
+ if (tmp == 0xFF)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+#if (FDS_ENABLED == 1)
+/**@brief Function for updating the node settings in persistent memory.
+ */
+static uint32_t persistent_settings_update(void)
+{
+ uint32_t err_code;
+
+ fds_find_token_t token;
+ memset(&token, 0, sizeof(token));
+
+ fds_record_t record;
+ memset(&record, 0, sizeof(record));
+
+ record.file_id = COMM_FDS_FILE_ID;
+ record.key = COMM_FDS_RECORD_KEY;
+ record.data.p_data = &m_node_settings;
+ record.data.length_words = ALIGN_NUM(4, sizeof(commissioning_settings_t))/sizeof(uint32_t);
+
+ // Try to find FDS record with node settings.
+ err_code = fds_record_find(COMM_FDS_FILE_ID, COMM_FDS_RECORD_KEY, &m_fds_record_desc, &token);
+ if (err_code == FDS_SUCCESS)
+ {
+ err_code = fds_record_update(&m_fds_record_desc, &record);
+ }
+ else
+ {
+
+ err_code = fds_record_write(&m_fds_record_desc, &record);
+ }
+
+ if (err_code == FDS_ERR_NO_SPACE_IN_FLASH)
+ {
+ // Run garbage collector to reclaim the flash space that is occupied by records that have been deleted,
+ // or that failed to be completely written due to, for example, a power loss.
+ err_code = fds_gc();
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for loading node settings from the persistent memory.
+ */
+static void persistent_settings_load(void)
+{
+ uint32_t err_code = FDS_SUCCESS;
+ fds_flash_record_t record;
+
+ fds_find_token_t token;
+ memset(&token, 0, sizeof(token));
+
+ // Try to find FDS record with node settings.
+ err_code = fds_record_find(COMM_FDS_FILE_ID, COMM_FDS_RECORD_KEY, &m_fds_record_desc, &token);
+ if (err_code == FDS_SUCCESS)
+ {
+ err_code = fds_record_open(&m_fds_record_desc, &record);
+ if (err_code == FDS_SUCCESS)
+ {
+ if (record.p_data)
+ {
+ memcpy(&m_node_settings, record.p_data, sizeof(m_node_settings));
+ }
+ }
+ }
+}
+
+
+/**@brief Function for clearing node settings from the persistent memory.
+ */
+static void persistent_settings_clear(void)
+{
+ fds_record_delete(&m_fds_record_desc);
+}
+
+/**@brief Function for handling File Data Storage events.
+ */
+static void persistent_settings_cb(fds_evt_t const * p_evt)
+{
+ if (p_evt->id == FDS_EVT_GC)
+ {
+ if (settings_are_valid())
+ {
+ persistent_settings_update();
+ }
+ }
+}
+
+
+/**@brief Function for initializing the File Data Storage module.
+ */
+static uint32_t persistent_settings_init(void)
+{
+ uint32_t err_code;
+
+ err_code = fds_init();
+ if (err_code == FDS_SUCCESS)
+ {
+ err_code = fds_register(persistent_settings_cb);
+ }
+
+ return err_code;
+}
+#endif
+
+
+/**@brief Function for setting advertisement parameters in Config mode.
+ */
+static void config_mode_adv_params_set(void)
+{
+ COMM_ENTRY();
+ memset(&m_config_mode_adv_params, 0x00, sizeof(m_config_mode_adv_params));
+
+ m_config_mode_adv_params.advdata.name_type = BLE_ADVDATA_FULL_NAME;
+ m_config_mode_adv_params.advdata.include_appearance = false;
+ m_config_mode_adv_params.advdata.flags = \
+ BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
+ m_config_mode_adv_params.advdata.uuids_complete.uuid_cnt = \
+ sizeof(m_config_mode_adv_uuids) / sizeof(m_config_mode_adv_uuids[0]);
+ m_config_mode_adv_params.advdata.uuids_complete.p_uuids = m_config_mode_adv_uuids;
+ m_config_mode_adv_params.advdata.p_manuf_specific_data = NULL;
+
+ if (m_node_settings.id_data_store.identity_data_len > 0)
+ {
+ m_config_mode_adv_params.sr_man_specific_data.data.size = \
+ m_node_settings.id_data_store.identity_data_len;
+ m_config_mode_adv_params.sr_man_specific_data.data.p_data = \
+ m_node_settings.id_data_store.identity_data;
+ m_config_mode_adv_params.sr_man_specific_data.company_identifier = \
+ COMPANY_IDENTIFIER;
+ m_config_mode_adv_params.srdata.p_manuf_specific_data = \
+ &m_config_mode_adv_params.sr_man_specific_data;
+ }
+ else
+ {
+ m_config_mode_adv_params.srdata.p_manuf_specific_data = NULL;
+ }
+
+ m_config_mode_adv_params.advparams.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+ m_config_mode_adv_params.advparams.p_peer_addr = NULL; // Undirected advertisement.
+ m_config_mode_adv_params.advparams.filter_policy = BLE_GAP_ADV_FP_ANY;
+ m_config_mode_adv_params.advparams.interval = CONFIG_MODE_ADV_ADV_INTERVAL;
+ m_config_mode_adv_params.advparams.duration = CONFIG_MODE_ADV_TIMEOUT;
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for setting GAP parameters in Config mode.
+ */
+static void config_mode_gap_params_set(void)
+{
+ COMM_ENTRY();
+
+ memset(&m_config_mode_gap_params, 0x00, sizeof(m_config_mode_gap_params));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&m_config_mode_gap_params.sec_mode);
+
+ m_config_mode_gap_params.p_dev_name = (const uint8_t *)CONFIG_MODE_DEVICE_NAME;
+ m_config_mode_gap_params.dev_name_len = strlen(CONFIG_MODE_DEVICE_NAME);
+
+ m_config_mode_gap_params.gap_conn_params.min_conn_interval = \
+ (uint16_t)CONFIG_MODE_MIN_CONN_INTERVAL;
+ m_config_mode_gap_params.gap_conn_params.max_conn_interval = \
+ (uint16_t)CONFIG_MODE_MAX_CONN_INTERVAL;
+ m_config_mode_gap_params.gap_conn_params.slave_latency = CONFIG_MODE_SLAVE_LATENCY;
+ m_config_mode_gap_params.gap_conn_params.conn_sup_timeout = CONFIG_MODE_CONN_SUP_TIMEOUT;
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for setting advertisement parameters in Joining mode.
+ */
+static void joining_mode_adv_params_set(void)
+{
+ COMM_ENTRY();
+
+ memset(&m_joining_mode_adv_params, 0x00, sizeof(m_joining_mode_adv_params));
+
+ if (m_node_settings.ssid_store.ssid_len > 0)
+ {
+ m_joining_mode_adv_params.adv_man_specific_data.data.size = \
+ m_node_settings.ssid_store.ssid_len;
+ m_joining_mode_adv_params.adv_man_specific_data.data.p_data = \
+ m_node_settings.ssid_store.ssid;
+ m_joining_mode_adv_params.adv_man_specific_data.company_identifier = \
+ COMPANY_IDENTIFIER;
+ }
+
+ m_joining_mode_adv_params.advdata.name_type = BLE_ADVDATA_NO_NAME;
+ m_joining_mode_adv_params.advdata.include_appearance = false;
+ m_joining_mode_adv_params.advdata.flags = \
+ BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
+ m_joining_mode_adv_params.advdata.uuids_complete.uuid_cnt = \
+ sizeof(m_joining_mode_adv_uuids) / sizeof(m_joining_mode_adv_uuids[0]);
+ m_joining_mode_adv_params.advdata.uuids_complete.p_uuids = m_joining_mode_adv_uuids;
+ if (m_node_settings.ssid_store.ssid_len > 0)
+ {
+ m_joining_mode_adv_params.advdata.p_manuf_specific_data = \
+ &m_joining_mode_adv_params.adv_man_specific_data;
+ }
+ else
+ {
+ m_joining_mode_adv_params.advdata.p_manuf_specific_data = NULL;
+ }
+
+ if (m_node_settings.id_data_store.identity_data_len > 0)
+ {
+ m_joining_mode_adv_params.sr_man_specific_data.data.size = \
+ m_node_settings.id_data_store.identity_data_len;
+ m_joining_mode_adv_params.sr_man_specific_data.data.p_data = \
+ m_node_settings.id_data_store.identity_data;
+ m_joining_mode_adv_params.sr_man_specific_data.company_identifier = \
+ COMPANY_IDENTIFIER;
+ m_joining_mode_adv_params.srdata.p_manuf_specific_data = \
+ &m_joining_mode_adv_params.sr_man_specific_data;
+ }
+ else
+ {
+ m_joining_mode_adv_params.srdata.p_manuf_specific_data = NULL;
+ }
+
+ m_joining_mode_adv_params.advparams.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+ m_joining_mode_adv_params.advparams.p_peer_addr = NULL; // Undirected advertisement.
+ m_joining_mode_adv_params.advparams.filter_policy = BLE_GAP_ADV_FP_ANY;
+ m_joining_mode_adv_params.advparams.interval = APP_ADV_ADV_INTERVAL;
+ m_joining_mode_adv_params.advparams.duration = APP_ADV_DURATION;
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for setting GAP parameters in Joining mode.
+ */
+static void joining_mode_gap_params_set(void)
+{
+ COMM_ENTRY();
+
+ memset(&m_joining_mode_gap_params, 0x00, sizeof(m_joining_mode_gap_params));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&m_joining_mode_gap_params.sec_mode);
+
+ m_joining_mode_gap_params.appearance = BLE_APPEARANCE_UNKNOWN;
+
+ m_joining_mode_gap_params.p_dev_name = (const uint8_t *)DEVICE_NAME;
+ m_joining_mode_gap_params.dev_name_len = strlen(DEVICE_NAME);
+
+ m_joining_mode_gap_params.gap_conn_params.min_conn_interval = \
+ (uint16_t)JOINING_MODE_MIN_CONN_INTERVAL;
+ m_joining_mode_gap_params.gap_conn_params.max_conn_interval = \
+ (uint16_t)JOINING_MODE_MAX_CONN_INTERVAL;
+ m_joining_mode_gap_params.gap_conn_params.slave_latency = JOINING_MODE_SLAVE_LATENCY;
+ m_joining_mode_gap_params.gap_conn_params.conn_sup_timeout = JOINING_MODE_CONN_SUP_TIMEOUT;
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for starting a timer in the Commissioning module.
+ *
+ */
+static void commissioning_timer_start(uint8_t index, uint32_t timeout_sec)
+{
+ m_commissioning_timers[index].is_timer_running = true;
+ m_commissioning_timers[index].current_value_sec = timeout_sec;
+}
+
+
+/**@brief Function for stopping and re-setting a timer in the Commissioning module.
+ *
+ */
+static void commissioning_timer_stop_reset(uint8_t index)
+{
+ m_commissioning_timers[index].is_timer_running = false;
+ m_commissioning_timers[index].current_value_sec = 0x00;
+}
+
+
+void commissioning_node_mode_change(uint8_t new_mode)
+{
+ COMM_ENTRY();
+
+ commissioning_evt_t commissioning_evt;
+ memset(&commissioning_evt, 0x00, sizeof(commissioning_evt));
+ commissioning_evt.p_commissioning_settings = &m_node_settings;
+ commissioning_evt.power_off_enable_requested = m_power_off_on_failure;
+
+ commissioning_timer_stop_reset(TIMER_INDEX_DELAYED_ACTION);
+ commissioning_timer_stop_reset(TIMER_INDEX_CONFIG_MODE);
+ commissioning_timer_stop_reset(TIMER_INDEX_JOINING_MODE);
+
+ config_mode_gap_params_set();
+ config_mode_adv_params_set();
+ joining_mode_gap_params_set();
+ joining_mode_adv_params_set();
+
+ m_current_mode = new_mode;
+
+ switch (m_current_mode)
+ {
+ case NODE_MODE_CONFIG:
+ {
+ commissioning_evt.commissioning_evt_id = COMMISSIONING_EVT_CONFIG_MODE_ENTER;
+ m_commissioning_evt_handler(&commissioning_evt);
+
+ // Start Configuration mode timer.
+ COMM_TRC("Config mode timeout: %ld seconds", m_node_settings.config_mode_to);
+ commissioning_timer_start(TIMER_INDEX_CONFIG_MODE, m_node_settings.config_mode_to);
+
+ break;
+ }
+ case NODE_MODE_JOINING:
+ {
+ commissioning_evt.commissioning_evt_id = COMMISSIONING_EVT_JOINING_MODE_ENTER;
+ m_commissioning_evt_handler(&commissioning_evt);
+
+ // Start Joining mode timer.
+ COMM_TRC("Joining mode timeout: %ld seconds", m_node_settings.joining_mode_to);
+ commissioning_timer_start(TIMER_INDEX_JOINING_MODE, m_node_settings.joining_mode_to);
+
+ break;
+ }
+ case NODE_MODE_IDENTITY:
+ {
+ commissioning_evt.commissioning_evt_id = COMMISSIONING_EVT_IDENTITY_MODE_ENTER;
+ m_commissioning_evt_handler(&commissioning_evt);
+
+ // Start Identity mode timer.
+ COMM_TRC("Identity mode timeout: %ld seconds", m_node_settings.id_mode_to);
+ commissioning_timer_start(TIMER_INDEX_IDENTITY_MODE, m_node_settings.id_mode_to);
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for handling the Delayed action timer timeout.
+ *
+ * @details This function will be called each time the delayed action timer expires.
+ *
+ */
+static void action_timeout_handler(void)
+{
+ COMM_ENTRY();
+
+ commissioning_node_mode_change(m_next_mode);
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for handling the Config mode timer timeout.
+ *
+ * @details This function will be called each time the Config mode timer expires.
+ *
+ */
+static void config_mode_timeout_handler(void)
+{
+ COMM_ENTRY();
+
+ switch (m_node_settings.config_mode_failure)
+ {
+ case NCFGS_SOF_NO_CHANGE:
+ // Fall-through.
+ case NCFGS_SOF_CONFIG_MODE:
+ {
+ commissioning_node_mode_change(NODE_MODE_CONFIG);
+
+ break;
+ }
+ case NCFGS_SOF_PWR_OFF:
+ {
+ LEDS_OFF(LEDS_MASK);
+ // The main timer in Config mode timed out, power off.
+ UNUSED_VARIABLE(sd_power_system_off());
+
+ break;
+ }
+ }
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for handling the Joining mode timer timeout.
+ *
+ * @details This function will be called each time the Joining mode timer expires.
+ *
+ */
+void joining_mode_timeout_handler(void)
+{
+ COMM_ENTRY();
+
+ switch (m_node_settings.joining_mode_failure)
+ {
+ case NCFGS_SOF_NO_CHANGE:
+ {
+ commissioning_node_mode_change(NODE_MODE_JOINING);
+ break;
+ }
+ case NCFGS_SOF_PWR_OFF:
+ {
+ LEDS_OFF(LEDS_MASK);
+
+ UNUSED_VARIABLE(sd_power_system_off());
+ break;
+ }
+ case NCFGS_SOF_CONFIG_MODE:
+ {
+ commissioning_node_mode_change(NODE_MODE_CONFIG);
+ break;
+ }
+ }
+
+ COMM_EXIT();
+}
+
+
+/**@brief Function for handling the Identity mode timer timeout.
+ *
+ * @details This function will be called each time the Identity mode timer expires.
+ *
+ */
+void identity_mode_timeout_handler(void)
+{
+ COMM_ENTRY();
+
+ commissioning_evt_t commissioning_evt;
+ memset(&commissioning_evt, 0x00, sizeof(commissioning_evt));
+ commissioning_evt.commissioning_evt_id = COMMISSIONING_EVT_IDENTITY_MODE_EXIT;
+
+ m_commissioning_evt_handler(&commissioning_evt);
+
+ COMM_EXIT();
+}
+
+
+void commissioning_joining_mode_timer_ctrl( \
+ joining_mode_timer_ctrl_cmd_t joining_mode_timer_ctrl_cmd)
+{
+ switch (joining_mode_timer_ctrl_cmd)
+ {
+ case JOINING_MODE_TIMER_STOP_RESET:
+ {
+ commissioning_timer_stop_reset(TIMER_INDEX_JOINING_MODE);
+
+ break;
+ }
+ case JOINING_MODE_TIMER_START:
+ {
+ commissioning_timer_start(TIMER_INDEX_JOINING_MODE, m_node_settings.joining_mode_to);
+
+ break;
+ }
+ }
+}
+
+
+void commissioning_gap_params_get(ipv6_medium_ble_gap_params_t ** pp_node_gap_params)
+{
+ switch (m_current_mode)
+ {
+ case NODE_MODE_JOINING:
+ {
+ *pp_node_gap_params = &m_joining_mode_gap_params;
+
+ break;
+ }
+ case NODE_MODE_IDENTITY:
+ // Fall-through.
+ case NODE_MODE_CONFIG:
+ {
+ *pp_node_gap_params = &m_config_mode_gap_params;
+
+ break;
+ }
+ }
+}
+
+
+void commissioning_adv_params_get(ipv6_medium_ble_adv_params_t ** pp_node_adv_params)
+{
+ switch (m_current_mode)
+ {
+ case NODE_MODE_JOINING:
+ {
+ *pp_node_adv_params = &m_joining_mode_adv_params;
+
+ break;
+ }
+ case NODE_MODE_IDENTITY:
+ // Fall-through.
+ case NODE_MODE_CONFIG:
+ {
+ *pp_node_adv_params = &m_config_mode_adv_params;
+
+ break;
+ }
+ }
+}
+
+
+/**@brief Function for reading all node settings from the persistent storage.
+ */
+static void read_node_settings(void)
+{
+ memset(&m_node_settings, 0x00, sizeof(m_node_settings));
+
+#if (FDS_ENABLED == 1)
+ persistent_settings_load();
+#endif // FDS_ENABLED
+
+ if (m_node_settings.ssid_store.ssid_len > NCFGS_SSID_MAX_LEN)
+ {
+ m_node_settings.ssid_store.ssid_len = 0;
+ }
+ if (m_node_settings.keys_store.keys_len > NCFGS_KEYS_MAX_LEN)
+ {
+ m_node_settings.keys_store.keys_len = 0;
+ }
+ if (m_node_settings.id_data_store.identity_data_len > NCFGS_IDENTITY_DATA_MAX_LEN)
+ {
+ m_node_settings.id_data_store.identity_data_len = 0;
+ }
+
+ // The duration of each mode needs to be at least 10 second.
+ m_node_settings.joining_mode_to = \
+ (m_node_settings.joining_mode_to < 10) ? 10 : m_node_settings.joining_mode_to;
+ m_node_settings.config_mode_to = \
+ (m_node_settings.config_mode_to < 10) ? 10 : m_node_settings.config_mode_to;
+ m_node_settings.id_mode_to = \
+ (m_node_settings.id_mode_to < 10) ? 10 : m_node_settings.id_mode_to;
+}
+
+#if (COMM_ENABLE_LOGS == 1)
+/**@brief Function for printing all node settings.
+ */
+static void print_node_settings(void)
+{
+ COMM_TRC("");
+ COMM_TRC(" Commissioning settings in memory:");
+ COMM_TRC(" Start mode: %5d", m_node_settings.poweron_mode);
+ COMM_TRC(" Mode if Joining Mode fails: %5d", m_node_settings.joining_mode_failure);
+ COMM_TRC(" General timeout in Joining Mode: %5ld", m_node_settings.joining_mode_to);
+ COMM_TRC(" Mode if Configuration Mode fails: %5d", m_node_settings.config_mode_failure);
+ COMM_TRC("General timeout in Configuration Mode: %5ld", m_node_settings.config_mode_to);
+ COMM_TRC(" Identity Mode duration: %5ld", m_node_settings.id_mode_to);
+ COMM_TRC(" Stored Keys length: %5d", m_node_settings.keys_store.keys_len);
+ COMM_TRC(" Stored Keys:");
+ uint8_t ii;
+ for (ii=0; ii<m_node_settings.keys_store.keys_len; ++ii)
+ {
+ COMM_TRC("0x%02X", m_node_settings.keys_store.keys[ii]);
+ }
+ COMM_TRC("");
+ COMM_TRC(" Stored SSID length: %5d", m_node_settings.ssid_store.ssid_len);
+ COMM_TRC(" Stored SSID:");
+ for (ii=0; ii<m_node_settings.ssid_store.ssid_len; ++ii)
+ {
+ COMM_TRC("0x%02X", m_node_settings.ssid_store.ssid[ii]);
+ }
+ COMM_TRC("");
+ COMM_TRC(" Stored Identity Data length: %5d", m_node_settings.id_data_store.identity_data_len);
+ COMM_TRC(" Stored Identity Data:");
+ for (ii=0; ii<m_node_settings.id_data_store.identity_data_len; ++ii)
+ {
+ COMM_TRC("0x%02X", m_node_settings.id_data_store.identity_data[ii]);
+ }
+ COMM_TRC("");
+}
+#endif // (COMM_ENABLE_LOGS == 1)
+
+
+void commissioning_settings_clear(void)
+{
+ COMM_ENTRY();
+ memset(&m_node_settings, 0x00, sizeof(m_node_settings));
+
+#if (FDS_ENABLED == 1)
+ persistent_settings_clear();
+#endif // FDS_ENABLED
+
+ COMM_EXIT();
+}
+
+
+void commissioning_ble_evt_handler(const ble_evt_t * p_ble_evt)
+{
+ uint32_t err_code;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ {
+ m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ commissioning_timer_stop_reset(TIMER_INDEX_DELAYED_ACTION);
+ commissioning_timer_stop_reset(TIMER_INDEX_CONFIG_MODE);
+
+ break;
+ }
+ case BLE_GAP_EVT_DISCONNECTED:
+ {
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+ if (m_current_mode == NODE_MODE_CONFIG)
+ {
+ commissioning_timer_start(TIMER_INDEX_CONFIG_MODE, \
+ m_node_settings.config_mode_to);
+ }
+ if (m_current_mode == NODE_MODE_JOINING)
+ {
+ commissioning_timer_start(TIMER_INDEX_JOINING_MODE, \
+ m_node_settings.joining_mode_to);
+ }
+
+ break;
+ }
+ case BLE_GAP_EVT_AUTH_KEY_REQUEST:
+ {
+ if (m_current_mode == NODE_MODE_JOINING)
+ {
+ // If passkey is shorter than BLE_GAP_PASSKEY_LEN, add '0' character.
+ if (m_node_settings.keys_store.keys_len < BLE_GAP_PASSKEY_LEN)
+ {
+ memset(&m_node_settings.keys_store.keys[m_node_settings.keys_store.keys_len], \
+ '0', BLE_GAP_PASSKEY_LEN - m_node_settings.keys_store.keys_len);
+ }
+
+ // Short passkey to 6-length character.
+ m_node_settings.keys_store.keys[BLE_GAP_PASSKEY_LEN] = 0;
+
+ COMM_TRC("Stored passkey is: %s", m_node_settings.keys_store.keys);
+
+ err_code = sd_ble_gap_auth_key_reply(m_conn_handle, \
+ BLE_GAP_AUTH_KEY_TYPE_PASSKEY, \
+ m_node_settings.keys_store.keys);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ break;
+ }
+ case BLE_GAP_EVT_AUTH_STATUS:
+ {
+ if (m_current_mode == NODE_MODE_JOINING)
+ {
+ COMM_TRC("Status of authentication: %08x", \
+ p_ble_evt->evt.gap_evt.params.auth_status.auth_status);
+ }
+
+ break;
+ }
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ {
+ if (m_current_mode == NODE_MODE_JOINING)
+ {
+ ble_gap_sec_params_t sec_param;
+ ble_gap_sec_keyset_t keys_exchanged;
+
+ memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
+ memset(&keys_exchanged, 0, sizeof(ble_gap_sec_keyset_t));
+
+ sec_param.bond = SEC_PARAM_BOND;
+ sec_param.oob = SEC_PARAM_OOB;
+ sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
+ sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
+ sec_param.mitm = SEC_PARAM_MITM;
+ sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
+
+ err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle,
+ BLE_GAP_SEC_STATUS_SUCCESS,
+ &sec_param,
+ &keys_exchanged);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+
+void on_ble_ncfgs_evt(ble_ncfgs_data_t * ncfgs_data)
+{
+ COMM_ENTRY();
+
+ commissioning_timer_stop_reset(TIMER_INDEX_DELAYED_ACTION);
+ commissioning_timer_stop_reset(TIMER_INDEX_CONFIG_MODE);
+
+ uint32_t mode_duration_sec;
+ mode_duration_sec = ncfgs_data->ctrlp_value.duration_sec;
+ mode_duration_sec = (mode_duration_sec == 0) ? 1 : mode_duration_sec;
+
+ switch (ncfgs_data->ctrlp_value.opcode)
+ {
+ case NCFGS_OPCODE_GOTO_JOINING_MODE:
+ {
+ m_next_mode = NODE_MODE_JOINING;
+
+ m_node_settings.joining_mode_to = mode_duration_sec;
+ m_node_settings.joining_mode_failure = ncfgs_data->ctrlp_value.state_on_failure;
+
+ /* This code will get executed in two scenarios:
+ - if the previous mode was Config mode and now we are ready to connect to the router, or
+ - if the previous mode was Joining mode and the state on failure was set to No Change.
+ */
+ if (m_node_settings.joining_mode_failure == NCFGS_SOF_NO_CHANGE)
+ {
+ m_node_settings.poweron_mode = NODE_MODE_JOINING;
+ }
+ else
+ {
+ // If the state on failure is NOT No Change, start next time in Config mode.
+ m_node_settings.poweron_mode = NODE_MODE_CONFIG;
+ }
+
+ if (m_node_settings.joining_mode_failure == NCFGS_SOF_PWR_OFF)
+ {
+ COMM_TRC("Will power off on failure.");
+ m_power_off_on_failure = true; // The assert handler will power off the system.
+ }
+
+ break;
+ }
+ case NCFGS_OPCODE_GOTO_CONFIG_MODE:
+ {
+ m_next_mode = NODE_MODE_CONFIG;
+
+ m_node_settings.config_mode_to = mode_duration_sec;
+ m_node_settings.config_mode_failure = ncfgs_data->ctrlp_value.state_on_failure;
+
+ /* The node is about to enter Config mode. Regardless of what the state on failure
+ setting is (No Change or Pwr Off or Cfg Mode), the poweron_mode value should be Cfg Mode. */
+ m_node_settings.poweron_mode = NODE_MODE_CONFIG;
+
+ if (m_node_settings.config_mode_failure == NCFGS_SOF_PWR_OFF)
+ {
+ COMM_TRC("Will power off on failure.");
+ m_power_off_on_failure = true; // The assert handler will power off the system.
+ }
+
+ break;
+ }
+ case NCFGS_OPCODE_GOTO_IDENTITY_MODE:
+ {
+ m_next_mode = NODE_MODE_IDENTITY;
+
+ m_node_settings.id_mode_to = mode_duration_sec;
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ memcpy(&m_node_settings.ssid_store, &ncfgs_data->ssid_from_router, sizeof(ssid_store_t));
+ memcpy(&m_node_settings.keys_store, &ncfgs_data->keys_from_router, sizeof(keys_store_t));
+ memcpy(&m_node_settings.id_data_store, &ncfgs_data->id_data, sizeof(id_data_store_t));
+
+#if (COMM_ENABLE_LOGS == 1)
+ print_node_settings();
+#endif // (COMM_ENABLE_LOGS == 1)
+
+#if (FDS_ENABLED == 1)
+ uint32_t err_code = persistent_settings_update();
+ APP_ERROR_CHECK(err_code);
+#endif // FDS_ENABLED
+
+ uint32_t action_delay_written = ncfgs_data->ctrlp_value.delay_sec;
+ // Set the timeout value to at least MINIMUM_ACTION_DELAY second(s).
+ // This is to make sure that storing settings in the persistent
+ // storage completes before activating the next mode.
+ action_delay_written = (action_delay_written < MINIMUM_ACTION_DELAY) ? \
+ MINIMUM_ACTION_DELAY : action_delay_written;
+
+ COMM_TRC("Action delay: %ld seconds.", action_delay_written);
+ commissioning_timer_start(TIMER_INDEX_DELAYED_ACTION, action_delay_written);
+
+ COMM_EXIT();
+}
+
+
+void commissioning_time_tick(iot_timer_time_in_ms_t wall_clock_value)
+{
+ UNUSED_PARAMETER(wall_clock_value);
+ uint8_t index;
+
+ for (index=0; index<NUMBER_OF_COMMISSIONING_TIMERS; ++index)
+ {
+ if (m_commissioning_timers[index].is_timer_running == true)
+ {
+ m_commissioning_timers[index].current_value_sec -= COMMISSIONING_TICK_INTERVAL_SEC;
+
+ if (m_commissioning_timers[index].current_value_sec == 0)
+ {
+ commissioning_timer_stop_reset(index);
+ m_commissioning_timers[index].timeout_handler();
+ }
+ }
+ }
+}
+
+
+static void commissioning_timers_init(void)
+{
+ memset(m_commissioning_timers, 0x00, sizeof(m_commissioning_timers));
+ m_commissioning_timers[TIMER_INDEX_DELAYED_ACTION].timeout_handler = \
+ action_timeout_handler;
+ m_commissioning_timers[TIMER_INDEX_CONFIG_MODE].timeout_handler = \
+ config_mode_timeout_handler;
+ m_commissioning_timers[TIMER_INDEX_JOINING_MODE].timeout_handler = \
+ joining_mode_timeout_handler;
+ m_commissioning_timers[TIMER_INDEX_IDENTITY_MODE].timeout_handler = \
+ identity_mode_timeout_handler;
+}
+
+uint32_t commissioning_init(commissioning_init_params_t * p_init_param, \
+ uint8_t * p_poweron_state)
+{
+ COMM_ENTRY();
+ uint32_t err_code = NRF_SUCCESS;
+
+ m_commissioning_evt_handler = p_init_param->commissioning_evt_handler;
+ m_power_off_on_failure = false;
+
+ // Initialize Commissioning timers.
+
+ commissioning_timers_init();
+
+ // Initialize GATT server.
+
+ err_code = ble_ncfgs_init(on_ble_ncfgs_evt);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+#if (FDS_ENABLED == 1)
+ err_code = persistent_settings_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+#endif
+
+ // Read application settings from persistent storage.
+ read_node_settings();
+
+#if (COMM_ENABLE_LOGS == 1)
+ print_node_settings();
+#endif // (COMM_ENABLE_LOGS == 1)
+
+ if (!settings_are_valid()) // If the settings are invalid for any reason go to Config mode.
+ {
+ COMM_ERR("Invalid settings!");
+
+ commissioning_settings_clear();
+
+ memset(&m_node_settings, 0x00, sizeof(m_node_settings));
+ m_node_settings.config_mode_to = 300;
+
+ *p_poweron_state = NODE_MODE_CONFIG;
+ }
+ else
+ {
+ if (m_node_settings.poweron_mode == NODE_MODE_JOINING)
+ {
+ /* This code will get executed in two scenarios:
+ - if the previous mode was Config mode and now we are ready to connect to the router, or
+ - if the previous mode was Joining mode and the state on failure was set to No Change.
+ */
+ if ((m_node_settings.joining_mode_failure == NCFGS_SOF_PWR_OFF) || \
+ (m_node_settings.joining_mode_failure == NCFGS_SOF_CONFIG_MODE))
+ {
+ // If the state on failure is NOT No Change, start next time in Config mode.
+ m_node_settings.poweron_mode = NODE_MODE_CONFIG;
+#if (FDS_ENABLED == 1)
+ err_code = persistent_settings_update();
+ APP_ERROR_CHECK(err_code);
+#endif // FDS_ENABLED
+ }
+
+ if (m_node_settings.joining_mode_failure == NCFGS_SOF_PWR_OFF)
+ {
+ COMM_TRC("Will power off on failure.");
+ m_power_off_on_failure = true; // The assert handler will power off the system.
+ }
+
+ *p_poweron_state = NODE_MODE_JOINING;
+ }
+ else
+ {
+ /* The app is about to enter Config mode. Regardless of what the state on failure
+ setting is (No Change or Pwr Off or Cfg Mode), the poweron_mode value should remain the same. */
+
+ if (m_node_settings.config_mode_failure == NCFGS_SOF_PWR_OFF)
+ {
+ COMM_TRC("Will power off on failure.");
+ m_power_off_on_failure = true; // The assert handler will power off the system.
+ }
+
+ *p_poweron_state = NODE_MODE_CONFIG;
+ }
+ }
+
+ // Set advertising and GAP parameters.
+ config_mode_gap_params_set();
+ config_mode_adv_params_set();
+ joining_mode_gap_params_set();
+ joining_mode_adv_params_set();
+
+ COMM_EXIT();
+ return err_code;
+}
+
+#endif // COMMISSIONING_ENABLED
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.h
new file mode 100644
index 0000000..777f60e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/commissioning/commissioning.h
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2015-2017 - 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup commissioning_module Commissioning Module
+ * @{
+ * @ingroup iot_sdk_common
+ * @brief Commissioning module.
+ *
+ * @details Enables commissioning of the node by managing transitions between the Config, Joining, and
+ * Identity modes. In Config mode the node can be configured with the settings required to
+ * join the network in Joining mode. The Identity mode can be requested to make the node
+ * easily recognizable for the user.
+ * The settings managed by the module are stored in persistent storage.
+ */
+
+#ifndef COMMISSIONING_H__
+#define COMMISSIONING_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble_ncfgs.h"
+#include "iot_timer.h"
+#include "ipv6_medium_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COMMISSIONING_TICK_INTERVAL_SEC 1 /**< Interval between periodic callbacks to the Commissioning module. */
+
+#define COMMISSIONING_EVT_CONFIG_MODE_ENTER 0x01 /**< Indicates that the medium entered mode for commissioning configuration. */
+#define COMMISSIONING_EVT_JOINING_MODE_ENTER 0x02 /**< Indicates that the medium exited mode for commissioning configuration. */
+#define COMMISSIONING_EVT_IDENTITY_MODE_ENTER 0x03 /**< Indicates that identity mode was requested. */
+#define COMMISSIONING_EVT_IDENTITY_MODE_EXIT 0x04 /**< Indicates that the node should stop using any features associated with the Identity mode. */
+
+#define NODE_MODE_NONE 0x00 /**< Node mode: before initialization. */
+#define NODE_MODE_JOINING 0x01 /**< Node mode: joining the network. */
+#define NODE_MODE_CONFIG 0x02 /**< Node mode: configuration. */
+#define NODE_MODE_IDENTITY 0x03 /**< Node mode: conspicuous for the user. */
+
+/**@brief Joining mode timer control commands. */
+typedef enum
+{
+ JOINING_MODE_TIMER_START = 0x01,
+ JOINING_MODE_TIMER_STOP_RESET = 0x02
+} joining_mode_timer_ctrl_cmd_t;
+
+/**@brief Structure for storing all settings necessary for commissioning. */
+typedef struct __attribute__ ((__packed__)) __attribute__((aligned))
+{
+ uint8_t poweron_mode; // Checked at startup to enter correct mode.
+ state_on_failure_t joining_mode_failure; // Mode to enter if Joining mode fails.
+ uint32_t joining_mode_to; // General timeout in Joining mode.
+ state_on_failure_t config_mode_failure; // Mode to enter if Config mode fails.
+ uint32_t config_mode_to; // General timeout in Config mode.
+ uint32_t id_mode_to; // Duration of Identity Mode.
+ ssid_store_t ssid_store; // SSID received from the router.
+ keys_store_t keys_store; // Keys received from the router.
+ id_data_store_t id_data_store; // Custom node identifier data.
+} commissioning_settings_t;
+
+/**@brief Commissioning module event handler type. */
+typedef void (*commissioning_timeout_handler_t)(void);
+
+/**@brief Structure for creating timers in the Commissioning module. */
+typedef struct
+{
+ bool is_timer_running;
+ uint32_t current_value_sec;
+ commissioning_timeout_handler_t timeout_handler;
+} commissioning_timer_t;
+
+/**@brief Structure of events passed by the Commissioning module to the parent layer. */
+typedef struct
+{
+ uint8_t commissioning_evt_id;
+ bool power_off_enable_requested;
+ commissioning_settings_t * p_commissioning_settings;
+} commissioning_evt_t;
+
+/**@brief Function for handling BLE events.
+ *
+ * @details This function must be called from the BLE stack event dispatcher
+ * to handle BLE events that are relevant for the Commissioning module.
+ *
+ * @param[in] p_ble_evt BLE stack event.
+ */
+void commissioning_ble_evt_handler(const ble_evt_t * p_ble_evt);
+
+/**@brief Commissioning module event handler type. */
+typedef void (*commissioning_evt_handler_t)(commissioning_evt_t * p_commissioning_evt);
+
+/**@brief Structure for initialization parameters of the Commissioning module. */
+typedef struct
+{
+ commissioning_evt_handler_t commissioning_evt_handler;
+} commissioning_init_params_t;
+
+/**@brief Function for initializing the Commissioning module.
+ *
+ * @details Initializes the Node Configuration Service module to create the GATT database.
+ * Loads previously stored node settings from the persistent storage and if
+ * the settings are valid, sets up the node to start in the right mode.
+ *
+ * @param[in] p_init_param Pointer to the initialization parameters.
+ * @param[out] p_poweron_state Pointer to the value of the mode that should be started.
+ *
+ * @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t commissioning_init(commissioning_init_params_t * p_init_param,
+ uint8_t * p_poweron_state);
+
+/**@brief Function for advancing the node to a new mode.
+ *
+ * @details Stops and starts app timers appropriate for the mode requested.
+ * Propagates the mode change event to the parent layer.
+ *
+ * @param[in] new_mode New mode to start.
+ *
+ */
+void commissioning_node_mode_change(uint8_t new_mode);
+
+/**@brief Function for getting the address of GAP parameters for the active mode.
+ *
+ * @param[out] pp_node_gap_params Address of GAP parameters for the active mode.
+ *
+ */
+void commissioning_gap_params_get(ipv6_medium_ble_gap_params_t ** pp_node_gap_params);
+
+/**@brief Function for getting the address of advertising parameters for the active mode.
+ *
+ * @param[out] pp_node_adv_params Address of advertising parameters for the active mode.
+ *
+ */
+void commissioning_adv_params_get(ipv6_medium_ble_adv_params_t ** pp_node_adv_params);
+
+/**@brief Function for clearing all node settings from the persistent storage.
+ *
+ * @details Calls the appropriate persistent storage interface function to clear
+ * all commissioning-related settings from the persistent storage.
+ *
+ */
+void commissioning_settings_clear(void);
+
+/**@brief Function for controlling the joining mode timer from the parent layer(s).
+ *
+ * @details If the Joining mode timer reaches zero, the node must enter the
+ * state-on-failure, as set by the user. This function allows the
+ * application designer to control the Joining mode timer from the
+ * application layer.
+ */
+void commissioning_joining_mode_timer_ctrl(
+ joining_mode_timer_ctrl_cmd_t joining_mode_timer_ctrl_cmd);
+
+/**@brief Commissioning time tick used for measuring delays and time between events.
+ *
+ * @param[in] wall_clock_value Wall clock value from the IoT Timer module.
+ */
+void commissioning_time_tick(iot_timer_time_in_ms_t wall_clock_value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COMMISSIONING_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium.h
new file mode 100644
index 0000000..064737d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium.h
@@ -0,0 +1,238 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup ipv6_medium IPv6 Medium
+ * @{
+ * @ingroup iot_sdk_common
+ * @brief IPv6 Medium Interface.
+ *
+ * @details Implementation-agnostic interface of the physical transport that
+ * facilitates IPv6 traffic.
+ */
+
+#ifndef IPV6_MEDIUM_H__
+#define IPV6_MEDIUM_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ipv6_medium_platform.h"
+#include "iot_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EUI_48_SIZE 6 /**< Size of a 48-bit Extended Unique Identifier in bytes. */
+
+#define IPV6_MEDIUM_ID_ANY 0x00 /**< Indicates invalid physical transport type. */
+#define IPV6_MEDIUM_ID_BLE 0x01 /**< Indicates that the physical transport is BLE. */
+#define IPV6_MEDIUM_ID_802154 0x02 /**< Indicates that the physical transport is 802.15.4. */
+
+#define IPV6_MEDIUM_EVT_CONN_DOWN 0x01 /**< Indicates that a connection is established. */
+#define IPV6_MEDIUM_EVT_CONN_UP 0x02 /**< Indicates that a connection is torn down. */
+#define IPV6_MEDIUM_EVT_CONNECTABLE_MODE_ENTER 0x01 /**< Indicates that the medium entered connectable mode. */
+#define IPV6_MEDIUM_EVT_CONNECTABLE_MODE_EXIT 0x02 /**< Indicates that the medium exited connectable mode. */
+#define IPV6_MEDIUM_EVT_MAC_ADDRESS_CHANGED 0x03 /**< Indicates that the device has a new MAC address. */
+#define IPV6_MEDIUM_EVT_PHY_SPECIFIC 0xFF /**< Indicates miscellaneous event from the physical layer. */
+
+/**@brief IPv6 medium instance identifier type. */
+typedef uint32_t ipv6_medium_instance_id_t;
+
+/**@brief Type of IPv6 medium type. */
+typedef uint8_t ipv6_medium_type_t;
+
+/**@brief IPv6 medium instance type. */
+typedef struct
+{
+ ipv6_medium_instance_id_t ipv6_medium_instance_id;
+ ipv6_medium_type_t ipv6_medium_instance_type;
+} ipv6_medium_instance_t;
+
+/**@brief EUI-48 value type. */
+typedef struct
+{
+ uint8_t identifier[EUI_48_SIZE]; /**< 48-bit identifier. */
+} eui48_t;
+
+/**@brief Type of IPv6 medium event parameters. */
+typedef struct
+{
+ ipv6_medium_instance_t ipv6_medium_instance_id;
+ uint8_t ipv6_medium_evt_id;
+ ipv6_medium_cb_params_union_t medium_specific;
+} ipv6_medium_evt_t;
+
+/**@brief Type of IPv6 medium error parameters. */
+typedef struct
+{
+ ipv6_medium_instance_t ipv6_medium_instance_id;
+ uint32_t error_label;
+ ipv6_medium_err_params_union_t medium_specific;
+} ipv6_medium_error_t;
+
+/**@brief IPv6 medium event handler type. */
+typedef void (*ipv6_medium_evt_handler_t)(ipv6_medium_evt_t * p_ipv6_medium_evt);
+
+/**@brief IPv6 medium error handler type. */
+typedef void (*ipv6_medium_error_handler_t)(ipv6_medium_error_t * p_ipv6_medium_error);
+
+#ifdef COMMISSIONING_ENABLED
+/**@brief Commissioning mode control commands. */
+typedef enum
+{
+ CMD_IDENTITY_MODE_EXIT = 0x00,
+ CMD_IDENTITY_MODE_ENTER = 0x01
+} mode_control_cmd_t;
+
+/**@brief Commissioning: Identity mode control callback function type. */
+typedef void (*commissioning_id_mode_cb_t)(mode_control_cmd_t control_command);
+
+/**@brief Commissioning: Power off on failure control callback function type. */
+typedef void (*commissioning_poweroff_cb_t)(bool do_poweroff_on_failure);
+#endif // COMMISSIONING_ENABLED
+
+/**@brief Structure for initialization parameters of the IPv6 medium. */
+typedef struct
+{
+ ipv6_medium_evt_handler_t ipv6_medium_evt_handler;
+ ipv6_medium_error_handler_t ipv6_medium_error_handler;
+#ifdef COMMISSIONING_ENABLED
+ commissioning_id_mode_cb_t commissioning_id_mode_cb;
+ commissioning_poweroff_cb_t commissioning_power_off_cb;
+#endif // COMMISSIONING_ENABLED
+} ipv6_medium_init_params_t;
+
+/**@brief Function for initializing the IPv6 medium.
+ *
+ * @details Initializes the IPv6 medium module.
+ * Performs all setup necessary that is specific to the implementation.
+ *
+ * @param[in] p_init_param Pointer to the initialization parameters.
+ * @param[in] desired_medium_type Value of the desired medium type.
+ * @param[out] p_new_medium_instance Pointer to the new medium instance initialized.
+ *
+ * @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_init(ipv6_medium_init_params_t * p_init_param,
+ ipv6_medium_type_t desired_medium_type,
+ ipv6_medium_instance_t * p_new_medium_instance);
+
+/**@brief Function for entering connectible mode.
+ *
+ * @details Requests the IPv6 medium to enter connectible mode.
+ *
+ * @param[in] ipv6_medium_instance_id Specifies the IPv6 medium instance.
+ *
+ * @retval NRF_SUCCESS If the procedure was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_connectable_mode_enter(ipv6_medium_instance_id_t ipv6_medium_instance_id);
+
+/**@brief Function for exiting connectible mode.
+ *
+ * @details Requests the IPv6 medium to exit connectible mode.
+ *
+ * @param[in] ipv6_medium_instance_id Specifies the IPv6 medium instance.
+ *
+ * @retval NRF_SUCCESS If the procedure was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_connectable_mode_exit(ipv6_medium_instance_id_t ipv6_medium_instance_id);
+
+/**@brief Function for getting the 48-bit Extended Unique Identifier.
+ *
+ * @param[in] ipv6_medium_instance_id Specifies the IPv6 medium instance.
+ * @param[out] p_ipv6_medium_eui48 Pointer to the EUI-48 value.
+ *
+ * @retval NRF_SUCCESS If the procedure was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_eui48_get(ipv6_medium_instance_id_t ipv6_medium_instance_id,
+ eui48_t * p_ipv6_medium_eui48);
+
+/**@brief Function for setting the 48-bit Extended Unique Identifier.
+ *
+ * @param[in] ipv6_medium_instance_id Specifies the IPv6 medium instance.
+ * @param[in] p_ipv6_medium_eui48 Pointer to the EUI-48 value.
+ *
+ * @retval NRF_SUCCESS If the procedure was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_eui48_set(ipv6_medium_instance_id_t ipv6_medium_instance_id,
+ eui48_t * p_ipv6_medium_eui48);
+
+/**@brief Function for getting the 64-bit Extended Unique Identifier.
+ *
+ * @param[in] ipv6_medium_instance_id Specifies the IPv6 medium instance.
+ * @param[out] p_ipv6_medium_eui64 Pointer to the EUI-64 value.
+ *
+ * @retval NRF_SUCCESS If the procedure was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_eui64_get(ipv6_medium_instance_id_t ipv6_medium_instance_id,
+ eui64_t * p_ipv6_medium_eui64);
+
+/**@brief Function for setting the 64-bit Extended Unique Identifier.
+ *
+ * @param[in] ipv6_medium_instance_id Specifies the IPv6 medium instance.
+ * @param[in] p_ipv6_medium_eui64 Pointer to the EUI-64 value.
+ *
+ * @retval NRF_SUCCESS If the procedure was successful. Otherwise, a propagated
+ * error code is returned.
+ *
+ */
+uint32_t ipv6_medium_eui64_set(ipv6_medium_instance_id_t ipv6_medium_instance_id,
+ eui64_t * p_ipv6_medium_eui64);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IPV6_MEDIUM_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.c
new file mode 100644
index 0000000..0d0a415
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.c
@@ -0,0 +1,689 @@
+/**
+ * Copyright (c) 2015-2018 - 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 <stdint.h>
+#include "boards.h"
+#include "ipv6_medium.h"
+#include "ipv6_medium_ble.h"
+#include "ble_advdata.h"
+#include "ble_hci.h"
+#include "ble_srv_common.h"
+#include "ble_ipsp.h"
+#include "sdk_config.h"
+#include "nrf_sdm.h"
+#include "nrf_sdh.h"
+#include "nrf_sdh_ble.h"
+#ifdef COMMISSIONING_ENABLED
+#include "commissioning.h"
+#endif // COMMISSIONING_ENABLED
+
+#define PUBLIC_BLE_GAP_ADDR_CREATE_FROM_EUI64(ble_gap_addr, eui64, ble_gap_addr_type) \
+ ble_gap_addr[0] = eui64[7]; \
+ ble_gap_addr[1] = eui64[6]; \
+ ble_gap_addr[2] = eui64[5]; \
+ ble_gap_addr[3] = eui64[2]; \
+ ble_gap_addr[4] = eui64[1]; \
+ ble_gap_addr[5] = 0x00; \
+ ble_gap_addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
+
+#define IOT_TIMER_DISABLE_API_PARAM_CHECK 0
+
+#if (IOT_TIMER_DISABLE_API_PARAM_CHECK == 0)
+
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL); \
+ }
+
+#else // IOT_TIMER_DISABLE_API_PARAM_CHECK
+
+#define NULL_PARAM_CHECK(PARAM)
+
+#endif //IOT_TIMER_DISABLE_API_PARAM_CHECK
+
+#define BLE_IPV6_MEDIUM_BLE_OBSERVER_PRIO 1 /**< BLE observer priority. */
+#define BLE_IPSP_TAG 35 /**< Identifies the L2CAP configuration used with SoftDevice. */
+
+
+static ipv6_medium_instance_id_t m_module_instance_id = 0x01; /**< Module instance identifier. As of today, only a single instance is supported. */
+static ipv6_medium_evt_handler_t m_ipv6_medium_evt_handler; /**< Pointer to the event handler procedure of the parent layer. */
+static ipv6_medium_error_handler_t m_ipv6_medium_error_handler; /**< Pointer to the error handler procedure of the parent layer. */
+static ble_gap_addr_t m_local_ble_addr; /**< Local BT device address. */
+static ipv6_medium_ble_gap_params_t * m_p_node_gap_params; /**< Pointer to advertising parameters to be used. */
+static ipv6_medium_ble_adv_params_t * m_p_node_adv_params; /**< Pointer to GAP parameters to be used. */
+
+#ifndef COMMISSIONING_ENABLED
+static ipv6_medium_ble_gap_params_t m_gap_params; /**< Advertising parameters w/o commissioning. */
+static ipv6_medium_ble_adv_params_t m_adv_params; /**< GAP parameters w/o commissioning. */
+static ble_uuid_t m_adv_uuids[] =
+ {
+ {BLE_UUID_IPSP_SERVICE, BLE_UUID_TYPE_BLE}
+ }; /**< List of available service UUIDs in advertisement data. */
+#else // COMMISSIONING_ENABLED
+static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the active connection. */
+static bool m_connectable_mode_active = false; /**< Indicates if the node is in connectable mode. */
+static commissioning_id_mode_cb_t m_commissioning_id_mode_cb;
+static commissioning_poweroff_cb_t m_commissioning_power_off_cb;
+static bool m_adv_params_applied = false; /**< Indicates if advertising (and GAP) parameters have been applied. */
+#endif // COMMISSIONING_ENABLED
+
+static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
+static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded advertising set. */
+
+/**@brief Struct that contains pointers to the encoded advertising data. */
+static ble_gap_adv_data_t m_adv_data =
+{
+ .adv_data =
+ {
+ .p_data = m_enc_advdata,
+ .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
+ },
+ .scan_rsp_data =
+ {
+ .p_data = NULL,
+ .len = 0
+
+ }
+};
+
+#if IPV6_MEDIUM_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME ipv6_medium
+
+#define NRF_LOG_LEVEL IPV6_MEDIUM_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IPV6_MEDIUM_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IPV6_MEDIUM_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define IPV6M_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define IPV6M_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define IPV6M_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define IPV6M_ENTRY() IPV6M_TRC(">> %s", __func__)
+#define IPV6M_EXIT() IPV6M_TRC("<< %s", __func__)
+
+#else // IPV6_MEDIUM_CONFIG_LOG_ENABLED
+
+#define IPV6M_TRC(...) /**< Disables traces. */
+#define IPV6M_DUMP(...) /**< Disables dumping of octet streams. */
+#define IPV6M_ERR(...) /**< Disables error logs. */
+
+#define IPV6M_ENTRY(...)
+#define IPV6M_EXIT(...)
+
+#endif // IPV6_MEDIUM_CONFIG_LOG_ENABLED
+
+
+#ifndef COMMISSIONING_ENABLED
+
+/**@brief Function for setting advertisement parameters.
+ *
+ * @details These parameters are applied if the Commissioning module is
+ * not used or in Joining mode.
+ */
+static void adv_params_set(void)
+{
+ IPV6M_ENTRY();
+ memset(&m_adv_params, 0x00, sizeof(m_adv_params));
+
+ m_adv_params.advdata.name_type = BLE_ADVDATA_FULL_NAME;
+ m_adv_params.advdata.flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
+ m_adv_params.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
+ m_adv_params.advdata.uuids_complete.p_uuids = m_adv_uuids;
+
+ m_adv_params.advparams.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+ m_adv_params.advparams.p_peer_addr = NULL; // Undirected advertisement.
+ m_adv_params.advparams.filter_policy = BLE_GAP_ADV_FP_ANY;
+ m_adv_params.advparams.interval = APP_ADV_ADV_INTERVAL;
+ m_adv_params.advparams.duration = APP_ADV_DURATION;
+
+ IPV6M_EXIT();
+}
+
+/**@brief Function for setting GAP parameters.
+ *
+ * @details These parameters are applied if the Commissioning module is
+ * not used or in Joining mode.
+ */
+static void gap_params_set(void)
+{
+ memset(&m_gap_params, 0x00, sizeof(m_gap_params));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&m_gap_params.sec_mode);
+
+ m_gap_params.appearance = BLE_APPEARANCE_UNKNOWN;
+
+ m_gap_params.p_dev_name = (const uint8_t *)DEVICE_NAME;
+ m_gap_params.dev_name_len = strlen(DEVICE_NAME);
+
+ m_gap_params.gap_conn_params.min_conn_interval = (uint16_t)MIN_CONN_INTERVAL;
+ m_gap_params.gap_conn_params.max_conn_interval = (uint16_t)MAX_CONN_INTERVAL;
+ m_gap_params.gap_conn_params.slave_latency = SLAVE_LATENCY;
+ m_gap_params.gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
+}
+
+#endif // COMMISSIONING_ENABLED
+
+
+/**@brief Function for applying the advertisement parameters.
+ *
+ * @details Encodes the required advertising data and passes it to the stack.
+ */
+static void adv_params_apply(void)
+{
+ uint32_t err_code;
+
+
+ err_code = ble_advdata_encode(&m_p_node_adv_params->advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
+ APP_ERROR_CHECK(err_code);
+#ifndef COMMISSIONING_ENABLED
+ err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params.advparams);
+ APP_ERROR_CHECK(err_code);
+#else
+ err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_p_node_adv_params->advparams);
+ APP_ERROR_CHECK(err_code);
+#endif
+}
+
+
+/**@brief Function for applying the GAP configuration.
+ *
+ * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
+ * device including the device name, appearance, and the preferred connection parameters.
+ */
+static void gap_params_apply(void)
+{
+ uint32_t err_code;
+
+ err_code = sd_ble_gap_device_name_set(&m_p_node_gap_params->sec_mode, \
+ m_p_node_gap_params->p_dev_name, \
+ m_p_node_gap_params->dev_name_len);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = sd_ble_gap_appearance_set(m_p_node_gap_params->appearance);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = sd_ble_gap_ppcp_set(&m_p_node_gap_params->gap_conn_params);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for handling the application's BLE Stack events and
+ * passing them on to the applications as generic transport medium events.
+ *
+ * @param[in] p_ble_evt Bluetooth stack event.
+ */
+static void on_ble_evt(ble_evt_t const * p_ble_evt)
+{
+ ipv6_medium_evt_t ipv6_medium_evt;
+
+ memset(&ipv6_medium_evt, 0x00, sizeof(ipv6_medium_evt));
+ ipv6_medium_evt.ipv6_medium_instance_id.ipv6_medium_instance_id = m_module_instance_id;
+ ipv6_medium_evt.ipv6_medium_instance_id.ipv6_medium_instance_type = IPV6_MEDIUM_ID_BLE;
+ ipv6_medium_evt.medium_specific.ble.p_ble_evt = (ble_evt_t*)p_ble_evt;
+
+ ipv6_medium_error_t ipv6_medium_error;
+ memset(&ipv6_medium_error, 0x00, sizeof(ipv6_medium_error));
+ ipv6_medium_error.ipv6_medium_instance_id.ipv6_medium_instance_id = m_module_instance_id;
+ ipv6_medium_error.ipv6_medium_instance_id.ipv6_medium_instance_type = IPV6_MEDIUM_ID_BLE;
+
+ bool do_notify_event = false;
+ bool do_notify_error = false;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ {
+#ifdef COMMISSIONING_ENABLED
+ m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+#endif // COMMISSIONING_ENABLED
+ ipv6_medium_evt.ipv6_medium_evt_id = IPV6_MEDIUM_EVT_CONN_UP;
+ do_notify_event = true;
+
+ break;
+ }
+ case BLE_GAP_EVT_DISCONNECTED:
+ {
+#ifdef COMMISSIONING_ENABLED
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+#endif // COMMISSIONING_ENABLED
+ ipv6_medium_evt.ipv6_medium_evt_id = IPV6_MEDIUM_EVT_CONN_DOWN;
+ do_notify_event = true;
+
+ break;
+ }
+ case BLE_GAP_EVT_ADV_SET_TERMINATED:
+ {
+ if (p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT)
+ {
+ ipv6_medium_evt.ipv6_medium_evt_id = IPV6_MEDIUM_EVT_CONNECTABLE_MODE_EXIT;
+ do_notify_event = true;
+ }
+ else
+ {
+ // This is not necessarily an error, only added here to show error handler usage.
+ ipv6_medium_error.medium_specific.ble.dummy_value = 0x13;
+ do_notify_error = true;
+ }
+ break;
+ }
+ default:
+ {
+ ipv6_medium_evt.ipv6_medium_evt_id = IPV6_MEDIUM_EVT_PHY_SPECIFIC;
+ do_notify_event = true;
+
+ break;
+ }
+ }
+
+ ble_ipsp_evt_handler(p_ble_evt);
+
+ if (do_notify_event == true)
+ {
+ m_ipv6_medium_evt_handler(&ipv6_medium_evt);
+ }
+ if (do_notify_error == true)
+ {
+ m_ipv6_medium_error_handler(&ipv6_medium_error);
+ }
+}
+
+/*
+ * @brief Function for handling BLE events.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Context.
+ */
+static void ble_evt_handler(const ble_evt_t * p_ble_evt, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+#ifdef COMMISSIONING_ENABLED
+ commissioning_ble_evt_handler(p_ble_evt);
+ ble_ncfgs_ble_evt_handler(p_ble_evt);
+#endif // COMMISSIONING_ENABLED
+
+ on_ble_evt(p_ble_evt);
+}
+
+
+
+
+/**@brief Function for initializing the BLE stack.
+ *
+ * @details Initializes the SoftDevice and the BLE event interrupt.
+ */
+static uint32_t ble_stack_init(void)
+{
+ ret_code_t err_code;
+ uint32_t ram_start = 0;
+ ble_cfg_t ble_cfg;
+
+ err_code = nrf_sdh_enable_request();
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Fetch the start address of the application RAM.
+ err_code = nrf_sdh_ble_app_ram_start_get(&ram_start);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Configure the maximum number of connections.
+ memset(&ble_cfg, 0, sizeof(ble_cfg));
+ ble_cfg.gap_cfg.role_count_cfg.periph_role_count = BLE_IPSP_MAX_CHANNELS;
+ ble_cfg.gap_cfg.role_count_cfg.central_role_count = 0;
+ ble_cfg.gap_cfg.role_count_cfg.central_sec_count = 0;
+ err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_cfg, ram_start);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ memset(&ble_cfg, 0, sizeof(ble_cfg));
+
+ // Configure total number of connections.
+ ble_cfg.conn_cfg.conn_cfg_tag = BLE_IPSP_TAG;
+ ble_cfg.conn_cfg.params.gap_conn_cfg.conn_count = BLE_IPSP_MAX_CHANNELS;
+ ble_cfg.conn_cfg.params.gap_conn_cfg.event_length = BLE_GAP_EVENT_LENGTH_DEFAULT;
+ err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_cfg, ram_start);
+
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ memset(&ble_cfg, 0, sizeof(ble_cfg));
+
+ // Configure the number of custom UUIDS.
+#ifdef COMMISSIONING_ENABLED
+ ble_cfg.common_cfg.vs_uuid_cfg.vs_uuid_count = 1;
+#else
+ ble_cfg.common_cfg.vs_uuid_cfg.vs_uuid_count = 0;
+#endif // COMMISSIONING_ENABLED
+
+ err_code = sd_ble_cfg_set(BLE_COMMON_CFG_VS_UUID, &ble_cfg, ram_start);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ memset(&ble_cfg, 0, sizeof(ble_cfg));
+
+ // Set L2CAP channel configuration
+ ble_cfg.conn_cfg.conn_cfg_tag = BLE_IPSP_TAG;
+ ble_cfg.conn_cfg.params.l2cap_conn_cfg.rx_mps = BLE_IPSP_RX_MPS;
+ ble_cfg.conn_cfg.params.l2cap_conn_cfg.rx_queue_size = BLE_IPSP_RX_BUFFER_COUNT;
+ ble_cfg.conn_cfg.params.l2cap_conn_cfg.tx_mps = BLE_IPSP_TX_MPS;
+ ble_cfg.conn_cfg.params.l2cap_conn_cfg.tx_queue_size = 1;
+ ble_cfg.conn_cfg.params.l2cap_conn_cfg.ch_count = 1; // One IPSP channel per link.
+ err_code = sd_ble_cfg_set(BLE_CONN_CFG_L2CAP, &ble_cfg, ram_start);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ memset(&ble_cfg, 0, sizeof(ble_cfg));
+
+ // Set the ATT table size.
+#ifdef COMMISSIONING_ENABLED
+ ble_cfg.gatts_cfg.attr_tab_size.attr_tab_size = 1024;
+#else
+ ble_cfg.gatts_cfg.attr_tab_size.attr_tab_size = 256;
+#endif // COMMISSIONING_ENABLED
+ err_code = sd_ble_cfg_set(BLE_GATTS_CFG_ATTR_TAB_SIZE, &ble_cfg, ram_start);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = nrf_sdh_ble_enable(&ram_start);
+ }
+
+ NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_IPV6_MEDIUM_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
+
+ return err_code;
+}
+
+
+uint32_t ipv6_medium_connectable_mode_enter(ipv6_medium_instance_id_t ipv6_medium_instance_id)
+{
+ IPV6M_ENTRY();
+
+ if (ipv6_medium_instance_id != m_module_instance_id)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+#ifdef COMMISSIONING_ENABLED
+ if (m_adv_params_applied == false)
+ {
+ // Apply advertising (and GAP) parameters, if not applied when node mode changed.
+ commissioning_gap_params_get(&m_p_node_gap_params);
+ commissioning_adv_params_get(&m_p_node_adv_params);
+ gap_params_apply();
+ adv_params_apply();
+ }
+ m_adv_params_applied = false;
+#endif // COMMISSIONING_ENABLED
+
+ adv_params_apply();
+
+ uint32_t err_code = sd_ble_gap_adv_start(m_adv_handle, BLE_IPSP_TAG);
+#ifdef COMMISSIONING_ENABLED
+ if (err_code == NRF_SUCCESS)
+ {
+ m_connectable_mode_active = true;
+ }
+#endif // COMMISSIONING_ENABLED
+ IPV6M_EXIT();
+ return err_code;
+}
+
+
+uint32_t ipv6_medium_connectable_mode_exit(ipv6_medium_instance_id_t ipv6_medium_instance_id)
+{
+ if (ipv6_medium_instance_id != m_module_instance_id)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ uint32_t err_code = sd_ble_gap_adv_stop(m_adv_handle);
+#ifdef COMMISSIONING_ENABLED
+ if (err_code == NRF_SUCCESS)
+ {
+ m_connectable_mode_active = false;
+ }
+#endif // COMMISSIONING_ENABLED
+ return err_code;
+}
+
+
+uint32_t ipv6_medium_eui48_get(ipv6_medium_instance_id_t ipv6_medium_instance_id, \
+ eui48_t * p_ipv6_medium_eui48)
+{
+ if (ipv6_medium_instance_id != m_module_instance_id)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ ble_gap_addr_t local_ble_addr;
+ uint32_t err_code = sd_ble_gap_addr_get(&local_ble_addr);
+
+ memcpy(p_ipv6_medium_eui48->identifier, local_ble_addr.addr, EUI_48_SIZE);
+
+ return err_code;
+}
+
+
+uint32_t ipv6_medium_eui48_set(ipv6_medium_instance_id_t ipv6_medium_instance_id, \
+ eui48_t * p_ipv6_medium_eui48)
+{
+ if (ipv6_medium_instance_id != m_module_instance_id)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ if (p_ipv6_medium_eui48->identifier[5] != 0x00)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ m_local_ble_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
+ memcpy(m_local_ble_addr.addr, p_ipv6_medium_eui48->identifier, EUI_48_SIZE);
+
+ return sd_ble_gap_addr_set(&m_local_ble_addr);
+}
+
+
+uint32_t ipv6_medium_eui64_get(ipv6_medium_instance_id_t ipv6_medium_instance_id, \
+ eui64_t * p_ipv6_medium_eui64)
+{
+ if (ipv6_medium_instance_id != m_module_instance_id)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ ble_gap_addr_t local_ble_addr;
+
+ uint32_t err_code = sd_ble_gap_addr_get(&local_ble_addr);
+ APP_ERROR_CHECK(err_code);
+
+ IPV6_EUI64_CREATE_FROM_EUI48(p_ipv6_medium_eui64->identifier,
+ local_ble_addr.addr,
+ local_ble_addr.addr_type);
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ipv6_medium_eui64_set(ipv6_medium_instance_id_t ipv6_medium_instance_id, \
+ eui64_t * p_ipv6_medium_eui64)
+{
+ if (ipv6_medium_instance_id != m_module_instance_id)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ if ((p_ipv6_medium_eui64->identifier[0] != 0x02) ||
+ (p_ipv6_medium_eui64->identifier[3] != 0xFF) ||
+ (p_ipv6_medium_eui64->identifier[4] != 0xFE))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ ble_gap_addr_t local_ble_addr;
+
+ PUBLIC_BLE_GAP_ADDR_CREATE_FROM_EUI64(local_ble_addr.addr, \
+ p_ipv6_medium_eui64->identifier, \
+ local_ble_addr.addr_type);
+
+ return sd_ble_gap_addr_set(&local_ble_addr);
+}
+
+
+#ifdef COMMISSIONING_ENABLED
+
+void commissioning_evt_handler(commissioning_evt_t * p_commissioning_evt)
+{
+ IPV6M_ENTRY();
+
+ switch (p_commissioning_evt->commissioning_evt_id)
+ {
+ case COMMISSIONING_EVT_CONFIG_MODE_ENTER:
+ // Fall-through.
+ case COMMISSIONING_EVT_JOINING_MODE_ENTER:
+ {
+ m_commissioning_power_off_cb(p_commissioning_evt->power_off_enable_requested);
+
+ if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ // Making sure that advertising (and GAP) parameters are
+ // applied when entering connectable mode the next time.
+ m_adv_params_applied = false;
+ UNUSED_VARIABLE(sd_ble_gap_disconnect(m_conn_handle, \
+ BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION));
+ }
+ else
+ {
+ bool do_return_to_connectable_mode = m_connectable_mode_active;
+ UNUSED_VARIABLE(ipv6_medium_connectable_mode_exit(m_module_instance_id));
+
+ commissioning_gap_params_get(&m_p_node_gap_params);
+ commissioning_adv_params_get(&m_p_node_adv_params);
+ gap_params_apply();
+ adv_params_apply();
+ // Advertising and GAP parameters applied, making sure that
+ // it is not repeated when entering connectable mode the next time.
+ m_adv_params_applied = true;
+
+ if (do_return_to_connectable_mode == true)
+ {
+ // Restart connectable mode, if the node was in connectable mode applying
+ // the new parameters.
+ UNUSED_VARIABLE(ipv6_medium_connectable_mode_enter(m_module_instance_id));
+ }
+ }
+
+ break;
+ }
+ case COMMISSIONING_EVT_IDENTITY_MODE_ENTER:
+ {
+ m_commissioning_id_mode_cb(CMD_IDENTITY_MODE_ENTER);
+
+ break;
+ }
+ case COMMISSIONING_EVT_IDENTITY_MODE_EXIT:
+ {
+ m_commissioning_id_mode_cb(CMD_IDENTITY_MODE_EXIT);
+
+ break;
+ }
+ default:
+ {
+ // No implementation needed.
+ break;
+ }
+ }
+
+ IPV6M_EXIT();
+}
+
+#endif // COMMISSIONING_ENABLED
+
+
+uint32_t ipv6_medium_init(ipv6_medium_init_params_t * p_init_param, \
+ ipv6_medium_type_t desired_medium_type, \
+ ipv6_medium_instance_t * p_new_medium_instance)
+{
+ IPV6M_ENTRY();
+ uint32_t err_code = NRF_SUCCESS;
+ NULL_PARAM_CHECK(p_init_param->ipv6_medium_evt_handler);
+ if (desired_medium_type != IPV6_MEDIUM_ID_BLE)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ m_ipv6_medium_evt_handler = p_init_param->ipv6_medium_evt_handler;
+ m_ipv6_medium_error_handler = p_init_param->ipv6_medium_error_handler;
+
+ p_new_medium_instance->ipv6_medium_instance_type = IPV6_MEDIUM_ID_BLE;
+ p_new_medium_instance->ipv6_medium_instance_id = m_module_instance_id;
+
+ err_code = ble_stack_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+#ifndef COMMISSIONING_ENABLED
+ gap_params_set();
+ adv_params_set();
+ m_p_node_gap_params = &m_gap_params;
+ m_p_node_adv_params = &m_adv_params;
+ gap_params_apply();
+#else // COMMISSIONING_ENABLED
+ m_commissioning_id_mode_cb = p_init_param->commissioning_id_mode_cb;
+ m_commissioning_power_off_cb = p_init_param->commissioning_power_off_cb;
+
+ commissioning_init_params_t init_param;
+ memset(&init_param, 0x00, sizeof(init_param));
+ init_param.commissioning_evt_handler = commissioning_evt_handler;
+ uint8_t new_mode;
+ err_code = commissioning_init(&init_param, \
+ &new_mode);
+
+ commissioning_node_mode_change(new_mode);
+#endif // COMMISSIONING_ENABLED
+
+ IPV6M_EXIT();
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.h
new file mode 100644
index 0000000..492afe4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_ble.h
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file
+ *
+ * @defgroup ipv6_medium_ble BLE IPv6 Medium Implementation
+ * @{
+ * @ingroup iot_sdk_common
+ * @brief Bluetooth Low Energy implementation of the IPv6 medium interface.
+ *
+ * @details Type definitions for the BLE implementation of the IPv6 medium interface.
+ * This header also includes the header with BLE-specific configuration.
+ */
+
+#ifndef IPV6_MEDIUM_BLE_H__
+#define IPV6_MEDIUM_BLE_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_advdata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Structure for storing all GAP parameters. */
+typedef struct
+{
+ uint16_t appearance;
+ uint8_t const * p_dev_name;
+ uint16_t dev_name_len;
+ ble_gap_conn_sec_mode_t sec_mode;
+ ble_gap_conn_params_t gap_conn_params;
+} ipv6_medium_ble_gap_params_t;
+
+/**@brief Structure for storing all advertisement parameters. */
+typedef struct
+{
+ ble_advdata_t advdata;
+ ble_advdata_manuf_data_t adv_man_specific_data;
+ ble_advdata_t srdata;
+ ble_advdata_manuf_data_t sr_man_specific_data;
+ ble_gap_adv_params_t advparams;
+} ipv6_medium_ble_adv_params_t;
+
+/**@brief Structure of BLE-specific parameters of events passed to the parent layer by the IPv6 medium. */
+typedef struct
+{
+ ble_evt_t * p_ble_evt;
+} ipv6_medium_ble_cb_params_t;
+
+/**@brief Structure of BLE-specific parameters of errors passed to the parent layer by the IPv6 medium. */
+typedef struct
+{
+ uint8_t dummy_value; // Parameters to be added.
+} ipv6_medium_ble_error_params_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IPV6_MEDIUM_BLE_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_platform_dummy.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_platform_dummy.h
new file mode 100644
index 0000000..341d326
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ipv6_medium_platform_dummy.h
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+#ifndef IPV6_MEDIUM_PLATFORM_DUMMY_H__
+#define IPV6_MEDIUM_PLATFORM_DUMMY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int ipv6_medium_cb_params_union_t;
+typedef int ipv6_medium_err_params_union_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IPV6_MEDIUM_PLATFORM_DUMMY_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.c
new file mode 100644
index 0000000..ecb6fcd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.c
@@ -0,0 +1,821 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt.c
+ *
+ * @brief MQTT Client API Implementation.
+ */
+
+
+#include "mqtt.h"
+#include "mem_manager.h"
+#include "mqtt_transport.h"
+#include "mqtt_internal.h"
+#include "iot_timer.h"
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+/**< Never changing ping request, needed for Keep Alive. */
+static const uint8_t m_ping_packet[MQTT_PKT_HEADER_SIZE] = \
+ {MQTT_PKT_TYPE_PINGREQ, \
+ 0x00};
+
+/**< Never changing disconnect request. */
+static const uint8_t m_disc_packet[MQTT_PKT_HEADER_SIZE] = \
+ {MQTT_PKT_TYPE_DISCONNECT, \
+ 0x00};
+
+static mqtt_client_t * m_mqtt_client[MQTT_MAX_CLIENTS]; /**< MQTT Client table. */
+SDK_MUTEX_DEFINE(m_mqtt_mutex) /**< Mutex variable for the module, currently unused. */
+
+
+static uint32_t get_client_index(mqtt_client_t * const p_client)
+{
+ for (uint32_t index = 0; index < MQTT_MAX_CLIENTS; index++)
+ {
+ if (m_mqtt_client[index] == p_client)
+ {
+ return index;
+ }
+ }
+
+ return MQTT_MAX_CLIENTS;
+}
+
+
+void client_free(mqtt_client_t * const p_client)
+{
+ MQTT_STATE_INIT(p_client);
+
+ // Free memory used for TX packets and reset the pointer.
+ nrf_free(p_client->p_packet);
+ p_client->p_packet = NULL;
+
+ // Free TLS instance and reset the instance.
+ UNUSED_VARIABLE(nrf_tls_free(&p_client->tls_instance));
+ NRF_TLS_INTSANCE_INIT(&p_client->tls_instance);
+}
+
+
+void client_init(mqtt_client_t * const p_client)
+{
+ memset(p_client, 0, sizeof(*p_client));
+
+ MQTT_STATE_INIT(p_client);
+
+ p_client->protocol_version = MQTT_VERSION_3_1_0;
+ p_client->clean_session = 1;
+
+ NRF_TLS_INTSANCE_INIT(&p_client->tls_instance);
+}
+
+
+/**@brief Notifies event to the application.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ * @param[in] p_evt Reason for disconnection.
+ */
+void event_notify(mqtt_client_t * const p_client, const mqtt_evt_t * p_evt, uint32_t flags)
+{
+ const mqtt_evt_cb_t evt_cb = p_client->evt_cb;
+
+ if (evt_cb != NULL)
+ {
+ MQTT_MUTEX_UNLOCK();
+
+ evt_cb(p_client, p_evt);
+
+ MQTT_MUTEX_LOCK();
+
+ if (IS_SET(flags,MQTT_EVT_FLAG_INSTANCE_RESET))
+ {
+ client_init(p_client);
+ }
+ }
+}
+
+
+/**@brief Notifies disconnection event to the application.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ * @param[in] result Reason for disconnection.
+ */
+void disconnect_event_notify(mqtt_client_t * p_client, uint32_t result)
+{
+ mqtt_evt_t evt;
+ const uint32_t client_index = get_client_index(p_client);
+
+ // Remove the client from internal table.
+ if (client_index != MQTT_MAX_CLIENTS)
+ {
+ m_mqtt_client[client_index] = NULL;
+ }
+
+ // Determine appropriate event to generate.
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED) ||
+ MQTT_VERIFY_STATE(p_client, MQTT_STATE_DISCONNECTING))
+ {
+ evt.id = MQTT_EVT_DISCONNECT;
+ evt.result = result;
+ }
+ else
+ {
+ evt.id = MQTT_EVT_CONNACK;
+ evt.result = MQTT_CONNECTION_FAILED;
+ }
+
+ // Free the instance.
+ client_free(p_client);
+
+ // Notify application.
+ event_notify(p_client, &evt, MQTT_EVT_FLAG_INSTANCE_RESET);
+}
+
+
+uint32_t mqtt_init(void)
+{
+ SDK_MUTEX_INIT(m_mqtt_mutex);
+
+ MQTT_MUTEX_LOCK();
+
+ memset(m_mqtt_client, 0, sizeof(m_mqtt_client));
+
+ MQTT_MUTEX_UNLOCK();
+
+ return nrf_tls_init();
+}
+
+
+void mqtt_client_init(mqtt_client_t * const p_client)
+{
+ NULL_PARAM_CHECK_VOID(p_client);
+
+ MQTT_MUTEX_LOCK();
+
+ client_init(p_client);
+
+ MQTT_MUTEX_UNLOCK();
+}
+
+
+uint32_t mqtt_connect(mqtt_client_t * const p_client)
+{
+ // Look for a free instance if available.
+ uint32_t err_code = NRF_SUCCESS;
+ uint32_t client_index = 0;
+
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_client->client_id.p_utf_str);
+
+ MQTT_MUTEX_LOCK();
+
+ for (client_index = 0; client_index < MQTT_MAX_CLIENTS; client_index++)
+ {
+ if (m_mqtt_client[client_index] == NULL)
+ {
+ // Found a free instance.
+ m_mqtt_client[client_index] = p_client;
+
+ // Allocate buffer packets in TX path.
+ p_client->p_packet = nrf_malloc(MQTT_MAX_PACKET_LENGTH);
+ break;
+ }
+ }
+
+ if ((client_index == MQTT_MAX_CLIENTS) || (p_client->p_packet == NULL))
+ {
+ err_code = (NRF_ERROR_NO_MEM | IOT_MQTT_ERR_BASE);
+ }
+ else
+ {
+ err_code = tcp_request_connection(p_client);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Free the instance.
+ m_mqtt_client[client_index] = NULL;
+ nrf_free(p_client->p_packet);
+ err_code = MQTT_ERR_TCP_PROC_FAILED;
+ }
+ }
+
+ UNUSED_VARIABLE(p_client);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_publish(mqtt_client_t * const p_client,
+ mqtt_publish_param_t const * const p_param)
+{
+ uint32_t err_code = MQTT_ERR_NOT_CONNECTED;
+ uint32_t offset = 0;
+ uint32_t mqtt_packetlen = 0;
+ uint8_t * p_payload;
+
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: >> %s Topic size 0x%08x, Data size 0x%08x",
+ p_client,
+ p_client->state,
+ __func__,
+ p_param->message.topic.topic.utf_strlen,
+ p_param->message.payload.bin_strlen);
+
+ MQTT_MUTEX_LOCK();
+
+ p_payload = &p_client->p_packet[MQTT_FIXED_HEADER_EXTENDED_SIZE];
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ memset(p_payload, 0, MQTT_MAX_PACKET_LENGTH);
+
+ // Pack topic.
+ err_code = pack_utf8_str(&p_param->message.topic.topic,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (p_param->message.topic.qos)
+ {
+ err_code = pack_uint16(p_param->message_id,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ // Pack message on the topic.
+ err_code = pack_bin_str(&p_param->message.payload,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const uint8_t message_type = MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_PUBLISH,
+ 0, // Duplicate flag not set.
+ p_param->message.topic.qos,
+ 0); // Retain flag not set.
+
+ mqtt_packetlen = mqtt_encode_fixed_header(message_type, // Message type
+ offset, // Payload size without the fixed header
+ &p_payload); // Address where the p_payload is contained.
+
+
+ // Publish message.
+ err_code = mqtt_transport_write(p_client, p_payload, mqtt_packetlen);
+ }
+ }
+
+ MQTT_TRC("<< %s", (uint32_t)__func__);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+/**@brief Encodes and sends messages that contain only message id in the variable header.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ * @param[in] op_code Opcode for the message.
+ * @param[in] message_id Message id to be encoded in the variable header.
+ *
+ * @retval NRF_SUCCESS or an error code indicating a reason for failure.
+ */
+uint32_t mqtt_message_id_only_enc_n_send(mqtt_client_t * const p_client,
+ uint8_t opcode,
+ uint16_t message_id)
+{
+ uint32_t err_code = MQTT_ERR_NOT_CONNECTED;
+ uint32_t offset = 0;
+ uint32_t mqtt_packetlen = 0;
+ uint8_t * p_payload;
+
+ p_payload = &p_client->p_packet[MQTT_FIXED_HEADER_EXTENDED_SIZE];
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ memset(p_payload, 0, MQTT_MAX_PACKET_LENGTH);
+
+ err_code = pack_uint16(message_id,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const uint8_t message_type = MQTT_MESSAGES_OPTIONS(opcode,
+ 0, // Duplicate flag not set.
+ 0, // QoS unused.
+ 0); // Retain flag not set.
+
+ mqtt_packetlen = mqtt_encode_fixed_header(message_type, // Message type
+ offset, // Payload size without the fixed header
+ &p_payload); // Address where the p_payload is contained.
+
+ // Publish message.
+ err_code = mqtt_transport_write(p_client, p_payload, mqtt_packetlen);
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Sends raw message to the peer.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ * @param[in] p_message Raw message to be sent to the peer.
+ * @param[in] message_id Message id to be encoded in the variable header.
+ *
+ * @retval NRF_SUCCESS or an error code indicating a reason for failure.
+ */
+uint32_t mqtt_raw_message_send(mqtt_client_t * const p_client,
+ const uint8_t * p_message,
+ uint16_t message_len)
+{
+ uint32_t err_code;
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ err_code = mqtt_transport_write(p_client, p_message, message_len);
+ }
+ else
+ {
+ err_code = MQTT_ERR_NOT_CONNECTED;
+ }
+
+ return err_code;
+}
+
+
+uint32_t mqtt_publish_ack(mqtt_client_t * const p_client,
+ mqtt_puback_param_t const * p_param)
+{
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: >> %s Message id 0x%04x",
+ p_client,
+ p_client->state,
+ __func__,
+ p_param->message_id);
+
+ MQTT_MUTEX_LOCK();
+
+ uint32_t err_code = mqtt_message_id_only_enc_n_send(p_client,
+ MQTT_PKT_TYPE_PUBACK,
+ p_param->message_id);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: << %s result 0x%08x",
+ p_client,
+ p_client->state,
+ __func__,
+ err_code);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_publish_receive(mqtt_client_t * const p_client,
+ mqtt_pubrec_param_t const * const p_param)
+{
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: >> %s Message id 0x%04x",
+ p_client,
+ p_client->state,
+ __func__,
+ p_param->message_id);
+
+ MQTT_MUTEX_LOCK();
+
+ uint32_t err_code = mqtt_message_id_only_enc_n_send(p_client,
+ MQTT_PKT_TYPE_PUBREC,
+ p_param->message_id);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: << %s result 0x%08x",
+ p_client,
+ p_client->state,
+ __func__,
+ err_code);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_publish_release(mqtt_client_t * const p_client,
+ mqtt_pubrel_param_t const * const p_param)
+{
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: >> %s Message id 0x%04x",
+ p_client,
+ p_client->state,
+ __func__,
+ p_param->message_id);
+
+ MQTT_MUTEX_LOCK();
+
+ uint32_t err_code = mqtt_message_id_only_enc_n_send(p_client,
+ MQTT_PKT_TYPE_PUBREL,
+ p_param->message_id);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: << %s result 0x%08x",
+ p_client,
+ p_client->state,
+ __func__,
+ err_code);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_publish_complete(mqtt_client_t * const p_client,
+ mqtt_pubcomp_param_t const * const p_param)
+{
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: >> %s Message id 0x%04x",
+ p_client,
+ p_client->state,
+ __func__,
+ p_param->message_id);
+
+ MQTT_MUTEX_LOCK();
+
+ uint32_t err_code = mqtt_message_id_only_enc_n_send(p_client,
+ MQTT_PKT_TYPE_PUBCOMP,
+ p_param->message_id);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: << %s result 0x%08x",
+ p_client,
+ p_client->state,
+ __func__,
+ err_code);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_disconnect(mqtt_client_t * const p_client)
+{
+ uint32_t err_code = MQTT_ERR_NOT_CONNECTED;
+
+ NULL_PARAM_CHECK(p_client);
+
+ MQTT_MUTEX_LOCK();
+
+ err_code = mqtt_raw_message_send(p_client, m_disc_packet, MQTT_FIXED_HEADER_SIZE);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ MQTT_SET_STATE_EXCLUSIVE(p_client, MQTT_STATE_DISCONNECTING);
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_subscribe(mqtt_client_t * const p_client,
+ mqtt_subscription_list_t const * const p_param)
+{
+ uint32_t err_code = MQTT_ERR_NOT_CONNECTED;
+ uint32_t offset = 0;
+ uint32_t count = 0;
+ uint32_t mqtt_packetlen = 0;
+ uint8_t * p_payload;
+
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: >> %s message id 0x%04x topic count 0x%04x",
+ p_client,
+ p_client->state,
+ __func__,
+ p_param->message_id,
+ p_param->list_count);
+
+ MQTT_MUTEX_LOCK();
+
+ p_payload = &p_client->p_packet[MQTT_FIXED_HEADER_EXTENDED_SIZE];
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ memset(p_payload, 0, MQTT_MAX_PACKET_LENGTH);
+
+ err_code = pack_uint16(p_param->message_id,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ do
+ {
+ err_code = pack_utf8_str(&p_param->p_list[count].topic,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = pack_uint8(p_param->p_list[count].qos,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+ count++;
+ } while ((err_code != NRF_SUCCESS) || (count < p_param->list_count));
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const uint8_t message_type = MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_SUBSCRIBE, 0, 1, 0);
+
+ // Rewind the packet to encode the packet correctly.
+ mqtt_packetlen = mqtt_encode_fixed_header(message_type, // Message type, Duplicate Flag, QoS and retain flag setting.
+ offset, // p_payload size without the fixed header
+ &p_payload); // Address where the p_payload is contained. Header will encoded by rewinding the location.
+ // Send message.
+ err_code = mqtt_transport_write(p_client, p_payload, mqtt_packetlen);
+ }
+ }
+
+ MQTT_TRC("[CID %p]:[State 0x%02x]: << %s result 0x%08x",
+ p_client,
+ p_client->state,
+ __func__,
+ err_code);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_unsubscribe(mqtt_client_t * const p_client,
+ mqtt_subscription_list_t const * const p_param)
+{
+ uint32_t err_code = MQTT_ERR_NOT_CONNECTED;
+ uint32_t count = 0;
+ uint32_t offset = 0;
+ uint32_t mqtt_packetlen = 0;
+ uint8_t * p_payload;
+
+ NULL_PARAM_CHECK(p_client);
+ NULL_PARAM_CHECK(p_param);
+
+ MQTT_MUTEX_LOCK();
+
+ p_payload = &p_client->p_packet[MQTT_FIXED_HEADER_EXTENDED_SIZE];
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ memset(p_payload, 0, MQTT_MAX_PACKET_LENGTH);
+
+ err_code = pack_uint16(p_param->message_id,
+ MQTT_MAX_PACKET_LENGTH,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ do
+ {
+ err_code = pack_utf8_str(&p_param->p_list[count].topic,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ count++;
+ } while ((err_code != NRF_SUCCESS) || (count < p_param->list_count));
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const uint8_t message_type = MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_UNSUBSCRIBE,
+ 0, // Duplicate flag.
+ MQTT_QoS_1_ATLEAST_ONCE,
+ 0); // Retain flag.
+
+ // Rewind the packet to encode the packet correctly.
+ mqtt_packetlen = mqtt_encode_fixed_header(message_type, // Message type, Duplicate Flag, QoS and retain flag setting.
+ offset, // Payload size without the fixed header
+ &p_payload); // Address where the p_payload is contained. Header will encoded by rewinding the location.
+
+ // Send message.
+ err_code = mqtt_transport_write(p_client, p_payload, mqtt_packetlen);
+ }
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_ping(mqtt_client_t * const p_client)
+{
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_client);
+
+ MQTT_MUTEX_LOCK();
+
+ err_code = mqtt_raw_message_send(p_client, m_ping_packet, MQTT_PKT_HEADER_SIZE);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_abort(mqtt_client_t * const p_client)
+{
+ MQTT_MUTEX_LOCK();
+
+ NULL_PARAM_CHECK(p_client);
+
+ if (p_client->state != MQTT_STATE_IDLE)
+ {
+ mqtt_client_tcp_abort(p_client);
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t mqtt_live(void)
+{
+ iot_timer_time_in_ms_t elapsed_time;
+ uint32_t index;
+
+ // Note: The module should not be locked when calling this TLS API.
+ nrf_tls_process();
+
+ MQTT_MUTEX_LOCK();
+
+ for (index = 0; index < MQTT_MAX_CLIENTS; index++)
+ {
+ mqtt_client_t * p_client = m_mqtt_client[index];
+ if (p_client != NULL)
+ {
+ UNUSED_VARIABLE(iot_timer_wall_clock_delta_get(&p_client->last_activity,
+ &elapsed_time));
+
+ if ((MQTT_KEEPALIVE > 0) && (elapsed_time > ((MQTT_KEEPALIVE - 2) * 1000)))
+ {
+ UNUSED_VARIABLE(mqtt_ping(p_client));
+ }
+ if (p_client->p_pending_packet != NULL)
+ {
+ uint32_t err;
+ err = mqtt_transport_write(p_client, p_client->p_pending_packet,
+ p_client->pending_packetlen);
+
+ if (err == NRF_SUCCESS)
+ {
+ p_client->p_pending_packet = NULL;
+ p_client->pending_packetlen = 0;
+ }
+ }
+ }
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t mqtt_input(mqtt_client_t * p_client, uint32_t timeout)
+{
+ uint32_t err_code;
+
+ NULL_PARAM_CHECK(p_client);
+
+ MQTT_MUTEX_LOCK();
+
+ MQTT_TRC("%s: 0x%08x", __func__, p_client->state);
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_TCP_CONNECTED) ||
+ MQTT_VERIFY_STATE(p_client, MQTT_STATE_DISCONNECTING))
+ {
+ err_code = tcp_receive_packet(p_client, timeout);
+ }
+ else
+ {
+ err_code = (NRF_ERROR_INVALID_STATE | IOT_MQTT_ERR_BASE);
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.h
new file mode 100644
index 0000000..980426a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt.h
@@ -0,0 +1,506 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt.h
+ *
+ * @defgroup iot_sdk_mqtt_api MQTT Client on nRF5x
+ * @ingroup iot_sdk_mqtt
+ * @{
+ * @brief MQTT Client Implementation on the Nordic nRF platforms.
+ *
+ * @details
+ * MQTT Client's Application interface is defined in this header.
+ *
+ * @note The implementation assumes LwIP Stack is available with TCP module enabled.
+ *
+ * @note By default the implementation uses MQTT version 3.1.0.
+ * However few cloud services like the Xively use the version 3.1.1.
+ * For this please set p_client.protocol_version = MQTT_VERSION_3_1_1.
+ */
+
+#ifndef MQTT_H_
+#define MQTT_H_
+
+#include <stdint.h>
+#include "iot_defines.h"
+#include "iot_timer.h"
+#include "nrf_tls.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief MQTT Asynchronous Events notified to the application from the module
+ * through the callback registered by the application. */
+typedef enum
+{
+ MQTT_EVT_CONNACK, /**< Acknowledgment of connection request. Event result accompanying the event indicates whether the connection failed or succeeded. */
+ MQTT_EVT_DISCONNECT, /**< Disconnection Event. MQTT Client Reference is no longer valid once this event is received for the client. */
+ MQTT_EVT_PUBLISH, /**< Publish event received when message is published on a topic client is subscribed to. */
+ MQTT_EVT_PUBACK, /**< Acknowledgment for published message with QoS 1. */
+ MQTT_EVT_PUBREC, /**< Reception confirmation for published message with QoS 2. */
+ MQTT_EVT_PUBREL, /**< Release of published published messages with QoS 2. */
+ MQTT_EVT_PUBCOMP, /**< Confirmation to a publish release message. Applicable only to QoS 2 messages. */
+ MQTT_EVT_SUBACK, /**< Acknowledgment to a subscription request. */
+ MQTT_EVT_UNSUBACK /**< Acknowledgment to a unsubscription request. */
+} mqtt_evt_id_t;
+
+/**@brief MQTT version protocol level. */
+typedef enum
+{
+ MQTT_VERSION_3_1_0 = 3, /**< Protocol level for 3.1.0. */
+ MQTT_VERSION_3_1_1 = 4 /**< Protocol level for 3.1.1. */
+} mqtt_version_t;
+
+/**@brief MQTT transport type. */
+typedef enum
+{
+ MQTT_TRANSPORT_NON_SECURE = 0x00, /**< Use non secure TCP transport for MQTT connection. */
+ MQTT_TRANSPORT_SECURE = 0x01, /**< Use secure TCP transport (TLS) for MQTT connection. */
+ MQTT_TRANSPORT_MAX = 0x02 /**< Shall not be used as a transport type. Indicator of maximum transport types possible. */
+} mqtt_transport_type_t;
+
+/**@brief MQTT Quality of Service types. */
+typedef enum
+{
+ MQTT_QoS_0_AT_MOST_ONCE = 0x00, /**< Lowest Quality of Service, no acknowledgment needed for published message. */
+ MQTT_QoS_1_ATLEAST_ONCE = 0x01, /**< Medium Quality of Service, if acknowledgment expected for published message, duplicate messages permitted. */
+ MQTT_QoS_2_EACTLY_ONCE = 0x02 /**< Highest Quality of Service, acknowledgment expected and message shall be published only once. Message not published to interested parties unless client issues a PUBREL. */
+} mqtt_qos_t;
+
+/**@brief MQTT Asynchronous Events notified to the application from the module
+ * through the callback registered by the application. */
+typedef enum
+{
+ MQTT_CONNECTION_ACCEPTED = 0x00, /**< Connection accepted. */
+ MQTT_UNACCEPTABLE_PROTOCOL_VERSION = 0x01, /**< The Server does not support the level of the MQTT protocol requested by the Client. */
+ MQTT_IDENTIFIER_REJECTED = 0x02, /**< The Client identifier is correct UTF-8 but not allowed by the Server. */
+ MQTT_SERVER_UNAVAILABLE = 0x03, /**< The Network Connection has been made but the MQTT service is unavailable. */
+ MQTT_BAD_USER_NAME_OR_PASSWORD = 0x04, /**< The data in the user name or password is malformed. */
+ MQTT_NOT_AUTHORIZED = 0x05 /**< The Client is not authorized to connect. */
+} mqtt_conn_return_code_t;
+
+/**@brief MQTT client forward declaration @ref mqtt_client_t for details. */
+typedef struct mqtt_client_t mqtt_client_t;
+
+/**@brief Abstracts UTF-8 encoded strings. */
+typedef struct
+{
+ uint8_t * p_utf_str; /**< Pointer to UTF-8 string. */
+ uint32_t utf_strlen; /**< Length of UTF string. */
+} mqtt_utf8_t;
+
+/**@brief Abstracts binary strings. */
+typedef struct
+{
+ uint8_t * p_bin_str; /**< Pointer to binary stream. */
+ uint32_t bin_strlen; /**< Length of binary stream. */
+} mqtt_binstr_t;
+
+/**@brief Abstracts MQTT UTF-8 encoded topic that can be subscribed to or published. */
+typedef struct
+{
+ mqtt_utf8_t topic; /**< Topic on to be published or subscribed to. */
+ uint8_t qos; /**< Quality of service requested for the subscription. @ref mqtt_qos_t for details. */
+} mqtt_topic_t;
+
+/**@brief Abstracts MQTT UTF-8 encoded unique client identifier. */
+typedef mqtt_utf8_t mqtt_client_id_t;
+
+/**@brief Abstracts MQTT UTF-8 encoded password to be used for the client connection. */
+typedef mqtt_utf8_t mqtt_password_t;
+
+/**@brief Abstracts MQTT UTF-8 encoded user name to be used for the client connection. */
+typedef mqtt_utf8_t mqtt_username_t;
+
+/**@brief Abstracts will message used in @ref mqtt_connect request.
+ *
+ * @note utf8 is used here instead of binary string as a zero length encoding is expected in
+ * will message is empty.
+ */
+typedef mqtt_utf8_t mqtt_will_message_t;
+
+/**@brief Abstracts message in binary encoded string received or published on a topic. */
+typedef mqtt_binstr_t mqtt_message_t;
+
+/**@brief Parameters for a publish message. */
+typedef struct
+{
+ mqtt_topic_t topic; /**< Topic on which data was published. */
+ mqtt_message_t payload; /**< Payload on the topic published. */
+} mqtt_publish_message_t;
+
+/**@brief Parameters for a connection acknowledgment (connack). */
+typedef struct
+{
+ uint8_t session_present_flag; /**< The Session Present flag enables a Client to establish whether the Client and Server have a consistent view about whether there is already stored Session state. */
+ mqtt_conn_return_code_t return_code; /**< The appropriate non-zero Connect return code indicates if the Server is unable to process a connection request for some reason. */
+} mqtt_connack_param_t;
+
+/**@brief Parameters for MQTT publish acknowledgment(puback). */
+typedef struct
+{
+ uint16_t message_id;
+} mqtt_puback_param_t;
+
+/**@brief Parameters for MQTT publish receive(pubrec). */
+typedef struct
+{
+ uint16_t message_id;
+} mqtt_pubrec_param_t;
+
+/**@brief Parameters for MQTT publish release(pubrec). */
+typedef struct
+{
+ uint16_t message_id;
+} mqtt_pubrel_param_t;
+
+/**@brief Parameters for MQTT publish complete(pubcomp). */
+typedef struct
+{
+ uint16_t message_id;
+} mqtt_pubcomp_param_t;
+
+/**@brief Parameters for MQTT subscription acknowledgment (suback). */
+typedef struct
+{
+ uint16_t message_id;
+} mqtt_suback_param_t;
+
+/**@brief Parameters for MQTT unsubscription acknowledgment (unsuback). */
+typedef struct
+{
+ uint16_t message_id;
+} mqtt_unsuback_param_t;
+
+/**@brief Parameters for a publish message. */
+typedef struct
+{
+ mqtt_publish_message_t message; /**< Messages including topic, QoS and its payload (if any) to be published. */
+ uint16_t message_id; /**< Message id used for the publish message. Redundant for QoS 0. */
+ uint8_t dup_flag:1; /**< Duplicate flag. If 1, it indicates the message is being retransmitted. Has no meaning with QoS 0. */
+ uint8_t retain_flag:1; /**< retain flag. If 1, the message shall be stored persistently by the broker. */
+} mqtt_publish_param_t;
+
+/**@brief List of topics in a subscription request. */
+typedef struct
+{
+ mqtt_topic_t * p_list; /**< Array containing topics along with QoS for each. */
+ uint32_t list_count; /**< Number of topics in the subscription list */
+ uint16_t message_id; /**< Message id used to identify subscription request. */
+} mqtt_subscription_list_t;
+
+/**
+ * @brief Defines event parameters notified along with asynchronous events to the application.
+ * Currently, only MQTT_EVT_PUBLISH is accompanied with parameters.
+ */
+typedef union
+{
+ mqtt_connack_param_t connack; /**< Parameters accompanying MQTT_EVT_CONNACK event. */
+ mqtt_publish_param_t publish; /**< Parameters accompanying MQTT_EVT_PUBLISH event. */
+ mqtt_puback_param_t puback; /**< Parameters accompanying MQTT_EVT_PUBACK event. */
+ mqtt_pubrec_param_t pubrec; /**< Parameters accompanying MQTT_EVT_PUBREC event. */
+ mqtt_pubrel_param_t pubrel; /**< Parameters accompanying MQTT_EVT_PUBREL event. */
+ mqtt_pubcomp_param_t pubcomp; /**< Parameters accompanying MQTT_EVT_PUBCOMP event. */
+ mqtt_suback_param_t suback; /**< Parameters accompanying MQTT_EVT_SUBACK event. */
+ mqtt_suback_param_t unsuback; /**< Parameters accompanying MQTT_EVT_UNSUBACK event. */
+} mqtt_evt_param_t;
+
+/**@brief Defined MQTT asynchronous event notified to the application. */
+typedef struct
+{
+ mqtt_evt_id_t id; /**< Identifies the event. */
+ mqtt_evt_param_t param; /**< Contains parameters (if any) accompanying the event. */
+ uint32_t result; /**< Event result. For example, MQTT_EVT_CONNACK has a result code indicating success or failure code of connection procedure. */
+} mqtt_evt_t;
+
+/**@brief Asynchronous event notification callback registered by the application with
+ * the module to receive module events.
+ *
+ * @param[in] p_client Identifies the client for which the event is notified.
+ * @param[in] p_evet Event description along with result and associated parameters (if any).
+ */
+typedef void (*mqtt_evt_cb_t)(mqtt_client_t * const p_client, const mqtt_evt_t * p_evt);
+
+/**@brief MQTT Client definition to maintain information relevant to the client. */
+struct mqtt_client_t
+{
+ mqtt_client_id_t client_id; /**< Unique client identification to be used for the connection. Shall be zero length or NULL valued. */
+ mqtt_username_t * p_user_name; /**< User name (if any) to be used for the connection. NULL indicates no user name. */
+ mqtt_password_t * p_password; /**< Password (if any) to be used for the connection. Note that if password is provided, user name shall also be provided. NULL indicates no password. */
+ mqtt_topic_t * p_will_topic; /**< Will topic and QoS. Can be NULL. */
+ mqtt_will_message_t * p_will_message; /**< Will message. Can be NULL. Non NULL value valid only if will topic is not NULL. */
+ nrf_tls_key_settings_t * p_security_settings; /**< Provide security settings like PSK, own certificate etc here. The memory provided for the settings shall be resident. */
+ mqtt_evt_cb_t evt_cb; /**< Application callback registered with the module to get MQTT events. */
+ ipv6_addr_t broker_addr; /**< IPv6 Address of MQTT broker to which client connection is requested. */
+ uint16_t broker_port; /**< Broker's Port number. */
+ uint8_t poll_abort_counter; /**< Poll abort counter maintained for the TCP connection. */
+ uint8_t protocol_version; /**< MQTT protocol version. */
+ uint8_t transport_type; /**< Transport type selection for client instance. @ref mqtt_transport_type_t for possible values. MQTT_TRANSPORT_MAX is not a valid type.*/
+ uint8_t will_retain:1; /**< Will retain flag, 1 if will message shall be retained persistently. */
+ uint8_t clean_session:1; /**< Clean session flag indicating a fresh (1) or a retained session (0). Default is 1. */
+ iot_timer_time_in_ms_t last_activity; /**< Internal. Ticks maintaining wallcock in last activity that occurred. Needed for periodic PING. */
+ uint32_t state; /**< Internal. Shall not be touched by the application. Client's state in the connection. */
+ int socket_fd; /**< Internal. Shall not be touched by the application. TCP socket file descriptor. */
+ uint32_t tcp_id; /**< Internal. Shall not be touched by the application. TCP Connection Reference provided by the IP stack. */
+ uint8_t * p_packet; /**< Internal. Shall not be touched by the application. Used for creating MQTT packet in TX path. */
+ uint8_t * p_pending_packet; /**< Internal. Shall not be touched by the application. */
+ nrf_tls_instance_t tls_instance; /**< Internal. Shall not be touched by the application. TLS instance identifier. Valid only if transport is a secure one. */
+ uint32_t pending_packetlen; /**< Internal. Shall not be touched by the application. */
+};
+
+
+/**
+ * @brief Initializes the module.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Shall be called before initiating any procedures on the module.
+ * @note If module initialization fails, no module APIs shall be called.
+ */
+uint32_t mqtt_init(void);
+
+
+/**
+ * @brief Initializes the client instance.
+ *
+ * @param[in] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ *
+ * @note Shall be called before connecting the client in order to avoid unexpected behavior
+ * caused by uninitialized parameters.
+ */
+void mqtt_client_init(mqtt_client_t * const p_client);
+
+
+/**
+ * @brief API to request new MQTT client connection.
+ *
+ * @param[out] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ *
+ * @note This memory is assumed to be resident until mqtt_disconnect is called.
+ * @note Any subsequent changes to parameters like broker address, user name, device id, etc. have
+ * no effect once MQTT connection is established.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Default protocol revision used for connection request is 3.1.0. Please set
+ * p_client.protocol_version = MQTT_VERSION_3_1_1 to use protocol 3.1.1.
+ * @note If more than one simultaneous client connections are needed, please define
+ * MQTT_MAX_CLIENTS to override default of 1.
+ * @note Please define MQTT_KEEPALIVE time to override default of 1 minute.
+ * @note Please define MQTT_MAX_PACKET_LENGTH time to override default of 128 bytes.
+ * Ensure the system has enough memory for the new length per client.
+ */
+uint32_t mqtt_connect(mqtt_client_t * const p_client);
+
+
+/**
+ * @brief API to publish messages on topics.
+ *
+ * @param[in] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Parameters to be used for the publish message.
+ * Shall not be NULL.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Default protocol revision used for connection request is 3.1.0. Please set
+ * p_client.protocol_version = MQTT_VERSION_3_1_1 to use protocol 3.1.1.
+ */
+uint32_t mqtt_publish(mqtt_client_t * const p_client,
+ mqtt_publish_param_t const * const p_param);
+
+
+/**
+ * @brief API used by subscribing client to send acknowledgment to the broker.
+ * Applicable only to QoS 1 publish messages.
+ *
+ * @param[in] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Identifies message being acknowledged.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Default protocol revision used for connection request is 3.1.0. Please set
+ * p_client.protocol_version = MQTT_VERSION_3_1_1 to use protocol 3.1.1.
+ */
+uint32_t mqtt_publish_ack(mqtt_client_t * const p_client,
+ mqtt_puback_param_t const * const p_param);
+
+
+/**
+ * @brief API to send assured acknowledgment from a subscribing client to the broker.
+ * Should be called on reception of @ref MQTT_EVT_PUBLISH with QoS set to
+ * @ref MQTT_QoS_2_EACTLY_ONCE.
+ *
+ * @param[in] p_client Identifies client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Identifies message being acknowledged.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Default protocol revision used for connection request is 3.1.0. Please set
+ * p_client.protocol_version = MQTT_VERSION_3_1_1 to use protocol 3.1.1.
+ */
+uint32_t mqtt_publish_receive(mqtt_client_t * const p_client,
+ mqtt_pubrec_param_t const * const p_param);
+
+
+/**
+ * @brief API to used by publishing client to request releasing published data.
+ * Shall be used only after @ref MQTT_EVT_PUBREC is received and is valid
+ * only for QoS level @ref MQTT_QoS_2_EACTLY_ONCE.
+ *
+ * @param[in] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Identifies message being released.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Default protocol revision used for connection request is 3.1.0. Please set
+ * p_client.protocol_version = MQTT_VERSION_3_1_1 to use protocol 3.1.1.
+ */
+uint32_t mqtt_publish_release(mqtt_client_t * const p_client,
+ mqtt_pubrel_param_t const * const p_param);
+
+
+/**
+ * @brief API used by subscribing clients to acknowledge reception of a released message.
+ * Should be used on reception @ref MQTT_EVT_PUBREL event.
+ *
+ * @param[in] p_client Identifies client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Identifies message being completed.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note Default protocol revision used for connection request is 3.1.0. Please set
+ * p_client.protocol_version = MQTT_VERSION_3_1_1 to use protocol 3.1.1.
+ */
+uint32_t mqtt_publish_complete(mqtt_client_t * const p_client,
+ mqtt_pubcomp_param_t const * const p_param);
+
+
+/**
+ * @brief API to request subscribing to a topic on the connection.
+ *
+ * @param[in] p_client Identifies client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Subscription parameters. Shall not be NULL.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_subscribe(mqtt_client_t * const p_client,
+ mqtt_subscription_list_t const * const p_param);
+
+
+/**
+ * @brief API to request un-subscribe from a topic on the connection.
+ *
+ * @param[in] p_client Identifies client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] p_param Parameters describing topics being unsubscribed from.
+ * Shall not be NULL.
+ *
+ * @note QoS included in topic description is unused in this API.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_unsubscribe(mqtt_client_t * const p_client,
+ mqtt_subscription_list_t const * const p_param);
+
+
+/**
+ * @brief API to abort MQTT connection.
+ *
+ * @param[in] p_client Identifies client instance for which procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_abort(mqtt_client_t * const p_client);
+
+
+/**
+ * @brief API to disconnect MQTT connection.
+ *
+ * @param[in] p_client Identifies client instance for which procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_disconnect(mqtt_client_t * const p_client);
+
+
+/**
+ * @brief This API should be called periodically for the module to be able to keep the connection
+ * alive by sending Ping Requests if need be.
+ *
+ * @note Application shall ensure that the periodicity of calling this function makes it possible to
+ * respect the Keep Alive time agreed with the broker on connection.
+ * @ref mqtt_connect for details on Keep Alive time.
+ *
+ * @retval NRF_SUCCESS or an result code indicating reason for failure.
+ */
+uint32_t mqtt_live(void);
+
+
+/**
+ * @brief Wait for an incoming MQTT packet.
+ * The registered callback will be called with the packet payload.
+ *
+ * @param[in] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] timeout Maximum interval (in milliseconds) to wait for a packet.
+ * If timeout is 0, the interval is indefinitely.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ *
+ * @note This API is only supported when using the socket transport layer.
+ */
+uint32_t mqtt_input(mqtt_client_t * const p_client, uint32_t timeout);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MQTT_H_
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_decoder.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_decoder.c
new file mode 100644
index 0000000..4a95865
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_decoder.c
@@ -0,0 +1,262 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt_decoder.c
+ *
+ * @brief Decoder functions needs for decoding packets received from the broker.
+ */
+
+#include "mqtt_internal.h"
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt_dec
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_LENGTH_VALUE_MASK 0x7F
+#define MQTT_LENGTH_CONTINUATION_BIT 0x80
+#define MQTT_LENGTH_MULTIPLIER 0x80
+
+
+uint32_t unpack_uint8(uint8_t * p_val,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t err_code = NRF_ERROR_DATA_SIZE;
+
+ if (buffer_len > (*p_offset))
+ {
+ const uint32_t available_len = buffer_len - (*p_offset);
+
+ MQTT_TRC(">> %s BL:%08x, B:%p, O:%08x A:%08x", __func__,
+ buffer_len, buffer, (*p_offset), available_len);
+
+ if (available_len >= SIZE_OF_UINT8)
+ {
+ // Create unit8 value.
+ (*p_val) = buffer[*p_offset];
+
+ // Increment offset.
+ (*p_offset) += SIZE_OF_UINT8;
+
+ // Indicate success.
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ MQTT_TRC("<< %s result:0x%08x val:0x%02x", __func__, err_code, (*p_val));
+ return err_code;
+}
+
+
+uint32_t unpack_uint16(uint16_t * p_val,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t err_code = NRF_ERROR_DATA_SIZE;
+
+ if (buffer_len > (*p_offset))
+ {
+ const uint32_t available_len = buffer_len - (*p_offset);
+
+ MQTT_TRC(">> %s BL:%08x, B:%p, O:%08x A:%08x", __func__,
+ buffer_len, buffer, (*p_offset), available_len);
+
+ if (available_len >= SIZE_OF_UINT16)
+ {
+ // Create unit16 value.
+ (*p_val) = ((buffer[*p_offset] & 0x00FF) << 8); // MSB
+ (*p_val) |= (buffer[(*p_offset+1)] & 0x00FF); // LSB
+
+ // Increment offset.
+ (*p_offset) += SIZE_OF_UINT16;
+
+ // Indicate success.
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ MQTT_TRC("<< %s result:0x%08x val:0x%04x", __func__, err_code, (*p_val));
+
+ return err_code;
+}
+
+
+uint32_t unpack_utf8_str(mqtt_utf8_t * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint16_t utf8_strlen;
+ uint32_t err_code = unpack_uint16(&utf8_strlen, buffer_len, buffer, p_offset);
+
+ p_str->p_utf_str = NULL;
+ p_str->utf_strlen = 0;
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const uint32_t available_len = buffer_len - (*p_offset);
+
+ MQTT_TRC(">> %s BL:%08x, B:%p, O:%08x A:%08x", __func__,
+ buffer_len, buffer, (*p_offset), available_len);
+
+ if (utf8_strlen <= available_len)
+ {
+ // Zero length UTF8 strings permitted.
+ if (utf8_strlen)
+ {
+ // Point to right location in buffer.
+ p_str->p_utf_str = &buffer[(*p_offset)];
+ }
+
+ // Populate length field.
+ p_str->utf_strlen = utf8_strlen;
+
+ // Increment offset.
+ (*p_offset) += utf8_strlen;
+
+ // Indicate success
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ // Reset to original value.
+ (*p_offset) -= SIZE_OF_UINT16;
+
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+
+ MQTT_TRC("<< %s result:0x%08x utf8 len:0x%08x", __func__, err_code, p_str->utf_strlen);
+
+ return err_code;
+}
+
+
+uint32_t unpack_bin_str(mqtt_binstr_t * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t error_code = NRF_ERROR_DATA_SIZE;
+
+ MQTT_TRC(">> %s BL:%08x, B:%p, O:%08x", __func__,
+ buffer_len, buffer, (*p_offset));
+
+ if (buffer_len >= (*p_offset))
+ {
+ p_str->p_bin_str = NULL;
+ p_str->bin_strlen = 0;
+
+ // Indicate success zero length binary strings are permitted.
+ error_code = NRF_SUCCESS;
+
+ const uint32_t available_len = buffer_len - (*p_offset);
+
+ if (available_len)
+ {
+ // Point to start of binary string.
+ p_str->p_bin_str = &buffer[(*p_offset)];
+ p_str->bin_strlen = available_len;
+
+ // Increment offset.
+ (*p_offset) += available_len;
+ }
+ }
+
+ MQTT_TRC("<< %s bin len:0x%08x", __func__, p_str->bin_strlen);
+
+ return error_code;
+}
+
+
+uint32_t packet_length_decode(uint8_t * p_buffer,
+ uint32_t buffer_len,
+ uint32_t * p_remaining_length,
+ uint32_t * p_offset)
+{
+ uint32_t index = (*p_offset);
+ uint32_t remaining_length = 0;
+ uint32_t multiplier = 1;
+
+ do
+ {
+ if (index >= buffer_len)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ remaining_length += (p_buffer[index] & MQTT_LENGTH_VALUE_MASK) * multiplier;
+ multiplier *= MQTT_LENGTH_MULTIPLIER;
+
+ } while ((p_buffer[index++] & MQTT_LENGTH_CONTINUATION_BIT) != 0);
+
+ *p_offset = index;
+ *p_remaining_length = remaining_length;
+
+ MQTT_TRC("%s: RL:0x%08x RLS:0x%08x", __func__, remaining_length, index);
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_encoder.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_encoder.c
new file mode 100644
index 0000000..74476f2
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_encoder.c
@@ -0,0 +1,457 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt_encoder.c
+ *
+ * @brief Encoding functions needed to create packet to be sent to the broker.
+ */
+
+
+#include "mqtt_internal.h"
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt_enc
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_3_1_0_PROTO_DESC_LEN 6
+#define MQTT_3_1_1_PROTO_DESC_LEN 4
+
+const uint8_t mqtt_3_1_0_proto_desc_str[MQTT_3_1_0_PROTO_DESC_LEN] = {'M', 'Q', 'I', 's', 'd', 'p'};
+const uint8_t mqtt_3_1_1_proto_desc_str[MQTT_3_1_1_PROTO_DESC_LEN] = {'M', 'Q', 'T', 'T'};
+
+const mqtt_utf8_t mqtt_3_1_0_proto_desc =
+{
+ .p_utf_str = (uint8_t *)&mqtt_3_1_0_proto_desc_str[0],
+ .utf_strlen = MQTT_3_1_0_PROTO_DESC_LEN
+};
+
+const mqtt_utf8_t mqtt_3_1_1_proto_desc =
+{
+ .p_utf_str = (uint8_t *)&mqtt_3_1_1_proto_desc_str[0],
+ .utf_strlen = MQTT_3_1_1_PROTO_DESC_LEN
+};
+
+uint32_t pack_uint8(uint8_t val,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t err_code = NRF_ERROR_DATA_SIZE;
+
+ if (buffer_len > (*p_offset))
+ {
+ MQTT_TRC(">> %s V:%02x BL:%08x, B:%p, O:%08x", __func__,
+ val, buffer_len, buffer, (*p_offset));
+
+ // Pack value.
+ buffer[(*p_offset)] = val;
+
+ // Increment offset.
+ (*p_offset) += SIZE_OF_UINT8;
+
+ // Indicate success.
+ err_code = NRF_SUCCESS;
+ }
+
+ return err_code;
+}
+
+
+uint32_t pack_uint16(uint16_t val,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t err_code = NRF_ERROR_DATA_SIZE;
+
+ if (buffer_len > (*p_offset))
+ {
+ const uint32_t available_len = buffer_len - (*p_offset);
+
+ MQTT_TRC(">> %s V:%04x BL:%08x, B:%p, O:%08x A:%08x", __func__,
+ val, buffer_len, buffer, (*p_offset), available_len);
+
+ if (available_len >= SIZE_OF_UINT16)
+ {
+ // Pack value.
+ buffer[(*p_offset)] = MSB_16(val);
+ buffer[(*p_offset)+1] = LSB_16(val);
+
+ // Increment offset.
+ (*p_offset) += SIZE_OF_UINT16;
+
+ // Indicate success.
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ return err_code;
+}
+
+
+uint32_t pack_utf8_str(mqtt_utf8_t const * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t err_code = NRF_ERROR_DATA_SIZE;
+
+ if (buffer_len > (*p_offset))
+ {
+ const uint32_t available_len = buffer_len - (*p_offset);
+ err_code = NRF_ERROR_NO_MEM;
+
+ MQTT_TRC(">> %s USL:%08x BL:%08x, B:%p, O:%08x A:%08x", __func__,
+ GET_UT8STR_BUFFER_SIZE(p_str), buffer_len, buffer, (*p_offset), available_len);
+
+ if (available_len >= GET_UT8STR_BUFFER_SIZE(p_str))
+ {
+ // Length followed by string.
+ err_code = pack_uint16(p_str->utf_strlen, buffer_len, buffer, p_offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ memcpy(&buffer[(*p_offset)], p_str->p_utf_str, p_str->utf_strlen);
+
+ (*p_offset) += p_str->utf_strlen;
+
+ err_code = NRF_SUCCESS;
+ }
+ }
+ }
+
+ return err_code;
+}
+
+uint32_t pack_bin_str(mqtt_binstr_t const * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const p_offset)
+{
+ uint32_t err_code = NRF_ERROR_DATA_SIZE;
+
+ if (buffer_len > (*p_offset))
+ {
+ const uint32_t available_len = buffer_len - (*p_offset);
+ err_code = NRF_ERROR_NO_MEM;
+
+ MQTT_TRC(">> %s BSL:%08x BL:%08x, B:%p, O:%08x A:%08x", __func__,
+ GET_BINSTR_BUFFER_SIZE(p_str), buffer_len, buffer, (*p_offset), available_len);
+
+ if (available_len >= GET_BINSTR_BUFFER_SIZE(p_str))
+ {
+ memcpy(&buffer[(*p_offset)], p_str->p_bin_str, p_str->bin_strlen);
+
+ (*p_offset) += p_str->bin_strlen;
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ return err_code;
+}
+
+
+void packet_length_encode(uint32_t remaining_length, uint8_t * p_buff, uint32_t * p_size)
+{
+ uint16_t index = 0;
+ const uint32_t offset = (*p_size);
+
+ MQTT_TRC(">> RL:0x%08x O:%08x P:%p", remaining_length, offset, p_buff);
+
+ do
+ {
+ if (p_buff != NULL)
+ {
+ p_buff[offset+index] = remaining_length % 0x80;
+ }
+
+ remaining_length /= 0x80;
+
+ if (remaining_length > 0)
+ {
+ if (p_buff != NULL)
+ {
+ p_buff[offset+index] |= 0x80;
+ }
+ }
+
+ index++;
+
+ } while (remaining_length > 0);
+
+ MQTT_TRC("<< RLS:0x%08x", index);
+
+ *p_size += index;
+}
+
+
+uint32_t mqtt_encode_fixed_header(uint8_t message_type, uint32_t length, uint8_t ** pp_packet)
+{
+ uint32_t packet_length = 0xFFFFFFFF;
+
+ if (MQTT_MAX_PAYLOAD_SIZE >= length)
+ {
+ uint32_t offset = 1;
+
+ MQTT_TRC("<< %s MT:0x%02x L:0x%08x", __func__, message_type, length);
+ packet_length_encode(length, NULL, &offset);
+
+ MQTT_TRC("Remaining length size = %02x", offset);
+
+ uint8_t * p_mqtt_header = ((*pp_packet) - offset);
+
+ // Reset offset.
+ offset = 0;
+ UNUSED_VARIABLE(pack_uint8(message_type, MQTT_MAX_PACKET_LENGTH, p_mqtt_header, &offset));
+ packet_length_encode(length, p_mqtt_header, &offset);
+
+ (* pp_packet) = p_mqtt_header;
+
+ packet_length = (length + offset);
+ }
+
+ return packet_length;
+}
+
+
+uint32_t zero_len_str_encode(uint32_t buffer_len,
+ uint8_t * const buffer,
+ uint32_t * const offset)
+{
+ return pack_uint16(0x0000, buffer_len, buffer, offset);
+}
+
+
+void connect_request_encode(const mqtt_client_t * p_client,
+ uint8_t ** pp_packet,
+ uint32_t * p_packet_length)
+{
+ uint32_t err_code;
+ uint32_t offset = 0;
+ uint8_t * p_payload = &p_client->p_packet[MQTT_FIXED_HEADER_EXTENDED_SIZE];
+ uint8_t connect_flags = p_client->clean_session << 1; // Clean session always.
+
+ const mqtt_utf8_t * p_mqtt_proto_desc;
+ if (p_client->protocol_version == MQTT_VERSION_3_1_1)
+ {
+ p_mqtt_proto_desc = &mqtt_3_1_1_proto_desc;
+ }
+ else
+ {
+ p_mqtt_proto_desc = &mqtt_3_1_0_proto_desc;
+ }
+
+ memset(p_payload, 0, MQTT_MAX_PACKET_LENGTH);
+
+ // Pack protocol description.
+ MQTT_TRC("Encoding Protocol Description. Str:%s Size:%08x.",
+ p_mqtt_proto_desc->p_utf_str,
+ p_mqtt_proto_desc->utf_strlen);
+
+ err_code = pack_utf8_str(p_mqtt_proto_desc,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ MQTT_TRC("Encoding Protocol Version %02x.", p_client->protocol_version);
+ // Pack protocol version.
+ err_code = pack_uint8(p_client->protocol_version,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+
+ // Remember position of connect flag and
+ // leave one byte for it to be packed once we determine its value.
+ const uint32_t connect_flag_offset = MQTT_FIXED_HEADER_EXTENDED_SIZE + offset;
+ offset++;
+
+ if (err_code == NRF_SUCCESS)
+ {
+ MQTT_TRC("Encoding Keep Alive Time %04x.", MQTT_KEEPALIVE);
+ // Pack keep alive time.
+ err_code = pack_uint16(MQTT_KEEPALIVE,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ MQTT_TRC("Encoding Client Id. Str:%s Size:%08x.",
+ p_client->client_id.p_utf_str,
+ p_client->client_id.utf_strlen);
+
+ // Pack client id
+ err_code = pack_utf8_str(&p_client->client_id,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Pack will topic and QoS
+ if (p_client->p_will_topic != NULL)
+ {
+ MQTT_TRC("Encoding Will Topic. Str:%s Size:%08x.",
+ p_client->p_will_topic->topic.p_utf_str,
+ p_client->p_will_topic->topic.utf_strlen);
+
+ // Set Will topic in connect flags.
+ connect_flags |= MQTT_CONNECT_FLAG_WILL_TOPIC;
+
+ err_code = pack_utf8_str(&p_client->p_will_topic->topic,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // QoS is always 1 as of now.
+ connect_flags |= ((p_client->p_will_topic->qos & 0x03) << 3);
+ connect_flags |= p_client->will_retain << 5;
+
+ if (p_client->p_will_message != NULL)
+ {
+ MQTT_TRC("Encoding Will Message. Str:%s Size:%08x.",
+ p_client->p_will_message->p_utf_str,
+ p_client->p_will_message->utf_strlen);
+
+ err_code = pack_utf8_str(p_client->p_will_message,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+ else
+ {
+ MQTT_TRC("Encoding Zero Length Will Message.");
+ err_code = zero_len_str_encode(MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Pack Username if any.
+ if (p_client->p_user_name != NULL)
+ {
+ connect_flags |= MQTT_CONNECT_FLAG_USERNAME;
+
+ MQTT_TRC("Encoding Username. Str:%s, Size:%08x.",
+ p_client->p_user_name->p_utf_str,
+ p_client->p_user_name->utf_strlen);
+
+ err_code = pack_utf8_str(p_client->p_user_name,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Pack Password if any.
+ if (p_client->p_password != NULL)
+ {
+ MQTT_TRC("Encoding Password. Str:%s Size:%08x.",
+ p_client->p_password->p_utf_str,
+ p_client->p_password->utf_strlen);
+
+ connect_flags |= MQTT_CONNECT_FLAG_PASSWORD;
+ err_code = pack_utf8_str(p_client->p_password,
+ MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
+ p_payload,
+ &offset);
+ }
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Pack the connect flags.
+ p_client->p_packet[connect_flag_offset] = connect_flags;
+
+ const uint8_t message_type = MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_CONNECT,
+ 0, // Duplicate flag not set.
+ 0, // QoS not set.
+ 0); // Retain not set.
+
+ offset = mqtt_encode_fixed_header(message_type,
+ offset,
+ &p_payload);
+
+ (*p_packet_length) = offset;
+ (*pp_packet) = p_payload;
+ }
+ else
+ {
+ (*p_packet_length) = 0;
+ (*pp_packet) = NULL;
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_internal.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_internal.h
new file mode 100644
index 0000000..807b2f9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_internal.h
@@ -0,0 +1,446 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt_internal.h
+ *
+ * @brief Function and data structures internal to MQTT module.
+ */
+
+#ifndef MQTT_INTERNAL_H_
+#define MQTT_INTERNAL_H_
+
+#include "nordic_common.h"
+#include "sdk_common.h"
+#include "sdk_config.h"
+#include "mqtt.h"
+#include "iot_errors.h"
+#include "nrf_tls.h"
+#include <stdint.h>
+#include <string.h>
+#include "nrf_error.h"
+#include "nrf_tls.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MQTT_MAX_CLIENTS
+#define MQTT_MAX_CLIENTS 1 /**< Maximum number of clients that can be managed by the module. */
+#endif //MQTT_MAX_CLIENTS
+
+#ifndef MQTT_KEEPALIVE
+#define MQTT_KEEPALIVE 60 /**< Keep alive time for MQTT (in seconds). Sending of Ping Requests to be keep the connection alive are governed by this value. */
+#endif //MQTT_KEEPALIVE
+
+#ifndef MQTT_MAX_PACKET_LENGTH
+#define MQTT_MAX_PACKET_LENGTH 128 /**< Maximum MQTT packet size that can be sent (including the fixed and variable header). */
+#endif // MQTT_MAX_PACKET_LENGTH
+
+#define MQTT_FIXED_HEADER_SIZE 2 /**< Fixed header minimum size. Remaining length size is 1 in this case. */
+#define MQTT_FIXED_HEADER_EXTENDED_SIZE 5 /**< Maximum size of the fixed header. Remaining length size is 4 in this case. */
+
+/**@brief MQTT Control Packet Types. */
+#define MQTT_PKT_TYPE_CONNECT 0x10
+#define MQTT_PKT_TYPE_CONNACK 0x20
+#define MQTT_PKT_TYPE_PUBLISH 0x30
+#define MQTT_PKT_TYPE_PUBACK 0x40
+#define MQTT_PKT_TYPE_PUBREC 0x50
+#define MQTT_PKT_TYPE_PUBREL 0x60
+#define MQTT_PKT_TYPE_PUBCOMP 0x70
+#define MQTT_PKT_TYPE_SUBSCRIBE 0x82 // QoS 1 for subscribe
+#define MQTT_PKT_TYPE_SUBACK 0x90
+#define MQTT_PKT_TYPE_UNSUBSCRIBE 0xA2
+#define MQTT_PKT_TYPE_UNSUBACK 0xB0
+#define MQTT_PKT_TYPE_PINGREQ 0xC0
+#define MQTT_PKT_TYPE_PINGRSP 0xD0
+#define MQTT_PKT_TYPE_DISCONNECT 0xE0
+
+
+/**@brief Masks for MQTT header flags. */
+#define MQTT_HEADER_DUP_MASK 0x08
+#define MQTT_HEADER_QOS_MASK 0x06
+#define MQTT_HEADER_RETAIN_MASK 0x01
+#define MQTT_HEADER_CONNACK_MASK 0x0F
+
+/**@brief Masks for MQTT header flags. */
+#define MQTT_CONNECT_FLAG_CLEAN_SESSION 0x02
+#define MQTT_CONNECT_FLAG_WILL_TOPIC 0x04
+#define MQTT_CONNECT_FLAG_WILL_RETAIN 0x20
+#define MQTT_CONNECT_FLAG_PASSWORD 0x40
+#define MQTT_CONNECT_FLAG_USERNAME 0x80
+
+/**@brief Size of mandatory header of MQTT Packet. */
+#define MQTT_PKT_HEADER_SIZE 2
+
+/**@brief */
+#define MQTT_MAX_PAYLOAD_SIZE 0x0FFFFFFF
+
+/**@brief Maximum size of variable and payload in the packet. */
+#define MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD (MQTT_MAX_PACKET_LENGTH - MQTT_FIXED_HEADER_EXTENDED_SIZE)
+
+/**@brief Defines size of uint8 in bytes. */
+#define SIZE_OF_UINT8 1
+
+/**@brief Defines size of uint8 in bytes. */
+#define SIZE_OF_UINT16 2
+
+/**@brief Computes total size needed to pack a UTF8 string. */
+#define GET_UT8STR_BUFFER_SIZE(STR) (SIZE_OF_UINT16 + (STR)->utf_strlen)
+
+/**@brief Computes total size needed to pack a binary stream. */
+#define GET_BINSTR_BUFFER_SIZE(STR) ((STR)->bin_strlen)
+
+/**@brief Unsubscribe packet size. */
+#define MQTT_UNSUBSCRIBE_PKT_SIZE 4
+
+/**@brief Sets MQTT Client's state with one indicated in 'STATE'. */
+#define MQTT_SET_STATE(CLIENT, STATE) ((CLIENT)->state |= (STATE))
+
+/**@brief Sets MQTT Client's state exclusive to 'STATE'. */
+#define MQTT_SET_STATE_EXCLUSIVE(CLIENT, STATE) ((CLIENT)->state = (STATE))
+
+/**@brief Verifies if MQTT Client's state is set with one indicated in 'STATE'. */
+#define MQTT_VERIFY_STATE(CLIENT, STATE) ((CLIENT)->state & (STATE))
+
+/**@brief Reset 'STATE' in MQTT Client's state. */
+#define MQTT_RESET_STATE(CLIENT, STATE) ((CLIENT)->state &= ~(STATE))
+
+/**@brief Initialize MQTT Client's state. */
+#define MQTT_STATE_INIT(CLIENT) (CLIENT)->state = MQTT_STATE_IDLE
+
+/**@brief Computes the first byte of MQTT message header based on message type, duplication flag,
+ * QoS and the retain flag.
+ */
+#define MQTT_MESSAGES_OPTIONS(TYPE, DUP, QOS, RETAIN) \
+ (((TYPE) & 0xF0) | \
+ (((DUP) << 3) & 0x08) | \
+ (((QOS) << 1) & 0x06) | \
+ ((RETAIN) & 0x01))
+
+
+#define MQTT_EVT_FLAG_NONE 0x00000000
+#define MQTT_EVT_FLAG_INSTANCE_RESET 0x00000001
+
+
+/**
+ * @defgroup iot_mqtt_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 the need to use an alternative architecture arises.
+ * @{
+ */
+#define MQTT_MUTEX_LOCK() SDK_MUTEX_LOCK(m_mqtt_mutex) /**< Lock module using mutex */
+#define MQTT_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_mqtt_mutex) /**< Unlock module using mutex */
+
+/** @} */
+
+/**@brief Check if the input pointer is NULL, if so it returns NRF_ERROR_NULL.
+ */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL | IOT_MQTT_ERR_BASE); \
+ }
+
+#define NULL_PARAM_CHECK_VOID(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return; \
+ }
+
+/**@brief MQTT States. */
+typedef enum
+{
+ MQTT_STATE_IDLE = 0x00000000, /**< Idle state, implying the client entry in the table is unused/free. */
+ MQTT_STATE_TCP_CONNECTING = 0x00000001, /**< TCP Connection has been requested, awaiting result of the request. */
+ MQTT_STATE_TCP_CONNECTED = 0x00000002, /**< TCP Connection successfully established. */
+ MQTT_STATE_CONNECTED = 0x00000004, /**< MQTT Connection successful. */
+ MQTT_STATE_PENDING_WRITE = 0x00000008, /**< State that indicates write callback is awaited for an issued request. */
+ MQTT_STATE_DISCONNECTING = 0x00000010 /**< TCP Disconnect has been requested, awaiting result of the request. */
+} mqtt_state_t;
+
+
+/**@brief Packs unsigned 8 bit value to the buffer at the offset requested.
+ *
+ * @param[in] val Value to be packed.
+ * @param[in] buffer_len Total size of the buffer on which value is to be packed.
+ * This shall not be zero.
+ * @param[out] p_buffer Buffer where the value is to be packed.
+ * @param[inout] p_offset Offset on the buffer where the value is to be packed. If the procedure
+ * is successful, the offset is incremented to point to the next write/pack
+ * location on the buffer.
+ *
+ * @retval NRF_SUCCESS if procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t pack_uint8(uint8_t val,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Packs unsigned 16 bit value to the buffer at the offset requested.
+ *
+ * @param[in] val Value to be packed.
+ * @param[in] buffer_len Total size of the buffer on which value is to be packed.
+ * This shall not be zero.
+ * @param[out] p_buffer Buffer where the value is to be packed.
+ * @param[inout] p_offset Offset on the buffer where the value is to be packed. If the procedure
+ * is successful, the offset is incremented to point to the next write/pack
+ * location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length minus
+ * the size of unsigned 16 bit integer.
+ */
+uint32_t pack_uint16(uint16_t val,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Packs utf8 string to the buffer at the offset requested.
+ *
+ * @param[in] p_str UTF-8 string and its length to be packed.
+ * @param[in] buffer_len Total size of the buffer on which string is to be packed.
+ * This shall not be zero.
+ * @param[out] p_buffer Buffer where the string is to be packed.
+ * @param[inout] p_offset Offset on the buffer where the string is to be packed. If the procedure
+ * is successful, the offset is incremented to point to the next write/pack
+ * location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length minus
+ * the size of unsigned 16 bit integer.
+ * @retval NRF_ERROR_NO_MEM if there is no room on the buffer to pack the string.
+ */
+uint32_t pack_utf8_str(mqtt_utf8_t const * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Packs binary string to the buffer at the offset requested.
+ *
+ * @param[in] p_str Binary string and its length to be packed.
+ * @param[in] buffer_len Total size of the buffer on which string is to be packed.
+ * @param[in] p_buffer Buffer where the string is to be packed.
+ * @param[inout] p_offset Offset on the buffer where the string is to be packed. If the procedure
+ * is successful, the offset is incremented to point to the next write/pack
+ * location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ * @retval NRF_ERROR_NO_MEM if there is no room on the buffer to pack the string.
+ */
+uint32_t pack_bin_str(mqtt_binstr_t const * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Unpacks unsigned 8 bit value from the buffer from the offset requested.
+ *
+ * @param[out] p_val Memory where the value is to be unpacked.
+ * @param[in] buffer_len Total size of the buffer. This shall not be zero.
+ * @param[in] p_buffer Buffer from which the value is to be unpacked.
+ * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
+ * procedure is successful, the offset is incremented to point to the next
+ * read/unpack location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t unpack_uint8(uint8_t * p_val,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+/**@brief Unpacks unsigned 16 bit value from the buffer from the offset requested.
+ *
+ * @param[out] p_val Memory where the value is to be unpacked.
+ * @param[in] buffer_len Total size of the buffer. This shall not be zero.
+ * @param[in] p_buffer Buffer from which the value is to be unpacked.
+ * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
+ * procedure is successful, the offset is incremented to point to the next
+ * read/unpack location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t unpack_uint16(uint16_t * p_val,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Unpacks unsigned 16 bit value from the buffer from the offset requested.
+ *
+ * @param[out] p_str Memory where the utf8 string and its value are to be unpacked.
+ * No copy of data is performed for the string.
+ * @param[in] buffer_len Total size of the buffer. This shall not be zero.
+ * @param[in] p_buffer Buffer from which the string is to be unpacked.
+ * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
+ * procedure is successful, the offset is incremented to point to the next
+ * read/unpack location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t unpack_utf8_str(mqtt_utf8_t * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Unpacks binary string from the buffer from the offset requested.
+ *
+ * @param[out] p_str Memory where the binary string and its length are to be unpacked.
+ * No copy of data is performed for the string.
+ * @param[in] buffer_len Total size of the buffer. This shall not be zero.
+ * @param[in] p_buffer Buffer where the value is to be unpacked.
+ * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
+ * procedure is successful, the offset is incremented to point to the next
+ * read/unpack location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t unpack_bin_str(mqtt_binstr_t * const p_str,
+ uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Unpacks utf8 string from the buffer from the offset requested.
+ *
+ * @param[out] p_str Memory where the utf8 string and its length are to be unpacked.
+ * @param[in] buffer_len Total size of the buffer. This shall not be zero.
+ * @param[in] p_buffer Buffer where the value is to be unpacked.
+ * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
+ * procedure is successful, the offset is incremented to point to the next
+ * read/unpack location on the buffer.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t zero_len_str_encode(uint32_t buffer_len,
+ uint8_t * const p_buffer,
+ uint32_t * const p_offset);
+
+
+/**@brief Computes and encodes length for the MQTT fixed header.
+ *
+ * @note The remaining length is not packed as a fixed unsigned 32 bit integer. Instead it is packed
+ * on algorithm below:
+ *
+ * @code
+ * do
+ * encodedByte = X MOD 128
+ * X = X DIV 128
+ * // if there are more data to encode, set the top bit of this byte
+ * if ( X > 0 )
+ * encodedByte = encodedByte OR 128
+ * endif
+ * 'output' encodedByte
+ * while ( X > 0 )
+ * @endcode
+ *
+ * @param[in] remaining_length Length of variable header and payload in the MQTT message.
+ * @param[out] p_buffer Buffer where the length is to be packed.
+ * @param[inout] p_offset Offset on the buffer where the length is to be packed.
+ */
+void packet_length_encode(uint32_t remaining_length, uint8_t * p_buffer, uint32_t * p_offset);
+
+
+/**@brief Decode MQTT Packet Length in the MQTT fixed header.
+ *
+ * @param[in] p_buffer Buffer where the length is to be decoded.
+ * @param[in] buffer_len Length of p_buffer
+ * @param[out] p_remaining_length Length of variable header and payload in the MQTT message.
+ * @param[inout] p_offset Offset on the buffer from where the length is to be unpacked.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful.
+ * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
+ */
+uint32_t packet_length_decode(uint8_t * p_buffer,
+ uint32_t buffer_len,
+ uint32_t * p_remaining_length,
+ uint32_t * p_offset);
+
+
+/**@brief Encodes fixed header for the MQTT message and provides pointer to start of the header.
+ *
+ * @param[in] message_type Message type containing packet type and the flags.
+ * Use @ref MQTT_MESSAGES_OPTIONS to construct the message_type.
+ * @param[in] length Buffer where the message payload along with variable header.
+ * @param[inout] pp_packet Pointer to the MQTT message variable header and payload.
+ * The 5 bytes before the start of the message are assumed by the
+ * routine to be available to pack the fixed header. However, since
+ * the fixed header length is variable length, the pointer to the
+ * start of the MQTT message along with encoded fixed header is
+ * supplied as output parameter if the procedure was successful.
+ *
+ * @retval 0xFFFFFFFF if the procedure failed, else length of total MQTT message along with the
+ * fixed header.
+ */
+uint32_t mqtt_encode_fixed_header(uint8_t message_type, uint32_t length, uint8_t ** pp_packet);
+
+
+/**@brief Constructs/encodes connect packet.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ * All information required for creating the packet like client id,
+ * clean session flag, retain session flag etc are assumed to be
+ * populated for the client instance when this procedure is requested.
+ * @param[out] pp_packet Pointer to the MQTT connect message.
+ * @param[out] p_packet_length Length of the connect request.
+ *
+ * @retval 0xFFFFFFFF if the procedure failed, else length of total MQTT message along with the
+ * fixed header.
+ */
+void connect_request_encode(const mqtt_client_t * p_client,
+ uint8_t ** pp_packet,
+ uint32_t * p_packet_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MQTT_INTERNAL_H_
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.c
new file mode 100644
index 0000000..10b0ae4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.c
@@ -0,0 +1,313 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt_rx.c
+ *
+ * @brief Handles packet receive on transport TCP or TLS.
+ */
+#include "mqtt_internal.h"
+
+void event_notify(mqtt_client_t * const p_client, const mqtt_evt_t * p_evt, uint32_t flags);
+void disconnect_event_notify(mqtt_client_t * p_client, uint32_t result);
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt_rx
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+static uint32_t mqtt_handle_packet(mqtt_client_t * p_client,
+ uint8_t * p_data,
+ uint32_t datalen,
+ uint32_t offset)
+{
+ mqtt_evt_t evt;
+ uint32_t err_code = NRF_SUCCESS;
+ bool notify_event = true;
+
+ // Success by default, overwritten in special cases.
+ evt.result = NRF_SUCCESS;
+
+ switch (p_data[0] & 0xF0)
+ {
+ case MQTT_PKT_TYPE_CONNACK:
+ {
+ MQTT_TRC("[%p]: Received MQTT_PKT_TYPE_CONNACK!", p_client);
+
+ if (p_client->protocol_version == MQTT_VERSION_3_1_1)
+ {
+ evt.param.connack.session_present_flag = p_data[2] & MQTT_HEADER_CONNACK_MASK;
+
+ MQTT_TRC("[%p]: session_present_flag: %d",
+ p_client,
+ evt.param.connack.session_present_flag);
+ }
+
+ evt.param.connack.return_code =
+ (mqtt_conn_return_code_t)(p_data[3] & MQTT_HEADER_CONNACK_MASK);
+
+ MQTT_TRC("[%p]: return_code: %d",
+ p_client,
+ evt.param.connack.return_code);
+
+ if (evt.param.connack.return_code == MQTT_CONNECTION_ACCEPTED)
+ {
+ // Set state.
+ MQTT_SET_STATE(p_client, MQTT_STATE_CONNECTED);
+ }
+
+ evt.result = evt.param.connack.return_code;
+ evt.id = MQTT_EVT_CONNACK;
+
+ break;
+ }
+ case MQTT_PKT_TYPE_PUBLISH:
+ {
+ evt.param.publish.dup_flag = p_data[0] & MQTT_HEADER_DUP_MASK;
+ evt.param.publish.retain_flag = p_data[0] & MQTT_HEADER_RETAIN_MASK;
+ evt.param.publish.message.topic.qos = ((p_data[0] & MQTT_HEADER_QOS_MASK) >> 1);
+
+ MQTT_TRC("[CID %p]: Received MQTT_PKT_TYPE_PUBLISH, QoS:%02x",
+ p_client, evt.param.publish.message.topic.qos);
+
+ err_code = unpack_utf8_str(&evt.param.publish.message.topic.topic,
+ datalen,
+ p_data,
+ &offset);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (evt.param.publish.message.topic.qos)
+ {
+ err_code = unpack_uint16(&evt.param.publish.message_id,
+ datalen,
+ p_data,
+ &offset);
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = unpack_bin_str(&evt.param.publish.message.payload,
+ datalen,
+ p_data,
+ &offset);
+
+ // Zero length publish messages are permitted.
+ if (err_code != NRF_SUCCESS)
+ {
+ evt.param.publish.message.payload.p_bin_str = NULL;
+ evt.param.publish.message.payload.bin_strlen = 0;
+ }
+ }
+
+ MQTT_TRC("PUB message len %08x, topic len %08x",
+ evt.param.publish.message.payload.bin_strlen,
+ evt.param.publish.message.topic.topic.utf_strlen);
+
+ evt.id = MQTT_EVT_PUBLISH;
+ evt.result = err_code;
+
+ UNUSED_VARIABLE(iot_timer_wall_clock_get(&p_client->last_activity));
+
+ break;
+ }
+
+ case MQTT_PKT_TYPE_PUBACK:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_PUBACK!");
+
+ evt.id = MQTT_EVT_PUBACK;
+ err_code = unpack_uint16(&evt.param.puback.message_id,
+ datalen,
+ p_data,
+ &offset);
+ evt.result = err_code;
+ break;
+ }
+
+ case MQTT_PKT_TYPE_PUBREC:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_PUBREC!");
+
+ evt.id = MQTT_EVT_PUBREC;
+ err_code = unpack_uint16(&evt.param.pubrec.message_id,
+ datalen,
+ p_data,
+ &offset);
+ evt.result = err_code;
+ break;
+ }
+ case MQTT_PKT_TYPE_PUBREL:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_PUBREL!");
+
+ evt.id = MQTT_EVT_PUBREL;
+ err_code = unpack_uint16(&evt.param.pubrel.message_id,
+ datalen,
+ p_data,
+ &offset);
+ evt.result = err_code;
+ break;
+ }
+ case MQTT_PKT_TYPE_PUBCOMP:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_PUBCOMP!");
+
+ evt.id = MQTT_EVT_PUBCOMP;
+ err_code = unpack_uint16(&evt.param.pubcomp.message_id,
+ datalen,
+ p_data,
+ &offset);
+ evt.result = err_code;
+ break;
+ }
+ case MQTT_PKT_TYPE_SUBACK:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_SUBACK!");
+
+ evt.id = MQTT_EVT_SUBACK;
+ err_code = unpack_uint16(&evt.param.pubrec.message_id,
+ datalen,
+ p_data,
+ &offset);
+ evt.result = err_code;
+ break;
+ }
+ case MQTT_PKT_TYPE_UNSUBACK:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_UNSUBACK!");
+
+ evt.id = MQTT_EVT_UNSUBACK;
+ err_code = unpack_uint16(&evt.param.pubrec.message_id,
+ datalen,
+ p_data,
+ &offset);
+ evt.result = err_code;
+ break;
+ }
+ case MQTT_PKT_TYPE_PINGRSP:
+ {
+ MQTT_TRC("Received MQTT_PKT_TYPE_PINGRSP!");
+
+ // No notification of Ping response to application.
+ notify_event = false;
+ break;
+ }
+ default:
+ {
+ // Nothing to notify.
+ notify_event = false;
+ break;
+ }
+ }
+
+ if (notify_event == true)
+ {
+ event_notify(p_client, &evt, MQTT_EVT_FLAG_NONE);
+ }
+
+ return err_code;
+}
+
+
+uint32_t mqtt_handle_rx_data(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ uint32_t offset = 0;
+
+ while (offset < datalen)
+ {
+ uint32_t start = offset;
+ uint32_t remaining_length = 0;
+
+ offset = 1; // Skip first byte to offset MQTT packet length.
+ err_code = packet_length_decode(p_data + start,
+ datalen - start,
+ &remaining_length,
+ &offset);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ uint32_t packet_length = offset + remaining_length;
+
+ if (start + packet_length > datalen)
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ err_code = mqtt_handle_packet(p_client,
+ p_data + start,
+ packet_length,
+ offset);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ offset = start + packet_length;
+ }
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.h
new file mode 100644
index 0000000..7372f0c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_rx.h
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file mqtt_rx.h
+ *
+ * @brief Internal methods to submit received packet.
+ */
+
+#ifndef MQTT_RX_H_
+#define MQTT_RX_H_
+
+#include "nordic_common.h"
+#include "sdk_common.h"
+#include "mqtt.h"
+#include "iot_errors.h"
+#include "nrf_tls.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Handles MQTT messages received from the peer. For TLS, this routine is evoked to handle
+ * decrypted application data. For TCP, this routine is evoked to handle TCP data.
+ *
+ * @param[in] p_client Identifies the client for which the data was received.
+ * @param[in] p_data MQTT data received.
+ * @param[inout] datalen Length of data received.
+ *
+ * @retval NRF_SUCCESS if the procedure is successful, else an error code indicating the reason
+ * for failure.
+ */
+uint32_t mqtt_handle_rx_data(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MQTT_RX_H_
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.c
new file mode 100644
index 0000000..5d0fbd8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.c
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+/** @file mqtt_transport.c
+ *
+ * @brief Internal functions to handle transport in MQTT module.
+ */
+
+
+#include "mqtt_transport.h"
+
+
+/**< Function pointer array for TCP/TLS transport handlers. */
+const transport_procedure_t transport_fn[MQTT_TRANSPORT_MAX] =
+{
+ {
+ mqtt_client_tcp_connect,
+ mqtt_client_tcp_write,
+ mqtt_client_tcp_read,
+ mqtt_client_tcp_disconnect
+ },
+ {
+ mqtt_client_tls_connect,
+ mqtt_client_tls_write,
+ mqtt_client_tls_read,
+ mqtt_client_tls_disconnect
+ }
+};
+
+
+uint32_t mqtt_transport_connect(mqtt_client_t * p_client)
+{
+ return transport_fn[p_client->transport_type].connect(p_client);
+}
+
+
+uint32_t mqtt_transport_write(mqtt_client_t * p_client, uint8_t const * p_data, uint32_t datalen)
+{
+ return transport_fn[p_client->transport_type].write(p_client, p_data, datalen);
+}
+
+
+uint32_t mqtt_transport_read(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen)
+{
+ return transport_fn[p_client->transport_type].read(p_client, p_data, datalen);
+}
+
+
+uint32_t mqtt_transport_disconnect(mqtt_client_t * p_client)
+{
+ return transport_fn[p_client->transport_type].disconnect(p_client);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.h
new file mode 100644
index 0000000..da588a7
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport.h
@@ -0,0 +1,233 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+/** @file mqtt_transport.h
+ *
+ * @brief Internal functions to handle transport in MQTT module.
+ */
+
+#ifndef MQTT_TRANSPORT_H_
+#define MQTT_TRANSPORT_H_
+
+#include "mqtt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Transport for handling transport connect procedure. */
+typedef uint32_t (*transport_connect_handler_t)(mqtt_client_t * p_client);
+
+/**@brief Transport write handler. */
+typedef uint32_t (*transport_write_handler_t)(mqtt_client_t * p_client, uint8_t const * data, uint32_t datalen);
+
+/**@brief Transport read handler. */
+typedef uint32_t (*transport_read_handler_t)(mqtt_client_t * p_client, uint8_t * data, uint32_t datalen);
+
+/**@brief Transport disconnect handler. */
+typedef uint32_t (*transport_disconnect_handler_t)(mqtt_client_t * p_client);
+
+/**@brief Transport procedure handlers. */
+typedef struct
+{
+ transport_connect_handler_t connect; /**< Transport connect handler. Handles TCP connection callback based on type of transport.*/
+ transport_write_handler_t write; /**< Transport write handler. Handles transport write based on type of transport. */
+ transport_read_handler_t read; /**< Transport read handler. Handles transport read based on type of transport. */
+ transport_disconnect_handler_t disconnect; /**< Transport disconnect handler. Handles transport disconnection based on type of transport. */
+} transport_procedure_t;
+
+
+/**@brief Handles TCP Connection Complete for configured transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_transport_connect(mqtt_client_t * p_client);
+
+
+/**@brief Handles write requests on configured transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Data to be written on the transport.
+ * @param[in] datalen Length of data to be written on the transport.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_transport_write(mqtt_client_t * p_client, uint8_t const * p_data, uint32_t datalen);
+
+
+/**@brief Handles read requests on configured transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Pointer where read data is to be fetched.
+ * @param[in] datalen Size of memory provided for the operation.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_transport_read(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen);
+
+
+/**@brief Handles transport disconnection requests on configured transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_transport_disconnect(mqtt_client_t * p_client);
+
+
+/**@brief Initiates TCP Connection.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t tcp_request_connection(mqtt_client_t * p_client);
+
+
+/**
+ * @brief Wait for an incoming MQTT packet.
+ * The registered callback will be called with the packet payload.
+ *
+ * @param[in] p_client Client instance for which the procedure is requested.
+ * Shall not be NULL.
+ * @param[in] timeout Maximum interval (in milliseconds) to wait for a packet.
+ * If timeout is 0, the interval is indefinitely.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t tcp_receive_packet(mqtt_client_t * p_client, uint32_t timeout);
+
+
+/**@brief Handles TCP Connection Complete for TCP(non-secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tcp_connect(mqtt_client_t * p_client);
+
+
+/**@brief Handles write requests on TCP(non-secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Data to be written on the transport.
+ * @param[in] datalen Length of data to be written on the transport.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tcp_write(mqtt_client_t * p_client, uint8_t const * p_data, uint32_t datalen);
+
+
+/**@brief Handles read requests on TCP(non-secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Pointer where read data is to be fetched.
+ * @param[in] datalen Size of memory provided for the operation.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tcp_read(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen);
+
+
+/**@brief Handles transport disconnection requests on TCP(non-secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tcp_disconnect(mqtt_client_t * p_client);
+
+
+/**@brief Handles read requests on TLS(secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Pointer where read data is to be fetched.
+ * @param[in] datalen Size of memory provided for the operation.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tls_connect(mqtt_client_t * p_client);
+
+
+/**@brief Handles write requests on TLS(secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Data to be written on the transport.
+ * @param[in] datalen Length of data to be written on the transport.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tls_write(mqtt_client_t * p_client, uint8_t const * p_data, uint32_t datalen);
+
+
+/**@brief Handles read requests on TLS(secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ * @param[in] p_data Pointer where read data is to be fetched.
+ * @param[in] datalen Size of memory provided for the operation.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tls_read(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen);
+
+
+/**@brief Handles transport disconnection requests on TLS(secure) transport.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+uint32_t mqtt_client_tls_disconnect(mqtt_client_t * p_client);
+
+
+/**@brief Aborts TCP connection.
+ *
+ * @param[in] p_client Identifies the client on which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS or an error code indicating reason for failure.
+ */
+void mqtt_client_tcp_abort(mqtt_client_t * p_client);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MQTT_TRANSPORT_H_
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_lwip.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_lwip.c
new file mode 100644
index 0000000..b609cd3
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_lwip.c
@@ -0,0 +1,349 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/** @file
+ *
+ * @brief MQTT Client Implementation over LwIP Stack port on nRF.
+ *
+ * This file contains the source code for MQTT Protocol over LwIP Stack for a nRF device.
+ * The implementation is limited to MQTT Client role only.
+ */
+
+
+#include "mqtt_transport.h"
+#include "mqtt_internal.h"
+#include "mqtt_rx.h"
+
+#include "lwip/opt.h"
+#include "lwip/stats.h"
+#include "lwip/sys.h"
+#include "lwip/pbuf.h"
+/*lint -save -e607 */
+#include "lwip/tcp.h"
+/*lint -restore -e607 */
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt_lwip
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+void disconnect_event_notify(mqtt_client_t * p_client, uint32_t result);
+
+
+/**@brief Close TCP connection and clean up client instance.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ */
+static void tcp_close_connection(const mqtt_client_t * p_client)
+{
+ tcp_arg((struct tcp_pcb *)p_client->tcp_id, NULL);
+ UNUSED_VARIABLE(tcp_output((struct tcp_pcb *)p_client->tcp_id));
+ tcp_recv((struct tcp_pcb *)p_client->tcp_id, NULL);
+
+ UNUSED_VARIABLE(tcp_close((struct tcp_pcb *)p_client->tcp_id));
+}
+
+
+err_t tcp_write_complete_cb(void *p_arg, struct tcp_pcb *ttcp_id, u16_t len)
+{
+ MQTT_MUTEX_LOCK();
+
+ mqtt_client_t *p_client = (mqtt_client_t *)(p_arg);
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_DISCONNECTING))
+ {
+ MQTT_TRC("[%p]: Closing TCP connection.", p_client);
+ tcp_close_connection(p_client);
+ disconnect_event_notify(p_client, NRF_SUCCESS);
+ }
+ else
+ {
+ MQTT_RESET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+ MQTT_TRC("[%p]: TCP Write Complete.", p_client);
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t mqtt_client_tcp_write(mqtt_client_t * p_client, uint8_t const * data, uint32_t datalen)
+{
+ uint32_t retval = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ retval = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_TCP_CONNECTED))
+ {
+ tcp_sent((struct tcp_pcb *)p_client->tcp_id, tcp_write_complete_cb);
+
+ MQTT_MUTEX_UNLOCK ();
+
+ uint32_t err = tcp_write((struct tcp_pcb *)p_client->tcp_id,
+ data,
+ datalen,
+ TCP_WRITE_FLAG_COPY);
+
+ MQTT_MUTEX_LOCK ();
+
+ if (err == ERR_OK)
+ {
+ MQTT_SET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+ UNUSED_VARIABLE(iot_timer_wall_clock_get(&p_client->last_activity));
+ MQTT_TRC("[%p]: TCP Write in Progress, length 0x%08x.", p_client, datalen);
+ retval = NRF_SUCCESS;
+ }
+ else
+ {
+ MQTT_TRC("[%p]: TCP write failed, err = %d", err);
+ retval = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ }
+
+ return retval;
+}
+
+
+uint32_t mqtt_client_tcp_read(mqtt_client_t * p_id, uint8_t * p_data, uint32_t datalen)
+{
+ return mqtt_handle_rx_data( p_id, p_data, datalen);
+}
+
+
+/**@brief Callback registered with TCP to handle incoming data on the connection. */
+err_t recv_callback(void * p_arg, struct tcp_pcb * p_tcp_id, struct pbuf * p_buffer, err_t err)
+{
+ MQTT_MUTEX_LOCK();
+
+ mqtt_client_t * p_client = (mqtt_client_t *)(p_arg);
+
+ MQTT_TRC(">> %s, result 0x%08x, buffer %p", __func__, err, p_buffer);
+
+ if (err == ERR_OK && p_buffer != NULL)
+ {
+ MQTT_TRC(">> Packet buffer length 0x%08x ", p_buffer->tot_len);
+ tcp_recved(p_tcp_id, p_buffer->tot_len);
+ UNUSED_VARIABLE(mqtt_transport_read(p_client, p_buffer->payload, p_buffer->tot_len));
+ }
+ else
+ {
+ MQTT_TRC("Error receiving data, closing connection");
+ tcp_close_connection(p_client);
+ disconnect_event_notify(p_client, MQTT_ERR_TRANSPORT_CLOSED);
+ }
+
+ UNUSED_VARIABLE(pbuf_free(p_buffer));
+
+ MQTT_MUTEX_UNLOCK();
+
+ return ERR_OK;
+}
+
+
+uint32_t mqtt_client_tcp_connect(mqtt_client_t * p_client)
+{
+ connect_request_encode(p_client, &p_client->p_pending_packet, &p_client->pending_packetlen);
+
+ // Send MQTT identification message to broker.
+ uint32_t err = mqtt_client_tcp_write(p_client, p_client->p_pending_packet,
+ p_client->pending_packetlen);
+ if (err != ERR_OK)
+ {
+ mqtt_client_tcp_abort(p_client);
+ }
+ else
+ {
+ p_client->p_pending_packet = NULL;
+ p_client->pending_packetlen = 0;
+ }
+
+ return err;
+}
+
+
+/**@brief TCP Connection Callback. MQTT Connection */
+err_t tcp_connection_callback(void * p_arg, struct tcp_pcb * p_tcp_id, err_t err)
+{
+ MQTT_MUTEX_LOCK();
+
+ mqtt_client_t * p_client = (mqtt_client_t *)p_arg;
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_TCP_CONNECTING) &&
+ (err == ERR_OK))
+ {
+ MQTT_SET_STATE(p_client, MQTT_STATE_TCP_CONNECTED);
+
+ // Register callback.
+ tcp_recv(p_tcp_id, recv_callback);
+ uint32_t err_code = mqtt_transport_connect(p_client);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ MQTT_TRC("Transport connect handler returned %08x", err_code);
+ disconnect_event_notify(p_client, MQTT_CONNECTION_FAILED);
+ }
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err;
+}
+
+
+void mqtt_client_tcp_abort(mqtt_client_t * p_client)
+{
+ tcp_abort((struct tcp_pcb *)p_client->tcp_id);
+ disconnect_event_notify(p_client, MQTT_ERR_TCP_PROC_FAILED);
+ MQTT_STATE_INIT(p_client);
+}
+
+
+void tcp_error_handler(void * p_arg, err_t err)
+{
+ MQTT_MUTEX_LOCK();
+
+ mqtt_client_t * p_client = (mqtt_client_t *)(p_arg);
+
+ disconnect_event_notify(p_client, err);
+
+ MQTT_STATE_INIT(p_client);
+
+ MQTT_MUTEX_UNLOCK();
+}
+
+
+err_t tcp_connection_poll(void * p_arg, struct tcp_pcb * p_tcp_id)
+{
+ MQTT_MUTEX_LOCK();
+
+ mqtt_client_t * p_client = (mqtt_client_t *)(p_arg);
+
+ p_client->poll_abort_counter++;
+
+ MQTT_MUTEX_UNLOCK();
+
+ return ERR_OK;
+}
+
+
+uint32_t tcp_request_connection(mqtt_client_t * p_client)
+{
+ p_client->poll_abort_counter = 0;
+ p_client->tcp_id = (uint32_t)tcp_new_ip6();
+
+ err_t err = tcp_connect((struct tcp_pcb *)p_client->tcp_id,
+ (ip_addr_t *)&p_client->broker_addr,
+ p_client->broker_port,
+ tcp_connection_callback);
+
+ if (err != ERR_OK)
+ {
+ UNUSED_VARIABLE(mqtt_abort(p_client));
+ }
+ else
+ {
+ tcp_arg((struct tcp_pcb *)p_client->tcp_id, p_client);
+ tcp_err((struct tcp_pcb *)p_client->tcp_id, tcp_error_handler);
+ tcp_poll((struct tcp_pcb *)p_client->tcp_id, tcp_connection_poll, 10);
+ tcp_accept((struct tcp_pcb *)p_client->tcp_id, tcp_connection_callback);
+
+ MQTT_SET_STATE(p_client, MQTT_STATE_TCP_CONNECTING);
+ }
+
+ return err;
+}
+
+
+uint32_t mqtt_client_tcp_disconnect(mqtt_client_t * p_client)
+{
+ uint32_t err_code = NRF_ERROR_INVALID_STATE;
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ const uint8_t packet[] = {MQTT_PKT_TYPE_DISCONNECT, 0x00};
+ UNUSED_VARIABLE(tcp_write((struct tcp_pcb *)p_client->tcp_id,
+ (void *)packet,
+ sizeof(packet),
+ 1));
+
+ tcp_close_connection(p_client);
+ err_code = NRF_SUCCESS;
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_TCP_CONNECTED))
+ {
+ tcp_close_connection(p_client);
+ err_code = NRF_SUCCESS;
+ }
+
+ return err_code;
+}
+
+
+uint32_t tcp_receive_packet(mqtt_client_t * p_client, uint32_t timeout)
+{
+ // This is not used in the lwip transport implementation.
+ return NRF_ERROR_NOT_SUPPORTED | IOT_MQTT_ERR_BASE;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_socket.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_socket.c
new file mode 100644
index 0000000..27bf6b6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_socket.c
@@ -0,0 +1,319 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+/** @file
+ *
+ * @brief MQTT Client Implementation over BSD Socket API on nRF.
+ *
+ * This file contains the source code for MQTT Protocol over BSD Socket API for a nRF device.
+ * The implementation is limited to MQTT Client role only.
+ */
+
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "mem_manager.h"
+#include "mqtt_transport.h"
+#include "mqtt_internal.h"
+#include "mqtt_rx.h"
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt_soc
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+void disconnect_event_notify(mqtt_client_t * p_client, uint32_t result);
+
+
+/**@brief Close TCP connection and clean up client instance.
+ *
+ * @param[in] p_client Identifies the client for which the procedure is requested.
+ */
+static void tcp_close_connection(const mqtt_client_t * p_client)
+{
+ MQTT_TRC("Closing socket %d", p_client->socket_fd);
+ UNUSED_VARIABLE(close(p_client->socket_fd));
+}
+
+
+uint32_t mqtt_client_tcp_write(mqtt_client_t * p_client, uint8_t const * data, uint32_t datalen)
+{
+ uint32_t err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_PENDING_WRITE))
+ {
+ err_code = (NRF_ERROR_BUSY | IOT_MQTT_ERR_BASE);
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_TCP_CONNECTED))
+ {
+ MQTT_TRC("[%p]: TCP writing %d bytes.", p_client, datalen);
+ MQTT_SET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+
+ MQTT_MUTEX_UNLOCK();
+
+ ssize_t nbytes = send(p_client->socket_fd, data, datalen, 0);
+
+ MQTT_MUTEX_LOCK();
+
+ MQTT_RESET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+
+ if (nbytes == datalen)
+ {
+ MQTT_TRC("[%p]: TCP write complete.", p_client);
+ UNUSED_VARIABLE(iot_timer_wall_clock_get(&p_client->last_activity));
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ MQTT_TRC("TCP write failed, errno = %d, closing connection", errno);
+ tcp_close_connection(p_client);
+ disconnect_event_notify(p_client, MQTT_ERR_TRANSPORT_CLOSED);
+ err_code = (NRF_ERROR_INTERNAL | IOT_MQTT_ERR_BASE);
+ }
+ }
+ else
+ {
+ err_code = MQTT_ERR_NOT_CONNECTED;
+ }
+
+ return err_code;
+}
+
+
+uint32_t mqtt_client_tcp_read(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen)
+{
+ return mqtt_handle_rx_data(p_client, p_data, datalen);
+}
+
+
+uint32_t mqtt_client_tcp_connect(mqtt_client_t * p_client)
+{
+ uint32_t err_code;
+
+ connect_request_encode(p_client, &p_client->p_pending_packet, &p_client->pending_packetlen);
+
+ // Send MQTT identification message to broker.
+ MQTT_SET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+
+ MQTT_MUTEX_UNLOCK();
+
+ ssize_t nbytes = send(p_client->socket_fd,
+ p_client->p_pending_packet,
+ p_client->pending_packetlen,
+ 0);
+
+ MQTT_MUTEX_LOCK();
+
+ MQTT_RESET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+
+ if (nbytes == p_client->pending_packetlen)
+ {
+ UNUSED_VARIABLE(iot_timer_wall_clock_get(&p_client->last_activity));
+ p_client->p_pending_packet = NULL;
+ p_client->pending_packetlen = 0;
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ mqtt_client_tcp_abort(p_client);
+ err_code = (NRF_ERROR_INTERNAL | IOT_MQTT_ERR_BASE);
+ }
+
+ return err_code;
+}
+
+
+void mqtt_client_tcp_abort(mqtt_client_t * p_client)
+{
+ tcp_close_connection(p_client);
+ disconnect_event_notify(p_client, MQTT_ERR_TCP_PROC_FAILED);
+}
+
+
+uint32_t tcp_receive_packet(mqtt_client_t * p_client, uint32_t timeout)
+{
+ if (timeout != 0)
+ {
+ // TODO: Implement support for timeout.
+ return NRF_ERROR_NOT_SUPPORTED | IOT_MQTT_ERR_BASE;
+ }
+
+ uint8_t * p_packet = nrf_malloc(MQTT_MAX_PACKET_LENGTH);
+ if (p_packet == NULL)
+ {
+ return NRF_ERROR_NO_MEM | IOT_MQTT_ERR_BASE;
+ }
+
+ MQTT_MUTEX_UNLOCK();
+
+ ssize_t p_len = recv(p_client->socket_fd, p_packet, MQTT_MAX_PACKET_LENGTH, 0);
+
+ MQTT_MUTEX_LOCK();
+
+ uint32_t err_code;
+
+ if (p_len > 0)
+ {
+ err_code = mqtt_transport_read(p_client, p_packet, p_len);
+ MQTT_TRC("Received %d bytes from %d: 0x%08x",
+ p_len, p_client->socket_fd, err_code);
+ }
+ else if (p_len == 0)
+ {
+ // Receiving 0 bytes indicates an orderly shutdown.
+ MQTT_TRC("Received end of stream, closing connection");
+ tcp_close_connection(p_client);
+ disconnect_event_notify(p_client, MQTT_ERR_TRANSPORT_CLOSED);
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ MQTT_TRC("Error receiving data, errno = %d, closing connection", errno);
+ mqtt_client_tcp_abort(p_client);
+ err_code = (NRF_ERROR_INVALID_DATA | IOT_MQTT_ERR_BASE);
+ }
+
+ nrf_free(p_packet);
+
+ return err_code;
+}
+
+
+uint32_t tcp_request_connection(mqtt_client_t * p_client)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ p_client->socket_fd = socket(AF_INET6, SOCK_STREAM, 0);
+ MQTT_TRC("Created socket %d", p_client->socket_fd);
+ if (p_client->socket_fd < 0)
+ {
+ err_code = (NRF_ERROR_INTERNAL | IOT_MQTT_ERR_BASE);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ struct sockaddr_in6 dest;
+ memset(&dest, 0, sizeof(dest));
+ dest.sin6_family = AF_INET6;
+ dest.sin6_port = htons(p_client->broker_port);
+ memcpy(&dest.sin6_addr, p_client->broker_addr.u8, sizeof(dest.sin6_addr));
+
+ int ret = connect(p_client->socket_fd, (struct sockaddr *)&dest, sizeof(dest));
+ if (ret == 0)
+ {
+ MQTT_SET_STATE(p_client, MQTT_STATE_TCP_CONNECTED);
+ err_code = mqtt_transport_connect(p_client);
+ MQTT_TRC("Sent connect %d: 0x%08x", p_client->socket_fd, err_code);
+ }
+ else
+ {
+ mqtt_client_tcp_abort(p_client);
+ err_code = (NRF_ERROR_INTERNAL | IOT_MQTT_ERR_BASE);
+ }
+ }
+
+ while (!MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED) && err_code == NRF_SUCCESS)
+ {
+ // Receive until connected.
+ MQTT_TRC("Receive until connected");
+ err_code = tcp_receive_packet(p_client, 0);
+ }
+
+ MQTT_TRC("Connect completed");
+ return err_code;
+}
+
+
+uint32_t mqtt_client_tcp_disconnect(mqtt_client_t * p_client)
+{
+ uint32_t err_code;
+
+ if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_CONNECTED))
+ {
+ const uint8_t packet[] = {MQTT_PKT_TYPE_DISCONNECT, 0x00};
+ MQTT_SET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+
+ MQTT_MUTEX_UNLOCK();
+
+ UNUSED_VARIABLE(send(p_client->socket_fd, (void *)packet, sizeof(packet), 0));
+
+ MQTT_MUTEX_LOCK();
+
+ MQTT_RESET_STATE(p_client, MQTT_STATE_PENDING_WRITE);
+ tcp_close_connection(p_client);
+ err_code = NRF_SUCCESS;
+ }
+ else if (MQTT_VERIFY_STATE(p_client, MQTT_STATE_TCP_CONNECTED))
+ {
+ tcp_close_connection(p_client);
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ err_code = (NRF_ERROR_INVALID_STATE | IOT_MQTT_ERR_BASE);
+ }
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_tls.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_tls.c
new file mode 100644
index 0000000..8f74600
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/mqtt/mqtt_transport_tls.c
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+/** @file
+ *
+ * @brief MQTT Client Implementation TLS layer.
+ *
+ * This file contains the source code for MQTT Protocol TLS layer for a nRF device.
+ * The implementation is limited to MQTT Client role only.
+ */
+
+
+#include "mqtt_transport.h"
+#include "mqtt_internal.h"
+#include "mqtt_rx.h"
+#include "mem_manager.h"
+
+#if MQTT_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME mqtt_tls
+
+#define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
+#define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
+
+#else // MQTT_CONFIG_LOG_ENABLED
+
+#define MQTT_TRC(...) /**< Disables traces. */
+#define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
+#define MQTT_ERR(...) /**< Disables error logs. */
+
+#define MQTT_ENTRY(...)
+#define MQTT_EXIT(...)
+
+#endif // MQTT_CONFIG_LOG_ENABLED
+
+uint32_t mqtt_client_tls_output_handler(nrf_tls_instance_t const * p_instance,
+ uint8_t const * p_data,
+ uint32_t datalen)
+{
+ NULL_PARAM_CHECK(p_instance);
+
+ uint32_t err_code = NRF_ERROR_INTERNAL;
+ mqtt_client_t * p_client = (mqtt_client_t *)p_instance->transport_id;
+
+ MQTT_MUTEX_LOCK();
+
+ MQTT_TRC(">> %s, client %p", __func__, p_client);
+
+ if (p_client != NULL)
+ {
+ err_code = mqtt_client_tcp_write(p_client, p_data, datalen);
+ }
+
+ MQTT_TRC("<< %s, client %p, result 0x%08x", __func__,
+ p_client, err_code);
+
+ MQTT_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_client_tls_connect(mqtt_client_t * p_client)
+{
+ const nrf_tls_options_t tls_option =
+ {
+ .output_fn = mqtt_client_tls_output_handler,
+ .transport_type = NRF_TLS_TYPE_STREAM,
+ .role = NRF_TLS_ROLE_CLIENT,
+ .p_key_settings = p_client->p_security_settings
+ };
+
+ connect_request_encode(p_client,
+ &p_client->p_pending_packet,
+ &p_client->pending_packetlen);
+
+ p_client->tls_instance.transport_id = (uint32_t)p_client;
+
+ MQTT_MUTEX_UNLOCK ();
+
+ uint32_t err_code = nrf_tls_alloc(&p_client->tls_instance, &tls_option);
+
+ MQTT_MUTEX_LOCK ();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_client_tls_write(mqtt_client_t * p_client,
+ uint8_t const * p_data,
+ uint32_t datalen)
+{
+ MQTT_MUTEX_UNLOCK ();
+
+ uint32_t err_code = nrf_tls_write(&p_client->tls_instance, p_data, &datalen);
+
+ MQTT_MUTEX_LOCK ();
+
+ return err_code;
+}
+
+
+uint32_t mqtt_client_tls_read(mqtt_client_t * p_client, uint8_t * p_data, uint32_t datalen)
+{
+ uint32_t err = nrf_tls_input(&p_client->tls_instance, p_data, datalen);
+
+ if ((err == NRF_SUCCESS) && (p_client->p_pending_packet == NULL))
+ {
+ uint32_t rx_datalen = 1024;
+ uint8_t * p_mqtt_data = nrf_malloc(1024);
+
+ if (p_data != NULL)
+ {
+ MQTT_MUTEX_UNLOCK ();
+
+ err = nrf_tls_read(&p_client->tls_instance,
+ p_mqtt_data,
+ &rx_datalen);
+
+ MQTT_MUTEX_LOCK ();
+
+ if ((err == NRF_SUCCESS) && (rx_datalen > 0))
+ {
+ err = mqtt_handle_rx_data(p_client, p_mqtt_data, rx_datalen);
+ }
+
+ nrf_free(p_mqtt_data);
+ }
+ }
+
+ return err;
+}
+
+
+uint32_t mqtt_client_tls_disconnect(mqtt_client_t * p_client)
+{
+ return mqtt_client_tcp_disconnect(p_client);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/README.md b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/README.md
new file mode 100644
index 0000000..9ec0b8d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/README.md
@@ -0,0 +1,28 @@
+# Socket module
+
+The socket module contains the BSD socket implementation for the IoT SDK. The purpose of the socket
+API is to
+
+* Provide a common API for all platforms
+* Simplify porting of pc network applications
+
+The socket API hides details of the underlying transport, but supports proprietary extensions for
+controlling configuration settings and using underlying transport layers.
+
+<pre>
+socket/
+ api/ - Public socket API headers
+ common/ - Common implementation of API and implementation code shared by all platforms (main socket API implementation, with hooks for different transports)
+ libraries/ - Generic libraries that are not tied to a specific platform
+ portdb/ - Port database to track and allocate socket ports
+ addr_util/ - Common address utilities
+ mbuf/ - Memory buffer utilities
+ transport/ - Transport/network stack hooks
+ ipv6/ - Nordic IPv6 stack transport hook
+ lwip/ - LwIP transport hook
+ test/ - Integration tests shared between transport stacks
+ platform/ - Platform specific code
+ ble/ - BLE specific code (only wrappers around sd_ble_app_evt_())
+ config/ - Configuration socket implementations
+ medium/ - Medium configuration socket implementation
+</pre>
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/arpa/inet.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/arpa/inet.h
new file mode 100644
index 0000000..c1749d3
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/arpa/inet.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+#ifndef SOCKET_ARPA_INET_H__
+#define SOCKET_ARPA_INET_H__
+
+#include "socket_api.h"
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/netinet/in.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/netinet/in.h
new file mode 100644
index 0000000..bfcf881
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/netinet/in.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+#ifndef SOCKET_NETINET_IN_H__
+#define SOCKET_NETINET_IN_H__
+
+#include "socket_api.h"
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/socket_api.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/socket_api.h
new file mode 100644
index 0000000..37e50d4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/socket_api.h
@@ -0,0 +1,593 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file socket_api.h
+ *
+ * @defgroup iot_socket BSD Socket interface
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Nordic socket interface for IoT.
+ *
+ * @details This module provides the socket interface for writing IoT applications. The API is
+ * designed to be compatible with the POSIX/BSD socket interface for the purpose of
+ * making porting easy. The socket options API has been extended to support configuring
+ * Nordic BLE stack, tuning of RF parameters as well as security options.
+ */
+#ifndef SOCKET_API_H__
+#define SOCKET_API_H__
+
+#include <stdint.h>
+
+#include "sdk_common.h"
+#include "iot_defines.h"
+#include "errno.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ == 0)
+typedef int32_t ssize_t;
+#else
+#include <sys/types.h>
+#ifdef __SES_ARM
+typedef int32_t ssize_t;
+#endif
+#endif
+
+#ifndef htons
+#define htons(x) HTONS(x) /**< Convert byte order from host to network (short). */
+#endif
+
+#ifndef htonl
+#define htonl(x) HTONL(x) /**< Convert byte order from host to network (long). */
+#endif
+
+#ifndef ntohs
+#define ntohs(x) NTOHS(x) /**< Convert byte order from network to host (short). */
+#endif
+
+#ifndef ntohl
+#define ntohl(x) NTOHL(x) /**< Convert byte order from network to host (long). */
+#endif
+
+/**@defgroup socket_families Values for socket_family_t
+ * @ingroup iot_socket
+ * @{
+ */
+#define AF_INET 2 /**< IPv4 socket family. */
+#define AF_INET6 10 /**< IPv6 socket family. */
+#if defined(NRF52) || defined(NRF52_SERIES)
+#define AF_NRF_CFG 39 /**< nRF configuration socket.*/
+#endif
+/**@} */
+
+/**@defgroup socket_types Values for socket_type_t
+ * @ingroup iot_socket
+ * @{
+ */
+#define SOCK_STREAM 1 /**< TCP socket type. */
+#define SOCK_DGRAM 2 /**< UDP socket type. */
+/**@} */
+
+/**@defgroup socket_protocols Values for socket_protocol_t
+ * @ingroup iot_socket
+ * @{
+ */
+#define IPPROTO_TCP 1 /**< Use TCP as transport protocol. */
+#define IPPROTO_UDP 2 /**< Use UDP as transport protocol. */
+/**@} */
+
+/**@defgroup socket_send_recv_flags Socket send/recv flags
+ * @ingroup iot_socket
+ * @{
+ */
+#define MSG_DONTROUTE 0x01 /**< Send only to hosts on directly connected networks. */
+#define MSG_DONTWAIT 0x02 /**< Enables non-blocking operation. */
+#define MSG_OOB 0x04 /**< Sends out-of-band data on sockets that support this. */
+#define MSG_PEEK 0x08 /**< Return data from the beginning of receive queue without removing data from the queue. */
+#define MSG_WAITALL 0x10 /**< Request a blocking operation until the request is satisfied. */
+/**@} */
+
+#if defined(NRF52) || defined(NRF52_SERIES)
+/**
+ * @defgroup socket_option_levels Values for socket_opt_lvl_t
+ * @ingroup iot_socket
+ * @{
+ */
+#define SOL_SOCKET 1 /**< Standard socket options. */
+#define SOL_NRF_MEDIUM 2 /**< Nordic medium socket options. Use this to control medium parameters. */
+/**@} */
+
+/**@defgroup socket_medium_options Medium socket option level types
+ * @ingroup iot_socket
+ * @{
+ */
+#define MEDIUM_INIT_PARAMS 1 /**< Medium initialization parameters. */
+/**@}
+ */
+#endif
+
+/**@defgroup fcnt_commands fcntl commands
+ * @ingroup iot_socket
+ * @{
+ */
+#define F_SETFL 1 /**< Set flag. */
+#define F_GETFL 2 /**< Get flag. */
+/**@} */
+
+/**@defgroup fcnt_flags fcntl flags
+ * @ingroup iot_socket
+ * @{
+ */
+#define O_NONBLOCK 0x01 /**< Use non-blocking I/O. */
+/**@} */
+
+/**
+ * @brief Socket module size type.
+ */
+typedef uint32_t socklen_t;
+
+/**
+ * @brief Socket port type.
+ */
+typedef uint16_t in_port_t;
+
+/**
+ * @brief Structure specifying time interval.
+ */
+struct timeval
+{
+ uint32_t tv_sec; /**< Time interval seconds. */
+ uint32_t tv_usec; /**< Time interval microseconds. */
+};
+
+/**
+ * @brief Socket families.
+ *
+ * @details For a list of valid values, refer to @ref socket_families.
+ */
+typedef int socket_family_t;
+typedef socket_family_t sa_family_t;
+
+/**
+ * @brief Socket types.
+ *
+ * @details For a list of valid values refer to @ref socket_types.
+ */
+typedef int socket_type_t;
+
+/**
+ * @brief Socket protocols.
+ *
+ * @details Use 0 if you do not want do specify socket protocol, which should be sufficient for most users.
+ * Other values are only provided for socket API compatibility, see @ref socket_protocols.
+ */
+typedef int socket_protocol_t;
+
+/**
+ * @if (IOT)
+ * @brief Socket option levels.
+ *
+ * @details For a list of valid values, refer to @ref socket_option_levels.
+ * @endif
+ */
+typedef int socket_opt_lvl_t;
+
+/**
+ * @brief Generic socket address.
+ *
+ * @details Only provided for API compatibility.
+ */
+struct sockaddr
+{
+ uint8_t sa_len;
+ socket_family_t sa_family;
+ char sa_data[];
+};
+
+/**
+ * @brief IPv6 address.
+ */
+struct in6_addr
+{
+ uint8_t s6_addr[16];
+};
+
+/**
+ * @brief IPv4 address.
+ */
+typedef uint32_t in_addr_t;
+
+/**
+ * @brief IPv4 address structure.
+ */
+struct in_addr
+{
+ in_addr_t s_addr;
+};
+
+/**
+ * @brief Global IPv6 any-address.
+ */
+extern const struct in6_addr in6addr_any;
+
+/**
+ * @brief Global IPv4 any-address.
+ */
+extern const struct in_addr inaddr_any;
+
+/**
+ * @brief Address record for IPv6 addresses.
+ *
+ * @details Contains the address and port of the host, as well as other socket options. All fields
+ * in this structure are compatible with the POSIX variant for API compatibility.
+ */
+struct sockaddr_in6
+{
+ uint8_t sin6_len; /**< Length of this data structure. */
+ sa_family_t sin6_family; /**< Socket family. */
+ in_port_t sin6_port; /**< Port, in network byte order. */
+
+ uint32_t sin6_flowinfo; /**< IPv6 flow info parameters. Not used. */
+ struct in6_addr sin6_addr; /**< IPv6 address. */
+ uint32_t sin6_scope_id; /**< IPv6 scope ID. Not used. */
+};
+
+/**
+ * @brief Address record for IPv4 addresses.
+ *
+ * @details Contains the address and port of the host. All fields
+ * in this structure are compatible with the POSIX variant for API compatibility.
+ */
+struct sockaddr_in
+{
+ uint8_t sin_len; /**< Length of this data structure. */
+ sa_family_t sin_family; /**< Socket family. */
+ in_port_t sin_port; /**< Port, in network byte order. */
+
+ struct in_addr sin_addr; /**< IPv4 address. */
+};
+
+typedef struct sockaddr sockaddr_t;
+typedef struct sockaddr_in6 sockaddr_in6_t;
+typedef struct in6_addr in6_addr_t;
+typedef struct sockaddr_in sockaddr_in_t;
+
+/**
+ * @brief Function for creating a socket.
+ *
+ * @details API to create a socket that can be used for network communication independently
+ * of lower protocol layers.
+ *
+ * @param[in] family The protocol family of the network protocol to use. Currently, only
+ * AF_INET6 is supported.
+ * @param[in] type The protocol type to use for this socket.
+ * @param[in] protocol The transport protocol to use for this socket.
+ *
+ * @return A non-negative socket descriptor on success, or -1 on error.
+ */
+int socket(socket_family_t family, socket_type_t type, socket_protocol_t protocol);
+
+/**
+ * @brief Function for closing a socket and freeing any resources held by it.
+ *
+ * @details If the socket is already closed, this function is a noop.
+ *
+ * @param[in] sock The socket to close.
+ *
+ * @return 0 on success, or -1 on error.
+ */
+int close(int sock);
+
+/**
+ * @brief Function for controlling file descriptor options.
+ *
+ * @details Set or get file descriptor options or flags. For a list of supported commands, refer to @ref fcnt_commands.
+ * For a list of supported flags, refer to @ref fcnt_flags.
+ *
+ * @param[in] fd The descriptor to set options on.
+ * @param[in] cmd The command class for options.
+ * @param[in] flags The flags to set.
+ */
+int fcntl(int fd, int cmd, int flags);
+
+/**
+ * @brief Function for connecting to an endpoint with a given address.
+ *
+ * @details The socket handle must be a valid handle that has not yet been connected. Running
+ * connect on a connected handle will return an error.
+ *
+ * @param[in] sock The socket to use for connection.
+ * @param[in] p_servaddr The address of the server to connect to. Currently, sockaddr_in6 is
+ * the only supported type.
+ * @param[in] addrlen The size of the p_servaddr argument.
+ *
+ * @return 0 on success, or -1 on error.
+ */
+int connect(int sock, const void * p_servaddr, socklen_t addrlen);
+
+/**
+ * @brief Function for sending data through a socket.
+ *
+ * @details By default, this function will block unless the O_NONBLOCK
+ * socket option has been set, OR MSG_DONTWAIT is passed as a flag. In that case, the
+ * method will return immediately.
+ *
+ * @param[in] sock The socket to write data to.
+ * @param[in] p_buff Buffer containing the data to send.
+ * @param[in] nbytes Size of data contained on p_buff.
+ * @param[in] flags Flags to control send behavior.
+ *
+ * @return The number of bytes that were sent on success, or -1 on error.
+ */
+ssize_t send(int sock, const void * p_buff, size_t nbytes, int flags);
+
+/**
+ * @brief Function for sending datagram through a socket.
+ *
+ * @details By default, this function will block if the lower layers are not able to process the
+ * packet, unless the O_NONBLOCK socket option has been set, OR MSG_DONTWAIT is passed as a flag.
+ * In that case, the method will return immediately.
+ *
+ * @param[in] sock The socket to write data to.
+ * @param[in] p_buff Buffer containing the data to send.
+ * @param[in] nbytes Size of data contained in p_buff.
+ * @param[in] flags Flags to control send behavior.
+ * @param[in] p_servaddr The address of the server to send to. Currently, sockaddr_in6 is
+ * the only supported type.
+ * @param[in] addrlen The size of the p_servaddr argument.
+ *
+ * @return The number of bytes that were sent on success, or -1 on error.
+ */
+ssize_t sendto(int sock,
+ const void * p_buff,
+ size_t nbytes,
+ int flags,
+ const void * p_servaddr,
+ socklen_t addrlen);
+
+/**
+ * @brief Function for writing data to a socket. See \ref send() for details.
+ *
+ * @param[in] sock The socket to write data to.
+ * @param[in] p_buff Buffer containing the data to send.
+ * @param[in] nbytes Size of data contained in p_buff.
+ *
+ * @return The number of bytes that were sent on success, or -1 on error.
+ */
+ssize_t write(int sock, const void * p_buff, size_t nbytes);
+
+/**
+ * @brief Function for receiving data on a socket.
+ *
+ * @details API for receiving data from a socket. By default, this function will block, unless the
+ * O_NONBLOCK socket option has been set, or MSG_DONTWAIT is passed as a flag.
+ *
+ * @param[in] sock The socket to receive data from.
+ * @param[out] p_buff Buffer to hold the data to be read.
+ * @param[in] nbytes Number of bytes to read. Should not be larger than the size of p_buff.
+ * @param[in] flags Flags to control receive behavior.
+ *
+ * @return The number of bytes that were read, or -1 on error.
+ */
+ssize_t recv(int sock, void * p_buff, size_t nbytes, int flags);
+
+/**
+ * @brief Function for receiving datagram on a socket.
+ *
+ * @details API for receiving data from a socket. By default, this function will block, unless the
+ * O_NONBLOCK socket option has been set, or MSG_DONTWAIT is passed as a flag.
+ *
+ * @param[in] sock The socket to receive data from.
+ * @param[out] p_buff Buffer to hold the data to be read.
+ * @param[in] nbytes Number of bytes to read. Should not be larger than the size of p_buff.
+ * @param[in] flags Flags to control receive behavior.
+ * @param[out] p_cliaddr Socket address that will be set to the client's address.
+ * @param[inout] p_addrlen The size of the p_cliaddr passed. Might be modified by the function.
+ *
+ * @return The number of bytes that were read, or -1 on error.
+ */
+ssize_t recvfrom(int sock,
+ void * p_buff,
+ size_t nbytes,
+ int flags,
+ void * p_cliaddr,
+ socklen_t * p_addrlen);
+
+/**
+ * @brief Function for reading data from a socket. See \ref recv() for details.
+ *
+ * @param[in] sock The socket to receive data from.
+ * @param[out] p_buff Buffer to hold the data to be read.
+ * @param[in] nbytes Number of bytes to read. Should not be larger than the size of p_buff.
+ *
+ * @return The number of bytes that were read, or -1 on error.
+ */
+ssize_t read(int sock, void * p_buff, size_t nbytes);
+
+/**
+ * @defgroup fd_set_api API for file descriptor set
+ * @ingroup iot_socket
+ * @details File descriptor sets are used as input to the select() function for doing I/O
+ * multiplexing. The maximum number of descriptors contained in a set is defined by
+ * FD_SETSIZE.
+ *
+ * @{
+ */
+#ifndef FD_ZERO
+
+typedef uint32_t fd_set;
+#define FD_ZERO(set) (*(set) = 0) /**< Clear the entire set. */
+#define FD_SET(fd, set) (*(set) |= (1u << (fd))) /**< Set a bit in the set. */
+#define FD_CLR(fd, set) (*(set) &= ~(1u << (fd))) /**< Clear a bit in the set. */
+#define FD_ISSET(fd, set) (*(set) & (1u << (fd))) /**< Check if a bit in the set is set. */
+#define FD_SETSIZE sizeof(fd_set) /**< The max size of a set. */
+
+#endif
+/**@} */
+
+/**
+ * @brief Function for waiting for read, write, or exception events on a socket.
+ *
+ * @details Wait for a set of socket descriptors to be ready for reading, writing, or having
+ * exceptions. The set of socket descriptors is configured before calling this function.
+ * This function will block until any of the descriptors in the set has any of the required
+ * events. This function is mostly useful when using O_NONBLOCK or MSG_DONTWAIT options
+ * to enable async operation.
+ *
+ * @param[in] nfds The highest socket descriptor value contained in the sets.
+ * @param[inout] p_readset The set of descriptors for which to wait for read events. Set to NULL
+ * if not used.
+ * @param[inout] p_writeset The set of descriptors for which to wait for write events. Set to NULL
+ * if not used.
+ * @param[inout] p_exceptset The set of descriptors for which to wait for exception events. Set to
+ * NULL if not used.
+ * @param[in] p_timeout The timeout to use for select call. Set to NULL if waiting forever.
+ *
+ * @return The number of ready descriptors contained in the descriptor sets on success, or -1 on error.
+ */
+int select(int nfds,
+ fd_set * p_readset,
+ fd_set * p_writeset,
+ fd_set * p_exceptset,
+ const struct timeval * p_timeout);
+
+/**
+ * @brief Function for setting socket options for a given socket.
+ *
+ * @details The options are grouped by level, and the option value should be the expected for the
+ * given option, and the lifetime must be longer than that of the socket.
+ *
+ * @param[in] sock The socket for which to set the option.
+ * @param[in] level The level or group to which the option belongs.
+ * @param[in] optname The name of the socket option.
+ * @param[in] p_optval The value to be stored for this option.
+ * @param[in] optlen The size of p_optval.
+ *
+ * @return 0 on success, or -1 on error.
+ */
+int setsockopt(int sock,
+ socket_opt_lvl_t level,
+ int optname,
+ const void * p_optval,
+ socklen_t optlen);
+
+/**
+ * @brief Function for getting socket options for a given socket.
+ *
+ * @details The options are grouped by level, and the option value is the value described by the
+ * option name.
+ *
+ * @param[in] sock The socket for which to set the option.
+ * @param[in] level The level or group to which the option belongs.
+ * @param[in] optname The name of the socket option.
+ * @param[out] p_optval Pointer to the storage for the option value.
+ * @param[inout] p_optlen The size of p_optval. Can be modified to the actual size of p_optval.
+ *
+ * @return 0 on success, or -1 on error.
+ */
+int getsockopt(int sock,
+ socket_opt_lvl_t level,
+ int optname,
+ void * p_optval,
+ socklen_t * p_optlen);
+
+/**
+ * @brief Function for binding a socket to an address and port.
+ *
+ * @details The provided address must be supported by the socket protocol family.
+ *
+ * @param[in] sock The socket descriptor to bind.
+ * @param[in] p_myaddr The address to bind this socket to.
+ * @param[in] addrlen The size of p_myaddr.
+ *
+ * @return 0 on success, or -1 on error.
+ */
+int bind(int sock, const void * p_myaddr, socklen_t addrlen);
+
+/**
+ * @brief Function for marking a socket as listenable.
+ *
+ * @details Once a socket is marked as listenable, it cannot be unmarked. It is important to
+ * consider the backlog parameter, as it will affect how much memory your application will
+ * use in the worst case.
+ *
+ * @param[in] sock The socket descriptor on which to set the listening options.
+ * @param[in] backlog The max length of the queue of pending connections. A value of 0 means
+ * infinite.
+ *
+ * @return 0 on success, or -1 on error.
+ */
+int listen(int sock, int backlog);
+
+/**
+ * @brief Function for waiting for the next client to connect.
+ *
+ * @details This function will block if there are no clients attempting to connect.
+ *
+ * @param[in] sock The socket descriptor to use for waiting on client connections.
+ * @param[out] p_cliaddr Socket address that will be set to the client's address.
+ * @param[out] p_addrlen The size of the p_cliaddr passed. Might be modified by the function.
+ *
+ * @return A non-negative client descriptor on success, or -1 on error.
+ */
+int accept(int sock, void * p_cliaddr, socklen_t * p_addrlen);
+
+/**
+ * @brief Function for converting a human-readable IP address to a form usable by the socket API.
+ *
+ * @details This function will convert a string form of addresses and encode it into a byte array.
+ *
+ * @param[in] af Address family. Only AF_INET6 supported.
+ * @param[in] p_src Null-terminated string containing the address to convert.
+ * @param[out] p_dst Pointer to a struct in6_addr where the address will be stored.
+ *
+ * @return 1 on success, 0 if src does not contain a valid address, -1 if af is not a valid address
+ * family.
+ */
+int inet_pton(socket_family_t af, const char * p_src, void * p_dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //SOCKET_API_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/select.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/select.h
new file mode 100644
index 0000000..3fb05fb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/select.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+#ifndef SOCKET_SYS_SELECT_H__
+#define SOCKET_SYS_SELECT_H__
+
+#include "socket_api.h"
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/socket.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/socket.h
new file mode 100644
index 0000000..c01fc3e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/sys/socket.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+#ifndef SOCKET_SYS_SOCKET_H__
+#define SOCKET_SYS_SOCKET_H__
+
+#include "socket_api.h"
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/unistd.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/unistd.h
new file mode 100644
index 0000000..ac77bdf
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/api/unistd.h
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file unistd.h
+ *
+ * @defgroup iot_posix_unistd POSIX operating system API
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief POSIX standard functions.
+ */
+#ifndef SOCKET_UNISTD_H__
+#define SOCKET_UNISTD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief POSIX sleep function.
+ *
+ * @note Uses busy looping nrf_delay.
+ *
+ * @param[in] seconds The number of seconds to sleep.
+ *
+ * @return The number of seconds slept.
+ */
+unsigned int sleep(unsigned int seconds);
+
+/**
+ * @brief POSIX usleep function.
+ *
+ * @note Uses busy looping nrf_delay.
+ *
+ * @param[in] useconds The number of microseconds to sleep.
+ *
+ * @return The number of microseconds slept.
+ */
+unsigned int usleep(unsigned int useconds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SOCKET_UNISTD_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/sleep.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/sleep.c
new file mode 100644
index 0000000..94dd07a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/sleep.c
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2015 - 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 "unistd.h"
+#include "nrf_delay.h"
+
+unsigned int sleep(unsigned int seconds)
+{
+ nrf_delay_ms(seconds * 1000);
+ return seconds;
+}
+
+unsigned int usleep(unsigned int useconds)
+{
+ nrf_delay_ms(useconds / 1000);
+ return useconds;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket.c
new file mode 100644
index 0000000..fe7d6ca
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket.c
@@ -0,0 +1,746 @@
+/**
+ * Copyright (c) 2015 - 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 "nrf_sdm.h"
+#include "app_scheduler.h"
+#include "app_timer.h"
+#include "iot_common.h"
+#include "app_error.h"
+#include "socket_api.h"
+#include "socket_common.h"
+#include "socket_trace.h"
+#include "sdk_os.h"
+#include "transport_if.h"
+#include "portdb.h"
+#include "errno.h"
+#include "mem_manager.h"
+#include "ipv6_parse.h"
+#include "netinet/in.h"
+#include "unistd.h"
+#include "sdk_os.h"
+#include "nrf_log_ctrl.h"
+#include "nrf_log_default_backends.h"
+
+#ifndef SOCKET_ENABLE_API_PARAM_CHECK
+#define SOCKET_ENABLE_API_PARAM_CHECK 0
+#endif
+
+#include "socket_config.h"
+
+#if SOCKET_CONFIG_LOG_ENABLED == 1
+ NRF_LOG_MODULE_REGISTER();
+#endif
+
+/**
+ * @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.
+ * SOCKET_ENABLE_API_PARAM_CHECK should be set to 0 to disable these checks.
+ *
+ * @{
+ */
+#if SOCKET_ENABLE_API_PARAM_CHECK == 1
+
+/**@brief Macro to check is module is initialized before requesting one of the module procedures. */
+#define VERIFY_MODULE_IS_INITIALIZED() \
+ do { \
+ if (m_initialization_state == false) \
+ { \
+ return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_SOCKET_ERR_BASE);\
+ } \
+ } while (0)
+
+
+/**
+ * @brief Verify NULL parameters are not passed to API by application.
+ */
+#define NULL_PARAM_CHECK(PARAM) \
+ do { \
+ if ((PARAM) == NULL) \
+ { \
+ set_errno(EFAULT); \
+ return -1; \
+ } \
+ } while (0)
+
+/**
+ * @brief Verify socket id passed on the API by application is valid.
+ */
+#define VERIFY_SOCKET_ID(ID) \
+ do { \
+ if (((ID) < 0) || ((ID) >= NUM_SOCKETS)) \
+ { \
+ set_errno(EBADF); \
+ return -1; \
+ } \
+ } while (0)
+
+
+#else
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define NULL_PARAM_CHECK(PARAM)
+#define VERIFY_SOCKET_ID(ID)
+#endif
+
+/** @} */
+#define SOCKET_MUTEX_INIT() SDK_MUTEX_INIT(m_socket_mtx);
+#define SOCKET_MUTEX_LOCK() SDK_MUTEX_LOCK(m_socket_mtx)
+#define SOCKET_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_socket_mtx)
+// note: one extra for configuration socket
+#define NUM_SOCKETS SOCKET_MAX_SOCKET_COUNT + 1
+
+SDK_MUTEX_DEFINE(m_socket_mtx) /**< Mutex for protecting m_socket_table (not individual entries). */
+
+#define SCHED_QUEUE_SIZE 16 /**< Maximum number of events in the scheduler queue. */
+#define SCHED_MAX_EVENT_DATA_SIZE 192 /**< Maximum size of scheduler events. */
+
+static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */
+static volatile bool m_interface_up = false; /**< Interface state. */
+static socket_t m_socket_table[NUM_SOCKETS]; /**< Socket table. */
+
+const struct in6_addr in6addr_any = { {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /**< IPv6 anycast address. */
+ 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u} };
+
+#if defined (NRF_LOG_ENABLED) && (NRF_LOG_ENABLED == 1)
+
+void log_init(void)
+{
+ ret_code_t err_code = NRF_LOG_INIT(NULL);
+ APP_ERROR_CHECK(err_code);
+
+ NRF_LOG_DEFAULT_BACKENDS_INIT();
+}
+
+#else // defined (NRF_LOG_ENABLED) && (NRF_LOG_ENABLED == 1)
+
+void log_init(void)
+{
+ ;
+}
+
+#endif // defined (NRF_LOG_ENABLED) && (NRF_LOG_ENABLED == 1)
+
+uint32_t socket_init(void)
+{
+ memset(m_socket_table, 0, sizeof(m_socket_table));
+
+ SOCKET_MUTEX_INIT();
+
+ log_init();
+
+ uint32_t err_code = nrf_mem_init();
+ APP_ERROR_CHECK(err_code);
+
+ APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
+
+ err_code = app_timer_init();
+ APP_ERROR_CHECK(err_code);
+
+ err_code = config_socket_init();
+ APP_ERROR_CHECK(err_code);
+
+#if SOCKET_TRANSPORT_ENABLE == 1
+ err_code = portdb_init(SOCKET_MAX_SOCKET_COUNT);
+ APP_ERROR_CHECK(err_code);
+
+ transport_handler_init();
+#endif
+ config_socket_start();
+ m_initialization_state = true;
+
+ SOCKET_TRACE("Socket init complete");
+
+ return NRF_SUCCESS;
+}
+
+/**
+ * Finds a free entry in the socket table, marks it as used and returns it. Returns -1 if no entry
+ * was found.
+ */
+static int socket_allocate(socket_t ** pp_socket)
+{
+ int ret_sock = -1;
+ SOCKET_MUTEX_LOCK();
+ for (int sock = 0; sock < NUM_SOCKETS; sock++)
+ {
+ SOCKET_TRACE("Looking at socket %d with state %d", (int)sock, m_socket_table[sock].so_state);
+ if (m_socket_table[sock].so_state == STATE_CLOSED)
+ {
+ m_socket_table[sock].so_state = STATE_OPEN;
+ ret_sock = sock;
+ *pp_socket = &m_socket_table[sock];
+ break;
+ }
+ }
+ if (ret_sock < 0)
+ {
+ set_errno(EMFILE);
+ }
+ SOCKET_MUTEX_UNLOCK();
+ return ret_sock;
+}
+
+static socket_t * socket_find(int sock)
+{
+ SOCKET_MUTEX_LOCK();
+ socket_t * p_socket = &m_socket_table[sock];
+ SOCKET_MUTEX_UNLOCK();
+ return p_socket;
+}
+
+static void socket_free(int sock)
+{
+ SOCKET_TRACE("Freeing socket %d", (int)sock);
+ SOCKET_MUTEX_LOCK();
+ memset(&m_socket_table[sock], 0, sizeof(m_socket_table[sock]));
+ m_socket_table[sock].so_state = STATE_CLOSED;
+ SOCKET_MUTEX_UNLOCK();
+}
+
+#if SOCKET_TRANSPORT_ENABLE == 1
+void transport_interface_up(void)
+{
+ m_interface_up = true;
+}
+
+void transport_interface_down(void)
+{
+ m_interface_up = false;
+ for (int sock = 0; sock < NUM_SOCKETS; sock++)
+ {
+ (void) close(sock);
+ }
+}
+#endif
+
+int fcntl(int fd, int cmd, int flags)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(fd);
+
+ if (!((cmd == F_SETFL) || (cmd == F_GETFL)))
+ {
+ set_errno(EINVAL);
+ return -1;
+ }
+ socket_t * p_socket = socket_find(fd);
+
+ if (cmd == F_SETFL)
+ {
+ p_socket->so_flags = flags;
+ }
+ else if (cmd == F_GETFL)
+ {
+ return p_socket->so_flags;
+ }
+
+ return 0;
+}
+
+static void socket_set_errno(uint32_t err_code)
+{
+ switch (err_code) {
+ case UDP_INTERFACE_NOT_READY: // fallthrough
+ case SOCKET_INTERFACE_NOT_READY:
+ set_errno(ENETDOWN);
+ break;
+ case SOCKET_WOULD_BLOCK:
+ set_errno(EAGAIN);
+ break;
+ case SOCKET_NO_ROUTE:
+ set_errno(ENETUNREACH);
+ break;
+ case NRF_ERROR_NO_MEM: // fallthrough
+ case SOCKET_NO_MEM:
+ set_errno(ENOMEM);
+ break;
+ case SOCKET_TIMEOUT:
+ set_errno(ETIMEDOUT);
+ break;
+ case SOCKET_NO_AVAILABLE_PORTS:
+ set_errno(EMFILE);
+ break;
+ case SOCKET_PORT_IN_USE: // fallthrough
+ case SOCKET_ADDRESS_IN_USE:
+ set_errno(EADDRINUSE);
+ break;
+ case SOCKET_INVALID_PARAM:
+ set_errno(EINVAL);
+ break;
+ case SOCKET_UNSUPPORTED_PROTOCOL:
+ set_errno(EPROTONOSUPPORT);
+ break;
+ case SOCKET_NOT_CONNECTED:
+ set_errno(ENOTCONN);
+ break;
+ }
+}
+
+
+int socket(socket_family_t family, socket_type_t type, socket_protocol_t protocol)
+{
+ if (m_initialization_state == false)
+ {
+ (void) socket_init();
+ }
+ VERIFY_MODULE_IS_INITIALIZED();
+
+ int ret_sock = -1;
+ socket_t * p_socket = NULL;
+ int sock = socket_allocate(&p_socket);
+ SOCKET_TRACE("Got value %d from allocate", (int)sock);
+ if (sock >= 0)
+ {
+ p_socket->so_params.so_family = family;
+ p_socket->so_params.so_protocol = protocol;
+ p_socket->so_params.so_type = type;
+ p_socket->so_transport = NULL;
+
+ if (family == AF_INET6)
+ {
+#if SOCKET_TRANSPORT_ENABLE == 1
+ p_socket->so_transport = &transport_impl;
+#else
+ set_errno(EAFNOSUPPORT);
+#endif
+ }
+ else if (family == AF_NRF_CFG || family == AF_NRF_CFG_INTERNAL)
+ {
+ p_socket->so_transport = &config_socket_transport;
+ }
+ else
+ {
+ set_errno(EAFNOSUPPORT);
+ }
+
+ if (p_socket->so_transport != NULL)
+ {
+ uint32_t err_code = p_socket->so_transport->open(p_socket);
+ socket_set_errno(err_code);
+ ret_sock = (err_code == NRF_SUCCESS) ? sock : ret_sock;
+ }
+
+ if (ret_sock < 0)
+ {
+ socket_free(sock);
+ }
+ }
+ SOCKET_TRACE("Returning socket value %d", (int)ret_sock);
+ return ret_sock;
+}
+
+static uint32_t wait_interface_up(void)
+{
+ SOCKET_TRACE("Waiting for interface to come up");
+ uint32_t err_code = NRF_SUCCESS;
+ while (err_code == NRF_SUCCESS && m_interface_up == false)
+ {
+ err_code = socket_wait();
+ }
+ if (m_interface_up == true)
+ {
+ SOCKET_TRACE("Interface is up!");
+ }
+ return err_code;
+}
+
+static uint32_t socket_interface_up(bool is_blocking)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ if (m_interface_up == false)
+ {
+ if (is_blocking)
+ {
+ (void) wait_interface_up();
+ }
+ }
+ if (m_interface_up == false)
+ {
+ err_code = SOCKET_INTERFACE_NOT_READY;
+ }
+ return err_code;
+}
+
+int connect(int sock, const void * p_addr, socklen_t addrlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+ NULL_PARAM_CHECK(p_addr);
+
+ socket_t * p_socket = socket_find(sock);
+ bool is_blocking = ((p_socket->so_flags & O_NONBLOCK) == 0);
+ int ret = -1;
+
+ uint32_t err_code = socket_interface_up(is_blocking);
+ if (err_code != NRF_SUCCESS)
+ {
+ socket_set_errno(err_code);
+ }
+ else if (p_socket->so_state == STATE_OPEN)
+ {
+ err_code = p_socket->so_transport->connect(p_socket, p_addr, addrlen);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_socket->so_state = STATE_CONNECTED;
+ ret = 0;
+ }
+ socket_set_errno(err_code);
+ }
+ else if (p_socket->so_state == STATE_CONNECTED)
+ {
+ set_errno(EISCONN);
+ }
+ else if (p_socket->so_state == STATE_CLOSED)
+ {
+ set_errno(EBADF);
+ }
+ return ret;
+}
+
+
+ssize_t sendto(int sock,
+ const void * p_buf,
+ size_t buflen,
+ int flags,
+ const void * p_servaddr,
+ socklen_t addrlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+ NULL_PARAM_CHECK(p_buf);
+
+ socket_t * p_socket = socket_find(sock);
+
+ if ((p_socket->so_flags & O_NONBLOCK) != 0 &&
+ (flags & MSG_WAITALL) == 0)
+ {
+ flags |= MSG_DONTWAIT;
+ }
+
+ uint32_t err_code = socket_interface_up(((p_socket->so_flags & O_NONBLOCK) == 0) || ((flags & MSG_DONTWAIT) == 0));
+
+ ssize_t ret = -1;
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = p_socket->so_transport->send(p_socket, p_buf, buflen, flags, p_servaddr, addrlen);
+ if (err_code == NRF_SUCCESS)
+ {
+ ret = (ssize_t) buflen;
+ }
+ }
+ socket_set_errno(err_code);
+ return ret;
+}
+
+ssize_t send(int sock, const void * p_buf, size_t buflen, int flags)
+{
+ return sendto(sock, p_buf, buflen, flags, NULL, 0);
+}
+
+ssize_t write(int sock, const void * p_buf, size_t buflen)
+{
+ return send(sock, p_buf, buflen, 0);
+}
+
+ssize_t recvfrom(int sock,
+ void * p_buf,
+ size_t buf_size,
+ int flags,
+ void * p_cliaddr,
+ socklen_t * p_addrlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+ NULL_PARAM_CHECK(p_buf);
+
+ socket_t * p_socket = socket_find(sock);
+ ssize_t ret = -1;
+ uint32_t recv_size = buf_size;
+
+ uint32_t err_code = p_socket->so_transport->recv(p_socket,
+ p_buf,
+ &recv_size,
+ flags,
+ p_cliaddr,
+ p_addrlen);
+ if (err_code == NRF_SUCCESS)
+ {
+ ret = (ssize_t) recv_size;
+ }
+ socket_set_errno(err_code);
+ return ret;
+}
+
+ssize_t recv(int sock, void * p_buf, size_t buf_size, int flags)
+{
+ return recvfrom(sock, p_buf, buf_size, flags, NULL, NULL);
+}
+
+ssize_t read(int sock, void * p_buf, size_t buf_size)
+{
+ return recv(sock, p_buf, buf_size, 0);
+}
+
+int setsockopt(int sock,
+ socket_opt_lvl_t level,
+ int optname,
+ const void * p_optval,
+ socklen_t optlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+
+ socket_t * p_socket = socket_find(sock);
+
+ uint32_t err_code = p_socket->so_transport->setsockopt(p_socket,
+ level,
+ optname,
+ p_optval,
+ optlen);
+ socket_set_errno(err_code);
+ return (err_code == NRF_SUCCESS ? 0 : -1);
+}
+
+int getsockopt(int sock, socket_opt_lvl_t level, int optname, void * p_optval, socklen_t * p_optlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+
+ socket_t * p_socket = socket_find(sock);
+
+ uint32_t err_code = p_socket->so_transport->getsockopt(p_socket,
+ level,
+ optname,
+ p_optval,
+ p_optlen);
+ socket_set_errno(err_code);
+ return (err_code == NRF_SUCCESS ? 0 : -1);
+}
+
+int bind(int sock, const void * p_addr, socklen_t addrlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+ NULL_PARAM_CHECK(p_addr);
+
+ socket_t * p_socket = socket_find(sock);
+ bool is_blocking = ((p_socket->so_flags & O_NONBLOCK) == 0);
+ int ret = -1;
+
+ uint32_t err_code = socket_interface_up(is_blocking);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = p_socket->so_transport->bind(p_socket, p_addr, addrlen);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ ret = 0;
+ }
+ socket_set_errno(err_code);
+ return ret;
+}
+
+int listen(int sock, int backlog)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+
+ socket_t * p_socket = socket_find(sock);
+
+ uint32_t err_code = p_socket->so_transport->listen(p_socket, backlog);
+ return (err_code == NRF_SUCCESS ? 0 : -1);
+}
+
+int accept(int sock, void * p_cliaddr, socklen_t * p_addrlen)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+ NULL_PARAM_CHECK(p_cliaddr);
+ NULL_PARAM_CHECK(p_addrlen);
+
+ socket_t * p_socket = socket_find(sock);
+ int ret = -1;
+
+ if (p_socket->so_params.so_type != SOCK_STREAM)
+ {
+ set_errno(EOPNOTSUPP);
+ }
+ else
+ {
+ uint32_t err_code = NRF_SUCCESS;
+ socket_t * p_client = NULL;
+ int sock_cli = socket_allocate(&p_client);
+ if (sock_cli >= 0)
+ {
+ p_client->so_params = p_socket->so_params;
+ p_client->so_state = STATE_CONNECTED;
+ p_client->so_transport = p_socket->so_transport;
+ err_code = p_socket->so_transport->accept(p_socket, p_client, p_cliaddr, p_addrlen);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ret = sock_cli;
+ }
+ else
+ {
+ socket_set_errno(err_code);
+ socket_free(sock_cli);
+ }
+ }
+ return ret;
+}
+
+int close(int sock)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ VERIFY_SOCKET_ID(sock);
+
+ socket_t * p_socket = socket_find(sock);
+ int ret = 0;
+
+ if (p_socket->so_state != STATE_CLOSED)
+ {
+ uint32_t err_code = p_socket->so_transport->close(p_socket);
+ ret = (err_code == NRF_SUCCESS) ? 0 : -1;
+ SOCKET_TRACE("Close socket %d: ret: %d", (int)sock, ret);
+ socket_free(sock);
+ }
+ return ret;
+}
+
+int fd_set_cmp(fd_set * set_a, fd_set * set_b)
+{
+ int ret = 0;
+ if (set_a != NULL && set_b != NULL)
+ {
+ for (uint32_t i = 0; i < FD_SETSIZE; i++)
+ {
+ if (FD_ISSET(i, set_a) != FD_ISSET(i, set_b))
+ {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+int select(int nfds,
+ fd_set * p_readset,
+ fd_set * p_writeset,
+ fd_set * p_exceptset,
+ const struct timeval * p_timeout)
+{
+ VERIFY_SOCKET_ID(nfds - 1);
+
+ // Approximately 10 ms sleep between each iteration
+ uint32_t timestep = 10000;
+ uint32_t endtime = 0;
+ if (p_timeout != NULL)
+ {
+ endtime = (p_timeout->tv_sec * 1000000) + p_timeout->tv_usec;
+ }
+ fd_set readset;
+ FD_ZERO(&readset);
+ fd_set writeset;
+ FD_ZERO(&writeset);
+ fd_set exceptset;
+ FD_ZERO(&exceptset);
+
+#define SELECT_CHECK_SET(in_set, out_set, evt_var) \
+ if ((in_set) != NULL) \
+ { \
+ if (FD_ISSET(sock, (in_set)) && (evt_var) > 0) \
+ { \
+ FD_SET(sock, (out_set)); \
+ num_ready++; \
+ } \
+ else \
+ { \
+ FD_CLR(sock, (out_set)); \
+ } \
+ }
+
+ int num_ready = 0;
+ uint32_t err_code = NRF_SUCCESS;
+ while (err_code == NRF_SUCCESS)
+ {
+ for (int sock = 0; sock < nfds; sock++)
+ {
+ socket_t * p_socket = socket_find(sock);
+ SELECT_CHECK_SET(p_readset, &readset, p_socket->so_read_evt);
+ SELECT_CHECK_SET(p_writeset, &writeset, p_socket->so_write_evt);
+ SELECT_CHECK_SET(p_exceptset, &exceptset, p_socket->so_except_evt);
+ }
+ // TODO: Check out how app events queue up while we checked the socket
+ if (fd_set_cmp(p_readset, &readset) == 0 &&
+ fd_set_cmp(p_writeset, &writeset) == 0 &&
+ fd_set_cmp(p_exceptset, &exceptset) == 0)
+
+ {
+ break;
+ }
+ else
+ {
+ if (p_timeout == NULL)
+ {
+ err_code = socket_wait();
+ }
+ else if (endtime - timestep < endtime)
+ {
+ (void) usleep(timestep);
+ endtime -= timestep;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ }
+
+ return num_ready;
+}
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_common.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_common.h
new file mode 100644
index 0000000..d9a0f8a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_common.h
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file socket_common.h
+ *
+ * @defgroup socket_common BSD Socket internal functions and structures
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Nordic socket interface internal functions and structures.
+ */
+#ifndef SOCKET_COMMON_H__
+#define SOCKET_COMMON_H__
+
+#include <stdint.h>
+#include "socket_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct socket_transport;
+
+#define AF_NRF_CFG_INTERNAL 41 /**< Socket family type, internal NRF configuration socket. */
+
+/**
+ * @brief Function for initializing the socket API module.
+ *
+ * @return NRF_SUCCESS on success, otherwise error code is returned.
+ */
+uint32_t socket_init(void);
+
+/**
+ * @brief Waiting function for sockets.
+ *
+ * @details Must be implemented by specific modules such as BLEs.
+ *
+ * @return NRF_SUCCESS on success, otherwise error code is returned.
+ */
+uint32_t socket_wait(void);
+
+/**
+ * @brief Create parameters for a socket.
+ */
+typedef struct {
+ socket_family_t so_family; /**< Socket family. */
+ socket_protocol_t so_protocol; /**< Socket protocol. */
+ socket_type_t so_type; /**< Socket type. */
+} socket_params_t;
+
+/**
+ * @brief Different states a socket can be in.
+ */
+typedef enum {
+ STATE_CLOSED = 0, /**< Socket is closed. */
+ STATE_OPEN, /**< Socket is opened. */
+ STATE_CONNECTED, /**< Socket is connected. */
+} socket_state_t;
+
+/**
+ * @brief The state associated with a socket handle.
+ */
+typedef struct {
+ socket_params_t so_params; /**< Generic socket parameters. */
+ void * so_ctx; /**< Transport specific context. */
+ int so_flags; /**< Socket flags. */
+ uint16_t so_read_evt; /**< Notifying of read events. */
+ uint16_t so_write_evt; /**< Notifying of write events. */
+ uint16_t so_except_evt; /**< Notifying of exceptional events. */
+ struct socket_transport * so_transport; /**< Transport attached to this socket. */
+ volatile socket_state_t so_state; /**< Socket state. */
+} socket_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SOCKET_COMMON_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_config.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_config.h
new file mode 100644
index 0000000..cce571e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_config.h
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file socket_config.h
+ *
+ * @defgroup iot_socket_config Configuration socket API
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Configuration socket API.
+ *
+ * This API is used internally by the socket handling to support the configuration
+ * socket type. The configuration socket is implemented using a special transport hook, which is
+ * implemented differently depending on the platform.
+ */
+#ifndef SOCKET_CONFIG_H__
+#define SOCKET_CONFIG_H__
+
+#include "socket_common.h"
+#include "transport_if.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Function for setting the default configuration.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t config_socket_init(void);
+
+/**
+ * @brief Function for starting the configuration layer.
+ */
+void config_socket_start(void);
+
+extern socket_transport_t config_socket_transport;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SOCKET_CONFIG_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_trace.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_trace.h
new file mode 100644
index 0000000..87fafdf
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/socket_trace.h
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file socket_trace.h
+ *
+ * @defgroup iot_socket_debug_log Module's log macros
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Socket trace macros.
+ *
+ * @details Macros for creating module logs which can be useful in understanding the handling
+ * of events or actions on API requests. These are intended for debugging purposes and
+ * can be disabled by defining the SOCKET_CONFIG_LOG_ENABLED.
+ * @note If NRF_LOG_ENABLED is disabled, SOCKET_CONFIG_LOG_ENABLED has no effect.
+ */
+#ifndef SOCKET_TRACE_H__
+#define SOCKET_TRACE_H__
+
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if SOCKET_CONFIG_LOG_ENABLED == 1
+#if defined (NRF_LOG_ENABLED) && (NRF_LOG_ENABLED == 1)
+
+#define NRF_LOG_MODULE_NAME socket
+
+#define NRF_LOG_LEVEL SOCKET_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR SOCKET_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR SOCKET_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+#define SOCKET_TRACE NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define SOCKET_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define SOCKET_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#else
+
+#define SOCKET_TRACE(...) \
+ do { \
+ (void) fprintf( stderr, "socket: " ); \
+ (void) fprintf( stderr, __VA_ARGS__ ); \
+ (void) fprintf( stderr, "\r\n" ); \
+ } while (0)
+
+#endif
+
+#else // SOCKET_CONFIG_LOG_ENABLED
+
+#define SOCKET_TRACE(...) /**< Disables traces. */
+#define SOCKET_ERR(...) /**< Disables error logs. */
+#define SOCKET_DUMP(...) /**< Disables dumping of octet streams. */
+
+#endif // SOCKET_CONFIG_LOG_ENABLED
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SOCKET_TRACE_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/transport_if.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/transport_if.h
new file mode 100644
index 0000000..75a86c1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/common/transport_if.h
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file transport_if.h
+ *
+ * @defgroup iot_socket_transport_if Transport implementation interface
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Transport implementation interface.
+ *
+ * The transport interface defines the hook to be used for socket transport. The implementation of
+ * this interface would be different across platforms and event IP stacks (i.e. Nordic IPv6 vs LwIP).
+ */
+#ifndef TRANSPORT_IF_H__
+#define TRANSPORT_IF_H__
+
+#include "iot_defines.h"
+#include "socket_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Function for opening a socket.
+ */
+typedef uint32_t (*tr_open_t) (socket_t * p_socket);
+
+/**
+ * @brief Function for connecting a socket to an address.
+ */
+typedef uint32_t (*tr_connect_t)(socket_t * p_socket, const void * p_addr, socklen_t addrlen);
+
+/**
+ * @brief Function for sending data on a socket.
+ */
+typedef uint32_t (*tr_send_t)(socket_t * p_socket,
+ const void * p_buf,
+ uint32_t len,
+ int flags,
+ const void * p_destaddr,
+ socklen_t destaddr_len);
+
+/**
+ * @brief Function for receiving data from a socket.
+ */
+typedef uint32_t (*tr_recv_t)(socket_t * p_socket,
+ void * p_buf,
+ uint32_t * sz,
+ int flags,
+ void * p_srcaddr,
+ socklen_t * p_srcaddr_len);
+
+/**
+ * @brief Function for binding a socket to an address and port.
+ */
+typedef uint32_t (*tr_bind_t)(socket_t * p_socket, const void * p_addr, socklen_t addrlen);
+
+/**
+ * @brief Function for listening on a socket.
+ */
+typedef uint32_t (*tr_listen_t)(socket_t * p_socket, int backlog);
+
+/**
+ * @brief Function for accepting a connection on a socket.
+ */
+typedef uint32_t (*tr_accept_t)(socket_t * p_socket,
+ socket_t * p_client,
+ void * p_client_addr,
+ socklen_t * p_client_addr_len);
+
+/**
+ * @brief Function for closing a socket.
+ */
+typedef uint32_t (*tr_close_t)(socket_t * p_socket);
+
+/**
+ * @brief Function for setting options on a socket.
+ */
+typedef uint32_t (*tr_setsockopt_t)(socket_t * p_socket,
+ int level,
+ int optname,
+ const void * p_optval,
+ socklen_t optlen);
+
+/**
+ * @brief Function for getting options from a socket.
+ */
+typedef uint32_t (*tr_getsockopt_t)(socket_t * p_socket,
+ int level,
+ int optname,
+ void * p_optval,
+ socklen_t * p_optlen);
+
+/**
+ * @brief The transport interface.
+ */
+typedef struct socket_transport
+{
+ tr_open_t open; /**< Open a socket. */
+ tr_connect_t connect; /**< Connect a socket to an address. */
+ tr_send_t send; /**< Send data on a socket. */
+ tr_recv_t recv; /**< Receive data from a socket. */
+ tr_bind_t bind; /**< Bind a socket to an address and port. */
+ tr_listen_t listen; /**< Listen on a socket. */
+ tr_accept_t accept; /**< Accept connection on a socket. */
+ tr_close_t close; /**< Close a socket. */
+ tr_setsockopt_t setsockopt; /**< Set options on a socket. */
+ tr_getsockopt_t getsockopt; /**< Get options from a socket. */
+} socket_transport_t;
+
+#if SOCKET_TRANSPORT_ENABLE == 1
+extern socket_transport_t transport_impl;
+void transport_handler_init(void);
+void transport_interface_up(void);
+void transport_interface_down(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TRANSPORT_IF_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.c
new file mode 100644
index 0000000..6b883dd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.c
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2016 - 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 "sdk_config.h"
+#include "socket_api.h"
+#include "config_medium.h"
+#include "ipv6_medium.h"
+#include "iot_errors.h"
+#include "app_error.h"
+#include "socket_config.h"
+
+static ipv6_medium_instance_t m_ipv6_medium; /**< IPv6 medium instance. */
+eui64_t eui64_local_iid; /**< Local EUI64 value that is used as the IID for*/
+
+eui64_t * config_medium_local_iid(void)
+{
+ return &eui64_local_iid;
+}
+
+void config_medium_start(void)
+{
+ uint32_t err_code = ipv6_medium_connectable_mode_enter(m_ipv6_medium.ipv6_medium_instance_id);
+ APP_ERROR_CHECK(err_code);
+}
+
+static void on_ipv6_medium_evt(ipv6_medium_evt_t * p_ipv6_medium_evt)
+{
+ switch (p_ipv6_medium_evt->ipv6_medium_evt_id)
+ {
+ case IPV6_MEDIUM_EVT_CONN_UP:
+ {
+ // TODO: Signal
+ break;
+ }
+ case IPV6_MEDIUM_EVT_CONN_DOWN:
+ {
+ config_medium_start();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+
+static void on_ipv6_medium_error(ipv6_medium_error_t * p_ipv6_medium_error)
+{
+ // Do something.
+}
+
+static uint32_t config_medium_init(ipv6_medium_init_params_t * p_medium_params,
+ ipv6_medium_type_t medium_type)
+{
+ uint32_t err_code = ipv6_medium_init(p_medium_params, medium_type, &m_ipv6_medium);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ eui48_t ipv6_medium_eui48;
+ err_code = ipv6_medium_eui48_get(m_ipv6_medium.ipv6_medium_instance_id, &ipv6_medium_eui48);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ ipv6_medium_eui48.identifier[EUI_48_SIZE - 1] = 0x00;
+
+ err_code = ipv6_medium_eui48_set(m_ipv6_medium.ipv6_medium_instance_id, &ipv6_medium_eui48);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = ipv6_medium_eui64_get(m_ipv6_medium.ipv6_medium_instance_id, &eui64_local_iid);
+ return err_code;
+}
+
+uint32_t config_medium_init_default(void)
+{
+ static ipv6_medium_init_params_t ipv6_medium_init_params;
+ memset(&ipv6_medium_init_params, 0x00, sizeof(ipv6_medium_init_params));
+ ipv6_medium_init_params.ipv6_medium_evt_handler = on_ipv6_medium_evt;
+ ipv6_medium_init_params.ipv6_medium_error_handler = on_ipv6_medium_error;
+ return config_medium_init(&ipv6_medium_init_params, IPV6_MEDIUM_ID_BLE);
+}
+
+uint32_t config_medium_setopt(int optname, const void * p_optarg, socklen_t optlen)
+{
+ uint32_t err_code = SOCKET_INVALID_PARAM;
+ if (optname == MEDIUM_INIT_PARAMS)
+ {
+ if (optlen == sizeof(config_medium_params_t))
+ {
+ const config_medium_params_t * p_cfg = (const config_medium_params_t *)p_optarg;
+ ipv6_medium_init_params_t ipv6_medium_init_params;
+ memset(&ipv6_medium_init_params, 0x00, sizeof(ipv6_medium_init_params));
+ ipv6_medium_init_params.ipv6_medium_evt_handler = p_cfg->evt_handler;
+ ipv6_medium_init_params.ipv6_medium_error_handler = p_cfg->error_handler;
+ err_code = config_medium_init(&ipv6_medium_init_params, p_cfg->medium_type);
+ }
+ }
+ return err_code;
+}
+
+uint32_t config_medium_getopt(int optname, void * p_optarg, socklen_t * p_optlen)
+{
+ (void) optname;
+ (void) p_optarg;
+ (void) p_optlen;
+ return SOCKET_INVALID_PARAM;
+}
+
+uint32_t config_socket_init(void)
+{
+ uint32_t err_code = NRF_SUCCESS;
+#if SOCKET_AUTOINIT_ENABLE == 1
+ err_code = config_medium_init_default();
+#endif
+ return err_code;
+}
+
+void config_socket_start(void)
+{
+#if SOCKET_AUTOINIT_ENABLE == 1
+ config_medium_start();
+#endif
+}
+
+static uint32_t config_socket_open(socket_t * p_socket)
+{
+ (void) p_socket;
+ return NRF_ERROR_NULL;
+}
+
+static uint32_t config_socket_close(socket_t * p_socket)
+{
+ (void) p_socket;
+ return NRF_ERROR_NULL;
+}
+
+uint32_t config_socket_setopt(socket_t * p_socket,
+ int level,
+ int optname,
+ const void * p_optarg,
+ socklen_t optlen)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ switch (level)
+ {
+ case SOL_NRF_MEDIUM:
+ err_code = config_medium_setopt(optname, p_optarg, optlen);
+ break;
+ default:
+ err_code = SOCKET_INVALID_PARAM;
+ break;
+ }
+ return err_code;
+}
+
+uint32_t config_socket_getopt(socket_t * p_socket,
+ int level,
+ int optname,
+ void * p_optarg,
+ socklen_t * p_optlen)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ switch (level)
+ {
+ case SOL_NRF_MEDIUM:
+ err_code = config_medium_getopt(optname, p_optarg, p_optlen);
+ break;
+ default:
+ err_code = SOCKET_INVALID_PARAM;
+ break;
+ }
+ return err_code;
+}
+
+/**
+ * @brief Transport for configuration socket.
+ */
+socket_transport_t config_socket_transport =
+{
+ .open = config_socket_open,
+ .setsockopt = config_socket_setopt,
+ .getsockopt = config_socket_getopt,
+ .close = config_socket_close
+};
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.h
new file mode 100644
index 0000000..e4b7c01
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/config/medium/config_medium.h
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+/**@file config_medium.h
+ *
+ * @defgroup iot_socket_config_medium Configuration socket based on ipv6_medium
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Configuration socket based on the ipv6_medium module.
+ *
+ * This module wraps the medium module in a configuration socket API.
+ */
+#ifndef CONFIG_MEDIUM_H__
+#define CONFIG_MEDIUM_H__
+
+#include <stdint.h>
+#include "iot_defines.h"
+#include "ipv6_medium.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Function for initializing a configuration socket with default settings.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t config_medium_init_default(void);
+
+/**
+ * @brief Function for starting the medium layer.
+ *
+ * For BLE, this means to start advertising.
+ */
+void config_medium_start(void);
+
+/**
+ * @brief Function for retrieving local interface ID assigned.
+ *
+ * @return Pointer to location of interface ID.
+ */
+eui64_t * config_medium_local_iid(void);
+
+/**
+ * @brief Function for setting configuration parameters for the medium layers using the socket option.
+ *
+ * @param optname Option name/type.
+ * @param p_optarg Pointer to option value.
+ * @param optlen Length of option value.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t config_medium_setopt(int optname, const void * p_optarg, socklen_t optlen);
+
+/**
+ * @brief Function for getting configuration parameters for the medium layers using the socket option.
+ *
+ * @param optname Option name/type.
+ * @param p_optarg Pointer to the option value structure where the value should be stored.
+ * @param p_optlen Length of option value.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t config_medium_getopt(int optname, void * p_optarg, socklen_t * p_optlen);
+
+/**
+ * @brief Parameters passed for the MEDIUM_INIT_PARAMS option.
+ *
+ * These are currently the same as for ipv6_medium initialization.
+ */
+typedef struct {
+ ipv6_medium_evt_handler_t evt_handler; /**< The medium event handler callback. */
+ ipv6_medium_error_handler_t error_handler; /**< The medium error handler callback. */
+ ipv6_medium_type_t medium_type; /**< The medium type. */
+} config_medium_params_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CONFIG_MEDIUM_H__
+
+/**@} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/addr_util/inet_pton.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/addr_util/inet_pton.c
new file mode 100644
index 0000000..2fd1f4c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/addr_util/inet_pton.c
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2015 - 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 "socket_api.h"
+#include "ipv6_parse.h"
+
+int inet_pton(socket_family_t af, const char * p_src, void * p_dst)
+{
+ int ret_val = 1;
+ if (af != AF_INET6)
+ {
+ ret_val = -1;
+ }
+ else
+ {
+ in6_addr_t * p_addr = (in6_addr_t *)p_dst;
+ uint32_t err_code = ipv6_parse_addr(p_addr->s6_addr, p_src, strlen(p_src));
+ if (err_code != NRF_SUCCESS)
+ {
+ ret_val = 0;
+ }
+ }
+ return ret_val;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.c
new file mode 100644
index 0000000..1458b01
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.c
@@ -0,0 +1,176 @@
+/**
+ * Copyright (c) 2015 - 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 "iot_defines.h"
+#include "iot_errors.h"
+#include "nrf_fifo.h"
+#include "mem_manager.h"
+#include "nrf.h"
+
+static __INLINE uint32_t fifo_inc(nrf_fifo_t * p_fifo, uint32_t pos)
+{
+ return (pos + 1) % p_fifo->nmemb;
+}
+
+static __INLINE bool fifo_full(nrf_fifo_t * p_fifo)
+{
+ return fifo_inc(p_fifo, p_fifo->write_pos) == p_fifo->read_pos;
+}
+
+static __INLINE bool fifo_empty(nrf_fifo_t * p_fifo)
+{
+ return p_fifo->read_pos == p_fifo->write_pos;
+}
+
+static __INLINE void fifo_enq(nrf_fifo_t * p_fifo, void * p_ctx)
+{
+ p_fifo->pp_elements[p_fifo->write_pos] = p_ctx;
+ __DSB();
+ p_fifo->write_pos = fifo_inc(p_fifo, p_fifo->write_pos);
+}
+
+
+static __INLINE void fifo_deq(nrf_fifo_t * p_fifo, void ** pp_ctx)
+{
+ *pp_ctx = p_fifo->pp_elements[p_fifo->read_pos];
+ __DSB();
+ p_fifo->read_pos = fifo_inc(p_fifo, p_fifo->read_pos);
+}
+
+uint32_t nrf_fifo_init(nrf_fifo_t * p_fifo, uint32_t nmemb, fifo_wait_fn wait_fn, fifo_flush_fn flush_fn)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ uint32_t nmemb_actual = nmemb + 1; // Required to allow detection of empty and full state
+ p_fifo->pp_elements = nrf_malloc(nmemb_actual * sizeof(void *));
+
+ if (p_fifo->pp_elements == NULL)
+ {
+ err_code = NRF_ERROR_NO_MEM;
+ }
+ else
+ {
+ p_fifo->nmemb = nmemb_actual;
+ p_fifo->wait = wait_fn;
+ p_fifo->flush = flush_fn;
+ p_fifo->read_pos = 0;
+ p_fifo->write_pos = 0;
+ }
+ return err_code;
+}
+
+void nrf_fifo_deinit(nrf_fifo_t * p_fifo)
+{
+ if (p_fifo->flush != NULL)
+ {
+ void * p_data;
+ uint32_t err_code = nrf_fifo_deq(p_fifo, &p_data, false);
+ while (err_code == NRF_SUCCESS)
+ {
+ p_fifo->flush(p_data);
+ err_code = nrf_fifo_deq(p_fifo, &p_data, false);
+ }
+ }
+ nrf_free(p_fifo->pp_elements);
+ p_fifo->nmemb = 0;
+ p_fifo->read_pos = 0;
+ p_fifo->write_pos = 0;
+ p_fifo->wait = NULL;
+ p_fifo->flush = NULL;
+}
+
+uint32_t nrf_fifo_enq(nrf_fifo_t * p_fifo, void * p_ctx, bool wait)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (fifo_full(p_fifo) == true)
+ {
+ if (wait == false || p_fifo->wait == NULL)
+ {
+ err_code = SOCKET_WOULD_BLOCK;
+ }
+ else
+ {
+ while (fifo_full(p_fifo) == true && err_code == NRF_SUCCESS)
+ {
+ err_code = p_fifo->wait();
+ }
+ }
+ }
+ else
+ {
+ fifo_enq(p_fifo, p_ctx);
+ }
+ return err_code;
+}
+
+uint32_t nrf_fifo_deq(nrf_fifo_t * p_fifo, void ** pp_ctx, bool wait)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (fifo_empty(p_fifo) == true)
+ {
+ if (wait == false || p_fifo->wait == NULL)
+ {
+ err_code = SOCKET_WOULD_BLOCK;
+ }
+ else
+ {
+ while (fifo_empty(p_fifo) == true && err_code == NRF_SUCCESS)
+ {
+ err_code = p_fifo->wait();
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ fifo_deq(p_fifo, pp_ctx);
+ }
+ return err_code;
+}
+
+bool nrf_fifo_empty(nrf_fifo_t * p_fifo)
+{
+ return fifo_empty(p_fifo);
+}
+
+bool nrf_fifo_full(nrf_fifo_t * p_fifo)
+{
+ return fifo_full(p_fifo);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.h
new file mode 100644
index 0000000..c6fb378
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/fifo/nrf_fifo.h
@@ -0,0 +1,170 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+#ifndef NRF_FIFO_H__
+#define NRF_FIFO_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file nrf_fifo.h
+ *
+ * @defgroup iot_socket_fifo FIFO
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief A wait-free bounded FIFO of pointers for single producer/single consumer use.
+ *
+ * This FIFO is safe to use in single producer/single consumer patterns. In addition, the following
+ * restrictions apply for init/deinit:
+ *
+ * a) nrf_fifo_enq() and nrf_fifo_deq() may only be called after nrf_fifo_init() is called.
+ *
+ * b) All calls to nrf_fifo_enq() and nrf_fifo_deq() must be finished and no new calls must be made before nrf_fifo_deinit() is called.
+ *
+ * These restrictions must be handled by the user of the module, for instance by using a mutex.
+ */
+
+/**
+ * @brief Wait function for blocking enqueue/dequeue.
+ *
+ * Should return NRF_SUCCESS as long as there are no errors while waiting.
+ */
+typedef uint32_t (*fifo_wait_fn)(void);
+
+/**
+ * @brief Flush function called on deinit.
+ *
+ * On deinit, this function will be called with each remaining element in the FIFO as argument. This
+ * can be used to ensure that memory is deallocated properly.
+ *
+ * @param[in] p_data Pointer to data that is flushed from FIFO.
+ */
+typedef void (*fifo_flush_fn)(void * p_data);
+
+/**
+ * @brief FIFO data structure.
+ */
+typedef struct {
+ void ** pp_elements; /**< The array of elements in the FIFO. */
+ uint32_t nmemb; /**< The number of elements in this FIFO. */
+ fifo_wait_fn wait; /**< The wait function used if blocking. */
+ fifo_flush_fn flush; /**< The flush function used on deinit. */
+ volatile uint32_t read_pos; /**< Read pointer to next element to read. */
+ volatile uint32_t write_pos; /**< Write pointer to next element to write. */
+} nrf_fifo_t;
+
+/**
+ * @brief Function for initializing the FIFO.
+ *
+ * @param[out] p_fifo The FIFO to initialize.
+ * @param[in] nmemb The maximum number of elements in the FIFO.
+ * @param[in] wait_fn The wait function to use for blocking enqueue/dequeue. If NULL, the enq/deq
+ * functions will never block.
+ * @param[in] flush_fn The flush function to call on deinit. If NULL, the flush function will not
+ * be called.
+ *
+ * @retval NRF_SUCCESS if fifo was initialized successfully.
+ */
+uint32_t nrf_fifo_init(nrf_fifo_t * p_fifo, uint32_t nmemb, fifo_wait_fn wait_fn, fifo_flush_fn flush_fn);
+
+/**
+ * @brief Function for deinitializing the FIFO.
+ *
+ * Frees all memory allocated by this FIFO. All elements are removed. If a flush function was
+ * specified in nrf_fifo_init(), the function will be called for each remaining element in the
+ * FIFO.
+ *
+ * @param[in, out] p_fifo The FIFO to deinitialize.
+ */
+void nrf_fifo_deinit(nrf_fifo_t * p_fifo);
+
+/**
+ * @brief Function for enqueuing an element on the FIFO.
+ *
+ * @param[in, out] p_fifo The FIFO to enqueue elements on.
+ * @param[in] p_ctx The pointer to enqueue.
+ * @param[in] wait If true, this function will block until the FIFO has available space. Any
+ * errors returned by this function will be propagated to the caller.
+ *
+ * @retval NRF_SUCCESS if the element was queued.
+ * @retval NRF_ERROR_NO_MEM if wait was set to false and no space was available.
+ */
+uint32_t nrf_fifo_enq(nrf_fifo_t * p_fifo, void * p_ctx, bool wait);
+
+/**
+ * @brief Function for dequeuing an element from the FIFO.
+ *
+ * @param[in, out] p_fifo The FIFO to dequeue elements from.
+ * @param[out] pp_ctx Pointer to where the dequeued element should be stored.
+ * @param[in] wait If true, this function will block until the FIFO has elements for dequeuing.
+ * Any errors returned by this function will be propagated to the caller.
+ *
+ * @retval NRF_SUCCESS if the element was queued.
+ * @retval NRF_ERROR_NO_MEM if wait was set to false and no space was available.
+ */
+uint32_t nrf_fifo_deq(nrf_fifo_t * p_fifo, void ** pp_ctx, bool wait);
+
+/**
+ * @brief Function for checking if the FIFO is empty.
+ *
+ * @param[in] p_fifo The FIFO to check.
+ * @return true if empty, false if not.
+ */
+bool nrf_fifo_empty(nrf_fifo_t * p_fifo);
+
+/**
+ * @brief Function for checking if the FIFO is full.
+ *
+ * @param[in] p_fifo The FIFO to check.
+ * @return true if full, false if not.
+ */
+bool nrf_fifo_full(nrf_fifo_t * p_fifo);
+
+/**@} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_FIFO_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.c
new file mode 100644
index 0000000..d4b0c79
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.c
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2015 - 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 "iot_defines.h"
+#include "iot_errors.h"
+#include "sdk_config.h"
+#include "mem_manager.h"
+#include "mbuf.h"
+#include "nrf_fifo.h"
+#include "socket_common.h"
+
+uint32_t mbuf_init(mbuf_t * p_mbuf,
+ mbuf_read_fn read_fn,
+ mbuf_buf_len_fn buf_len_fn,
+ mbuf_free_fn free_fn,
+ uint32_t nmemb)
+{
+ p_mbuf->p_current = NULL;
+ p_mbuf->read_pos = 0;
+ p_mbuf->read = read_fn;
+ p_mbuf->buf_len = buf_len_fn;
+ p_mbuf->free = free_fn;
+ return nrf_fifo_init(&p_mbuf->fifo, nmemb, socket_wait, free_fn);
+}
+
+void mbuf_deinit(mbuf_t * p_mbuf)
+{
+ if (p_mbuf->p_current != NULL)
+ {
+ p_mbuf->free(p_mbuf->p_current);
+ p_mbuf->p_current = NULL;
+ }
+
+ p_mbuf->read_pos = 0;
+ p_mbuf->read = NULL;
+ p_mbuf->buf_len = NULL;
+ p_mbuf->free = NULL;
+ nrf_fifo_deinit(&p_mbuf->fifo);
+}
+
+static bool mbuf_empty_current(mbuf_t * p_mbuf)
+{
+ return (p_mbuf->buf_len(p_mbuf->p_current) == p_mbuf->read_pos);
+}
+
+bool mbuf_empty(mbuf_t * p_mbuf)
+{
+ return ((p_mbuf->p_current == NULL || mbuf_empty_current(p_mbuf)) &&
+ nrf_fifo_empty(&p_mbuf->fifo));
+}
+
+uint32_t mbuf_write(mbuf_t * p_mbuf, void * p_ctx)
+{
+ return nrf_fifo_enq(&p_mbuf->fifo, p_ctx, false);
+}
+
+static void mbuf_load(mbuf_t * p_mbuf)
+{
+ if (p_mbuf->p_current == NULL)
+ {
+ (void)nrf_fifo_deq(&p_mbuf->fifo, &p_mbuf->p_current, false);
+ }
+}
+
+uint32_t mbuf_read(mbuf_t * p_mbuf, void * p_buf, uint32_t buf_size)
+{
+ uint32_t nbytes = 0;
+ while (nbytes < buf_size && mbuf_empty(p_mbuf) == false)
+ {
+ mbuf_load(p_mbuf);
+ void * p_current = p_mbuf->p_current;
+ const uint32_t copy_len = p_mbuf->read(p_current,
+ p_mbuf->read_pos,
+ ((uint8_t *)p_buf) + nbytes,
+ buf_size - nbytes);
+ p_mbuf->read_pos += copy_len;
+ nbytes += copy_len;
+ if (mbuf_empty_current(p_mbuf) == true)
+ {
+ p_mbuf->free(p_mbuf->p_current);
+ p_mbuf->p_current = NULL;
+ p_mbuf->read_pos = 0;
+ }
+ }
+ return nbytes;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.h
new file mode 100644
index 0000000..884c650
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/mbuf/mbuf.h
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2015 - 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.
+ *
+ */
+#ifndef MBUF_H__
+#define MBUF_H__
+
+/**
+ * @file mbuf.h
+ *
+ * @defgroup iot_socket_mbuf Memory management for socket
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Memory management for socket.
+ */
+
+#include <stdbool.h>
+#include "nrf_fifo.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Function for reading data from a buffer. */
+typedef uint32_t (*mbuf_read_fn)(void * p_ctx,
+ uint32_t read_offset,
+ uint8_t * p_dest,
+ uint32_t dest_len);
+
+/**@brief Function for checking buffer length. */
+typedef uint32_t (*mbuf_buf_len_fn)(void * p_ctx);
+
+/**@brief Function for freeing a buffer. */
+typedef void (*mbuf_free_fn)(void * p_ctx);
+
+/**@brief Memory management structure. */
+typedef struct
+{
+ nrf_fifo_t fifo; /**< FIFO for storing data buffers. */
+ mbuf_read_fn read; /**< Function for reading data from a buffer. */
+ mbuf_buf_len_fn buf_len; /**< Function for checking buffer length. */
+ mbuf_free_fn free; /**< Function for freeing a buffer. */
+ uint32_t read_pos; /**< Read position in the currently processed buffer. */
+ void * p_current; /**< Pointer to the currently processed buffer. */
+} mbuf_t;
+
+/**
+ * @brief Function for initializing the memory buffer manager.
+ *
+ * This function allocates resources for the mbuf FIFO and initializes the mbuf.
+ *
+ * @param[in, out] p_mbuf Pointer to the mbuf structure to initialize.
+ * @param[in] read_fn Function for reading data from a buffer.
+ * @param[in] buf_len_fn Function for checking buffer length.
+ * @param[in] free_fn Function for freeing a buffer.
+ * @param[in] nmemb Maximum number of data buffers.
+ *
+ * @return NRF_SUCCESS on success, otherwise error code is returned.
+ */
+uint32_t mbuf_init(mbuf_t * p_mbuf,
+ mbuf_read_fn read_fn,
+ mbuf_buf_len_fn buf_len_fn,
+ mbuf_free_fn free_fn,
+ uint32_t nmemb);
+
+/**
+ * @brief Function for deinitializing the memory buffer manager.
+ *
+ * This function releases any resources allocated for mbuf instance pointed by p_mbuf.
+ *
+ * @param[in, out] p_mbuf Pointer to the mbuf structure to deinitialize.
+ */
+void mbuf_deinit(mbuf_t * p_mbuf);
+
+/**
+ * @brief Function for putting a data buffer in the mbuf.
+ *
+ * @param[in, out] p_mbuf Pointer to the mbuf structure that shall store the buffer.
+ * @param[in] p_ctx Pointer to the data buffer to store.
+ *
+ * @return NRF_SUCCESS on success, otherwise error code is returned.
+ */
+uint32_t mbuf_write(mbuf_t * p_mbuf, void * p_ctx);
+
+/**
+ * @brief Function for reading data from the mbuf.
+ *
+ * @param[in, out] p_mbuf Pointer to the mbuf structure to read data from.
+ * @param[in] p_buf Pointer to the buffer where data shall be read from.
+ * @param[out] buf_size Size of the buffer pointed by p_buf.
+ *
+ * @return NRF_SUCCESS on success, otherwise error code is returned.
+ */
+uint32_t mbuf_read(mbuf_t * p_mbuf, void * p_buf, uint32_t buf_size);
+
+/**
+ * @brief Function for checking if the mbuf is empty.
+ *
+ * @param[in] p_mbuf Pointer to the mbuf structure that shall be checked.
+ *
+ * @return True if mbuf is empty, false otherwise.
+ */
+bool mbuf_empty(mbuf_t * p_mbuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@} */
+
+#endif // MBUF_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.c
new file mode 100644
index 0000000..7bfbcc4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.c
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2016 - 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 "portdb.h"
+#include <string.h>
+#include "iot_common.h"
+#include "iot_errors.h"
+#include "mem_manager.h"
+#include "nrf_error.h"
+
+#define IANA_EPHEMRAL_BEGIN 49152u /**< Minimum port number of the ephemeral port range. */
+#define IANA_EPHEMRAL_END 65535u /**< Maximum port number of the ephemeral port range. */
+
+static uint16_t * m_portdb; /**< A pointer to the port database. */
+static uint32_t m_portdb_len; /**< Length of the port database. */
+
+
+
+static __INLINE uint32_t db_size_get(void)
+{
+ return m_portdb_len * sizeof(uint16_t);
+}
+
+
+static __INLINE void db_reset(void)
+{
+ memset(&m_portdb[0], 0, db_size_get());
+}
+
+
+uint32_t portdb_init(uint32_t max_ports)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ m_portdb_len = max_ports;
+ m_portdb = nrf_malloc(db_size_get());
+ if (m_portdb == NULL)
+ {
+ err_code = NRF_ERROR_NO_MEM;
+ }
+ else
+ {
+ db_reset();
+ }
+ return err_code;
+}
+
+
+void portdb_deinit(void)
+{
+ nrf_free(m_portdb);
+ m_portdb = NULL;
+ m_portdb_len = 0;
+}
+
+
+void portdb_reset(void)
+{
+ db_reset();
+}
+
+
+static inline uint32_t check_port_in_use(uint16_t port)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ for (uint32_t i = 0; i < m_portdb_len; i++)
+ {
+ if (m_portdb[i] == port)
+ {
+ err_code = SOCKET_PORT_IN_USE;
+ break;
+ }
+ }
+ return err_code;
+}
+
+static inline uint32_t find_free_index(uint32_t * p_idx)
+{
+ uint32_t err_code = SOCKET_NO_AVAILABLE_PORTS;
+
+ for (uint32_t i = 0; i < m_portdb_len; i++)
+ {
+ if (m_portdb[i] == 0)
+ {
+ *p_idx = i;
+ err_code = NRF_SUCCESS;
+ break;
+ }
+ }
+ return err_code;
+}
+
+static uint32_t portdb_find_available_index(uint32_t * p_idx, uint16_t port)
+{
+ uint32_t err_code = SOCKET_NO_AVAILABLE_PORTS;
+
+ err_code = check_port_in_use(port);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = find_free_index(p_idx);
+ }
+ return err_code;
+}
+
+uint32_t portdb_register(uint16_t port)
+{
+ uint32_t idx = 0;
+ uint32_t err_code = portdb_find_available_index(&idx, port);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_portdb[idx] = port;
+ }
+ return err_code;
+}
+
+uint32_t portdb_alloc(uint16_t * p_port)
+{
+ uint32_t err_code = SOCKET_NO_AVAILABLE_PORTS;
+ for (uint32_t i = IANA_EPHEMRAL_BEGIN; i <= IANA_EPHEMRAL_END; i++)
+ {
+ uint16_t port = (uint16_t)i;
+ err_code = portdb_register(port);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ *p_port = port;
+ break;
+ }
+ else if (err_code == SOCKET_NO_AVAILABLE_PORTS)
+ {
+ break;
+ }
+ }
+ return err_code;
+}
+
+void portdb_free(uint16_t port)
+{
+ for (uint32_t i = 0; i < m_portdb_len; i++)
+ {
+ if (m_portdb[i] == port)
+ {
+ m_portdb[i] = 0;
+ break;
+ }
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.h
new file mode 100644
index 0000000..94f0d38
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/libraries/portdb/portdb.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2016 - 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.
+ *
+ */
+#ifndef PORTDB_H__
+#define PORTDB_H__
+
+/**
+ * @file portdb.h
+ *
+ * @defgroup iot_socket_portdb Port Database
+ * @ingroup iot_sdk_socket
+ * @{
+ * @brief Port database for sockets.
+ *
+ * The port database provides a functionality for registering, allocating, and freeing ports.
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Function for initializing the port database.
+ *
+ * This must be called before allocating and freeing ports.
+ *
+ * @param max_len The max length of the portdb.
+ *
+ * @retval NRF_SUCCESS If successfully initialized.
+ */
+uint32_t portdb_init(uint32_t max_len);
+
+/**
+ * @brief Function for deinitializing the portdb.
+ *
+ * This will free all memory allocated by this portdb.
+ */
+void portdb_deinit(void);
+
+/**
+ * @brief Function to reset all ports without freeing any memories.
+ */
+void portdb_reset(void);
+
+/**
+ * @brief Function for allocating a port.
+ *
+ * Looks for an available port in the database and allocates it to the caller.
+ *
+ * @param[out] p_port Pointer to a variable where the allocated port number should be stored.
+ *
+ * @retval NRF_SUCCESS If a free port was located and successfully allocated.
+ * @retval SOCKET_NO_AVAILABLE_PORTS If no available ports were found.
+ */
+uint32_t portdb_alloc(uint16_t * p_port);
+
+/**
+ * @brief Function for registering a port.
+ *
+ * Marks a given port in the database as being in use.
+ *
+ * @param[in] port The port to mark as in use.
+ *
+ * @retval NRF_SUCCESS If port was successfully marked as in use.
+ * @retval SOCKET_NO_AVAILABLE_PORTS If there was no slot in which to register the port.
+ * @retval SOCKET_PORT_IN_USE If the port has already been registered or allocated.
+ */
+uint32_t portdb_register(uint16_t port);
+
+/**
+ * @brief Function for freeing a port.
+ *
+ * Mark a given port as free and make it available for others to register or allocate.
+ *
+ * @param[in] port The port to mark as free.
+ */
+void portdb_free(uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@} */
+
+#endif // PORTDB_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/platform/ble/socket_ble.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/platform/ble/socket_ble.c
new file mode 100644
index 0000000..da2cc7b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/platform/ble/socket_ble.c
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2016 - 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 <stdint.h>
+#include "nrf_soc.h"
+#include "app_scheduler.h"
+
+uint32_t socket_wait(void)
+{
+ // Execute event schedule.
+ app_sched_execute();
+
+ return sd_app_evt_wait();
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/ipv6/transport_handler.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/ipv6/transport_handler.c
new file mode 100644
index 0000000..a9d6edd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/ipv6/transport_handler.c
@@ -0,0 +1,387 @@
+/**
+ * Copyright (c) 2015 - 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 "iot_defines.h"
+#include "iot_errors.h"
+#include "sdk_config.h"
+#include "socket_trace.h"
+#include "socket_common.h"
+#include "socket_config.h"
+#include "config_medium.h"
+#include "transport_if.h"
+#include "udp_api.h"
+#include "portdb.h"
+#include "nrf_soc.h"
+#include "nrf_fifo.h"
+
+/**@brief Verify that IPv6 address length is correct. */
+#define VERIFY_ADDRESS_LEN(len) \
+ do { \
+ if ((len) != sizeof(sockaddr_in6_t)) { \
+ return NRF_ERROR_NULL | IOT_SOCKET_ERR_BASE; \
+ } \
+ } while (0)
+
+#define SOCKET_MAX_PENDING_PACKETS 32 /**< Maximum number of pending received packets. */
+
+/**@brief Nordic IPv6 handle structure. */
+typedef struct
+{
+ udp6_socket_t socket; /**< UDP socket. */
+ nrf_fifo_t recv_queue; /**< Received packets queue. */
+ uint16_t local_port; /**< Local port number. */
+} ipv6_handle_t;
+
+static const char * unused = "UNUSED"; /**< A pointer indicating an unused socket. */
+static ipv6_handle_t ipv6_handles[SOCKET_MAX_SOCKET_COUNT]; /**< IPv6 handle array. */
+
+void free_pbuffer(void * p_data)
+{
+ (void) iot_pbuffer_free((iot_pbuffer_t *)p_data, true);
+}
+
+static ipv6_handle_t * ipv6_handle_allocate(socket_t * p_socket)
+{
+ ipv6_handle_t * p_handle = NULL;
+ for (uint32_t i = 0; i < SOCKET_MAX_SOCKET_COUNT; i++)
+ {
+ if (ipv6_handles[i].socket.p_app_data == unused)
+ {
+ p_handle = &ipv6_handles[i];
+ p_handle->socket.p_app_data = p_socket;
+ (void) nrf_fifo_init(&p_handle->recv_queue, SOCKET_MAX_PENDING_PACKETS, socket_wait, free_pbuffer);
+ uint32_t err_code = udp6_socket_app_data_set(&p_handle->socket);
+ if (err_code != NRF_SUCCESS)
+ {
+ p_handle = NULL;
+ }
+ break;
+ }
+ }
+ return p_handle;
+}
+
+static uint32_t ipv6_handle_free(ipv6_handle_t * p_handle)
+{
+ p_handle->local_port = 0;
+ p_handle->socket.p_app_data = (void *)unused;
+ return udp6_socket_app_data_set(&p_handle->socket);
+}
+
+void transport_event_handler(iot_interface_t * p_interface, ipv6_event_t * p_event)
+{
+ (void) p_interface;
+
+ switch (p_event->event_id)
+ {
+ case IPV6_EVT_INTERFACE_ADD:
+ transport_interface_up();
+ break;
+ case IPV6_EVT_INTERFACE_DELETE:
+ transport_interface_down();
+ break;
+ case IPV6_EVT_INTERFACE_RX_DATA:
+ break;
+ default:
+ break;
+ }
+}
+
+void transport_handler_init(void)
+{
+ ipv6_init_t init_param;
+ init_param.p_eui64 = config_medium_local_iid();
+ init_param.event_handler = transport_event_handler;
+
+ uint32_t err_code = ipv6_init(&init_param);
+ (void) err_code;
+ // APP_ERROR_CHECK(err_code);
+ for (uint32_t i = 0; i< SOCKET_MAX_SOCKET_COUNT; i++)
+ {
+ ipv6_handles[i].local_port = 0;
+ ipv6_handles[i].socket.socket_id = 0;
+ ipv6_handles[i].socket.p_app_data = (void *)unused;
+ }
+}
+
+static uint32_t ipv6_transport_open(socket_t * p_socket)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ if (p_socket->so_params.so_type != SOCK_DGRAM)
+ {
+ err_code = SOCKET_UNSUPPORTED_PROTOCOL;
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ ipv6_handle_t * p_ipv6_handle = ipv6_handle_allocate(p_socket);
+ if (p_ipv6_handle == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ }
+ else
+ {
+ err_code = udp6_socket_allocate(&p_ipv6_handle->socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_socket->so_ctx = p_ipv6_handle;
+ }
+ else
+ {
+ (void) ipv6_handle_free(p_ipv6_handle);
+ }
+ }
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_close(socket_t * p_socket)
+{
+ ipv6_handle_t * p_ipv6_handle = (ipv6_handle_t *) p_socket->so_ctx;
+ if (p_ipv6_handle->local_port > 0)
+ {
+ portdb_free(p_ipv6_handle->local_port);
+ }
+
+ uint32_t err_code = udp6_socket_free(&p_ipv6_handle->socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = ipv6_handle_free(p_ipv6_handle);
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_recv_callback(const udp6_socket_t * p_udp_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 err_code = process_result;
+ socket_t * p_socket = (socket_t *)p_udp_socket->p_app_data;
+ ipv6_handle_t * p_ipv6_handle = (ipv6_handle_t *)p_socket->so_ctx;
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = nrf_fifo_enq(&p_ipv6_handle->recv_queue, p_rx_packet, false);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_socket->so_read_evt++;
+ err_code = IOT_IPV6_ERR_PENDING;
+ }
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_bind(socket_t * p_socket, const void * p_addr, socklen_t addr_len)
+{
+ VERIFY_ADDRESS_LEN(addr_len);
+ const sockaddr_in6_t * p_addr_in6 = (const sockaddr_in6_t *)p_addr;
+ ipv6_handle_t * p_ipv6_handle = (ipv6_handle_t *)p_socket->so_ctx;
+ udp6_socket_t * p_udp_socket = &p_ipv6_handle->socket;
+
+ p_ipv6_handle->local_port = HTONS(p_addr_in6->sin6_port);
+ uint32_t err_code = portdb_register(p_ipv6_handle->local_port);
+ if (err_code == NRF_SUCCESS)
+ {
+ ipv6_addr_t * p_ipv6_addr = (ipv6_addr_t *)&p_addr_in6->sin6_addr;
+ err_code = udp6_socket_bind(p_udp_socket, p_ipv6_addr, p_ipv6_handle->local_port);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = udp6_socket_recv(p_udp_socket, ipv6_transport_recv_callback);
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_bind_any(ipv6_handle_t * p_ipv6_handle)
+{
+ udp6_socket_t * p_udp_socket = &p_ipv6_handle->socket;
+ uint32_t err_code = portdb_alloc(&p_ipv6_handle->local_port);
+ if (err_code == NRF_SUCCESS)
+ {
+ SOCKET_TRACE("Binding to port %hu\r\n", p_ipv6_handle->local_port);
+ err_code = udp6_socket_bind(p_udp_socket, IPV6_ADDR_ANY, p_ipv6_handle->local_port);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = udp6_socket_recv(p_udp_socket, ipv6_transport_recv_callback);
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_connect(socket_t * p_socket, const void * p_addr, socklen_t addr_len)
+{
+ VERIFY_ADDRESS_LEN(addr_len);
+
+ ipv6_handle_t * p_ipv6_handle = (ipv6_handle_t *)p_socket->so_ctx;
+ udp6_socket_t * p_udp_socket = &p_ipv6_handle->socket;
+ const sockaddr_in6_t * p_addr_in6 = (const sockaddr_in6_t *)p_addr;
+ uint32_t err_code = NRF_SUCCESS;
+
+ // Port might already have been bound with an explicit call to bind()
+ if (p_ipv6_handle->local_port == 0)
+ {
+ err_code = ipv6_transport_bind_any(p_ipv6_handle);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // These data structures are compatible, and can therefore be cast
+ err_code = udp6_socket_connect(p_udp_socket,
+ (ipv6_addr_t *)&p_addr_in6->sin6_addr,
+ HTONS(p_addr_in6->sin6_port));
+ }
+
+ return err_code;
+}
+
+static uint32_t ipv6_transport_send(socket_t * p_socket,
+ const void * p_buf,
+ uint32_t len,
+ int flags,
+ const void * p_destaddr,
+ socklen_t destaddr_len)
+{
+ ipv6_handle_t * p_ipv6_handle = (ipv6_handle_t *)p_socket->so_ctx;
+ udp6_socket_t * p_udp_socket = &p_ipv6_handle->socket;
+ uint32_t err_code = NRF_SUCCESS;
+ iot_pbuffer_alloc_param_t pbuff_param;
+
+ // Ensure that port is bound before sending packet
+ if (p_ipv6_handle->local_port == 0)
+ {
+ err_code = ipv6_transport_bind_any(p_ipv6_handle);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
+ pbuff_param.type = UDP6_PACKET_TYPE;
+ pbuff_param.length = len;
+
+ iot_pbuffer_t * p_buffer = NULL;
+ err_code = iot_pbuffer_allocate(&pbuff_param, &p_buffer);
+ if (err_code == NRF_SUCCESS)
+ {
+ memcpy(p_buffer->p_payload, p_buf, len);
+ if (p_destaddr != NULL && destaddr_len == sizeof(sockaddr_in6_t))
+ {
+ sockaddr_in6_t * p_addr_in6 = (sockaddr_in6_t *)p_destaddr;
+ err_code = udp6_socket_sendto(p_udp_socket,
+ (ipv6_addr_t *)&p_addr_in6->sin6_addr,
+ HTONS(p_addr_in6->sin6_port),
+ p_buffer);
+ }
+ else
+ {
+ err_code = udp6_socket_send(p_udp_socket, p_buffer);
+ }
+ }
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_recv(socket_t * p_socket,
+ void * p_buf,
+ uint32_t * p_sz,
+ int flags,
+ void * p_srcaddr,
+ socklen_t * p_srcaddr_len)
+{
+ if ((p_socket->so_flags & O_NONBLOCK) != 0 &&
+ (flags & MSG_WAITALL) == 0)
+ {
+ flags |= MSG_DONTWAIT;
+ }
+
+ ipv6_handle_t * p_ipv6_handle = (ipv6_handle_t *)p_socket->so_ctx;
+ iot_pbuffer_t * p_pbuffer = NULL;
+ uint32_t err_code = nrf_fifo_deq(&p_ipv6_handle->recv_queue,
+ (void **)&p_pbuffer,
+ (flags & MSG_DONTWAIT) == 0);
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t copy_len = MIN(*p_sz, p_pbuffer->length);
+ memcpy(p_buf, p_pbuffer->p_payload, copy_len);
+ *p_sz = copy_len;
+
+ if (p_srcaddr != NULL && p_srcaddr_len != NULL)
+ {
+ const udp6_header_t * p_udp_header =
+ (udp6_header_t *)(p_pbuffer->p_payload - UDP_HEADER_SIZE);
+ const ipv6_header_t * p_ipv6_header =
+ (ipv6_header_t *)(p_pbuffer->p_payload - UDP_HEADER_SIZE - IPV6_IP_HEADER_SIZE);
+ sockaddr_in6_t * p_srcsockaddr = (sockaddr_in6_t *)p_srcaddr;
+
+ *p_srcaddr_len = sizeof(sockaddr_in6_t);
+ p_srcsockaddr->sin6_addr = *((in6_addr_t *)&p_ipv6_header->srcaddr);
+ p_srcsockaddr->sin6_port = HTONS(p_udp_header->srcport);
+ p_srcsockaddr->sin6_len = *p_srcaddr_len;
+ p_srcsockaddr->sin6_family = AF_INET6;
+ p_srcsockaddr->sin6_flowinfo = 0;
+ p_srcsockaddr->sin6_scope_id = 0;
+ }
+
+ (void) iot_pbuffer_free(p_pbuffer, true);
+ p_socket->so_read_evt = 0;
+ }
+ return err_code;
+}
+
+static uint32_t ipv6_transport_listen(socket_t * p_socket, int backlog)
+{
+ // Ignore as this does not make sense for UDP
+ (void) p_socket;
+ (void) backlog;
+ return NRF_SUCCESS;
+}
+
+/**
+ * @brief Transport for Nordic IPv6 socket.
+ */
+socket_transport_t transport_impl =
+{
+ .open = ipv6_transport_open,
+ .bind = ipv6_transport_bind,
+ .connect = ipv6_transport_connect,
+ .send = ipv6_transport_send,
+ .recv = ipv6_transport_recv,
+ .listen = ipv6_transport_listen,
+ .close = ipv6_transport_close
+};
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c
new file mode 100644
index 0000000..4537053
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c
@@ -0,0 +1,630 @@
+/**
+ * Copyright (c) 2015 - 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 "iot_defines.h"
+#include "iot_errors.h"
+#include "sdk_config.h"
+#include "socket_common.h"
+#include "socket_trace.h"
+#include "transport_if.h"
+#include "portdb.h"
+#include "app_timer.h"
+#include "mem_manager.h"
+#include "nrf_fifo.h"
+#include "mbuf.h"
+#include "app_util.h"
+#include "nrf_platform_port.h"
+#include "app_util_platform.h"
+
+#include "lwip/opt.h"
+#include "lwip/init.h"
+#include "lwip/tcp.h"
+#include "lwip/timers.h"
+
+/**@brief Verify that IPv6 address length is correct. */
+#define VERIFY_ADDRESS_LEN(len) \
+ do { \
+ if ((len) != sizeof(sockaddr_in6_t)) { \
+ return NRF_ERROR_NULL | IOT_SOCKET_ERR_BASE; \
+ } \
+ } while (0)
+
+#define LWIP_SYS_TIMER_INTERVAL APP_TIMER_TICKS(100) /**< Interval for timer used as trigger to send. */
+
+#define SOCKET_MAX_PENDING_PACKETS 32 /**< Maximum number of pending received packets. */
+#define SOCKET_MAX_PENDING_CONNECTIONS 10 /**< Maximum number of simultaneous connections. */
+
+/**@brief TCP state */
+typedef enum
+{
+ TCP_STATE_IDLE,
+ TCP_STATE_REQUEST_CONNECTION,
+ TCP_STATE_CONNECTED,
+ TCP_STATE_DATA_TX_IN_PROGRESS,
+ TCP_STATE_TCP_SEND_PENDING,
+ TCP_STATE_DISCONNECTED
+} tcp_state_t;
+
+/**@brief LwIP handle structure. */
+typedef struct {
+ struct tcp_pcb * p_pcb; /**< A pointer to LwIP TCP protocol control block. */
+ socket_t * p_socket; /**< A pointer to corresponding socket. */
+ nrf_fifo_t conn_queue; /**< Connections queue. */
+ mbuf_t mbuf; /**< Memory management queue. */
+ volatile tcp_state_t tcp_state; /**< TCP state. */
+} lwip_handle_t;
+
+static lwip_handle_t lwip_handles[SOCKET_MAX_SOCKET_COUNT]; /**< LwIP handle array. */
+
+/**@brief Timer for LwIP. */
+APP_TIMER_DEF(m_lwip_timer_id);
+
+static err_t lwip_recv_callback(void * p_arg,
+ struct tcp_pcb * p_pcb,
+ struct pbuf * p_pbuf,
+ err_t err);
+
+static uint32_t lwip_buf_read(void * p_ctx,
+ uint32_t read_offset,
+ uint8_t * p_destbuf,
+ uint32_t destbuf_len)
+{
+ struct pbuf * p_pbuf = (struct pbuf *)p_ctx;
+ uint32_t copy_len = MIN(destbuf_len, (p_pbuf->len - read_offset));
+ memcpy(p_destbuf, (void *)(((uint8_t *)p_pbuf->payload) + read_offset), copy_len);
+ return copy_len;
+}
+
+static uint32_t lwip_buf_len(void * p_ctx)
+{
+ struct pbuf * p_pbuf = (struct pbuf *)p_ctx;
+ return p_pbuf->len;
+}
+
+static void lwip_buf_free(void * p_ctx)
+{
+ nrf_free(((struct pbuf *)p_ctx)->payload);
+ (void) pbuf_free((struct pbuf *)p_ctx);
+}
+
+static void lwip_timer_callback(void * p_ctx)
+{
+ (void) p_ctx;
+ sys_check_timeouts();
+}
+
+void nrf_driver_interface_up(iot_interface_t const * p_interface)
+{
+ UNUSED_PARAMETER(p_interface);
+ transport_interface_up();
+}
+
+void nrf_driver_interface_down(iot_interface_t const * p_interface)
+{
+ UNUSED_PARAMETER(p_interface);
+ transport_interface_down();
+}
+
+void transport_handler_init(void)
+{
+ lwip_init();
+ uint32_t err_code = nrf_driver_init();
+ APP_ERROR_CHECK(err_code);
+ for (uint32_t i = 0; i < SOCKET_MAX_SOCKET_COUNT; i++)
+ {
+ lwip_handles[i].p_pcb = NULL;
+ lwip_handles[i].p_socket = NULL;
+ lwip_handles[i].tcp_state = TCP_STATE_IDLE;
+ }
+ err_code = app_timer_create(&m_lwip_timer_id,
+ APP_TIMER_MODE_REPEATED,
+ lwip_timer_callback);
+ APP_ERROR_CHECK(err_code);
+ err_code = app_timer_start(m_lwip_timer_id, LWIP_SYS_TIMER_INTERVAL, NULL);
+ APP_ERROR_CHECK(err_code);
+ SOCKET_TRACE("Initialized LWIP transport handler\r\n");
+}
+
+static void lwip_error_handler(void * p_arg, err_t err)
+{
+ (void) p_arg;
+ SOCKET_TRACE("Error occured: %d\r\n", (int)err);
+ if(err == ERR_ABRT)
+ {
+ portdb_reset();
+ }
+}
+
+static err_t lwip_poll_handler(void * p_arg, struct tcp_pcb * p_pcb)
+{
+ (void) p_arg;
+ (void) p_pcb;
+
+ return ERR_OK;
+}
+
+static void lwip_drop_connection(void * p_ctx)
+{
+ struct tcp_pcb * p_pcb = (struct tcp_pcb *)p_ctx;
+ tcp_abort(p_pcb);
+}
+
+static lwip_handle_t * lwip_handle_allocate(socket_t * p_socket, struct tcp_pcb * p_pcb)
+{
+ lwip_handle_t * p_handle = NULL;
+ for (uint32_t i = 0; i < SOCKET_MAX_SOCKET_COUNT; i++)
+ {
+ if (lwip_handles[i].p_pcb == NULL)
+ {
+ p_handle = &lwip_handles[i];
+ (void)mbuf_init(&p_handle->mbuf,
+ lwip_buf_read,
+ lwip_buf_len,
+ lwip_buf_free,
+ SOCKET_MAX_PENDING_PACKETS);
+ (void) nrf_fifo_init(&p_handle->conn_queue,
+ SOCKET_MAX_PENDING_CONNECTIONS,
+ socket_wait,
+ lwip_drop_connection);
+ p_handle->p_socket = p_socket;
+ p_handle->tcp_state = TCP_STATE_IDLE;
+ if (p_pcb == NULL)
+ {
+ p_handle->p_pcb = tcp_new();
+ }
+ else
+ {
+ p_handle->p_pcb = p_pcb;
+ }
+ tcp_arg(p_handle->p_pcb, p_handle);
+ tcp_setprio(p_handle->p_pcb, TCP_PRIO_MIN);
+ tcp_recv(p_handle->p_pcb, lwip_recv_callback);
+ tcp_err(p_handle->p_pcb, lwip_error_handler);
+ tcp_poll(p_handle->p_pcb, lwip_poll_handler, 0);
+ break;
+ }
+ }
+ SOCKET_TRACE("Allocated LWIP socket handle\r\n");
+ return p_handle;
+}
+
+static void lwip_handle_free(lwip_handle_t * p_handle)
+{
+ nrf_fifo_deinit(&p_handle->conn_queue);
+ mbuf_deinit(&p_handle->mbuf);
+ p_handle->p_pcb = NULL;
+ p_handle->p_socket = NULL;
+ p_handle->tcp_state = TCP_STATE_IDLE;
+ SOCKET_TRACE("Released LWIP socket handle\r\n");
+}
+
+static uint32_t lwip_transport_open(socket_t * p_socket)
+{
+ lwip_handle_t * p_handle = NULL;
+ uint32_t err_code = NRF_SUCCESS;
+ switch (p_socket->so_params.so_type)
+ {
+ case SOCK_STREAM:
+ p_handle = lwip_handle_allocate(p_socket, NULL);
+ if (p_handle == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ }
+ else
+ {
+ p_socket->so_ctx = p_handle;
+ }
+ break;
+ default:
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+ return err_code;
+}
+
+uint32_t lwip_error_convert(err_t lwip_err)
+{
+ uint32_t err_code = NRF_ERROR_NULL;
+ switch (lwip_err)
+ {
+ case ERR_OK:
+ err_code = NRF_SUCCESS;
+ break;
+ case ERR_MEM:
+ err_code = SOCKET_NO_MEM;
+ break;
+ case ERR_TIMEOUT:
+ err_code = SOCKET_TIMEOUT;
+ break;
+ case ERR_RTE:
+ err_code = SOCKET_NO_ROUTE;
+ break;
+ default:
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+ return err_code;
+}
+
+static uint32_t lwip_transport_close(socket_t * p_socket)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ portdb_free((uint16_t)p_handle->p_pcb->local_port);
+ err_t err_code = tcp_close(p_handle->p_pcb);
+ if (err_code == ERR_OK)
+ {
+ lwip_handle_free(p_handle);
+ }
+ return lwip_error_convert(err_code);
+}
+
+static err_t lwip_connect_callback(void * p_arg, struct tcp_pcb * p_pcb, err_t err)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ // TODO: Error check
+ SOCKET_TRACE("New connection\r\n");
+ p_handle->tcp_state = TCP_STATE_CONNECTED;
+ return ERR_OK;
+}
+
+static err_t lwip_recv_callback(void * p_arg,
+ struct tcp_pcb * p_pcb,
+ struct pbuf * p_pbuf,
+ err_t err)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ socket_t * p_socket = p_handle->p_socket;
+ if (err == ERR_OK)
+ {
+ uint8_t * p_payload_cp = nrf_malloc(p_pbuf->len);
+ struct pbuf * p_pbuf_cp = pbuf_alloc(PBUF_RAW, p_pbuf->len, PBUF_REF);
+
+ memcpy(p_payload_cp, p_pbuf->payload, p_pbuf->len);
+ p_pbuf_cp->payload = p_payload_cp;
+ p_pbuf_cp->len = p_pbuf->len;
+ p_pbuf_cp->tot_len = p_pbuf->tot_len;
+
+ uint32_t err_code = mbuf_write(&p_handle->mbuf, p_pbuf_cp);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_socket->so_read_evt++;
+ }
+ else
+ {
+ err = ERR_MEM;
+ }
+ }
+ return err;
+}
+
+static uint32_t lwip_wait_for_state(lwip_handle_t * p_handle, tcp_state_t state)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ while (err_code == NRF_SUCCESS &&
+ p_handle->tcp_state != state &&
+ p_handle->tcp_state != TCP_STATE_DISCONNECTED)
+ {
+ err_code = socket_wait();
+ }
+ if (err_code == NRF_SUCCESS && p_handle->tcp_state != state)
+ {
+ err_code = NRF_ERROR_NULL;
+ }
+ return err_code;
+}
+
+static void lwipaddr_to_sockaddr(const ip6_addr_t * p_lwip_addr, sockaddr_in6_t * p_addr_in6)
+{
+ struct in6_addr * addr = &p_addr_in6->sin6_addr;
+ addr->s6_addr[0] = p_lwip_addr->addr[0] & 0xFF;
+ addr->s6_addr[1] = (p_lwip_addr->addr[0] >> 8) & 0xFF;
+ addr->s6_addr[2] = (p_lwip_addr->addr[0] >> 16) & 0xFF;
+ addr->s6_addr[3] = (p_lwip_addr->addr[0] >> 24) & 0xFF;
+
+ addr->s6_addr[4] = p_lwip_addr->addr[1] & 0xFF;
+ addr->s6_addr[5] = (p_lwip_addr->addr[1] >> 8) & 0xFF;
+ addr->s6_addr[6] = (p_lwip_addr->addr[1] >> 16) & 0xFF;
+ addr->s6_addr[7] = (p_lwip_addr->addr[1] >> 24) & 0xFF;
+
+ addr->s6_addr[8] = p_lwip_addr->addr[2] & 0xFF;
+ addr->s6_addr[9] = (p_lwip_addr->addr[2] >> 8) & 0xFF;
+ addr->s6_addr[10] = (p_lwip_addr->addr[2] >> 16) & 0xFF;
+ addr->s6_addr[11] = (p_lwip_addr->addr[2] >> 24) & 0xFF;
+
+ addr->s6_addr[12] = p_lwip_addr->addr[3] & 0xFF;
+ addr->s6_addr[13] = (p_lwip_addr->addr[3] >> 8) & 0xFF;
+ addr->s6_addr[14] = (p_lwip_addr->addr[3] >> 16) & 0xFF;
+ addr->s6_addr[15] = (p_lwip_addr->addr[3] >> 24) & 0xFF;
+}
+
+static void sockaddr_to_lwipaddr(const sockaddr_in6_t * p_addr_in6, ip6_addr_t * p_lwip_addr)
+{
+ const struct in6_addr * addr = &p_addr_in6->sin6_addr;
+ IP6_ADDR_PART(p_lwip_addr, 0, addr->s6_addr[0], addr->s6_addr[1], addr->s6_addr[2], addr->s6_addr[3]);
+ IP6_ADDR_PART(p_lwip_addr, 1, addr->s6_addr[4], addr->s6_addr[5], addr->s6_addr[6], addr->s6_addr[7]);
+ IP6_ADDR_PART(p_lwip_addr, 2, addr->s6_addr[8], addr->s6_addr[9], addr->s6_addr[10], addr->s6_addr[11]);
+ IP6_ADDR_PART(p_lwip_addr, 3, addr->s6_addr[12], addr->s6_addr[13], addr->s6_addr[14], addr->s6_addr[15]);
+}
+
+static uint32_t lwip_transport_bind(socket_t * p_socket, const void * p_addr, socklen_t addr_len)
+{
+ VERIFY_ADDRESS_LEN(addr_len);
+ const sockaddr_in6_t * p_addr_in6 = (const sockaddr_in6_t *)p_addr;
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+
+ uint16_t port = HTONS(p_addr_in6->sin6_port);
+ uint32_t err_code = portdb_register(port);
+ if (err_code == NRF_SUCCESS)
+ {
+ ip6_addr_t lwip_addr;
+ sockaddr_to_lwipaddr(p_addr_in6, &lwip_addr);
+ err_t err = tcp_bind(p_handle->p_pcb, &lwip_addr, port);
+ err_code = lwip_error_convert(err);
+ }
+ return err_code;
+}
+
+static uint32_t lwip_transport_connect(socket_t * p_socket,
+ const void * p_addr,
+ socklen_t addr_len)
+{
+ VERIFY_ADDRESS_LEN(addr_len);
+
+ bool is_blocking = ((p_socket->so_flags & O_NONBLOCK) == 0);
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ const sockaddr_in6_t * p_addr_in6 = (const sockaddr_in6_t *)p_addr;
+ uint16_t port = 0;
+ uint32_t err_code = portdb_alloc(&port);
+
+ SOCKET_TRACE("Binding to port %d\r\n", (int)port);
+ if (err_code == NRF_SUCCESS)
+ {
+ ip6_addr_t any_addr;
+ ip6_addr_set_any(&any_addr);
+ err_t err = tcp_bind (p_handle->p_pcb, &any_addr, port);
+ SOCKET_TRACE("Err %d from bind\r\n", (int)err);
+ err_code = lwip_error_convert(err);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ip6_addr_t remote_addr;
+ sockaddr_to_lwipaddr(p_addr_in6, &remote_addr);
+
+ p_handle->tcp_state = TCP_STATE_REQUEST_CONNECTION;
+ err_t err = tcp_connect(p_handle->p_pcb, &remote_addr, HTONS(p_addr_in6->sin6_port), lwip_connect_callback);
+ SOCKET_TRACE("Err %d from connect\r\n", (int)err);
+ err_code = lwip_error_convert(err);
+
+ if (err_code == NRF_SUCCESS && is_blocking)
+ {
+ err_code = lwip_wait_for_state(p_handle, TCP_STATE_CONNECTED);
+ }
+ }
+ if (err_code != NRF_SUCCESS)
+ {
+ SOCKET_TRACE("Error %d when connecting to socket\r\n", (int)err_code);
+ portdb_free(port);
+ }
+ else
+ {
+ SOCKET_TRACE("Successfully connected to remote host!\r\n");
+ }
+
+ return err_code;
+}
+
+static err_t lwip_send_complete(void * p_arg, struct tcp_pcb * p_pcb, u16_t len)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ if (p_handle->tcp_state == TCP_STATE_TCP_SEND_PENDING)
+ {
+ p_handle->tcp_state = TCP_STATE_DATA_TX_IN_PROGRESS;
+ }
+ return ERR_OK;
+}
+
+static inline uint32_t lwip_check_connected(socket_t * p_socket)
+{
+ return (p_socket->so_state == STATE_CONNECTED || p_socket->so_params.so_type == SOCK_DGRAM) ?
+ NRF_SUCCESS : SOCKET_NOT_CONNECTED;
+}
+
+
+static uint32_t lwip_transport_send(socket_t * p_socket,
+ const void * p_buf,
+ uint32_t buf_len,
+ int flags,
+ const void * p_destaddr,
+ socklen_t destaddr_len)
+{
+ (void) p_destaddr;
+ (void) destaddr_len;
+
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ if ((p_socket->so_flags & O_NONBLOCK) != 0 &&
+ (flags & MSG_WAITALL) == 0)
+ {
+ flags |= MSG_DONTWAIT;
+ }
+
+ uint32_t err_code = lwip_check_connected(p_socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t len = tcp_sndbuf(p_handle->p_pcb);
+ if (len >= buf_len)
+ {
+ tcp_sent(p_handle->p_pcb, lwip_send_complete);
+ p_handle->tcp_state = TCP_STATE_TCP_SEND_PENDING;
+ err_t err = tcp_write(p_handle->p_pcb, p_buf, buf_len, 1);
+ err_code = lwip_error_convert(err);
+ if (err_code == NRF_SUCCESS &&
+ (flags & MSG_DONTWAIT) == 0)
+ {
+ err_code = lwip_wait_for_state(p_handle, TCP_STATE_DATA_TX_IN_PROGRESS);
+ }
+ }
+ else
+ {
+ err_code = SOCKET_NO_MEM;
+ }
+ }
+ return err_code;
+}
+
+
+static uint32_t lwip_transport_recv(socket_t * p_socket,
+ void * p_buf,
+ uint32_t * p_buf_size,
+ int flags,
+ void * p_srcaddr,
+ socklen_t * p_srcaddr_len)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ if ((p_socket->so_flags & O_NONBLOCK) != 0 &&
+ (flags & MSG_WAITALL) == 0)
+ {
+ flags |= MSG_DONTWAIT;
+ }
+ uint32_t err_code = lwip_check_connected(p_socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ if (mbuf_empty(&p_handle->mbuf) == true)
+ {
+ if ((flags & MSG_DONTWAIT) != 0)
+ {
+ err_code = SOCKET_WOULD_BLOCK;
+ }
+ else
+ {
+ while ((mbuf_empty(&p_handle->mbuf) == true) && (err_code == NRF_SUCCESS))
+ {
+ err_code = socket_wait();
+ }
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ *p_buf_size = mbuf_read(&p_handle->mbuf, p_buf, *p_buf_size);
+ tcp_recved(p_handle->p_pcb, *p_buf_size);
+ p_socket->so_read_evt = 0;
+ }
+ return err_code;
+}
+
+static err_t lwip_accept_callback(void * p_arg, struct tcp_pcb * p_pcb, err_t err)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ socket_t * p_socket = p_handle->p_socket;
+ if (err == ERR_OK)
+ {
+ (void) nrf_fifo_enq(&p_handle->conn_queue, p_pcb, true);
+ // TODO: Error check
+ p_socket->so_read_evt++;
+ }
+ return err;
+}
+
+static uint32_t lwip_transport_listen(socket_t * p_socket, int backlog)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ uint32_t err_code = NRF_SUCCESS;
+ struct tcp_pcb * p_pcb = tcp_listen_with_backlog(p_handle->p_pcb, backlog);
+ if (p_pcb == NULL)
+ {
+ err_code = SOCKET_ADDRESS_IN_USE;
+ }
+ else
+ {
+ p_handle->p_pcb = p_pcb;
+ tcp_accept(p_handle->p_pcb, lwip_accept_callback);
+ }
+ return err_code;
+}
+
+static uint32_t lwip_transport_accept(socket_t * p_socket,
+ socket_t * p_client,
+ void * p_cliaddr,
+ socklen_t * p_cliaddr_len)
+{
+ VERIFY_ADDRESS_LEN(*p_cliaddr_len);
+ struct tcp_pcb * p_client_pcb = NULL;
+ lwip_handle_t * p_lwip_handle = (lwip_handle_t *)p_socket->so_ctx;
+ uint32_t err_code = nrf_fifo_deq(&p_lwip_handle->conn_queue,
+ (void **)&p_client_pcb,
+ (p_socket->so_flags & O_NONBLOCK) == 0);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ lwip_handle_t * p_lwip_client = lwip_handle_allocate(p_client, p_client_pcb);
+ sockaddr_in6_t * p_sockaddr = (sockaddr_in6_t *)p_cliaddr;
+
+ p_client->so_ctx = p_lwip_client;
+
+ lwipaddr_to_sockaddr(&p_client_pcb->remote_ip, p_sockaddr);
+ p_sockaddr->sin6_port = p_client_pcb->remote_port;
+ p_sockaddr->sin6_len = *p_cliaddr_len;
+ p_sockaddr->sin6_family = AF_INET6;
+ p_sockaddr->sin6_flowinfo = 0;
+ p_sockaddr->sin6_scope_id = 0;
+
+ /*lint -save -e548 */
+ tcp_accepted(p_lwip_handle->p_pcb);
+ /*lint -restore */
+ }
+
+ return err_code;
+}
+
+/**
+ * @brief Transport for LwIP socket.
+ */
+socket_transport_t transport_impl =
+{
+ .open = lwip_transport_open,
+ .bind = lwip_transport_bind,
+ .connect = lwip_transport_connect,
+ .send = lwip_transport_send,
+ .recv = lwip_transport_recv,
+ .listen = lwip_transport_listen,
+ .accept = lwip_transport_accept,
+ .close = lwip_transport_close
+};