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