154359Sroberto
254359Sroberto/*
354359Sroberto * refclock_local - local pseudo-clock driver
4132451Sroberto *
5132451Sroberto * wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT
654359Sroberto */
754359Sroberto#ifdef HAVE_CONFIG_H
854359Sroberto#include <config.h>
954359Sroberto#endif
1054359Sroberto
1154359Sroberto#ifdef REFCLOCK
1254359Sroberto
1354359Sroberto#include "ntpd.h"
1454359Sroberto#include "ntp_refclock.h"
1554359Sroberto#include "ntp_stdlib.h"
1654359Sroberto
1782498Sroberto#include <stdio.h>
1882498Sroberto#include <ctype.h>
1982498Sroberto
2054359Sroberto#ifdef KERNEL_PLL
2154359Sroberto#include "ntp_syscall.h"
2254359Sroberto#endif
2354359Sroberto
2454359Sroberto/*
2554359Sroberto * This is a hack to allow a machine to use its own system clock as a
2654359Sroberto * reference clock, i.e., to free-run using no outside clock discipline
2754359Sroberto * source. This is useful if you want to use NTP in an isolated
2854359Sroberto * environment with no radio clock or NIST modem available. Pick a
2954359Sroberto * machine that you figure has a good clock oscillator and configure it
3054359Sroberto * with this driver. Set the clock using the best means available, like
3154359Sroberto * eyeball-and-wristwatch. Then, point all the other machines at this
3254359Sroberto * one or use broadcast (not multicast) mode to distribute time.
3354359Sroberto *
3454359Sroberto * Another application for this driver is if you want to use a
3554359Sroberto * particular server's clock as the clock of last resort when all other
3654359Sroberto * normal synchronization sources have gone away. This is especially
3754359Sroberto * useful if that server has an ovenized oscillator. For this you would
3882498Sroberto * configure this driver at a higher stratum (say 5) to prevent the
3954359Sroberto * server's stratum from falling below that.
4054359Sroberto *
4154359Sroberto * A third application for this driver is when an external discipline
4254359Sroberto * source is available, such as the NIST "lockclock" program, which
4354359Sroberto * synchronizes the local clock via a telephone modem and the NIST
4454359Sroberto * Automated Computer Time Service (ACTS), or the Digital Time
4554359Sroberto * Synchronization Service (DTSS), which runs on DCE machines. In this
4654359Sroberto * case the stratum should be set at zero, indicating a bona fide
4754359Sroberto * stratum-1 source. Exercise some caution with this, since there is no
4854359Sroberto * easy way to telegraph via NTP that something might be wrong in the
4954359Sroberto * discipline source itself. In the case of DTSS, the local clock can
5054359Sroberto * have a rather large jitter, depending on the interval between
5154359Sroberto * corrections and the intrinsic frequency error of the clock
5254359Sroberto * oscillator. In extreme cases, this can cause clients to exceed the
5354359Sroberto * 128-ms slew window and drop off the NTP subnet.
5454359Sroberto *
5554359Sroberto * THis driver includes provisions to telegraph synchronization state
5654359Sroberto * and related variables by means of kernel variables with specially
5754359Sroberto * modified kernels. This is done using the ntp_adjtime() syscall.
5854359Sroberto * In the cases where another protocol or device synchronizes the local
5954359Sroberto * host, the data given to the kernel can be slurped up by this driver
6054359Sroberto * and distributed to clients by ordinary NTP messaging.
6154359Sroberto *
6254359Sroberto * In the default mode the behavior of the clock selection algorithm is
6354359Sroberto * modified when this driver is in use. The algorithm is designed so
6454359Sroberto * that this driver will never be selected unless no other discipline
6554359Sroberto * source is available. This can be overriden with the prefer keyword of
6654359Sroberto * the server configuration command, in which case only this driver will
6754359Sroberto * be selected for synchronization and all other discipline sources will
6854359Sroberto * be ignored. This behavior is intended for use when an external
6954359Sroberto * discipline source controls the system clock.
7054359Sroberto *
7154359Sroberto * Fudge Factors
7254359Sroberto *
73132451Sroberto * The stratum for this driver set at 5 by default, but it can be
74132451Sroberto * changed by the fudge command and/or the ntpdc utility. The reference
75182007Sroberto * ID is 127.0.0.1 by default, but can be changed using the same mechanism.
76132451Sroberto * *NEVER* configure this driver to operate at a stratum which might
77132451Sroberto * possibly disrupt a client with access to a bona fide primary server,
78132451Sroberto * unless the local clock oscillator is reliably disciplined by another
79132451Sroberto * source. *NEVER NEVER* configure a server which might devolve to an
80132451Sroberto * undisciplined local clock to use multicast mode. Always remember that
81132451Sroberto * an improperly configured local clock driver let loose in the Internet
82132451Sroberto * can cause very serious disruption. This is why most of us who care
83132451Sroberto * about good time use cryptographic authentication.
8454359Sroberto *
8554359Sroberto * This driver provides a mechanism to trim the local clock in both time
8654359Sroberto * and frequency, as well as a way to manipulate the leap bits. The
8754359Sroberto * fudge time1 parameter adjusts the time, in seconds, and the fudge
88132451Sroberto * time2 parameter adjusts the frequency, in ppm. The fudge time1
89132451Sroberto * parameter is additive; that is, it adds an increment to the current
90132451Sroberto * time. The fudge time2 parameter directly sets the frequency.
9154359Sroberto */
9254359Sroberto/*
9354359Sroberto * Local interface definitions
9454359Sroberto */
9554359Sroberto#define PRECISION	(-7)	/* about 10 ms precision */
9654359Sroberto#define DESCRIPTION "Undisciplined local clock" /* WRU */
9782498Sroberto#define STRATUM 	5	/* default stratum */
9854359Sroberto#define DISPERSION	.01	/* default dispersion (10 ms) */
9954359Sroberto
10054359Sroberto/*
10154359Sroberto * Imported from the timer module
10254359Sroberto */
10354359Srobertoextern u_long current_time;
10454359Sroberto
10554359Sroberto/*
10654359Sroberto * Imported from ntp_proto
10754359Sroberto */
10854359Srobertoextern s_char sys_precision;
10954359Sroberto
11054359Sroberto#ifdef KERNEL_PLL
11154359Sroberto/*
11254359Sroberto * Imported from ntp_loopfilter
11354359Sroberto */
11454359Srobertoextern int pll_control; 	/* kernel pll control */
11554359Srobertoextern int kern_enable;		/* kernel pll enabled */
11654359Srobertoextern int ext_enable;		/* external clock enable */
11754359Sroberto#endif /* KERNEL_PLL */
11854359Sroberto
11954359Sroberto/*
12054359Sroberto * Function prototypes
12154359Sroberto */
12254359Srobertostatic	int local_start P((int, struct peer *));
12354359Srobertostatic	void	local_poll	P((int, struct peer *));
12454359Sroberto
12554359Sroberto/*
12654359Sroberto * Local variables
12754359Sroberto */
12854359Srobertostatic	u_long poll_time;	/* last time polled */
12954359Sroberto
13054359Sroberto/*
13154359Sroberto * Transfer vector
13254359Sroberto */
13354359Srobertostruct	refclock refclock_local = {
13454359Sroberto	local_start,		/* start up driver */
13554359Sroberto	noentry,		/* shut down driver (not used) */
13654359Sroberto	local_poll,	 	/* transmit poll message */
13754359Sroberto	noentry,		/* not used (old lcl_control) */
13854359Sroberto	noentry,		/* initialize driver (not used) */
13954359Sroberto	noentry,		/* not used (old lcl_buginfo) */
14054359Sroberto	NOFLAGS 		/* not used */
14154359Sroberto};
14254359Sroberto
14354359Sroberto
14454359Sroberto/*
14554359Sroberto * local_start - start up the clock
14654359Sroberto */
14754359Srobertostatic int
14854359Srobertolocal_start(
14954359Sroberto	int unit,
15054359Sroberto	struct peer *peer
15154359Sroberto	)
15254359Sroberto{
15354359Sroberto	struct refclockproc *pp;
15454359Sroberto
15554359Sroberto	pp = peer->procptr;
15654359Sroberto
15754359Sroberto	/*
15854359Sroberto	 * Initialize miscellaneous variables
15954359Sroberto	 */
16054359Sroberto	peer->precision = sys_precision;
161132451Sroberto	pp->leap = LEAP_NOTINSYNC;
16254359Sroberto	peer->stratum = STRATUM;
163132451Sroberto	pp->stratum = STRATUM;
16454359Sroberto	pp->clockdesc = DESCRIPTION;
165182007Sroberto	memcpy(&pp->refid, "LOCL", 4);
16654359Sroberto	poll_time = current_time;
16754359Sroberto	return (1);
16854359Sroberto}
16954359Sroberto
17054359Sroberto
17154359Sroberto/*
17254359Sroberto * local_poll - called by the transmit procedure
173132451Sroberto *
174132451Sroberto * LOCKCLOCK: If the kernel supports the nanokernel or microkernel
175132451Sroberto * system calls, the leap bits are extracted from the kernel. If there
176132451Sroberto * is a kernel error or the kernel leap bits are set to 11, the NTP leap
177132451Sroberto * bits are set to 11 and the stratum is set to infinity. Otherwise, the
178132451Sroberto * NTP leap bits are set to the kernel leap bits and the stratum is set
179132451Sroberto * as fudged. This behavior does not faithfully follow the
180132451Sroberto * specification, but is probably more appropriate in a multiple-server
181132451Sroberto * national laboratory network.
18254359Sroberto */
18354359Srobertostatic void
18454359Srobertolocal_poll(
18554359Sroberto	int unit,
18654359Sroberto	struct peer *peer
18754359Sroberto	)
18854359Sroberto{
189132451Sroberto#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
190132451Sroberto	struct timex ntv;
191132451Sroberto#endif /* KERNEL_PLL LOCKCLOCK */
19254359Sroberto	struct refclockproc *pp;
19354359Sroberto
19454359Sroberto#if defined(VMS) && defined(VMS_LOCALUNIT)
195132451Sroberto	if (unit == VMS_LOCALUNIT) {
19654359Sroberto		extern void vms_local_poll(struct peer *);
19754359Sroberto
19854359Sroberto		vms_local_poll(peer);
19954359Sroberto		return;
20054359Sroberto	}
201132451Sroberto#endif /* VMS && VMS_LOCALUNIT */
20254359Sroberto	pp = peer->procptr;
20354359Sroberto	pp->polls++;
20454359Sroberto
20554359Sroberto	/*
20654359Sroberto	 * Ramble through the usual filtering and grooming code, which
20754359Sroberto	 * is essentially a no-op and included mostly for pretty
20854359Sroberto	 * billboards. We allow a one-time time adjustment using fudge
20954359Sroberto	 * time1 (s) and a continuous frequency adjustment using fudge
21054359Sroberto	 * time 2 (ppm).
21154359Sroberto	 */
21254359Sroberto	get_systime(&pp->lastrec);
21354359Sroberto	pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time -
21454359Sroberto	    poll_time);
21554359Sroberto	poll_time = current_time;
216132451Sroberto	refclock_process_offset(pp, pp->lastrec, pp->lastrec,
217132451Sroberto	    pp->fudgetime1);
21854359Sroberto
21954359Sroberto	/*
220132451Sroberto	 * If another process is disciplining the system clock, we set
221132451Sroberto	 * the leap bits and quality indicators from the kernel.
22254359Sroberto	 */
223132451Sroberto#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
224132451Sroberto	memset(&ntv,  0, sizeof ntv);
225132451Sroberto	switch (ntp_adjtime(&ntv)) {
226132451Sroberto	case TIME_OK:
227132451Sroberto		pp->leap = LEAP_NOWARNING;
228132451Sroberto		peer->stratum = pp->stratum;
229132451Sroberto		break;
23054359Sroberto
231132451Sroberto	case TIME_INS:
232132451Sroberto		pp->leap = LEAP_ADDSECOND;
233132451Sroberto		peer->stratum = pp->stratum;
234132451Sroberto		break;
23554359Sroberto
236132451Sroberto	case TIME_DEL:
237132451Sroberto		pp->leap = LEAP_DELSECOND;
238132451Sroberto		peer->stratum = pp->stratum;
239132451Sroberto		break;
24054359Sroberto
241132451Sroberto	default:
242132451Sroberto		pp->leap = LEAP_NOTINSYNC;
243132451Sroberto		peer->stratum = STRATUM_UNSPEC;
24454359Sroberto	}
245132451Sroberto	pp->disp = 0;
246132451Sroberto	pp->jitter = 0;
247132451Sroberto#else /* KERNEL_PLL LOCKCLOCK */
248132451Sroberto	pp->leap = LEAP_NOWARNING;
249132451Sroberto	pp->disp = DISPERSION;
250132451Sroberto	pp->jitter = 0;
251132451Sroberto#endif /* KERNEL_PLL LOCKCLOCK */
252106424Sroberto	pp->lastref = pp->lastrec;
25354359Sroberto	refclock_receive(peer);
25454359Sroberto	pp->fudgetime1 = 0;
25554359Sroberto}
256106163Sroberto#else
257106163Srobertoint refclock_local_bs;
25854359Sroberto#endif /* REFCLOCK */
259