netutils: prefer DHCP-provided NTP servers for ntpc

Use the DHCP-learned NTP server list as the default ntpc server source when DHCP option 42 is available.

Fall back to CONFIG_NETUTILS_NTPCLIENT_SERVER only when DHCP does not provide any NTP servers, and restart ntpc when the DHCP-provided server list changes.

Signed-off-by: Jerry Ma <masc2008@gmail.com>
This commit is contained in:
shichunma 2026-04-11 18:41:05 +08:00 • committed by Alan C. Assis
parent 4b705721ca
commit c82957109f
6 changed files with 535 additions and 33 deletions

View file

@ -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()

View file

@ -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

View file

@ -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 <nuttx/config.h>
#ifdef CONFIG_NETUTILS_DHCPC
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#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 */

View file

@ -25,6 +25,10 @@
****************************************************************************/
#include <nuttx/debug.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#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
{