xref: /freebsd/contrib/ntp/ntpd/ntp_refclock.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * ntp_refclock - processing support for reference clocks
3c0b746e5SOllivier Robert  */
4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
5c0b746e5SOllivier Robert # include <config.h>
6c0b746e5SOllivier Robert #endif
7c0b746e5SOllivier Robert 
8c0b746e5SOllivier Robert #include "ntpd.h"
9c0b746e5SOllivier Robert #include "ntp_io.h"
10c0b746e5SOllivier Robert #include "ntp_unixtime.h"
11224ba2bdSOllivier Robert #include "ntp_tty.h"
12c0b746e5SOllivier Robert #include "ntp_refclock.h"
13a466cc55SCy Schubert #include "ntp_clockdev.h"
14c0b746e5SOllivier Robert #include "ntp_stdlib.h"
152b15cb3dSCy Schubert #include "ntp_assert.h"
162d4e511cSCy Schubert #include "timespecops.h"
17c0b746e5SOllivier Robert 
18224ba2bdSOllivier Robert #include <stdio.h>
19224ba2bdSOllivier Robert 
20224ba2bdSOllivier Robert #ifdef HAVE_SYS_IOCTL_H
21224ba2bdSOllivier Robert # include <sys/ioctl.h>
22224ba2bdSOllivier Robert #endif /* HAVE_SYS_IOCTL_H */
23224ba2bdSOllivier Robert 
24c0b746e5SOllivier Robert #ifdef REFCLOCK
25c0b746e5SOllivier Robert 
26224ba2bdSOllivier Robert #ifdef KERNEL_PLL
27224ba2bdSOllivier Robert #include "ntp_syscall.h"
28224ba2bdSOllivier Robert #endif /* KERNEL_PLL */
29c0b746e5SOllivier Robert 
302b15cb3dSCy Schubert #ifdef HAVE_PPSAPI
312b15cb3dSCy Schubert #include "ppsapi_timepps.h"
322b15cb3dSCy Schubert #include "refclock_atom.h"
332b15cb3dSCy Schubert #endif /* HAVE_PPSAPI */
342b15cb3dSCy Schubert 
35c0b746e5SOllivier Robert /*
36c0b746e5SOllivier Robert  * Reference clock support is provided here by maintaining the fiction
372b15cb3dSCy Schubert  * that the clock is actually a peer.  As no packets are exchanged with
382b15cb3dSCy Schubert  * a reference clock, however, we replace the transmit, receive and
392b15cb3dSCy Schubert  * packet procedures with separate code to simulate them.  Routines
40c0b746e5SOllivier Robert  * refclock_transmit() and refclock_receive() maintain the peer
41c0b746e5SOllivier Robert  * variables in a state analogous to an actual peer and pass reference
42c0b746e5SOllivier Robert  * clock data on through the filters.  Routines refclock_peer() and
43c0b746e5SOllivier Robert  * refclock_unpeer() are called to initialize and terminate reference
44c0b746e5SOllivier Robert  * clock associations.  A set of utility routines is included to open
452b15cb3dSCy Schubert  * serial devices, process sample data, and to perform various debugging
462b15cb3dSCy Schubert  * functions.
47c0b746e5SOllivier Robert  *
48c0b746e5SOllivier Robert  * The main interface used by these routines is the refclockproc
492b15cb3dSCy Schubert  * structure, which contains for most drivers the decimal equivalants
502b15cb3dSCy Schubert  * of the year, day, month, hour, second and millisecond/microsecond
512b15cb3dSCy Schubert  * decoded from the ASCII timecode.  Additional information includes
522b15cb3dSCy Schubert  * the receive timestamp, exception report, statistics tallies, etc.
532b15cb3dSCy Schubert  * In addition, there may be a driver-specific unit structure used for
54c0b746e5SOllivier Robert  * local control of the device.
55c0b746e5SOllivier Robert  *
56c0b746e5SOllivier Robert  * The support routines are passed a pointer to the peer structure,
572b15cb3dSCy Schubert  * which is used for all peer-specific processing and contains a
582b15cb3dSCy Schubert  * pointer to the refclockproc structure, which in turn contains a
592b15cb3dSCy Schubert  * pointer to the unit structure, if used.  The peer structure is
602b15cb3dSCy Schubert  * identified by an interface address in the dotted quad form
612b15cb3dSCy Schubert  * 127.127.t.u, where t is the clock type and u the unit.
62c0b746e5SOllivier Robert  */
63c0b746e5SOllivier Robert #define FUDGEFAC	.1	/* fudge correction factor */
64ea906c41SOllivier Robert #define LF		0x0a	/* ASCII LF */
65c0b746e5SOllivier Robert 
66224ba2bdSOllivier Robert int	cal_enable;		/* enable refclock calibrate */
67224ba2bdSOllivier Robert 
68c0b746e5SOllivier Robert /*
69c0b746e5SOllivier Robert  * Forward declarations
70c0b746e5SOllivier Robert  */
712b15cb3dSCy Schubert static int  refclock_cmpl_fp (const void *, const void *);
722b15cb3dSCy Schubert static int  refclock_sample (struct refclockproc *);
732b15cb3dSCy Schubert static int  refclock_ioctl(int, u_int);
742d4e511cSCy Schubert static void refclock_checkburst(struct peer *, struct refclockproc *);
75c0b746e5SOllivier Robert 
762d4e511cSCy Schubert /* circular buffer functions
772d4e511cSCy Schubert  *
782d4e511cSCy Schubert  * circular buffer management comes in two flovours:
792d4e511cSCy Schubert  * for powers of two, and all others.
802d4e511cSCy Schubert  */
812d4e511cSCy Schubert 
822d4e511cSCy Schubert #if MAXSTAGE & (MAXSTAGE - 1)
832d4e511cSCy Schubert 
842d4e511cSCy Schubert static void clk_add_sample(
852d4e511cSCy Schubert 	struct refclockproc * const	pp,
862d4e511cSCy Schubert 	double				sv
872d4e511cSCy Schubert 	)
882d4e511cSCy Schubert {
892d4e511cSCy Schubert 	pp->coderecv = (pp->coderecv + 1) % MAXSTAGE;
902d4e511cSCy Schubert 	if (pp->coderecv == pp->codeproc)
912d4e511cSCy Schubert 		pp->codeproc = (pp->codeproc + 1) % MAXSTAGE;
922d4e511cSCy Schubert 	pp->filter[pp->coderecv] = sv;
932d4e511cSCy Schubert }
942d4e511cSCy Schubert 
952d4e511cSCy Schubert static double clk_pop_sample(
962d4e511cSCy Schubert 	struct refclockproc * const	pp
972d4e511cSCy Schubert 	)
982d4e511cSCy Schubert {
992d4e511cSCy Schubert 	if (pp->coderecv == pp->codeproc)
1002d4e511cSCy Schubert 		return 0; /* Maybe a NaN would be better? */
1012d4e511cSCy Schubert 	pp->codeproc = (pp->codeproc + 1) % MAXSTAGE;
1022d4e511cSCy Schubert 	return pp->filter[pp->codeproc];
1032d4e511cSCy Schubert }
1042d4e511cSCy Schubert 
1052d4e511cSCy Schubert static inline u_int clk_cnt_sample(
1062d4e511cSCy Schubert 	struct refclockproc * const	pp
1072d4e511cSCy Schubert 	)
1082d4e511cSCy Schubert {
1092d4e511cSCy Schubert 	u_int retv = pp->coderecv - pp->codeproc;
1102d4e511cSCy Schubert 	if (retv > MAXSTAGE)
1112d4e511cSCy Schubert 		retv += MAXSTAGE;
1122d4e511cSCy Schubert 	return retv;
1132d4e511cSCy Schubert }
1142d4e511cSCy Schubert 
1152d4e511cSCy Schubert #else
1162d4e511cSCy Schubert 
1172d4e511cSCy Schubert static inline void clk_add_sample(
1182d4e511cSCy Schubert 	struct refclockproc * const	pp,
1192d4e511cSCy Schubert 	double				sv
1202d4e511cSCy Schubert 	)
1212d4e511cSCy Schubert {
1222d4e511cSCy Schubert 	pp->coderecv  = (pp->coderecv + 1) & (MAXSTAGE - 1);
1232d4e511cSCy Schubert 	if (pp->coderecv == pp->codeproc)
1242d4e511cSCy Schubert 		pp->codeproc = (pp->codeproc + 1) & (MAXSTAGE - 1);
1252d4e511cSCy Schubert 	pp->filter[pp->coderecv] = sv;
1262d4e511cSCy Schubert }
1272d4e511cSCy Schubert 
1282d4e511cSCy Schubert static inline double clk_pop_sample(
1292d4e511cSCy Schubert 	struct refclockproc * const	pp
1302d4e511cSCy Schubert 	)
1312d4e511cSCy Schubert {
1322d4e511cSCy Schubert 	if (pp->coderecv == pp->codeproc)
1332d4e511cSCy Schubert 		return 0; /* Maybe a NaN would be better? */
1342d4e511cSCy Schubert 	pp->codeproc = (pp->codeproc + 1) & (MAXSTAGE - 1);
1352d4e511cSCy Schubert 	return pp->filter[pp->codeproc];
1362d4e511cSCy Schubert }
1372d4e511cSCy Schubert 
1382d4e511cSCy Schubert static inline u_int clk_cnt_sample(
1392d4e511cSCy Schubert 	struct refclockproc * const	pp
1402d4e511cSCy Schubert 	)
1412d4e511cSCy Schubert {
1422d4e511cSCy Schubert 	return (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1);
1432d4e511cSCy Schubert }
1442d4e511cSCy Schubert 
1452d4e511cSCy Schubert #endif
146ea906c41SOllivier Robert 
147c0b746e5SOllivier Robert /*
148c0b746e5SOllivier Robert  * refclock_report - note the occurance of an event
149c0b746e5SOllivier Robert  *
150c0b746e5SOllivier Robert  * This routine presently just remembers the report and logs it, but
151c0b746e5SOllivier Robert  * does nothing heroic for the trap handler. It tries to be a good
152c0b746e5SOllivier Robert  * citizen and bothers the system log only if things change.
153c0b746e5SOllivier Robert  */
154c0b746e5SOllivier Robert void
155c0b746e5SOllivier Robert refclock_report(
156c0b746e5SOllivier Robert 	struct peer *peer,
157c0b746e5SOllivier Robert 	int code
158c0b746e5SOllivier Robert 	)
159c0b746e5SOllivier Robert {
160c0b746e5SOllivier Robert 	struct refclockproc *pp;
161c0b746e5SOllivier Robert 
1629c2daa00SOllivier Robert 	pp = peer->procptr;
1639c2daa00SOllivier Robert 	if (pp == NULL)
164c0b746e5SOllivier Robert 		return;
165ea906c41SOllivier Robert 
166ea906c41SOllivier Robert 	switch (code) {
167ea906c41SOllivier Robert 
168ea906c41SOllivier Robert 	case CEVNT_TIMEOUT:
169c0b746e5SOllivier Robert 		pp->noreply++;
170ea906c41SOllivier Robert 		break;
171ea906c41SOllivier Robert 
172ea906c41SOllivier Robert 	case CEVNT_BADREPLY:
173ea906c41SOllivier Robert 		pp->badformat++;
174ea906c41SOllivier Robert 		break;
175ea906c41SOllivier Robert 
176ea906c41SOllivier Robert 	case CEVNT_FAULT:
177ea906c41SOllivier Robert 		break;
178ea906c41SOllivier Robert 
179ea906c41SOllivier Robert 	case CEVNT_BADDATE:
180ea906c41SOllivier Robert 	case CEVNT_BADTIME:
181ea906c41SOllivier Robert 		pp->baddata++;
182ea906c41SOllivier Robert 		break;
183ea906c41SOllivier Robert 
184ea906c41SOllivier Robert 	default:
1852b15cb3dSCy Schubert 		/* ignore others */
186ea906c41SOllivier Robert 		break;
187ea906c41SOllivier Robert 	}
1884e1ef62aSXin LI 	if ((code != CEVNT_NOMINAL) && (pp->lastevent < 15))
1892b15cb3dSCy Schubert 		pp->lastevent++;
190c0b746e5SOllivier Robert 	if (pp->currentstatus != code) {
1919c2daa00SOllivier Robert 		pp->currentstatus = (u_char)code;
1922b15cb3dSCy Schubert 		report_event(PEVNT_CLOCK, peer, ceventstr(code));
193ea906c41SOllivier Robert 	}
194ea906c41SOllivier Robert }
195c0b746e5SOllivier Robert 
1962b15cb3dSCy Schubert 
197c0b746e5SOllivier Robert /*
198c0b746e5SOllivier Robert  * init_refclock - initialize the reference clock drivers
199c0b746e5SOllivier Robert  *
200c0b746e5SOllivier Robert  * This routine calls each of the drivers in turn to initialize internal
201c0b746e5SOllivier Robert  * variables, if necessary. Most drivers have nothing to say at this
202c0b746e5SOllivier Robert  * point.
203c0b746e5SOllivier Robert  */
204c0b746e5SOllivier Robert void
205c0b746e5SOllivier Robert init_refclock(void)
206c0b746e5SOllivier Robert {
2072b15cb3dSCy Schubert 	int i;
208c0b746e5SOllivier Robert 
2092b15cb3dSCy Schubert 	for (i = 0; i < (int)num_refclock_conf; i++)
210c0b746e5SOllivier Robert 		if (refclock_conf[i]->clock_init != noentry)
211c0b746e5SOllivier Robert 			(refclock_conf[i]->clock_init)();
212c0b746e5SOllivier Robert }
213c0b746e5SOllivier Robert 
214c0b746e5SOllivier Robert 
215c0b746e5SOllivier Robert /*
216c0b746e5SOllivier Robert  * refclock_newpeer - initialize and start a reference clock
217c0b746e5SOllivier Robert  *
218c0b746e5SOllivier Robert  * This routine allocates and initializes the interface structure which
219c0b746e5SOllivier Robert  * supports a reference clock in the form of an ordinary NTP peer. A
220c0b746e5SOllivier Robert  * driver-specific support routine completes the initialization, if
221c0b746e5SOllivier Robert  * used. Default peer variables which identify the clock and establish
222c0b746e5SOllivier Robert  * its reference ID and stratum are set here. It returns one if success
223c0b746e5SOllivier Robert  * and zero if the clock address is invalid or already running,
224c0b746e5SOllivier Robert  * insufficient resources are available or the driver declares a bum
225c0b746e5SOllivier Robert  * rap.
226c0b746e5SOllivier Robert  */
227c0b746e5SOllivier Robert int
228c0b746e5SOllivier Robert refclock_newpeer(
229c0b746e5SOllivier Robert 	struct peer *peer	/* peer structure pointer */
230c0b746e5SOllivier Robert 	)
231c0b746e5SOllivier Robert {
232c0b746e5SOllivier Robert 	struct refclockproc *pp;
233c0b746e5SOllivier Robert 	u_char clktype;
234c0b746e5SOllivier Robert 	int unit;
235c0b746e5SOllivier Robert 
236c0b746e5SOllivier Robert 	/*
237c0b746e5SOllivier Robert 	 * Check for valid clock address. If already running, shut it
238c0b746e5SOllivier Robert 	 * down first.
239c0b746e5SOllivier Robert 	 */
240c0b746e5SOllivier Robert 	if (!ISREFCLOCKADR(&peer->srcadr)) {
241c0b746e5SOllivier Robert 		msyslog(LOG_ERR,
242c0b746e5SOllivier Robert 			"refclock_newpeer: clock address %s invalid",
2439c2daa00SOllivier Robert 			stoa(&peer->srcadr));
244c0b746e5SOllivier Robert 		return (0);
245c0b746e5SOllivier Robert 	}
246c0b746e5SOllivier Robert 	clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
247c0b746e5SOllivier Robert 	unit = REFCLOCKUNIT(&peer->srcadr);
2482b15cb3dSCy Schubert 	if (clktype >= num_refclock_conf ||
249c0b746e5SOllivier Robert 		refclock_conf[clktype]->clock_start == noentry) {
250c0b746e5SOllivier Robert 		msyslog(LOG_ERR,
251c0b746e5SOllivier Robert 			"refclock_newpeer: clock type %d invalid\n",
252c0b746e5SOllivier Robert 			clktype);
253c0b746e5SOllivier Robert 		return (0);
254c0b746e5SOllivier Robert 	}
255c0b746e5SOllivier Robert 
256c0b746e5SOllivier Robert 	/*
257c0b746e5SOllivier Robert 	 * Allocate and initialize interface structure
258c0b746e5SOllivier Robert 	 */
2592b15cb3dSCy Schubert 	pp = emalloc_zero(sizeof(*pp));
260c0b746e5SOllivier Robert 	peer->procptr = pp;
261c0b746e5SOllivier Robert 
262c0b746e5SOllivier Robert 	/*
263c0b746e5SOllivier Robert 	 * Initialize structures
264c0b746e5SOllivier Robert 	 */
265c0b746e5SOllivier Robert 	peer->refclktype = clktype;
2669c2daa00SOllivier Robert 	peer->refclkunit = (u_char)unit;
2672b15cb3dSCy Schubert 	peer->flags |= FLAG_REFCLOCK;
268ea906c41SOllivier Robert 	peer->leap = LEAP_NOTINSYNC;
2699c2daa00SOllivier Robert 	peer->stratum = STRATUM_REFCLOCK;
270ea906c41SOllivier Robert 	peer->ppoll = peer->maxpoll;
271c0b746e5SOllivier Robert 	pp->type = clktype;
2722b15cb3dSCy Schubert 	pp->conf = refclock_conf[clktype];
273c0b746e5SOllivier Robert 	pp->timestarted = current_time;
2742b15cb3dSCy Schubert 	pp->io.fd = -1;
275c0b746e5SOllivier Robert 
276c0b746e5SOllivier Robert 	/*
277c0b746e5SOllivier Robert 	 * Set peer.pmode based on the hmode. For appearances only.
278c0b746e5SOllivier Robert 	 */
279c0b746e5SOllivier Robert 	switch (peer->hmode) {
280c0b746e5SOllivier Robert 	case MODE_ACTIVE:
281c0b746e5SOllivier Robert 		peer->pmode = MODE_PASSIVE;
282c0b746e5SOllivier Robert 		break;
283c0b746e5SOllivier Robert 
284c0b746e5SOllivier Robert 	default:
285c0b746e5SOllivier Robert 		peer->pmode = MODE_SERVER;
286c0b746e5SOllivier Robert 		break;
287c0b746e5SOllivier Robert 	}
288c0b746e5SOllivier Robert 
289c0b746e5SOllivier Robert 	/*
290c0b746e5SOllivier Robert 	 * Do driver dependent initialization. The above defaults
291c0b746e5SOllivier Robert 	 * can be wiggled, then finish up for consistency.
292c0b746e5SOllivier Robert 	 */
293c0b746e5SOllivier Robert 	if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
294224ba2bdSOllivier Robert 		refclock_unpeer(peer);
295c0b746e5SOllivier Robert 		return (0);
296c0b746e5SOllivier Robert 	}
297c0b746e5SOllivier Robert 	peer->refid = pp->refid;
298c0b746e5SOllivier Robert 	return (1);
299c0b746e5SOllivier Robert }
300c0b746e5SOllivier Robert 
301c0b746e5SOllivier Robert 
302c0b746e5SOllivier Robert /*
303c0b746e5SOllivier Robert  * refclock_unpeer - shut down a clock
304c0b746e5SOllivier Robert  */
305c0b746e5SOllivier Robert void
306c0b746e5SOllivier Robert refclock_unpeer(
307c0b746e5SOllivier Robert 	struct peer *peer	/* peer structure pointer */
308c0b746e5SOllivier Robert 	)
309c0b746e5SOllivier Robert {
310c0b746e5SOllivier Robert 	u_char clktype;
311c0b746e5SOllivier Robert 	int unit;
312c0b746e5SOllivier Robert 
313c0b746e5SOllivier Robert 	/*
314c0b746e5SOllivier Robert 	 * Wiggle the driver to release its resources, then give back
315c0b746e5SOllivier Robert 	 * the interface structure.
316c0b746e5SOllivier Robert 	 */
3172b15cb3dSCy Schubert 	if (NULL == peer->procptr)
318c0b746e5SOllivier Robert 		return;
319ea906c41SOllivier Robert 
320c0b746e5SOllivier Robert 	clktype = peer->refclktype;
321c0b746e5SOllivier Robert 	unit = peer->refclkunit;
322c0b746e5SOllivier Robert 	if (refclock_conf[clktype]->clock_shutdown != noentry)
323c0b746e5SOllivier Robert 		(refclock_conf[clktype]->clock_shutdown)(unit, peer);
324c0b746e5SOllivier Robert 	free(peer->procptr);
3252b15cb3dSCy Schubert 	peer->procptr = NULL;
326c0b746e5SOllivier Robert }
327c0b746e5SOllivier Robert 
328c0b746e5SOllivier Robert 
329c0b746e5SOllivier Robert /*
330ea906c41SOllivier Robert  * refclock_timer - called once per second for housekeeping.
331ea906c41SOllivier Robert  */
332ea906c41SOllivier Robert void
333ea906c41SOllivier Robert refclock_timer(
3342b15cb3dSCy Schubert 	struct peer *p
335ea906c41SOllivier Robert 	)
336ea906c41SOllivier Robert {
3372b15cb3dSCy Schubert 	struct refclockproc *	pp;
338ea906c41SOllivier Robert 	int			unit;
339ea906c41SOllivier Robert 
3402b15cb3dSCy Schubert 	unit = p->refclkunit;
3412b15cb3dSCy Schubert 	pp = p->procptr;
3422b15cb3dSCy Schubert 	if (pp->conf->clock_timer != noentry)
3432b15cb3dSCy Schubert 		(*pp->conf->clock_timer)(unit, p);
3442b15cb3dSCy Schubert 	if (pp->action != NULL && pp->nextaction <= current_time)
3452b15cb3dSCy Schubert 		(*pp->action)(p);
346ea906c41SOllivier Robert }
347ea906c41SOllivier Robert 
348ea906c41SOllivier Robert 
349ea906c41SOllivier Robert /*
350c0b746e5SOllivier Robert  * refclock_transmit - simulate the transmit procedure
351c0b746e5SOllivier Robert  *
352c0b746e5SOllivier Robert  * This routine implements the NTP transmit procedure for a reference
353c0b746e5SOllivier Robert  * clock. This provides a mechanism to call the driver at the NTP poll
354c0b746e5SOllivier Robert  * interval, as well as provides a reachability mechanism to detect a
355c0b746e5SOllivier Robert  * broken radio or other madness.
356c0b746e5SOllivier Robert  */
357c0b746e5SOllivier Robert void
358c0b746e5SOllivier Robert refclock_transmit(
359c0b746e5SOllivier Robert 	struct peer *peer	/* peer structure pointer */
360c0b746e5SOllivier Robert 	)
361c0b746e5SOllivier Robert {
362c0b746e5SOllivier Robert 	u_char clktype;
363c0b746e5SOllivier Robert 	int unit;
364c0b746e5SOllivier Robert 
365c0b746e5SOllivier Robert 	clktype = peer->refclktype;
366c0b746e5SOllivier Robert 	unit = peer->refclkunit;
367c0b746e5SOllivier Robert 	peer->sent++;
368ea906c41SOllivier Robert 	get_systime(&peer->xmt);
369c0b746e5SOllivier Robert 
370c0b746e5SOllivier Robert 	/*
371c0b746e5SOllivier Robert 	 * This is a ripoff of the peer transmit routine, but
372c0b746e5SOllivier Robert 	 * specialized for reference clocks. We do a little less
373c0b746e5SOllivier Robert 	 * protocol here and call the driver-specific transmit routine.
374c0b746e5SOllivier Robert 	 */
375c0b746e5SOllivier Robert 	if (peer->burst == 0) {
376c0b746e5SOllivier Robert 		u_char oreach;
377c0b746e5SOllivier Robert #ifdef DEBUG
378c0b746e5SOllivier Robert 		if (debug)
379c0b746e5SOllivier Robert 			printf("refclock_transmit: at %ld %s\n",
3809c2daa00SOllivier Robert 			    current_time, stoa(&(peer->srcadr)));
381c0b746e5SOllivier Robert #endif
382c0b746e5SOllivier Robert 
383c0b746e5SOllivier Robert 		/*
384c0b746e5SOllivier Robert 		 * Update reachability and poll variables like the
385c0b746e5SOllivier Robert 		 * network code.
386c0b746e5SOllivier Robert 		 */
3872b15cb3dSCy Schubert 		oreach = peer->reach & 0xfe;
388c0b746e5SOllivier Robert 		peer->reach <<= 1;
3892b15cb3dSCy Schubert 		if (!(peer->reach & 0x0f))
3902b15cb3dSCy Schubert 			clock_filter(peer, 0., 0., MAXDISPERSE);
391ea906c41SOllivier Robert 		peer->outdate = current_time;
392224ba2bdSOllivier Robert 		if (!peer->reach) {
393224ba2bdSOllivier Robert 			if (oreach) {
3942b15cb3dSCy Schubert 				report_event(PEVNT_UNREACH, peer, NULL);
395c0b746e5SOllivier Robert 				peer->timereachable = current_time;
396c0b746e5SOllivier Robert 			}
397c0b746e5SOllivier Robert 		} else {
398c0b746e5SOllivier Robert 			if (peer->flags & FLAG_BURST)
399c0b746e5SOllivier Robert 				peer->burst = NSTAGE;
400c0b746e5SOllivier Robert 		}
401ea906c41SOllivier Robert 	} else {
402ea906c41SOllivier Robert 		peer->burst--;
403c0b746e5SOllivier Robert 	}
4042d4e511cSCy Schubert 	peer->procptr->inpoll = TRUE;
405c0b746e5SOllivier Robert 	if (refclock_conf[clktype]->clock_poll != noentry)
406c0b746e5SOllivier Robert 		(refclock_conf[clktype]->clock_poll)(unit, peer);
4072d4e511cSCy Schubert 	poll_update(peer, peer->hpoll, 0);
408c0b746e5SOllivier Robert }
409c0b746e5SOllivier Robert 
410c0b746e5SOllivier Robert 
411c0b746e5SOllivier Robert /*
412c0b746e5SOllivier Robert  * Compare two doubles - used with qsort()
413c0b746e5SOllivier Robert  */
414c0b746e5SOllivier Robert static int
415c0b746e5SOllivier Robert refclock_cmpl_fp(
416c0b746e5SOllivier Robert 	const void *p1,
417c0b746e5SOllivier Robert 	const void *p2
418c0b746e5SOllivier Robert 	)
419c0b746e5SOllivier Robert {
420c0b746e5SOllivier Robert 	const double *dp1 = (const double *)p1;
421c0b746e5SOllivier Robert 	const double *dp2 = (const double *)p2;
422c0b746e5SOllivier Robert 
423c0b746e5SOllivier Robert 	if (*dp1 < *dp2)
4242b15cb3dSCy Schubert 		return -1;
425c0b746e5SOllivier Robert 	if (*dp1 > *dp2)
4262b15cb3dSCy Schubert 		return 1;
4272b15cb3dSCy Schubert 	return 0;
428c0b746e5SOllivier Robert }
429ea906c41SOllivier Robert 
4302d4e511cSCy Schubert /*
4312d4e511cSCy Schubert  * Get number of available samples
4322d4e511cSCy Schubert  */
4332d4e511cSCy Schubert int
4342d4e511cSCy Schubert refclock_samples_avail(
4352d4e511cSCy Schubert 	struct refclockproc const * pp
4362d4e511cSCy Schubert 	)
4372d4e511cSCy Schubert {
4382d4e511cSCy Schubert 	u_int	na;
4392d4e511cSCy Schubert 
4402d4e511cSCy Schubert #   if MAXSTAGE & (MAXSTAGE - 1)
4412d4e511cSCy Schubert 
4422d4e511cSCy Schubert 	na = pp->coderecv - pp->codeproc;
4432d4e511cSCy Schubert 	if (na > MAXSTAGE)
4442d4e511cSCy Schubert 		na += MAXSTAGE;
4452d4e511cSCy Schubert 
4462d4e511cSCy Schubert #   else
4472d4e511cSCy Schubert 
4482d4e511cSCy Schubert 	na = (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1);
4492d4e511cSCy Schubert 
4502d4e511cSCy Schubert #   endif
4512d4e511cSCy Schubert 	return na;
4522d4e511cSCy Schubert }
4532d4e511cSCy Schubert 
4542d4e511cSCy Schubert /*
4552d4e511cSCy Schubert  * Expire (remove) samples from the tail (oldest samples removed)
4562d4e511cSCy Schubert  *
4572d4e511cSCy Schubert  * Returns number of samples deleted
4582d4e511cSCy Schubert  */
4592d4e511cSCy Schubert int
4602d4e511cSCy Schubert refclock_samples_expire(
4612d4e511cSCy Schubert 	struct refclockproc * pp,
4622d4e511cSCy Schubert 	int                   nd
4632d4e511cSCy Schubert 	)
4642d4e511cSCy Schubert {
4652d4e511cSCy Schubert 	u_int	na;
4662d4e511cSCy Schubert 
4672d4e511cSCy Schubert 	if (nd <= 0)
4682d4e511cSCy Schubert 		return 0;
4692d4e511cSCy Schubert 
4702d4e511cSCy Schubert #   if MAXSTAGE & (MAXSTAGE - 1)
4712d4e511cSCy Schubert 
4722d4e511cSCy Schubert 	na = pp->coderecv - pp->codeproc;
4732d4e511cSCy Schubert 	if (na > MAXSTAGE)
4742d4e511cSCy Schubert 		na += MAXSTAGE;
4752d4e511cSCy Schubert 	if ((u_int)nd < na)
4762d4e511cSCy Schubert 		nd = na;
4772d4e511cSCy Schubert 	pp->codeproc = (pp->codeproc + nd) % MAXSTAGE;
4782d4e511cSCy Schubert 
4792d4e511cSCy Schubert #   else
4802d4e511cSCy Schubert 
4812d4e511cSCy Schubert 	na = (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1);
4822d4e511cSCy Schubert 	if ((u_int)nd > na)
4832d4e511cSCy Schubert 		nd = (int)na;
4842d4e511cSCy Schubert 	pp->codeproc = (pp->codeproc + nd) & (MAXSTAGE - 1);
4852d4e511cSCy Schubert 
4862d4e511cSCy Schubert #   endif
4872d4e511cSCy Schubert 	return nd;
4882d4e511cSCy Schubert }
489c0b746e5SOllivier Robert 
490c0b746e5SOllivier Robert /*
491c0b746e5SOllivier Robert  * refclock_process_offset - update median filter
492c0b746e5SOllivier Robert  *
493224ba2bdSOllivier Robert  * This routine uses the given offset and timestamps to construct a new
494224ba2bdSOllivier Robert  * entry in the median filter circular buffer. Samples that overflow the
495224ba2bdSOllivier Robert  * filter are quietly discarded.
496c0b746e5SOllivier Robert  */
497c0b746e5SOllivier Robert void
498c0b746e5SOllivier Robert refclock_process_offset(
4999c2daa00SOllivier Robert 	struct refclockproc *pp,	/* refclock structure pointer */
5009c2daa00SOllivier Robert 	l_fp lasttim,			/* last timecode timestamp */
5019c2daa00SOllivier Robert 	l_fp lastrec,			/* last receive timestamp */
502c0b746e5SOllivier Robert 	double fudge
503c0b746e5SOllivier Robert 	)
504c0b746e5SOllivier Robert {
5059c2daa00SOllivier Robert 	l_fp lftemp;
506c0b746e5SOllivier Robert 	double doffset;
507c0b746e5SOllivier Robert 
508c0b746e5SOllivier Robert 	pp->lastrec = lastrec;
5099c2daa00SOllivier Robert 	lftemp = lasttim;
5109c2daa00SOllivier Robert 	L_SUB(&lftemp, &lastrec);
5119c2daa00SOllivier Robert 	LFPTOD(&lftemp, doffset);
5122d4e511cSCy Schubert 	clk_add_sample(pp, doffset + fudge);
5132d4e511cSCy Schubert 	refclock_checkburst(pp->io.srcclock, pp);
514c0b746e5SOllivier Robert }
515c0b746e5SOllivier Robert 
516ea906c41SOllivier Robert 
517c0b746e5SOllivier Robert /*
518c0b746e5SOllivier Robert  * refclock_process - process a sample from the clock
5192b15cb3dSCy Schubert  * refclock_process_f - refclock_process with other than time1 fudge
520c0b746e5SOllivier Robert  *
521c0b746e5SOllivier Robert  * This routine converts the timecode in the form days, hours, minutes,
522c0b746e5SOllivier Robert  * seconds and milliseconds/microseconds to internal timestamp format,
523c0b746e5SOllivier Robert  * then constructs a new entry in the median filter circular buffer.
524c0b746e5SOllivier Robert  * Return success (1) if the data are correct and consistent with the
5252d4e511cSCy Schubert  * conventional calendar.
526ea906c41SOllivier Robert  *
527ea906c41SOllivier Robert  * Important for PPS users: Normally, the pp->lastrec is set to the
528ea906c41SOllivier Robert  * system time when the on-time character is received and the pp->year,
529ea906c41SOllivier Robert  * ..., pp->second decoded and the seconds fraction pp->nsec in
530ea906c41SOllivier Robert  * nanoseconds). When a PPS offset is available, pp->nsec is forced to
531ea906c41SOllivier Robert  * zero and the fraction for pp->lastrec is set to the PPS offset.
532c0b746e5SOllivier Robert  */
533c0b746e5SOllivier Robert int
5342b15cb3dSCy Schubert refclock_process_f(
5352b15cb3dSCy Schubert 	struct refclockproc *pp,	/* refclock structure pointer */
5362b15cb3dSCy Schubert 	double fudge
537c0b746e5SOllivier Robert 	)
538c0b746e5SOllivier Robert {
5399c2daa00SOllivier Robert 	l_fp offset, ltemp;
540c0b746e5SOllivier Robert 
541c0b746e5SOllivier Robert 	/*
542c0b746e5SOllivier Robert 	 * Compute the timecode timestamp from the days, hours, minutes,
543c0b746e5SOllivier Robert 	 * seconds and milliseconds/microseconds of the timecode. Use
544c0b746e5SOllivier Robert 	 * clocktime() for the aggregate seconds and the msec/usec for
545c0b746e5SOllivier Robert 	 * the fraction, when present. Note that this code relies on the
546c0b746e5SOllivier Robert 	 * file system time for the years and does not use the years of
547c0b746e5SOllivier Robert 	 * the timecode.
548c0b746e5SOllivier Robert 	 */
549c0b746e5SOllivier Robert 	if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
550c0b746e5SOllivier Robert 		pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
551c0b746e5SOllivier Robert 		return (0);
552ea906c41SOllivier Robert 
5539c2daa00SOllivier Robert 	offset.l_uf = 0;
5549c2daa00SOllivier Robert 	DTOLFP(pp->nsec / 1e9, &ltemp);
5559c2daa00SOllivier Robert 	L_ADD(&offset, &ltemp);
5562b15cb3dSCy Schubert 	refclock_process_offset(pp, offset, pp->lastrec, fudge);
557c0b746e5SOllivier Robert 	return (1);
558c0b746e5SOllivier Robert }
559c0b746e5SOllivier Robert 
560ea906c41SOllivier Robert 
5612b15cb3dSCy Schubert int
5622b15cb3dSCy Schubert refclock_process(
5632b15cb3dSCy Schubert 	struct refclockproc *pp		/* refclock structure pointer */
5642b15cb3dSCy Schubert )
5652b15cb3dSCy Schubert {
5662b15cb3dSCy Schubert 	return refclock_process_f(pp, pp->fudgetime1);
5672b15cb3dSCy Schubert }
5682b15cb3dSCy Schubert 
5692b15cb3dSCy Schubert 
570c0b746e5SOllivier Robert /*
571c0b746e5SOllivier Robert  * refclock_sample - process a pile of samples from the clock
572c0b746e5SOllivier Robert  *
573c0b746e5SOllivier Robert  * This routine implements a recursive median filter to suppress spikes
574c0b746e5SOllivier Robert  * in the data, as well as determine a performance statistic. It
575ea906c41SOllivier Robert  * calculates the mean offset and RMS jitter. A time adjustment
576224ba2bdSOllivier Robert  * fudgetime1 can be added to the final offset to compensate for various
577224ba2bdSOllivier Robert  * systematic errors. The routine returns the number of samples
578224ba2bdSOllivier Robert  * processed, which could be zero.
579c0b746e5SOllivier Robert  */
580c0b746e5SOllivier Robert static int
581c0b746e5SOllivier Robert refclock_sample(
5829c2daa00SOllivier Robert 	struct refclockproc *pp		/* refclock structure pointer */
583c0b746e5SOllivier Robert 	)
584c0b746e5SOllivier Robert {
5852b15cb3dSCy Schubert 	size_t	i, j, k, m, n;
586c0b746e5SOllivier Robert 	double	off[MAXSTAGE];
587c0b746e5SOllivier Robert 
588c0b746e5SOllivier Robert 	/*
589c0b746e5SOllivier Robert 	 * Copy the raw offsets and sort into ascending order. Don't do
590c0b746e5SOllivier Robert 	 * anything if the buffer is empty.
591c0b746e5SOllivier Robert 	 */
592c0b746e5SOllivier Robert 	n = 0;
5932d4e511cSCy Schubert 	while (pp->codeproc != pp->coderecv)
5942d4e511cSCy Schubert 		off[n++] = clk_pop_sample(pp);
5959c2daa00SOllivier Robert 	if (n == 0)
5969c2daa00SOllivier Robert 		return (0);
597ea906c41SOllivier Robert 
598c0b746e5SOllivier Robert 	if (n > 1)
5992b15cb3dSCy Schubert 		qsort(off, n, sizeof(off[0]), refclock_cmpl_fp);
600c0b746e5SOllivier Robert 
601c0b746e5SOllivier Robert 	/*
602c0b746e5SOllivier Robert 	 * Reject the furthest from the median of the samples until
603c0b746e5SOllivier Robert 	 * approximately 60 percent of the samples remain.
604a466cc55SCy Schubert 	 *
605a466cc55SCy Schubert 	 * [Bug 3672] The elimination is now based on the proper
606a466cc55SCy Schubert 	 * definition of the median. The true median is not calculated
607a466cc55SCy Schubert 	 * directly, though.
608c0b746e5SOllivier Robert 	 */
609c0b746e5SOllivier Robert 	i = 0; j = n;
610ea906c41SOllivier Robert 	m = n - (n * 4) / 10;
611a466cc55SCy Schubert 	while ((k = j - i) > m) {
612a466cc55SCy Schubert 		k = (k - 1) >> 1;
613a466cc55SCy Schubert 		if ((off[j - 1] - off[j - k - 1]) < (off[i + k] - off[i]))
614c0b746e5SOllivier Robert 			i++;	/* reject low end */
615c0b746e5SOllivier Robert 		else
616c0b746e5SOllivier Robert 			j--;	/* reject high end */
617c0b746e5SOllivier Robert 	}
618c0b746e5SOllivier Robert 
619c0b746e5SOllivier Robert 	/*
620224ba2bdSOllivier Robert 	 * Determine the offset and jitter.
621c0b746e5SOllivier Robert 	 */
622767173ceSCy Schubert 	pp->offset = off[i];
623224ba2bdSOllivier Robert 	pp->jitter = 0;
624767173ceSCy Schubert 	for (k = i + 1; k < j; k++) {
625ea906c41SOllivier Robert 		pp->offset += off[k];
626ea906c41SOllivier Robert 		pp->jitter += SQUARE(off[k] - off[k - 1]);
627ea906c41SOllivier Robert 	}
628ea906c41SOllivier Robert 	pp->offset /= m;
629767173ceSCy Schubert 	m -= (m > 1);	/* only (m-1) terms attribute to jitter! */
630ea906c41SOllivier Robert 	pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision));
6312d4e511cSCy Schubert 
6322d4e511cSCy Schubert 	/*
6332d4e511cSCy Schubert 	 * If the source has a jitter that cannot be estimated, because
6342d4e511cSCy Schubert 	 * it is not statistic jitter, the source will be detected as
6352d4e511cSCy Schubert 	 * falseticker sooner or later.  Enforcing a minimal jitter value
6362d4e511cSCy Schubert 	 * avoids a too low estimation while still detecting higher jitter.
6372d4e511cSCy Schubert 	 *
6382d4e511cSCy Schubert 	 * Note that this changes the refclock samples and ends up in the
6392d4e511cSCy Schubert 	 * clock dispersion, not the clock jitter, despite being called
6402d4e511cSCy Schubert 	 * jitter.  To see the modified values, check the NTP clock variable
6412d4e511cSCy Schubert 	 * "filtdisp", not "jitter".
6422d4e511cSCy Schubert 	 */
6432d4e511cSCy Schubert 	pp->jitter = max(pp->jitter, pp->fudgeminjitter);
6442d4e511cSCy Schubert 
645c0b746e5SOllivier Robert #ifdef DEBUG
646c0b746e5SOllivier Robert 	if (debug)
647c0b746e5SOllivier Robert 		printf(
648224ba2bdSOllivier Robert 		    "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
6492b15cb3dSCy Schubert 		    (int)n, pp->offset, pp->disp, pp->jitter);
650c0b746e5SOllivier Robert #endif
6512b15cb3dSCy Schubert 	return (int)n;
652c0b746e5SOllivier Robert }
653c0b746e5SOllivier Robert 
654c0b746e5SOllivier Robert 
655c0b746e5SOllivier Robert /*
656c0b746e5SOllivier Robert  * refclock_receive - simulate the receive and packet procedures
657c0b746e5SOllivier Robert  *
658c0b746e5SOllivier Robert  * This routine simulates the NTP receive and packet procedures for a
659c0b746e5SOllivier Robert  * reference clock. This provides a mechanism in which the ordinary NTP
660c0b746e5SOllivier Robert  * filter, selection and combining algorithms can be used to suppress
661c0b746e5SOllivier Robert  * misbehaving radios and to mitigate between them when more than one is
662c0b746e5SOllivier Robert  * available for backup.
663c0b746e5SOllivier Robert  */
664c0b746e5SOllivier Robert void
665c0b746e5SOllivier Robert refclock_receive(
666c0b746e5SOllivier Robert 	struct peer *peer	/* peer structure pointer */
667c0b746e5SOllivier Robert 	)
668c0b746e5SOllivier Robert {
669c0b746e5SOllivier Robert 	struct refclockproc *pp;
670c0b746e5SOllivier Robert 
671c0b746e5SOllivier Robert #ifdef DEBUG
672c0b746e5SOllivier Robert 	if (debug)
673c0b746e5SOllivier Robert 		printf("refclock_receive: at %lu %s\n",
6749c2daa00SOllivier Robert 		    current_time, stoa(&peer->srcadr));
675c0b746e5SOllivier Robert #endif
676c0b746e5SOllivier Robert 
677c0b746e5SOllivier Robert 	/*
678c0b746e5SOllivier Robert 	 * Do a little sanity dance and update the peer structure. Groom
679c0b746e5SOllivier Robert 	 * the median filter samples and give the data to the clock
680c0b746e5SOllivier Robert 	 * filter.
681c0b746e5SOllivier Robert 	 */
682c0b746e5SOllivier Robert 	pp = peer->procptr;
6832d4e511cSCy Schubert 	pp->inpoll = FALSE;
684c0b746e5SOllivier Robert 	peer->leap = pp->leap;
685ea906c41SOllivier Robert 	if (peer->leap == LEAP_NOTINSYNC)
686c0b746e5SOllivier Robert 		return;
687ea906c41SOllivier Robert 
688ea906c41SOllivier Robert 	peer->received++;
689ea906c41SOllivier Robert 	peer->timereceived = current_time;
690ea906c41SOllivier Robert 	if (!peer->reach) {
6912b15cb3dSCy Schubert 		report_event(PEVNT_REACH, peer, NULL);
692ea906c41SOllivier Robert 		peer->timereachable = current_time;
693ea906c41SOllivier Robert 	}
6942d4e511cSCy Schubert 	peer->reach = (peer->reach << (peer->reach & 1)) | 1;
6959c2daa00SOllivier Robert 	peer->reftime = pp->lastref;
6962b15cb3dSCy Schubert 	peer->aorg = pp->lastrec;
6972b15cb3dSCy Schubert 	peer->rootdisp = pp->disp;
6982b15cb3dSCy Schubert 	get_systime(&peer->dst);
699c0b746e5SOllivier Robert 	if (!refclock_sample(pp))
700c0b746e5SOllivier Robert 		return;
701ea906c41SOllivier Robert 
702224ba2bdSOllivier Robert 	clock_filter(peer, pp->offset, 0., pp->jitter);
7032b15cb3dSCy Schubert 	if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer !=
7042b15cb3dSCy Schubert 	    NULL) {
7052b15cb3dSCy Schubert 		if (sys_peer->refclktype == REFCLK_ATOM_PPS &&
7062b15cb3dSCy Schubert 		    peer->refclktype != REFCLK_ATOM_PPS)
707c0b746e5SOllivier Robert 			pp->fudgetime1 -= pp->offset * FUDGEFAC;
708224ba2bdSOllivier Robert 	}
709c0b746e5SOllivier Robert }
710c0b746e5SOllivier Robert 
711ea906c41SOllivier Robert 
712c0b746e5SOllivier Robert /*
713c0b746e5SOllivier Robert  * refclock_gtlin - groom next input line and extract timestamp
714c0b746e5SOllivier Robert  *
715c0b746e5SOllivier Robert  * This routine processes the timecode received from the clock and
716ea906c41SOllivier Robert  * strips the parity bit and control characters. It returns the number
717ea906c41SOllivier Robert  * of characters in the line followed by a NULL character ('\0'), which
718ea906c41SOllivier Robert  * is not included in the count. In case of an empty line, the previous
719ea906c41SOllivier Robert  * line is preserved.
720c0b746e5SOllivier Robert  */
721c0b746e5SOllivier Robert int
722c0b746e5SOllivier Robert refclock_gtlin(
723c0b746e5SOllivier Robert 	struct recvbuf *rbufp,	/* receive buffer pointer */
724c0b746e5SOllivier Robert 	char	*lineptr,	/* current line pointer */
725c0b746e5SOllivier Robert 	int	bmax,		/* remaining characters in line */
726c0b746e5SOllivier Robert 	l_fp	*tsptr		/* pointer to timestamp returned */
727c0b746e5SOllivier Robert 	)
728c0b746e5SOllivier Robert {
7292b15cb3dSCy Schubert 	const char *sp, *spend;
7302b15cb3dSCy Schubert 	char	   *dp, *dpend;
7312b15cb3dSCy Schubert 	int         dlen;
732ea906c41SOllivier Robert 
7332b15cb3dSCy Schubert 	if (bmax <= 0)
7342b15cb3dSCy Schubert 		return (0);
7352b15cb3dSCy Schubert 
7362b15cb3dSCy Schubert 	dp    = lineptr;
7372b15cb3dSCy Schubert 	dpend = dp + bmax - 1; /* leave room for NUL pad */
7382b15cb3dSCy Schubert 	sp    = (const char *)rbufp->recv_buffer;
7392b15cb3dSCy Schubert 	spend = sp + rbufp->recv_length;
7402b15cb3dSCy Schubert 
7412b15cb3dSCy Schubert 	while (sp != spend && dp != dpend) {
742c0b746e5SOllivier Robert 		char c;
743c0b746e5SOllivier Robert 
7442b15cb3dSCy Schubert 		c = *sp++ & 0x7f;
745ea906c41SOllivier Robert 		if (c >= 0x20 && c < 0x7f)
746ea906c41SOllivier Robert 			*dp++ = c;
747ea906c41SOllivier Robert 	}
7482b15cb3dSCy Schubert 	/* Get length of data written to the destination buffer. If
7492b15cb3dSCy Schubert 	 * zero, do *not* place a NUL byte to preserve the previous
7502b15cb3dSCy Schubert 	 * buffer content.
7512b15cb3dSCy Schubert 	 */
7522b15cb3dSCy Schubert 	dlen = dp - lineptr;
7532b15cb3dSCy Schubert 	if (dlen)
754ea906c41SOllivier Robert 	    *dp  = '\0';
7552b15cb3dSCy Schubert 	*tsptr = rbufp->recv_time;
7562b15cb3dSCy Schubert 	DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n",
7572b15cb3dSCy Schubert 		    rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen,
7582b15cb3dSCy Schubert 		    (dlen != 0)
7592b15cb3dSCy Schubert 			? lineptr
7602b15cb3dSCy Schubert 			: ""));
7612b15cb3dSCy Schubert 	return (dlen);
762ea906c41SOllivier Robert }
763ea906c41SOllivier Robert 
764ea906c41SOllivier Robert 
765ea906c41SOllivier Robert /*
766ea906c41SOllivier Robert  * refclock_gtraw - get next line/chunk of data
767ea906c41SOllivier Robert  *
768ea906c41SOllivier Robert  * This routine returns the raw data received from the clock in both
769ea906c41SOllivier Robert  * canonical or raw modes. The terminal interface routines map CR to LF.
770ea906c41SOllivier Robert  * In canonical mode this results in two lines, one containing data
771ea906c41SOllivier Robert  * followed by LF and another containing only LF. In raw mode the
772ea906c41SOllivier Robert  * interface routines can deliver arbitraty chunks of data from one
773ea906c41SOllivier Robert  * character to a maximum specified by the calling routine. In either
774ea906c41SOllivier Robert  * mode the routine returns the number of characters in the line
775ea906c41SOllivier Robert  * followed by a NULL character ('\0'), which is not included in the
776ea906c41SOllivier Robert  * count.
777ea906c41SOllivier Robert  *
7782b15cb3dSCy Schubert  * *tsptr receives a copy of the buffer timestamp.
779ea906c41SOllivier Robert  */
780ea906c41SOllivier Robert int
781ea906c41SOllivier Robert refclock_gtraw(
782ea906c41SOllivier Robert 	struct recvbuf *rbufp,	/* receive buffer pointer */
783ea906c41SOllivier Robert 	char	*lineptr,	/* current line pointer */
784ea906c41SOllivier Robert 	int	bmax,		/* remaining characters in line */
785ea906c41SOllivier Robert 	l_fp	*tsptr		/* pointer to timestamp returned */
786ea906c41SOllivier Robert 	)
787ea906c41SOllivier Robert {
7882b15cb3dSCy Schubert 	if (bmax <= 0)
7892b15cb3dSCy Schubert 		return (0);
7902b15cb3dSCy Schubert 	bmax -= 1; /* leave room for trailing NUL */
7912b15cb3dSCy Schubert 	if (bmax > rbufp->recv_length)
7922b15cb3dSCy Schubert 		bmax = rbufp->recv_length;
7932b15cb3dSCy Schubert 	memcpy(lineptr, rbufp->recv_buffer, bmax);
7942b15cb3dSCy Schubert 	lineptr[bmax] = '\0';
795ea906c41SOllivier Robert 
7962b15cb3dSCy Schubert 	*tsptr = rbufp->recv_time;
7972b15cb3dSCy Schubert 	DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n",
7982b15cb3dSCy Schubert 		    rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax,
7992b15cb3dSCy Schubert 		    lineptr));
8002b15cb3dSCy Schubert 	return (bmax);
801c0b746e5SOllivier Robert }
802c0b746e5SOllivier Robert 
803a466cc55SCy Schubert /*
804a466cc55SCy Schubert  * refclock_fdwrite()
805a466cc55SCy Schubert  *
806a466cc55SCy Schubert  * Write data to a clock device. Does the necessary result checks and
807a466cc55SCy Schubert  * logging, and encapsulates OS dependencies.
808a466cc55SCy Schubert  */
809a466cc55SCy Schubert #ifdef SYS_WINNT
810a466cc55SCy Schubert extern int async_write(int fd, const void * buf, unsigned int len);
811a466cc55SCy Schubert #endif
812a466cc55SCy Schubert 
813a466cc55SCy Schubert size_t
814a466cc55SCy Schubert refclock_fdwrite(
815a466cc55SCy Schubert 	const struct peer *	peer,
816a466cc55SCy Schubert 	int			fd,
817a466cc55SCy Schubert 	const void *		buf,
818a466cc55SCy Schubert 	size_t			len,
819a466cc55SCy Schubert 	const char *		what
820a466cc55SCy Schubert 	)
821a466cc55SCy Schubert {
822a466cc55SCy Schubert 	size_t	nret, nout;
823a466cc55SCy Schubert 	int	nerr;
824a466cc55SCy Schubert 
825a466cc55SCy Schubert 	nout = (INT_MAX > len) ? len : INT_MAX;
826a466cc55SCy Schubert #   ifdef SYS_WINNT
827a466cc55SCy Schubert 	nret = (size_t)async_write(fd, buf, (unsigned int)nout);
828a466cc55SCy Schubert #   else
829a466cc55SCy Schubert 	nret = (size_t)write(fd, buf, nout);
830a466cc55SCy Schubert #   endif
831a466cc55SCy Schubert 	if (NULL != what) {
832a466cc55SCy Schubert 		if (nret == FDWRITE_ERROR) {
833a466cc55SCy Schubert 			nerr = errno;
834a466cc55SCy Schubert 			msyslog(LOG_INFO,
835a466cc55SCy Schubert 				"%s: write %s failed, fd=%d, %m",
836a466cc55SCy Schubert 				refnumtoa(&peer->srcadr), what,
837a466cc55SCy Schubert 				fd);
838a466cc55SCy Schubert 			errno = nerr;
839a466cc55SCy Schubert 		} else if (nret != len) {
840a466cc55SCy Schubert 			nerr = errno;
841a466cc55SCy Schubert 			msyslog(LOG_NOTICE,
842*f5f40dd6SCy Schubert 				"%s: %s shortened, fd=%d, wrote %u of %u bytes",
843a466cc55SCy Schubert 				refnumtoa(&peer->srcadr), what,
844*f5f40dd6SCy Schubert 				fd, (u_int)nret, (u_int)len);
845a466cc55SCy Schubert 			errno = nerr;
846a466cc55SCy Schubert 		}
847a466cc55SCy Schubert 	}
848a466cc55SCy Schubert 	return nret;
849a466cc55SCy Schubert }
850a466cc55SCy Schubert 
851a466cc55SCy Schubert size_t
852a466cc55SCy Schubert refclock_write(
853a466cc55SCy Schubert 	const struct peer *	peer,
854a466cc55SCy Schubert 	const void *		buf,
855a466cc55SCy Schubert 	size_t			len,
856a466cc55SCy Schubert 	const char *		what
857a466cc55SCy Schubert 	)
858a466cc55SCy Schubert {
859a466cc55SCy Schubert 	if ( ! (peer && peer->procptr)) {
860a466cc55SCy Schubert 		if (NULL != what)
861a466cc55SCy Schubert 			msyslog(LOG_INFO,
862a466cc55SCy Schubert 				"%s: write %s failed, invalid clock peer",
863a466cc55SCy Schubert 				refnumtoa(&peer->srcadr), what);
864a466cc55SCy Schubert 		errno = EINVAL;
865a466cc55SCy Schubert 		return FDWRITE_ERROR;
866a466cc55SCy Schubert 	}
867a466cc55SCy Schubert 	return refclock_fdwrite(peer, peer->procptr->io.fd,
868a466cc55SCy Schubert 				buf, len, what);
869a466cc55SCy Schubert }
8702b15cb3dSCy Schubert 
871c0b746e5SOllivier Robert /*
8722b15cb3dSCy Schubert  * indicate_refclock_packet()
8732b15cb3dSCy Schubert  *
8742b15cb3dSCy Schubert  * Passes a fragment of refclock input read from the device to the
8752b15cb3dSCy Schubert  * driver direct input routine, which may consume it (batch it for
8762b15cb3dSCy Schubert  * queuing once a logical unit is assembled).  If it is not so
8772b15cb3dSCy Schubert  * consumed, queue it for the driver's receive entrypoint.
8782b15cb3dSCy Schubert  *
8792b15cb3dSCy Schubert  * The return value is TRUE if the data has been consumed as a fragment
8802b15cb3dSCy Schubert  * and should not be counted as a received packet.
881c0b746e5SOllivier Robert  */
8822b15cb3dSCy Schubert int
8832b15cb3dSCy Schubert indicate_refclock_packet(
8842b15cb3dSCy Schubert 	struct refclockio *	rio,
8852b15cb3dSCy Schubert 	struct recvbuf *	rb
8862b15cb3dSCy Schubert 	)
8872b15cb3dSCy Schubert {
8882b15cb3dSCy Schubert 	/* Does this refclock use direct input routine? */
8892b15cb3dSCy Schubert 	if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) {
8902b15cb3dSCy Schubert 		/*
8912b15cb3dSCy Schubert 		 * data was consumed - nothing to pass up
8922b15cb3dSCy Schubert 		 * into block input machine
8932b15cb3dSCy Schubert 		 */
8942b15cb3dSCy Schubert 		freerecvbuf(rb);
8952b15cb3dSCy Schubert 
8962b15cb3dSCy Schubert 		return TRUE;
897c0b746e5SOllivier Robert 	}
8982b15cb3dSCy Schubert 	add_full_recv_buffer(rb);
8992b15cb3dSCy Schubert 
9002b15cb3dSCy Schubert 	return FALSE;
9012b15cb3dSCy Schubert }
9022b15cb3dSCy Schubert 
9032b15cb3dSCy Schubert 
9042b15cb3dSCy Schubert /*
9052b15cb3dSCy Schubert  * process_refclock_packet()
9062b15cb3dSCy Schubert  *
9072b15cb3dSCy Schubert  * Used for deferred processing of 'io_input' on systems where threading
9082b15cb3dSCy Schubert  * is used (notably Windows). This is acting as a trampoline to make the
9092b15cb3dSCy Schubert  * real calls to the refclock functions.
9102b15cb3dSCy Schubert  */
9112b15cb3dSCy Schubert #ifdef HAVE_IO_COMPLETION_PORT
9122b15cb3dSCy Schubert void
9132b15cb3dSCy Schubert process_refclock_packet(
9142b15cb3dSCy Schubert 	struct recvbuf * rb
9152b15cb3dSCy Schubert 	)
9162b15cb3dSCy Schubert {
9172b15cb3dSCy Schubert 	struct refclockio * rio;
9182b15cb3dSCy Schubert 
9192b15cb3dSCy Schubert 	/* get the refclockio structure from the receive buffer */
9202b15cb3dSCy Schubert 	rio  = &rb->recv_peer->procptr->io;
9212b15cb3dSCy Schubert 
9222b15cb3dSCy Schubert 	/* call 'clock_recv' if either there is no input function or the
9232b15cb3dSCy Schubert 	 * raw input function tells us to feed the packet to the
9242b15cb3dSCy Schubert 	 * receiver.
9252b15cb3dSCy Schubert 	 */
9262b15cb3dSCy Schubert 	if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) {
9272b15cb3dSCy Schubert 		rio->recvcount++;
9282b15cb3dSCy Schubert 		packets_received++;
9292b15cb3dSCy Schubert 		handler_pkts++;
9302b15cb3dSCy Schubert 		(*rio->clock_recv)(rb);
9312b15cb3dSCy Schubert 	}
9322b15cb3dSCy Schubert }
9332b15cb3dSCy Schubert #endif	/* HAVE_IO_COMPLETION_PORT */
934c0b746e5SOllivier Robert 
935ea906c41SOllivier Robert 
936c0b746e5SOllivier Robert /*
937c0b746e5SOllivier Robert  * The following code does not apply to WINNT & VMS ...
938c0b746e5SOllivier Robert  */
9392b15cb3dSCy Schubert #if !defined(SYS_VXWORKS) && !defined(SYS_WINNT)
940c0b746e5SOllivier Robert #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
941c0b746e5SOllivier Robert 
942c0b746e5SOllivier Robert /*
943c0b746e5SOllivier Robert  * refclock_open - open serial port for reference clock
944c0b746e5SOllivier Robert  *
945c0b746e5SOllivier Robert  * This routine opens a serial port for I/O and sets default options. It
9462b15cb3dSCy Schubert  * returns the file descriptor if successful, or logs an error and
9472b15cb3dSCy Schubert  * returns -1.
948c0b746e5SOllivier Robert  */
949c0b746e5SOllivier Robert int
950c0b746e5SOllivier Robert refclock_open(
951a466cc55SCy Schubert 	const sockaddr_u *srcadr,
9523311ff84SXin LI  	const char	*dev,	/* device name pointer */
953ea906c41SOllivier Robert 	u_int		speed,	/* serial port speed (code) */
954ea906c41SOllivier Robert 	u_int		lflags	/* line discipline flags */
955c0b746e5SOllivier Robert 	)
956c0b746e5SOllivier Robert {
957a466cc55SCy Schubert 	const char *cdev;
958ea906c41SOllivier Robert 	int	fd;
959224ba2bdSOllivier Robert 	int	omode;
9602b15cb3dSCy Schubert #ifdef O_NONBLOCK
9612b15cb3dSCy Schubert 	char	trash[128];	/* litter bin for old input data */
9622b15cb3dSCy Schubert #endif
963c0b746e5SOllivier Robert 
964c0b746e5SOllivier Robert 	/*
965c0b746e5SOllivier Robert 	 * Open serial port and set default options
966c0b746e5SOllivier Robert 	 */
967224ba2bdSOllivier Robert 	omode = O_RDWR;
968c0b746e5SOllivier Robert #ifdef O_NONBLOCK
969224ba2bdSOllivier Robert 	omode |= O_NONBLOCK;
970224ba2bdSOllivier Robert #endif
971224ba2bdSOllivier Robert #ifdef O_NOCTTY
972224ba2bdSOllivier Robert 	omode |= O_NOCTTY;
973224ba2bdSOllivier Robert #endif
974224ba2bdSOllivier Robert 
975a466cc55SCy Schubert 	if (NULL != (cdev = clockdev_lookup(srcadr, 0)))
976a466cc55SCy Schubert 		dev = cdev;
977a466cc55SCy Schubert 
978224ba2bdSOllivier Robert 	fd = open(dev, omode, 0777);
9792b15cb3dSCy Schubert 	/* refclock_open() long returned 0 on failure, avoid it. */
9802b15cb3dSCy Schubert 	if (0 == fd) {
9812b15cb3dSCy Schubert 		fd = dup(0);
9822b15cb3dSCy Schubert 		SAVE_ERRNO(
9832b15cb3dSCy Schubert 			close(0);
9842b15cb3dSCy Schubert 		)
9852b15cb3dSCy Schubert 	}
986224ba2bdSOllivier Robert 	if (fd < 0) {
9872b15cb3dSCy Schubert 		SAVE_ERRNO(
988ea906c41SOllivier Robert 			msyslog(LOG_ERR, "refclock_open %s: %m", dev);
9892b15cb3dSCy Schubert 		)
9902b15cb3dSCy Schubert 		return -1;
991c0b746e5SOllivier Robert 	}
992ea906c41SOllivier Robert 	if (!refclock_setup(fd, speed, lflags)) {
993ea906c41SOllivier Robert 		close(fd);
9942b15cb3dSCy Schubert 		return -1;
995ea906c41SOllivier Robert 	}
996ea906c41SOllivier Robert 	if (!refclock_ioctl(fd, lflags)) {
997ea906c41SOllivier Robert 		close(fd);
9982b15cb3dSCy Schubert 		return -1;
999ea906c41SOllivier Robert 	}
1000a466cc55SCy Schubert 	msyslog(LOG_NOTICE, "%s serial %s open at %d bps",
1001a466cc55SCy Schubert 		refnumtoa(srcadr), dev, symBaud2numBaud(speed));
1002a466cc55SCy Schubert 
10032b15cb3dSCy Schubert #ifdef O_NONBLOCK
10042b15cb3dSCy Schubert 	/*
10052b15cb3dSCy Schubert 	 * We want to make sure there is no pending trash in the input
10062b15cb3dSCy Schubert 	 * buffer. Since we have non-blocking IO available, this is a
10072b15cb3dSCy Schubert 	 * good moment to read and dump all available outdated stuff
10082b15cb3dSCy Schubert 	 * that might have become toxic for the driver.
10092b15cb3dSCy Schubert 	 */
10102b15cb3dSCy Schubert 	while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR)
10112b15cb3dSCy Schubert 		/*NOP*/;
10122b15cb3dSCy Schubert #endif
10132b15cb3dSCy Schubert 	return fd;
1014ea906c41SOllivier Robert }
1015c0b746e5SOllivier Robert 
10162b15cb3dSCy Schubert 
1017c0b746e5SOllivier Robert /*
1018ea906c41SOllivier Robert  * refclock_setup - initialize terminal interface structure
1019224ba2bdSOllivier Robert  */
1020ea906c41SOllivier Robert int
1021ea906c41SOllivier Robert refclock_setup(
1022ea906c41SOllivier Robert 	int	fd,		/* file descriptor */
1023ea906c41SOllivier Robert 	u_int	speed,		/* serial port speed (code) */
1024ea906c41SOllivier Robert 	u_int	lflags		/* line discipline flags */
1025ea906c41SOllivier Robert 	)
1026ea906c41SOllivier Robert {
1027ea906c41SOllivier Robert 	int	i;
1028ea906c41SOllivier Robert 	TTY	ttyb, *ttyp;
1029224ba2bdSOllivier Robert 
1030224ba2bdSOllivier Robert 	/*
1031ea906c41SOllivier Robert 	 * By default, the serial line port is initialized in canonical
1032ea906c41SOllivier Robert 	 * (line-oriented) mode at specified line speed, 8 bits and no
1033ea906c41SOllivier Robert 	 * parity. LF ends the line and CR is mapped to LF. The break,
1034ea906c41SOllivier Robert 	 * erase and kill functions are disabled. There is a different
1035ea906c41SOllivier Robert 	 * section for each terminal interface, as selected at compile
1036ea906c41SOllivier Robert 	 * time. The flag bits can be used to set raw mode and echo.
1037c0b746e5SOllivier Robert 	 */
1038c0b746e5SOllivier Robert 	ttyp = &ttyb;
1039c0b746e5SOllivier Robert #ifdef HAVE_TERMIOS
1040ea906c41SOllivier Robert 
1041c0b746e5SOllivier Robert 	/*
1042c0b746e5SOllivier Robert 	 * POSIX serial line parameters (termios interface)
1043c0b746e5SOllivier Robert 	 */
1044c0b746e5SOllivier Robert 	if (tcgetattr(fd, ttyp) < 0) {
10452b15cb3dSCy Schubert 		SAVE_ERRNO(
1046c0b746e5SOllivier Robert 			msyslog(LOG_ERR,
10472b15cb3dSCy Schubert 				"refclock_setup fd %d tcgetattr: %m",
10482b15cb3dSCy Schubert 				fd);
10492b15cb3dSCy Schubert 		)
10502b15cb3dSCy Schubert 		return FALSE;
1051c0b746e5SOllivier Robert 	}
1052c0b746e5SOllivier Robert 
1053c0b746e5SOllivier Robert 	/*
1054c0b746e5SOllivier Robert 	 * Set canonical mode and local connection; set specified speed,
1055c0b746e5SOllivier Robert 	 * 8 bits and no parity; map CR to NL; ignore break.
1056c0b746e5SOllivier Robert 	 */
1057ea906c41SOllivier Robert 	if (speed) {
1058ea906c41SOllivier Robert 		u_int	ltemp = 0;
1059ea906c41SOllivier Robert 
1060c0b746e5SOllivier Robert 		ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
1061c0b746e5SOllivier Robert 		ttyp->c_oflag = 0;
1062c0b746e5SOllivier Robert 		ttyp->c_cflag = CS8 | CLOCAL | CREAD;
1063ea906c41SOllivier Robert 		if (lflags & LDISC_7O1) {
1064ea906c41SOllivier Robert 			/* HP Z3801A needs 7-bit, odd parity */
1065ea906c41SOllivier Robert 			ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
1066ea906c41SOllivier Robert 		}
1067ea906c41SOllivier Robert 		cfsetispeed(&ttyb, speed);
1068ea906c41SOllivier Robert 		cfsetospeed(&ttyb, speed);
1069c0b746e5SOllivier Robert 		for (i = 0; i < NCCS; ++i)
1070c0b746e5SOllivier Robert 			ttyp->c_cc[i] = '\0';
1071ea906c41SOllivier Robert 
1072ea906c41SOllivier Robert #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
1073ea906c41SOllivier Robert 
1074ea906c41SOllivier Robert 		/*
1075ea906c41SOllivier Robert 		 * If we have modem control, check to see if modem leads
1076ea906c41SOllivier Robert 		 * are active; if so, set remote connection. This is
1077ea906c41SOllivier Robert 		 * necessary for the kernel pps mods to work.
1078ea906c41SOllivier Robert 		 */
1079ea906c41SOllivier Robert 		if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
1080ea906c41SOllivier Robert 			msyslog(LOG_ERR,
1081ea906c41SOllivier Robert 			    "refclock_setup fd %d TIOCMGET: %m", fd);
1082ea906c41SOllivier Robert #ifdef DEBUG
1083ea906c41SOllivier Robert 		if (debug)
1084ea906c41SOllivier Robert 			printf("refclock_setup fd %d modem status: 0x%x\n",
1085ea906c41SOllivier Robert 			    fd, ltemp);
1086ea906c41SOllivier Robert #endif
1087ea906c41SOllivier Robert 		if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE)
1088ea906c41SOllivier Robert 			ttyp->c_cflag &= ~CLOCAL;
1089ea906c41SOllivier Robert #endif /* TIOCMGET */
1090c0b746e5SOllivier Robert 	}
1091c0b746e5SOllivier Robert 
1092c0b746e5SOllivier Robert 	/*
1093ea906c41SOllivier Robert 	 * Set raw and echo modes. These can be changed on-fly.
1094c0b746e5SOllivier Robert 	 */
1095ea906c41SOllivier Robert 	ttyp->c_lflag = ICANON;
1096ea906c41SOllivier Robert 	if (lflags & LDISC_RAW) {
1097c0b746e5SOllivier Robert 		ttyp->c_lflag = 0;
1098ea906c41SOllivier Robert 		ttyp->c_iflag = 0;
1099c0b746e5SOllivier Robert 		ttyp->c_cc[VMIN] = 1;
1100c0b746e5SOllivier Robert 	}
1101ea906c41SOllivier Robert 	if (lflags & LDISC_ECHO)
1102ea906c41SOllivier Robert 		ttyp->c_lflag |= ECHO;
1103c0b746e5SOllivier Robert 	if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
11042b15cb3dSCy Schubert 		SAVE_ERRNO(
1105c0b746e5SOllivier Robert 			msyslog(LOG_ERR,
11062b15cb3dSCy Schubert 				"refclock_setup fd %d TCSANOW: %m",
11072b15cb3dSCy Schubert 				fd);
11082b15cb3dSCy Schubert 		)
11092b15cb3dSCy Schubert 		return FALSE;
1110c0b746e5SOllivier Robert 	}
11112b15cb3dSCy Schubert 
11122b15cb3dSCy Schubert 	/*
11132b15cb3dSCy Schubert 	 * flush input and output buffers to discard any outdated stuff
11142b15cb3dSCy Schubert 	 * that might have become toxic for the driver. Failing to do so
11152b15cb3dSCy Schubert 	 * is logged, but we keep our fingers crossed otherwise.
11162b15cb3dSCy Schubert 	 */
11172b15cb3dSCy Schubert 	if (tcflush(fd, TCIOFLUSH) < 0)
11182b15cb3dSCy Schubert 		msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m",
11192b15cb3dSCy Schubert 			fd);
1120c0b746e5SOllivier Robert #endif /* HAVE_TERMIOS */
1121c0b746e5SOllivier Robert 
1122c0b746e5SOllivier Robert #ifdef HAVE_SYSV_TTYS
1123c0b746e5SOllivier Robert 
1124c0b746e5SOllivier Robert 	/*
1125c0b746e5SOllivier Robert 	 * System V serial line parameters (termio interface)
1126c0b746e5SOllivier Robert 	 *
1127c0b746e5SOllivier Robert 	 */
1128c0b746e5SOllivier Robert 	if (ioctl(fd, TCGETA, ttyp) < 0) {
11292b15cb3dSCy Schubert 		SAVE_ERRNO(
1130c0b746e5SOllivier Robert 			msyslog(LOG_ERR,
11312b15cb3dSCy Schubert 				"refclock_setup fd %d TCGETA: %m",
11322b15cb3dSCy Schubert 				fd);
11332b15cb3dSCy Schubert 		)
11342b15cb3dSCy Schubert 		return FALSE;
1135c0b746e5SOllivier Robert 	}
1136c0b746e5SOllivier Robert 
1137c0b746e5SOllivier Robert 	/*
1138c0b746e5SOllivier Robert 	 * Set canonical mode and local connection; set specified speed,
1139c0b746e5SOllivier Robert 	 * 8 bits and no parity; map CR to NL; ignore break.
1140c0b746e5SOllivier Robert 	 */
1141ea906c41SOllivier Robert 	if (speed) {
1142ea906c41SOllivier Robert 		u_int	ltemp = 0;
1143ea906c41SOllivier Robert 
1144c0b746e5SOllivier Robert 		ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
1145c0b746e5SOllivier Robert 		ttyp->c_oflag = 0;
1146c0b746e5SOllivier Robert 		ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
1147ea906c41SOllivier Robert 		for (i = 0; i < NCCS; ++i)
1148ea906c41SOllivier Robert 			ttyp->c_cc[i] = '\0';
1149ea906c41SOllivier Robert 
1150ea906c41SOllivier Robert #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
1151c0b746e5SOllivier Robert 
1152c0b746e5SOllivier Robert 		/*
1153ea906c41SOllivier Robert 		 * If we have modem control, check to see if modem leads
1154ea906c41SOllivier Robert 		 * are active; if so, set remote connection. This is
1155ea906c41SOllivier Robert 		 * necessary for the kernel pps mods to work.
1156c0b746e5SOllivier Robert 		 */
1157c0b746e5SOllivier Robert 		if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
1158c0b746e5SOllivier Robert 			msyslog(LOG_ERR,
1159ea906c41SOllivier Robert 			    "refclock_setup fd %d TIOCMGET: %m", fd);
1160c0b746e5SOllivier Robert #ifdef DEBUG
1161c0b746e5SOllivier Robert 		if (debug)
1162ea906c41SOllivier Robert 			printf("refclock_setup fd %d modem status: %x\n",
1163c0b746e5SOllivier Robert 			    fd, ltemp);
1164c0b746e5SOllivier Robert #endif
1165c0b746e5SOllivier Robert 		if (ltemp & TIOCM_DSR)
1166c0b746e5SOllivier Robert 			ttyp->c_cflag &= ~CLOCAL;
1167c0b746e5SOllivier Robert #endif /* TIOCMGET */
1168ea906c41SOllivier Robert 	}
1169ea906c41SOllivier Robert 
1170ea906c41SOllivier Robert 	/*
1171ea906c41SOllivier Robert 	 * Set raw and echo modes. These can be changed on-fly.
1172ea906c41SOllivier Robert 	 */
1173ea906c41SOllivier Robert 	ttyp->c_lflag = ICANON;
1174ea906c41SOllivier Robert 	if (lflags & LDISC_RAW) {
1175ea906c41SOllivier Robert 		ttyp->c_lflag = 0;
1176ea906c41SOllivier Robert 		ttyp->c_iflag = 0;
1177ea906c41SOllivier Robert 		ttyp->c_cc[VMIN] = 1;
1178ea906c41SOllivier Robert 	}
1179c0b746e5SOllivier Robert 	if (ioctl(fd, TCSETA, ttyp) < 0) {
11802b15cb3dSCy Schubert 		SAVE_ERRNO(
1181c0b746e5SOllivier Robert 			msyslog(LOG_ERR,
1182ea906c41SOllivier Robert 				"refclock_setup fd %d TCSETA: %m", fd);
11832b15cb3dSCy Schubert 		)
11842b15cb3dSCy Schubert 		return FALSE;
1185c0b746e5SOllivier Robert 	}
1186c0b746e5SOllivier Robert #endif /* HAVE_SYSV_TTYS */
1187c0b746e5SOllivier Robert 
1188c0b746e5SOllivier Robert #ifdef HAVE_BSD_TTYS
1189c0b746e5SOllivier Robert 
1190c0b746e5SOllivier Robert 	/*
1191c0b746e5SOllivier Robert 	 * 4.3bsd serial line parameters (sgttyb interface)
1192c0b746e5SOllivier Robert 	 */
1193c0b746e5SOllivier Robert 	if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
11942b15cb3dSCy Schubert 		SAVE_ERRNO(
1195c0b746e5SOllivier Robert 			msyslog(LOG_ERR,
11962b15cb3dSCy Schubert 				"refclock_setup fd %d TIOCGETP: %m",
11972b15cb3dSCy Schubert 				fd);
11982b15cb3dSCy Schubert 		)
11992b15cb3dSCy Schubert 		return FALSE;
1200c0b746e5SOllivier Robert 	}
1201ea906c41SOllivier Robert 	if (speed)
1202c0b746e5SOllivier Robert 		ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
1203c0b746e5SOllivier Robert 	ttyp->sg_flags = EVENP | ODDP | CRMOD;
1204c0b746e5SOllivier Robert 	if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
12052b15cb3dSCy Schubert 		SAVE_ERRNO(
12062b15cb3dSCy Schubert 			msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m");
12072b15cb3dSCy Schubert 		)
12082b15cb3dSCy Schubert 		return FALSE;
1209c0b746e5SOllivier Robert 	}
1210c0b746e5SOllivier Robert #endif /* HAVE_BSD_TTYS */
1211ea906c41SOllivier Robert 	return(1);
1212c0b746e5SOllivier Robert }
1213c0b746e5SOllivier Robert #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
1214c0b746e5SOllivier Robert 
1215ea906c41SOllivier Robert 
1216c0b746e5SOllivier Robert /*
1217c0b746e5SOllivier Robert  * refclock_ioctl - set serial port control functions
1218c0b746e5SOllivier Robert  *
1219c0b746e5SOllivier Robert  * This routine attempts to hide the internal, system-specific details
1220c0b746e5SOllivier Robert  * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
1221c0b746e5SOllivier Robert  * (sgtty) interfaces with varying degrees of success. The routine sets
12222b15cb3dSCy Schubert  * up optional features such as tty_clk. The routine returns TRUE if
12232b15cb3dSCy Schubert  * successful.
1224c0b746e5SOllivier Robert  */
1225c0b746e5SOllivier Robert int
1226c0b746e5SOllivier Robert refclock_ioctl(
1227c0b746e5SOllivier Robert 	int	fd, 		/* file descriptor */
1228ea906c41SOllivier Robert 	u_int	lflags		/* line discipline flags */
1229c0b746e5SOllivier Robert 	)
1230c0b746e5SOllivier Robert {
1231ea906c41SOllivier Robert 	/*
12322b15cb3dSCy Schubert 	 * simply return TRUE if no UNIX line discipline is supported
1233ea906c41SOllivier Robert 	 */
12342b15cb3dSCy Schubert 	DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags));
1235c0b746e5SOllivier Robert 
12362b15cb3dSCy Schubert 	return TRUE;
1237ea906c41SOllivier Robert }
12382b15cb3dSCy Schubert #endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */
1239c0b746e5SOllivier Robert 
1240ea906c41SOllivier Robert 
1241c0b746e5SOllivier Robert /*
1242c0b746e5SOllivier Robert  * refclock_control - set and/or return clock values
1243c0b746e5SOllivier Robert  *
1244c0b746e5SOllivier Robert  * This routine is used mainly for debugging. It returns designated
1245c0b746e5SOllivier Robert  * values from the interface structure that can be displayed using
1246c0b746e5SOllivier Robert  * ntpdc and the clockstat command. It can also be used to initialize
1247c0b746e5SOllivier Robert  * configuration variables, such as fudgetimes, fudgevalues, reference
1248c0b746e5SOllivier Robert  * ID and stratum.
1249c0b746e5SOllivier Robert  */
1250c0b746e5SOllivier Robert void
1251c0b746e5SOllivier Robert refclock_control(
12522b15cb3dSCy Schubert 	sockaddr_u *srcadr,
12532b15cb3dSCy Schubert 	const struct refclockstat *in,
1254c0b746e5SOllivier Robert 	struct refclockstat *out
1255c0b746e5SOllivier Robert 	)
1256c0b746e5SOllivier Robert {
1257c0b746e5SOllivier Robert 	struct peer *peer;
1258c0b746e5SOllivier Robert 	struct refclockproc *pp;
1259c0b746e5SOllivier Robert 	u_char clktype;
1260c0b746e5SOllivier Robert 	int unit;
1261c0b746e5SOllivier Robert 
1262c0b746e5SOllivier Robert 	/*
1263c0b746e5SOllivier Robert 	 * Check for valid address and running peer
1264c0b746e5SOllivier Robert 	 */
1265c0b746e5SOllivier Robert 	if (!ISREFCLOCKADR(srcadr))
1266c0b746e5SOllivier Robert 		return;
1267ea906c41SOllivier Robert 
1268c0b746e5SOllivier Robert 	clktype = (u_char)REFCLOCKTYPE(srcadr);
1269c0b746e5SOllivier Robert 	unit = REFCLOCKUNIT(srcadr);
12702b15cb3dSCy Schubert 
127109100258SXin LI 	peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL);
12722b15cb3dSCy Schubert 
12732b15cb3dSCy Schubert 	if (NULL == peer)
1274c0b746e5SOllivier Robert 		return;
1275ea906c41SOllivier Robert 
12769034852cSGleb Smirnoff 	INSIST(peer->procptr != NULL);
1277c0b746e5SOllivier Robert 	pp = peer->procptr;
1278c0b746e5SOllivier Robert 
1279c0b746e5SOllivier Robert 	/*
1280c0b746e5SOllivier Robert 	 * Initialize requested data
1281c0b746e5SOllivier Robert 	 */
12822b15cb3dSCy Schubert 	if (in != NULL) {
1283c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVETIME1)
1284c0b746e5SOllivier Robert 			pp->fudgetime1 = in->fudgetime1;
1285c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVETIME2)
1286c0b746e5SOllivier Robert 			pp->fudgetime2 = in->fudgetime2;
1287c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVEVAL1)
1288ea906c41SOllivier Robert 			peer->stratum = pp->stratum = (u_char)in->fudgeval1;
1289c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVEVAL2)
1290ea906c41SOllivier Robert 			peer->refid = pp->refid = in->fudgeval2;
1291c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVEFLAG1) {
1292c0b746e5SOllivier Robert 			pp->sloppyclockflag &= ~CLK_FLAG1;
1293c0b746e5SOllivier Robert 			pp->sloppyclockflag |= in->flags & CLK_FLAG1;
1294c0b746e5SOllivier Robert 		}
1295c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVEFLAG2) {
1296c0b746e5SOllivier Robert 			pp->sloppyclockflag &= ~CLK_FLAG2;
1297c0b746e5SOllivier Robert 			pp->sloppyclockflag |= in->flags & CLK_FLAG2;
1298c0b746e5SOllivier Robert 		}
1299c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVEFLAG3) {
1300c0b746e5SOllivier Robert 			pp->sloppyclockflag &= ~CLK_FLAG3;
1301c0b746e5SOllivier Robert 			pp->sloppyclockflag |= in->flags & CLK_FLAG3;
1302c0b746e5SOllivier Robert 		}
1303c0b746e5SOllivier Robert 		if (in->haveflags & CLK_HAVEFLAG4) {
1304c0b746e5SOllivier Robert 			pp->sloppyclockflag &= ~CLK_FLAG4;
1305c0b746e5SOllivier Robert 			pp->sloppyclockflag |= in->flags & CLK_FLAG4;
1306c0b746e5SOllivier Robert 		}
13072d4e511cSCy Schubert 		if (in->haveflags & CLK_HAVEMINJIT)
13082d4e511cSCy Schubert 			pp->fudgeminjitter = in->fudgeminjitter;
1309c0b746e5SOllivier Robert 	}
1310c0b746e5SOllivier Robert 
1311c0b746e5SOllivier Robert 	/*
1312c0b746e5SOllivier Robert 	 * Readback requested data
1313c0b746e5SOllivier Robert 	 */
13142b15cb3dSCy Schubert 	if (out != NULL) {
13159c2daa00SOllivier Robert 		out->fudgeval1 = pp->stratum;
1316c0b746e5SOllivier Robert 		out->fudgeval2 = pp->refid;
13172b15cb3dSCy Schubert 		out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
13182b15cb3dSCy Schubert 		out->fudgetime1 = pp->fudgetime1;
13192b15cb3dSCy Schubert 		if (0.0 != out->fudgetime1)
13202b15cb3dSCy Schubert 			out->haveflags |= CLK_HAVETIME1;
13212b15cb3dSCy Schubert 		out->fudgetime2 = pp->fudgetime2;
13222b15cb3dSCy Schubert 		if (0.0 != out->fudgetime2)
13232b15cb3dSCy Schubert 			out->haveflags |= CLK_HAVETIME2;
1324c0b746e5SOllivier Robert 		out->flags = (u_char) pp->sloppyclockflag;
13252b15cb3dSCy Schubert 		if (CLK_FLAG1 & out->flags)
13262b15cb3dSCy Schubert 			out->haveflags |= CLK_HAVEFLAG1;
13272b15cb3dSCy Schubert 		if (CLK_FLAG2 & out->flags)
13282b15cb3dSCy Schubert 			out->haveflags |= CLK_HAVEFLAG2;
13292b15cb3dSCy Schubert 		if (CLK_FLAG3 & out->flags)
13302b15cb3dSCy Schubert 			out->haveflags |= CLK_HAVEFLAG3;
13312b15cb3dSCy Schubert 		if (CLK_FLAG4 & out->flags)
13322b15cb3dSCy Schubert 			out->haveflags |= CLK_HAVEFLAG4;
13332d4e511cSCy Schubert 		out->fudgeminjitter = pp->fudgeminjitter;
13342d4e511cSCy Schubert 		if (0.0 != out->fudgeminjitter)
13352d4e511cSCy Schubert 			out->haveflags |= CLK_HAVEMINJIT;
1336c0b746e5SOllivier Robert 
1337c0b746e5SOllivier Robert 		out->timereset = current_time - pp->timestarted;
1338c0b746e5SOllivier Robert 		out->polls = pp->polls;
1339c0b746e5SOllivier Robert 		out->noresponse = pp->noreply;
1340c0b746e5SOllivier Robert 		out->badformat = pp->badformat;
1341c0b746e5SOllivier Robert 		out->baddata = pp->baddata;
1342c0b746e5SOllivier Robert 
1343c0b746e5SOllivier Robert 		out->lastevent = pp->lastevent;
1344c0b746e5SOllivier Robert 		out->currentstatus = pp->currentstatus;
1345c0b746e5SOllivier Robert 		out->type = pp->type;
1346c0b746e5SOllivier Robert 		out->clockdesc = pp->clockdesc;
13472b15cb3dSCy Schubert 		out->lencode = (u_short)pp->lencode;
1348c0b746e5SOllivier Robert 		out->p_lastcode = pp->a_lastcode;
1349c0b746e5SOllivier Robert 	}
1350c0b746e5SOllivier Robert 
1351c0b746e5SOllivier Robert 	/*
1352c0b746e5SOllivier Robert 	 * Give the stuff to the clock
1353c0b746e5SOllivier Robert 	 */
1354c0b746e5SOllivier Robert 	if (refclock_conf[clktype]->clock_control != noentry)
1355c0b746e5SOllivier Robert 		(refclock_conf[clktype]->clock_control)(unit, in, out, peer);
1356c0b746e5SOllivier Robert }
1357c0b746e5SOllivier Robert 
1358c0b746e5SOllivier Robert 
1359c0b746e5SOllivier Robert /*
1360c0b746e5SOllivier Robert  * refclock_buginfo - return debugging info
1361c0b746e5SOllivier Robert  *
1362c0b746e5SOllivier Robert  * This routine is used mainly for debugging. It returns designated
1363c0b746e5SOllivier Robert  * values from the interface structure that can be displayed using
1364c0b746e5SOllivier Robert  * ntpdc and the clkbug command.
1365c0b746e5SOllivier Robert  */
1366c0b746e5SOllivier Robert void
1367c0b746e5SOllivier Robert refclock_buginfo(
13682b15cb3dSCy Schubert 	sockaddr_u *srcadr,	/* clock address */
1369c0b746e5SOllivier Robert 	struct refclockbug *bug /* output structure */
1370c0b746e5SOllivier Robert 	)
1371c0b746e5SOllivier Robert {
1372c0b746e5SOllivier Robert 	struct peer *peer;
1373c0b746e5SOllivier Robert 	struct refclockproc *pp;
13742b15cb3dSCy Schubert 	int clktype;
1375c0b746e5SOllivier Robert 	int unit;
13762b15cb3dSCy Schubert 	unsigned u;
1377c0b746e5SOllivier Robert 
1378c0b746e5SOllivier Robert 	/*
1379c0b746e5SOllivier Robert 	 * Check for valid address and peer structure
1380c0b746e5SOllivier Robert 	 */
1381c0b746e5SOllivier Robert 	if (!ISREFCLOCKADR(srcadr))
1382c0b746e5SOllivier Robert 		return;
1383ea906c41SOllivier Robert 
1384c0b746e5SOllivier Robert 	clktype = (u_char) REFCLOCKTYPE(srcadr);
1385c0b746e5SOllivier Robert 	unit = REFCLOCKUNIT(srcadr);
1386ea906c41SOllivier Robert 
138709100258SXin LI 	peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL);
13882b15cb3dSCy Schubert 
13892b15cb3dSCy Schubert 	if (NULL == peer || NULL == peer->procptr)
1390c0b746e5SOllivier Robert 		return;
1391ea906c41SOllivier Robert 
1392c0b746e5SOllivier Robert 	pp = peer->procptr;
1393c0b746e5SOllivier Robert 
1394c0b746e5SOllivier Robert 	/*
1395c0b746e5SOllivier Robert 	 * Copy structure values
1396c0b746e5SOllivier Robert 	 */
1397c0b746e5SOllivier Robert 	bug->nvalues = 8;
1398c0b746e5SOllivier Robert 	bug->svalues = 0x0000003f;
1399c0b746e5SOllivier Robert 	bug->values[0] = pp->year;
1400c0b746e5SOllivier Robert 	bug->values[1] = pp->day;
1401c0b746e5SOllivier Robert 	bug->values[2] = pp->hour;
1402c0b746e5SOllivier Robert 	bug->values[3] = pp->minute;
1403c0b746e5SOllivier Robert 	bug->values[4] = pp->second;
14049c2daa00SOllivier Robert 	bug->values[5] = pp->nsec;
1405c0b746e5SOllivier Robert 	bug->values[6] = pp->yearstart;
1406c0b746e5SOllivier Robert 	bug->values[7] = pp->coderecv;
1407c0b746e5SOllivier Robert 	bug->stimes = 0xfffffffc;
1408c0b746e5SOllivier Robert 	bug->times[0] = pp->lastref;
1409c0b746e5SOllivier Robert 	bug->times[1] = pp->lastrec;
14102b15cb3dSCy Schubert 	for (u = 2; u < bug->ntimes; u++)
14112b15cb3dSCy Schubert 		DTOLFP(pp->filter[u - 2], &bug->times[u]);
1412c0b746e5SOllivier Robert 
1413c0b746e5SOllivier Robert 	/*
1414c0b746e5SOllivier Robert 	 * Give the stuff to the clock
1415c0b746e5SOllivier Robert 	 */
1416c0b746e5SOllivier Robert 	if (refclock_conf[clktype]->clock_buginfo != noentry)
1417c0b746e5SOllivier Robert 		(refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
1418c0b746e5SOllivier Robert }
1419c0b746e5SOllivier Robert 
14202b15cb3dSCy Schubert 
14212b15cb3dSCy Schubert #ifdef HAVE_PPSAPI
14222b15cb3dSCy Schubert /*
14232b15cb3dSCy Schubert  * refclock_ppsapi - initialize/update ppsapi
14242b15cb3dSCy Schubert  *
14252b15cb3dSCy Schubert  * This routine is called after the fudge command to open the PPSAPI
14262b15cb3dSCy Schubert  * interface for later parameter setting after the fudge command.
14272b15cb3dSCy Schubert  */
14282b15cb3dSCy Schubert int
14292b15cb3dSCy Schubert refclock_ppsapi(
14302b15cb3dSCy Schubert 	int	fddev,			/* fd device */
14312b15cb3dSCy Schubert 	struct refclock_atom *ap	/* atom structure pointer */
14322b15cb3dSCy Schubert 	)
14332b15cb3dSCy Schubert {
14342b15cb3dSCy Schubert 	if (ap->handle == 0) {
14352b15cb3dSCy Schubert 		if (time_pps_create(fddev, &ap->handle) < 0) {
14362b15cb3dSCy Schubert 			msyslog(LOG_ERR,
14372b15cb3dSCy Schubert 			    "refclock_ppsapi: time_pps_create: %m");
14382b15cb3dSCy Schubert 			return (0);
14392b15cb3dSCy Schubert 		}
1440f391d6bcSXin LI 		ZERO(ap->ts); /* [Bug 2689] defined INIT state */
14412b15cb3dSCy Schubert 	}
14422b15cb3dSCy Schubert 	return (1);
14432b15cb3dSCy Schubert }
14442b15cb3dSCy Schubert 
14452b15cb3dSCy Schubert 
14462b15cb3dSCy Schubert /*
14472b15cb3dSCy Schubert  * refclock_params - set ppsapi parameters
14482b15cb3dSCy Schubert  *
14492b15cb3dSCy Schubert  * This routine is called to set the PPSAPI parameters after the fudge
14502b15cb3dSCy Schubert  * command.
14512b15cb3dSCy Schubert  */
14522b15cb3dSCy Schubert int
14532b15cb3dSCy Schubert refclock_params(
14542b15cb3dSCy Schubert 	int	mode,			/* mode bits */
14552b15cb3dSCy Schubert 	struct refclock_atom *ap	/* atom structure pointer */
14562b15cb3dSCy Schubert 	)
14572b15cb3dSCy Schubert {
14582b15cb3dSCy Schubert 	ZERO(ap->pps_params);
14592b15cb3dSCy Schubert 	ap->pps_params.api_version = PPS_API_VERS_1;
14602b15cb3dSCy Schubert 
14612b15cb3dSCy Schubert 	/*
14622b15cb3dSCy Schubert 	 * Solaris serial ports provide PPS pulse capture only on the
14632b15cb3dSCy Schubert 	 * assert edge. FreeBSD serial ports provide capture on the
14642b15cb3dSCy Schubert 	 * clear edge, while FreeBSD parallel ports provide capture
14652b15cb3dSCy Schubert 	 * on the assert edge. Your mileage may vary.
14662b15cb3dSCy Schubert 	 */
14672b15cb3dSCy Schubert 	if (mode & CLK_FLAG2)
14682b15cb3dSCy Schubert 		ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR;
14692b15cb3dSCy Schubert 	else
14702b15cb3dSCy Schubert 		ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT;
14712b15cb3dSCy Schubert 	if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) {
14722b15cb3dSCy Schubert 		msyslog(LOG_ERR,
14732b15cb3dSCy Schubert 		    "refclock_params: time_pps_setparams: %m");
14742b15cb3dSCy Schubert 		return (0);
14752b15cb3dSCy Schubert 	}
14762b15cb3dSCy Schubert 
14772b15cb3dSCy Schubert 	/*
14782b15cb3dSCy Schubert 	 * If flag3 is lit, select the kernel PPS if we can.
147909100258SXin LI 	 *
148009100258SXin LI 	 * Note: EOPNOTSUPP is the only 'legal' error code we deal with;
148109100258SXin LI 	 * it is part of the 'if we can' strategy.  Any other error
148209100258SXin LI 	 * indicates something more sinister and makes this function fail.
14832b15cb3dSCy Schubert 	 */
14842b15cb3dSCy Schubert 	if (mode & CLK_FLAG3) {
14852b15cb3dSCy Schubert 		if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS,
14862b15cb3dSCy Schubert 		    ap->pps_params.mode & ~PPS_TSFMT_TSPEC,
148709100258SXin LI 		    PPS_TSFMT_TSPEC) < 0)
148809100258SXin LI 		{
148909100258SXin LI 			if (errno != EOPNOTSUPP) {
14902b15cb3dSCy Schubert 				msyslog(LOG_ERR,
14912b15cb3dSCy Schubert 					"refclock_params: time_pps_kcbind: %m");
14922b15cb3dSCy Schubert 				return (0);
14932b15cb3dSCy Schubert 			}
149409100258SXin LI 		} else {
14952b15cb3dSCy Schubert 			hardpps_enable = 1;
14962b15cb3dSCy Schubert 		}
149709100258SXin LI 	}
14982b15cb3dSCy Schubert 	return (1);
14992b15cb3dSCy Schubert }
15002b15cb3dSCy Schubert 
15012b15cb3dSCy Schubert 
15022b15cb3dSCy Schubert /*
15032b15cb3dSCy Schubert  * refclock_pps - called once per second
15042b15cb3dSCy Schubert  *
15052b15cb3dSCy Schubert  * This routine is called once per second. It snatches the PPS
15062b15cb3dSCy Schubert  * timestamp from the kernel and saves the sign-extended fraction in
15072b15cb3dSCy Schubert  * a circular buffer for processing at the next poll event.
15082b15cb3dSCy Schubert  */
15092b15cb3dSCy Schubert int
15102b15cb3dSCy Schubert refclock_pps(
15112b15cb3dSCy Schubert 	struct peer *peer,		/* peer structure pointer */
15122b15cb3dSCy Schubert 	struct refclock_atom *ap,	/* atom structure pointer */
15132b15cb3dSCy Schubert 	int	mode			/* mode bits */
15142b15cb3dSCy Schubert 	)
15152b15cb3dSCy Schubert {
15162b15cb3dSCy Schubert 	struct refclockproc *pp;
15172b15cb3dSCy Schubert 	pps_info_t pps_info;
15182b15cb3dSCy Schubert 	struct timespec timeout;
1519f391d6bcSXin LI 	double	dtemp, dcorr, trash;
15202b15cb3dSCy Schubert 
15212b15cb3dSCy Schubert 	/*
15222b15cb3dSCy Schubert 	 * We require the clock to be synchronized before setting the
15232b15cb3dSCy Schubert 	 * parameters. When the parameters have been set, fetch the
15242b15cb3dSCy Schubert 	 * most recent PPS timestamp.
15252b15cb3dSCy Schubert 	 */
15262b15cb3dSCy Schubert 	pp = peer->procptr;
15272b15cb3dSCy Schubert 	if (ap->handle == 0)
15282b15cb3dSCy Schubert 		return (0);
15292b15cb3dSCy Schubert 
15302b15cb3dSCy Schubert 	if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) {
15312b15cb3dSCy Schubert 		if (refclock_params(pp->sloppyclockflag, ap) < 1)
15322b15cb3dSCy Schubert 			return (0);
15332b15cb3dSCy Schubert 	}
1534f391d6bcSXin LI 	ZERO(timeout);
15352b15cb3dSCy Schubert 	ZERO(pps_info);
15362b15cb3dSCy Schubert 	if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info,
15372b15cb3dSCy Schubert 	    &timeout) < 0) {
15382b15cb3dSCy Schubert 		refclock_report(peer, CEVNT_FAULT);
15392b15cb3dSCy Schubert 		return (0);
15402b15cb3dSCy Schubert 	}
1541f391d6bcSXin LI 	timeout = ap->ts;	/* save old timestamp for check */
15422b15cb3dSCy Schubert 	if (ap->pps_params.mode & PPS_CAPTUREASSERT)
15432b15cb3dSCy Schubert 		ap->ts = pps_info.assert_timestamp;
15442b15cb3dSCy Schubert 	else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
15452b15cb3dSCy Schubert 		ap->ts = pps_info.clear_timestamp;
15462b15cb3dSCy Schubert 	else
15472b15cb3dSCy Schubert 		return (0);
15482b15cb3dSCy Schubert 
1549f391d6bcSXin LI 	/* [Bug 2689] Discard the first sample we read -- if the PPS
1550f391d6bcSXin LI 	 * source is currently down / disconnected, we have read a
1551f391d6bcSXin LI 	 * potentially *very* stale value here. So if our old TS value
1552f391d6bcSXin LI 	 * is all-zero, we consider this sample unrealiable and drop it.
1553f391d6bcSXin LI 	 *
1554f391d6bcSXin LI 	 * Note 1: a better check would compare the PPS time stamp to
1555f391d6bcSXin LI 	 * the current system time and drop it if it's more than say 3s
1556f391d6bcSXin LI 	 * away.
1557f391d6bcSXin LI 	 *
1558f391d6bcSXin LI 	 * Note 2: If we ever again get an all-zero PPS sample, the next
1559f391d6bcSXin LI 	 * one will be discarded. This can happen every 136yrs and is
1560f391d6bcSXin LI 	 * unlikely to be ever observed.
1561f391d6bcSXin LI 	 */
1562f391d6bcSXin LI 	if (0 == (timeout.tv_sec | timeout.tv_nsec))
1563f391d6bcSXin LI 		return (0);
1564f391d6bcSXin LI 
1565f391d6bcSXin LI 	/* If the PPS source fails to deliver a new sample between
1566f391d6bcSXin LI 	 * polls, it regurgitates the last sample. We do not want to
1567f391d6bcSXin LI 	 * process the same sample multiple times.
1568f391d6bcSXin LI 	 */
15692b15cb3dSCy Schubert 	if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout)))
15702b15cb3dSCy Schubert 		return (0);
15712b15cb3dSCy Schubert 
15722b15cb3dSCy Schubert 	/*
1573f391d6bcSXin LI 	 * Convert to signed fraction offset, apply fudge and properly
1574f391d6bcSXin LI 	 * fold the correction into the [-0.5s,0.5s] range. Handle
1575f391d6bcSXin LI 	 * excessive fudge times, too.
1576f391d6bcSXin LI 	 */
1577f391d6bcSXin LI 	dtemp = ap->ts.tv_nsec / 1e9;
1578f391d6bcSXin LI 	dcorr = modf((pp->fudgetime1 - dtemp), &trash);
1579f391d6bcSXin LI 	if (dcorr > 0.5)
1580f391d6bcSXin LI 		dcorr -= 1.0;
1581f391d6bcSXin LI 	else if (dcorr < -0.5)
1582f391d6bcSXin LI 		dcorr += 1.0;
1583f391d6bcSXin LI 
1584f391d6bcSXin LI 	/* phase gate check: avoid wobbling by +/-1s when too close to
1585f391d6bcSXin LI 	 * the switch-over point. We allow +/-400ms max phase deviation.
1586f391d6bcSXin LI 	 * The trade-off is clear: The smaller the limit, the less
1587f391d6bcSXin LI 	 * sensitive to sampling noise the clock becomes. OTOH the
1588f391d6bcSXin LI 	 * system must get into phase gate range by other means for the
1589f391d6bcSXin LI 	 * PPS clock to lock in.
1590f391d6bcSXin LI 	 */
1591f391d6bcSXin LI 	if (fabs(dcorr) > 0.4)
1592f391d6bcSXin LI 		return (0);
1593f391d6bcSXin LI 
1594f391d6bcSXin LI 	/*
1595f391d6bcSXin LI 	 * record this time stamp and stuff in median filter
15962b15cb3dSCy Schubert 	 */
15972b15cb3dSCy Schubert 	pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970;
15982b15cb3dSCy Schubert 	pp->lastrec.l_uf = (u_int32)(dtemp * FRAC);
15992d4e511cSCy Schubert 	clk_add_sample(pp, dcorr);
16002d4e511cSCy Schubert 	refclock_checkburst(peer, pp);
1601f391d6bcSXin LI 
16022b15cb3dSCy Schubert #ifdef DEBUG
16032b15cb3dSCy Schubert 	if (debug > 1)
16042b15cb3dSCy Schubert 		printf("refclock_pps: %lu %f %f\n", current_time,
1605f391d6bcSXin LI 		    dcorr, pp->fudgetime1);
16062b15cb3dSCy Schubert #endif
16072b15cb3dSCy Schubert 	return (1);
16082b15cb3dSCy Schubert }
16092b15cb3dSCy Schubert #endif /* HAVE_PPSAPI */
16102d4e511cSCy Schubert 
16112d4e511cSCy Schubert 
16122d4e511cSCy Schubert /*
16132d4e511cSCy Schubert  * -------------------------------------------------------------------
16142d4e511cSCy Schubert  * refclock_ppsaugment(...) -- correlate with PPS edge
16152d4e511cSCy Schubert  *
16162d4e511cSCy Schubert  * This function is used to correlate a receive time stamp with a PPS
16172d4e511cSCy Schubert  * edge time stamp. It applies the necessary fudges and then tries to
16182d4e511cSCy Schubert  * move the receive time stamp to the corresponding edge. This can warp
16192d4e511cSCy Schubert  * into future, if a transmission delay of more than 500ms is not
16202d4e511cSCy Schubert  * compensated with a corresponding fudge time2 value, because then the
16212d4e511cSCy Schubert  * next PPS edge is nearer than the last. (Similiar to what the PPS ATOM
16222d4e511cSCy Schubert  * driver does, but we deal with full time stamps here, not just phase
16232d4e511cSCy Schubert  * shift information.) Likewise, a negative fudge time2 value must be
16242d4e511cSCy Schubert  * used if the reference time stamp correlates with the *following* PPS
16252d4e511cSCy Schubert  * pulse.
16262d4e511cSCy Schubert  *
16272d4e511cSCy Schubert  * Note that the receive time fudge value only needs to move the receive
16282d4e511cSCy Schubert  * stamp near a PPS edge but that close proximity is not required;
16292d4e511cSCy Schubert  * +/-100ms precision should be enough. But since the fudge value will
16302d4e511cSCy Schubert  * probably also be used to compensate the transmission delay when no
16312d4e511cSCy Schubert  * PPS edge can be related to the time stamp, it's best to get it as
16322d4e511cSCy Schubert  * close as possible.
16332d4e511cSCy Schubert  *
16342d4e511cSCy Schubert  * It should also be noted that the typical use case is matching to the
16352d4e511cSCy Schubert  * preceeding edge, as most units relate their sentences to the current
16362d4e511cSCy Schubert  * second.
16372d4e511cSCy Schubert  *
16382d4e511cSCy Schubert  * The function returns FALSE if there is no correlation possible, TRUE
16392d4e511cSCy Schubert  * otherwise.  Reason for failures are:
16402d4e511cSCy Schubert  *
16412d4e511cSCy Schubert  *  - no PPS/ATOM unit given
16422d4e511cSCy Schubert  *  - PPS stamp is stale (that is, the difference between the PPS stamp
16432d4e511cSCy Schubert  *    and the corrected time stamp would exceed two seconds)
16442d4e511cSCy Schubert  *  - The phase difference is too close to 0.5, and the decision wether
16452d4e511cSCy Schubert  *    to move up or down is too sensitive to noise.
16462d4e511cSCy Schubert  *
16472d4e511cSCy Schubert  * On output, the receive time stamp is updated with the 'fixed' receive
16482d4e511cSCy Schubert  * time.
16492d4e511cSCy Schubert  * -------------------------------------------------------------------
16502d4e511cSCy Schubert  */
16512d4e511cSCy Schubert 
1652*f5f40dd6SCy Schubert int
16532d4e511cSCy Schubert refclock_ppsaugment(
16542d4e511cSCy Schubert 	const struct refclock_atom * ap	    ,	/* for PPS io	  */
16552d4e511cSCy Schubert 	l_fp 			   * rcvtime ,
16562d4e511cSCy Schubert 	double			     rcvfudge,	/* i/o read fudge */
16572d4e511cSCy Schubert 	double			     ppsfudge	/* pps fudge	  */
16582d4e511cSCy Schubert 	)
16592d4e511cSCy Schubert {
16602d4e511cSCy Schubert 	l_fp		delta[1];
16612d4e511cSCy Schubert 
16622d4e511cSCy Schubert #ifdef HAVE_PPSAPI
16632d4e511cSCy Schubert 
16642d4e511cSCy Schubert 	pps_info_t	pps_info;
16652d4e511cSCy Schubert 	struct timespec timeout;
16662d4e511cSCy Schubert 	l_fp		stamp[1];
16672d4e511cSCy Schubert 	uint32_t	phase;
16682d4e511cSCy Schubert 
16692d4e511cSCy Schubert 	static const uint32_t s_plim_hi = UINT32_C(1932735284);
16702d4e511cSCy Schubert 	static const uint32_t s_plim_lo = UINT32_C(2362232013);
16712d4e511cSCy Schubert 
16722d4e511cSCy Schubert 	/* fixup receive time in case we have to bail out early */
16732d4e511cSCy Schubert 	DTOLFP(rcvfudge, delta);
16742d4e511cSCy Schubert 	L_SUB(rcvtime, delta);
16752d4e511cSCy Schubert 
16762d4e511cSCy Schubert 	if (NULL == ap)
16772d4e511cSCy Schubert 		return FALSE;
16782d4e511cSCy Schubert 
16792d4e511cSCy Schubert 	ZERO(timeout);
16802d4e511cSCy Schubert 	ZERO(pps_info);
16812d4e511cSCy Schubert 
16822d4e511cSCy Schubert 	/* fetch PPS stamp from ATOM block */
16832d4e511cSCy Schubert 	if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC,
16842d4e511cSCy Schubert 			   &pps_info, &timeout) < 0)
16852d4e511cSCy Schubert 		return FALSE; /* can't get time stamps */
16862d4e511cSCy Schubert 
16872d4e511cSCy Schubert 	/* get last active PPS edge before receive */
16882d4e511cSCy Schubert 	if (ap->pps_params.mode & PPS_CAPTUREASSERT)
16892d4e511cSCy Schubert 		timeout = pps_info.assert_timestamp;
16902d4e511cSCy Schubert 	else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
16912d4e511cSCy Schubert 		timeout = pps_info.clear_timestamp;
16922d4e511cSCy Schubert 	else
16932d4e511cSCy Schubert 		return FALSE; /* WHICH edge, please?!? */
16942d4e511cSCy Schubert 
16952d4e511cSCy Schubert 	/* convert PPS stamp to l_fp and apply fudge */
16962d4e511cSCy Schubert 	*stamp = tspec_stamp_to_lfp(timeout);
16972d4e511cSCy Schubert 	DTOLFP(ppsfudge, delta);
16982d4e511cSCy Schubert 	L_SUB(stamp, delta);
16992d4e511cSCy Schubert 
17002d4e511cSCy Schubert 	/* Get difference between PPS stamp (--> yield) and receive time
17012d4e511cSCy Schubert 	 * (--> base)
17022d4e511cSCy Schubert 	 */
17032d4e511cSCy Schubert 	*delta = *stamp;
17042d4e511cSCy Schubert 	L_SUB(delta, rcvtime);
17052d4e511cSCy Schubert 
17062d4e511cSCy Schubert 	/* check if either the PPS or the STAMP is stale in relation
17072d4e511cSCy Schubert 	 * to each other. Bail if it is so...
17082d4e511cSCy Schubert 	 */
17092d4e511cSCy Schubert 	phase = delta->l_ui;
17102d4e511cSCy Schubert 	if (phase >= 2 && phase < (uint32_t)-2)
17112d4e511cSCy Schubert 		return FALSE; /* PPS is stale, don't use it */
17122d4e511cSCy Schubert 
17132d4e511cSCy Schubert 	/* If the phase is too close to 0.5, the decision whether to
17142d4e511cSCy Schubert 	 * move up or down is becoming noise sensitive. That is, we
17152d4e511cSCy Schubert 	 * might amplify usec noise between samples into seconds with a
17162d4e511cSCy Schubert 	 * simple threshold. This can be solved by a Schmitt Trigger
17172d4e511cSCy Schubert 	 * characteristic, but that would also require additional state
17182d4e511cSCy Schubert 	 * where we could remember previous decisions.  Easier to play
17192d4e511cSCy Schubert 	 * dead duck and wait for the conditions to become clear.
17202d4e511cSCy Schubert 	 */
17212d4e511cSCy Schubert 	phase = delta->l_uf;
17222d4e511cSCy Schubert 	if (phase > s_plim_hi && phase < s_plim_lo)
17232d4e511cSCy Schubert 		return FALSE; /* we're in the noise lock gap */
17242d4e511cSCy Schubert 
17252d4e511cSCy Schubert 	/* sign-extend fraction into seconds */
17262d4e511cSCy Schubert 	delta->l_ui = UINT32_C(0) - ((phase >> 31) & 1);
17272d4e511cSCy Schubert 	/* add it up now */
17282d4e511cSCy Schubert 	L_ADD(rcvtime, delta);
17292d4e511cSCy Schubert 	return TRUE;
17302d4e511cSCy Schubert 
17312d4e511cSCy Schubert #   else /* have no PPS support at all */
17322d4e511cSCy Schubert 
17332d4e511cSCy Schubert 	/* just fixup receive time and fail */
17342d4e511cSCy Schubert 	UNUSED_ARG(ap);
17352d4e511cSCy Schubert 	UNUSED_ARG(ppsfudge);
17362d4e511cSCy Schubert 
17372d4e511cSCy Schubert 	DTOLFP(rcvfudge, delta);
17382d4e511cSCy Schubert 	L_SUB(rcvtime, delta);
17392d4e511cSCy Schubert 	return FALSE;
17402d4e511cSCy Schubert 
17412d4e511cSCy Schubert #   endif
17422d4e511cSCy Schubert }
17432d4e511cSCy Schubert 
17442d4e511cSCy Schubert /*
17452d4e511cSCy Schubert  * -------------------------------------------------------------------
17462d4e511cSCy Schubert  * check if it makes sense to schedule an 'early' poll to get the clock
17472d4e511cSCy Schubert  * up fast after start or longer signal dropout.
17482d4e511cSCy Schubert  */
17492d4e511cSCy Schubert static void
17502d4e511cSCy Schubert refclock_checkburst(
17512d4e511cSCy Schubert 	struct peer *         peer,
17522d4e511cSCy Schubert 	struct refclockproc * pp
17532d4e511cSCy Schubert 	)
17542d4e511cSCy Schubert {
17552d4e511cSCy Schubert 	uint32_t	limit;	/* when we should poll */
17562d4e511cSCy Schubert 	u_int		needs;	/* needed number of samples */
17572d4e511cSCy Schubert 
17582d4e511cSCy Schubert 	/* Paranoia: stop here if peer and clockproc don't match up.
17592d4e511cSCy Schubert 	 * And when a poll is actually pending, we don't have to do
17602d4e511cSCy Schubert 	 * anything, either. Likewise if the reach mask is full, of
17612d4e511cSCy Schubert 	 * course, and if the filter has stabilized.
17622d4e511cSCy Schubert 	 */
17632d4e511cSCy Schubert 	if (pp->inpoll || (peer->procptr != pp) ||
17642d4e511cSCy Schubert 	    ((peer->reach == 0xFF) && (peer->disp <= MAXDISTANCE)))
17652d4e511cSCy Schubert 		return;
17662d4e511cSCy Schubert 
17672d4e511cSCy Schubert 	/* If the next poll is soon enough, bail out, too: */
17682d4e511cSCy Schubert 	limit = current_time + 1;
17692d4e511cSCy Schubert 	if (peer->nextdate <= limit)
17702d4e511cSCy Schubert 		return;
17712d4e511cSCy Schubert 
17722d4e511cSCy Schubert 	/* Derive the number of samples needed from the popcount of the
17732d4e511cSCy Schubert 	 * reach mask.  With less samples available, we break away.
17742d4e511cSCy Schubert 	 */
17752d4e511cSCy Schubert 	needs  = peer->reach;
17762d4e511cSCy Schubert 	needs -= (needs >> 1) & 0x55;
17772d4e511cSCy Schubert 	needs  = (needs & 0x33) + ((needs >> 2) & 0x33);
17782d4e511cSCy Schubert 	needs  = (needs + (needs >> 4)) & 0x0F;
17792d4e511cSCy Schubert 	if (needs > 6)
17802d4e511cSCy Schubert 		needs = 6;
17812d4e511cSCy Schubert 	else if (needs < 3)
17822d4e511cSCy Schubert 		needs = 3;
17832d4e511cSCy Schubert 	if (clk_cnt_sample(pp) < needs)
17842d4e511cSCy Schubert 		return;
17852d4e511cSCy Schubert 
17862d4e511cSCy Schubert 	/* Get serious. Reduce the poll to minimum and schedule early.
17872d4e511cSCy Schubert 	 * (Changing the peer poll is probably in vain, as it will be
17882d4e511cSCy Schubert 	 * re-adjusted, but maybe some time the hint will work...)
17892d4e511cSCy Schubert 	 */
17902d4e511cSCy Schubert 	peer->hpoll = peer->minpoll;
17912d4e511cSCy Schubert 	peer->nextdate = limit;
17922d4e511cSCy Schubert }
17932d4e511cSCy Schubert 
17942d4e511cSCy Schubert /*
17952d4e511cSCy Schubert  * -------------------------------------------------------------------
17962d4e511cSCy Schubert  * Save the last timecode string, making sure it's properly truncated
17972d4e511cSCy Schubert  * if necessary and NUL terminated in any case.
17982d4e511cSCy Schubert  */
17992d4e511cSCy Schubert void
18002d4e511cSCy Schubert refclock_save_lcode(
18012d4e511cSCy Schubert 	struct refclockproc *	pp,
18022d4e511cSCy Schubert 	char const *		tc,
18032d4e511cSCy Schubert 	size_t			len
18042d4e511cSCy Schubert 	)
18052d4e511cSCy Schubert {
18062d4e511cSCy Schubert 	if (len == (size_t)-1)
18072d4e511cSCy Schubert 		len = strnlen(tc,  sizeof(pp->a_lastcode) - 1);
18082d4e511cSCy Schubert 	else if (len >= sizeof(pp->a_lastcode))
18092d4e511cSCy Schubert 		len = sizeof(pp->a_lastcode) - 1;
18102d4e511cSCy Schubert 
18112d4e511cSCy Schubert 	pp->lencode = (u_short)len;
18122d4e511cSCy Schubert 	memcpy(pp->a_lastcode, tc, len);
18132d4e511cSCy Schubert 	pp->a_lastcode[len] = '\0';
18142d4e511cSCy Schubert }
18152d4e511cSCy Schubert 
18162d4e511cSCy Schubert /* format data into a_lastcode */
18172d4e511cSCy Schubert void
18182d4e511cSCy Schubert refclock_vformat_lcode(
18192d4e511cSCy Schubert 	struct refclockproc *	pp,
18202d4e511cSCy Schubert 	char const *		fmt,
18212d4e511cSCy Schubert 	va_list			va
18222d4e511cSCy Schubert 	)
18232d4e511cSCy Schubert {
18242d4e511cSCy Schubert 	long len;
18252d4e511cSCy Schubert 
18262d4e511cSCy Schubert 	len = vsnprintf(pp->a_lastcode, sizeof(pp->a_lastcode), fmt, va);
1827*f5f40dd6SCy Schubert 	if (len <= 0) {
18282d4e511cSCy Schubert 		len = 0;
1829*f5f40dd6SCy Schubert 	} else if (len >= sizeof(pp->a_lastcode)) {
18302d4e511cSCy Schubert 		len = sizeof(pp->a_lastcode) - 1;
1831*f5f40dd6SCy Schubert 	}
18322d4e511cSCy Schubert 
18332d4e511cSCy Schubert 	pp->lencode = (u_short)len;
18342d4e511cSCy Schubert 	pp->a_lastcode[len] = '\0';
18352d4e511cSCy Schubert 	/* !note! the NUL byte is needed in case vsnprintf() really fails */
18362d4e511cSCy Schubert }
18372d4e511cSCy Schubert 
18382d4e511cSCy Schubert void
18392d4e511cSCy Schubert refclock_format_lcode(
18402d4e511cSCy Schubert 	struct refclockproc *	pp,
18412d4e511cSCy Schubert 	char const *		fmt,
18422d4e511cSCy Schubert 	...
18432d4e511cSCy Schubert 	)
18442d4e511cSCy Schubert {
18452d4e511cSCy Schubert 	va_list va;
18462d4e511cSCy Schubert 
18472d4e511cSCy Schubert 	va_start(va, fmt);
18482d4e511cSCy Schubert 	refclock_vformat_lcode(pp, fmt, va);
18492d4e511cSCy Schubert 	va_end(va);
18502d4e511cSCy Schubert }
18512d4e511cSCy Schubert 
1852c0b746e5SOllivier Robert #endif	/* REFCLOCK */
1853