1*2d44acdfSotto /* $OpenBSD: ntp.c,v 1.37 2023/11/12 18:53:22 otto Exp $ */
24142bea0Sjakob
34142bea0Sjakob /*
44142bea0Sjakob * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
54142bea0Sjakob * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved.
62f6e235dSjakob * Copyright (c) 2002 by Thorsten "mirabile" Glaser.
74142bea0Sjakob *
84142bea0Sjakob * Redistribution and use in source and binary forms, with or without
94142bea0Sjakob * modification, are permitted provided that the following conditions
104142bea0Sjakob * are met:
114142bea0Sjakob * 1. Redistributions of source code must retain the above copyright
124142bea0Sjakob * notice, this list of conditions and the following disclaimer.
134142bea0Sjakob * 2. Redistributions in binary form must reproduce the above copyright
144142bea0Sjakob * notice, this list of conditions and the following disclaimer in the
154142bea0Sjakob * documentation and/or other materials provided with the distribution.
164142bea0Sjakob * 3. Neither the name of the author nor the university may be used to
174142bea0Sjakob * endorse or promote products derived from this software without
184142bea0Sjakob * specific prior written permission.
194142bea0Sjakob *
204142bea0Sjakob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
214142bea0Sjakob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
224142bea0Sjakob * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
234142bea0Sjakob * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
244142bea0Sjakob * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
254142bea0Sjakob * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
264142bea0Sjakob * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
274142bea0Sjakob * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
284142bea0Sjakob * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
294142bea0Sjakob * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
304142bea0Sjakob */
314142bea0Sjakob
324142bea0Sjakob #include <sys/socket.h>
334142bea0Sjakob #include <sys/time.h>
344142bea0Sjakob #include <netinet/in.h>
354142bea0Sjakob #include <arpa/inet.h>
364142bea0Sjakob
374142bea0Sjakob #include <ctype.h>
384142bea0Sjakob #include <err.h>
394142bea0Sjakob #include <errno.h>
404142bea0Sjakob #include <fcntl.h>
414142bea0Sjakob #include <float.h>
424142bea0Sjakob #include <limits.h>
434142bea0Sjakob #include <math.h>
444142bea0Sjakob #include <netdb.h>
45*2d44acdfSotto #include <stdint.h>
464142bea0Sjakob #include <stdio.h>
474142bea0Sjakob #include <stdlib.h>
484142bea0Sjakob #include <string.h>
494142bea0Sjakob #include <time.h>
504d79ab39Sderaadt #include <poll.h>
514142bea0Sjakob #include <unistd.h>
52b9ce4fd1Sjakob
532f6e235dSjakob #include "ntpleaps.h"
544142bea0Sjakob
55eea542eaSderaadt /*
56eea542eaSderaadt * NTP definitions. Note that these assume 8-bit bytes - sigh. There
574142bea0Sjakob * is little point in parameterising everything, as it is neither
584142bea0Sjakob * feasible nor useful. It would be very useful if more fields could
594142bea0Sjakob * be defined as unspecified. The NTP packet-handling routines
60eea542eaSderaadt * contain a lot of extra assumptions.
61eea542eaSderaadt */
624142bea0Sjakob
634142bea0Sjakob #define JAN_1970 2208988800.0 /* 1970 - 1900 in seconds */
644142bea0Sjakob #define NTP_SCALE 4294967296.0 /* 2^32, of course! */
654142bea0Sjakob
664142bea0Sjakob #define NTP_MODE_CLIENT 3 /* NTP client mode */
674142bea0Sjakob #define NTP_MODE_SERVER 4 /* NTP server mode */
684844c6b7Salexander #define NTP_VERSION 4 /* The current version */
694f8983dbSsthen #define NTP_VERSION_MIN 1 /* The minimum valid version */
704142bea0Sjakob #define NTP_VERSION_MAX 4 /* The maximum valid version */
714844c6b7Salexander #define NTP_STRATUM_MAX 14 /* The maximum valid stratum */
724142bea0Sjakob #define NTP_INSANITY 3600.0 /* Errors beyond this are hopeless */
734142bea0Sjakob
744142bea0Sjakob #define NTP_PACKET_MIN 48 /* Without authentication */
754142bea0Sjakob #define NTP_PACKET_MAX 68 /* With authentication (ignored) */
764142bea0Sjakob
774142bea0Sjakob #define NTP_DISP_FIELD 8 /* Offset of dispersion field */
784142bea0Sjakob #define NTP_REFERENCE 16 /* Offset of reference timestamp */
794142bea0Sjakob #define NTP_ORIGINATE 24 /* Offset of originate timestamp */
804142bea0Sjakob #define NTP_RECEIVE 32 /* Offset of receive timestamp */
814142bea0Sjakob #define NTP_TRANSMIT 40 /* Offset of transmit timestamp */
824142bea0Sjakob
835d5f61deSjakob #define STATUS_NOWARNING 0 /* No Leap Indicator */
845d5f61deSjakob #define STATUS_LEAPHIGH 1 /* Last Minute Has 61 Seconds */
855d5f61deSjakob #define STATUS_LEAPLOW 2 /* Last Minute Has 59 Seconds */
865d5f61deSjakob #define STATUS_ALARM 3 /* Server Clock Not Synchronized */
875d5f61deSjakob
884142bea0Sjakob #define MAX_QUERIES 25
894142bea0Sjakob #define MAX_DELAY 15
904142bea0Sjakob
914142bea0Sjakob #define MILLION_L 1000000l /* For conversion to/from timeval */
924142bea0Sjakob #define MILLION_D 1.0e6 /* Must be equal to MILLION_L */
934142bea0Sjakob
94*2d44acdfSotto /*
95*2d44acdfSotto * The era we're in if we have no reason to assume otherwise.
96*2d44acdfSotto * If unpack_ntp() sees a small offset the era is is assumed to be
97*2d44acdfSotto * NTP_ERA + 1.
98*2d44acdfSotto * Once the actual year is well into era 1, (after 2036) define NTP_ERA to 1
99*2d44acdfSotto * and adapt (disable) the increments in unpack_ntp().
100*2d44acdfSotto * Once more than half of era 1 has elapsed (after 2104), re-inroduce the test
101*2d44acdfSotto * to move to era 2 if offset is small, repeat for each half era.
102*2d44acdfSotto */
103*2d44acdfSotto #define NTP_ERA 0
104*2d44acdfSotto
105*2d44acdfSotto #define SECS_IN_ERA (UINT32_MAX + 1ULL)
106*2d44acdfSotto
107*2d44acdfSotto
1084142bea0Sjakob struct ntp_data {
10904ef39a3Sderaadt u_char status;
11004ef39a3Sderaadt u_char version;
11104ef39a3Sderaadt u_char mode;
11204ef39a3Sderaadt u_char stratum;
1134142bea0Sjakob double receive;
1144142bea0Sjakob double transmit;
1154142bea0Sjakob double current;
1161346900eSjakob u_int64_t recvck;
1174844c6b7Salexander
1184844c6b7Salexander /* Local State */
1194844c6b7Salexander double originate;
1204844c6b7Salexander u_int64_t xmitck;
1214142bea0Sjakob };
1224142bea0Sjakob
12322d417c3Sjakob void ntp_client(const char *, int, struct timeval *, struct timeval *, int);
1244142bea0Sjakob int sync_ntp(int, const struct sockaddr *, double *, double *);
1254844c6b7Salexander int write_packet(int, struct ntp_data *);
1264844c6b7Salexander int read_packet(int, struct ntp_data *, double *, double *);
1274844c6b7Salexander void unpack_ntp(struct ntp_data *, u_char *);
1284142bea0Sjakob double current_time(double);
1294142bea0Sjakob void create_timeval(double, struct timeval *, struct timeval *);
1304142bea0Sjakob
1317ad2fb6cSderaadt #ifdef DEBUG
1324844c6b7Salexander void print_packet(const struct ntp_data *);
1334844c6b7Salexander #endif
1344844c6b7Salexander
135246969aeSjakob int corrleaps;
1367c465852Sjakob
1374142bea0Sjakob void
ntp_client(const char * hostname,int family,struct timeval * new,struct timeval * adjust,int leapflag)13822d417c3Sjakob ntp_client(const char *hostname, int family, struct timeval *new,
139246969aeSjakob struct timeval *adjust, int leapflag)
1404142bea0Sjakob {
1412e2f3e6dSjakob struct addrinfo hints, *res0, *res;
1424142bea0Sjakob double offset, error;
1434844c6b7Salexander int accept = 0, ret, s, ierror;
1444142bea0Sjakob
1452e2f3e6dSjakob memset(&hints, 0, sizeof(hints));
14622d417c3Sjakob hints.ai_family = family;
1472e2f3e6dSjakob hints.ai_socktype = SOCK_DGRAM;
14863894342Sitojun ierror = getaddrinfo(hostname, "ntp", &hints, &res0);
14963894342Sitojun if (ierror) {
15063894342Sitojun errx(1, "%s: %s", hostname, gai_strerror(ierror));
1512e2f3e6dSjakob /*NOTREACHED*/
1524142bea0Sjakob }
1534142bea0Sjakob
1544a5cc25cSmestre if (pledge("stdio inet", NULL) == -1)
1554a5cc25cSmestre err(1, "pledge");
1564a5cc25cSmestre
157246969aeSjakob corrleaps = leapflag;
15843a75b63Sjakob if (corrleaps)
15943a75b63Sjakob ntpleaps_init();
16043a75b63Sjakob
1612e2f3e6dSjakob s = -1;
1622e2f3e6dSjakob for (res = res0; res; res = res->ai_next) {
1632e2f3e6dSjakob s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
164df69c215Sderaadt if (s == -1)
1652e2f3e6dSjakob continue;
1664142bea0Sjakob
1674844c6b7Salexander ret = sync_ntp(s, res->ai_addr, &offset, &error);
1684844c6b7Salexander if (ret < 0) {
1692e2f3e6dSjakob #ifdef DEBUG
1702e2f3e6dSjakob fprintf(stderr, "try the next address\n");
1712e2f3e6dSjakob #endif
1724142bea0Sjakob close(s);
1732e2f3e6dSjakob s = -1;
1742e2f3e6dSjakob continue;
1752e2f3e6dSjakob }
1764844c6b7Salexander
1774844c6b7Salexander accept++;
1782e2f3e6dSjakob break;
1792e2f3e6dSjakob }
1802e2f3e6dSjakob freeaddrinfo(res0);
1814142bea0Sjakob
18220d5699bSjakob #ifdef DEBUG
1834142bea0Sjakob fprintf(stderr, "Correction: %.6f +/- %.6f\n", offset, error);
18420d5699bSjakob #endif
1854142bea0Sjakob
186ab7b68a0Shenning if (accept < 1)
1874844c6b7Salexander errx(1, "Unable to get a reasonable time estimate");
1884844c6b7Salexander
1894142bea0Sjakob create_timeval(offset, new, adjust);
1904142bea0Sjakob }
1914142bea0Sjakob
1924142bea0Sjakob int
sync_ntp(int fd,const struct sockaddr * peer,double * offset,double * error)1934142bea0Sjakob sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
1944142bea0Sjakob {
19519b39fdbStb int accepts = 0, rejects = 0;
1964844c6b7Salexander int delay = MAX_DELAY, ret;
1974142bea0Sjakob double deadline;
1984142bea0Sjakob double a, b, x, y;
1994142bea0Sjakob double minerr = 0.1; /* Maximum ignorable variation */
2004142bea0Sjakob struct ntp_data data;
2014142bea0Sjakob
2024142bea0Sjakob deadline = current_time(JAN_1970) + delay;
2034142bea0Sjakob *offset = 0.0;
2044142bea0Sjakob *error = NTP_INSANITY;
2054142bea0Sjakob
206df69c215Sderaadt if (connect(fd, peer, SA_LEN(peer)) == -1) {
2074844c6b7Salexander warn("Failed to connect to server");
208ab7b68a0Shenning return (-1);
2094844c6b7Salexander }
2104844c6b7Salexander
21119b39fdbStb while (accepts < MAX_QUERIES) {
2124844c6b7Salexander memset(&data, 0, sizeof(data));
2134142bea0Sjakob
2144844c6b7Salexander if (current_time(JAN_1970) > deadline) {
2154844c6b7Salexander warnx("Not enough valid responses received in time");
216ab7b68a0Shenning return (-1);
2174844c6b7Salexander }
2184142bea0Sjakob
2194844c6b7Salexander if (write_packet(fd, &data) < 0)
220ab7b68a0Shenning return (-1);
2214844c6b7Salexander
2224844c6b7Salexander ret = read_packet(fd, &data, &x, &y);
2234844c6b7Salexander
2244844c6b7Salexander if (ret < 0)
225ab7b68a0Shenning return (-1);
2264844c6b7Salexander else if (ret > 0) {
2274844c6b7Salexander #ifdef DEBUG
2284844c6b7Salexander print_packet(&data);
2294844c6b7Salexander #endif
2304844c6b7Salexander
2314844c6b7Salexander if (++rejects > MAX_QUERIES) {
2324844c6b7Salexander warnx("Too many bad or lost packets");
233ab7b68a0Shenning return (-1);
2344844c6b7Salexander } else
2354142bea0Sjakob continue;
2364142bea0Sjakob } else
2374142bea0Sjakob ++accepts;
2384142bea0Sjakob
23920d5699bSjakob #ifdef DEBUG
240ab7b68a0Shenning fprintf(stderr, "Offset: %.6f +/- %.6f\n", x, y);
24120d5699bSjakob #endif
2424142bea0Sjakob
24304ef39a3Sderaadt if ((a = x - *offset) < 0.0)
24404ef39a3Sderaadt a = -a;
24504ef39a3Sderaadt if (accepts <= 1)
24604ef39a3Sderaadt a = 0.0;
2474142bea0Sjakob b = *error + y;
2484142bea0Sjakob if (y < *error) {
2494142bea0Sjakob *offset = x;
2504142bea0Sjakob *error = y;
2514142bea0Sjakob }
2524142bea0Sjakob
25320d5699bSjakob #ifdef DEBUG
2544142bea0Sjakob fprintf(stderr, "Best: %.6f +/- %.6f\n", *offset, *error);
25520d5699bSjakob #endif
2564142bea0Sjakob
2574844c6b7Salexander if (a > b) {
2584844c6b7Salexander warnx("Inconsistent times received from NTP server");
259ab7b68a0Shenning return (-1);
2604844c6b7Salexander }
2614142bea0Sjakob
262231a5ec4Sckuethe if ((data.status & STATUS_ALARM) == STATUS_ALARM) {
263231a5ec4Sckuethe warnx("Ignoring NTP server with alarm flag set");
264231a5ec4Sckuethe return (-1);
265231a5ec4Sckuethe }
266231a5ec4Sckuethe
26704ef39a3Sderaadt if (*error <= minerr)
26804ef39a3Sderaadt break;
2694142bea0Sjakob }
2704142bea0Sjakob
271ab7b68a0Shenning return (accepts);
2724142bea0Sjakob }
2734142bea0Sjakob
2744844c6b7Salexander /* Send out NTP packet. */
2754844c6b7Salexander int
write_packet(int fd,struct ntp_data * data)2764844c6b7Salexander write_packet(int fd, struct ntp_data *data)
2774142bea0Sjakob {
2784844c6b7Salexander u_char packet[NTP_PACKET_MIN];
2794844c6b7Salexander ssize_t length;
2801346900eSjakob
2814844c6b7Salexander memset(packet, 0, sizeof(packet));
2824844c6b7Salexander
2834844c6b7Salexander packet[0] = (NTP_VERSION << 3) | (NTP_MODE_CLIENT);
2844844c6b7Salexander
2854d79ab39Sderaadt arc4random_buf(&data->xmitck, sizeof(data->xmitck));
2861346900eSjakob
2871346900eSjakob /*
2881346900eSjakob * Send out a random 64-bit number as our transmit time. The NTP
2891346900eSjakob * server will copy said number into the originate field on the
2901346900eSjakob * response that it sends us. This is totally legal per the SNTP spec.
2911346900eSjakob *
2921346900eSjakob * The impact of this is two fold: we no longer send out the current
2931346900eSjakob * system time for the world to see (which may aid an attacker), and
2941346900eSjakob * it gives us a (not very secure) way of knowing that we're not
2951346900eSjakob * getting spoofed by an attacker that can't capture our traffic
2961346900eSjakob * but can spoof packets from the NTP server we're communicating with.
2971346900eSjakob *
2984844c6b7Salexander * No endian concerns here. Since we're running as a strict
2994844c6b7Salexander * unicast client, we don't have to worry about anyone else finding
3004844c6b7Salexander * the transmit field intelligible.
3011346900eSjakob */
3021346900eSjakob
303914fb6eeSkrw bcopy(&data->xmitck, (packet + NTP_TRANSMIT), sizeof(data->xmitck));
3044142bea0Sjakob
3054844c6b7Salexander data->originate = current_time(JAN_1970);
3064142bea0Sjakob
3074844c6b7Salexander length = write(fd, packet, sizeof(packet));
3084844c6b7Salexander
3094844c6b7Salexander if (length != sizeof(packet)) {
3104844c6b7Salexander warn("Unable to send NTP packet to server");
311ab7b68a0Shenning return (-1);
3124142bea0Sjakob }
3134142bea0Sjakob
314ab7b68a0Shenning return (0);
3154142bea0Sjakob }
3164142bea0Sjakob
317eea542eaSderaadt /*
318eea542eaSderaadt * Check the packet and work out the offset and optionally the error.
3194142bea0Sjakob * Note that this contains more checking than xntp does. Return 0 for
3204142bea0Sjakob * success, 1 for failure. Note that it must not change its arguments
321eea542eaSderaadt * if it fails.
322eea542eaSderaadt */
3234142bea0Sjakob int
read_packet(int fd,struct ntp_data * data,double * off,double * error)3244844c6b7Salexander read_packet(int fd, struct ntp_data *data, double *off, double *error)
3254142bea0Sjakob {
3264844c6b7Salexander u_char receive[NTP_PACKET_MAX];
3274d79ab39Sderaadt struct pollfd pfd[1];
3284844c6b7Salexander double x, y;
3291ed5e288Sho int length, r;
3304142bea0Sjakob
3314d79ab39Sderaadt pfd[0].fd = fd;
3324d79ab39Sderaadt pfd[0].events = POLLIN;
3331ed5e288Sho
3341ed5e288Sho retry:
3354d79ab39Sderaadt r = poll(pfd, 1, 1000 * MAX_DELAY / MAX_QUERIES);
336df69c215Sderaadt if (r == -1) {
3371ed5e288Sho if (errno == EINTR)
3381ed5e288Sho goto retry;
3394844c6b7Salexander warn("select");
340ab7b68a0Shenning return (r);
3414844c6b7Salexander }
3424844c6b7Salexander
3434d79ab39Sderaadt if (r != 1)
344ab7b68a0Shenning return (1);
3454d79ab39Sderaadt if ((pfd[0].revents & POLLIN) == 0)
3464d79ab39Sderaadt return (1);
3474844c6b7Salexander
3484844c6b7Salexander length = read(fd, receive, NTP_PACKET_MAX);
349df69c215Sderaadt if (length == -1) {
3504844c6b7Salexander warn("Unable to receive NTP packet from server");
351ab7b68a0Shenning return (-1);
3524844c6b7Salexander }
3534844c6b7Salexander
3544142bea0Sjakob if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
35556dc85a1Salexander warnx("Invalid NTP packet size, packet rejected");
356ab7b68a0Shenning return (1);
3574142bea0Sjakob }
3584142bea0Sjakob
3594844c6b7Salexander unpack_ntp(data, receive);
3604142bea0Sjakob
3611346900eSjakob if (data->recvck != data->xmitck) {
36256dc85a1Salexander warnx("Invalid cookie received, packet rejected");
363ab7b68a0Shenning return (1);
3641346900eSjakob }
3651346900eSjakob
366eb434a57Shenning if (data->version < NTP_VERSION_MIN ||
367eb434a57Shenning data->version > NTP_VERSION_MAX) {
368eb22ee6cShenning warnx("Received NTP version %u, need %u or lower",
369eb22ee6cShenning data->version, NTP_VERSION);
370ab7b68a0Shenning return (1);
3714142bea0Sjakob }
3724142bea0Sjakob
3734142bea0Sjakob if (data->mode != NTP_MODE_SERVER) {
3744142bea0Sjakob warnx("Invalid NTP server mode, packet rejected");
375ab7b68a0Shenning return (1);
3764142bea0Sjakob }
3774142bea0Sjakob
378454d8160Shenning if (data->stratum > NTP_STRATUM_MAX) {
3794844c6b7Salexander warnx("Invalid stratum received, packet rejected");
380ab7b68a0Shenning return (1);
3814844c6b7Salexander }
3824844c6b7Salexander
3834844c6b7Salexander if (data->transmit == 0.0) {
3844844c6b7Salexander warnx("Server clock invalid, packet rejected");
385ab7b68a0Shenning return (1);
3864142bea0Sjakob }
3874142bea0Sjakob
3884142bea0Sjakob x = data->receive - data->originate;
3894844c6b7Salexander y = data->transmit - data->current;
3904844c6b7Salexander
3914844c6b7Salexander *off = (x + y) / 2;
3924142bea0Sjakob *error = x - y;
3934844c6b7Salexander
3944844c6b7Salexander x = (data->current - data->originate) / 2;
3954844c6b7Salexander
3964844c6b7Salexander if (x > *error)
3974844c6b7Salexander *error = x;
3984142bea0Sjakob
399ab7b68a0Shenning return (0);
4004142bea0Sjakob }
4014142bea0Sjakob
402eea542eaSderaadt /*
403eea542eaSderaadt * Unpack the essential data from an NTP packet, bypassing struct
4044142bea0Sjakob * layout and endian problems. Note that it ignores fields irrelevant
405eea542eaSderaadt * to SNTP.
406eea542eaSderaadt */
4074142bea0Sjakob void
unpack_ntp(struct ntp_data * data,u_char * packet)4084844c6b7Salexander unpack_ntp(struct ntp_data *data, u_char *packet)
4094142bea0Sjakob {
410*2d44acdfSotto int i, era;
4114142bea0Sjakob double d;
4124142bea0Sjakob
4134142bea0Sjakob data->current = current_time(JAN_1970);
4144142bea0Sjakob
4154142bea0Sjakob data->status = (packet[0] >> 6);
4164142bea0Sjakob data->version = (packet[0] >> 3) & 0x07;
4174142bea0Sjakob data->mode = packet[0] & 0x07;
4184142bea0Sjakob data->stratum = packet[1];
4194142bea0Sjakob
4204142bea0Sjakob for (i = 0, d = 0.0; i < 8; ++i)
4214142bea0Sjakob d = 256.0*d+packet[NTP_RECEIVE+i];
422ab7b68a0Shenning
423*2d44acdfSotto era = NTP_ERA;
424*2d44acdfSotto if (packet[NTP_RECEIVE] <= 127)
425*2d44acdfSotto era++;
4264142bea0Sjakob data->receive = d / NTP_SCALE;
427*2d44acdfSotto data->receive += era * SECS_IN_ERA;
4284142bea0Sjakob
4294142bea0Sjakob for (i = 0, d = 0.0; i < 8; ++i)
4304142bea0Sjakob d = 256.0*d+packet[NTP_TRANSMIT+i];
431ab7b68a0Shenning
432*2d44acdfSotto era = NTP_ERA;
433*2d44acdfSotto if (packet[NTP_TRANSMIT] <= 127)
434*2d44acdfSotto era++;
4354142bea0Sjakob data->transmit = d / NTP_SCALE;
436*2d44acdfSotto data->transmit += era * SECS_IN_ERA;
4371346900eSjakob
4384844c6b7Salexander /* See write_packet for why this isn't an endian problem. */
439914fb6eeSkrw bcopy((packet + NTP_ORIGINATE), &data->recvck, sizeof(data->recvck));
4404142bea0Sjakob }
4414142bea0Sjakob
442eea542eaSderaadt /*
443eea542eaSderaadt * Get the current UTC time in seconds since the Epoch plus an offset
4444142bea0Sjakob * (usually the time from the beginning of the century to the Epoch)
445eea542eaSderaadt */
4464142bea0Sjakob double
current_time(double offset)4474142bea0Sjakob current_time(double offset)
4484142bea0Sjakob {
4494142bea0Sjakob struct timeval current;
4502f6e235dSjakob u_int64_t t;
4514142bea0Sjakob
4524142bea0Sjakob if (gettimeofday(¤t, NULL))
4534142bea0Sjakob err(1, "Could not get local time of day");
4544142bea0Sjakob
455c81dd12eSjakob /*
456c81dd12eSjakob * At this point, current has the current TAI time.
4572f6e235dSjakob * Now subtract leap seconds to set the posix tick.
4582f6e235dSjakob */
4592f6e235dSjakob
460c81dd12eSjakob t = SEC_TO_TAI64(current.tv_sec);
4617c465852Sjakob if (corrleaps)
4622f6e235dSjakob ntpleaps_sub(&t);
4632f6e235dSjakob
464ab7b68a0Shenning return (offset + TAI64_TO_SEC(t) + 1.0e-6 * current.tv_usec);
4654142bea0Sjakob }
4664142bea0Sjakob
467eea542eaSderaadt /*
468eea542eaSderaadt * Change offset into current UTC time. This is portable, even if
469eea542eaSderaadt * struct timeval uses an unsigned long for tv_sec.
470eea542eaSderaadt */
4714142bea0Sjakob void
create_timeval(double difference,struct timeval * new,struct timeval * adjust)4724142bea0Sjakob create_timeval(double difference, struct timeval *new, struct timeval *adjust)
4734142bea0Sjakob {
4744142bea0Sjakob struct timeval old;
475*2d44acdfSotto long long n;
4764142bea0Sjakob
4774142bea0Sjakob /* Start by converting to timeval format. Note that we have to
4784142bea0Sjakob * cater for negative, unsigned values. */
479*2d44acdfSotto if ((n = (long long) difference) > difference)
4804142bea0Sjakob --n;
4814142bea0Sjakob adjust->tv_sec = n;
4824142bea0Sjakob adjust->tv_usec = (long) (MILLION_D * (difference-n));
4834142bea0Sjakob errno = 0;
4844142bea0Sjakob if (gettimeofday(&old, NULL))
4854142bea0Sjakob err(1, "Could not get local time of day");
4864142bea0Sjakob new->tv_sec = old.tv_sec + adjust->tv_sec;
4874142bea0Sjakob new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
4884142bea0Sjakob
4894142bea0Sjakob if (n < 0) {
4904142bea0Sjakob new->tv_usec += MILLION_L;
4914142bea0Sjakob --new->tv_sec;
4924142bea0Sjakob } else if (n >= MILLION_L) {
4934142bea0Sjakob new->tv_usec -= MILLION_L;
4944142bea0Sjakob ++new->tv_sec;
4954142bea0Sjakob }
4964142bea0Sjakob }
4974142bea0Sjakob
4984142bea0Sjakob #ifdef DEBUG
4994142bea0Sjakob void
print_packet(const struct ntp_data * data)5004142bea0Sjakob print_packet(const struct ntp_data *data)
5014142bea0Sjakob {
5024142bea0Sjakob printf("status: %u\n", data->status);
5034142bea0Sjakob printf("version: %u\n", data->version);
5044142bea0Sjakob printf("mode: %u\n", data->mode);
5054142bea0Sjakob printf("stratum: %u\n", data->stratum);
5064844c6b7Salexander printf("originate: %f\n", data->originate);
5074844c6b7Salexander printf("receive: %f\n", data->receive);
5084844c6b7Salexander printf("transmit: %f\n", data->transmit);
5094844c6b7Salexander printf("current: %f\n", data->current);
5101346900eSjakob printf("xmitck: 0x%0llX\n", data->xmitck);
5111346900eSjakob printf("recvck: 0x%0llX\n", data->recvck);
5124142bea0Sjakob };
5134142bea0Sjakob #endif
514