aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/ipv6_stack/sntp_client')
-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
2 files changed, 809 insertions, 0 deletions
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__
+
+/**@} */