Skip to content

Commit ae63429

Browse files
committed
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>
1 parent 9f8fb46 commit ae63429

6 files changed

Lines changed: 535 additions & 33 deletions

File tree

include/netutils/netlib.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ struct url_s
203203
};
204204
#endif
205205

206+
#ifdef CONFIG_NETUTILS_DHCPC
207+
typedef CODE void (*netlib_dhcp_ntp_callback_t)
208+
(FAR const char *ntp_server_list, FAR void *arg);
209+
#endif
210+
206211
/****************************************************************************
207212
* Public Data
208213
****************************************************************************/
@@ -247,6 +252,44 @@ ssize_t netlib_get_devices(FAR struct netlib_device_s *devlist,
247252
bool netlib_ipv4addrconv(FAR const char *addrstr, FAR uint8_t *addr);
248253
bool netlib_ethaddrconv(FAR const char *hwstr, FAR uint8_t *hw);
249254

255+
#ifdef CONFIG_NETUTILS_DHCPC
256+
/****************************************************************************
257+
* Name: netlib_set_ntp_servers_from_dhcp
258+
*
259+
* Description:
260+
* Update the currently active DHCP option 42 NTP server list. The list
261+
* contains semicolon-separated hostnames or addresses. Passing NULL or
262+
* an empty string clears the DHCP-provided list.
263+
*
264+
****************************************************************************/
265+
266+
int netlib_set_ntp_servers_from_dhcp(FAR const char *ntp_server_list);
267+
268+
/****************************************************************************
269+
* Name: netlib_register_dhcp_ntp_callback
270+
*
271+
* Description:
272+
* Register a callback to receive DHCP option 42 NTP server list updates.
273+
* The current list, if any, is replayed immediately after registration.
274+
* Only one callback may be registered at a time.
275+
*
276+
****************************************************************************/
277+
278+
int netlib_register_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback,
279+
FAR void *arg);
280+
281+
/****************************************************************************
282+
* Name: netlib_unregister_dhcp_ntp_callback
283+
*
284+
* Description:
285+
* Unregister a previously registered DHCP option 42 NTP update callback.
286+
*
287+
****************************************************************************/
288+
289+
int netlib_unregister_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback,
290+
FAR void *arg);
291+
#endif
292+
250293
#ifdef CONFIG_NET_ETHERNET
251294
/* Get and set IP/MAC addresses (Ethernet L2 only) */
252295

netutils/netlib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ if(CONFIG_NETUTILS_NETLIB)
5757
endif()
5858
if(CONFIG_NETUTILS_DHCPC)
5959
list(APPEND SRCS netlib_obtainipv4addr.c)
60+
list(APPEND SRCS netlib_dhcp_ntp.c)
6061
endif()
6162
endif()
6263

netutils/netlib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ CSRCS += netlib_iptables.c
5757
endif
5858
ifeq ($(CONFIG_NETUTILS_DHCPC),y)
5959
CSRCS += netlib_obtainipv4addr.c
60+
CSRCS += netlib_dhcp_ntp.c
6061
endif
6162
endif
6263

