5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netinet/ip.h>
36 #include <arpa/inet.h>
45 } __attribute__ ((packed));
50 } __attribute__ ((packed));
53 uint8_t flags; /* Mode, version and leap indicator */
54 uint8_t stratum; /* Stratum details */
55 int8_t poll; /* Maximum interval in log2 seconds */
56 int8_t precision; /* Clock precision in log2 seconds */
57 struct ntp_short rootdelay; /* Root delay */
58 struct ntp_short rootdisp; /* Root dispersion */
59 uint32_t refid; /* Reference ID */
60 struct ntp_time reftime; /* Reference timestamp */
61 struct ntp_time orgtime; /* Origin timestamp */
62 struct ntp_time rectime; /* Receive timestamp */
63 struct ntp_time xmttime; /* Transmit timestamp */
64 } __attribute__ ((packed));
66 #define OFFSET_1900_1970 2208988800UL /* 1970 - 1900 in seconds */
68 #define STEPTIME_MIN_OFFSET 0.128
70 #define LOGTOD(a) ((a) < 0 ? 1. / (1L << -(a)) : 1L << (int)(a))
72 #define NTP_FLAG_LI_SHIFT 6
73 #define NTP_FLAG_LI_MASK 0x3
74 #define NTP_FLAG_LI_NOWARNING 0x0
75 #define NTP_FLAG_LI_ADDSECOND 0x1
76 #define NTP_FLAG_LI_DELSECOND 0x2
77 #define NTP_FLAG_LI_NOTINSYNC 0x3
79 #define NTP_FLAG_VN_SHIFT 3
80 #define NTP_FLAG_VN_MASK 0x7
82 #define NTP_FLAG_MD_SHIFT 0
83 #define NTP_FLAG_MD_MASK 0x7
84 #define NTP_FLAG_MD_UNSPEC 0
85 #define NTP_FLAG_MD_ACTIVE 1
86 #define NTP_FLAG_MD_PASSIVE 2
87 #define NTP_FLAG_MD_CLIENT 3
88 #define NTP_FLAG_MD_SERVER 4
89 #define NTP_FLAG_MD_BROADCAST 5
90 #define NTP_FLAG_MD_CONTROL 6
91 #define NTP_FLAG_MD_PRIVATE 7
93 #define NTP_FLAGS_ENCODE(li, vn, md) ((uint8_t)( \
94 (((li) & NTP_FLAG_LI_MASK) << NTP_FLAG_LI_SHIFT) | \
95 (((vn) & NTP_FLAG_VN_MASK) << NTP_FLAG_VN_SHIFT) | \
96 (((md) & NTP_FLAG_MD_MASK) << NTP_FLAG_MD_SHIFT)))
98 #define NTP_FLAGS_LI_DECODE(flags) ((uint8_t)(((flags) >> NTP_FLAG_LI_SHIFT) & NTP_FLAG_LI_MASK))
99 #define NTP_FLAGS_VN_DECODE(flags) ((uint8_t)(((flags) >> NTP_FLAG_VN_SHIFT) & NTP_FLAG_VN_MASK))
100 #define NTP_FLAGS_MD_DECODE(flags) ((uint8_t)(((flags) >> NTP_FLAG_MD_SHIFT) & NTP_FLAG_MD_MASK))
102 static guint channel_watch = 0;
103 static struct timeval transmit_timeval;
104 static int transmit_fd = 0;
106 static char *timeserver = NULL;
107 static gint poll_id = 0;
108 static gint timeout_id = 0;
110 static void send_packet(int fd, const char *server)
113 struct sockaddr_in addr;
116 memset(&msg, 0, sizeof(msg));
117 msg.flags = NTP_FLAGS_ENCODE(NTP_FLAG_LI_NOTINSYNC, 4, NTP_FLAG_MD_CLIENT);
119 msg.poll = 10; // max
121 memset(&addr, 0, sizeof(addr));
122 addr.sin_family = AF_INET;
123 addr.sin_port = htons(123);
124 addr.sin_addr.s_addr = inet_addr(server);
126 gettimeofday(&transmit_timeval, NULL);
128 msg.xmttime.seconds = htonl(transmit_timeval.tv_sec + OFFSET_1900_1970);
129 msg.xmttime.fraction = htonl(transmit_timeval.tv_usec * 1000);
131 len = sendto(fd, &msg, sizeof(msg), MSG_DONTWAIT,
132 &addr, sizeof(addr));
134 connman_error("Time request for server %s failed (%d/%s)",
135 server, errno, strerror(errno));
137 if (errno == ENETUNREACH)
138 __connman_timeserver_sync_next();
143 if (len != sizeof(msg)) {
144 connman_error("Broken time request for server %s", server);
149 static gboolean next_server(gpointer user_data)
151 if (timeserver != NULL) {
156 __connman_timeserver_sync_next();
161 static gboolean next_poll(gpointer user_data)
163 if (timeserver == NULL || transmit_fd == 0)
166 send_packet(transmit_fd, timeserver);
171 static void decode_msg(void *base, size_t len, struct timeval *tv)
173 struct ntp_msg *msg = base;
174 double org, rec, xmt, dst;
175 double delay, offset;
176 static guint transmit_delay;
178 if (len < sizeof(*msg)) {
179 connman_error("Invalid response from time server");
184 connman_error("Invalid packet timestamp from time server");
188 DBG("flags : 0x%02x", msg->flags);
189 DBG("stratum : %u", msg->stratum);
190 DBG("poll : %f seconds (%d)",
191 LOGTOD(msg->poll), msg->poll);
192 DBG("precision : %f seconds (%d)",
193 LOGTOD(msg->precision), msg->precision);
194 DBG("root delay : %u seconds (fraction %u)",
195 msg->rootdelay.seconds, msg->rootdelay.fraction);
196 DBG("root disp. : %u seconds (fraction %u)",
197 msg->rootdisp.seconds, msg->rootdisp.fraction);
198 DBG("reference : 0x%04x", msg->refid);
200 transmit_delay = LOGTOD(msg->poll);
202 if (NTP_FLAGS_LI_DECODE(msg->flags) == NTP_FLAG_LI_NOTINSYNC) {
203 DBG("ignoring unsynchronized peer");
207 if (NTP_FLAGS_VN_DECODE(msg->flags) != 4) {
208 DBG("unsupported version %d", NTP_FLAGS_VN_DECODE(msg->flags));
212 if (NTP_FLAGS_MD_DECODE(msg->flags) != NTP_FLAG_MD_SERVER) {
213 DBG("unsupported mode %d", NTP_FLAGS_MD_DECODE(msg->flags));
217 org = transmit_timeval.tv_sec +
218 (1.0e-6 * transmit_timeval.tv_usec) + OFFSET_1900_1970;
219 rec = ntohl(msg->rectime.seconds) +
220 ((double) ntohl(msg->rectime.fraction) / UINT_MAX);
221 xmt = ntohl(msg->xmttime.seconds) +
222 ((double) ntohl(msg->xmttime.fraction) / UINT_MAX);
223 dst = tv->tv_sec + (1.0e-6 * tv->tv_usec) + OFFSET_1900_1970;
225 DBG("org=%f rec=%f xmt=%f dst=%f", org, rec, xmt, dst);
227 offset = ((rec - org) + (xmt - dst)) / 2;
228 delay = (dst - org) - (xmt - rec);
230 DBG("offset=%f delay=%f", offset, delay);
232 /* Remove the timeout, as timeserver has responded */
234 g_source_remove(timeout_id);
237 * Now poll the server every transmit_delay seconds
238 * for time correction.
241 g_source_remove(poll_id);
243 DBG("Timeserver %s, next sync in %d seconds", timeserver, transmit_delay);
245 poll_id = g_timeout_add_seconds(transmit_delay, next_poll, NULL);
247 connman_info("ntp: time slew %+.6f s", offset);
249 if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) {
252 adj.tv_sec = (long) offset;
253 adj.tv_usec = (offset - adj.tv_sec) * 1000000;
255 DBG("adjusting time");
257 if (adjtime(&adj, &adj) < 0) {
258 connman_error("Failed to adjust time");
262 DBG("%lu seconds, %lu msecs", adj.tv_sec, adj.tv_usec);
267 gettimeofday(&cur, NULL);
268 dtime = offset + cur.tv_sec + 1.0e-6 * cur.tv_usec;
269 cur.tv_sec = (long) dtime;
270 cur.tv_usec = (dtime - cur.tv_sec) * 1000000;
274 if (settimeofday(&cur, NULL) < 0) {
275 connman_error("Failed to set time");
279 DBG("%lu seconds, %lu msecs", cur.tv_sec, cur.tv_usec);
283 static gboolean received_data(GIOChannel *channel, GIOCondition condition,
286 unsigned char buf[128];
289 struct cmsghdr *cmsg;
295 if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
296 connman_error("Problem with timer server channel");
301 fd = g_io_channel_unix_get_fd(channel);
304 iov.iov_len = sizeof(buf);
306 memset(&msg, 0, sizeof(msg));
309 msg.msg_control = aux;
310 msg.msg_controllen = sizeof(aux);
312 len = recvmsg(fd, &msg, MSG_DONTWAIT);
318 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
319 if (cmsg->cmsg_level != SOL_SOCKET)
322 switch (cmsg->cmsg_type) {
324 tv = (struct timeval *) CMSG_DATA(cmsg);
329 decode_msg(iov.iov_base, iov.iov_len, tv);
334 static void start_ntp(char *server)
337 struct sockaddr_in addr;
338 int tos = IPTOS_LOWDELAY, timestamp = 1;
343 DBG("server %s", server);
345 if (channel_watch > 0)
348 transmit_fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
349 if (transmit_fd < 0) {
350 connman_error("Failed to open time server socket");
354 memset(&addr, 0, sizeof(addr));
355 addr.sin_family = AF_INET;
357 if (bind(transmit_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
358 connman_error("Failed to bind time server socket");
363 if (setsockopt(transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
364 connman_error("Failed to set type of service option");
369 if (setsockopt(transmit_fd, SOL_SOCKET, SO_TIMESTAMP, ×tamp,
370 sizeof(timestamp)) < 0) {
371 connman_error("Failed to enable timestamp support");
376 channel = g_io_channel_unix_new(transmit_fd);
377 if (channel == NULL) {
382 g_io_channel_set_encoding(channel, NULL, NULL);
383 g_io_channel_set_buffered(channel, FALSE);
385 g_io_channel_set_close_on_unref(channel, TRUE);
387 channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
388 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
389 received_data, NULL, NULL);
391 g_io_channel_unref(channel);
394 send_packet(transmit_fd, server);
397 int __connman_ntp_start(char *server)
404 if (timeserver != NULL)
407 timeserver = g_strdup(server);
409 start_ntp(timeserver);
412 * Add a fallback timeout , preferably short, 5 sec here,
413 * to fallback on the next server.
416 timeout_id = g_timeout_add_seconds(5, next_server, NULL);
421 void __connman_ntp_stop()
426 g_source_remove(poll_id);
429 g_source_remove(timeout_id);
431 if (channel_watch > 0) {
432 g_source_remove(channel_watch);
437 if (timeserver != NULL) {