kern_ntptime.c revision 21101
12858Swollman/****************************************************************************** 22858Swollman * * 32858Swollman * Copyright (c) David L. Mills 1993, 1994 * 42858Swollman * * 52858Swollman * Permission to use, copy, modify, and distribute this software and its * 62858Swollman * documentation for any purpose and without fee is hereby granted, provided * 72858Swollman * that the above copyright notice appears in all copies and that both the * 82858Swollman * copyright notice and this permission notice appear in supporting * 92858Swollman * documentation, and that the name University of Delaware not be used in * 102858Swollman * advertising or publicity pertaining to distribution of the software * 112858Swollman * without specific, written prior permission. The University of Delaware * 122858Swollman * makes no representations about the suitability this software for any * 132858Swollman * purpose. It is provided "as is" without express or implied warranty. * 142858Swollman * * 152858Swollman ******************************************************************************/ 162858Swollman 172858Swollman/* 182858Swollman * Modification history kern_ntptime.c 192858Swollman * 2021101Sjhay * 24 Sep 94 David L. Mills 2121101Sjhay * Tightened code at exits. 2221101Sjhay * 232858Swollman * 24 Mar 94 David L. Mills 242858Swollman * Revised syscall interface to include new variables for PPS 252858Swollman * time discipline. 262858Swollman * 272858Swollman * 14 Feb 94 David L. Mills 282858Swollman * Added code for external clock 292858Swollman * 302858Swollman * 28 Nov 93 David L. Mills 312858Swollman * Revised frequency scaling to conform with adjusted parameters 322858Swollman * 332858Swollman * 17 Sep 93 David L. Mills 342858Swollman * Created file 352858Swollman */ 362858Swollman/* 372858Swollman * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS 3821101Sjhay * V4.1.1 and V4.1.3 392858Swollman * 402858Swollman * These routines consitute the Network Time Protocol (NTP) interfaces 412858Swollman * for user and daemon application programs. The ntp_gettime() routine 422858Swollman * provides the time, maximum error (synch distance) and estimated error 432858Swollman * (dispersion) to client user application programs. The ntp_adjtime() 442858Swollman * routine is used by the NTP daemon to adjust the system clock to an 452858Swollman * externally derived time. The time offset and related variables set by 462858Swollman * this routine are used by hardclock() to adjust the phase and 472858Swollman * frequency of the phase-lock loop which controls the system clock. 482858Swollman */ 492858Swollman#include <sys/param.h> 502858Swollman#include <sys/systm.h> 5112221Sbde#include <sys/sysproto.h> 522858Swollman#include <sys/kernel.h> 532858Swollman#include <sys/proc.h> 542858Swollman#include <sys/timex.h> 552858Swollman#include <sys/sysctl.h> 562858Swollman 572858Swollman/* 582858Swollman * The following variables are used by the hardclock() routine in the 598876Srgrimes * kern_clock.c module and are described in that module. 602858Swollman */ 612858Swollmanextern int time_state; /* clock state */ 622858Swollmanextern int time_status; /* clock status bits */ 632858Swollmanextern long time_offset; /* time adjustment (us) */ 642858Swollmanextern long time_freq; /* frequency offset (scaled ppm) */ 652858Swollmanextern long time_maxerror; /* maximum error (us) */ 662858Swollmanextern long time_esterror; /* estimated error (us) */ 672858Swollmanextern long time_constant; /* pll time constant */ 682858Swollmanextern long time_precision; /* clock precision (us) */ 692858Swollmanextern long time_tolerance; /* frequency tolerance (scaled ppm) */ 702858Swollman 712858Swollman#ifdef PPS_SYNC 722858Swollman/* 732858Swollman * The following variables are used only if the PPS signal discipline 742858Swollman * is configured in the kernel. 752858Swollman */ 762858Swollmanextern int pps_shift; /* interval duration (s) (shift) */ 772858Swollmanextern long pps_freq; /* pps frequency offset (scaled ppm) */ 782858Swollmanextern long pps_jitter; /* pps jitter (us) */ 792858Swollmanextern long pps_stabil; /* pps stability (scaled ppm) */ 802858Swollmanextern long pps_jitcnt; /* jitter limit exceeded */ 812858Swollmanextern long pps_calcnt; /* calibration intervals */ 822858Swollmanextern long pps_errcnt; /* calibration errors */ 832858Swollmanextern long pps_stbcnt; /* stability limit exceeded */ 842858Swollman#endif /* PPS_SYNC */ 852858Swollman 8612279Sphkstatic int 8712279Sphkntp_sysctl SYSCTL_HANDLER_ARGS 882858Swollman{ 892858Swollman struct timeval atv; 902858Swollman struct ntptimeval ntv; 912858Swollman int s; 922858Swollman 932858Swollman s = splclock(); 942858Swollman#ifdef EXT_CLOCK 952858Swollman /* 962858Swollman * The microtime() external clock routine returns a 972858Swollman * status code. If less than zero, we declare an error 982858Swollman * in the clock status word and return the kernel 992858Swollman * (software) time variable. While there are other 1002858Swollman * places that call microtime(), this is the only place 1012858Swollman * that matters from an application point of view. 1022858Swollman */ 1032858Swollman if (microtime(&atv) < 0) { 1042858Swollman time_status |= STA_CLOCKERR; 1052858Swollman ntv.time = time; 1062858Swollman } else { 1072858Swollman time_status &= ~STA_CLOCKERR; 1082858Swollman } 1092858Swollman#else /* EXT_CLOCK */ 1102858Swollman microtime(&atv); 1112858Swollman#endif /* EXT_CLOCK */ 1122858Swollman ntv.time = atv; 1132858Swollman ntv.maxerror = time_maxerror; 1142858Swollman ntv.esterror = time_esterror; 1152858Swollman splx(s); 1168876Srgrimes 1172858Swollman ntv.time_state = time_state; 1182858Swollman 1192858Swollman /* 1202858Swollman * Status word error decode. If any of these conditions 1212858Swollman * occur, an error is returned, instead of the status 1222858Swollman * word. Most applications will care only about the fact 1232858Swollman * the system clock may not be trusted, not about the 1242858Swollman * details. 1252858Swollman * 1262858Swollman * Hardware or software error 1272858Swollman */ 1282858Swollman if (time_status & (STA_UNSYNC | STA_CLOCKERR)) { 1292858Swollman ntv.time_state = TIME_ERROR; 1302858Swollman } 1312858Swollman 1322858Swollman /* 1332858Swollman * PPS signal lost when either time or frequency 1342858Swollman * synchronization requested 1352858Swollman */ 1362858Swollman if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 1372858Swollman !(time_status & STA_PPSSIGNAL)) { 1382858Swollman ntv.time_state = TIME_ERROR; 1392858Swollman } 1402858Swollman 1412858Swollman /* 1422858Swollman * PPS jitter exceeded when time synchronization 1432858Swollman * requested 1442858Swollman */ 1452858Swollman if (time_status & STA_PPSTIME && 1462858Swollman time_status & STA_PPSJITTER) { 1472858Swollman ntv.time_state = TIME_ERROR; 1482858Swollman } 1492858Swollman 1502858Swollman /* 1512858Swollman * PPS wander exceeded or calibration error when 1522858Swollman * frequency synchronization requested 1532858Swollman */ 1542858Swollman if (time_status & STA_PPSFREQ && 1552858Swollman time_status & (STA_PPSWANDER | STA_PPSERROR)) { 1562858Swollman ntv.time_state = TIME_ERROR; 1572858Swollman } 15812279Sphk return (sysctl_handle_opaque(oidp, &ntv, sizeof ntv, req)); 1592858Swollman} 1602858Swollman 16112279SphkSYSCTL_NODE(_kern, KERN_NTP_PLL, ntp_pll, CTLFLAG_RW, 0, 16212279Sphk "NTP kernel PLL related stuff"); 16312279SphkSYSCTL_PROC(_kern_ntp_pll, NTP_PLL_GETTIME, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD, 16412623Sphk 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", ""); 16512279Sphk 1662858Swollman/* 1672858Swollman * ntp_adjtime() - NTP daemon application interface 1682858Swollman */ 16912221Sbde#ifndef _SYS_SYSPROTO_H_ 1702858Swollmanstruct ntp_adjtime_args { 1712858Swollman struct timex *tp; 1722858Swollman}; 17312221Sbde#endif 1742858Swollman 1752858Swollmanint 1762858Swollmanntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap, int *retval) 1772858Swollman{ 1782858Swollman struct timex ntv; 1792858Swollman int modes; 1802858Swollman int s; 1812858Swollman int error; 1822858Swollman 1832858Swollman error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv)); 1842858Swollman if (error) 1852858Swollman return error; 1862858Swollman 1872858Swollman /* 1882858Swollman * Update selected clock variables - only the superuser can 1892858Swollman * change anything. Note that there is no error checking here on 1902858Swollman * the assumption the superuser should know what it is doing. 1912858Swollman */ 1922858Swollman modes = ntv.modes; 1932858Swollman if ((modes != 0) 1942858Swollman && (error = suser(p->p_cred->pc_ucred, &p->p_acflag))) 1952858Swollman return error; 1962858Swollman 1972858Swollman s = splclock(); 1982858Swollman if (modes & MOD_FREQUENCY) 1992858Swollman#ifdef PPS_SYNC 2002858Swollman time_freq = ntv.freq - pps_freq; 2012858Swollman#else /* PPS_SYNC */ 2022858Swollman time_freq = ntv.freq; 2032858Swollman#endif /* PPS_SYNC */ 2042858Swollman if (modes & MOD_MAXERROR) 2052858Swollman time_maxerror = ntv.maxerror; 2062858Swollman if (modes & MOD_ESTERROR) 2072858Swollman time_esterror = ntv.esterror; 2082858Swollman if (modes & MOD_STATUS) { 2092858Swollman time_status &= STA_RONLY; 2102858Swollman time_status |= ntv.status & ~STA_RONLY; 2112858Swollman } 2122858Swollman if (modes & MOD_TIMECONST) 2132858Swollman time_constant = ntv.constant; 2142858Swollman if (modes & MOD_OFFSET) 2152858Swollman hardupdate(ntv.offset); 2162858Swollman 2172858Swollman /* 2182858Swollman * Retrieve all clock variables 2192858Swollman */ 2202858Swollman if (time_offset < 0) 2212858Swollman ntv.offset = -(-time_offset >> SHIFT_UPDATE); 2222858Swollman else 2232858Swollman ntv.offset = time_offset >> SHIFT_UPDATE; 2242858Swollman#ifdef PPS_SYNC 2252858Swollman ntv.freq = time_freq + pps_freq; 2262858Swollman#else /* PPS_SYNC */ 2272858Swollman ntv.freq = time_freq; 2282858Swollman#endif /* PPS_SYNC */ 2292858Swollman ntv.maxerror = time_maxerror; 2302858Swollman ntv.esterror = time_esterror; 2312858Swollman ntv.status = time_status; 2322858Swollman ntv.constant = time_constant; 2332858Swollman ntv.precision = time_precision; 2342858Swollman ntv.tolerance = time_tolerance; 2352858Swollman#ifdef PPS_SYNC 2362858Swollman ntv.shift = pps_shift; 2372858Swollman ntv.ppsfreq = pps_freq; 2382858Swollman ntv.jitter = pps_jitter >> PPS_AVG; 2392858Swollman ntv.stabil = pps_stabil; 2402858Swollman ntv.calcnt = pps_calcnt; 2412858Swollman ntv.errcnt = pps_errcnt; 2422858Swollman ntv.jitcnt = pps_jitcnt; 2432858Swollman ntv.stbcnt = pps_stbcnt; 2442858Swollman#endif /* PPS_SYNC */ 2452858Swollman (void)splx(s); 2462858Swollman 2472858Swollman error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv)); 2482858Swollman if (!error) { 2492858Swollman /* 2502858Swollman * Status word error decode. See comments in 2512858Swollman * ntp_gettime() routine. 2522858Swollman */ 2532858Swollman retval[0] = time_state; 2542858Swollman if (time_status & (STA_UNSYNC | STA_CLOCKERR)) 2552858Swollman retval[0] = TIME_ERROR; 2562858Swollman if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 2572858Swollman !(time_status & STA_PPSSIGNAL)) 2582858Swollman retval[0] = TIME_ERROR; 2592858Swollman if (time_status & STA_PPSTIME && 2602858Swollman time_status & STA_PPSJITTER) 2612858Swollman retval[0] = TIME_ERROR; 2622858Swollman if (time_status & STA_PPSFREQ && 2632858Swollman time_status & (STA_PPSWANDER | STA_PPSERROR)) 2642858Swollman retval[0] = TIME_ERROR; 2652858Swollman } 2662858Swollman return error; 2672858Swollman} 2682858Swollman 2692858Swollman 270