1 |
786 |
skrzyp |
//=============================================================================
|
2 |
|
|
//
|
3 |
|
|
// sntp.c
|
4 |
|
|
//
|
5 |
|
|
// Simple Network Time Protocol
|
6 |
|
|
//
|
7 |
|
|
//=============================================================================
|
8 |
|
|
// ####ECOSGPLCOPYRIGHTBEGIN####
|
9 |
|
|
// -------------------------------------------
|
10 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
11 |
|
|
// Copyright (C) 2003 Free Software Foundation, Inc.
|
12 |
|
|
//
|
13 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
14 |
|
|
// the terms of the GNU General Public License as published by the Free
|
15 |
|
|
// Software Foundation; either version 2 or (at your option) any later
|
16 |
|
|
// version.
|
17 |
|
|
//
|
18 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT
|
19 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
20 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
21 |
|
|
// for more details.
|
22 |
|
|
//
|
23 |
|
|
// You should have received a copy of the GNU General Public License
|
24 |
|
|
// along with eCos; if not, write to the Free Software Foundation, Inc.,
|
25 |
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
26 |
|
|
//
|
27 |
|
|
// As a special exception, if other files instantiate templates or use
|
28 |
|
|
// macros or inline functions from this file, or you compile this file
|
29 |
|
|
// and link it with other works to produce a work based on this file,
|
30 |
|
|
// this file does not by itself cause the resulting work to be covered by
|
31 |
|
|
// the GNU General Public License. However the source code for this file
|
32 |
|
|
// must still be made available in accordance with section (3) of the GNU
|
33 |
|
|
// General Public License v2.
|
34 |
|
|
//
|
35 |
|
|
// This exception does not invalidate any other reasons why a work based
|
36 |
|
|
// on this file might be covered by the GNU General Public License.
|
37 |
|
|
// -------------------------------------------
|
38 |
|
|
// ####ECOSGPLCOPYRIGHTEND####
|
39 |
|
|
//=============================================================================
|
40 |
|
|
//#####DESCRIPTIONBEGIN####
|
41 |
|
|
//
|
42 |
|
|
// Author(s): andrew.lunn
|
43 |
|
|
// Contributors:
|
44 |
|
|
// Date: 2003-02-12
|
45 |
|
|
// Description: Provides a Simple Network Time Protocol Client
|
46 |
|
|
//####DESCRIPTIONEND####
|
47 |
|
|
//
|
48 |
|
|
//=============================================================================
|
49 |
|
|
|
50 |
|
|
#include <pkgconf/system.h>
|
51 |
|
|
#include <pkgconf/net_sntp.h>
|
52 |
|
|
#include <network.h>
|
53 |
|
|
#include <cyg/infra/cyg_type.h>
|
54 |
|
|
#include <cyg/infra/cyg_ass.h>
|
55 |
|
|
#include <cyg/infra/cyg_trac.h>
|
56 |
|
|
#include <cyg/sntp/sntp.h>
|
57 |
|
|
#include <time.h>
|
58 |
|
|
|
59 |
|
|
/* NTP/SNTPv4 Packet Format (RFC2030) */
|
60 |
|
|
typedef struct
|
61 |
|
|
{
|
62 |
|
|
cyg_uint32 Seconds; /* Since 00:00:00 Jan 01 1900 */
|
63 |
|
|
cyg_uint32 Fraction;
|
64 |
|
|
} NTP_TIMESTAMP;
|
65 |
|
|
|
66 |
|
|
typedef struct
|
67 |
|
|
{
|
68 |
|
|
/* Control combines LeapIndicator, Version, and Mode */
|
69 |
|
|
cyg_uint8 Control;
|
70 |
|
|
cyg_uint8 Stratum;
|
71 |
|
|
cyg_uint8 Poll;
|
72 |
|
|
cyg_uint8 Precision;
|
73 |
|
|
|
74 |
|
|
cyg_uint32 RootDelay;
|
75 |
|
|
cyg_uint32 RootDispersion;
|
76 |
|
|
cyg_uint32 ReferenceIdentifier;
|
77 |
|
|
|
78 |
|
|
NTP_TIMESTAMP ReferenceTimestamp;
|
79 |
|
|
NTP_TIMESTAMP OriginateTimestamp;
|
80 |
|
|
NTP_TIMESTAMP ReceiveTimestamp;
|
81 |
|
|
NTP_TIMESTAMP TransmitTimestamp;
|
82 |
|
|
|
83 |
|
|
// cyg_uint32 KeyIdentifier; /* Optional */
|
84 |
|
|
// cyg_uint8 MessageDigest[16]; /* Optional */
|
85 |
|
|
} NTP_PACKET;
|
86 |
|
|
#define NTP_PACKET_MINLEN 48 /* Packet size - optional fields */
|
87 |
|
|
|
88 |
|
|
/* Leap Indicator Field [Bits 7:6] */
|
89 |
|
|
#define NTP_LI_NOLEAP 0x00
|
90 |
|
|
#define NTP_LI_61SECS 0x40
|
91 |
|
|
#define NTP_LI_59SECS 0x80
|
92 |
|
|
#define NTP_LI_ALARM 0xC0
|
93 |
|
|
|
94 |
|
|
/* Version Field [Bits 5:3] */
|
95 |
|
|
#define NTP_VERSION_GET(pkt) ((((pkt)->Control)>>3)&0x7)
|
96 |
|
|
#define NTP_VERSION_SET(ver) (((ver)&0x7)<<3)
|
97 |
|
|
|
98 |
|
|
/* Mode Field [Bits 2:0] */
|
99 |
|
|
#define NTP_MODE_RESERVED 0
|
100 |
|
|
#define NTP_MODE_SYMACTIVE 1 /* Symmetric Active */
|
101 |
|
|
#define NTP_MODE_SYMPASSIVE 2 /* Symmetric Passive */
|
102 |
|
|
#define NTP_MODE_CLIENT 3
|
103 |
|
|
#define NTP_MODE_SERVER 4
|
104 |
|
|
#define NTP_MODE_BROADCAST 5
|
105 |
|
|
#define NTP_MODE_NTPCTRL 6 /* Reserved for NTP control message */
|
106 |
|
|
#define NTP_MODE_PRIVATE 7 /* Reserved for private use */
|
107 |
|
|
#define NTP_MODE_GET(pkt) (((pkt)->Control)&0x7)
|
108 |
|
|
#define NTP_MODE_SET(mode) ((mode)&0x7)
|
109 |
|
|
|
110 |
|
|
/* Time Base Conversion Macros
|
111 |
|
|
*
|
112 |
|
|
* The NTP timebase is 00:00 Jan 1 1900. The local
|
113 |
|
|
* time base is 00:00 Jan 1 1970. Convert between
|
114 |
|
|
* these two by added or substracting 70 years
|
115 |
|
|
* worth of time. Note that 17 of these years were
|
116 |
|
|
* leap years.
|
117 |
|
|
*/
|
118 |
|
|
#define TIME_BASEDIFF ((((cyg_uint32)70*365 + 17) * 24*3600))
|
119 |
|
|
#define TIME_NTP_TO_LOCAL(t) ((t)-TIME_BASEDIFF)
|
120 |
|
|
#define TIME_LOCAL_TO_NTP(t) ((t)+TIME_BASEDIFF)
|
121 |
|
|
|
122 |
|
|
|
123 |
|
|
struct sntp_srv_s {
|
124 |
|
|
struct sockaddr addr;
|
125 |
|
|
int stratum;
|
126 |
|
|
int version;
|
127 |
|
|
cyg_uint32 timestamp;
|
128 |
|
|
};
|
129 |
|
|
static int sntp_initialized = 0;
|
130 |
|
|
|
131 |
|
|
|
132 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
133 |
|
|
/* When using SNTP unicast mode, sntp_servers
|
134 |
|
|
* points to an array of char pointers that
|
135 |
|
|
* specify NTP server addresses to send
|
136 |
|
|
* requests to. sntp_num_servers specifies
|
137 |
|
|
* the number of hostnames in the array.
|
138 |
|
|
*/
|
139 |
|
|
static struct sockaddr *sntp_servers = NULL;
|
140 |
|
|
static cyg_uint32 sntp_num_servers = 0;
|
141 |
|
|
static cyg_mutex_t sntp_mutex;
|
142 |
|
|
static time_t NextTimeUpdate = 0;
|
143 |
|
|
|
144 |
|
|
/* SNTP Timeouts
|
145 |
|
|
*
|
146 |
|
|
* SNTP_WAITPERIOD is the number of seconds to wait
|
147 |
|
|
* before retransmitting unanswered NTP requests
|
148 |
|
|
* whenever we are due for an update.
|
149 |
|
|
*
|
150 |
|
|
* SNTP_UPDATEPERIOD is the number of seconds to wait
|
151 |
|
|
* after we get a good time update before we feel
|
152 |
|
|
* like we should re-synchronize again with the
|
153 |
|
|
* time server.
|
154 |
|
|
*/
|
155 |
|
|
#define SNTP_WAITPERIOD 10 /* Wait period in seconds */
|
156 |
|
|
#define SNTP_UPDATEPERIOD (30*60) /* Update period in seconds */
|
157 |
|
|
|
158 |
|
|
#endif /* CYKPKG_NET_SNTP_UNICAST */
|
159 |
|
|
|
160 |
|
|
#ifndef CYGNUM_SNTP_STACK_SIZE
|
161 |
|
|
/* Use a stack size of at least CYGNUM_SNTP_STACK_SIZE_MIN, but not less than
|
162 |
|
|
* CYGNUM_HAL_STACK_SIZE_TYPICAL.
|
163 |
|
|
*/
|
164 |
|
|
#define CYGNUM_SNTP_STACK_SIZE_MIN 4096
|
165 |
|
|
#if (CYGNUM_HAL_STACK_SIZE_TYPICAL < CYGNUM_SNTP_STACK_SIZE_MIN)
|
166 |
|
|
#define CYGNUM_SNTP_STACK_SIZE CYGNUM_SNTP_STACK_SIZE_MIN
|
167 |
|
|
#else
|
168 |
|
|
#define CYGNUM_SNTP_STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
|
169 |
|
|
#endif
|
170 |
|
|
#endif /* CYGNUM_SNTP_STACK_SIZE */
|
171 |
|
|
|
172 |
|
|
/* Is the new server better than the current one? If its the same as
|
173 |
|
|
the current, its always better. If the stratum is lower its better.
|
174 |
|
|
If we have not heard from the old server for more than 10 minutes,
|
175 |
|
|
the new server is better. */
|
176 |
|
|
|
177 |
|
|
static int is_better(struct sntp_srv_s *newer, struct sntp_srv_s *old) {
|
178 |
|
|
|
179 |
|
|
time_t last_time, diff;
|
180 |
|
|
|
181 |
|
|
if (!memcmp(&newer->addr, &old->addr, newer->addr.sa_len)) return 1;
|
182 |
|
|
if (newer->stratum < old->stratum) return 1;
|
183 |
|
|
|
184 |
|
|
if (old->timestamp != 0xffffffff) {
|
185 |
|
|
last_time = TIME_NTP_TO_LOCAL(old->timestamp);
|
186 |
|
|
|
187 |
|
|
diff = time(NULL) - last_time;
|
188 |
|
|
if (diff > 600) return 1;
|
189 |
|
|
|
190 |
|
|
return 0;
|
191 |
|
|
}
|
192 |
|
|
return 1;
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
const struct in6_addr in6addr_ntp_multicast = IN6ADDR_NTP_MULTICAST;
|
196 |
|
|
|
197 |
|
|
static void sntp_fn(cyg_addrword_t data)
|
198 |
|
|
{
|
199 |
|
|
int fd;
|
200 |
|
|
int ret;
|
201 |
|
|
struct sockaddr_in local;
|
202 |
|
|
struct servent *serv;
|
203 |
|
|
NTP_PACKET ntp_pkt;
|
204 |
|
|
struct sntp_srv_s new_srv;
|
205 |
|
|
struct sntp_srv_s best_srv;
|
206 |
|
|
int mode;
|
207 |
|
|
socklen_t len;
|
208 |
|
|
time_t new_time, current_time, diff;
|
209 |
|
|
fd_set readfds;
|
210 |
|
|
int n;
|
211 |
|
|
#ifdef CYGPKG_NET_INET6
|
212 |
|
|
int fd6 = -1;
|
213 |
|
|
struct ipv6_mreq mreq;
|
214 |
|
|
struct sockaddr_in6 local6;
|
215 |
|
|
#endif
|
216 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
217 |
|
|
int i;
|
218 |
|
|
struct timeval timeout;
|
219 |
|
|
#endif /* CYGPKG_NET_SNTP_UNICAST */
|
220 |
|
|
struct timeval *ptimeout = NULL;
|
221 |
|
|
|
222 |
|
|
memset(&best_srv,0xff,sizeof(best_srv));
|
223 |
|
|
|
224 |
|
|
fd = socket(AF_INET,SOCK_DGRAM,0);
|
225 |
|
|
CYG_ASSERT(-1 != fd,"Failed to open socket");
|
226 |
|
|
|
227 |
|
|
serv = getservbyname("ntp","udp");
|
228 |
|
|
CYG_ASSERT(serv,"getservbyname(sntp,udp)");
|
229 |
|
|
|
230 |
|
|
memset(&local,0,sizeof(local));
|
231 |
|
|
local.sin_family = AF_INET;
|
232 |
|
|
local.sin_len = sizeof(local);
|
233 |
|
|
local.sin_port = serv->s_port;
|
234 |
|
|
local.sin_addr.s_addr = INADDR_ANY;
|
235 |
|
|
|
236 |
|
|
ret=bind(fd,(struct sockaddr *)&local,sizeof(local));
|
237 |
|
|
CYG_ASSERT(0 == ret, "Bind failed");
|
238 |
|
|
|
239 |
|
|
n = fd;
|
240 |
|
|
|
241 |
|
|
#ifdef CYGPKG_NET_INET6
|
242 |
|
|
fd6 = socket(AF_INET6, SOCK_DGRAM,0);
|
243 |
|
|
CYG_ASSERT(-1 != fd,"Failed to open socket");
|
244 |
|
|
mreq.ipv6mr_multiaddr = in6addr_ntp_multicast;
|
245 |
|
|
mreq.ipv6mr_interface = 0;
|
246 |
|
|
|
247 |
|
|
/* Join the well-known NTP multicast groups. We will
|
248 |
|
|
* try to join the link-local, site-local, and global
|
249 |
|
|
* unicast groups.
|
250 |
|
|
*
|
251 |
|
|
* Note that we skip the node-local group since it
|
252 |
|
|
* doesn't make any sense to join that group. If we
|
253 |
|
|
* had an NTP server running on the local node, we
|
254 |
|
|
* wouldn't need to have an NTP client get the time
|
255 |
|
|
* from it!
|
256 |
|
|
*/
|
257 |
|
|
#ifdef CYGHWR_NET_DRIVER_ETH0
|
258 |
|
|
// Link-Local
|
259 |
|
|
mreq.ipv6mr_multiaddr.s6_addr[1]=0x02;
|
260 |
|
|
mreq.ipv6mr_interface = if_nametoindex("eth0");
|
261 |
|
|
if (mreq.ipv6mr_interface != 0 ) {
|
262 |
|
|
ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
263 |
|
|
CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Link-Local eth0");
|
264 |
|
|
}
|
265 |
|
|
#endif
|
266 |
|
|
#ifdef CYGHWR_NET_DRIVER_ETH1
|
267 |
|
|
// Link-Local
|
268 |
|
|
mreq.ipv6mr_multiaddr.s6_addr[1]=0x02;
|
269 |
|
|
mreq.ipv6mr_interface = if_nametoindex("eth1");
|
270 |
|
|
if (mreq.ipv6mr_interface != 0 ) {
|
271 |
|
|
ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
272 |
|
|
CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Link-Local eth1");
|
273 |
|
|
}
|
274 |
|
|
#endif
|
275 |
|
|
|
276 |
|
|
// Site-Local
|
277 |
|
|
mreq.ipv6mr_multiaddr.s6_addr[1]=0x05;
|
278 |
|
|
ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
279 |
|
|
CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Site-Local");
|
280 |
|
|
|
281 |
|
|
// Global
|
282 |
|
|
mreq.ipv6mr_multiaddr.s6_addr[1]=0x0e;
|
283 |
|
|
ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
284 |
|
|
CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Global");
|
285 |
|
|
|
286 |
|
|
memset(&local6,0,sizeof(local6));
|
287 |
|
|
local6.sin6_family = AF_INET6;
|
288 |
|
|
local6.sin6_len = sizeof(local6);
|
289 |
|
|
local6.sin6_port = serv->s_port;
|
290 |
|
|
local6.sin6_addr = in6addr_any;
|
291 |
|
|
|
292 |
|
|
ret = bind(fd6, (struct sockaddr *)&local6,sizeof(local6));
|
293 |
|
|
CYG_ASSERT(0 == ret, "Bind6 failed");
|
294 |
|
|
|
295 |
|
|
n = (n > fd6 ? n : fd6);
|
296 |
|
|
#endif
|
297 |
|
|
|
298 |
|
|
while (1) {
|
299 |
|
|
FD_ZERO(&readfds);
|
300 |
|
|
FD_SET(fd,&readfds);
|
301 |
|
|
#ifdef CYGPKG_NET_INET6
|
302 |
|
|
FD_SET(fd6,&readfds);
|
303 |
|
|
#endif
|
304 |
|
|
|
305 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
306 |
|
|
/* By default, we will let select() wait
|
307 |
|
|
* for SNTP_WAITPERIOD to receive a packet. This
|
308 |
|
|
* allows us to periodically wake up and check
|
309 |
|
|
* if new servers have been configured. However,
|
310 |
|
|
* if we are waiting to send an update request,
|
311 |
|
|
* we will set ptimeout to something more
|
312 |
|
|
* reasonable below.
|
313 |
|
|
*/
|
314 |
|
|
timeout.tv_sec = SNTP_WAITPERIOD;
|
315 |
|
|
timeout.tv_usec = 0;
|
316 |
|
|
ptimeout = &timeout;
|
317 |
|
|
|
318 |
|
|
/* If we've already set the time, then
|
319 |
|
|
* check to see if it's time to try and
|
320 |
|
|
* update it.
|
321 |
|
|
*/
|
322 |
|
|
if (NextTimeUpdate != 0)
|
323 |
|
|
{
|
324 |
|
|
current_time = time(NULL);
|
325 |
|
|
if (current_time < NextTimeUpdate)
|
326 |
|
|
{
|
327 |
|
|
/* Set the select() timeout to wake us
|
328 |
|
|
* up when it's time to send more
|
329 |
|
|
* requests.
|
330 |
|
|
*/
|
331 |
|
|
timeout.tv_sec = (SNTP_WAITPERIOD > (NextTimeUpdate - current_time)?
|
332 |
|
|
(NextTimeUpdate - current_time):SNTP_WAITPERIOD);
|
333 |
|
|
} else {
|
334 |
|
|
/* It's already time for us to update our time */
|
335 |
|
|
NextTimeUpdate = 0;
|
336 |
|
|
}
|
337 |
|
|
}
|
338 |
|
|
|
339 |
|
|
/* If we need to update our time and we have
|
340 |
|
|
* a list of NTP servers, then send out some
|
341 |
|
|
* time requests.
|
342 |
|
|
*/
|
343 |
|
|
if (NextTimeUpdate == 0 && (sntp_num_servers > 0))
|
344 |
|
|
{
|
345 |
|
|
/* Send an NTP request to each NTP server
|
346 |
|
|
* in our server list. Use version 3
|
347 |
|
|
* for v3 and v4 compatibility.
|
348 |
|
|
*/
|
349 |
|
|
memset(&ntp_pkt, 0, sizeof(ntp_pkt));
|
350 |
|
|
ntp_pkt.Control =
|
351 |
|
|
NTP_LI_NOLEAP |
|
352 |
|
|
NTP_MODE_SET(NTP_MODE_CLIENT) |
|
353 |
|
|
NTP_VERSION_SET(3);
|
354 |
|
|
|
355 |
|
|
/* Send a request packet to each of our
|
356 |
|
|
* configured servers.
|
357 |
|
|
*/
|
358 |
|
|
cyg_mutex_lock(&sntp_mutex);
|
359 |
|
|
for (i = 0; i < sntp_num_servers; i++)
|
360 |
|
|
{
|
361 |
|
|
/* Send the request packet using the
|
362 |
|
|
* appropriate protocol.
|
363 |
|
|
*/
|
364 |
|
|
ntp_pkt.TransmitTimestamp.Seconds =
|
365 |
|
|
htonl(TIME_LOCAL_TO_NTP(time(NULL)));
|
366 |
|
|
if (sntp_servers[i].sa_family == AF_INET)
|
367 |
|
|
{
|
368 |
|
|
sendto(fd, &ntp_pkt, sizeof(ntp_pkt), 0,
|
369 |
|
|
&sntp_servers[i], sntp_servers[i].sa_len);
|
370 |
|
|
#ifdef CYGPKG_NET_INET6
|
371 |
|
|
} else if (sntp_servers[i].sa_family == AF_INET6) {
|
372 |
|
|
sendto(fd6, &ntp_pkt, sizeof(ntp_pkt), 0,
|
373 |
|
|
&sntp_servers[i], sntp_servers[i].sa_len);
|
374 |
|
|
#endif
|
375 |
|
|
}
|
376 |
|
|
}
|
377 |
|
|
cyg_mutex_unlock(&sntp_mutex);
|
378 |
|
|
|
379 |
|
|
/* Set the NextTimeUpdate so that we don't
|
380 |
|
|
* send any more requests until the next
|
381 |
|
|
* poll period. And we've already configured
|
382 |
|
|
* the select() timeout above to wait for
|
383 |
|
|
* replies.
|
384 |
|
|
*/
|
385 |
|
|
NextTimeUpdate = time(NULL) + SNTP_WAITPERIOD;
|
386 |
|
|
}
|
387 |
|
|
#endif /* CYGPKG_NET_SNTP_UNICAST */
|
388 |
|
|
|
389 |
|
|
ret = select(n+1, &readfds, NULL, NULL, ptimeout);
|
390 |
|
|
CYG_ASSERT(-1 != ret, "Select");
|
391 |
|
|
|
392 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
393 |
|
|
/* If we timed out, then try resending requests */
|
394 |
|
|
if (ret == 0)
|
395 |
|
|
continue;
|
396 |
|
|
#endif /* CYGPKG_NET_SNTP_UNICAST */
|
397 |
|
|
|
398 |
|
|
len = sizeof(new_srv.addr);
|
399 |
|
|
if (FD_ISSET(fd,&readfds)) {
|
400 |
|
|
ret=recvfrom(fd,&ntp_pkt,sizeof(ntp_pkt),0,(struct sockaddr *)&new_srv.addr,&len);
|
401 |
|
|
}
|
402 |
|
|
#ifdef CYGPKG_NET_INET6
|
403 |
|
|
if (FD_ISSET(fd6,&readfds)) {
|
404 |
|
|
ret=recvfrom(fd6,&ntp_pkt,sizeof(ntp_pkt),0,(struct sockaddr *)&new_srv.addr,&len);
|
405 |
|
|
}
|
406 |
|
|
#endif
|
407 |
|
|
CYG_ASSERT(0 < ret,"recvfrom");
|
408 |
|
|
|
409 |
|
|
/* We expect at least enough bytes to fill the buffer */
|
410 |
|
|
if (ret < NTP_PACKET_MINLEN)
|
411 |
|
|
continue;
|
412 |
|
|
|
413 |
|
|
new_srv.version = NTP_VERSION_GET(&ntp_pkt);
|
414 |
|
|
new_srv.stratum = ntp_pkt.Stratum;
|
415 |
|
|
new_srv.timestamp = ntohl(ntp_pkt.TransmitTimestamp.Seconds);
|
416 |
|
|
mode = NTP_MODE_GET(&ntp_pkt);
|
417 |
|
|
|
418 |
|
|
/* Only support protocol versions 3 or 4 */
|
419 |
|
|
if (new_srv.version < 3 || new_srv.version > 4) {
|
420 |
|
|
CYG_TRACE1(1, "Unsupported version of NTP. Version %d",new_srv.version);
|
421 |
|
|
continue;
|
422 |
|
|
}
|
423 |
|
|
|
424 |
|
|
/* Only process broadcast and server packets */
|
425 |
|
|
if (mode != NTP_MODE_BROADCAST && mode != NTP_MODE_SERVER)
|
426 |
|
|
continue;
|
427 |
|
|
|
428 |
|
|
/* Is the packet from a better server than our current one */
|
429 |
|
|
if (is_better(&new_srv,&best_srv)) {
|
430 |
|
|
best_srv = new_srv;
|
431 |
|
|
|
432 |
|
|
/* Work out the difference between server and our time.
|
433 |
|
|
* TODO: Implement RFC2030 recommendations for
|
434 |
|
|
* calculating propagation delay between the client
|
435 |
|
|
* and server.
|
436 |
|
|
*/
|
437 |
|
|
new_time = TIME_NTP_TO_LOCAL(best_srv.timestamp);
|
438 |
|
|
current_time = time(NULL);
|
439 |
|
|
diff = current_time - new_time;
|
440 |
|
|
|
441 |
|
|
if (diff < 0)
|
442 |
|
|
diff = -diff;
|
443 |
|
|
|
444 |
|
|
if (diff > 2)
|
445 |
|
|
cyg_libc_time_settime(new_time);
|
446 |
|
|
}
|
447 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
448 |
|
|
NextTimeUpdate = time(NULL) + SNTP_UPDATEPERIOD;
|
449 |
|
|
#endif
|
450 |
|
|
}
|
451 |
|
|
}
|
452 |
|
|
|
453 |
|
|
/* Start the SNTP server */
|
454 |
|
|
void cyg_sntp_start(void) {
|
455 |
|
|
|
456 |
|
|
static char sntp_stack[CYGNUM_SNTP_STACK_SIZE];
|
457 |
|
|
static cyg_thread sntp_thread_data;
|
458 |
|
|
static cyg_handle_t sntp_handle;
|
459 |
|
|
|
460 |
|
|
/* Only initialize things once */
|
461 |
|
|
if (sntp_initialized)
|
462 |
|
|
return;
|
463 |
|
|
sntp_initialized = 1;
|
464 |
|
|
|
465 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
466 |
|
|
/* Initialize the SNTP mutex */
|
467 |
|
|
cyg_mutex_init(&sntp_mutex);
|
468 |
|
|
#endif
|
469 |
|
|
|
470 |
|
|
cyg_thread_create(CYGPKG_NET_THREAD_PRIORITY+1,
|
471 |
|
|
sntp_fn, // entry
|
472 |
|
|
0, // entry parameter
|
473 |
|
|
"SNTP Client", // Name
|
474 |
|
|
&sntp_stack, // stack
|
475 |
|
|
sizeof(sntp_stack), // stack size
|
476 |
|
|
&sntp_handle, // Handle
|
477 |
|
|
&sntp_thread_data); // Thread data structure
|
478 |
|
|
|
479 |
|
|
cyg_thread_resume(sntp_handle);
|
480 |
|
|
}
|
481 |
|
|
|
482 |
|
|
#ifdef CYGPKG_NET_SNTP_UNICAST
|
483 |
|
|
/*
|
484 |
|
|
* FUNCTION cyg_sntp_set_servers
|
485 |
|
|
*
|
486 |
|
|
* DESCRIPTION
|
487 |
|
|
* Sets the list of SNTP/NTP servers to use
|
488 |
|
|
* for SNTP unicast requests. The list is
|
489 |
|
|
* specified as a list of sockaddr structures
|
490 |
|
|
* and can contain both IPv4 and IPv6
|
491 |
|
|
* addresses and UDP port numbers.
|
492 |
|
|
*
|
493 |
|
|
* The server_list array must be maintained
|
494 |
|
|
* by the caller and must not be modified after
|
495 |
|
|
* it is registered by this function. The
|
496 |
|
|
* array can be unregistered by calling this
|
497 |
|
|
* function again with different parameters.
|
498 |
|
|
*
|
499 |
|
|
* NOTE: If cyg_sntp_start() has not been called
|
500 |
|
|
* already, and this function is called with a
|
501 |
|
|
* list of 1 or more servers, then cyg_sntp_start()
|
502 |
|
|
* will be called by this function to start the client.
|
503 |
|
|
*
|
504 |
|
|
* PARAMETERS
|
505 |
|
|
* server_list - Array of IPv4 and/or IPv6 sockaddr's
|
506 |
|
|
* num_servers - Number of sockaddr's in array (0 to disable)
|
507 |
|
|
*
|
508 |
|
|
* RETURN VALUES
|
509 |
|
|
* None
|
510 |
|
|
*/
|
511 |
|
|
void cyg_sntp_set_servers(struct sockaddr *server_list,
|
512 |
|
|
cyg_uint32 num_servers)
|
513 |
|
|
{
|
514 |
|
|
/* If we haven't already started the SNTP client, then
|
515 |
|
|
* start it now.
|
516 |
|
|
*/
|
517 |
|
|
if (!sntp_initialized)
|
518 |
|
|
{
|
519 |
|
|
/* If we haven't started already and we don't
|
520 |
|
|
* have a list of servers, then don't start
|
521 |
|
|
* anything up.
|
522 |
|
|
*/
|
523 |
|
|
if (num_servers == 0)
|
524 |
|
|
return;
|
525 |
|
|
cyg_sntp_start();
|
526 |
|
|
}
|
527 |
|
|
|
528 |
|
|
/* Get the server list mutex */
|
529 |
|
|
cyg_mutex_lock(&sntp_mutex);
|
530 |
|
|
|
531 |
|
|
/* Record the new server list */
|
532 |
|
|
sntp_num_servers = num_servers;
|
533 |
|
|
if (num_servers == 0) {
|
534 |
|
|
server_list = NULL;
|
535 |
|
|
} else {
|
536 |
|
|
/* reset the waiting time to force a new update <= SNTP_WAITPERIOD*/
|
537 |
|
|
NextTimeUpdate = 0;
|
538 |
|
|
}
|
539 |
|
|
sntp_servers = server_list;
|
540 |
|
|
|
541 |
|
|
/* Free the mutex */
|
542 |
|
|
cyg_mutex_unlock(&sntp_mutex);
|
543 |
|
|
}
|
544 |
|
|
#endif /* CYGPKG_NET_SNTP_UNICAST */
|
545 |
|
|
|
546 |
|
|
|
547 |
|
|
|
548 |
|
|
|