diff --git a/include/netutils/dhcpc.h b/include/netutils/dhcpc.h index 0cf16907b19..b17d6f36898 100644 --- a/include/netutils/dhcpc.h +++ b/include/netutils/dhcpc.h @@ -55,6 +55,10 @@ # define CONFIG_NETDB_DNSSERVER_NAMESERVERS 1 #endif +#if !defined(CONFIG_NETUTILS_DHCPC_NTP_SERVERS) +# define CONFIG_NETUTILS_DHCPC_NTP_SERVERS 1 +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -66,6 +70,8 @@ struct dhcpc_state struct in_addr netmask; struct in_addr dnsaddr[CONFIG_NETDB_DNSSERVER_NAMESERVERS]; uint8_t num_dnsaddr; /* Number of DNS addresses received */ + struct in_addr ntpaddr[CONFIG_NETUTILS_DHCPC_NTP_SERVERS]; + uint8_t num_ntpaddr; /* Number of NTP addresses received */ struct in_addr default_router; uint32_t lease_time; /* Lease expires in this number of seconds */ uint32_t renewal_time; /* Seconds to transition to RENEW state(T1) */ diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index 2b3146e9145..eb3933fe95d 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -203,6 +203,11 @@ struct url_s }; #endif +#ifdef CONFIG_NETUTILS_DHCPC +typedef CODE void (*netlib_dhcp_ntp_callback_t) + (FAR const char *ntp_server_list, FAR void *arg); +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -247,6 +252,44 @@ ssize_t netlib_get_devices(FAR struct netlib_device_s *devlist, bool netlib_ipv4addrconv(FAR const char *addrstr, FAR uint8_t *addr); bool netlib_ethaddrconv(FAR const char *hwstr, FAR uint8_t *hw); +#ifdef CONFIG_NETUTILS_DHCPC +/**************************************************************************** + * Name: netlib_set_ntp_servers_from_dhcp + * + * Description: + * Update the currently active DHCP option 42 NTP server list. The list + * contains semicolon-separated hostnames or addresses. Passing NULL or + * an empty string clears the DHCP-provided list. + * + ****************************************************************************/ + +int netlib_set_ntp_servers_from_dhcp(FAR const char *ntp_server_list); + +/**************************************************************************** + * Name: netlib_register_dhcp_ntp_callback + * + * Description: + * Register a callback to receive DHCP option 42 NTP server list updates. + * The current list, if any, is replayed immediately after registration. + * Only one callback may be registered at a time. + * + ****************************************************************************/ + +int netlib_register_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback, + FAR void *arg); + +/**************************************************************************** + * Name: netlib_unregister_dhcp_ntp_callback + * + * Description: + * Unregister a previously registered DHCP option 42 NTP update callback. + * + ****************************************************************************/ + +int netlib_unregister_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback, + FAR void *arg); +#endif + #ifdef CONFIG_NET_ETHERNET /* Get and set IP/MAC addresses (Ethernet L2 only) */ diff --git a/netutils/dhcpc/dhcpc.c b/netutils/dhcpc/dhcpc.c index e899b69303f..a449c96ca4c 100644 --- a/netutils/dhcpc/dhcpc.c +++ b/netutils/dhcpc/dhcpc.c @@ -91,6 +91,7 @@ #define DHCP_OPTION_ROUTER 3 #define DHCP_OPTION_DNS_SERVER 6 #define DHCP_OPTION_HOST_NAME 12 +#define DHCP_OPTION_NTP_SERVER 42 #define DHCP_OPTION_REQ_IPADDR 50 #define DHCP_OPTION_LEASE_TIME 51 #define DHCP_OPTION_MSG_TYPE 53 @@ -210,10 +211,11 @@ static FAR uint8_t *dhcpc_addclientid(FAR uint8_t *clientid, static FAR uint8_t *dhcpc_addreqoptions(FAR uint8_t *optptr) { *optptr++ = DHCP_OPTION_REQ_LIST; - *optptr++ = 3; + *optptr++ = 4; *optptr++ = DHCP_OPTION_SUBNET_MASK; *optptr++ = DHCP_OPTION_ROUTER; *optptr++ = DHCP_OPTION_DNS_SERVER; + *optptr++ = DHCP_OPTION_NTP_SERVER; return optptr; } @@ -411,6 +413,39 @@ static uint8_t dhcpc_parseoptions(FAR struct dhcpc_state *presult, } break; + case DHCP_OPTION_NTP_SERVER: + + /* Get the NTP server addresses in network order. + * DHCP option 42 can contain multiple IPv4 addresses, + * each 4 bytes long. + */ + + if (optptr + 2 <= end) + { + uint8_t optlen = *(optptr + 1); + uint8_t num_ntp = optlen / 4; + uint8_t i; + + if (num_ntp > CONFIG_NETUTILS_DHCPC_NTP_SERVERS) + { + num_ntp = CONFIG_NETUTILS_DHCPC_NTP_SERVERS; + } + + presult->num_ntpaddr = 0; + for (i = 0; i < num_ntp && (optptr + 2 + i * 4 + 4) <= end; + i++) + { + memcpy(&presult->ntpaddr[i].s_addr, optptr + 2 + i * 4, + 4); + presult->num_ntpaddr++; + } + } + else + { + nerr("Packet too short (NTP address missing)\n"); + } + break; + case DHCP_OPTION_MSG_TYPE: /* Get message type */ @@ -999,6 +1034,21 @@ int dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult) } } + /* Print all NTP servers received */ + + if (presult->num_ntpaddr > 0) + { + uint8_t i; + for (i = 0; i < presult->num_ntpaddr; i++) + { + ninfo("Got NTP server %d: %u.%u.%u.%u\n", i, + ip4_addr1(presult->ntpaddr[i].s_addr), + ip4_addr2(presult->ntpaddr[i].s_addr), + ip4_addr3(presult->ntpaddr[i].s_addr), + ip4_addr4(presult->ntpaddr[i].s_addr)); + } + } + ninfo("Got default router %u.%u.%u.%u\n", ip4_addr1(presult->default_router.s_addr), ip4_addr2(presult->default_router.s_addr), diff --git a/netutils/netlib/CMakeLists.txt b/netutils/netlib/CMakeLists.txt index 49e8aa81ec6..2f0f11e0f06 100644 --- a/netutils/netlib/CMakeLists.txt +++ b/netutils/netlib/CMakeLists.txt @@ -57,6 +57,7 @@ if(CONFIG_NETUTILS_NETLIB) endif() if(CONFIG_NETUTILS_DHCPC) list(APPEND SRCS netlib_obtainipv4addr.c) + list(APPEND SRCS netlib_dhcp_ntp.c) endif() endif() diff --git a/netutils/netlib/Makefile b/netutils/netlib/Makefile index 4bfc8d9d40b..7bba856b7dc 100644 --- a/netutils/netlib/Makefile +++ b/netutils/netlib/Makefile @@ -57,6 +57,7 @@ CSRCS += netlib_iptables.c endif ifeq ($(CONFIG_NETUTILS_DHCPC),y) CSRCS += netlib_obtainipv4addr.c +CSRCS += netlib_dhcp_ntp.c endif endif diff --git a/netutils/netlib/netlib_dhcp_ntp.c b/netutils/netlib/netlib_dhcp_ntp.c new file mode 100644 index 00000000000..b1d608db098 --- /dev/null +++ b/netutils/netlib/netlib_dhcp_ntp.c @@ -0,0 +1,182 @@ +/**************************************************************************** + * apps/netutils/netlib/netlib_dhcp_ntp.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_NETUTILS_DHCPC + +#include +#include +#include +#include + +#include "netutils/netlib.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static pthread_mutex_t g_dhcp_ntp_lock = PTHREAD_MUTEX_INITIALIZER; +static FAR char *g_dhcp_ntp_servers; +static netlib_dhcp_ntp_callback_t g_dhcp_ntp_callback; +static FAR void *g_dhcp_ntp_callback_arg; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static FAR char *netlib_dhcp_ntp_dup(FAR const char *ntp_server_list) +{ + if (ntp_server_list == NULL || ntp_server_list[0] == '\0') + { + return NULL; + } + + return strdup(ntp_server_list); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int netlib_set_ntp_servers_from_dhcp(FAR const char *ntp_server_list) +{ + FAR char *new_servers; + FAR char *notify_servers = NULL; + FAR char *old_servers; + netlib_dhcp_ntp_callback_t callback; + FAR void *arg; + int ret = OK; + + new_servers = netlib_dhcp_ntp_dup(ntp_server_list); + if (ntp_server_list != NULL && ntp_server_list[0] != '\0' && + new_servers == NULL) + { + return -ENOMEM; + } + + pthread_mutex_lock(&g_dhcp_ntp_lock); + + if ((g_dhcp_ntp_servers == NULL && new_servers == NULL) || + (g_dhcp_ntp_servers != NULL && new_servers != NULL && + strcmp(g_dhcp_ntp_servers, new_servers) == 0)) + { + pthread_mutex_unlock(&g_dhcp_ntp_lock); + free(new_servers); + return OK; + } + + callback = g_dhcp_ntp_callback; + arg = g_dhcp_ntp_callback_arg; + + if (callback != NULL && new_servers != NULL) + { + notify_servers = strdup(new_servers); + if (notify_servers == NULL) + { + ret = -ENOMEM; + goto errout_with_lock; + } + } + + old_servers = g_dhcp_ntp_servers; + g_dhcp_ntp_servers = new_servers; + pthread_mutex_unlock(&g_dhcp_ntp_lock); + + free(old_servers); + + if (callback != NULL) + { + callback(notify_servers, arg); + } + + free(notify_servers); + return OK; + +errout_with_lock: + pthread_mutex_unlock(&g_dhcp_ntp_lock); + free(new_servers); + return ret; +} + +int netlib_register_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback, + FAR void *arg) +{ + FAR char *notify_servers = NULL; + + if (callback == NULL) + { + return -EINVAL; + } + + pthread_mutex_lock(&g_dhcp_ntp_lock); + + if (g_dhcp_ntp_callback != NULL && + (g_dhcp_ntp_callback != callback || g_dhcp_ntp_callback_arg != arg)) + { + pthread_mutex_unlock(&g_dhcp_ntp_lock); + return -EBUSY; + } + + if (g_dhcp_ntp_servers != NULL) + { + notify_servers = strdup(g_dhcp_ntp_servers); + if (notify_servers == NULL) + { + pthread_mutex_unlock(&g_dhcp_ntp_lock); + return -ENOMEM; + } + } + + g_dhcp_ntp_callback = callback; + g_dhcp_ntp_callback_arg = arg; + + pthread_mutex_unlock(&g_dhcp_ntp_lock); + + callback(notify_servers, arg); + free(notify_servers); + return OK; +} + +int netlib_unregister_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback, + FAR void *arg) +{ + int ret = -ENOENT; + + pthread_mutex_lock(&g_dhcp_ntp_lock); + + if (g_dhcp_ntp_callback == callback && g_dhcp_ntp_callback_arg == arg) + { + g_dhcp_ntp_callback = NULL; + g_dhcp_ntp_callback_arg = NULL; + ret = OK; + } + + pthread_mutex_unlock(&g_dhcp_ntp_lock); + return ret; +} + +#endif /* CONFIG_NETUTILS_DHCPC */ diff --git a/netutils/netlib/netlib_obtainipv4addr.c b/netutils/netlib/netlib_obtainipv4addr.c index cab55b74cc8..df07fef5968 100644 --- a/netutils/netlib/netlib_obtainipv4addr.c +++ b/netutils/netlib/netlib_obtainipv4addr.c @@ -25,6 +25,10 @@ ****************************************************************************/ #include +#include +#include +#include +#include #include #include "netutils/dhcpc.h" @@ -105,6 +109,68 @@ static int dhcp_setup_result(FAR const char *ifname, return OK; } +#ifdef CONFIG_NETUTILS_NTPCLIENT +static int dhcp_set_ntp_servers(FAR const struct dhcpc_state *ds) +{ + char ntp_server_list[CONFIG_NETUTILS_DHCPC_NTP_SERVERS * + (INET_ADDRSTRLEN + 1)]; + size_t offset = 0; + uint8_t i; + + /* Clear the DHCP-provided NTP server list, + * consider case: that device has joined another dhcp domain, + * it need refresh related settings. + */ + + if (ds->num_ntpaddr == 0) + { + return netlib_set_ntp_servers_from_dhcp(NULL); + } + + ntp_server_list[0] = '\0'; + + for (i = 0; i < ds->num_ntpaddr; i++) + { + char addrbuf[INET_ADDRSTRLEN]; + int ret; + + /* Skip empty entries */ + + if (ds->ntpaddr[i].s_addr == 0) + { + continue; + } + + if (inet_ntop(AF_INET, &ds->ntpaddr[i], addrbuf, sizeof(addrbuf)) == + NULL) + { + return -EINVAL; + } + + /* Append the server to the list */ + + ret = snprintf(ntp_server_list + offset, + sizeof(ntp_server_list) - offset, + "%s%s", offset == 0 ? "" : ";", addrbuf); + if (ret < 0 || (size_t)ret >= sizeof(ntp_server_list) - offset) + { + return -E2BIG; + } + + offset += (size_t)ret; + } + + /* Clear the list if all entries were empty */ + + if (offset == 0) + { + return netlib_set_ntp_servers_from_dhcp(NULL); + } + + return netlib_set_ntp_servers_from_dhcp(ntp_server_list); +} +#endif + /**************************************************************************** * Name: dhcp_obtain_statefuladdr * @@ -156,6 +222,18 @@ static int dhcp_obtain_statefuladdr(FAR const char *ifname) if (ret == OK) { ret = dhcp_setup_result(ifname, &ds); +#ifdef CONFIG_NETUTILS_NTPCLIENT + if (ret == OK) + { + ret = dhcp_set_ntp_servers(&ds); + if (ret < 0) + { + nwarn("WARNING: failed to update DHCP NTP server list: %d\n", + ret); + ret = OK; + } + } +#endif } else { diff --git a/netutils/ntpclient/ntpclient.c b/netutils/ntpclient/ntpclient.c index ce7d2f0d940..ec002a7f168 100644 --- a/netutils/ntpclient/ntpclient.c +++ b/netutils/ntpclient/ntpclient.c @@ -126,6 +126,14 @@ enum ntpc_daemon_e NTP_STOPPED }; +enum ntpc_server_source_e +{ + NTP_SERVER_SOURCE_NONE = 0, + NTP_SERVER_SOURCE_CONFIG, + NTP_SERVER_SOURCE_DHCP, + NTP_SERVER_SOURCE_EXPLICIT +}; + /* This type describes the state of the NTP client daemon. Only one * instance of the NTP daemon is permitted in this implementation. */ @@ -133,11 +141,17 @@ enum ntpc_daemon_e struct ntpc_daemon_s { uint8_t state; /* See enum ntpc_daemon_e */ + uint8_t source; /* See enum ntpc_server_source_e */ + bool dhcp_registered; sem_t lock; /* Used to protect the whole structure */ sem_t sync; /* Used to synchronize start and stop events */ pid_t pid; /* Task ID of the NTP daemon */ sq_queue_t kod_list; /* KoD excluded server addresses */ int family; /* Allowed address family */ + + /* DHCP-provided server list */ + + FAR char *dhcp_servers; }; union ntp_addr_u @@ -194,11 +208,14 @@ struct ntp_kod_exclude_s static struct ntpc_daemon_s g_ntpc_daemon = { NTP_NOT_RUNNING, + NTP_SERVER_SOURCE_NONE, + false, SEM_INITIALIZER(1), SEM_INITIALIZER(0), -1, { NULL, NULL }, AF_UNSPEC, /* Default is both IPv4 and IPv6 */ + NULL, }; static struct ntp_sample_s g_last_samples @@ -209,6 +226,115 @@ unsigned int g_last_nsamples = 0; * Private Functions ****************************************************************************/ +static int ntpc_daemon(int argc, FAR char **argv); +static int ntpc_set_servers_from_dhcp(FAR const char *ntp_server_list); + +static FAR char *ntpc_dup_server_list(FAR const char *ntp_server_list) +{ + if (ntp_server_list == NULL || ntp_server_list[0] == '\0') + { + return NULL; + } + + return strdup(ntp_server_list); +} + +static FAR const char *ntpc_select_server_list(FAR uint8_t *source) +{ + if (g_ntpc_daemon.dhcp_servers != NULL && + g_ntpc_daemon.dhcp_servers[0] != '\0') + { + *source = NTP_SERVER_SOURCE_DHCP; + return g_ntpc_daemon.dhcp_servers; + } + + if (CONFIG_NETUTILS_NTPCLIENT_SERVER[0] != '\0') + { + *source = NTP_SERVER_SOURCE_CONFIG; + return CONFIG_NETUTILS_NTPCLIENT_SERVER; + } + + *source = NTP_SERVER_SOURCE_NONE; + return NULL; +} + +#ifdef CONFIG_NETUTILS_DHCPC +static void ntpc_dhcp_notify(FAR const char *ntp_server_list, FAR void *arg) +{ + int ret; + + UNUSED(arg); + + ret = ntpc_set_servers_from_dhcp(ntp_server_list); + if (ret < 0) + { + nwarn("WARNING: failed to update DHCP NTP server list: %d\n", ret); + } +} + +static int ntpc_register_dhcp(void) +{ + int ret; + + sem_wait(&g_ntpc_daemon.lock); + if (g_ntpc_daemon.dhcp_registered) + { + sem_post(&g_ntpc_daemon.lock); + return OK; + } + + g_ntpc_daemon.dhcp_registered = true; + sem_post(&g_ntpc_daemon.lock); + + ret = netlib_register_dhcp_ntp_callback(ntpc_dhcp_notify, NULL); + if (ret < 0) + { + sem_wait(&g_ntpc_daemon.lock); + g_ntpc_daemon.dhcp_registered = false; + sem_post(&g_ntpc_daemon.lock); + return ret; + } + + return OK; +} +#endif + +static int ntpc_start_selected(FAR const char *ntp_server_list, + uint8_t source) +{ + FAR char *task_argv[] = + { + (FAR char *)ntp_server_list, + NULL + }; + + g_ntpc_daemon.state = NTP_STARTED; + g_ntpc_daemon.source = source; + g_ntpc_daemon.pid = + task_create("NTP daemon", CONFIG_NETUTILS_NTPCLIENT_SERVERPRIO, + CONFIG_NETUTILS_NTPCLIENT_STACKSIZE, ntpc_daemon, + task_argv); + + if (g_ntpc_daemon.pid < 0) + { + int errval = errno; + DEBUGASSERT(errval > 0); + + g_ntpc_daemon.state = NTP_STOPPED; + g_ntpc_daemon.source = NTP_SERVER_SOURCE_NONE; + nerr("ERROR: Failed to start the NTP daemon: %d\n", errval); + return -errval; + } + + do + { + sem_wait(&g_ntpc_daemon.sync); + } + while (g_ntpc_daemon.state == NTP_STARTED); + + return g_ntpc_daemon.pid; +} + /**************************************************************************** * Name: sample_cmp ****************************************************************************/ @@ -1490,11 +1616,12 @@ void ntpc_dualstack_family(int family) int ntpc_start_with_list(FAR const char *ntp_server_list) { - FAR char *task_argv[] = + int ret; + + if (ntp_server_list == NULL || ntp_server_list[0] == '\0') { - (FAR char *)ntp_server_list, - NULL - }; + return -EINVAL; + } /* Is the NTP in a non-running state? */ @@ -1502,34 +1629,10 @@ int ntpc_start_with_list(FAR const char *ntp_server_list) if (g_ntpc_daemon.state == NTP_NOT_RUNNING || g_ntpc_daemon.state == NTP_STOPPED) { - /* Start the NTP daemon */ - - g_ntpc_daemon.state = NTP_STARTED; - g_ntpc_daemon.pid = - task_create("NTP daemon", CONFIG_NETUTILS_NTPCLIENT_SERVERPRIO, - CONFIG_NETUTILS_NTPCLIENT_STACKSIZE, ntpc_daemon, - task_argv); - - /* Handle failures to start the NTP daemon */ - - if (g_ntpc_daemon.pid < 0) - { - int errval = errno; - DEBUGASSERT(errval > 0); - - g_ntpc_daemon.state = NTP_STOPPED; - nerr("ERROR: Failed to start the NTP daemon: %d\n", errval); - sem_post(&g_ntpc_daemon.lock); - return -errval; - } - - /* Wait for any daemon state change */ - - do - { - sem_wait(&g_ntpc_daemon.sync); - } - while (g_ntpc_daemon.state == NTP_STARTED); + ret = ntpc_start_selected(ntp_server_list, + NTP_SERVER_SOURCE_EXPLICIT); + sem_post(&g_ntpc_daemon.lock); + return ret; } sem_post(&g_ntpc_daemon.lock); @@ -1550,7 +1653,101 @@ int ntpc_start_with_list(FAR const char *ntp_server_list) int ntpc_start(void) { - return ntpc_start_with_list(CONFIG_NETUTILS_NTPCLIENT_SERVER); + FAR const char *ntp_server_list; + uint8_t source; + int ret; + +#ifdef CONFIG_NETUTILS_DHCPC + ret = ntpc_register_dhcp(); + if (ret < 0) + { + return ret; + } +#endif + + sem_wait(&g_ntpc_daemon.lock); + if (g_ntpc_daemon.state != NTP_NOT_RUNNING && + g_ntpc_daemon.state != NTP_STOPPED) + { + ret = g_ntpc_daemon.pid; + sem_post(&g_ntpc_daemon.lock); + return ret; + } + + ntp_server_list = ntpc_select_server_list(&source); + if (ntp_server_list == NULL) + { + g_ntpc_daemon.source = NTP_SERVER_SOURCE_NONE; + sem_post(&g_ntpc_daemon.lock); + return -ENOENT; + } + + ret = ntpc_start_selected(ntp_server_list, source); + sem_post(&g_ntpc_daemon.lock); + return ret; +} + +static int ntpc_set_servers_from_dhcp(FAR const char *ntp_server_list) +{ + FAR char *new_servers; + FAR char *old_servers; + bool start = false; + bool restart = false; + int ret = OK; + + new_servers = ntpc_dup_server_list(ntp_server_list); + if (ntp_server_list != NULL && ntp_server_list[0] != '\0' && + new_servers == NULL) + { + return -ENOMEM; + } + + sem_wait(&g_ntpc_daemon.lock); + + if ((g_ntpc_daemon.dhcp_servers == NULL && new_servers == NULL) || + (g_ntpc_daemon.dhcp_servers != NULL && new_servers != NULL && + strcmp(g_ntpc_daemon.dhcp_servers, new_servers) == 0)) + { + sem_post(&g_ntpc_daemon.lock); + free(new_servers); + return OK; + } + + old_servers = g_ntpc_daemon.dhcp_servers; + g_ntpc_daemon.dhcp_servers = new_servers; + + if ((g_ntpc_daemon.source == NTP_SERVER_SOURCE_DHCP || + g_ntpc_daemon.source == NTP_SERVER_SOURCE_CONFIG) && + (g_ntpc_daemon.state == NTP_STARTED || + g_ntpc_daemon.state == NTP_RUNNING)) + { + restart = true; + } + else if (g_ntpc_daemon.source == NTP_SERVER_SOURCE_NONE && + new_servers != NULL && + (g_ntpc_daemon.state == NTP_NOT_RUNNING || + g_ntpc_daemon.state == NTP_STOPPED)) + { + start = true; + } + + sem_post(&g_ntpc_daemon.lock); + free(old_servers); + + if (restart) + { + ret = ntpc_stop(); + if (ret >= 0 && new_servers != NULL) + { + ret = ntpc_start(); + } + } + else if (start) + { + ret = ntpc_start(); + } + + return ret; } /****************************************************************************