netutils/netlib/netlib_dhcp_ntp.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/****************************************************************************
2+
* apps/netutils/netlib/netlib_dhcp_ntp.c
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
/****************************************************************************
24+
* Included Files
25+
****************************************************************************/
26+
27+
#include <nuttx/config.h>
28+
29+
#ifdef CONFIG_NETUTILS_DHCPC
30+
31+
#include <errno.h>
32+
#include <pthread.h>
33+
#include <stdlib.h>
34+
#include <string.h>
35+
36+
#include "netutils/netlib.h"
37+
38+
/****************************************************************************
39+
* Private Data
40+
****************************************************************************/
41+
42+
static pthread_mutex_t g_dhcp_ntp_lock = PTHREAD_MUTEX_INITIALIZER;
43+
static FAR char *g_dhcp_ntp_servers;
44+
static netlib_dhcp_ntp_callback_t g_dhcp_ntp_callback;
45+
static FAR void *g_dhcp_ntp_callback_arg;
46+
47+
/****************************************************************************
48+
* Private Functions
49+
****************************************************************************/
50+
51+
static FAR char *netlib_dhcp_ntp_dup(FAR const char *ntp_server_list)
52+
{
53+
if (ntp_server_list == NULL || ntp_server_list[0] == '\0')
54+
{
55+
return NULL;
56+
}
57+
58+
return strdup(ntp_server_list);
59+
}
60+
61+
/****************************************************************************
62+
* Public Functions
63+
****************************************************************************/
64+
65+
int netlib_set_ntp_servers_from_dhcp(FAR const char *ntp_server_list)
66+
{
67+
FAR char *new_servers;
68+
FAR char *notify_servers = NULL;
69+
FAR char *old_servers;
70+
netlib_dhcp_ntp_callback_t callback;
71+
FAR void *arg;
72+
int ret = OK;
73+
74+
new_servers = netlib_dhcp_ntp_dup(ntp_server_list);
75+
if (ntp_server_list != NULL && ntp_server_list[0] != '\0' &&
76+
new_servers == NULL)
77+
{
78+
return -ENOMEM;
79+
}
80+
81+
pthread_mutex_lock(&g_dhcp_ntp_lock);
82+
83+
if ((g_dhcp_ntp_servers == NULL && new_servers == NULL) ||
84+
(g_dhcp_ntp_servers != NULL && new_servers != NULL &&
85+
strcmp(g_dhcp_ntp_servers, new_servers) == 0))
86+
{
87+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
88+
free(new_servers);
89+
return OK;
90+
}
91+
92+
callback = g_dhcp_ntp_callback;
93+
arg = g_dhcp_ntp_callback_arg;
94+
95+
if (callback != NULL && new_servers != NULL)
96+
{
97+
notify_servers = strdup(new_servers);
98+
if (notify_servers == NULL)
99+
{
100+
ret = -ENOMEM;
101+
goto errout_with_lock;
102+
}
103+
}
104+
105+
old_servers = g_dhcp_ntp_servers;
106+
g_dhcp_ntp_servers = new_servers;
107+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
108+
109+
free(old_servers);
110+
111+
if (callback != NULL)
112+
{
113+
callback(notify_servers, arg);
114+
}
115+
116+
free(notify_servers);
117+
return OK;
118+
119+
errout_with_lock:
120+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
121+
free(new_servers);
122+
return ret;
123+
}
124+
125+
int netlib_register_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback,
126+
FAR void *arg)
127+
{
128+
FAR char *notify_servers = NULL;
129+
130+
if (callback == NULL)
131+
{
132+
return -EINVAL;
133+
}
134+
135+
pthread_mutex_lock(&g_dhcp_ntp_lock);
136+
137+
if (g_dhcp_ntp_callback != NULL &&
138+
(g_dhcp_ntp_callback != callback || g_dhcp_ntp_callback_arg != arg))
139+
{
140+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
141+
return -EBUSY;
142+
}
143+
144+
if (g_dhcp_ntp_servers != NULL)
145+
{
146+
notify_servers = strdup(g_dhcp_ntp_servers);
147+
if (notify_servers == NULL)
148+
{
149+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
150+
return -ENOMEM;
151+
}
152+
}
153+
154+
g_dhcp_ntp_callback = callback;
155+
g_dhcp_ntp_callback_arg = arg;
156+
157+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
158+
159+
callback(notify_servers, arg);
160+
free(notify_servers);
161+
return OK;
162+
}
163+
164+
int netlib_unregister_dhcp_ntp_callback(netlib_dhcp_ntp_callback_t callback,
165+
FAR void *arg)
166+
{
167+
int ret = -ENOENT;
168+
169+
pthread_mutex_lock(&g_dhcp_ntp_lock);
170+
171+
if (g_dhcp_ntp_callback == callback && g_dhcp_ntp_callback_arg == arg)
172+
{
173+
g_dhcp_ntp_callback = NULL;
174+
g_dhcp_ntp_callback_arg = NULL;
175+
ret = OK;
176+
}
177+
178+
pthread_mutex_unlock(&g_dhcp_ntp_lock);
179+
return ret;
180+
}
181+
182+
#endif /* CONFIG_NETUTILS_DHCPC */

