summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/refclock_local.c
blob: d816c55c128121a63a2cd7e2c2f1a9e8b8cca92e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

/*
 * refclock_local - local pseudo-clock driver
 *
 * wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef REFCLOCK

#include "ntpd.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"

#include <stdio.h>
#include <ctype.h>

#ifdef KERNEL_PLL
#include "ntp_syscall.h"
#endif

/*
 * This is a hack to allow a machine to use its own system clock as a
 * reference clock, i.e., to free-run using no outside clock discipline
 * source. Note that the clock selection algorithm will not select this
 * driver unless all other sources of synchronization have been lost.
 * This is useful if you want to use NTP in an isolated environment
 * with no radio clock or NIST modem available. Pick a machine that you
 * figure has a good clock oscillator and configure it with this
 * driver. Set the clock using the best means available, like
 * eyeball-and-wristwatch. Then, point all the other machines at this
 * one or use broadcast (not multicast) mode to distribute time.
 *
 * Another application for this driver is if you want to use a
 * particular server's clock as the clock of last resort when all other
 * normal synchronization sources have gone away. This is especially
 * useful if that server has an ovenized oscillator. However, the
 * preferred was to do this is using orphan mode. See the documentation.
 *
 * A third application for this driver is when an external discipline
 * source is available, such as the NIST "lockclock" program, which
 * synchronizes the local clock via a telephone modem and the NIST
 * Automated Computer Time Service (ACTS), or the Digital Time
 * Synchronization Service (DTSS), which runs on DCE machines. In this
 * case the stratum should be set at zero, indicating a bona fide
 * stratum-1 source. Exercise some caution with this, since there is no
 * easy way to telegraph via NTP that something might be wrong in the
 * discipline source itself. In the case of DTSS, the local clock can
 * have a rather large jitter, depending on the interval between
 * corrections and the intrinsic frequency error of the clock
 * oscillator. In extreme cases, this can cause clients to exceed the
 * 128-ms slew window and drop off the NTP subnet.
 *
 * Fudge Factors
 *
 * None currently supported.
 */
/*
 * Local interface definitions
 */
#define PRECISION	(-7)	/* about 10 ms precision */
#define DESCRIPTION "Undisciplined local clock" /* WRU */
#define STRATUM 	5	/* default stratum */
#define DISPERSION	.01	/* default dispersion (10 ms) */

/*
 * Imported from the timer module
 */
extern u_long current_time;

/*
 * Imported from ntp_proto
 */
extern s_char sys_precision;

/*
 * Function prototypes
 */
static	int local_start (int, struct peer *);
static	void	local_poll	(int, struct peer *);

/*
 * Local variables
 */
static	u_long poll_time;	/* last time polled */
	
/*
 * Transfer vector
 */
struct	refclock refclock_local = {
	local_start,		/* start up driver */
	noentry,		/* shut down driver (not used) */
	local_poll,	 	/* transmit poll message */
	noentry,		/* not used (old lcl_control) */
	noentry,		/* initialize driver (not used) */
	noentry,		/* not used (old lcl_buginfo) */
	NOFLAGS 		/* not used */
};


/*
 * local_start - start up the clock
 */
static int
local_start(
	int unit,
	struct peer *peer
	)
{
	struct refclockproc *pp;

	pp = peer->procptr;

	/*
	 * Initialize miscellaneous variables
	 */
	peer->precision = sys_precision;
	pp->leap = LEAP_NOTINSYNC;
	peer->stratum = STRATUM;
	pp->stratum = STRATUM;
	pp->clockdesc = DESCRIPTION;
	memcpy(&pp->refid, "LOCL", 4);
	poll_time = current_time;
	return (1);
}


/*
 * local_poll - called by the transmit procedure
 *
 * LOCKCLOCK: If the kernel supports the nanokernel or microkernel
 * system calls, the leap bits are extracted from the kernel. If there
 * is a kernel error or the kernel leap bits are set to 11, the NTP leap
 * bits are set to 11 and the stratum is set to infinity. Otherwise, the
 * NTP leap bits are set to the kernel leap bits and the stratum is set
 * as fudged. This behavior does not faithfully follow the
 * specification, but is probably more appropriate in a multiple-server
 * national laboratory network.
 */
static void
local_poll(
	int unit,
	struct peer *peer
	)
{
#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
	struct timex ntv;
#endif /* KERNEL_PLL LOCKCLOCK */
	struct refclockproc *pp;

	/*
	 * Do no evil unless the house is dark or lit with our own lamp.
	 */
	if (!(sys_peer == NULL || sys_peer == peer))
		return;

#if defined(VMS) && defined(VMS_LOCALUNIT)
	if (unit == VMS_LOCALUNIT) {
		extern void vms_local_poll(struct peer *);

		vms_local_poll(peer);
		return;
	}
#endif /* VMS && VMS_LOCALUNIT */

	pp = peer->procptr;
	pp->polls++;

	/*
	 * Ramble through the usual filtering and grooming code, which
	 * is essentially a no-op and included mostly for pretty
	 * billboards.
	 */
	poll_time = current_time;
	refclock_process_offset(pp, pp->lastrec, pp->lastrec, 0);

	/*
	 * If another process is disciplining the system clock, we set
	 * the leap bits and quality indicators from the kernel.
	 */
#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
	memset(&ntv,  0, sizeof ntv);
	switch (ntp_adjtime(&ntv)) {
	case TIME_OK:
		pp->leap = LEAP_NOWARNING;
		peer->stratum = pp->stratum;
		break;

	case TIME_INS:
		pp->leap = LEAP_ADDSECOND;
		peer->stratum = pp->stratum;
		break;

	case TIME_DEL:
		pp->leap = LEAP_DELSECOND;
		peer->stratum = pp->stratum;
		break;

	default:
		pp->leap = LEAP_NOTINSYNC;
		peer->stratum = STRATUM_UNSPEC;
	}
	pp->disp = 0;
	pp->jitter = 0;
#else /* KERNEL_PLL LOCKCLOCK */
	pp->disp = DISPERSION;
	pp->jitter = 0;
#endif /* KERNEL_PLL LOCKCLOCK */
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
}
#else
int refclock_local_bs;
#endif /* REFCLOCK */
OpenPOWER on IntegriCloud