Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

110 lines
3.2 KiB

/*
* Copyright (c) 2019 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_config, CONFIG_NET_CONFIG_LOG_LEVEL);
#include <errno.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/sntp.h>
#include <zephyr/posix/time.h>
#ifdef CONFIG_NET_CONFIG_SNTP_INIT_RESYNC
static void sntp_resync_handler(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(sntp_resync_work_handle, sntp_resync_handler);
#endif
BUILD_ASSERT(
IS_ENABLED(CONFIG_NET_CONFIG_SNTP_INIT_SERVER_USE_DHCPV4_OPTION) ||
(sizeof(CONFIG_NET_CONFIG_SNTP_INIT_SERVER) != 1),
"SNTP server has to be configured, unless DHCPv4 is used to set it");
static int sntp_init_helper(struct sntp_time *tm)
{
#ifdef CONFIG_NET_CONFIG_SNTP_INIT_SERVER_USE_DHCPV4_OPTION
struct net_if *iface = net_if_get_default();
if (!net_ipv4_is_addr_unspecified(&iface->config.dhcpv4.ntp_addr)) {
struct sockaddr_in sntp_addr = {0};
sntp_addr.sin_family = AF_INET;
sntp_addr.sin_addr.s_addr = iface->config.dhcpv4.ntp_addr.s_addr;
return sntp_simple_addr((struct sockaddr *)&sntp_addr, sizeof(sntp_addr),
CONFIG_NET_CONFIG_SNTP_INIT_TIMEOUT, tm);
}
if (sizeof(CONFIG_NET_CONFIG_SNTP_INIT_SERVER) == 1) {
/* Empty address, skip using SNTP via Kconfig defaults */
return -EINVAL;
}
LOG_INF("SNTP address not set by DHCPv4, using Kconfig defaults");
#endif /* NET_CONFIG_SNTP_INIT_SERVER_USE_DHCPV4_OPTION */
return sntp_simple(CONFIG_NET_CONFIG_SNTP_INIT_SERVER,
CONFIG_NET_CONFIG_SNTP_INIT_TIMEOUT, tm);
}
int net_init_clock_via_sntp(void)
{
struct sntp_time ts;
struct timespec tspec;
int res = sntp_init_helper(&ts);
if (res < 0) {
LOG_ERR("Cannot set time using SNTP");
goto end;
}
tspec.tv_sec = ts.seconds;
tspec.tv_nsec = ((uint64_t)ts.fraction * (1000 * 1000 * 1000)) >> 32;
res = clock_settime(CLOCK_REALTIME, &tspec);
end:
#ifdef CONFIG_NET_CONFIG_SNTP_INIT_RESYNC
k_work_reschedule(
&sntp_resync_work_handle,
(res < 0) ? K_SECONDS(CONFIG_NET_CONFIG_SNTP_INIT_RESYNC_ON_FAILURE_INTERVAL)
: K_SECONDS(CONFIG_NET_CONFIG_SNTP_INIT_RESYNC_INTERVAL));
#endif
return res;
}
#ifdef CONFIG_NET_CONFIG_SNTP_INIT_RESYNC
static void sntp_resync_handler(struct k_work *work)
{
int res;
ARG_UNUSED(work);
res = net_init_clock_via_sntp();
if (res < 0) {
LOG_ERR("Cannot resync time using SNTP");
return;
}
LOG_DBG("Time resynced using SNTP");
}
#endif /* CONFIG_NET_CONFIG_SNTP_INIT_RESYNC */
#ifdef CONFIG_NET_CONFIG_SNTP_INIT_USE_CONNECTION_MANAGER
static void l4_event_handler(uint64_t mgmt_event, struct net_if *iface, void *info,
size_t info_length, void *user_data)
{
ARG_UNUSED(iface);
ARG_UNUSED(info);
ARG_UNUSED(info_length);
ARG_UNUSED(user_data);
if (mgmt_event == NET_EVENT_L4_CONNECTED) {
k_work_reschedule(&sntp_resync_work_handle, K_NO_WAIT);
} else if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
k_work_cancel_delayable(&sntp_resync_work_handle);
}
}
NET_MGMT_REGISTER_EVENT_HANDLER(sntp_init_event_handler,
NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED,
&l4_event_handler, NULL);
#endif /* CONFIG_LOG_BACKEND_NET_USE_CONNECTION_MANAGER */