netutils/netlib/netlib_obtainipv4addr.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
****************************************************************************/
2626

2727
#include <nuttx/debug.h>
28+
#include <arpa/inet.h>
29+
#include <errno.h>
30+
#include <stdio.h>
31+
#include <string.h>
2832
#include <sys/types.h>
2933

3034
#include "netutils/dhcpc.h"
@@ -105,6 +109,68 @@ static int dhcp_setup_result(FAR const char *ifname,
105109
return OK;
106110
}
107111

112+
#ifdef CONFIG_NETUTILS_NTPCLIENT
113+
static int dhcp_set_ntp_servers(FAR const struct dhcpc_state *ds)
114+
{
115+
char ntp_server_list[CONFIG_NETUTILS_DHCPC_NTP_SERVERS *
116+
(INET_ADDRSTRLEN + 1)];
117+
size_t offset = 0;
118+
uint8_t i;
119+
120+
/* Clear the DHCP-provided NTP server list,
121+
* consider case: that device has joined another dhcp domain,
122+
* it need refresh related settings.
123+
*/
124+
125+
if (ds->num_ntpaddr == 0)
126+
{
127+
return netlib_set_ntp_servers_from_dhcp(NULL);
128+
}
129+
130+
ntp_server_list[0] = '\0';
131+
132+
for (i = 0; i < ds->num_ntpaddr; i++)
133+
{
134+
char addrbuf[INET_ADDRSTRLEN];
135+
int ret;
136+
137+
/* Skip empty entries */
138+
139+
if (ds->ntpaddr[i].s_addr == 0)
140+
{
141+
continue;
142+
}
143+
144+
if (inet_ntop(AF_INET, &ds->ntpaddr[i], addrbuf, sizeof(addrbuf)) ==
145+
NULL)
146+
{
147+
return -EINVAL;
148+
}
149+
150+
/* Append the server to the list */
151+
152+
ret = snprintf(ntp_server_list + offset,
153+
sizeof(ntp_server_list) - offset,
154+
"%s%s", offset == 0 ? "" : ";", addrbuf);
155+
if (ret < 0 || (size_t)ret >= sizeof(ntp_server_list) - offset)
156+
{
157+
return -E2BIG;
158+
}
159+
160+
offset += (size_t)ret;
161+
}
162+
163+
/* Clear the list if all entries were empty */
164+
165+
if (offset == 0)
166+
{
167+
return netlib_set_ntp_servers_from_dhcp(NULL);
168+
}
169+
170+
return netlib_set_ntp_servers_from_dhcp(ntp_server_list);
171+
}
172+
#endif
173+
108174
/****************************************************************************
109175
* Name: dhcp_obtain_statefuladdr
110176
*
@@ -156,6 +222,18 @@ static int dhcp_obtain_statefuladdr(FAR const char *ifname)
156222
if (ret == OK)
157223
{
158224
ret = dhcp_setup_result(ifname, &ds);
225+
#ifdef CONFIG_NETUTILS_NTPCLIENT
226+
if (ret == OK)
227+
{
228+
ret = dhcp_set_ntp_servers(&ds);
229+
if (ret < 0)
230+
{
231+
nwarn("WARNING: failed to update DHCP NTP server list: %d\n",
232+
ret);
233+
ret = OK;
234+
}
235+
}
236+
#endif
159237
}
160238
else
161239
{

0 commit comments

Comments
 (0)