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 127.0.0.1 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 #define DESCRIPTION "Undisciplined local clock" /* WRU */ 97 #define STRATUM 5 /* default stratum */ 98 #define DISPERSION .01 /* default dispersion (10 ms) */ 99 100 /* 101 * Imported from the timer module 102 */ 103 extern u_long current_time; 104 105 /* 106 * Imported from ntp_proto 107 */ 108 extern s_char sys_precision; 109 110 #ifdef KERNEL_PLL 111 /* 112 * Imported from ntp_loopfilter 113 */ 114 extern int pll_control; /* kernel pll control */ 115 extern int kern_enable; /* kernel pll enabled */ 116 extern int ext_enable; /* external clock enable */ 117 #endif /* KERNEL_PLL */ 118 119 /* 120 * Function prototypes 121 */ 122 static int local_start P((int, struct peer *)); 123 static void local_poll P((int, struct peer *)); 124 125 /* 126 * Local variables 127 */ 128 static u_long poll_time; /* last time polled */ 129 130 /* 131 * Transfer vector 132 */ 133 struct refclock refclock_local = { 134 local_start, /* start up driver */ 135 noentry, /* shut down driver (not used) */ 136 local_poll, /* transmit poll message */ 137 noentry, /* not used (old lcl_control) */ 138 noentry, /* initialize driver (not used) */ 139 noentry, /* not used (old lcl_buginfo) */ 140 NOFLAGS /* not used */ 141 }; 142 143 144 /* 145 * local_start - start up the clock 146 */ 147 static int 148 local_start( 149 int unit, 150 struct peer *peer 151 ) 152 { 153 struct refclockproc *pp; 154 155 pp = peer->procptr; 156 157 /* 158 * Initialize miscellaneous variables 159 */ 160 peer->precision = sys_precision; 161 pp->leap = LEAP_NOTINSYNC; 162 peer->stratum = STRATUM; 163 pp->stratum = STRATUM; 164 pp->clockdesc = DESCRIPTION; 165 memcpy(&pp->refid, "LOCL", 4); 166 poll_time = current_time; 167 return (1); 168 } 169 170 171 /* 172 * local_poll - called by the transmit procedure 173 * 174 * LOCKCLOCK: If the kernel supports the nanokernel or microkernel 175 * system calls, the leap bits are extracted from the kernel. If there 176 * is a kernel error or the kernel leap bits are set to 11, the NTP leap 177 * bits are set to 11 and the stratum is set to infinity. Otherwise, the 178 * NTP leap bits are set to the kernel leap bits and the stratum is set 179 * as fudged. This behavior does not faithfully follow the 180 * specification, but is probably more appropriate in a multiple-server 181 * national laboratory network. 182 */ 183 static void 184 local_poll( 185 int unit, 186 struct peer *peer 187 ) 188 { 189 #if defined(KERNEL_PLL) && defined(LOCKCLOCK) 190 struct timex ntv; 191 #endif /* KERNEL_PLL LOCKCLOCK */ 192 struct refclockproc *pp; 193 194 #if defined(VMS) && defined(VMS_LOCALUNIT) 195 if (unit == VMS_LOCALUNIT) { 196 extern void vms_local_poll(struct peer *); 197 198 vms_local_poll(peer); 199 return; 200 } 201 #endif /* VMS && VMS_LOCALUNIT */ 202 pp = peer->procptr; 203 pp->polls++; 204 205 /* 206 * Ramble through the usual filtering and grooming code, which 207 * is essentially a no-op and included mostly for pretty 208 * billboards. We allow a one-time time adjustment using fudge 209 * time1 (s) and a continuous frequency adjustment using fudge 210 * time 2 (ppm). 211 */ 212 get_systime(&pp->lastrec); 213 pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time - 214 poll_time); 215 poll_time = current_time; 216 refclock_process_offset(pp, pp->lastrec, pp->lastrec, 217 pp->fudgetime1); 218 219 /* 220 * If another process is disciplining the system clock, we set 221 * the leap bits and quality indicators from the kernel. 222 */ 223 #if defined(KERNEL_PLL) && defined(LOCKCLOCK) 224 memset(&ntv, 0, sizeof ntv); 225 switch (ntp_adjtime(&ntv)) { 226 case TIME_OK: 227 pp->leap = LEAP_NOWARNING; 228 peer->stratum = pp->stratum; 229 break; 230 231 case TIME_INS: 232 pp->leap = LEAP_ADDSECOND; 233 peer->stratum = pp->stratum; 234 break; 235 236 case TIME_DEL: 237 pp->leap = LEAP_DELSECOND; 238 peer->stratum = pp->stratum; 239 break; 240 241 default: 242 pp->leap = LEAP_NOTINSYNC; 243 peer->stratum = STRATUM_UNSPEC; 244 } 245 pp->disp = 0; 246 pp->jitter = 0; 247 #else /* KERNEL_PLL LOCKCLOCK */ 248 pp->leap = LEAP_NOWARNING; 249 pp->disp = DISPERSION; 250 pp->jitter = 0; 251 #endif /* KERNEL_PLL LOCKCLOCK */ 252 pp->lastref = pp->lastrec; 253 refclock_receive(peer); 254 pp->fudgetime1 = 0; 255 } 256 #else 257 int refclock_local_bs; 258 #endif /* REFCLOCK */ 259