788 lines
20 KiB
C
788 lines
20 KiB
C
/* $OpenBSD: rdate.c,v 1.22 2004/02/18 20:10:53 jmc Exp $ */
|
|
/* $NetBSD: rdate.c,v 1.4 1996/03/16 12:37:45 pk Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1994 Christos Zoulas
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Christos Zoulas.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* rdate.c: Set the date from the specified host
|
|
*
|
|
* Uses the rfc868 time protocol at socket 37.
|
|
* Time is returned as the number of seconds since
|
|
* midnight January 1st 1900.
|
|
*/
|
|
#ifndef lint
|
|
#if 0
|
|
from: static char rcsid[] = "$NetBSD: rdate.c,v 1.3 1996/02/22 06:59:18 thorpej Exp $";
|
|
#else
|
|
static const char rcsid[] = "$OpenBSD: rdate.c,v 1.22 2004/02/18 20:10:53 jmc Exp $";
|
|
#endif
|
|
#endif /* lint */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifndef TTPCOM_TCPIP
|
|
#define TTPCOM_TCPIP
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sockets.h>
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
#include <netdb.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ntpleaps.h"
|
|
#include "arc4random.h"
|
|
#include "ntp.h"
|
|
#include "saremo_RTC.h"
|
|
#ifdef PSM_ENABLE
|
|
#include "psm_wrapper.h"
|
|
#endif
|
|
#include "utltime.h"
|
|
#include "quec_cust_feature.h"
|
|
/* there are systems without libutil; for portability */
|
|
#ifdef HAVE_UTIL_H
|
|
#include <util.h>
|
|
#else
|
|
#define logwtmp(a,b,c)
|
|
#endif
|
|
|
|
typedef unsigned int size_t, ssize_t;
|
|
typedef long fd_mask;
|
|
#define NBBY 8
|
|
#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
|
|
|
|
#ifndef howmany
|
|
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
|
#endif
|
|
|
|
#ifdef MRVL_USE_POOL_MEM
|
|
#define duster_free(p) DusterFree(p)
|
|
#else
|
|
#define duster_free(p) free(p)
|
|
#endif
|
|
|
|
/*
|
|
* NTP definitions. Note that these assume 8-bit bytes - sigh. There
|
|
* is little point in parameterising everything, as it is neither
|
|
* feasible nor useful. It would be very useful if more fields could
|
|
* be defined as unspecified. The NTP packet-handling routines
|
|
* contain a lot of extra assumptions.
|
|
*/
|
|
|
|
#define JAN_1970 2208988800.0 /* 1970 - 1900 in seconds */
|
|
#define NTP_SCALE 4294967296.0 /* 2^32, of course! */
|
|
|
|
#define NTP_MODE_CLIENT 3 /* NTP client mode */
|
|
#define NTP_MODE_SERVER 4 /* NTP server mode */
|
|
#define NTP_VERSION 4 /* The current version */
|
|
#define NTP_VERSION_MIN 1 /* The minum valid version */
|
|
#define NTP_VERSION_MAX 4 /* The maximum valid version */
|
|
#define NTP_STRATUM_MAX 14 /* The maximum valid stratum */
|
|
#define NTP_INSANITY 3600.0 /* Errors beyond this are hopeless */
|
|
|
|
#define NTP_PACKET_MIN 48 /* Without authentication */
|
|
#define NTP_PACKET_MAX 68 /* With authentication (ignored) */
|
|
|
|
#define NTP_DISP_FIELD 8 /* Offset of dispersion field */
|
|
#define NTP_REFERENCE 16 /* Offset of reference timestamp */
|
|
#define NTP_ORIGINATE 24 /* Offset of originate timestamp */
|
|
#define NTP_RECEIVE 32 /* Offset of receive timestamp */
|
|
#define NTP_TRANSMIT 40 /* Offset of transmit timestamp */
|
|
|
|
#define STATUS_NOWARNING 0 /* No Leap Indicator */
|
|
#define STATUS_LEAPHIGH 1 /* Last Minute Has 61 Seconds */
|
|
#define STATUS_LEAPLOW 2 /* Last Minute Has 59 Seconds */
|
|
#define STATUS_ALARM 3 /* Server Clock Not Synchronized */
|
|
|
|
#define MAX_QUERIES 25
|
|
#define MAX_DELAY 15
|
|
|
|
#define MILLION_L 1000000l /* For conversion to/from timeval */
|
|
#define MILLION_D 1.0e6 /* Must be equal to MILLION_L */
|
|
|
|
//#ifdef __GLIBC__
|
|
#define SA_LEN(x) sizeof(*x)
|
|
//#endif
|
|
|
|
//#define DEBUG
|
|
|
|
struct ntp_data {
|
|
u_char status;
|
|
u_char version;
|
|
u_char mode;
|
|
u_char stratum;
|
|
double receive;
|
|
double transmit;
|
|
double current;
|
|
u_int64_t recvck;
|
|
|
|
/* Local State */
|
|
double originate;
|
|
u_int64_t xmitck;
|
|
};
|
|
|
|
int ntp_client (const char *, int, struct timeval *, struct timeval *, int);
|
|
int sync_ntp(int, const struct sockaddr *, double *, double *);
|
|
int write_packet(int, struct ntp_data *);
|
|
int read_packet(int, struct ntp_data *, double *, double *);
|
|
void unpack_ntp(struct ntp_data *, u_char *);
|
|
double current_time(double);
|
|
void create_timeval(double, struct timeval *, struct timeval *);
|
|
|
|
#ifdef DEBUG
|
|
void print_packet(const struct ntp_data *);
|
|
#endif
|
|
|
|
extern char *__progname;
|
|
|
|
//#ifdef NTP
|
|
#define NTP_TASK_PRIORITY 160
|
|
#define NTP_STACK_SIZE (3*1024)
|
|
|
|
OSTaskRef NTPTaskRef;
|
|
UINT8* NTPTaskStack=NULL;
|
|
//UINT32 NTPTaskStack[NTP_STACK_SIZE>>2] = {0x55555555};
|
|
|
|
static OSAFlagRef NtpFlagRef = NULL;
|
|
static time_t NtpResult = 0;
|
|
extern char *GetNTPServer(void);
|
|
extern int GetTimeZone(void);
|
|
extern char *psm_get_wrapper(char *mod_name, char *subspace, char *variable);
|
|
extern UINT8 getDefaultCidNum(void);
|
|
extern char get_linkstas(char cid);
|
|
extern int gettimeofday(struct timeval *tv, void* dummy);
|
|
|
|
|
|
|
|
int NTP_SYNC_SUCCESS = 0;
|
|
|
|
void SetNTPStatus(int flag)
|
|
{
|
|
NTP_SYNC_SUCCESS = flag;
|
|
}
|
|
|
|
int GetNTPStatus(void)
|
|
{
|
|
return NTP_SYNC_SUCCESS;
|
|
}
|
|
|
|
static unsigned int ntp_retry_timer[] = {
|
|
(1 * 1000 / 5), /*2 sec*/
|
|
(10 * 1000 / 5), /*10 sec*/
|
|
(60 * 1000 / 5), /*1 min*/
|
|
(600 * 1000 / 5), /*10 min*/
|
|
(1800 * 1000 / 5), /*30 min*/
|
|
(3600 * 1000 / 5), /*1 hour*/
|
|
(18000 * 1000 / 5), /*5 hour*/
|
|
(36000 * 1000 / 5), /*10 hour*/
|
|
};
|
|
static int ntp_retry_index = 0;
|
|
#define NTP_MAX_RETRY_COUNT (sizeof(ntp_retry_timer)/sizeof(unsigned int))
|
|
|
|
void NTPTask(void *argv)
|
|
{
|
|
int pr = 0, silent = 0, ntp = 0, verbose = 0;
|
|
int slidetime = 0, corrleaps = 0;
|
|
char hname_default[32] = "202.112.31.197";
|
|
char hname[32] = {'\0'};
|
|
char *ntp_server = NULL;
|
|
int c = 0;
|
|
int family = PF_UNSPEC;
|
|
struct tm *ltm = NULL;
|
|
struct timeval new, adjust;
|
|
char buf[80];
|
|
time_t tim = 0;
|
|
double adjsec;
|
|
|
|
UINT32 flag_value = 0;
|
|
int ret = 0;
|
|
OSA_STATUS status;
|
|
|
|
while(1)
|
|
{
|
|
int try_times = 3;
|
|
int count = 0;
|
|
OSATaskSleep(50);
|
|
status = OSAFlagWait(NtpFlagRef, NTP_FLAG_BIT, OSA_FLAG_OR_CLEAR, &flag_value, OSA_SUSPEND);
|
|
ASSERT(status == OS_SUCCESS);
|
|
SetNTPStatus(0);
|
|
CPUartLogPrintf("%s status %u", __FUNCTION__, GetNTPStatus());
|
|
#ifndef QUEC_GNSS_NTP
|
|
while(!get_linkstas(getDefaultCidNum() - 1) && count < 8)
|
|
{
|
|
OSATaskSleep(200 * pow(2, count));
|
|
++count;
|
|
}
|
|
ntp_server = GetNTPServer();
|
|
if(ntp_server)
|
|
{
|
|
strncpy(hname, ntp_server, 32);
|
|
}
|
|
|
|
#ifndef NO_EXTEND_MY_Q_AT
|
|
if(bspGetBoardType() == TIGX_MIFI){
|
|
|
|
if(ntp_retry_index >= NTP_MAX_RETRY_COUNT){
|
|
ntp_retry_index = NTP_MAX_RETRY_COUNT - 1;
|
|
}
|
|
OSATaskSleep(ntp_retry_timer[ntp_retry_index]);
|
|
ntp_retry_index++;
|
|
strncpy(hname, hname_default, 32);
|
|
|
|
}
|
|
#endif
|
|
#endif
|
|
#ifdef QUEC_GNSS_NTP
|
|
extern char *get_ntp_server_ip(void);
|
|
strncpy(hname,get_ntp_server_ip(),32);
|
|
RTI_LOG("NTP SRVER is %s", hname);
|
|
#endif
|
|
while(try_times > 0 && count < 8)
|
|
{
|
|
--try_times;
|
|
if(strlen(hname) > 0)
|
|
ret = ntp_client(hname, family, &new, &adjust, corrleaps);
|
|
else
|
|
ret = ntp_client(hname_default, family, &new, &adjust, corrleaps);
|
|
|
|
if(ret != 0)
|
|
{
|
|
continue;
|
|
}
|
|
tim = new.tv_sec;
|
|
NtpResult = tim;
|
|
|
|
ltm = localtime(&tim);
|
|
(void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y\n", ltm);
|
|
CPUartLogPrintf("NTPTask time is %s", buf);
|
|
|
|
if (new.tv_sec > 60 * 60 * 24 * 365)
|
|
{
|
|
SaveNTPParameters(ltm);
|
|
break;
|
|
}
|
|
OSATaskSleep(200);
|
|
|
|
}
|
|
if(try_times > 0)
|
|
{
|
|
SetNTPStatus(1);//successful
|
|
}
|
|
else
|
|
{
|
|
|
|
SetNTPStatus(2);//failed
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void NTP_Init_Internal(void)
|
|
{
|
|
OSA_STATUS status;
|
|
char *str = NULL;
|
|
|
|
#ifdef NTP
|
|
str = psm_get_wrapper("Debug", NULL, "debug_ntp_disable");
|
|
if (str && strcmp(str, "1") == 0)
|
|
{
|
|
free(str);
|
|
return;
|
|
}
|
|
if (str)
|
|
free(str);
|
|
|
|
/* Ntp Flag initialize. */
|
|
status = OSAFlagCreate(&NtpFlagRef);
|
|
ASSERT(status == OS_SUCCESS);
|
|
|
|
NTPTaskStack = malloc(NTP_STACK_SIZE);
|
|
if(NTPTaskStack != NULL)
|
|
memset(NTPTaskStack,0x55,NTP_STACK_SIZE);
|
|
else
|
|
return;
|
|
|
|
status = OSATaskCreate(&NTPTaskRef, (void *)NTPTaskStack, NTP_STACK_SIZE,
|
|
NTP_TASK_PRIORITY, "NTPTask", NTPTask, NULL);
|
|
ASSERT(status == OS_SUCCESS);
|
|
#endif
|
|
}
|
|
|
|
void SyncNTP(void)
|
|
{
|
|
#ifdef NTP
|
|
OSA_STATUS status;
|
|
if(NtpFlagRef != NULL)
|
|
{
|
|
status = OSAFlagSet(NtpFlagRef, NTP_FLAG_BIT, OSA_FLAG_OR);
|
|
ASSERT(status == OS_SUCCESS);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
time_t GetNtpResult(void)
|
|
{
|
|
return NtpResult;
|
|
}
|
|
//#endif
|
|
|
|
int
|
|
ntp_client(const char *hostname, int family, struct timeval *new,
|
|
struct timeval *adjust, int leapflag)
|
|
{
|
|
struct addrinfo hints, *res0 = NULL, *res = NULL;
|
|
double offset = 0, error = 0;
|
|
int accept = 0, ret, s, ierror;
|
|
|
|
#if 0
|
|
struct sockaddr_in servaddr;
|
|
memset(&servaddr, 0, sizeof(servaddr));
|
|
servaddr.sin_family = AF_INET;
|
|
servaddr.sin_port = htons(123);
|
|
|
|
if(inet_aton(hostname, &servaddr.sin_addr) < 0)
|
|
{
|
|
CPUartLogPrintf("convert ip error %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
ret = sync_ntp(s, (struct sockaddr *)&servaddr, &offset, &error);
|
|
if (ret < 0) {
|
|
#ifdef DEBUG
|
|
CPUartLogPrintf("try the next address\n");
|
|
#endif
|
|
close(s);
|
|
s = -1;
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
#if 1
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = family;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
ierror = getaddrinfo(hostname, "123", &hints, &res0);
|
|
if (ierror) {
|
|
CPUartLogPrintf("%s: %d", hostname, ierror);
|
|
return -1;
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
s = -1;
|
|
for (res = res0; res; res = res->ai_next) {
|
|
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
if (s < 0)
|
|
continue;
|
|
#ifdef QUEC_GNSS_NTP
|
|
struct sockaddr_in ip4_local_addr = {0};
|
|
extern struct in_addr quec_get_gps_ip4_addr(void);
|
|
ip4_local_addr.sin_family = AF_INET;
|
|
ip4_local_addr.sin_port = htons(0);
|
|
ip4_local_addr.sin_addr = quec_get_gps_ip4_addr();
|
|
ret = bind(s, (struct sockaddr *)&ip4_local_addr, sizeof(ip4_local_addr));
|
|
#endif
|
|
ret = sync_ntp(s, res->ai_addr, &offset, &error);
|
|
if (ret < 0) {
|
|
#ifdef DEBUG
|
|
CPUartLogPrintf("%s: try the next address\n", __func__);
|
|
#endif
|
|
close(s);
|
|
s = -1;
|
|
continue;
|
|
}
|
|
|
|
accept++;
|
|
close(s);
|
|
s = -1;
|
|
break;
|
|
}
|
|
freeaddrinfo(res0);
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
CPUartLogPrintf("%s: Correction %.6f +/- %.6f\n", __func__, offset, error);
|
|
#endif
|
|
|
|
if (accept < 1)
|
|
{
|
|
CPUartLogPrintf("%s: Unable to get a reasonable time estimate", __func__);
|
|
return -1;
|
|
}
|
|
|
|
create_timeval(offset, new, adjust);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
|
|
{
|
|
int attempts = 0, accepts = 0, rejects = 0, retry_num=0;
|
|
int delay = MAX_DELAY, ret;
|
|
double deadline;
|
|
double a, b, x, y;
|
|
double minerr = 0.1; /* Maximum ignorable variation */
|
|
struct ntp_data data;
|
|
|
|
deadline = current_time(JAN_1970) + delay;
|
|
*offset = 0.0;
|
|
*error = NTP_INSANITY;
|
|
|
|
if (connect(fd, peer, SA_LEN(peer)) < 0) {
|
|
CPUartLogPrintf("Failed to connect to server");
|
|
return (-1);
|
|
}
|
|
if(bspGetBoardType() == TIGX_MIFI){
|
|
retry_num = 2;
|
|
}else{
|
|
retry_num = MAX_QUERIES;
|
|
}
|
|
|
|
while (accepts < retry_num && attempts < 2 * retry_num) {
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
if (current_time(JAN_1970) > deadline) {
|
|
CPUartLogPrintf("Not enough valid responses received in time");
|
|
return (-1);
|
|
}
|
|
|
|
if (write_packet(fd, &data) < 0)
|
|
return (-1);
|
|
|
|
ret = read_packet(fd, &data, &x, &y);
|
|
|
|
if (ret < 0)
|
|
return (-1);
|
|
else if (ret > 0) {
|
|
#ifdef DEBUG
|
|
print_packet(&data);
|
|
#endif
|
|
|
|
if (++rejects > retry_num) {
|
|
CPUartLogPrintf("Too many bad or lost packets");
|
|
return (-1);
|
|
} else{
|
|
continue;
|
|
}
|
|
} else
|
|
++accepts;
|
|
|
|
#ifdef DEBUG
|
|
CPUartLogPrintf("Offset: %.6f +/- %.6f\n", x, y);
|
|
#endif
|
|
|
|
if ((a = x - *offset) < 0.0)
|
|
a = -a;
|
|
if (accepts <= 1)
|
|
a = 0.0;
|
|
b = *error + y;
|
|
if (y < *error) {
|
|
*offset = x;
|
|
*error = y;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CPUartLogPrintf("Best: %.6f +/- %.6f\n", *offset, *error);
|
|
#endif
|
|
|
|
if (a > b) {
|
|
CPUartLogPrintf("Inconsistent times received from NTP server");
|
|
return (-1);
|
|
}
|
|
|
|
if ((data.status & STATUS_ALARM) == STATUS_ALARM) {
|
|
CPUartLogPrintf("Ignoring NTP server with alarm flag set");
|
|
return (-1);
|
|
}
|
|
|
|
if (*error <= minerr)
|
|
break;
|
|
}
|
|
|
|
return (accepts);
|
|
}
|
|
|
|
/* Send out NTP packet. */
|
|
int
|
|
write_packet(int fd, struct ntp_data *data)
|
|
{
|
|
u_char packet[NTP_PACKET_MIN];
|
|
ssize_t length;
|
|
|
|
memset(packet, 0, sizeof(packet));
|
|
|
|
packet[0] = (NTP_VERSION << 3) | (NTP_MODE_CLIENT);
|
|
|
|
data->xmitck = (u_int64_t)arc4random() << 32 | arc4random();
|
|
|
|
/*
|
|
* Send out a random 64-bit number as our transmit time. The NTP
|
|
* server will copy said number into the originate field on the
|
|
* response that it sends us. This is totally legal per the SNTP spec.
|
|
*
|
|
* The impact of this is two fold: we no longer send out the current
|
|
* system time for the world to see (which may aid an attacker), and
|
|
* it gives us a (not very secure) way of knowing that we're not
|
|
* getting spoofed by an attacker that can't capture our traffic
|
|
* but can spoof packets from the NTP server we're communicating with.
|
|
*
|
|
* No endian concerns here. Since we're running as a strict
|
|
* unicast client, we don't have to worry about anyone else finding
|
|
* the transmit field intelligible.
|
|
*/
|
|
|
|
*(u_int64_t *)(packet + NTP_TRANSMIT) = data->xmitck;
|
|
|
|
data->originate = current_time(JAN_1970);
|
|
|
|
length = write(fd, packet, sizeof(packet));
|
|
|
|
if (length != sizeof(packet)) {
|
|
CPUartLogPrintf("Unable to send NTP packet to server");
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Check the packet and work out the offset and optionally the error.
|
|
* Note that this contains more checking than xntp does. Return 0 for
|
|
* success, 1 for failure. Note that it must not change its arguments
|
|
* if it fails.
|
|
*/
|
|
int
|
|
read_packet(int fd, struct ntp_data *data, double *off, double *error)
|
|
{
|
|
u_char receive[NTP_PACKET_MAX];
|
|
struct timeval tv;
|
|
double x, y;
|
|
int length, r;
|
|
fd_set rfds;
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(fd, &rfds);
|
|
|
|
retry:
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 1000000 * MAX_DELAY / MAX_QUERIES;
|
|
|
|
r = select(fd + 1, &rfds, NULL, NULL, &tv);
|
|
|
|
if (r < 0) {
|
|
if (errno == EINTR)
|
|
goto retry;
|
|
else
|
|
CPUartLogPrintf("%s: select" ,__FUNCTION__);
|
|
|
|
return (r);
|
|
}
|
|
|
|
if (r != 1 || !FD_ISSET(fd, &rfds)) {
|
|
CPUartLogPrintf("%s: no event ready after timeout" ,__FUNCTION__);
|
|
return (1);
|
|
}
|
|
|
|
length = read(fd, receive, NTP_PACKET_MAX);
|
|
|
|
if (length < 0) {
|
|
CPUartLogPrintf(" %s: Unable to receive NTP packet from server", __FUNCTION__);
|
|
return (-1);
|
|
}
|
|
|
|
if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
|
|
CPUartLogPrintf("%s: Invalid NTP packet size, packet rejected", __FUNCTION__);
|
|
return (1);
|
|
}
|
|
|
|
unpack_ntp(data, receive);
|
|
|
|
if (data->recvck != data->xmitck) {
|
|
CPUartLogPrintf("%s: Invalid cookie received, packet rejected", __FUNCTION__);
|
|
return (1);
|
|
}
|
|
|
|
if (data->version < NTP_VERSION_MIN ||
|
|
data->version > NTP_VERSION_MAX) {
|
|
CPUartLogPrintf("%s: Received NTP version %u, need %u or lower", __FUNCTION__,\
|
|
data->version, NTP_VERSION);
|
|
return (1);
|
|
}
|
|
|
|
if (data->mode != NTP_MODE_SERVER) {
|
|
CPUartLogPrintf("%s: Invalid NTP server mode, packet rejected", __FUNCTION__);
|
|
return (1);
|
|
}
|
|
|
|
if (data->stratum > NTP_STRATUM_MAX) {
|
|
CPUartLogPrintf("%s: Invalid stratum received, packet rejected", __FUNCTION__);
|
|
return (1);
|
|
}
|
|
|
|
if (data->transmit == 0.0) {
|
|
CPUartLogPrintf("%s: Server clock invalid, packet rejected", __FUNCTION__);
|
|
return (1);
|
|
}
|
|
|
|
x = data->receive - data->originate;
|
|
y = data->transmit - data->current;
|
|
|
|
*off = (x + y) / 2;
|
|
*error = x - y;
|
|
|
|
x = (data->current - data->originate) / 2;
|
|
|
|
if (x > *error)
|
|
*error = x;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Unpack the essential data from an NTP packet, bypassing struct
|
|
* layout and endian problems. Note that it ignores fields irrelevant
|
|
* to SNTP.
|
|
*/
|
|
void
|
|
unpack_ntp(struct ntp_data *data, u_char *packet)
|
|
{
|
|
int i;
|
|
double d;
|
|
|
|
data->current = current_time(JAN_1970);
|
|
|
|
data->status = (packet[0] >> 6);
|
|
data->version = (packet[0] >> 3) & 0x07;
|
|
data->mode = packet[0] & 0x07;
|
|
data->stratum = packet[1];
|
|
|
|
for (i = 0, d = 0.0; i < 8; ++i)
|
|
d = 256.0*d+packet[NTP_RECEIVE+i];
|
|
|
|
data->receive = d / NTP_SCALE;
|
|
|
|
for (i = 0, d = 0.0; i < 8; ++i)
|
|
d = 256.0*d+packet[NTP_TRANSMIT+i];
|
|
|
|
data->transmit = d / NTP_SCALE;
|
|
|
|
/* See write_packet for why this isn't an endian problem. */
|
|
data->recvck = *(u_int64_t *)(packet + NTP_ORIGINATE);
|
|
}
|
|
|
|
/*
|
|
* Get the current UTC time in seconds since the Epoch plus an offset
|
|
* (usually the time from the beginning of the century to the Epoch)
|
|
*/
|
|
double
|
|
current_time(double offset)
|
|
{
|
|
struct timeval current;
|
|
u_int64_t t;
|
|
|
|
if (gettimeofday(¤t, NULL))
|
|
CPUartLogPrintf("Could not get local time of day");
|
|
|
|
/*
|
|
* At this point, current has the current TAI time.
|
|
* Now subtract leap seconds to set the posix tick.
|
|
*/
|
|
|
|
t = SEC_TO_TAI64(current.tv_sec);
|
|
//if (corrleaps)
|
|
//ntpleaps_sub(&t);
|
|
|
|
return (offset + TAI64_TO_SEC(t) + 1.0e-6 * current.tv_usec);
|
|
}
|
|
|
|
/*
|
|
* Change offset into current UTC time. This is portable, even if
|
|
* struct timeval uses an unsigned long for tv_sec.
|
|
*/
|
|
void
|
|
create_timeval(double difference, struct timeval *new, struct timeval *adjust)
|
|
{
|
|
struct timeval old;
|
|
long n;
|
|
|
|
/* Start by converting to timeval format. Note that we have to
|
|
* cater for negative, unsigned values. */
|
|
if ((n = (long) difference) > difference)
|
|
--n;
|
|
adjust->tv_sec = n;
|
|
adjust->tv_usec = (long) (MILLION_D * (difference-n));
|
|
errno = 0;
|
|
if (gettimeofday(&old, NULL))
|
|
CPUartLogPrintf("%s: Could not get local time of day", __func__);
|
|
new->tv_sec = old.tv_sec + adjust->tv_sec;
|
|
new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
|
|
|
|
if (n < 0) {
|
|
new->tv_usec += MILLION_L;
|
|
--new->tv_sec;
|
|
} else if (n >= MILLION_L) {
|
|
new->tv_usec -= MILLION_L;
|
|
++new->tv_sec;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
print_packet(const struct ntp_data *data)
|
|
{
|
|
CPUartLogPrintf("%s: start");
|
|
CPUartLogPrintf("status: %u\n", data->status);
|
|
CPUartLogPrintf("version: %u\n", data->version);
|
|
CPUartLogPrintf("mode: %u\n", data->mode);
|
|
CPUartLogPrintf("stratum: %u\n", data->stratum);
|
|
CPUartLogPrintf("originate: %f\n", data->originate);
|
|
CPUartLogPrintf("receive: %f\n", data->receive);
|
|
CPUartLogPrintf("transmit: %f\n", data->transmit);
|
|
CPUartLogPrintf("current: %f\n", data->current);
|
|
CPUartLogPrintf("xmitck: 0x%0llX\n", data->xmitck);
|
|
CPUartLogPrintf("recvck: 0x%0llX\n", data->recvck);
|
|
CPUartLogPrintf("%s: end");
|
|
};
|
|
#endif
|
|
|