Initial import of NFC GNSS SDK project
This commit is contained in:
@@ -0,0 +1,787 @@
|
||||
/* $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
|
||||
|
||||
Reference in New Issue
Block a user