/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) David L. Mills 1993, 1994 * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appears in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation, and that the name University of Delaware not be used in * advertising or publicity pertaining to distribution of the software * without specific, written prior permission. The University of Delaware * makes no representations about the suitability this software for any * purpose. It is provided "as is" without express or implied warranty. */ /* * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. */ /* * Modification history kern_ntptime.c * * 24 Sep 94 David L. Mills * Tightened code at exits. * * 24 Mar 94 David L. Mills * Revised syscall interface to include new variables for PPS * time discipline. * * 14 Feb 94 David L. Mills * Added code for external clock * * 28 Nov 93 David L. Mills * Revised frequency scaling to conform with adjusted parameters * * 17 Sep 93 David L. Mills * Created file */ /* * ntp_gettime(), ntp_adjtime() - precision time interface * * These routines consitute the Network Time Protocol (NTP) interfaces * for user and daemon application programs. The ntp_gettime() routine * provides the time, maximum error (synch distance) and estimated error * (dispersion) to client user application programs. The ntp_adjtime() * routine is used by the NTP daemon to adjust the system clock to an * externally derived time. The time offset and related variables set by * this routine are used by clock() to adjust the phase and * frequency of the phase-lock loop which controls the system clock. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * ntp_gettime() - NTP user application interface */ int ntp_gettime(struct ntptimeval *tp) { timestruc_t tod; struct ntptimeval ntv; model_t datamodel = get_udatamodel(); gethrestime(&tod); if (tod.tv_sec > TIME32_MAX) return (set_errno(EOVERFLOW)); ntv.time.tv_sec = tod.tv_sec; ntv.time.tv_usec = tod.tv_nsec / (NANOSEC / MICROSEC); ntv.maxerror = time_maxerror; ntv.esterror = time_esterror; if (datamodel == DATAMODEL_NATIVE) { if (copyout(&ntv, tp, sizeof (ntv))) return (set_errno(EFAULT)); } else { struct ntptimeval32 ntv32; if (TIMEVAL_OVERFLOW(&ntv.time)) return (set_errno(EOVERFLOW)); TIMEVAL_TO_TIMEVAL32(&ntv32.time, &ntv.time); ntv32.maxerror = ntv.maxerror; ntv32.esterror = ntv.esterror; if (copyout(&ntv32, tp, sizeof (ntv32))) return (set_errno(EFAULT)); } /* * Status word error decode. If any of these conditions * occur, an error is returned, instead of the status * word. Most applications will care only about the fact * the system clock may not be trusted, not about the * details. * * Hardware or software error */ if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || /* * PPS signal lost when either time or frequency * synchronization requested */ (time_status & (STA_PPSFREQ | STA_PPSTIME) && !(time_status & STA_PPSSIGNAL)) || /* * PPS jitter exceeded when time synchronization * requested */ (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) || /* * PPS wander exceeded or calibration error when * frequency synchronization requested */ (time_status & STA_PPSFREQ && time_status & (STA_PPSWANDER | STA_PPSERROR))) { return (TIME_ERROR); } return (time_state); } /* * ntp_adjtime() - NTP daemon application interface */ int ntp_adjtime(struct timex *tp) { struct timex ntv; int modes; if (copyin(tp, &ntv, sizeof (ntv))) return (set_errno(EFAULT)); /* * Update selected clock variables - only privileged users can * change anything. Note that there is no error checking here on * the assumption privileged users know what they're doing. */ modes = ntv.modes; if (modes != 0 && secpolicy_settime(CRED()) != 0) return (set_errno(EPERM)); /* * If the time constant is being set, validate it first so that * no changes are made if it is out of range. */ if ((modes & MOD_TIMECONST) && (ntv.constant < 0 || ntv.constant > 30)) return (set_errno(EINVAL)); mutex_enter(&tod_lock); if (modes & MOD_MAXERROR) time_maxerror = ntv.maxerror; if (modes & MOD_ESTERROR) time_esterror = ntv.esterror; if (modes & MOD_STATUS) { time_status &= STA_RONLY; time_status |= ntv.status & ~STA_RONLY; } if (modes & MOD_TIMECONST) time_constant = ntv.constant; if (modes & MOD_OFFSET) clock_update(ntv.offset); /* * clock_update() updates time_freq so keep MOD_FREQUENCY after * MOD_OFFSET. */ if (modes & MOD_FREQUENCY) { time_freq = ntv.freq - pps_freq; /* * If the frequency offset was adjusted, then set tod_needsync * since it implies someone is watching over the system clock. */ int s = hr_clock_lock(); tod_needsync = 1; hr_clock_unlock(s); } /* * Retrieve all clock variables */ ntv.offset = time_offset / SCALE_UPDATE; ntv.freq = time_freq + pps_freq; ntv.maxerror = time_maxerror; ntv.esterror = time_esterror; ntv.status = time_status; ntv.constant = time_constant; ntv.precision = time_precision; ntv.tolerance = time_tolerance; ntv.shift = pps_shift; ntv.ppsfreq = pps_freq; ntv.jitter = pps_jitter >> PPS_AVG; ntv.stabil = pps_stabil; ntv.calcnt = pps_calcnt; ntv.errcnt = pps_errcnt; ntv.jitcnt = pps_jitcnt; ntv.stbcnt = pps_stbcnt; mutex_exit(&tod_lock); if (copyout(&ntv, tp, sizeof (ntv))) return (set_errno(EFAULT)); /* * Status word error decode. See comments in * ntp_gettime() routine. */ if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || (time_status & (STA_PPSFREQ | STA_PPSTIME) && !(time_status & STA_PPSSIGNAL)) || (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) || (time_status & STA_PPSFREQ && time_status & (STA_PPSWANDER | STA_PPSERROR))) return (TIME_ERROR); return (time_state); }