1 1.6 christos /* $NetBSD: refclock_local.c,v 1.7 2024/08/18 20:47:18 christos Exp $ */ 2 1.1 kardel 3 1.1 kardel 4 1.1 kardel /* 5 1.1 kardel * refclock_local - local pseudo-clock driver 6 1.1 kardel * 7 1.1 kardel * wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT 8 1.1 kardel */ 9 1.1 kardel #ifdef HAVE_CONFIG_H 10 1.1 kardel #include <config.h> 11 1.1 kardel #endif 12 1.1 kardel 13 1.1 kardel #ifdef REFCLOCK 14 1.1 kardel 15 1.1 kardel #include "ntpd.h" 16 1.1 kardel #include "ntp_refclock.h" 17 1.1 kardel #include "ntp_stdlib.h" 18 1.1 kardel 19 1.1 kardel #include <stdio.h> 20 1.1 kardel #include <ctype.h> 21 1.1 kardel 22 1.1 kardel #ifdef KERNEL_PLL 23 1.1 kardel #include "ntp_syscall.h" 24 1.1 kardel #endif 25 1.1 kardel 26 1.1 kardel /* 27 1.1 kardel * This is a hack to allow a machine to use its own system clock as a 28 1.1 kardel * reference clock, i.e., to free-run using no outside clock discipline 29 1.1 kardel * source. Note that the clock selection algorithm will not select this 30 1.1 kardel * driver unless all other sources of synchronization have been lost. 31 1.1 kardel * This is useful if you want to use NTP in an isolated environment 32 1.1 kardel * with no radio clock or NIST modem available. Pick a machine that you 33 1.1 kardel * figure has a good clock oscillator and configure it with this 34 1.1 kardel * driver. Set the clock using the best means available, like 35 1.1 kardel * eyeball-and-wristwatch. Then, point all the other machines at this 36 1.1 kardel * one or use broadcast (not multicast) mode to distribute time. 37 1.1 kardel * 38 1.1 kardel * Another application for this driver is if you want to use a 39 1.1 kardel * particular server's clock as the clock of last resort when all other 40 1.1 kardel * normal synchronization sources have gone away. This is especially 41 1.1 kardel * useful if that server has an ovenized oscillator. However, the 42 1.1 kardel * preferred was to do this is using orphan mode. See the documentation. 43 1.1 kardel * 44 1.1 kardel * A third application for this driver is when an external discipline 45 1.1 kardel * source is available, such as the NIST "lockclock" program, which 46 1.1 kardel * synchronizes the local clock via a telephone modem and the NIST 47 1.1 kardel * Automated Computer Time Service (ACTS), or the Digital Time 48 1.1 kardel * Synchronization Service (DTSS), which runs on DCE machines. In this 49 1.1 kardel * case the stratum should be set at zero, indicating a bona fide 50 1.1 kardel * stratum-1 source. Exercise some caution with this, since there is no 51 1.1 kardel * easy way to telegraph via NTP that something might be wrong in the 52 1.1 kardel * discipline source itself. In the case of DTSS, the local clock can 53 1.1 kardel * have a rather large jitter, depending on the interval between 54 1.1 kardel * corrections and the intrinsic frequency error of the clock 55 1.1 kardel * oscillator. In extreme cases, this can cause clients to exceed the 56 1.1 kardel * 128-ms slew window and drop off the NTP subnet. 57 1.1 kardel * 58 1.1 kardel * Fudge Factors 59 1.1 kardel * 60 1.4 christos * None currently supported. 61 1.1 kardel */ 62 1.1 kardel /* 63 1.1 kardel * Local interface definitions 64 1.1 kardel */ 65 1.1 kardel #define PRECISION (-7) /* about 10 ms precision */ 66 1.1 kardel #define DESCRIPTION "Undisciplined local clock" /* WRU */ 67 1.1 kardel #define STRATUM 5 /* default stratum */ 68 1.1 kardel #define DISPERSION .01 /* default dispersion (10 ms) */ 69 1.1 kardel 70 1.1 kardel /* 71 1.1 kardel * Imported from the timer module 72 1.1 kardel */ 73 1.1 kardel extern u_long current_time; 74 1.1 kardel 75 1.1 kardel /* 76 1.1 kardel * Imported from ntp_proto 77 1.1 kardel */ 78 1.1 kardel extern s_char sys_precision; 79 1.1 kardel 80 1.1 kardel /* 81 1.1 kardel * Function prototypes 82 1.1 kardel */ 83 1.1 kardel static int local_start (int, struct peer *); 84 1.1 kardel static void local_poll (int, struct peer *); 85 1.1 kardel 86 1.1 kardel /* 87 1.1 kardel * Local variables 88 1.1 kardel */ 89 1.1 kardel static u_long poll_time; /* last time polled */ 90 1.1 kardel 91 1.1 kardel /* 92 1.1 kardel * Transfer vector 93 1.1 kardel */ 94 1.1 kardel struct refclock refclock_local = { 95 1.1 kardel local_start, /* start up driver */ 96 1.1 kardel noentry, /* shut down driver (not used) */ 97 1.1 kardel local_poll, /* transmit poll message */ 98 1.1 kardel noentry, /* not used (old lcl_control) */ 99 1.1 kardel noentry, /* initialize driver (not used) */ 100 1.1 kardel noentry, /* not used (old lcl_buginfo) */ 101 1.1 kardel NOFLAGS /* not used */ 102 1.1 kardel }; 103 1.1 kardel 104 1.1 kardel 105 1.1 kardel /* 106 1.1 kardel * local_start - start up the clock 107 1.1 kardel */ 108 1.1 kardel static int 109 1.1 kardel local_start( 110 1.1 kardel int unit, 111 1.1 kardel struct peer *peer 112 1.1 kardel ) 113 1.1 kardel { 114 1.1 kardel struct refclockproc *pp; 115 1.1 kardel 116 1.1 kardel pp = peer->procptr; 117 1.1 kardel 118 1.1 kardel /* 119 1.1 kardel * Initialize miscellaneous variables 120 1.1 kardel */ 121 1.1 kardel peer->precision = sys_precision; 122 1.1 kardel pp->leap = LEAP_NOTINSYNC; 123 1.1 kardel peer->stratum = STRATUM; 124 1.1 kardel pp->stratum = STRATUM; 125 1.1 kardel pp->clockdesc = DESCRIPTION; 126 1.1 kardel memcpy(&pp->refid, "LOCL", 4); 127 1.1 kardel poll_time = current_time; 128 1.1 kardel return (1); 129 1.1 kardel } 130 1.1 kardel 131 1.1 kardel 132 1.1 kardel /* 133 1.1 kardel * local_poll - called by the transmit procedure 134 1.1 kardel * 135 1.1 kardel * LOCKCLOCK: If the kernel supports the nanokernel or microkernel 136 1.1 kardel * system calls, the leap bits are extracted from the kernel. If there 137 1.1 kardel * is a kernel error or the kernel leap bits are set to 11, the NTP leap 138 1.1 kardel * bits are set to 11 and the stratum is set to infinity. Otherwise, the 139 1.1 kardel * NTP leap bits are set to the kernel leap bits and the stratum is set 140 1.1 kardel * as fudged. This behavior does not faithfully follow the 141 1.1 kardel * specification, but is probably more appropriate in a multiple-server 142 1.1 kardel * national laboratory network. 143 1.1 kardel */ 144 1.1 kardel static void 145 1.1 kardel local_poll( 146 1.1 kardel int unit, 147 1.1 kardel struct peer *peer 148 1.1 kardel ) 149 1.1 kardel { 150 1.1 kardel #if defined(KERNEL_PLL) && defined(LOCKCLOCK) 151 1.1 kardel struct timex ntv; 152 1.1 kardel #endif /* KERNEL_PLL LOCKCLOCK */ 153 1.1 kardel struct refclockproc *pp; 154 1.1 kardel 155 1.1 kardel /* 156 1.1 kardel * Do no evil unless the house is dark or lit with our own lamp. 157 1.1 kardel */ 158 1.1 kardel if (!(sys_peer == NULL || sys_peer == peer)) 159 1.1 kardel return; 160 1.1 kardel 161 1.1 kardel #if defined(VMS) && defined(VMS_LOCALUNIT) 162 1.1 kardel if (unit == VMS_LOCALUNIT) { 163 1.1 kardel extern void vms_local_poll(struct peer *); 164 1.1 kardel 165 1.1 kardel vms_local_poll(peer); 166 1.1 kardel return; 167 1.1 kardel } 168 1.1 kardel #endif /* VMS && VMS_LOCALUNIT */ 169 1.1 kardel 170 1.1 kardel pp = peer->procptr; 171 1.1 kardel pp->polls++; 172 1.1 kardel 173 1.1 kardel /* 174 1.1 kardel * Ramble through the usual filtering and grooming code, which 175 1.1 kardel * is essentially a no-op and included mostly for pretty 176 1.4 christos * billboards. 177 1.1 kardel */ 178 1.1 kardel poll_time = current_time; 179 1.1 kardel refclock_process_offset(pp, pp->lastrec, pp->lastrec, 0); 180 1.1 kardel 181 1.1 kardel /* 182 1.1 kardel * If another process is disciplining the system clock, we set 183 1.1 kardel * the leap bits and quality indicators from the kernel. 184 1.1 kardel */ 185 1.1 kardel #if defined(KERNEL_PLL) && defined(LOCKCLOCK) 186 1.1 kardel memset(&ntv, 0, sizeof ntv); 187 1.1 kardel switch (ntp_adjtime(&ntv)) { 188 1.1 kardel case TIME_OK: 189 1.1 kardel pp->leap = LEAP_NOWARNING; 190 1.1 kardel peer->stratum = pp->stratum; 191 1.1 kardel break; 192 1.1 kardel 193 1.1 kardel case TIME_INS: 194 1.1 kardel pp->leap = LEAP_ADDSECOND; 195 1.1 kardel peer->stratum = pp->stratum; 196 1.1 kardel break; 197 1.1 kardel 198 1.1 kardel case TIME_DEL: 199 1.1 kardel pp->leap = LEAP_DELSECOND; 200 1.1 kardel peer->stratum = pp->stratum; 201 1.1 kardel break; 202 1.1 kardel 203 1.1 kardel default: 204 1.1 kardel pp->leap = LEAP_NOTINSYNC; 205 1.1 kardel peer->stratum = STRATUM_UNSPEC; 206 1.1 kardel } 207 1.1 kardel pp->disp = 0; 208 1.1 kardel pp->jitter = 0; 209 1.1 kardel #else /* KERNEL_PLL LOCKCLOCK */ 210 1.5 christos pp->leap = LEAP_NOWARNING; 211 1.1 kardel pp->disp = DISPERSION; 212 1.1 kardel pp->jitter = 0; 213 1.1 kardel #endif /* KERNEL_PLL LOCKCLOCK */ 214 1.1 kardel pp->lastref = pp->lastrec; 215 1.1 kardel refclock_receive(peer); 216 1.1 kardel } 217 1.1 kardel #else 218 1.7 christos NONEMPTY_TRANSLATION_UNIT 219 1.1 kardel #endif /* REFCLOCK */ 220