ntp_refclock.c revision 54359
1/*
2 * ntp_refclock - processing support for reference clocks
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#include <stdio.h>
9#include <sys/types.h>
10#ifdef HAVE_SYS_IOCTL_H
11# include <sys/ioctl.h>
12#endif /* HAVE_SYS_IOCTL_H */
13
14#include "ntpd.h"
15#include "ntp_io.h"
16#include "ntp_unixtime.h"
17#include "ntp_refclock.h"
18#include "ntp_stdlib.h"
19
20#ifdef REFCLOCK
21
22#ifdef TTYCLK
23# ifdef SCO5_CLOCK
24#  include <sys/sio.h>
25# else
26#  include <sys/clkdefs.h>
27# endif
28#endif /* TTYCLK */
29
30#ifdef HAVE_PPSCLOCK_H
31#include <sys/ppsclock.h>
32#endif /* HAVE_PPSCLOCK_H */
33
34#ifdef HAVE_PPSAPI
35#include <sys/timepps.h>
36#endif /* HAVE_PPSAPI */
37
38/*
39 * Reference clock support is provided here by maintaining the fiction
40 * that the clock is actually a peer. As no packets are exchanged with a
41 * reference clock, however, we replace the transmit, receive and packet
42 * procedures with separate code to simulate them. Routines
43 * refclock_transmit() and refclock_receive() maintain the peer
44 * variables in a state analogous to an actual peer and pass reference
45 * clock data on through the filters. Routines refclock_peer() and
46 * refclock_unpeer() are called to initialize and terminate reference
47 * clock associations. A set of utility routines is included to open
48 * serial devices, process sample data, edit input lines to extract
49 * embedded timestamps and to peform various debugging functions.
50 *
51 * The main interface used by these routines is the refclockproc
52 * structure, which contains for most drivers the decimal equivalants of
53 * the year, day, month, hour, second and millisecond/microsecond
54 * decoded from the ASCII timecode. Additional information includes the
55 * receive timestamp, exception report, statistics tallies, etc. In
56 * addition, there may be a driver-specific unit structure used for
57 * local control of the device.
58 *
59 * The support routines are passed a pointer to the peer structure,
60 * which is used for all peer-specific processing and contains a pointer
61 * to the refclockproc structure, which in turn containes a pointer to
62 * the unit structure, if used. The peer structure is identified by an
63 * interface address in the dotted quad form 127.127.t.u, where t is the
64 * clock type and u the unit. Some legacy drivers derive the
65 * refclockproc structure pointer from the table typeunit[type][unit].
66 * This interface is strongly discouraged and may be abandoned in
67 * future.
68 *
69 * The routines include support for the 1-pps signal provided by some
70 * radios and connected via a level converted described in the gadget
71 * directory. The signal is captured using a serial port and one of
72 * three STREAMS modules described in the refclock_atom.c file. For the
73 * highest precision, the signal is captured using the carrier-detect
74 * line of a serial port and either the ppsclock or ppsapi streams
75 * module or some devilish ioctl() folks keep slipping in as a patch. Be
76 * advised ALL support for other than the duly standardized ppsapi
77 * interface will eventually be withdrawn.
78 */
79#define MAXUNIT 	4	/* max units */
80
81#if defined(PPS) || defined(HAVE_PPSAPI)
82int fdpps;			/* pps file descriptor */
83#endif /* PPS HAVE_PPSAPI */
84
85#define FUDGEFAC	.1	/* fudge correction factor */
86
87/*
88 * Type/unit peer index. Used to find the peer structure for control and
89 * debugging. When all clock drivers have been converted to new style,
90 * this dissapears.
91 */
92static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
93
94/*
95 * Forward declarations
96 */
97#ifdef QSORT_USES_VOID_P
98static int refclock_cmpl_fp P((const void *, const void *));
99#else
100static int refclock_cmpl_fp P((const double *, const double *));
101#endif /* QSORT_USES_VOID_P */
102static int refclock_sample P((struct refclockproc *));
103
104#ifdef HAVE_PPSAPI
105extern int pps_assert;		/* capture edge 1:assert, 0:clear */
106extern int pps_hardpps;		/* PPS kernel 1:on, 0:off */
107#endif /* HAVE_PPSAPI */
108
109/*
110 * refclock_report - note the occurance of an event
111 *
112 * This routine presently just remembers the report and logs it, but
113 * does nothing heroic for the trap handler. It tries to be a good
114 * citizen and bothers the system log only if things change.
115 */
116void
117refclock_report(
118	struct peer *peer,
119	int code
120	)
121{
122	struct refclockproc *pp;
123
124	if (!(pp = peer->procptr))
125		return;
126	if (code == CEVNT_BADREPLY)
127		pp->badformat++;
128	if (code == CEVNT_BADTIME)
129		pp->baddata++;
130	if (code == CEVNT_TIMEOUT)
131		pp->noreply++;
132	if (pp->currentstatus != code) {
133		pp->currentstatus = code;
134		pp->lastevent = code;
135		if (code == CEVNT_FAULT)
136			msyslog(LOG_ERR,
137				"clock %s event '%s' (0x%02x)",
138				refnumtoa(peer->srcadr.sin_addr.s_addr),
139				ceventstr(code), code);
140		else {
141			NLOG(NLOG_CLOCKEVENT)
142				msyslog(LOG_INFO,
143				"clock %s event '%s' (0x%02x)",
144				refnumtoa(peer->srcadr.sin_addr.s_addr),
145				ceventstr(code), code);
146		}
147	}
148#ifdef DEBUG
149	if (debug)
150		printf("clock %s event '%s' (0x%02x)\n",
151			refnumtoa(peer->srcadr.sin_addr.s_addr),
152			ceventstr(code), code);
153#endif
154}
155
156
157/*
158 * init_refclock - initialize the reference clock drivers
159 *
160 * This routine calls each of the drivers in turn to initialize internal
161 * variables, if necessary. Most drivers have nothing to say at this
162 * point.
163 */
164void
165init_refclock(void)
166{
167	int i, j;
168
169	for (i = 0; i < (int)num_refclock_conf; i++) {
170		if (refclock_conf[i]->clock_init != noentry)
171			(refclock_conf[i]->clock_init)();
172		for (j = 0; j < MAXUNIT; j++)
173			typeunit[i][j] = 0;
174	}
175}
176
177
178/*
179 * refclock_newpeer - initialize and start a reference clock
180 *
181 * This routine allocates and initializes the interface structure which
182 * supports a reference clock in the form of an ordinary NTP peer. A
183 * driver-specific support routine completes the initialization, if
184 * used. Default peer variables which identify the clock and establish
185 * its reference ID and stratum are set here. It returns one if success
186 * and zero if the clock address is invalid or already running,
187 * insufficient resources are available or the driver declares a bum
188 * rap.
189 */
190int
191refclock_newpeer(
192	struct peer *peer	/* peer structure pointer */
193	)
194{
195	struct refclockproc *pp;
196	u_char clktype;
197	int unit;
198
199	/*
200	 * Check for valid clock address. If already running, shut it
201	 * down first.
202	 */
203	if (!ISREFCLOCKADR(&peer->srcadr)) {
204		msyslog(LOG_ERR,
205			"refclock_newpeer: clock address %s invalid",
206			ntoa(&peer->srcadr));
207		return (0);
208	}
209	clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
210	unit = REFCLOCKUNIT(&peer->srcadr);
211	if (clktype >= num_refclock_conf || unit >= MAXUNIT ||
212		refclock_conf[clktype]->clock_start == noentry) {
213		msyslog(LOG_ERR,
214			"refclock_newpeer: clock type %d invalid\n",
215			clktype);
216		return (0);
217	}
218	refclock_unpeer(peer);
219
220	/*
221	 * Allocate and initialize interface structure
222	 */
223	if (!(pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc))))
224		return (0);
225	memset((char *)pp, 0, sizeof(struct refclockproc));
226	typeunit[clktype][unit] = peer;
227	peer->procptr = pp;
228
229	/*
230	 * Initialize structures
231	 */
232	peer->refclktype = clktype;
233	peer->refclkunit = unit;
234	peer->flags |= FLAG_REFCLOCK;
235	peer->stratum = STRATUM_REFCLOCK;
236	peer->refid = peer->srcadr.sin_addr.s_addr;
237	peer->maxpoll = peer->minpoll;
238
239	pp->type = clktype;
240	pp->timestarted = current_time;
241
242	/*
243	 * If the interface has been set to any_interface, set it to the
244	 * loopback address if we have one. This is so that peers which
245	 * are unreachable are easy to see in the peer display.
246	 */
247	if (peer->dstadr == any_interface && loopback_interface != 0)
248		peer->dstadr = loopback_interface;
249
250	/*
251	 * Set peer.pmode based on the hmode. For appearances only.
252	 */
253	switch (peer->hmode) {
254
255		case MODE_ACTIVE:
256		peer->pmode = MODE_PASSIVE;
257		break;
258
259		default:
260		peer->pmode = MODE_SERVER;
261		break;
262	}
263
264	/*
265	 * Do driver dependent initialization. The above defaults
266	 * can be wiggled, then finish up for consistency.
267	 */
268	if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
269		free(pp);
270		return (0);
271	}
272	peer->hpoll = peer->minpoll;
273	peer->ppoll = peer->maxpoll;
274	if (peer->stratum <= 1)
275		peer->refid = pp->refid;
276	else
277		peer->refid = peer->srcadr.sin_addr.s_addr;
278	return (1);
279}
280
281
282/*
283 * refclock_unpeer - shut down a clock
284 */
285void
286refclock_unpeer(
287	struct peer *peer	/* peer structure pointer */
288	)
289{
290	u_char clktype;
291	int unit;
292
293	/*
294	 * Wiggle the driver to release its resources, then give back
295	 * the interface structure.
296	 */
297	if (!peer->procptr)
298		return;
299	clktype = peer->refclktype;
300	unit = peer->refclkunit;
301	if (refclock_conf[clktype]->clock_shutdown != noentry)
302		(refclock_conf[clktype]->clock_shutdown)(unit, peer);
303	free(peer->procptr);
304	peer->procptr = 0;
305}
306
307
308/*
309 * refclock_transmit - simulate the transmit procedure
310 *
311 * This routine implements the NTP transmit procedure for a reference
312 * clock. This provides a mechanism to call the driver at the NTP poll
313 * interval, as well as provides a reachability mechanism to detect a
314 * broken radio or other madness.
315 */
316void
317refclock_transmit(
318	struct peer *peer	/* peer structure pointer */
319	)
320{
321	u_char clktype;
322	int unit;
323	int hpoll;
324	u_long next;
325
326	clktype = peer->refclktype;
327	unit = peer->refclkunit;
328	peer->sent++;
329
330	/*
331	 * This is a ripoff of the peer transmit routine, but
332	 * specialized for reference clocks. We do a little less
333	 * protocol here and call the driver-specific transmit routine.
334	 */
335	hpoll = peer->hpoll;
336	next = peer->outdate;
337	if (peer->burst == 0) {
338		u_char oreach;
339#ifdef DEBUG
340		if (debug)
341			printf("refclock_transmit: at %ld %s\n",
342			    current_time, ntoa(&(peer->srcadr)));
343#endif
344
345		/*
346		 * Update reachability and poll variables like the
347		 * network code.
348		 */
349		oreach = peer->reach;
350		if (oreach & 0x01)
351			peer->valid++;
352		if (oreach & 0x80)
353			peer->valid--;
354				peer->reach <<= 1;
355		if (peer->reach == 0) {
356			if (oreach != 0) {
357				report_event(EVNT_UNREACH, peer);
358				peer->timereachable = current_time;
359				peer_clear(peer);
360			}
361		} else {
362			if ((oreach & 0x03) == 0) {
363				clock_filter(peer, 0., 0., MAXDISPERSE);
364				clock_select();
365			}
366			if (peer->valid <= 2) {
367				hpoll--;
368			} else if (peer->valid > NTP_SHIFT - 2)
369				hpoll++;
370			if (peer->flags & FLAG_BURST)
371				peer->burst = NSTAGE;
372		}
373		next = current_time;
374	}
375	get_systime(&peer->xmt);
376	if (refclock_conf[clktype]->clock_poll != noentry)
377		(refclock_conf[clktype]->clock_poll)(unit, peer);
378	peer->outdate = next;
379	poll_update(peer, hpoll);
380	if (peer->burst > 0)
381		peer->burst--;
382	poll_update(peer, hpoll);
383}
384
385
386/*
387 * Compare two doubles - used with qsort()
388 */
389#ifdef QSORT_USES_VOID_P
390static int
391refclock_cmpl_fp(
392	const void *p1,
393	const void *p2
394	)
395{
396	const double *dp1 = (const double *)p1;
397	const double *dp2 = (const double *)p2;
398
399	if (*dp1 < *dp2)
400		return (-1);
401	if (*dp1 > *dp2)
402		return (1);
403	return (0);
404}
405#else
406static int
407refclock_cmpl_fp(
408	const double *dp1,
409	const double *dp2
410	)
411{
412	if (*dp1 < *dp2)
413		return (-1);
414	if (*dp1 > *dp2)
415		return (1);
416	return (0);
417}
418#endif /* QSORT_USES_VOID_P */
419
420
421/*
422 * refclock_process_offset - update median filter
423 *
424 * This routine uses the given offset and timestamps to construct a new entry in the median filter circular buffer. Samples that overflow the filter are quietly discarded.
425 */
426void
427refclock_process_offset(
428	struct refclockproc *pp,
429	l_fp offset,
430	l_fp lastrec,
431	double fudge
432	)
433{
434	double doffset;
435
436	pp->lastref = offset;
437	pp->lastrec = lastrec;
438	pp->variance = 0;
439	L_SUB(&offset, &lastrec);
440	LFPTOD(&offset, doffset);
441	SAMPLE(doffset + fudge);
442}
443
444/*
445 * refclock_process - process a sample from the clock
446 *
447 * This routine converts the timecode in the form days, hours, minutes,
448 * seconds and milliseconds/microseconds to internal timestamp format,
449 * then constructs a new entry in the median filter circular buffer.
450 * Return success (1) if the data are correct and consistent with the
451 * converntional calendar.
452*/
453int
454refclock_process(
455	struct refclockproc *pp
456	)
457{
458	l_fp offset;
459
460	/*
461	 * Compute the timecode timestamp from the days, hours, minutes,
462	 * seconds and milliseconds/microseconds of the timecode. Use
463	 * clocktime() for the aggregate seconds and the msec/usec for
464	 * the fraction, when present. Note that this code relies on the
465	 * filesystem time for the years and does not use the years of
466	 * the timecode.
467	 */
468	if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
469		pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
470		return (0);
471	if (pp->usec) {
472		TVUTOTSF(pp->usec, offset.l_uf);
473	} else {
474		MSUTOTSF(pp->msec, offset.l_uf);
475	}
476	refclock_process_offset(pp, offset, pp->lastrec,
477	    pp->fudgetime1);
478	return (1);
479}
480
481/*
482 * refclock_sample - process a pile of samples from the clock
483 *
484 * This routine implements a recursive median filter to suppress spikes
485 * in the data, as well as determine a performance statistic. It
486 * calculates the mean offset and mean-square variance. A time
487 * adjustment fudgetime1 can be added to the final offset to compensate
488 * for various systematic errors. The routine returns the number of
489 * samples processed, which could be 0.
490 */
491static int
492refclock_sample(
493	struct refclockproc *pp
494	)
495{
496	int i, j, k, n;
497	double offset, disp;
498	double off[MAXSTAGE];
499
500	/*
501	 * Copy the raw offsets and sort into ascending order. Don't do
502	 * anything if the buffer is empty.
503	 */
504	if (pp->codeproc == pp->coderecv)
505		return (0);
506	n = 0;
507	while (pp->codeproc != pp->coderecv)
508		off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE];
509	if (n > 1)
510		qsort((char *)off, n, sizeof(double), refclock_cmpl_fp);
511
512	/*
513	 * Reject the furthest from the median of the samples until
514	 * approximately 60 percent of the samples remain.
515	 */
516	i = 0; j = n;
517	k = n - (n * 2) / NSTAGE;
518	while ((j - i) > k) {
519		offset = off[(j + i) / 2];
520		if (off[j - 1] - offset < offset - off[i])
521			i++;	/* reject low end */
522		else
523			j--;	/* reject high end */
524	}
525
526	/*
527	 * Determine the offset and variance.
528	 */
529	offset = disp = 0;
530	for (; i < j; i++) {
531		offset += off[i];
532		disp += SQUARE(off[i]);
533	}
534	offset /= k;
535	pp->offset = offset;
536	pp->variance += disp / k - SQUARE(offset);
537#ifdef DEBUG
538	if (debug)
539		printf(
540		    "refclock_sample: n %d offset %.6f disp %.6f std %.6f\n",
541		    n, pp->offset, pp->disp, SQRT(pp->variance));
542#endif
543	return (n);
544}
545
546
547/*
548 * refclock_receive - simulate the receive and packet procedures
549 *
550 * This routine simulates the NTP receive and packet procedures for a
551 * reference clock. This provides a mechanism in which the ordinary NTP
552 * filter, selection and combining algorithms can be used to suppress
553 * misbehaving radios and to mitigate between them when more than one is
554 * available for backup.
555 */
556void
557refclock_receive(
558	struct peer *peer	/* peer structure pointer */
559	)
560{
561	struct refclockproc *pp;
562
563#ifdef DEBUG
564	if (debug)
565		printf("refclock_receive: at %lu %s\n",
566		    current_time, ntoa(&peer->srcadr));
567#endif
568
569	/*
570	 * Do a little sanity dance and update the peer structure. Groom
571	 * the median filter samples and give the data to the clock
572	 * filter.
573	 */
574	peer->received++;
575	pp = peer->procptr;
576	peer->processed++;
577	peer->timereceived = current_time;
578	peer->leap = pp->leap;
579	if (peer->leap == LEAP_NOTINSYNC) {
580		refclock_report(peer, CEVNT_FAULT);
581		return;
582	}
583	if (peer->reach == 0)
584		report_event(EVNT_REACH, peer);
585	peer->reach |= 1;
586	peer->reftime = peer->org = pp->lastrec;
587	peer->rootdispersion = pp->disp + SQRT(pp->variance);
588	get_systime(&peer->rec);
589	if (!refclock_sample(pp))
590		return;
591	clock_filter(peer, pp->offset, 0., 0.);
592	clock_select();
593	record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
594	    peer->offset, peer->delay, CLOCK_PHI * (current_time -
595	    peer->epoch), SQRT(peer->variance));
596	if (pps_control && pp->sloppyclockflag & CLK_FLAG1)
597		pp->fudgetime1 -= pp->offset * FUDGEFAC;
598}
599
600/*
601 * refclock_gtlin - groom next input line and extract timestamp
602 *
603 * This routine processes the timecode received from the clock and
604 * removes the parity bit and control characters. If a timestamp is
605 * present in the timecode, as produced by the tty_clk STREAMS module,
606 * it returns that as the timestamp; otherwise, it returns the buffer
607 *  timestamp. The routine return code is the number of characters in
608 * the line.
609 */
610int
611refclock_gtlin(
612	struct recvbuf *rbufp,	/* receive buffer pointer */
613	char *lineptr,		/* current line pointer */
614	int bmax,		/* remaining characters in line */
615	l_fp *tsptr 	/* pointer to timestamp returned */
616	)
617{
618	char *dpt, *dpend, *dp;
619	int i;
620	l_fp trtmp, tstmp;
621	char c;
622#ifdef TIOCDCDTIMESTAMP
623	struct timeval dcd_time;
624#endif /* TIOCDCDTIMESTAMP */
625#ifdef HAVE_PPSAPI
626	pps_info_t pi;
627	struct timespec timeout, *tsp;
628	double a;
629#endif /* HAVE_PPSAPI */
630
631	/*
632	 * Check for the presence of a timestamp left by the tty_clock
633	 * module and, if present, use that instead of the buffer
634	 * timestamp captured by the I/O routines. We recognize a
635	 * timestamp by noting its value is earlier than the buffer
636	 * timestamp, but not more than one second earlier.
637	 */
638	dpt = (char *)&rbufp->recv_space;
639	dpend = dpt + rbufp->recv_length;
640	trtmp = rbufp->recv_time;
641
642#ifdef HAVE_PPSAPI
643	timeout.tv_sec = 0;
644	timeout.tv_nsec = 0;
645	if ((rbufp->fd == fdpps) &&
646	    (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &pi, &timeout) >= 0)) {
647		if(pps_assert)
648			tsp = &pi.assert_timestamp;
649		else
650			tsp = &pi.clear_timestamp;
651		a = tsp->tv_nsec;
652		a /= 1e9;
653		tstmp.l_uf =  a * 4294967296.0;
654		tstmp.l_ui = tsp->tv_sec;
655		tstmp.l_ui += JAN_1970;
656		L_SUB(&trtmp, &tstmp);
657		if (trtmp.l_ui == 0) {
658#ifdef DEBUG
659			if (debug > 1) {
660				printf(
661				    "refclock_gtlin: fd %d time_pps_fetch %s",
662				    fdpps, lfptoa(&tstmp, 6));
663				printf(" sigio %s\n", lfptoa(&trtmp, 6));
664			}
665#endif
666			trtmp = tstmp;
667			goto gotit;
668		} else
669			trtmp = rbufp->recv_time;
670	}
671#endif /* HAVE_PPSAPI */
672#ifdef TIOCDCDTIMESTAMP
673	if(ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) {
674		TVTOTS(&dcd_time, &tstmp);
675		tstmp.l_ui += JAN_1970;
676		L_SUB(&trtmp, &tstmp);
677		if (trtmp.l_ui == 0) {
678#ifdef DEBUG
679			if (debug > 1) {
680				printf(
681				    "refclock_gtlin: fd %d DCDTIMESTAMP %s",
682				    rbufp->fd, lfptoa(&tstmp, 6));
683				printf(" sigio %s\n", lfptoa(&trtmp, 6));
684			}
685#endif
686			trtmp = tstmp;
687			goto gotit;
688		} else
689			trtmp = rbufp->recv_time;
690	}
691	else
692	/* XXX fallback to old method if kernel refuses TIOCDCDTIMESTAMP */
693#endif  /* TIOCDCDTIMESTAMP */
694	if (dpend >= dpt + 8) {
695		if (buftvtots(dpend - 8, &tstmp)) {
696			L_SUB(&trtmp, &tstmp);
697			if (trtmp.l_ui == 0) {
698#ifdef DEBUG
699				if (debug > 1) {
700					printf(
701					    "refclock_gtlin: fd %d ldisc %s",
702					    rbufp->fd, lfptoa(&trtmp, 6));
703					get_systime(&trtmp);
704					L_SUB(&trtmp, &tstmp);
705					printf(" sigio %s\n", lfptoa(&trtmp, 6));
706				}
707#endif
708				dpend -= 8;
709				trtmp = tstmp;
710			} else
711				trtmp = rbufp->recv_time;
712		}
713	}
714
715#if defined(HAVE_PPSAPI) || defined(TIOCDCDTIMESTAMP)
716gotit:
717#endif
718	/*
719	 * Edit timecode to remove control chars. Don't monkey with the
720	 * line buffer if the input buffer contains no ASCII printing
721	 * characters.
722	 */
723	if (dpend - dpt > bmax - 1)
724		dpend = dpt + bmax - 1;
725	for (dp = lineptr; dpt < dpend; dpt++) {
726		c = *dpt & 0x7f;
727		if (c >= ' ')
728			*dp++ = c;
729	}
730	i = dp - lineptr;
731	if (i > 0)
732		*dp = '\0';
733#ifdef DEBUG
734	if (debug > 1 && i > 0)
735		printf("refclock_gtlin: fd %d time %s timecode %d %s\n",
736		    rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
737#endif
738	*tsptr = trtmp;
739	return (i);
740}
741
742/*
743 * The following code does not apply to WINNT & VMS ...
744 */
745#if !defined SYS_VXWORKS && !defined SYS_WINNT
746#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
747
748/*
749 * refclock_open - open serial port for reference clock
750 *
751 * This routine opens a serial port for I/O and sets default options. It
752 * returns the file descriptor if success and zero if failure.
753 */
754int
755refclock_open(
756	char *dev,		/* device name pointer */
757	int speed,		/* serial port speed (code) */
758	int flags		/* line discipline flags */
759	)
760{
761	int fd, i;
762#ifdef HAVE_TERMIOS
763	struct termios ttyb, *ttyp;
764#endif /* HAVE_TERMIOS */
765#ifdef HAVE_SYSV_TTYS
766	struct termio ttyb, *ttyp;
767#endif /* HAVE_SYSV_TTYS */
768#ifdef HAVE_BSD_TTYS
769	struct sgttyb ttyb, *ttyp;
770#endif /* HAVE_BSD_TTYS */
771#ifdef TIOCMGET
772	u_long ltemp;
773#endif /* TIOCMGET */
774
775	/*
776	 * Open serial port and set default options
777	 */
778#ifdef O_NONBLOCK
779	fd = open(dev, O_RDWR | O_NONBLOCK, 0777);
780#else
781	fd = open(dev, O_RDWR, 0777);
782#endif /* O_NONBLOCK */
783	if (fd == -1) {
784		msyslog(LOG_ERR, "refclock_open: %s: %m", dev);
785		return (0);
786	}
787
788	/*
789	 * The following sections initialize the serial line port in
790	 * canonical (line-oriented) mode and set the specified line
791	 * speed, 8 bits and no parity. The modem control, break, erase
792	 * and kill functions are normally disabled. There is a
793	 * different section for each terminal interface, as selected at
794	 * compile time.
795	 */
796	ttyp = &ttyb;
797
798#ifdef HAVE_TERMIOS
799	/*
800	 * POSIX serial line parameters (termios interface)
801	 */
802	if (tcgetattr(fd, ttyp) < 0) {
803		msyslog(LOG_ERR,
804			"refclock_open: fd %d tcgetattr: %m", fd);
805		return (0);
806	}
807
808	/*
809	 * Set canonical mode and local connection; set specified speed,
810	 * 8 bits and no parity; map CR to NL; ignore break.
811	 */
812	ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
813	ttyp->c_oflag = 0;
814	ttyp->c_cflag = CS8 | CLOCAL | CREAD;
815	(void)cfsetispeed(&ttyb, (u_int)speed);
816	(void)cfsetospeed(&ttyb, (u_int)speed);
817	ttyp->c_lflag = ICANON;
818	for (i = 0; i < NCCS; ++i)
819	{
820		ttyp->c_cc[i] = '\0';
821	}
822
823	/*
824	 * Some special cases
825	 */
826	if (flags & LDISC_RAW) {
827		ttyp->c_iflag = 0;
828		ttyp->c_lflag = 0;
829		ttyp->c_cc[VMIN] = 1;
830	}
831#if defined(TIOCMGET) && !defined(SCO5_CLOCK)
832	/*
833	 * If we have modem control, check to see if modem leads are
834	 * active; if so, set remote connection. This is necessary for
835	 * the kernel pps mods to work.
836	 */
837	ltemp = 0;
838	if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
839		msyslog(LOG_ERR,
840			"refclock_open: fd %d TIOCMGET failed: %m", fd);
841#ifdef DEBUG
842	if (debug)
843		printf("refclock_open: fd %d modem status 0x%lx\n",
844		    fd, ltemp);
845#endif
846	if (ltemp & TIOCM_DSR)
847		ttyp->c_cflag &= ~CLOCAL;
848#endif /* TIOCMGET */
849	if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
850		msyslog(LOG_ERR,
851		    "refclock_open: fd %d TCSANOW failed: %m", fd);
852		return (0);
853	}
854	if (tcflush(fd, TCIOFLUSH) < 0) {
855		msyslog(LOG_ERR,
856		    "refclock_open: fd %d TCIOFLUSH failed: %m", fd);
857		return (0);
858	}
859#endif /* HAVE_TERMIOS */
860
861#ifdef HAVE_SYSV_TTYS
862
863	/*
864	 * System V serial line parameters (termio interface)
865	 *
866	 */
867	if (ioctl(fd, TCGETA, ttyp) < 0) {
868		msyslog(LOG_ERR,
869		    "refclock_open: fd %d TCGETA failed: %m", fd);
870		return (0);
871	}
872
873	/*
874	 * Set canonical mode and local connection; set specified speed,
875	 * 8 bits and no parity; map CR to NL; ignore break.
876	 */
877	ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
878	ttyp->c_oflag = 0;
879	ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
880	ttyp->c_lflag = ICANON;
881	ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
882
883	/*
884	 * Some special cases
885	 */
886	if (flags & LDISC_RAW) {
887		ttyp->c_iflag = 0;
888		ttyp->c_lflag = 0;
889	}
890#ifdef TIOCMGET
891	/*
892	 * If we have modem control, check to see if modem leads are
893	 * active; if so, set remote connection. This is necessary for
894	 * the kernel pps mods to work.
895	 */
896	ltemp = 0;
897	if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
898		msyslog(LOG_ERR,
899		    "refclock_open: fd %d TIOCMGET failed: %m", fd);
900#ifdef DEBUG
901	if (debug)
902		printf("refclock_open: fd %d modem status %lx\n",
903		    fd, ltemp);
904#endif
905	if (ltemp & TIOCM_DSR)
906		ttyp->c_cflag &= ~CLOCAL;
907#endif /* TIOCMGET */
908	if (ioctl(fd, TCSETA, ttyp) < 0) {
909		msyslog(LOG_ERR,
910		    "refclock_open: fd %d TCSETA failed: %m", fd);
911		return (0);
912	}
913#endif /* HAVE_SYSV_TTYS */
914
915#ifdef HAVE_BSD_TTYS
916
917	/*
918	 * 4.3bsd serial line parameters (sgttyb interface)
919	 */
920	if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
921		msyslog(LOG_ERR,
922		    "refclock_open: fd %d TIOCGETP %m", fd);
923		return (0);
924	}
925	ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
926	ttyp->sg_flags = EVENP | ODDP | CRMOD;
927	if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
928		msyslog(LOG_ERR,
929		    "refclock_open: TIOCSETP failed: %m");
930		return (0);
931	}
932#endif /* HAVE_BSD_TTYS */
933	if (!refclock_ioctl(fd, flags)) {
934		(void)close(fd);
935		msyslog(LOG_ERR,
936		    "refclock_open: fd %d ioctl failed: %m", fd);
937		return (0);
938	}
939
940	/*
941	 * If this is the PPS device, so say and initialize the thing.
942	 */
943	if (strcmp(dev, pps_device) == 0)
944		(void)refclock_ioctl(fd, LDISC_PPS);
945	return (fd);
946}
947#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
948#endif /* SYS_VXWORKS SYS_WINNT */
949
950/*
951 * refclock_ioctl - set serial port control functions
952 *
953 * This routine attempts to hide the internal, system-specific details
954 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
955 * (sgtty) interfaces with varying degrees of success. The routine sets
956 * up optional features such as tty_clk, ppsclock and ppsapi, as well as
957 * their many other variants. The routine returns 1 if success and 0 if
958 * failure.
959 */
960int
961refclock_ioctl(
962	int fd, 		/* file descriptor */
963	int flags		/* line discipline flags */
964	)
965{
966	/* simply return 1 if no UNIX line discipline is supported */
967#if !defined SYS_VXWORKS && !defined SYS_WINNT
968#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
969
970#ifdef TTYCLK
971#ifdef HAVE_TERMIOS
972	struct termios ttyb, *ttyp;
973#endif /* HAVE_TERMIOS */
974#ifdef HAVE_SYSV_TTYS
975	struct termio ttyb, *ttyp;
976#endif /* HAVE_SYSV_TTYS */
977#ifdef HAVE_BSD_TTYS
978	struct sgttyb ttyb, *ttyp;
979#endif /* HAVE_BSD_TTYS */
980#endif /* TTYCLK */
981
982#ifdef DEBUG
983	if (debug)
984		printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags);
985#endif
986
987	/*
988	 * The following sections select optional features, such as
989	 * modem control, PPS capture and so forth. Some require
990	 * specific operating system support in the form of STREAMS
991	 * modules, which can be loaded and unloaded at run time without
992	 * rebooting the kernel. The STREAMS modules require System
993	 * V STREAMS support. The checking frenzy is attenuated here,
994	 * since the device is already open.
995	 *
996	 * Note that the tty_clk and ppsclock modules are optional; if
997	 * configured and unavailable, the dang thing still works, but
998	 * the accuracy improvement using them will not be available.
999	 * The only known implmentations of these moldules are specific
1000	 * to SunOS 4.x. Use the ppsclock module ONLY with Sun baseboard
1001	 * ttya or ttyb. Using it with the SPIF multipexor crashes the
1002	 * kernel.
1003	 *
1004	 * The preferred way to capture PPS timestamps is using the
1005	 * ppsapi interface, which is machine independent. The SunOS 4.x
1006	 * and Digital Unix 4.x interfaces use STREAMS modules and
1007	 * support both the ppsapi specification and ppsclock
1008	 * functionality, but other systems may vary widely.
1009	 */
1010	if (flags == 0)
1011		return (1);
1012#if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS))
1013	if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) {
1014		msyslog(LOG_ERR,
1015			"refclock_ioctl: unsupported terminal interface");
1016		return (0);
1017	}
1018#endif /* HAVE_TERMIOS HAVE_BSD_TTYS */
1019#ifdef TTYCLK
1020	ttyp = &ttyb;
1021#endif /* TTYCLK */
1022
1023	/*
1024	 * The following features may or may not require System V
1025	 * STREAMS support, depending on the particular implementation.
1026	 */
1027#if defined(TTYCLK)
1028	/*
1029	 * The TTYCLK option provides timestamping at the driver level.
1030	 * It requires the tty_clk streams module and System V STREAMS
1031	 * support. If not available, don't complain.
1032	 */
1033	if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
1034		int rval = 0;
1035
1036		if (ioctl(fd, I_PUSH, "clk") < 0) {
1037			msyslog(LOG_NOTICE,
1038			    "refclock_ioctl: I_PUSH clk failed: %m");
1039		} else {
1040			char *str;
1041
1042			if (flags & LDISC_CLKPPS)
1043				str = "\377";
1044			else if (flags & LDISC_ACTS)
1045				str = "*";
1046			else
1047				str = "\n";
1048#ifdef CLK_SETSTR
1049			if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0)
1050				msyslog(LOG_ERR,
1051				    "refclock_ioctl: CLK_SETSTR failed: %m");
1052			if (debug)
1053				printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n",
1054				    fd, rval, str);
1055#endif
1056		}
1057	}
1058#endif /* TTYCLK */
1059
1060#if defined(PPS) && !defined(HAVE_PPSAPI)
1061	/*
1062	 * The PPS option provides timestamping at the driver level.
1063	 * It uses a 1-pps signal and level converter (gadget box) and
1064	 * requires the ppsclock streams module and System V STREAMS
1065	 * support. This option has been superseded by the ppsapi
1066	 * option and may be withdrawn in future.
1067	 */
1068	if (flags & LDISC_PPS) {
1069		int rval = 0;
1070#ifdef HAVE_TIOCSPPS		/* Solaris */
1071		int one = 1;
1072#endif /* HAVE_TIOCSPPS */
1073
1074		if (fdpps > 0) {
1075			msyslog(LOG_ERR,
1076				"refclock_ioctl: PPS already configured");
1077			return (0);
1078		}
1079#ifdef HAVE_TIOCSPPS		/* Solaris */
1080		if (ioctl(fd, TIOCSPPS, &one) < 0) {
1081			msyslog(LOG_NOTICE,
1082				"refclock_ioctl: TIOCSPPS failed: %m");
1083			return (0);
1084		}
1085		if (debug)
1086			printf("refclock_ioctl: fd %d TIOCSPPS %d\n",
1087			    fd, rval);
1088#else
1089		if (ioctl(fd, I_PUSH, "ppsclock") < 0) {
1090			msyslog(LOG_NOTICE,
1091				"refclock_ioctl: I_PUSH ppsclock failed: %m");
1092			return (0);
1093		}
1094		if (debug)
1095			printf("refclock_ioctl: fd %d ppsclock %d\n",
1096			    fd, rval);
1097#endif /* not HAVE_TIOCSPPS */
1098		fdpps = fd;
1099	}
1100#endif /* PPS HAVE_PPSAPI */
1101
1102#ifdef HAVE_PPSAPI
1103	/*
1104	 * The PPSAPI option provides timestamping at the driver level.
1105	 * It uses a 1-pps signal and level converter (gadget box) and
1106	 * requires ppsapi compiled into the kernel on non STREAMS
1107	 * systems. This is the preferred way to capture PPS timestamps
1108	 * and is expected to become an IETF cross-platform standard.
1109	 */
1110	if (flags & (LDISC_PPS | LDISC_CLKPPS)) {
1111		pps_params_t pp;
1112		int mode, temp;
1113		pps_handle_t handle;
1114
1115		memset((char *)&pp, 0, sizeof(pp));
1116		if (fdpps > 0) {
1117			msyslog(LOG_ERR,
1118			    "refclock_ioctl: ppsapi already configured");
1119			return (0);
1120		}
1121		if (time_pps_create(fd, &handle) < 0) {
1122			msyslog(LOG_ERR,
1123			    "refclock_ioctl: time_pps_create failed: %m");
1124			return (0);
1125		}
1126		if (time_pps_getcap(handle, &mode) < 0) {
1127			msyslog(LOG_ERR,
1128			    "refclock_ioctl: time_pps_getcap failed: %m");
1129			return (0);
1130		}
1131		pp.mode = mode & PPS_CAPTUREBOTH;
1132		if (time_pps_setparams(handle, &pp) < 0) {
1133			msyslog(LOG_ERR,
1134			    "refclock_ioctl: time_pps_setparams failed: %m");
1135			return (0);
1136		}
1137		if (!pps_hardpps)
1138			temp = 0;
1139		else if (pps_assert)
1140			temp = mode & PPS_CAPTUREASSERT;
1141		else
1142			temp = mode & PPS_CAPTURECLEAR;
1143		if (time_pps_kcbind(handle, PPS_KC_HARDPPS, temp,
1144		    PPS_TSFMT_TSPEC) < 0) {
1145			msyslog(LOG_ERR,
1146			    "refclock_ioctl: time_pps_kcbind failed: %m");
1147			return (0);
1148		}
1149		(void)time_pps_getparams(handle, &pp);
1150		fdpps = (int)handle;
1151		if (debug)
1152			printf(
1153			    "refclock_ioctl: fd %d ppsapi vers %d mode 0x%x cap 0x%x\n",
1154			    fdpps, pp.api_version, pp.mode, mode);
1155	}
1156#endif /* HAVE_PPSAPI */
1157#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
1158#endif /* SYS_VXWORKS SYS_WINNT */
1159	return (1);
1160}
1161
1162/*
1163 * refclock_control - set and/or return clock values
1164 *
1165 * This routine is used mainly for debugging. It returns designated
1166 * values from the interface structure that can be displayed using
1167 * ntpdc and the clockstat command. It can also be used to initialize
1168 * configuration variables, such as fudgetimes, fudgevalues, reference
1169 * ID and stratum.
1170 */
1171void
1172refclock_control(
1173	struct sockaddr_in *srcadr,
1174	struct refclockstat *in,
1175	struct refclockstat *out
1176	)
1177{
1178	struct peer *peer;
1179	struct refclockproc *pp;
1180	u_char clktype;
1181	int unit;
1182
1183	/*
1184	 * Check for valid address and running peer
1185	 */
1186	if (!ISREFCLOCKADR(srcadr))
1187		return;
1188	clktype = (u_char)REFCLOCKTYPE(srcadr);
1189	unit = REFCLOCKUNIT(srcadr);
1190	if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1191		return;
1192	if (!(peer = typeunit[clktype][unit]))
1193		return;
1194	pp = peer->procptr;
1195
1196	/*
1197	 * Initialize requested data
1198	 */
1199	if (in != 0) {
1200		if (in->haveflags & CLK_HAVETIME1)
1201			pp->fudgetime1 = in->fudgetime1;
1202		if (in->haveflags & CLK_HAVETIME2)
1203			pp->fudgetime2 = in->fudgetime2;
1204		if (in->haveflags & CLK_HAVEVAL1)
1205			peer->stratum = (u_char) in->fudgeval1;
1206		if (in->haveflags & CLK_HAVEVAL2)
1207			pp->refid = in->fudgeval2;
1208		if (peer->stratum <= 1)
1209			peer->refid = pp->refid;
1210		else
1211			peer->refid = peer->srcadr.sin_addr.s_addr;
1212		if (in->haveflags & CLK_HAVEFLAG1) {
1213			pp->sloppyclockflag &= ~CLK_FLAG1;
1214			pp->sloppyclockflag |= in->flags & CLK_FLAG1;
1215		}
1216		if (in->haveflags & CLK_HAVEFLAG2) {
1217			pp->sloppyclockflag &= ~CLK_FLAG2;
1218			pp->sloppyclockflag |= in->flags & CLK_FLAG2;
1219		}
1220		if (in->haveflags & CLK_HAVEFLAG3) {
1221			pp->sloppyclockflag &= ~CLK_FLAG3;
1222			pp->sloppyclockflag |= in->flags & CLK_FLAG3;
1223		}
1224		if (in->haveflags & CLK_HAVEFLAG4) {
1225			pp->sloppyclockflag &= ~CLK_FLAG4;
1226			pp->sloppyclockflag |= in->flags & CLK_FLAG4;
1227		}
1228	}
1229
1230	/*
1231	 * Readback requested data
1232	 */
1233	if (out != 0) {
1234		out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
1235			CLK_HAVEVAL2 | CLK_HAVEFLAG4;
1236		out->fudgetime1 = pp->fudgetime1;
1237		out->fudgetime2 = pp->fudgetime2;
1238		out->fudgeval1 = peer->stratum;
1239		out->fudgeval2 = pp->refid;
1240		out->flags = (u_char) pp->sloppyclockflag;
1241
1242		out->timereset = current_time - pp->timestarted;
1243		out->polls = pp->polls;
1244		out->noresponse = pp->noreply;
1245		out->badformat = pp->badformat;
1246		out->baddata = pp->baddata;
1247
1248		out->lastevent = pp->lastevent;
1249		out->currentstatus = pp->currentstatus;
1250		out->type = pp->type;
1251		out->clockdesc = pp->clockdesc;
1252		out->lencode = pp->lencode;
1253		out->p_lastcode = pp->a_lastcode;
1254	}
1255
1256	/*
1257	 * Give the stuff to the clock
1258	 */
1259	if (refclock_conf[clktype]->clock_control != noentry)
1260		(refclock_conf[clktype]->clock_control)(unit, in, out, peer);
1261}
1262
1263
1264/*
1265 * refclock_buginfo - return debugging info
1266 *
1267 * This routine is used mainly for debugging. It returns designated
1268 * values from the interface structure that can be displayed using
1269 * ntpdc and the clkbug command.
1270 */
1271void
1272refclock_buginfo(
1273	struct sockaddr_in *srcadr, /* clock address */
1274	struct refclockbug *bug /* output structure */
1275	)
1276{
1277	struct peer *peer;
1278	struct refclockproc *pp;
1279	u_char clktype;
1280	int unit;
1281	int i;
1282
1283	/*
1284	 * Check for valid address and peer structure
1285	 */
1286	if (!ISREFCLOCKADR(srcadr))
1287		return;
1288	clktype = (u_char) REFCLOCKTYPE(srcadr);
1289	unit = REFCLOCKUNIT(srcadr);
1290	if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1291		return;
1292	if (!(peer = typeunit[clktype][unit]))
1293		return;
1294	pp = peer->procptr;
1295
1296	/*
1297	 * Copy structure values
1298	 */
1299	bug->nvalues = 8;
1300	bug->svalues = 0x0000003f;
1301	bug->values[0] = pp->year;
1302	bug->values[1] = pp->day;
1303	bug->values[2] = pp->hour;
1304	bug->values[3] = pp->minute;
1305	bug->values[4] = pp->second;
1306	bug->values[5] = pp->msec;
1307	bug->values[6] = pp->yearstart;
1308	bug->values[7] = pp->coderecv;
1309	bug->stimes = 0xfffffffc;
1310	bug->times[0] = pp->lastref;
1311	bug->times[1] = pp->lastrec;
1312	for (i = 2; i < (int)bug->ntimes; i++)
1313		DTOLFP(pp->filter[i - 2], &bug->times[i]);
1314
1315	/*
1316	 * Give the stuff to the clock
1317	 */
1318	if (refclock_conf[clktype]->clock_buginfo != noentry)
1319		(refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
1320}
1321
1322#endif /* REFCLOCK */
1323