summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/ntp_refclock.c
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
committerdelphij <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
commit2a25cee78ab1d37e7d2bc40ae675646974d99f56 (patch)
treeb0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/ntpd/ntp_refclock.c
parenta0741a75537b2e0514472ac3b28afc55a7846c30 (diff)
downloadFreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.zip
FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.tar.gz
MFC r280849,280915-280916,281015-281016,282097,282408,282415,283542,
284864,285169-285170,285435: ntp 4.2.8p3. Relnotes: yes Approved by: re (?)
Diffstat (limited to 'contrib/ntp/ntpd/ntp_refclock.c')
-rw-r--r--contrib/ntp/ntpd/ntp_refclock.c801
1 files changed, 452 insertions, 349 deletions
diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c
index a29ef08..f0e9b9e 100644
--- a/contrib/ntp/ntpd/ntp_refclock.c
+++ b/contrib/ntp/ntpd/ntp_refclock.c
@@ -11,6 +11,7 @@
#include "ntp_tty.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
#include <stdio.h>
@@ -20,77 +21,54 @@
#ifdef REFCLOCK
-#ifdef TTYCLK
-# ifdef HAVE_SYS_CLKDEFS_H
-# include <sys/clkdefs.h>
-# include <stropts.h>
-# endif
-# ifdef HAVE_SYS_SIO_H
-# include <sys/sio.h>
-# endif
-#endif /* TTYCLK */
-
#ifdef KERNEL_PLL
#include "ntp_syscall.h"
#endif /* KERNEL_PLL */
+#ifdef HAVE_PPSAPI
+#include "ppsapi_timepps.h"
+#include "refclock_atom.h"
+#endif /* HAVE_PPSAPI */
+
/*
* Reference clock support is provided here by maintaining the fiction
- * that the clock is actually a peer. As no packets are exchanged with a
- * reference clock, however, we replace the transmit, receive and packet
- * procedures with separate code to simulate them. Routines
+ * that the clock is actually a peer. As no packets are exchanged with
+ * a reference clock, however, we replace the transmit, receive and
+ * packet procedures with separate code to simulate them. Routines
* refclock_transmit() and refclock_receive() maintain the peer
* variables in a state analogous to an actual peer and pass reference
- * clock data on through the filters. Routines refclock_peer() and
+ * clock data on through the filters. Routines refclock_peer() and
* refclock_unpeer() are called to initialize and terminate reference
- * clock associations. A set of utility routines is included to open
- * serial devices, process sample data, edit input lines to extract
- * embedded timestamps and to peform various debugging functions.
+ * clock associations. A set of utility routines is included to open
+ * serial devices, process sample data, and to perform various debugging
+ * functions.
*
* The main interface used by these routines is the refclockproc
- * structure, which contains for most drivers the decimal equivalants of
- * the year, day, month, hour, second and millisecond/microsecond
- * decoded from the ASCII timecode. Additional information includes the
- * receive timestamp, exception report, statistics tallies, etc. In
- * addition, there may be a driver-specific unit structure used for
+ * structure, which contains for most drivers the decimal equivalants
+ * of the year, day, month, hour, second and millisecond/microsecond
+ * decoded from the ASCII timecode. Additional information includes
+ * the receive timestamp, exception report, statistics tallies, etc.
+ * In addition, there may be a driver-specific unit structure used for
* local control of the device.
*
* The support routines are passed a pointer to the peer structure,
- * which is used for all peer-specific processing and contains a pointer
- * to the refclockproc structure, which in turn containes a pointer to
- * the unit structure, if used. The peer structure is identified by an
- * interface address in the dotted quad form 127.127.t.u (for now only
- * IPv4 addresses are used, so we need to be sure the address is it),
- * where t is the clock type and u the unit. Some legacy drivers derive
- * the refclockproc structure pointer from the table
- * typeunit[type][unit]. This interface is strongly discouraged and may
- * be abandoned in future.
+ * which is used for all peer-specific processing and contains a
+ * pointer to the refclockproc structure, which in turn contains a
+ * pointer to the unit structure, if used. The peer structure is
+ * identified by an interface address in the dotted quad form
+ * 127.127.t.u, where t is the clock type and u the unit.
*/
-#define MAXUNIT 4 /* max units */
#define FUDGEFAC .1 /* fudge correction factor */
#define LF 0x0a /* ASCII LF */
-#ifdef PPS
-int fdpps; /* ppsclock legacy */
-#endif /* PPS */
int cal_enable; /* enable refclock calibrate */
/*
- * Type/unit peer index. Used to find the peer structure for control and
- * debugging. When all clock drivers have been converted to new style,
- * this dissapears.
- */
-static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
-
-/*
* Forward declarations
*/
-#ifdef QSORT_USES_VOID_P
-static int refclock_cmpl_fp P((const void *, const void *));
-#else
-static int refclock_cmpl_fp P((const double *, const double *));
-#endif /* QSORT_USES_VOID_P */
-static int refclock_sample P((struct refclockproc *));
+static int refclock_cmpl_fp (const void *, const void *);
+static int refclock_sample (struct refclockproc *);
+static int refclock_ioctl(int, u_int);
/*
@@ -113,58 +91,36 @@ refclock_report(
return;
switch (code) {
- case CEVNT_NOMINAL:
- break;
-
- case CEVNT_TIMEOUT:
- pp->noreply++;
- break;
- case CEVNT_BADREPLY:
- pp->badformat++;
- break;
+ case CEVNT_TIMEOUT:
+ pp->noreply++;
+ break;
- case CEVNT_FAULT:
- break;
+ case CEVNT_BADREPLY:
+ pp->badformat++;
+ break;
- case CEVNT_PROP:
- break;
+ case CEVNT_FAULT:
+ break;
- case CEVNT_BADDATE:
- case CEVNT_BADTIME:
- pp->baddata++;
- break;
+ case CEVNT_BADDATE:
+ case CEVNT_BADTIME:
+ pp->baddata++;
+ break;
- default:
- /* shouldn't happen */
- break;
+ default:
+ /* ignore others */
+ break;
}
-
+ if (pp->lastevent < 15)
+ pp->lastevent++;
if (pp->currentstatus != code) {
pp->currentstatus = (u_char)code;
-
- /* RFC1305: copy only iff not CEVNT_NOMINAL */
- if (code != CEVNT_NOMINAL)
- pp->lastevent = (u_char)code;
-
- if (code == CEVNT_FAULT)
- msyslog(LOG_ERR,
- "clock %s event '%s' (0x%02x)",
- refnumtoa(&peer->srcadr),
- ceventstr(code), code);
- else {
- NLOG(NLOG_CLOCKEVENT)
- msyslog(LOG_INFO,
- "clock %s event '%s' (0x%02x)",
- refnumtoa(&peer->srcadr),
- ceventstr(code), code);
- }
-
- /* RFC1305: post peer clock event */
- report_event(EVNT_PEERCLOCK, peer);
+ report_event(PEVNT_CLOCK, peer, ceventstr(code));
}
}
+
/*
* init_refclock - initialize the reference clock drivers
*
@@ -175,14 +131,11 @@ refclock_report(
void
init_refclock(void)
{
- int i, j;
+ int i;
- for (i = 0; i < (int)num_refclock_conf; i++) {
+ for (i = 0; i < (int)num_refclock_conf; i++)
if (refclock_conf[i]->clock_init != noentry)
(refclock_conf[i]->clock_init)();
- for (j = 0; j < MAXUNIT; j++)
- typeunit[i][j] = 0;
- }
}
@@ -211,12 +164,6 @@ refclock_newpeer(
* Check for valid clock address. If already running, shut it
* down first.
*/
- if (peer->srcadr.ss_family != AF_INET) {
- msyslog(LOG_ERR,
- "refclock_newpeer: clock address %s invalid, address family not implemented for refclock",
- stoa(&peer->srcadr));
- return (0);
- }
if (!ISREFCLOCKADR(&peer->srcadr)) {
msyslog(LOG_ERR,
"refclock_newpeer: clock address %s invalid",
@@ -225,7 +172,7 @@ refclock_newpeer(
}
clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
unit = REFCLOCKUNIT(&peer->srcadr);
- if (clktype >= num_refclock_conf || unit >= MAXUNIT ||
+ if (clktype >= num_refclock_conf ||
refclock_conf[clktype]->clock_start == noentry) {
msyslog(LOG_ERR,
"refclock_newpeer: clock type %d invalid\n",
@@ -236,12 +183,7 @@ refclock_newpeer(
/*
* Allocate and initialize interface structure
*/
- pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc));
- if (pp == NULL)
- return (0);
-
- memset((char *)pp, 0, sizeof(struct refclockproc));
- typeunit[clktype][unit] = peer;
+ pp = emalloc_zero(sizeof(*pp));
peer->procptr = pp;
/*
@@ -249,12 +191,14 @@ refclock_newpeer(
*/
peer->refclktype = clktype;
peer->refclkunit = (u_char)unit;
- peer->flags |= FLAG_REFCLOCK | FLAG_FIXPOLL;
+ peer->flags |= FLAG_REFCLOCK;
peer->leap = LEAP_NOTINSYNC;
peer->stratum = STRATUM_REFCLOCK;
peer->ppoll = peer->maxpoll;
pp->type = clktype;
+ pp->conf = refclock_conf[clktype];
pp->timestarted = current_time;
+ pp->io.fd = -1;
/*
* Set peer.pmode based on the hmode. For appearances only.
@@ -297,7 +241,7 @@ refclock_unpeer(
* Wiggle the driver to release its resources, then give back
* the interface structure.
*/
- if (!peer->procptr)
+ if (NULL == peer->procptr)
return;
clktype = peer->refclktype;
@@ -305,7 +249,7 @@ refclock_unpeer(
if (refclock_conf[clktype]->clock_shutdown != noentry)
(refclock_conf[clktype]->clock_shutdown)(unit, peer);
free(peer->procptr);
- peer->procptr = 0;
+ peer->procptr = NULL;
}
@@ -314,16 +258,18 @@ refclock_unpeer(
*/
void
refclock_timer(
- struct peer *peer /* peer structure pointer */
+ struct peer *p
)
{
- u_char clktype;
- int unit;
-
- clktype = peer->refclktype;
- unit = peer->refclkunit;
- if (refclock_conf[clktype]->clock_timer != noentry)
- (refclock_conf[clktype]->clock_timer)(unit, peer);
+ struct refclockproc * pp;
+ int unit;
+
+ unit = p->refclkunit;
+ pp = p->procptr;
+ if (pp->conf->clock_timer != noentry)
+ (*pp->conf->clock_timer)(unit, p);
+ if (pp->action != NULL && pp->nextaction <= current_time)
+ (*pp->action)(p);
}
@@ -365,19 +311,17 @@ refclock_transmit(
* Update reachability and poll variables like the
* network code.
*/
- oreach = peer->reach;
+ oreach = peer->reach & 0xfe;
peer->reach <<= 1;
+ if (!(peer->reach & 0x0f))
+ clock_filter(peer, 0., 0., MAXDISPERSE);
peer->outdate = current_time;
if (!peer->reach) {
if (oreach) {
- report_event(EVNT_UNREACH, peer);
+ report_event(PEVNT_UNREACH, peer, NULL);
peer->timereachable = current_time;
}
} else {
- if (!(oreach & 0x07)) {
- clock_filter(peer, 0., 0., MAXDISPERSE);
- clock_select();
- }
if (peer->flags & FLAG_BURST)
peer->burst = NSTAGE;
}
@@ -393,7 +337,6 @@ refclock_transmit(
/*
* Compare two doubles - used with qsort()
*/
-#ifdef QSORT_USES_VOID_P
static int
refclock_cmpl_fp(
const void *p1,
@@ -404,30 +347,11 @@ refclock_cmpl_fp(
const double *dp2 = (const double *)p2;
if (*dp1 < *dp2)
- return (-1);
-
- if (*dp1 > *dp2)
- return (1);
-
- return (0);
-}
-
-#else
-static int
-refclock_cmpl_fp(
- const double *dp1,
- const double *dp2
- )
-{
- if (*dp1 < *dp2)
- return (-1);
-
+ return -1;
if (*dp1 > *dp2)
- return (1);
-
- return (0);
+ return 1;
+ return 0;
}
-#endif /* QSORT_USES_VOID_P */
/*
@@ -458,6 +382,7 @@ refclock_process_offset(
/*
* refclock_process - process a sample from the clock
+ * refclock_process_f - refclock_process with other than time1 fudge
*
* This routine converts the timecode in the form days, hours, minutes,
* seconds and milliseconds/microseconds to internal timestamp format,
@@ -472,8 +397,9 @@ refclock_process_offset(
* zero and the fraction for pp->lastrec is set to the PPS offset.
*/
int
-refclock_process(
- struct refclockproc *pp /* refclock structure pointer */
+refclock_process_f(
+ struct refclockproc *pp, /* refclock structure pointer */
+ double fudge
)
{
l_fp offset, ltemp;
@@ -493,12 +419,20 @@ refclock_process(
offset.l_uf = 0;
DTOLFP(pp->nsec / 1e9, &ltemp);
L_ADD(&offset, &ltemp);
- refclock_process_offset(pp, offset, pp->lastrec,
- pp->fudgetime1);
+ refclock_process_offset(pp, offset, pp->lastrec, fudge);
return (1);
}
+int
+refclock_process(
+ struct refclockproc *pp /* refclock structure pointer */
+)
+{
+ return refclock_process_f(pp, pp->fudgetime1);
+}
+
+
/*
* refclock_sample - process a pile of samples from the clock
*
@@ -514,7 +448,7 @@ refclock_sample(
struct refclockproc *pp /* refclock structure pointer */
)
{
- int i, j, k, m, n;
+ size_t i, j, k, m, n;
double off[MAXSTAGE];
double offset;
@@ -532,13 +466,7 @@ refclock_sample(
return (0);
if (n > 1)
- qsort(
-#ifdef QSORT_USES_VOID_P
- (void *)
-#else
- (char *)
-#endif
- off, (size_t)n, sizeof(double), refclock_cmpl_fp);
+ qsort(off, n, sizeof(off[0]), refclock_cmpl_fp);
/*
* Reject the furthest from the median of the samples until
@@ -570,9 +498,9 @@ refclock_sample(
if (debug)
printf(
"refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
- n, pp->offset, pp->disp, pp->jitter);
+ (int)n, pp->offset, pp->disp, pp->jitter);
#endif
- return (n);
+ return (int)n;
}
@@ -611,30 +539,23 @@ refclock_receive(
peer->received++;
peer->timereceived = current_time;
if (!peer->reach) {
- report_event(EVNT_REACH, peer);
+ report_event(PEVNT_REACH, peer, NULL);
peer->timereachable = current_time;
}
peer->reach |= 1;
peer->reftime = pp->lastref;
- peer->org = pp->lastrec;
- peer->rootdispersion = pp->disp;
- get_systime(&peer->rec);
+ peer->aorg = pp->lastrec;
+ peer->rootdisp = pp->disp;
+ get_systime(&peer->dst);
if (!refclock_sample(pp))
return;
clock_filter(peer, pp->offset, 0., pp->jitter);
- record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
- peer->offset, peer->delay, clock_phi * (current_time -
- peer->epoch), peer->jitter);
- if (cal_enable && last_offset < MINDISPERSE) {
-#ifdef KERNEL_PLL
- if (peer != sys_peer || pll_status & STA_PPSTIME)
-#else
- if (peer != sys_peer)
-#endif /* KERNEL_PLL */
+ if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer !=
+ NULL) {
+ if (sys_peer->refclktype == REFCLK_ATOM_PPS &&
+ peer->refclktype != REFCLK_ATOM_PPS)
pp->fudgetime1 -= pp->offset * FUDGEFAC;
- else
- pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC;
}
}
@@ -656,25 +577,39 @@ refclock_gtlin(
l_fp *tsptr /* pointer to timestamp returned */
)
{
- char s[BMAX];
- char *dpt, *dpend, *dp;
+ const char *sp, *spend;
+ char *dp, *dpend;
+ int dlen;
- dpt = s;
- dpend = s + refclock_gtraw(rbufp, s, BMAX - 1, tsptr);
- if (dpend - dpt > bmax - 1)
- dpend = dpt + bmax - 1;
- for (dp = lineptr; dpt < dpend; dpt++) {
- char c;
+ if (bmax <= 0)
+ return (0);
- c = *dpt & 0x7f;
+ dp = lineptr;
+ dpend = dp + bmax - 1; /* leave room for NUL pad */
+ sp = (const char *)rbufp->recv_buffer;
+ spend = sp + rbufp->recv_length;
+
+ while (sp != spend && dp != dpend) {
+ char c;
+
+ c = *sp++ & 0x7f;
if (c >= 0x20 && c < 0x7f)
*dp++ = c;
}
- if (dp == lineptr)
- return (0);
-
- *dp = '\0';
- return (dp - lineptr);
+ /* Get length of data written to the destination buffer. If
+ * zero, do *not* place a NUL byte to preserve the previous
+ * buffer content.
+ */
+ dlen = dp - lineptr;
+ if (dlen)
+ *dp = '\0';
+ *tsptr = rbufp->recv_time;
+ DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n",
+ rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen,
+ (dlen != 0)
+ ? lineptr
+ : ""));
+ return (dlen);
}
@@ -691,9 +626,7 @@ refclock_gtlin(
* followed by a NULL character ('\0'), which is not included in the
* count.
*
- * If a timestamp is present in the timecode, as produced by the tty_clk
- * STREAMS module, it returns that as the timestamp; otherwise, it
- * returns the buffer timestamp.
+ * *tsptr receives a copy of the buffer timestamp.
*/
int
refclock_gtraw(
@@ -703,74 +636,99 @@ refclock_gtraw(
l_fp *tsptr /* pointer to timestamp returned */
)
{
- char *dpt, *dpend, *dp;
- l_fp trtmp, tstmp;
- int i;
+ if (bmax <= 0)
+ return (0);
+ bmax -= 1; /* leave room for trailing NUL */
+ if (bmax > rbufp->recv_length)
+ bmax = rbufp->recv_length;
+ memcpy(lineptr, rbufp->recv_buffer, bmax);
+ lineptr[bmax] = '\0';
+
+ *tsptr = rbufp->recv_time;
+ DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n",
+ rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax,
+ lineptr));
+ return (bmax);
+}
- /*
- * Check for the presence of a timestamp left by the tty_clock
- * module and, if present, use that instead of the buffer
- * timestamp captured by the I/O routines. We recognize a
- * timestamp by noting its value is earlier than the buffer
- * timestamp, but not more than one second earlier.
- */
- dpt = (char *)rbufp->recv_buffer;
- dpend = dpt + rbufp->recv_length;
- trtmp = rbufp->recv_time;
- if (dpend >= dpt + 8) {
- if (buftvtots(dpend - 8, &tstmp)) {
- L_SUB(&trtmp, &tstmp);
- if (trtmp.l_ui == 0) {
-#ifdef DEBUG
- if (debug > 1) {
- printf(
- "refclock_gtlin: fd %d ldisc %s",
- rbufp->fd, lfptoa(&trtmp,
- 6));
- get_systime(&trtmp);
- L_SUB(&trtmp, &tstmp);
- printf(" sigio %s\n",
- lfptoa(&trtmp, 6));
- }
-#endif
- dpend -= 8;
- trtmp = tstmp;
- } else
- trtmp = rbufp->recv_time;
- }
+
+/*
+ * indicate_refclock_packet()
+ *
+ * Passes a fragment of refclock input read from the device to the
+ * driver direct input routine, which may consume it (batch it for
+ * queuing once a logical unit is assembled). If it is not so
+ * consumed, queue it for the driver's receive entrypoint.
+ *
+ * The return value is TRUE if the data has been consumed as a fragment
+ * and should not be counted as a received packet.
+ */
+int
+indicate_refclock_packet(
+ struct refclockio * rio,
+ struct recvbuf * rb
+ )
+{
+ /* Does this refclock use direct input routine? */
+ if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) {
+ /*
+ * data was consumed - nothing to pass up
+ * into block input machine
+ */
+ freerecvbuf(rb);
+
+ return TRUE;
}
+ add_full_recv_buffer(rb);
- /*
- * Copy the raw buffer to the user string. The string is padded
- * with a NULL, which is not included in the character count.
+ return FALSE;
+}
+
+
+/*
+ * process_refclock_packet()
+ *
+ * Used for deferred processing of 'io_input' on systems where threading
+ * is used (notably Windows). This is acting as a trampoline to make the
+ * real calls to the refclock functions.
+ */
+#ifdef HAVE_IO_COMPLETION_PORT
+void
+process_refclock_packet(
+ struct recvbuf * rb
+ )
+{
+ struct refclockio * rio;
+
+ /* get the refclockio structure from the receive buffer */
+ rio = &rb->recv_peer->procptr->io;
+
+ /* call 'clock_recv' if either there is no input function or the
+ * raw input function tells us to feed the packet to the
+ * receiver.
*/
- if (dpend - dpt > bmax - 1)
- dpend = dpt + bmax - 1;
- for (dp = lineptr; dpt < dpend; dpt++)
- *dp++ = *dpt;
- *dp = '\0';
- i = dp - lineptr;
-#ifdef DEBUG
- if (debug > 1)
- printf("refclock_gtraw: fd %d time %s timecode %d %s\n",
- rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
-#endif
- *tsptr = trtmp;
- return (i);
+ if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) {
+ rio->recvcount++;
+ packets_received++;
+ handler_pkts++;
+ (*rio->clock_recv)(rb);
+ }
}
+#endif /* HAVE_IO_COMPLETION_PORT */
/*
* The following code does not apply to WINNT & VMS ...
*/
-#if !defined SYS_VXWORKS && !defined SYS_WINNT
+#if !defined(SYS_VXWORKS) && !defined(SYS_WINNT)
#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
/*
* refclock_open - open serial port for reference clock
*
* This routine opens a serial port for I/O and sets default options. It
- * returns the file descriptor if success and zero if failure.
+ * returns the file descriptor if successful, or logs an error and
+ * returns -1.
*/
int
refclock_open(
@@ -781,6 +739,9 @@ refclock_open(
{
int fd;
int omode;
+#ifdef O_NONBLOCK
+ char trash[128]; /* litter bin for old input data */
+#endif
/*
* Open serial port and set default options
@@ -794,21 +755,41 @@ refclock_open(
#endif
fd = open(dev, omode, 0777);
+ /* refclock_open() long returned 0 on failure, avoid it. */
+ if (0 == fd) {
+ fd = dup(0);
+ SAVE_ERRNO(
+ close(0);
+ )
+ }
if (fd < 0) {
- msyslog(LOG_ERR, "refclock_open %s: %m", dev);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR, "refclock_open %s: %m", dev);
+ )
+ return -1;
}
if (!refclock_setup(fd, speed, lflags)) {
close(fd);
- return (0);
+ return -1;
}
if (!refclock_ioctl(fd, lflags)) {
close(fd);
- return (0);
+ return -1;
}
- return (fd);
+#ifdef O_NONBLOCK
+ /*
+ * We want to make sure there is no pending trash in the input
+ * buffer. Since we have non-blocking IO available, this is a
+ * good moment to read and dump all available outdated stuff
+ * that might have become toxic for the driver.
+ */
+ while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR)
+ /*NOP*/;
+#endif
+ return fd;
}
+
/*
* refclock_setup - initialize terminal interface structure
*/
@@ -821,9 +802,6 @@ refclock_setup(
{
int i;
TTY ttyb, *ttyp;
-#ifdef PPS
- fdpps = fd; /* ppsclock legacy */
-#endif /* PPS */
/*
* By default, the serial line port is initialized in canonical
@@ -840,9 +818,12 @@ refclock_setup(
* POSIX serial line parameters (termios interface)
*/
if (tcgetattr(fd, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d tcgetattr: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d tcgetattr: %m",
+ fd);
+ )
+ return FALSE;
}
/*
@@ -857,7 +838,7 @@ refclock_setup(
ttyp->c_cflag = CS8 | CLOCAL | CREAD;
if (lflags & LDISC_7O1) {
/* HP Z3801A needs 7-bit, odd parity */
- ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
+ ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
}
cfsetispeed(&ttyb, speed);
cfsetospeed(&ttyb, speed);
@@ -896,10 +877,22 @@ refclock_setup(
if (lflags & LDISC_ECHO)
ttyp->c_lflag |= ECHO;
if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TCSANOW: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TCSANOW: %m",
+ fd);
+ )
+ return FALSE;
}
+
+ /*
+ * flush input and output buffers to discard any outdated stuff
+ * that might have become toxic for the driver. Failing to do so
+ * is logged, but we keep our fingers crossed otherwise.
+ */
+ if (tcflush(fd, TCIOFLUSH) < 0)
+ msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m",
+ fd);
#endif /* HAVE_TERMIOS */
#ifdef HAVE_SYSV_TTYS
@@ -909,9 +902,12 @@ refclock_setup(
*
*/
if (ioctl(fd, TCGETA, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TCGETA: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TCGETA: %m",
+ fd);
+ )
+ return FALSE;
}
/*
@@ -957,9 +953,11 @@ refclock_setup(
ttyp->c_cc[VMIN] = 1;
}
if (ioctl(fd, TCSETA, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TCSETA: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TCSETA: %m", fd);
+ )
+ return FALSE;
}
#endif /* HAVE_SYSV_TTYS */
@@ -969,23 +967,26 @@ refclock_setup(
* 4.3bsd serial line parameters (sgttyb interface)
*/
if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TIOCGETP: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TIOCGETP: %m",
+ fd);
+ )
+ return FALSE;
}
if (speed)
ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
ttyp->sg_flags = EVENP | ODDP | CRMOD;
if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup TIOCSETP: %m");
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m");
+ )
+ return FALSE;
}
#endif /* HAVE_BSD_TTYS */
return(1);
}
#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
-#endif /* SYS_VXWORKS SYS_WINNT */
/*
@@ -994,8 +995,8 @@ refclock_setup(
* This routine attempts to hide the internal, system-specific details
* of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
* (sgtty) interfaces with varying degrees of success. The routine sets
- * up optional features such as tty_clk. The routine returns 1 if
- * success and 0 if failure.
+ * up optional features such as tty_clk. The routine returns TRUE if
+ * successful.
*/
int
refclock_ioctl(
@@ -1004,53 +1005,13 @@ refclock_ioctl(
)
{
/*
- * simply return 1 if no UNIX line discipline is supported
- */
-#if !defined SYS_VXWORKS && !defined SYS_WINNT
-#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
-
-#ifdef DEBUG
- if (debug)
- printf("refclock_ioctl: fd %d flags 0x%x\n", fd,
- lflags);
-#endif
-#ifdef TTYCLK
-
- /*
- * The TTYCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module and System V STREAMS
- * support. If not available, don't complain.
+ * simply return TRUE if no UNIX line discipline is supported
*/
- if (lflags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
- int rval = 0;
+ DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags));
- if (ioctl(fd, I_PUSH, "clk") < 0) {
- msyslog(LOG_NOTICE,
- "refclock_ioctl fd %d I_PUSH: %m", fd);
- return (0);
-#ifdef CLK_SETSTR
- } else {
- char *str;
-
- if (lflags & LDISC_CLKPPS)
- str = "\377";
- else if (lflags & LDISC_ACTS)
- str = "*";
- else
- str = "\n";
- if (ioctl(fd, CLK_SETSTR, str) < 0) {
- msyslog(LOG_ERR,
- "refclock_ioctl fd %d CLK_SETSTR: %m", fd);
- return (0);
- }
-#endif /*CLK_SETSTR */
- }
- }
-#endif /* TTYCLK */
-#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
-#endif /* SYS_VXWORKS SYS_WINNT */
- return (1);
+ return TRUE;
}
+#endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */
/*
@@ -1064,8 +1025,8 @@ refclock_ioctl(
*/
void
refclock_control(
- struct sockaddr_storage *srcadr,
- struct refclockstat *in,
+ sockaddr_u *srcadr,
+ const struct refclockstat *in,
struct refclockstat *out
)
{
@@ -1077,30 +1038,24 @@ refclock_control(
/*
* Check for valid address and running peer
*/
- if (srcadr->ss_family != AF_INET)
- return;
-
if (!ISREFCLOCKADR(srcadr))
return;
clktype = (u_char)REFCLOCKTYPE(srcadr);
unit = REFCLOCKUNIT(srcadr);
- if (clktype >= num_refclock_conf || unit >= MAXUNIT)
- return;
- peer = typeunit[clktype][unit];
- if (peer == NULL)
- return;
+ peer = findexistingpeer(srcadr, NULL, NULL, -1, 0);
- if (peer->procptr == NULL)
+ if (NULL == peer)
return;
+ NTP_INSIST(peer->procptr != NULL);
pp = peer->procptr;
/*
* Initialize requested data
*/
- if (in != 0) {
+ if (in != NULL) {
if (in->haveflags & CLK_HAVETIME1)
pp->fudgetime1 = in->fudgetime1;
if (in->haveflags & CLK_HAVETIME2)
@@ -1130,14 +1085,25 @@ refclock_control(
/*
* Readback requested data
*/
- if (out != 0) {
- out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
- CLK_HAVEVAL2 | CLK_HAVEFLAG4;
- out->fudgetime1 = pp->fudgetime1;
- out->fudgetime2 = pp->fudgetime2;
+ if (out != NULL) {
out->fudgeval1 = pp->stratum;
out->fudgeval2 = pp->refid;
+ out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
+ out->fudgetime1 = pp->fudgetime1;
+ if (0.0 != out->fudgetime1)
+ out->haveflags |= CLK_HAVETIME1;
+ out->fudgetime2 = pp->fudgetime2;
+ if (0.0 != out->fudgetime2)
+ out->haveflags |= CLK_HAVETIME2;
out->flags = (u_char) pp->sloppyclockflag;
+ if (CLK_FLAG1 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG1;
+ if (CLK_FLAG2 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG2;
+ if (CLK_FLAG3 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG3;
+ if (CLK_FLAG4 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG4;
out->timereset = current_time - pp->timestarted;
out->polls = pp->polls;
@@ -1149,7 +1115,7 @@ refclock_control(
out->currentstatus = pp->currentstatus;
out->type = pp->type;
out->clockdesc = pp->clockdesc;
- out->lencode = pp->lencode;
+ out->lencode = (u_short)pp->lencode;
out->p_lastcode = pp->a_lastcode;
}
@@ -1170,32 +1136,28 @@ refclock_control(
*/
void
refclock_buginfo(
- struct sockaddr_storage *srcadr, /* clock address */
+ sockaddr_u *srcadr, /* clock address */
struct refclockbug *bug /* output structure */
)
{
struct peer *peer;
struct refclockproc *pp;
- u_char clktype;
+ int clktype;
int unit;
- int i;
+ unsigned u;
/*
* Check for valid address and peer structure
*/
- if (srcadr->ss_family != AF_INET)
- return;
-
if (!ISREFCLOCKADR(srcadr))
return;
clktype = (u_char) REFCLOCKTYPE(srcadr);
unit = REFCLOCKUNIT(srcadr);
- if (clktype >= num_refclock_conf || unit >= MAXUNIT)
- return;
- peer = typeunit[clktype][unit];
- if (peer == NULL)
+ peer = findexistingpeer(srcadr, NULL, NULL, -1, 0);
+
+ if (NULL == peer || NULL == peer->procptr)
return;
pp = peer->procptr;
@@ -1216,8 +1178,8 @@ refclock_buginfo(
bug->stimes = 0xfffffffc;
bug->times[0] = pp->lastref;
bug->times[1] = pp->lastrec;
- for (i = 2; i < (int)bug->ntimes; i++)
- DTOLFP(pp->filter[i - 2], &bug->times[i]);
+ for (u = 2; u < bug->ntimes; u++)
+ DTOLFP(pp->filter[u - 2], &bug->times[u]);
/*
* Give the stuff to the clock
@@ -1226,4 +1188,145 @@ refclock_buginfo(
(refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
}
+
+#ifdef HAVE_PPSAPI
+/*
+ * refclock_ppsapi - initialize/update ppsapi
+ *
+ * This routine is called after the fudge command to open the PPSAPI
+ * interface for later parameter setting after the fudge command.
+ */
+int
+refclock_ppsapi(
+ int fddev, /* fd device */
+ struct refclock_atom *ap /* atom structure pointer */
+ )
+{
+ if (ap->handle == 0) {
+ if (time_pps_create(fddev, &ap->handle) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_ppsapi: time_pps_create: %m");
+ return (0);
+ }
+ }
+ return (1);
+}
+
+
+/*
+ * refclock_params - set ppsapi parameters
+ *
+ * This routine is called to set the PPSAPI parameters after the fudge
+ * command.
+ */
+int
+refclock_params(
+ int mode, /* mode bits */
+ struct refclock_atom *ap /* atom structure pointer */
+ )
+{
+ ZERO(ap->pps_params);
+ ap->pps_params.api_version = PPS_API_VERS_1;
+
+ /*
+ * Solaris serial ports provide PPS pulse capture only on the
+ * assert edge. FreeBSD serial ports provide capture on the
+ * clear edge, while FreeBSD parallel ports provide capture
+ * on the assert edge. Your mileage may vary.
+ */
+ if (mode & CLK_FLAG2)
+ ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR;
+ else
+ ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT;
+ if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_params: time_pps_setparams: %m");
+ return (0);
+ }
+
+ /*
+ * If flag3 is lit, select the kernel PPS if we can.
+ */
+ if (mode & CLK_FLAG3) {
+ if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS,
+ ap->pps_params.mode & ~PPS_TSFMT_TSPEC,
+ PPS_TSFMT_TSPEC) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_params: time_pps_kcbind: %m");
+ return (0);
+ }
+ hardpps_enable = 1;
+ }
+ return (1);
+}
+
+
+/*
+ * refclock_pps - called once per second
+ *
+ * This routine is called once per second. It snatches the PPS
+ * timestamp from the kernel and saves the sign-extended fraction in
+ * a circular buffer for processing at the next poll event.
+ */
+int
+refclock_pps(
+ struct peer *peer, /* peer structure pointer */
+ struct refclock_atom *ap, /* atom structure pointer */
+ int mode /* mode bits */
+ )
+{
+ struct refclockproc *pp;
+ pps_info_t pps_info;
+ struct timespec timeout;
+ double dtemp;
+
+ /*
+ * We require the clock to be synchronized before setting the
+ * parameters. When the parameters have been set, fetch the
+ * most recent PPS timestamp.
+ */
+ pp = peer->procptr;
+ if (ap->handle == 0)
+ return (0);
+
+ if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) {
+ if (refclock_params(pp->sloppyclockflag, ap) < 1)
+ return (0);
+ }
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+ ZERO(pps_info);
+ if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info,
+ &timeout) < 0) {
+ refclock_report(peer, CEVNT_FAULT);
+ return (0);
+ }
+ timeout = ap->ts;
+ if (ap->pps_params.mode & PPS_CAPTUREASSERT)
+ ap->ts = pps_info.assert_timestamp;
+ else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
+ ap->ts = pps_info.clear_timestamp;
+ else
+ return (0);
+
+ if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout)))
+ return (0);
+
+ /*
+ * Convert to signed fraction offset and stuff in median filter.
+ */
+ pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970;
+ dtemp = ap->ts.tv_nsec / 1e9;
+ pp->lastrec.l_uf = (u_int32)(dtemp * FRAC);
+ if (dtemp > .5)
+ dtemp -= 1.;
+ SAMPLE(-dtemp + pp->fudgetime1);
+#ifdef DEBUG
+ if (debug > 1)
+ printf("refclock_pps: %lu %f %f\n", current_time,
+ dtemp, pp->fudgetime1);
+#endif
+ return (1);
+}
+#endif /* HAVE_PPSAPI */
#endif /* REFCLOCK */
OpenPOWER on IntegriCloud