1 2 /* 3 * refclock_local - local pseudo-clock driver 4 * 5 * wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT 6 */ 7 #ifdef HAVE_CONFIG_H 8 #include <config.h> 9 #endif 10 11 #ifdef REFCLOCK 12 13 #include "ntpd.h" 14 #include "ntp_refclock.h" 15 #include "ntp_stdlib.h" 16 17 #include <stdio.h> 18 #include <ctype.h> 19 20 #ifdef KERNEL_PLL 21 #include "ntp_syscall.h" 22 #endif 23 24 /* 25 * This is a hack to allow a machine to use its own system clock as a 26 * reference clock, i.e., to free-run using no outside clock discipline 27 * source. This is useful if you want to use NTP in an isolated 28 * environment with no radio clock or NIST modem available. Pick a 29 * machine that you figure has a good clock oscillator and configure it 30 * with this driver. Set the clock using the best means available, like 31 * eyeball-and-wristwatch. Then, point all the other machines at this 32 * one or use broadcast (not multicast) mode to distribute time. 33 * 34 * Another application for this driver is if you want to use a 35 * particular server's clock as the clock of last resort when all other 36 * normal synchronization sources have gone away. This is especially 37 * useful if that server has an ovenized oscillator. For this you would 38 * configure this driver at a higher stratum (say 5) to prevent the 39 * server's stratum from falling below that. 40 * 41 * A third application for this driver is when an external discipline 42 * source is available, such as the NIST "lockclock" program, which 43 * synchronizes the local clock via a telephone modem and the NIST 44 * Automated Computer Time Service (ACTS), or the Digital Time 45 * Synchronization Service (DTSS), which runs on DCE machines. In this 46 * case the stratum should be set at zero, indicating a bona fide 47 * stratum-1 source. Exercise some caution with this, since there is no 48 * easy way to telegraph via NTP that something might be wrong in the 49 * discipline source itself. In the case of DTSS, the local clock can 50 * have a rather large jitter, depending on the interval between 51 * corrections and the intrinsic frequency error of the clock 52 * oscillator. In extreme cases, this can cause clients to exceed the 53 * 128-ms slew window and drop off the NTP subnet. 54 * 55 * THis driver includes provisions to telegraph synchronization state 56 * and related variables by means of kernel variables with specially 57 * modified kernels. This is done using the ntp_adjtime() syscall. 58 * In the cases where another protocol or device synchronizes the local 59 * host, the data given to the kernel can be slurped up by this driver 60 * and distributed to clients by ordinary NTP messaging. 61 * 62 * In the default mode the behavior of the clock selection algorithm is 63 * modified when this driver is in use. The algorithm is designed so 64 * that this driver will never be selected unless no other discipline 65 * source is available. This can be overriden with the prefer keyword of 66 * the server configuration command, in which case only this driver will 67 * be selected for synchronization and all other discipline sources will 68 * be ignored. This behavior is intended for use when an external 69 * discipline source controls the system clock. 70 * 71 * Fudge Factors 72 * 73 * The stratum for this driver set at 5 by default, but it can be 74 * changed by the fudge command and/or the ntpdc utility. The reference 75 * ID is "LCL" by default, but can be changed using the same mechanism. 76 * *NEVER* configure this driver to operate at a stratum which might 77 * possibly disrupt a client with access to a bona fide primary server, 78 * unless the local clock oscillator is reliably disciplined by another 79 * source. *NEVER NEVER* configure a server which might devolve to an 80 * undisciplined local clock to use multicast mode. Always remember that 81 * an improperly configured local clock driver let loose in the Internet 82 * can cause very serious disruption. This is why most of us who care 83 * about good time use cryptographic authentication. 84 * 85 * This driver provides a mechanism to trim the local clock in both time 86 * and frequency, as well as a way to manipulate the leap bits. The 87 * fudge time1 parameter adjusts the time, in seconds, and the fudge 88 * time2 parameter adjusts the frequency, in ppm. The fudge time1 89 * parameter is additive; that is, it adds an increment to the current 90 * time. The fudge time2 parameter directly sets the frequency. 91 */ 92 /* 93 * Local interface definitions 94 */ 95 #define PRECISION (-7) /* about 10 ms precision */ 96 #if defined(VMS) && defined(VMS_LOCALUNIT) 97 #define REFID "LCLv" /* reference ID */ 98 #else /* VMS VMS_LOCALUNIT */ 99 #define REFID "LCL\0" /* reference ID */ 100 #endif /* VMS VMS_LOCALUNIT */ 101 #define DESCRIPTION "Undisciplined local clock" /* WRU */ 102 103 #define STRATUM 5 /* default stratum */ 104 #define DISPERSION .01 /* default dispersion (10 ms) */ 105 106 /* 107 * Imported from the timer module 108 */ 109 extern u_long current_time; 110 111 /* 112 * Imported from ntp_proto 113 */ 114 extern s_char sys_precision; 115 116 #ifdef KERNEL_PLL 117 /* 118 * Imported from ntp_loopfilter 119 */ 120 extern int pll_control; /* kernel pll control */ 121 extern int kern_enable; /* kernel pll enabled */ 122 extern int ext_enable; /* external clock enable */ 123 #endif /* KERNEL_PLL */ 124 125 /* 126 * Function prototypes 127 */ 128 static int local_start P((int, struct peer *)); 129 static void local_poll P((int, struct peer *)); 130 131 /* 132 * Local variables 133 */ 134 static u_long poll_time; /* last time polled */ 135 136 /* 137 * Transfer vector 138 */ 139 struct refclock refclock_local = { 140 local_start, /* start up driver */ 141 noentry, /* shut down driver (not used) */ 142 local_poll, /* transmit poll message */ 143 noentry, /* not used (old lcl_control) */ 144 noentry, /* initialize driver (not used) */ 145 noentry, /* not used (old lcl_buginfo) */ 146 NOFLAGS /* not used */ 147 }; 148 149 150 /* 151 * local_start - start up the clock 152 */ 153 static int 154 local_start( 155 int unit, 156 struct peer *peer 157 ) 158 { 159 struct refclockproc *pp; 160 161 pp = peer->procptr; 162 163 /* 164 * Initialize miscellaneous variables 165 */ 166 peer->precision = sys_precision; 167 pp->leap = LEAP_NOTINSYNC; 168 peer->stratum = STRATUM; 169 pp->stratum = STRATUM; 170 pp->clockdesc = DESCRIPTION; 171 memcpy(&pp->refid, "INIT", 4); 172 poll_time = current_time; 173 return (1); 174 } 175 176 177 /* 178 * local_poll - called by the transmit procedure 179 * 180 * LOCKCLOCK: If the kernel supports the nanokernel or microkernel 181 * system calls, the leap bits are extracted from the kernel. If there 182 * is a kernel error or the kernel leap bits are set to 11, the NTP leap 183 * bits are set to 11 and the stratum is set to infinity. Otherwise, the 184 * NTP leap bits are set to the kernel leap bits and the stratum is set 185 * as fudged. This behavior does not faithfully follow the 186 * specification, but is probably more appropriate in a multiple-server 187 * national laboratory network. 188 */ 189 static void 190 local_poll( 191 int unit, 192 struct peer *peer 193 ) 194 { 195 #if defined(KERNEL_PLL) && defined(LOCKCLOCK) 196 struct timex ntv; 197 #endif /* KERNEL_PLL LOCKCLOCK */ 198 struct refclockproc *pp; 199 200 #if defined(VMS) && defined(VMS_LOCALUNIT) 201 if (unit == VMS_LOCALUNIT) { 202 extern void vms_local_poll(struct peer *); 203 204 vms_local_poll(peer); 205 return; 206 } 207 #endif /* VMS && VMS_LOCALUNIT */ 208 pp = peer->procptr; 209 pp->polls++; 210 211 /* 212 * Ramble through the usual filtering and grooming code, which 213 * is essentially a no-op and included mostly for pretty 214 * billboards. We allow a one-time time adjustment using fudge 215 * time1 (s) and a continuous frequency adjustment using fudge 216 * time 2 (ppm). 217 */ 218 get_systime(&pp->lastrec); 219 pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time - 220 poll_time); 221 poll_time = current_time; 222 refclock_process_offset(pp, pp->lastrec, pp->lastrec, 223 pp->fudgetime1); 224 225 /* 226 * If another process is disciplining the system clock, we set 227 * the leap bits and quality indicators from the kernel. 228 */ 229 #if defined(KERNEL_PLL) && defined(LOCKCLOCK) 230 memset(&ntv, 0, sizeof ntv); 231 switch (ntp_adjtime(&ntv)) { 232 case TIME_OK: 233 pp->leap = LEAP_NOWARNING; 234 peer->stratum = pp->stratum; 235 break; 236 237 case TIME_INS: 238 pp->leap = LEAP_ADDSECOND; 239 peer->stratum = pp->stratum; 240 break; 241 242 case TIME_DEL: 243 pp->leap = LEAP_DELSECOND; 244 peer->stratum = pp->stratum; 245 break; 246 247 default: 248 pp->leap = LEAP_NOTINSYNC; 249 peer->stratum = STRATUM_UNSPEC; 250 } 251 pp->disp = 0; 252 pp->jitter = 0; 253 #else /* KERNEL_PLL LOCKCLOCK */ 254 pp->leap = LEAP_NOWARNING; 255 pp->disp = DISPERSION; 256 pp->jitter = 0; 257 #endif /* KERNEL_PLL LOCKCLOCK */ 258 pp->lastref = pp->lastrec; 259 refclock_receive(peer); 260 pp->fudgetime1 = 0; 261 } 262 #else 263 int refclock_local_bs; 264 #endif /* REFCLOCK */ 265