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, &ltemp);
495132451Sroberto	L_ADD(&offset, &ltemp);
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 *)&ltemp) < 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 *)&ltemp) < 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