154359Sroberto/* 254359Sroberto * ntp_refclock - processing support for reference clocks 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto# include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include "ntpd.h" 954359Sroberto#include "ntp_io.h" 1054359Sroberto#include "ntp_unixtime.h" 1182498Sroberto#include "ntp_tty.h" 1254359Sroberto#include "ntp_refclock.h" 1354359Sroberto#include "ntp_stdlib.h" 1454359Sroberto 1582498Sroberto#include <stdio.h> 1682498Sroberto 1782498Sroberto#ifdef HAVE_SYS_IOCTL_H 1882498Sroberto# include <sys/ioctl.h> 1982498Sroberto#endif /* HAVE_SYS_IOCTL_H */ 2082498Sroberto 2154359Sroberto#ifdef REFCLOCK 2254359Sroberto 2354359Sroberto#ifdef TTYCLK 2456746Sroberto# ifdef HAVE_SYS_CLKDEFS_H 2554359Sroberto# include <sys/clkdefs.h> 2682498Sroberto# include <stropts.h> 2754359Sroberto# endif 2856746Sroberto# ifdef HAVE_SYS_SIO_H 2956746Sroberto# include <sys/sio.h> 3056746Sroberto# endif 3154359Sroberto#endif /* TTYCLK */ 3254359Sroberto 3382498Sroberto#ifdef KERNEL_PLL 3482498Sroberto#include "ntp_syscall.h" 3582498Sroberto#endif /* KERNEL_PLL */ 3654359Sroberto 3754359Sroberto/* 3854359Sroberto * Reference clock support is provided here by maintaining the fiction 3954359Sroberto * that the clock is actually a peer. As no packets are exchanged with a 4054359Sroberto * reference clock, however, we replace the transmit, receive and packet 4154359Sroberto * procedures with separate code to simulate them. Routines 4254359Sroberto * refclock_transmit() and refclock_receive() maintain the peer 4354359Sroberto * variables in a state analogous to an actual peer and pass reference 4454359Sroberto * clock data on through the filters. Routines refclock_peer() and 4554359Sroberto * refclock_unpeer() are called to initialize and terminate reference 4654359Sroberto * clock associations. A set of utility routines is included to open 4754359Sroberto * serial devices, process sample data, edit input lines to extract 4854359Sroberto * embedded timestamps and to peform various debugging functions. 4954359Sroberto * 5054359Sroberto * The main interface used by these routines is the refclockproc 5154359Sroberto * structure, which contains for most drivers the decimal equivalants of 5254359Sroberto * the year, day, month, hour, second and millisecond/microsecond 5354359Sroberto * decoded from the ASCII timecode. Additional information includes the 5454359Sroberto * receive timestamp, exception report, statistics tallies, etc. In 5554359Sroberto * addition, there may be a driver-specific unit structure used for 5654359Sroberto * local control of the device. 5754359Sroberto * 5854359Sroberto * The support routines are passed a pointer to the peer structure, 5954359Sroberto * which is used for all peer-specific processing and contains a pointer 6054359Sroberto * to the refclockproc structure, which in turn containes a pointer to 6154359Sroberto * the unit structure, if used. The peer structure is identified by an 62182007Sroberto * interface address in the dotted quad form 127.127.t.u (for now only 63182007Sroberto * IPv4 addresses are used, so we need to be sure the address is it), 64182007Sroberto * where t is the clock type and u the unit. Some legacy drivers derive 65182007Sroberto * the refclockproc structure pointer from the table 66182007Sroberto * typeunit[type][unit]. This interface is strongly discouraged and may 67182007Sroberto * be abandoned in future. 6854359Sroberto */ 6954359Sroberto#define MAXUNIT 4 /* max units */ 7082498Sroberto#define FUDGEFAC .1 /* fudge correction factor */ 71182007Sroberto#define LF 0x0a /* ASCII LF */ 7254359Sroberto 73182007Sroberto#ifdef PPS 74182007Srobertoint fdpps; /* ppsclock legacy */ 75182007Sroberto#endif /* PPS */ 76182007Srobertoint cal_enable; /* enable refclock calibrate */ 7754359Sroberto 7854359Sroberto/* 7954359Sroberto * Type/unit peer index. Used to find the peer structure for control and 8054359Sroberto * debugging. When all clock drivers have been converted to new style, 8154359Sroberto * this dissapears. 8254359Sroberto */ 8354359Srobertostatic struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT]; 8454359Sroberto 8554359Sroberto/* 8654359Sroberto * Forward declarations 8754359Sroberto */ 8854359Sroberto#ifdef QSORT_USES_VOID_P 8954359Srobertostatic int refclock_cmpl_fp P((const void *, const void *)); 9054359Sroberto#else 9154359Srobertostatic int refclock_cmpl_fp P((const double *, const double *)); 9254359Sroberto#endif /* QSORT_USES_VOID_P */ 9354359Srobertostatic int refclock_sample P((struct refclockproc *)); 9454359Sroberto 95182007Sroberto 9654359Sroberto/* 9754359Sroberto * refclock_report - note the occurance of an event 9854359Sroberto * 9954359Sroberto * This routine presently just remembers the report and logs it, but 10054359Sroberto * does nothing heroic for the trap handler. It tries to be a good 10154359Sroberto * citizen and bothers the system log only if things change. 10254359Sroberto */ 10354359Srobertovoid 10454359Srobertorefclock_report( 10554359Sroberto struct peer *peer, 10654359Sroberto int code 10754359Sroberto ) 10854359Sroberto{ 10954359Sroberto struct refclockproc *pp; 11054359Sroberto 111132451Sroberto pp = peer->procptr; 112132451Sroberto if (pp == NULL) 11354359Sroberto return; 114182007Sroberto 115182007Sroberto switch (code) { 116182007Sroberto case CEVNT_NOMINAL: 117182007Sroberto break; 118182007Sroberto 119182007Sroberto case CEVNT_TIMEOUT: 120182007Sroberto pp->noreply++; 121182007Sroberto break; 122182007Sroberto 123182007Sroberto case CEVNT_BADREPLY: 124182007Sroberto pp->badformat++; 125182007Sroberto break; 126182007Sroberto 127182007Sroberto case CEVNT_FAULT: 128182007Sroberto break; 129182007Sroberto 130182007Sroberto case CEVNT_PROP: 131182007Sroberto break; 132182007Sroberto 133182007Sroberto case CEVNT_BADDATE: 134182007Sroberto case CEVNT_BADTIME: 135182007Sroberto pp->baddata++; 136182007Sroberto break; 137182007Sroberto 138182007Sroberto default: 139182007Sroberto /* shouldn't happen */ 140182007Sroberto break; 141182007Sroberto } 142182007Sroberto 14354359Sroberto if (pp->currentstatus != code) { 144132451Sroberto pp->currentstatus = (u_char)code; 145182007Sroberto 146182007Sroberto /* RFC1305: copy only iff not CEVNT_NOMINAL */ 147182007Sroberto if (code != CEVNT_NOMINAL) 148182007Sroberto pp->lastevent = (u_char)code; 149182007Sroberto 15054359Sroberto if (code == CEVNT_FAULT) 15154359Sroberto msyslog(LOG_ERR, 152182007Sroberto "clock %s event '%s' (0x%02x)", 153182007Sroberto refnumtoa(&peer->srcadr), 154182007Sroberto ceventstr(code), code); 15554359Sroberto else { 15654359Sroberto NLOG(NLOG_CLOCKEVENT) 157182007Sroberto msyslog(LOG_INFO, 158182007Sroberto "clock %s event '%s' (0x%02x)", 159182007Sroberto refnumtoa(&peer->srcadr), 160182007Sroberto ceventstr(code), code); 16154359Sroberto } 162182007Sroberto 163182007Sroberto /* RFC1305: post peer clock event */ 164182007Sroberto report_event(EVNT_PEERCLOCK, peer); 16554359Sroberto } 16654359Sroberto} 16754359Sroberto 16854359Sroberto/* 16954359Sroberto * init_refclock - initialize the reference clock drivers 17054359Sroberto * 17154359Sroberto * This routine calls each of the drivers in turn to initialize internal 17254359Sroberto * variables, if necessary. Most drivers have nothing to say at this 17354359Sroberto * point. 17454359Sroberto */ 17554359Srobertovoid 17654359Srobertoinit_refclock(void) 17754359Sroberto{ 17854359Sroberto int i, j; 17954359Sroberto 18054359Sroberto for (i = 0; i < (int)num_refclock_conf; i++) { 18154359Sroberto if (refclock_conf[i]->clock_init != noentry) 18254359Sroberto (refclock_conf[i]->clock_init)(); 18354359Sroberto for (j = 0; j < MAXUNIT; j++) 18454359Sroberto typeunit[i][j] = 0; 18554359Sroberto } 18654359Sroberto} 18754359Sroberto 18854359Sroberto 18954359Sroberto/* 19054359Sroberto * refclock_newpeer - initialize and start a reference clock 19154359Sroberto * 19254359Sroberto * This routine allocates and initializes the interface structure which 19354359Sroberto * supports a reference clock in the form of an ordinary NTP peer. A 19454359Sroberto * driver-specific support routine completes the initialization, if 19554359Sroberto * used. Default peer variables which identify the clock and establish 19654359Sroberto * its reference ID and stratum are set here. It returns one if success 19754359Sroberto * and zero if the clock address is invalid or already running, 19854359Sroberto * insufficient resources are available or the driver declares a bum 19954359Sroberto * rap. 20054359Sroberto */ 20154359Srobertoint 20254359Srobertorefclock_newpeer( 20354359Sroberto struct peer *peer /* peer structure pointer */ 20454359Sroberto ) 20554359Sroberto{ 20654359Sroberto struct refclockproc *pp; 20754359Sroberto u_char clktype; 20854359Sroberto int unit; 20954359Sroberto 21054359Sroberto /* 21154359Sroberto * Check for valid clock address. If already running, shut it 21254359Sroberto * down first. 21354359Sroberto */ 214132451Sroberto if (peer->srcadr.ss_family != AF_INET) { 215132451Sroberto msyslog(LOG_ERR, 216132451Sroberto "refclock_newpeer: clock address %s invalid, address family not implemented for refclock", 217132451Sroberto stoa(&peer->srcadr)); 218132451Sroberto return (0); 219132451Sroberto } 22054359Sroberto if (!ISREFCLOCKADR(&peer->srcadr)) { 22154359Sroberto msyslog(LOG_ERR, 22254359Sroberto "refclock_newpeer: clock address %s invalid", 223132451Sroberto stoa(&peer->srcadr)); 22454359Sroberto return (0); 22554359Sroberto } 22654359Sroberto clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 22754359Sroberto unit = REFCLOCKUNIT(&peer->srcadr); 22854359Sroberto if (clktype >= num_refclock_conf || unit >= MAXUNIT || 22954359Sroberto refclock_conf[clktype]->clock_start == noentry) { 23054359Sroberto msyslog(LOG_ERR, 23154359Sroberto "refclock_newpeer: clock type %d invalid\n", 23254359Sroberto clktype); 23354359Sroberto return (0); 23454359Sroberto } 23554359Sroberto 23654359Sroberto /* 23754359Sroberto * Allocate and initialize interface structure 23854359Sroberto */ 239132451Sroberto pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)); 240132451Sroberto if (pp == NULL) 24154359Sroberto return (0); 242182007Sroberto 24354359Sroberto memset((char *)pp, 0, sizeof(struct refclockproc)); 24454359Sroberto typeunit[clktype][unit] = peer; 24554359Sroberto peer->procptr = pp; 24654359Sroberto 24754359Sroberto /* 24854359Sroberto * Initialize structures 24954359Sroberto */ 25054359Sroberto peer->refclktype = clktype; 251132451Sroberto peer->refclkunit = (u_char)unit; 252182007Sroberto peer->flags |= FLAG_REFCLOCK | FLAG_FIXPOLL; 253182007Sroberto peer->leap = LEAP_NOTINSYNC; 25454359Sroberto peer->stratum = STRATUM_REFCLOCK; 255182007Sroberto peer->ppoll = peer->maxpoll; 25654359Sroberto pp->type = clktype; 25754359Sroberto pp->timestarted = current_time; 25854359Sroberto 25954359Sroberto /* 26054359Sroberto * Set peer.pmode based on the hmode. For appearances only. 26154359Sroberto */ 26254359Sroberto switch (peer->hmode) { 263132451Sroberto case MODE_ACTIVE: 26454359Sroberto peer->pmode = MODE_PASSIVE; 26554359Sroberto break; 26654359Sroberto 267132451Sroberto default: 26854359Sroberto peer->pmode = MODE_SERVER; 26954359Sroberto break; 27054359Sroberto } 27154359Sroberto 27254359Sroberto /* 27354359Sroberto * Do driver dependent initialization. The above defaults 27454359Sroberto * can be wiggled, then finish up for consistency. 27554359Sroberto */ 27654359Sroberto if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { 27782498Sroberto refclock_unpeer(peer); 27854359Sroberto return (0); 27954359Sroberto } 280132451Sroberto peer->refid = pp->refid; 28154359Sroberto return (1); 28254359Sroberto} 28354359Sroberto 28454359Sroberto 28554359Sroberto/* 28654359Sroberto * refclock_unpeer - shut down a clock 28754359Sroberto */ 28854359Srobertovoid 28954359Srobertorefclock_unpeer( 29054359Sroberto struct peer *peer /* peer structure pointer */ 29154359Sroberto ) 29254359Sroberto{ 29354359Sroberto u_char clktype; 29454359Sroberto int unit; 29554359Sroberto 29654359Sroberto /* 29754359Sroberto * Wiggle the driver to release its resources, then give back 29854359Sroberto * the interface structure. 29954359Sroberto */ 30054359Sroberto if (!peer->procptr) 30154359Sroberto return; 302182007Sroberto 30354359Sroberto clktype = peer->refclktype; 30454359Sroberto unit = peer->refclkunit; 30554359Sroberto if (refclock_conf[clktype]->clock_shutdown != noentry) 30654359Sroberto (refclock_conf[clktype]->clock_shutdown)(unit, peer); 30754359Sroberto free(peer->procptr); 30854359Sroberto peer->procptr = 0; 30954359Sroberto} 31054359Sroberto 31154359Sroberto 31254359Sroberto/* 313182007Sroberto * refclock_timer - called once per second for housekeeping. 314182007Sroberto */ 315182007Srobertovoid 316182007Srobertorefclock_timer( 317182007Sroberto struct peer *peer /* peer structure pointer */ 318182007Sroberto ) 319182007Sroberto{ 320182007Sroberto u_char clktype; 321182007Sroberto int unit; 322182007Sroberto 323182007Sroberto clktype = peer->refclktype; 324182007Sroberto unit = peer->refclkunit; 325182007Sroberto if (refclock_conf[clktype]->clock_timer != noentry) 326182007Sroberto (refclock_conf[clktype]->clock_timer)(unit, peer); 327182007Sroberto} 328182007Sroberto 329182007Sroberto 330182007Sroberto/* 33154359Sroberto * refclock_transmit - simulate the transmit procedure 33254359Sroberto * 33354359Sroberto * This routine implements the NTP transmit procedure for a reference 33454359Sroberto * clock. This provides a mechanism to call the driver at the NTP poll 33554359Sroberto * interval, as well as provides a reachability mechanism to detect a 33654359Sroberto * broken radio or other madness. 33754359Sroberto */ 33854359Srobertovoid 33954359Srobertorefclock_transmit( 34054359Sroberto struct peer *peer /* peer structure pointer */ 34154359Sroberto ) 34254359Sroberto{ 34354359Sroberto u_char clktype; 34454359Sroberto int unit; 34554359Sroberto 34654359Sroberto clktype = peer->refclktype; 34754359Sroberto unit = peer->refclkunit; 34854359Sroberto peer->sent++; 349182007Sroberto get_systime(&peer->xmt); 35054359Sroberto 35154359Sroberto /* 35254359Sroberto * This is a ripoff of the peer transmit routine, but 35354359Sroberto * specialized for reference clocks. We do a little less 35454359Sroberto * protocol here and call the driver-specific transmit routine. 35554359Sroberto */ 35654359Sroberto if (peer->burst == 0) { 35754359Sroberto u_char oreach; 35854359Sroberto#ifdef DEBUG 35954359Sroberto if (debug) 36054359Sroberto printf("refclock_transmit: at %ld %s\n", 361132451Sroberto current_time, stoa(&(peer->srcadr))); 36254359Sroberto#endif 36354359Sroberto 36454359Sroberto /* 36554359Sroberto * Update reachability and poll variables like the 36654359Sroberto * network code. 36754359Sroberto */ 36854359Sroberto oreach = peer->reach; 36982498Sroberto peer->reach <<= 1; 370182007Sroberto peer->outdate = current_time; 37182498Sroberto if (!peer->reach) { 37282498Sroberto if (oreach) { 37354359Sroberto report_event(EVNT_UNREACH, peer); 37454359Sroberto peer->timereachable = current_time; 37554359Sroberto } 37654359Sroberto } else { 377182007Sroberto if (!(oreach & 0x07)) { 37854359Sroberto clock_filter(peer, 0., 0., MAXDISPERSE); 37954359Sroberto clock_select(); 38054359Sroberto } 38154359Sroberto if (peer->flags & FLAG_BURST) 38254359Sroberto peer->burst = NSTAGE; 38354359Sroberto } 384182007Sroberto } else { 385182007Sroberto peer->burst--; 38654359Sroberto } 38754359Sroberto if (refclock_conf[clktype]->clock_poll != noentry) 38854359Sroberto (refclock_conf[clktype]->clock_poll)(unit, peer); 389182007Sroberto poll_update(peer, peer->hpoll); 39054359Sroberto} 39154359Sroberto 39254359Sroberto 39354359Sroberto/* 39454359Sroberto * Compare two doubles - used with qsort() 39554359Sroberto */ 39654359Sroberto#ifdef QSORT_USES_VOID_P 39754359Srobertostatic int 39854359Srobertorefclock_cmpl_fp( 39954359Sroberto const void *p1, 40054359Sroberto const void *p2 40154359Sroberto ) 40254359Sroberto{ 40354359Sroberto const double *dp1 = (const double *)p1; 40454359Sroberto const double *dp2 = (const double *)p2; 40554359Sroberto 40654359Sroberto if (*dp1 < *dp2) 40754359Sroberto return (-1); 408182007Sroberto 40954359Sroberto if (*dp1 > *dp2) 41054359Sroberto return (1); 411182007Sroberto 41254359Sroberto return (0); 41354359Sroberto} 414182007Sroberto 41554359Sroberto#else 41654359Srobertostatic int 41754359Srobertorefclock_cmpl_fp( 41854359Sroberto const double *dp1, 41954359Sroberto const double *dp2 42054359Sroberto ) 42154359Sroberto{ 42254359Sroberto if (*dp1 < *dp2) 42354359Sroberto return (-1); 424182007Sroberto 42554359Sroberto if (*dp1 > *dp2) 42654359Sroberto return (1); 427182007Sroberto 42854359Sroberto return (0); 42954359Sroberto} 43054359Sroberto#endif /* QSORT_USES_VOID_P */ 43154359Sroberto 43254359Sroberto 43354359Sroberto/* 43454359Sroberto * refclock_process_offset - update median filter 43554359Sroberto * 43682498Sroberto * This routine uses the given offset and timestamps to construct a new 43782498Sroberto * entry in the median filter circular buffer. Samples that overflow the 43882498Sroberto * filter are quietly discarded. 43954359Sroberto */ 44054359Srobertovoid 44154359Srobertorefclock_process_offset( 442132451Sroberto struct refclockproc *pp, /* refclock structure pointer */ 443132451Sroberto l_fp lasttim, /* last timecode timestamp */ 444132451Sroberto l_fp lastrec, /* last receive timestamp */ 44554359Sroberto double fudge 44654359Sroberto ) 44754359Sroberto{ 448132451Sroberto l_fp lftemp; 44954359Sroberto double doffset; 45054359Sroberto 45154359Sroberto pp->lastrec = lastrec; 452132451Sroberto lftemp = lasttim; 453132451Sroberto L_SUB(&lftemp, &lastrec); 454132451Sroberto LFPTOD(&lftemp, doffset); 45554359Sroberto SAMPLE(doffset + fudge); 45654359Sroberto} 45754359Sroberto 458182007Sroberto 45954359Sroberto/* 46054359Sroberto * refclock_process - process a sample from the clock 46154359Sroberto * 46254359Sroberto * This routine converts the timecode in the form days, hours, minutes, 46354359Sroberto * seconds and milliseconds/microseconds to internal timestamp format, 46454359Sroberto * then constructs a new entry in the median filter circular buffer. 46554359Sroberto * Return success (1) if the data are correct and consistent with the 46654359Sroberto * converntional calendar. 467182007Sroberto * 468182007Sroberto * Important for PPS users: Normally, the pp->lastrec is set to the 469182007Sroberto * system time when the on-time character is received and the pp->year, 470182007Sroberto * ..., pp->second decoded and the seconds fraction pp->nsec in 471182007Sroberto * nanoseconds). When a PPS offset is available, pp->nsec is forced to 472182007Sroberto * zero and the fraction for pp->lastrec is set to the PPS offset. 473182007Sroberto */ 47454359Srobertoint 47554359Srobertorefclock_process( 476132451Sroberto struct refclockproc *pp /* refclock structure pointer */ 47754359Sroberto ) 47854359Sroberto{ 479132451Sroberto l_fp offset, ltemp; 48054359Sroberto 48154359Sroberto /* 48254359Sroberto * Compute the timecode timestamp from the days, hours, minutes, 48354359Sroberto * seconds and milliseconds/microseconds of the timecode. Use 48454359Sroberto * clocktime() for the aggregate seconds and the msec/usec for 48554359Sroberto * the fraction, when present. Note that this code relies on the 48654359Sroberto * filesystem time for the years and does not use the years of 48754359Sroberto * the timecode. 48854359Sroberto */ 48954359Sroberto if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 49054359Sroberto pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 49154359Sroberto return (0); 492182007Sroberto 493132451Sroberto offset.l_uf = 0; 494132451Sroberto DTOLFP(pp->nsec / 1e9, <emp); 495132451Sroberto L_ADD(&offset, <emp); 49654359Sroberto refclock_process_offset(pp, offset, pp->lastrec, 49754359Sroberto pp->fudgetime1); 49854359Sroberto return (1); 49954359Sroberto} 50054359Sroberto 501182007Sroberto 50254359Sroberto/* 50354359Sroberto * refclock_sample - process a pile of samples from the clock 50454359Sroberto * 50554359Sroberto * This routine implements a recursive median filter to suppress spikes 50654359Sroberto * in the data, as well as determine a performance statistic. It 507182007Sroberto * calculates the mean offset and RMS jitter. A time adjustment 50882498Sroberto * fudgetime1 can be added to the final offset to compensate for various 50982498Sroberto * systematic errors. The routine returns the number of samples 51082498Sroberto * processed, which could be zero. 51154359Sroberto */ 51254359Srobertostatic int 51354359Srobertorefclock_sample( 514132451Sroberto struct refclockproc *pp /* refclock structure pointer */ 51554359Sroberto ) 51654359Sroberto{ 517182007Sroberto int i, j, k, m, n; 518182007Sroberto double off[MAXSTAGE]; 519182007Sroberto double offset; 52054359Sroberto 52154359Sroberto /* 52254359Sroberto * Copy the raw offsets and sort into ascending order. Don't do 52354359Sroberto * anything if the buffer is empty. 52454359Sroberto */ 525132451Sroberto n = 0; 526132451Sroberto while (pp->codeproc != pp->coderecv) { 527132451Sroberto pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 528132451Sroberto off[n] = pp->filter[pp->codeproc]; 529132451Sroberto n++; 530132451Sroberto } 531132451Sroberto if (n == 0) 53254359Sroberto return (0); 533182007Sroberto 53454359Sroberto if (n > 1) 535182007Sroberto qsort( 536182007Sroberto#ifdef QSORT_USES_VOID_P 537182007Sroberto (void *) 538182007Sroberto#else 539182007Sroberto (char *) 540182007Sroberto#endif 541182007Sroberto off, (size_t)n, sizeof(double), refclock_cmpl_fp); 54254359Sroberto 54354359Sroberto /* 54454359Sroberto * Reject the furthest from the median of the samples until 54554359Sroberto * approximately 60 percent of the samples remain. 54654359Sroberto */ 54754359Sroberto i = 0; j = n; 548182007Sroberto m = n - (n * 4) / 10; 54982498Sroberto while ((j - i) > m) { 55054359Sroberto offset = off[(j + i) / 2]; 55154359Sroberto if (off[j - 1] - offset < offset - off[i]) 55254359Sroberto i++; /* reject low end */ 55354359Sroberto else 55454359Sroberto j--; /* reject high end */ 55554359Sroberto } 55654359Sroberto 55754359Sroberto /* 55882498Sroberto * Determine the offset and jitter. 55954359Sroberto */ 560182007Sroberto pp->offset = 0; 561182007Sroberto pp->jitter = 0; 562182007Sroberto for (k = i; k < j; k++) { 563182007Sroberto pp->offset += off[k]; 564182007Sroberto if (k > i) 565182007Sroberto pp->jitter += SQUARE(off[k] - off[k - 1]); 566182007Sroberto } 567182007Sroberto pp->offset /= m; 568182007Sroberto pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision)); 56954359Sroberto#ifdef DEBUG 57054359Sroberto if (debug) 57154359Sroberto printf( 57282498Sroberto "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", 573182007Sroberto n, pp->offset, pp->disp, pp->jitter); 57454359Sroberto#endif 57554359Sroberto return (n); 57654359Sroberto} 57754359Sroberto 57854359Sroberto 57954359Sroberto/* 58054359Sroberto * refclock_receive - simulate the receive and packet procedures 58154359Sroberto * 58254359Sroberto * This routine simulates the NTP receive and packet procedures for a 58354359Sroberto * reference clock. This provides a mechanism in which the ordinary NTP 58454359Sroberto * filter, selection and combining algorithms can be used to suppress 58554359Sroberto * misbehaving radios and to mitigate between them when more than one is 58654359Sroberto * available for backup. 58754359Sroberto */ 58854359Srobertovoid 58954359Srobertorefclock_receive( 59054359Sroberto struct peer *peer /* peer structure pointer */ 59154359Sroberto ) 59254359Sroberto{ 59354359Sroberto struct refclockproc *pp; 59454359Sroberto 59554359Sroberto#ifdef DEBUG 59654359Sroberto if (debug) 59754359Sroberto printf("refclock_receive: at %lu %s\n", 598132451Sroberto current_time, stoa(&peer->srcadr)); 59954359Sroberto#endif 60054359Sroberto 60154359Sroberto /* 60254359Sroberto * Do a little sanity dance and update the peer structure. Groom 60354359Sroberto * the median filter samples and give the data to the clock 60454359Sroberto * filter. 60554359Sroberto */ 60654359Sroberto pp = peer->procptr; 60754359Sroberto peer->leap = pp->leap; 608182007Sroberto if (peer->leap == LEAP_NOTINSYNC) 60954359Sroberto return; 610182007Sroberto 611182007Sroberto peer->received++; 612182007Sroberto peer->timereceived = current_time; 613182007Sroberto if (!peer->reach) { 614182007Sroberto report_event(EVNT_REACH, peer); 615182007Sroberto peer->timereachable = current_time; 61654359Sroberto } 61754359Sroberto peer->reach |= 1; 618132451Sroberto peer->reftime = pp->lastref; 619132451Sroberto peer->org = pp->lastrec; 620132451Sroberto peer->rootdispersion = pp->disp; 62154359Sroberto get_systime(&peer->rec); 62254359Sroberto if (!refclock_sample(pp)) 62354359Sroberto return; 624182007Sroberto 62582498Sroberto clock_filter(peer, pp->offset, 0., pp->jitter); 62654359Sroberto record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), 62782498Sroberto peer->offset, peer->delay, clock_phi * (current_time - 628182007Sroberto peer->epoch), peer->jitter); 62982498Sroberto if (cal_enable && last_offset < MINDISPERSE) { 63082498Sroberto#ifdef KERNEL_PLL 63182498Sroberto if (peer != sys_peer || pll_status & STA_PPSTIME) 63282498Sroberto#else 63382498Sroberto if (peer != sys_peer) 63482498Sroberto#endif /* KERNEL_PLL */ 63582498Sroberto pp->fudgetime1 -= pp->offset * FUDGEFAC; 63682498Sroberto else 63782498Sroberto pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC; 63882498Sroberto } 63954359Sroberto} 64054359Sroberto 641182007Sroberto 64254359Sroberto/* 64354359Sroberto * refclock_gtlin - groom next input line and extract timestamp 64454359Sroberto * 64554359Sroberto * This routine processes the timecode received from the clock and 646182007Sroberto * strips the parity bit and control characters. It returns the number 647182007Sroberto * of characters in the line followed by a NULL character ('\0'), which 648182007Sroberto * is not included in the count. In case of an empty line, the previous 649182007Sroberto * line is preserved. 65054359Sroberto */ 65154359Srobertoint 65254359Srobertorefclock_gtlin( 65354359Sroberto struct recvbuf *rbufp, /* receive buffer pointer */ 654182007Sroberto char *lineptr, /* current line pointer */ 655182007Sroberto int bmax, /* remaining characters in line */ 656182007Sroberto l_fp *tsptr /* pointer to timestamp returned */ 65754359Sroberto ) 65854359Sroberto{ 659182007Sroberto char s[BMAX]; 660182007Sroberto char *dpt, *dpend, *dp; 66154359Sroberto 662182007Sroberto dpt = s; 663182007Sroberto dpend = s + refclock_gtraw(rbufp, s, BMAX - 1, tsptr); 664182007Sroberto if (dpend - dpt > bmax - 1) 665182007Sroberto dpend = dpt + bmax - 1; 666182007Sroberto for (dp = lineptr; dpt < dpend; dpt++) { 667182007Sroberto char c; 668182007Sroberto 669182007Sroberto c = *dpt & 0x7f; 670182007Sroberto if (c >= 0x20 && c < 0x7f) 671182007Sroberto *dp++ = c; 672182007Sroberto } 673182007Sroberto if (dp == lineptr) 674182007Sroberto return (0); 675182007Sroberto 676182007Sroberto *dp = '\0'; 677182007Sroberto return (dp - lineptr); 678182007Sroberto} 679182007Sroberto 680182007Sroberto 681182007Sroberto/* 682182007Sroberto * refclock_gtraw - get next line/chunk of data 683182007Sroberto * 684182007Sroberto * This routine returns the raw data received from the clock in both 685182007Sroberto * canonical or raw modes. The terminal interface routines map CR to LF. 686182007Sroberto * In canonical mode this results in two lines, one containing data 687182007Sroberto * followed by LF and another containing only LF. In raw mode the 688182007Sroberto * interface routines can deliver arbitraty chunks of data from one 689182007Sroberto * character to a maximum specified by the calling routine. In either 690182007Sroberto * mode the routine returns the number of characters in the line 691182007Sroberto * followed by a NULL character ('\0'), which is not included in the 692182007Sroberto * count. 693182007Sroberto * 694182007Sroberto * If a timestamp is present in the timecode, as produced by the tty_clk 695182007Sroberto * STREAMS module, it returns that as the timestamp; otherwise, it 696182007Sroberto * returns the buffer timestamp. 697182007Sroberto */ 698182007Srobertoint 699182007Srobertorefclock_gtraw( 700182007Sroberto struct recvbuf *rbufp, /* receive buffer pointer */ 701182007Sroberto char *lineptr, /* current line pointer */ 702182007Sroberto int bmax, /* remaining characters in line */ 703182007Sroberto l_fp *tsptr /* pointer to timestamp returned */ 704182007Sroberto ) 705182007Sroberto{ 706182007Sroberto char *dpt, *dpend, *dp; 707182007Sroberto l_fp trtmp, tstmp; 708182007Sroberto int i; 709182007Sroberto 71054359Sroberto /* 71154359Sroberto * Check for the presence of a timestamp left by the tty_clock 71254359Sroberto * module and, if present, use that instead of the buffer 71354359Sroberto * timestamp captured by the I/O routines. We recognize a 71454359Sroberto * timestamp by noting its value is earlier than the buffer 71554359Sroberto * timestamp, but not more than one second earlier. 71654359Sroberto */ 717132451Sroberto dpt = (char *)rbufp->recv_buffer; 71854359Sroberto dpend = dpt + rbufp->recv_length; 71954359Sroberto trtmp = rbufp->recv_time; 72054359Sroberto if (dpend >= dpt + 8) { 72154359Sroberto if (buftvtots(dpend - 8, &tstmp)) { 72254359Sroberto L_SUB(&trtmp, &tstmp); 72354359Sroberto if (trtmp.l_ui == 0) { 72454359Sroberto#ifdef DEBUG 72554359Sroberto if (debug > 1) { 72654359Sroberto printf( 72754359Sroberto "refclock_gtlin: fd %d ldisc %s", 728182007Sroberto rbufp->fd, lfptoa(&trtmp, 729182007Sroberto 6)); 73054359Sroberto get_systime(&trtmp); 73154359Sroberto L_SUB(&trtmp, &tstmp); 732182007Sroberto printf(" sigio %s\n", 733182007Sroberto lfptoa(&trtmp, 6)); 73454359Sroberto } 73554359Sroberto#endif 73654359Sroberto dpend -= 8; 73754359Sroberto trtmp = tstmp; 73854359Sroberto } else 73954359Sroberto trtmp = rbufp->recv_time; 74054359Sroberto } 74154359Sroberto } 74254359Sroberto 74354359Sroberto /* 744182007Sroberto * Copy the raw buffer to the user string. The string is padded 745182007Sroberto * with a NULL, which is not included in the character count. 74654359Sroberto */ 74754359Sroberto if (dpend - dpt > bmax - 1) 74854359Sroberto dpend = dpt + bmax - 1; 749182007Sroberto for (dp = lineptr; dpt < dpend; dpt++) 750182007Sroberto *dp++ = *dpt; 751182007Sroberto *dp = '\0'; 75254359Sroberto i = dp - lineptr; 75354359Sroberto#ifdef DEBUG 754182007Sroberto if (debug > 1) 755182007Sroberto printf("refclock_gtraw: fd %d time %s timecode %d %s\n", 756182007Sroberto rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); 75754359Sroberto#endif 75854359Sroberto *tsptr = trtmp; 75954359Sroberto return (i); 76054359Sroberto} 76154359Sroberto 762182007Sroberto 76354359Sroberto/* 76454359Sroberto * The following code does not apply to WINNT & VMS ... 76554359Sroberto */ 76654359Sroberto#if !defined SYS_VXWORKS && !defined SYS_WINNT 76754359Sroberto#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 76854359Sroberto 76954359Sroberto/* 77054359Sroberto * refclock_open - open serial port for reference clock 77154359Sroberto * 77254359Sroberto * This routine opens a serial port for I/O and sets default options. It 77354359Sroberto * returns the file descriptor if success and zero if failure. 77454359Sroberto */ 77554359Srobertoint 77654359Srobertorefclock_open( 777182007Sroberto char *dev, /* device name pointer */ 778182007Sroberto u_int speed, /* serial port speed (code) */ 779182007Sroberto u_int lflags /* line discipline flags */ 78054359Sroberto ) 78154359Sroberto{ 782182007Sroberto int fd; 783182007Sroberto int omode; 78454359Sroberto 78554359Sroberto /* 78654359Sroberto * Open serial port and set default options 78754359Sroberto */ 78882498Sroberto omode = O_RDWR; 78954359Sroberto#ifdef O_NONBLOCK 79082498Sroberto omode |= O_NONBLOCK; 79182498Sroberto#endif 79282498Sroberto#ifdef O_NOCTTY 79382498Sroberto omode |= O_NOCTTY; 79482498Sroberto#endif 79582498Sroberto 79682498Sroberto fd = open(dev, omode, 0777); 79782498Sroberto if (fd < 0) { 798182007Sroberto msyslog(LOG_ERR, "refclock_open %s: %m", dev); 79954359Sroberto return (0); 80054359Sroberto } 801182007Sroberto if (!refclock_setup(fd, speed, lflags)) { 802182007Sroberto close(fd); 803182007Sroberto return (0); 804182007Sroberto } 805182007Sroberto if (!refclock_ioctl(fd, lflags)) { 806182007Sroberto close(fd); 807182007Sroberto return (0); 808182007Sroberto } 809182007Sroberto return (fd); 810182007Sroberto} 81154359Sroberto 812182007Sroberto/* 813182007Sroberto * refclock_setup - initialize terminal interface structure 814182007Sroberto */ 815182007Srobertoint 816182007Srobertorefclock_setup( 817182007Sroberto int fd, /* file descriptor */ 818182007Sroberto u_int speed, /* serial port speed (code) */ 819182007Sroberto u_int lflags /* line discipline flags */ 820182007Sroberto ) 821182007Sroberto{ 822182007Sroberto int i; 823182007Sroberto TTY ttyb, *ttyp; 824182007Sroberto#ifdef PPS 825182007Sroberto fdpps = fd; /* ppsclock legacy */ 826182007Sroberto#endif /* PPS */ 82782498Sroberto 82882498Sroberto /* 829182007Sroberto * By default, the serial line port is initialized in canonical 830182007Sroberto * (line-oriented) mode at specified line speed, 8 bits and no 831182007Sroberto * parity. LF ends the line and CR is mapped to LF. The break, 832182007Sroberto * erase and kill functions are disabled. There is a different 833182007Sroberto * section for each terminal interface, as selected at compile 834182007Sroberto * time. The flag bits can be used to set raw mode and echo. 83554359Sroberto */ 83654359Sroberto ttyp = &ttyb; 837182007Sroberto#ifdef HAVE_TERMIOS 83854359Sroberto 83954359Sroberto /* 84054359Sroberto * POSIX serial line parameters (termios interface) 84154359Sroberto */ 84254359Sroberto if (tcgetattr(fd, ttyp) < 0) { 84354359Sroberto msyslog(LOG_ERR, 844182007Sroberto "refclock_setup fd %d tcgetattr: %m", fd); 84554359Sroberto return (0); 84654359Sroberto } 84754359Sroberto 84854359Sroberto /* 84954359Sroberto * Set canonical mode and local connection; set specified speed, 85054359Sroberto * 8 bits and no parity; map CR to NL; ignore break. 85154359Sroberto */ 852182007Sroberto if (speed) { 853182007Sroberto u_int ltemp = 0; 854182007Sroberto 855182007Sroberto ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 856182007Sroberto ttyp->c_oflag = 0; 857182007Sroberto ttyp->c_cflag = CS8 | CLOCAL | CREAD; 858182007Sroberto if (lflags & LDISC_7O1) { 859182007Sroberto /* HP Z3801A needs 7-bit, odd parity */ 860182007Sroberto ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; 861182007Sroberto } 862182007Sroberto cfsetispeed(&ttyb, speed); 863182007Sroberto cfsetospeed(&ttyb, speed); 864182007Sroberto for (i = 0; i < NCCS; ++i) 865182007Sroberto ttyp->c_cc[i] = '\0'; 866182007Sroberto 867182007Sroberto#if defined(TIOCMGET) && !defined(SCO5_CLOCK) 868182007Sroberto 869182007Sroberto /* 870182007Sroberto * If we have modem control, check to see if modem leads 871182007Sroberto * are active; if so, set remote connection. This is 872182007Sroberto * necessary for the kernel pps mods to work. 873182007Sroberto */ 874182007Sroberto if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 875182007Sroberto msyslog(LOG_ERR, 876182007Sroberto "refclock_setup fd %d TIOCMGET: %m", fd); 877182007Sroberto#ifdef DEBUG 878182007Sroberto if (debug) 879182007Sroberto printf("refclock_setup fd %d modem status: 0x%x\n", 880182007Sroberto fd, ltemp); 881182007Sroberto#endif 882182007Sroberto if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) 883182007Sroberto ttyp->c_cflag &= ~CLOCAL; 884182007Sroberto#endif /* TIOCMGET */ 88554359Sroberto } 88654359Sroberto 88754359Sroberto /* 888182007Sroberto * Set raw and echo modes. These can be changed on-fly. 88954359Sroberto */ 890182007Sroberto ttyp->c_lflag = ICANON; 891182007Sroberto if (lflags & LDISC_RAW) { 892182007Sroberto ttyp->c_lflag = 0; 89354359Sroberto ttyp->c_iflag = 0; 89454359Sroberto ttyp->c_cc[VMIN] = 1; 89554359Sroberto } 896182007Sroberto if (lflags & LDISC_ECHO) 897182007Sroberto ttyp->c_lflag |= ECHO; 89854359Sroberto if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 89954359Sroberto msyslog(LOG_ERR, 900182007Sroberto "refclock_setup fd %d TCSANOW: %m", fd); 90154359Sroberto return (0); 90254359Sroberto } 90354359Sroberto#endif /* HAVE_TERMIOS */ 90454359Sroberto 90554359Sroberto#ifdef HAVE_SYSV_TTYS 90654359Sroberto 90754359Sroberto /* 90854359Sroberto * System V serial line parameters (termio interface) 90954359Sroberto * 91054359Sroberto */ 91154359Sroberto if (ioctl(fd, TCGETA, ttyp) < 0) { 91254359Sroberto msyslog(LOG_ERR, 913182007Sroberto "refclock_setup fd %d TCGETA: %m", fd); 91454359Sroberto return (0); 91554359Sroberto } 91654359Sroberto 91754359Sroberto /* 91854359Sroberto * Set canonical mode and local connection; set specified speed, 91954359Sroberto * 8 bits and no parity; map CR to NL; ignore break. 92054359Sroberto */ 921182007Sroberto if (speed) { 922182007Sroberto u_int ltemp = 0; 92354359Sroberto 924182007Sroberto ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 925182007Sroberto ttyp->c_oflag = 0; 926182007Sroberto ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 927182007Sroberto for (i = 0; i < NCCS; ++i) 928182007Sroberto ttyp->c_cc[i] = '\0'; 929182007Sroberto 930182007Sroberto#if defined(TIOCMGET) && !defined(SCO5_CLOCK) 931182007Sroberto 932182007Sroberto /* 933182007Sroberto * If we have modem control, check to see if modem leads 934182007Sroberto * are active; if so, set remote connection. This is 935182007Sroberto * necessary for the kernel pps mods to work. 936182007Sroberto */ 937182007Sroberto if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 938182007Sroberto msyslog(LOG_ERR, 939182007Sroberto "refclock_setup fd %d TIOCMGET: %m", fd); 940182007Sroberto#ifdef DEBUG 941182007Sroberto if (debug) 942182007Sroberto printf("refclock_setup fd %d modem status: %x\n", 943182007Sroberto fd, ltemp); 944182007Sroberto#endif 945182007Sroberto if (ltemp & TIOCM_DSR) 946182007Sroberto ttyp->c_cflag &= ~CLOCAL; 947182007Sroberto#endif /* TIOCMGET */ 948182007Sroberto } 949182007Sroberto 95054359Sroberto /* 951182007Sroberto * Set raw and echo modes. These can be changed on-fly. 95254359Sroberto */ 953182007Sroberto ttyp->c_lflag = ICANON; 954182007Sroberto if (lflags & LDISC_RAW) { 955182007Sroberto ttyp->c_lflag = 0; 95654359Sroberto ttyp->c_iflag = 0; 957182007Sroberto ttyp->c_cc[VMIN] = 1; 95854359Sroberto } 95954359Sroberto if (ioctl(fd, TCSETA, ttyp) < 0) { 96054359Sroberto msyslog(LOG_ERR, 961182007Sroberto "refclock_setup fd %d TCSETA: %m", fd); 96254359Sroberto return (0); 96354359Sroberto } 96454359Sroberto#endif /* HAVE_SYSV_TTYS */ 96554359Sroberto 96654359Sroberto#ifdef HAVE_BSD_TTYS 96754359Sroberto 96854359Sroberto /* 96954359Sroberto * 4.3bsd serial line parameters (sgttyb interface) 97054359Sroberto */ 97154359Sroberto if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { 97254359Sroberto msyslog(LOG_ERR, 973182007Sroberto "refclock_setup fd %d TIOCGETP: %m", fd); 97454359Sroberto return (0); 97554359Sroberto } 976182007Sroberto if (speed) 977182007Sroberto ttyp->sg_ispeed = ttyp->sg_ospeed = speed; 97854359Sroberto ttyp->sg_flags = EVENP | ODDP | CRMOD; 97954359Sroberto if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { 98054359Sroberto msyslog(LOG_ERR, 981182007Sroberto "refclock_setup TIOCSETP: %m"); 98254359Sroberto return (0); 98354359Sroberto } 98454359Sroberto#endif /* HAVE_BSD_TTYS */ 985182007Sroberto return(1); 98654359Sroberto} 98754359Sroberto#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 98854359Sroberto#endif /* SYS_VXWORKS SYS_WINNT */ 98954359Sroberto 990182007Sroberto 99154359Sroberto/* 99254359Sroberto * refclock_ioctl - set serial port control functions 99354359Sroberto * 99454359Sroberto * This routine attempts to hide the internal, system-specific details 99554359Sroberto * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 99654359Sroberto * (sgtty) interfaces with varying degrees of success. The routine sets 99782498Sroberto * up optional features such as tty_clk. The routine returns 1 if 99882498Sroberto * success and 0 if failure. 99954359Sroberto */ 100054359Srobertoint 100154359Srobertorefclock_ioctl( 1002182007Sroberto int fd, /* file descriptor */ 1003182007Sroberto u_int lflags /* line discipline flags */ 100454359Sroberto ) 100554359Sroberto{ 1006182007Sroberto /* 1007182007Sroberto * simply return 1 if no UNIX line discipline is supported 1008182007Sroberto */ 100954359Sroberto#if !defined SYS_VXWORKS && !defined SYS_WINNT 101054359Sroberto#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 101154359Sroberto 101254359Sroberto#ifdef DEBUG 101354359Sroberto if (debug) 1014182007Sroberto printf("refclock_ioctl: fd %d flags 0x%x\n", fd, 1015182007Sroberto lflags); 101654359Sroberto#endif 101754359Sroberto#ifdef TTYCLK 101854359Sroberto 101954359Sroberto /* 102054359Sroberto * The TTYCLK option provides timestamping at the driver level. 102154359Sroberto * It requires the tty_clk streams module and System V STREAMS 102254359Sroberto * support. If not available, don't complain. 102354359Sroberto */ 1024182007Sroberto if (lflags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) { 102554359Sroberto int rval = 0; 102654359Sroberto 102754359Sroberto if (ioctl(fd, I_PUSH, "clk") < 0) { 102854359Sroberto msyslog(LOG_NOTICE, 1029182007Sroberto "refclock_ioctl fd %d I_PUSH: %m", fd); 1030182007Sroberto return (0); 1031182007Sroberto#ifdef CLK_SETSTR 103254359Sroberto } else { 103354359Sroberto char *str; 103454359Sroberto 1035182007Sroberto if (lflags & LDISC_CLKPPS) 103654359Sroberto str = "\377"; 1037182007Sroberto else if (lflags & LDISC_ACTS) 103854359Sroberto str = "*"; 103954359Sroberto else 104054359Sroberto str = "\n"; 1041182007Sroberto if (ioctl(fd, CLK_SETSTR, str) < 0) { 104254359Sroberto msyslog(LOG_ERR, 1043182007Sroberto "refclock_ioctl fd %d CLK_SETSTR: %m", fd); 1044182007Sroberto return (0); 1045182007Sroberto } 1046182007Sroberto#endif /*CLK_SETSTR */ 104754359Sroberto } 104854359Sroberto } 104954359Sroberto#endif /* TTYCLK */ 105054359Sroberto#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 105154359Sroberto#endif /* SYS_VXWORKS SYS_WINNT */ 105254359Sroberto return (1); 105354359Sroberto} 105454359Sroberto 1055182007Sroberto 105654359Sroberto/* 105754359Sroberto * refclock_control - set and/or return clock values 105854359Sroberto * 105954359Sroberto * This routine is used mainly for debugging. It returns designated 106054359Sroberto * values from the interface structure that can be displayed using 106154359Sroberto * ntpdc and the clockstat command. It can also be used to initialize 106254359Sroberto * configuration variables, such as fudgetimes, fudgevalues, reference 106354359Sroberto * ID and stratum. 106454359Sroberto */ 106554359Srobertovoid 106654359Srobertorefclock_control( 1067132451Sroberto struct sockaddr_storage *srcadr, 106854359Sroberto struct refclockstat *in, 106954359Sroberto struct refclockstat *out 107054359Sroberto ) 107154359Sroberto{ 107254359Sroberto struct peer *peer; 107354359Sroberto struct refclockproc *pp; 107454359Sroberto u_char clktype; 107554359Sroberto int unit; 107654359Sroberto 107754359Sroberto /* 107854359Sroberto * Check for valid address and running peer 107954359Sroberto */ 1080132451Sroberto if (srcadr->ss_family != AF_INET) 1081132451Sroberto return; 1082182007Sroberto 108354359Sroberto if (!ISREFCLOCKADR(srcadr)) 108454359Sroberto return; 1085182007Sroberto 108654359Sroberto clktype = (u_char)REFCLOCKTYPE(srcadr); 108754359Sroberto unit = REFCLOCKUNIT(srcadr); 108854359Sroberto if (clktype >= num_refclock_conf || unit >= MAXUNIT) 108954359Sroberto return; 1090182007Sroberto 1091132451Sroberto peer = typeunit[clktype][unit]; 1092132451Sroberto if (peer == NULL) 109354359Sroberto return; 1094182007Sroberto 109582498Sroberto if (peer->procptr == NULL) 109682498Sroberto return; 1097182007Sroberto 109854359Sroberto pp = peer->procptr; 109954359Sroberto 110054359Sroberto /* 110154359Sroberto * Initialize requested data 110254359Sroberto */ 110354359Sroberto if (in != 0) { 110454359Sroberto if (in->haveflags & CLK_HAVETIME1) 110554359Sroberto pp->fudgetime1 = in->fudgetime1; 110654359Sroberto if (in->haveflags & CLK_HAVETIME2) 110754359Sroberto pp->fudgetime2 = in->fudgetime2; 110854359Sroberto if (in->haveflags & CLK_HAVEVAL1) 1109182007Sroberto peer->stratum = pp->stratum = (u_char)in->fudgeval1; 111054359Sroberto if (in->haveflags & CLK_HAVEVAL2) 1111182007Sroberto peer->refid = pp->refid = in->fudgeval2; 111254359Sroberto if (in->haveflags & CLK_HAVEFLAG1) { 111354359Sroberto pp->sloppyclockflag &= ~CLK_FLAG1; 111454359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG1; 111554359Sroberto } 111654359Sroberto if (in->haveflags & CLK_HAVEFLAG2) { 111754359Sroberto pp->sloppyclockflag &= ~CLK_FLAG2; 111854359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG2; 111954359Sroberto } 112054359Sroberto if (in->haveflags & CLK_HAVEFLAG3) { 112154359Sroberto pp->sloppyclockflag &= ~CLK_FLAG3; 112254359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG3; 112354359Sroberto } 112454359Sroberto if (in->haveflags & CLK_HAVEFLAG4) { 112554359Sroberto pp->sloppyclockflag &= ~CLK_FLAG4; 112654359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG4; 112754359Sroberto } 112854359Sroberto } 112954359Sroberto 113054359Sroberto /* 113154359Sroberto * Readback requested data 113254359Sroberto */ 113354359Sroberto if (out != 0) { 113454359Sroberto out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | 113554359Sroberto CLK_HAVEVAL2 | CLK_HAVEFLAG4; 113654359Sroberto out->fudgetime1 = pp->fudgetime1; 113754359Sroberto out->fudgetime2 = pp->fudgetime2; 1138132451Sroberto out->fudgeval1 = pp->stratum; 113954359Sroberto out->fudgeval2 = pp->refid; 114054359Sroberto out->flags = (u_char) pp->sloppyclockflag; 114154359Sroberto 114254359Sroberto out->timereset = current_time - pp->timestarted; 114354359Sroberto out->polls = pp->polls; 114454359Sroberto out->noresponse = pp->noreply; 114554359Sroberto out->badformat = pp->badformat; 114654359Sroberto out->baddata = pp->baddata; 114754359Sroberto 114854359Sroberto out->lastevent = pp->lastevent; 114954359Sroberto out->currentstatus = pp->currentstatus; 115054359Sroberto out->type = pp->type; 115154359Sroberto out->clockdesc = pp->clockdesc; 115254359Sroberto out->lencode = pp->lencode; 115354359Sroberto out->p_lastcode = pp->a_lastcode; 115454359Sroberto } 115554359Sroberto 115654359Sroberto /* 115754359Sroberto * Give the stuff to the clock 115854359Sroberto */ 115954359Sroberto if (refclock_conf[clktype]->clock_control != noentry) 116054359Sroberto (refclock_conf[clktype]->clock_control)(unit, in, out, peer); 116154359Sroberto} 116254359Sroberto 116354359Sroberto 116454359Sroberto/* 116554359Sroberto * refclock_buginfo - return debugging info 116654359Sroberto * 116754359Sroberto * This routine is used mainly for debugging. It returns designated 116854359Sroberto * values from the interface structure that can be displayed using 116954359Sroberto * ntpdc and the clkbug command. 117054359Sroberto */ 117154359Srobertovoid 117254359Srobertorefclock_buginfo( 1173132451Sroberto struct sockaddr_storage *srcadr, /* clock address */ 117454359Sroberto struct refclockbug *bug /* output structure */ 117554359Sroberto ) 117654359Sroberto{ 117754359Sroberto struct peer *peer; 117854359Sroberto struct refclockproc *pp; 117954359Sroberto u_char clktype; 118054359Sroberto int unit; 118154359Sroberto int i; 118254359Sroberto 118354359Sroberto /* 118454359Sroberto * Check for valid address and peer structure 118554359Sroberto */ 1186132451Sroberto if (srcadr->ss_family != AF_INET) 1187132451Sroberto return; 1188182007Sroberto 118954359Sroberto if (!ISREFCLOCKADR(srcadr)) 119054359Sroberto return; 1191182007Sroberto 119254359Sroberto clktype = (u_char) REFCLOCKTYPE(srcadr); 119354359Sroberto unit = REFCLOCKUNIT(srcadr); 119454359Sroberto if (clktype >= num_refclock_conf || unit >= MAXUNIT) 119554359Sroberto return; 1196182007Sroberto 1197132451Sroberto peer = typeunit[clktype][unit]; 1198132451Sroberto if (peer == NULL) 119954359Sroberto return; 1200182007Sroberto 120154359Sroberto pp = peer->procptr; 120254359Sroberto 120354359Sroberto /* 120454359Sroberto * Copy structure values 120554359Sroberto */ 120654359Sroberto bug->nvalues = 8; 120754359Sroberto bug->svalues = 0x0000003f; 120854359Sroberto bug->values[0] = pp->year; 120954359Sroberto bug->values[1] = pp->day; 121054359Sroberto bug->values[2] = pp->hour; 121154359Sroberto bug->values[3] = pp->minute; 121254359Sroberto bug->values[4] = pp->second; 1213132451Sroberto bug->values[5] = pp->nsec; 121454359Sroberto bug->values[6] = pp->yearstart; 121554359Sroberto bug->values[7] = pp->coderecv; 121654359Sroberto bug->stimes = 0xfffffffc; 121754359Sroberto bug->times[0] = pp->lastref; 121854359Sroberto bug->times[1] = pp->lastrec; 121954359Sroberto for (i = 2; i < (int)bug->ntimes; i++) 122054359Sroberto DTOLFP(pp->filter[i - 2], &bug->times[i]); 122154359Sroberto 122254359Sroberto /* 122354359Sroberto * Give the stuff to the clock 122454359Sroberto */ 122554359Sroberto if (refclock_conf[clktype]->clock_buginfo != noentry) 122654359Sroberto (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 122754359Sroberto} 122854359Sroberto 122954359Sroberto#endif /* REFCLOCK */ 1230