diff options
author | delphij <delphij@FreeBSD.org> | 2015-07-15 19:21:26 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2015-07-15 19:21:26 +0000 |
commit | 2a25cee78ab1d37e7d2bc40ae675646974d99f56 (patch) | |
tree | b0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/ntpd/ntp_refclock.c | |
parent | a0741a75537b2e0514472ac3b28afc55a7846c30 (diff) | |
download | FreeBSD-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.c | 801 |
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, <emp); L_ADD(&offset, <emp); - 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 */ |