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