xref: /illumos-gate/usr/src/uts/common/syscall/ntptime.c (revision c538cdc56b01e46a42335d3f8d315c44ecf91ac9)
17c478bd9Sstevel@tonic-gate /*
24e98c196Sblu  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) David L. Mills 1993, 1994
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
107c478bd9Sstevel@tonic-gate  * documentation for any purpose and without fee is hereby granted, provided
117c478bd9Sstevel@tonic-gate  * that the above copyright notice appears in all copies and that both the
127c478bd9Sstevel@tonic-gate  * copyright notice and this permission notice appear in supporting
137c478bd9Sstevel@tonic-gate  * documentation, and that the name University of Delaware not be used in
147c478bd9Sstevel@tonic-gate  * advertising or publicity pertaining to distribution of the software
157c478bd9Sstevel@tonic-gate  * without specific, written prior permission.	The University of Delaware
167c478bd9Sstevel@tonic-gate  * makes no representations about the suitability this software for any
177c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
187c478bd9Sstevel@tonic-gate  */
197c478bd9Sstevel@tonic-gate 
20ea3cb02bSAndy Fiddaman /*
21ea3cb02bSAndy Fiddaman  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
22ea3cb02bSAndy Fiddaman  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate /*
257c478bd9Sstevel@tonic-gate  * Modification history kern_ntptime.c
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * 24 Sep 94	David L. Mills
287c478bd9Sstevel@tonic-gate  *	Tightened code at exits.
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * 24 Mar 94	David L. Mills
317c478bd9Sstevel@tonic-gate  *	Revised syscall interface to include new variables for PPS
327c478bd9Sstevel@tonic-gate  *	time discipline.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * 14 Feb 94	David L. Mills
357c478bd9Sstevel@tonic-gate  *	Added code for external clock
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * 28 Nov 93	David L. Mills
387c478bd9Sstevel@tonic-gate  *	Revised frequency scaling to conform with adjusted parameters
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * 17 Sep 93	David L. Mills
417c478bd9Sstevel@tonic-gate  *	Created file
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * ntp_gettime(), ntp_adjtime() - precision time interface
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  * These routines consitute the Network Time Protocol (NTP) interfaces
477c478bd9Sstevel@tonic-gate  * for user and daemon application programs. The ntp_gettime() routine
487c478bd9Sstevel@tonic-gate  * provides the time, maximum error (synch distance) and estimated error
497c478bd9Sstevel@tonic-gate  * (dispersion) to client user application programs. The ntp_adjtime()
507c478bd9Sstevel@tonic-gate  * routine is used by the NTP daemon to adjust the system clock to an
517c478bd9Sstevel@tonic-gate  * externally derived time. The time offset and related variables set by
527c478bd9Sstevel@tonic-gate  * this routine are used by clock() to adjust the phase and
537c478bd9Sstevel@tonic-gate  * frequency of the phase-lock loop which controls the system clock.
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate #include <sys/param.h>
567c478bd9Sstevel@tonic-gate #include <sys/user.h>
577c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
587c478bd9Sstevel@tonic-gate #include <sys/proc.h>
597c478bd9Sstevel@tonic-gate #include <sys/time.h>
607c478bd9Sstevel@tonic-gate #include <sys/systm.h>
617c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
627c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
637c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
647c478bd9Sstevel@tonic-gate #include <sys/timer.h>
657c478bd9Sstevel@tonic-gate #include <sys/debug.h>
667c478bd9Sstevel@tonic-gate #include <sys/timex.h>
677c478bd9Sstevel@tonic-gate #include <sys/model.h>
687c478bd9Sstevel@tonic-gate #include <sys/policy.h>
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * ntp_gettime() - NTP user application interface
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate int
ntp_gettime(struct ntptimeval * tp)747c478bd9Sstevel@tonic-gate ntp_gettime(struct ntptimeval *tp)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	timestruc_t tod;
777c478bd9Sstevel@tonic-gate 	struct ntptimeval ntv;
787c478bd9Sstevel@tonic-gate 	model_t datamodel = get_udatamodel();
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	gethrestime(&tod);
817c478bd9Sstevel@tonic-gate 	if (tod.tv_sec > TIME32_MAX)
827c478bd9Sstevel@tonic-gate 		return (set_errno(EOVERFLOW));
837c478bd9Sstevel@tonic-gate 	ntv.time.tv_sec = tod.tv_sec;
847c478bd9Sstevel@tonic-gate 	ntv.time.tv_usec = tod.tv_nsec / (NANOSEC / MICROSEC);
857c478bd9Sstevel@tonic-gate 	ntv.maxerror = time_maxerror;
867c478bd9Sstevel@tonic-gate 	ntv.esterror = time_esterror;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if (datamodel == DATAMODEL_NATIVE) {
897c478bd9Sstevel@tonic-gate 		if (copyout(&ntv, tp, sizeof (ntv)))
907c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
917c478bd9Sstevel@tonic-gate 	} else {
927c478bd9Sstevel@tonic-gate 		struct ntptimeval32 ntv32;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 		if (TIMEVAL_OVERFLOW(&ntv.time))
957c478bd9Sstevel@tonic-gate 			return (set_errno(EOVERFLOW));
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 		TIMEVAL_TO_TIMEVAL32(&ntv32.time, &ntv.time);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 		ntv32.maxerror = ntv.maxerror;
1007c478bd9Sstevel@tonic-gate 		ntv32.esterror = ntv.esterror;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 		if (copyout(&ntv32, tp, sizeof (ntv32)))
1037c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
1047c478bd9Sstevel@tonic-gate 	}
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/*
1077c478bd9Sstevel@tonic-gate 	 * Status word error decode. If any of these conditions
1087c478bd9Sstevel@tonic-gate 	 * occur, an error is returned, instead of the status
1097c478bd9Sstevel@tonic-gate 	 * word. Most applications will care only about the fact
1107c478bd9Sstevel@tonic-gate 	 * the system clock may not be trusted, not about the
1117c478bd9Sstevel@tonic-gate 	 * details.
1127c478bd9Sstevel@tonic-gate 	 *
1137c478bd9Sstevel@tonic-gate 	 * Hardware or software error
1147c478bd9Sstevel@tonic-gate 	 */
1157c478bd9Sstevel@tonic-gate 	if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * PPS signal lost when either time or frequency
1187c478bd9Sstevel@tonic-gate 	 * synchronization requested
1197c478bd9Sstevel@tonic-gate 	 */
1207c478bd9Sstevel@tonic-gate 	    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
1217c478bd9Sstevel@tonic-gate 	    !(time_status & STA_PPSSIGNAL)) ||
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * PPS jitter exceeded when time synchronization
1257c478bd9Sstevel@tonic-gate 	 * requested
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 	    (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) ||
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/*
1307c478bd9Sstevel@tonic-gate 	 * PPS wander exceeded or calibration error when
1317c478bd9Sstevel@tonic-gate 	 * frequency synchronization requested
1327c478bd9Sstevel@tonic-gate 	 */
133ea3cb02bSAndy Fiddaman 	    (time_status & STA_PPSFREQ &&
134ea3cb02bSAndy Fiddaman 	    time_status & (STA_PPSWANDER | STA_PPSERROR))) {
1357c478bd9Sstevel@tonic-gate 		return (TIME_ERROR);
136ea3cb02bSAndy Fiddaman 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	return (time_state);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * ntp_adjtime() - NTP daemon application interface
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate int
ntp_adjtime(struct timex * tp)1457c478bd9Sstevel@tonic-gate ntp_adjtime(struct timex *tp)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	struct timex ntv;
1487c478bd9Sstevel@tonic-gate 	int modes;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	if (copyin(tp, &ntv, sizeof (ntv)))
1517c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/*
1547c478bd9Sstevel@tonic-gate 	 * Update selected clock variables - only privileged users can
1557c478bd9Sstevel@tonic-gate 	 * change anything. Note that there is no error checking here on
1567c478bd9Sstevel@tonic-gate 	 * the assumption privileged users know what they're doing.
1577c478bd9Sstevel@tonic-gate 	 */
1587c478bd9Sstevel@tonic-gate 	modes = ntv.modes;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (modes != 0 && secpolicy_settime(CRED()) != 0)
1617c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
1627c478bd9Sstevel@tonic-gate 
163ea3cb02bSAndy Fiddaman 	/*
164ea3cb02bSAndy Fiddaman 	 * If the time constant is being set, validate it first so that
165ea3cb02bSAndy Fiddaman 	 * no changes are made if it is out of range.
166ea3cb02bSAndy Fiddaman 	 */
167ea3cb02bSAndy Fiddaman 	if ((modes & MOD_TIMECONST) && (ntv.constant < 0 || ntv.constant > 30))
1687c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	mutex_enter(&tod_lock);
1717c478bd9Sstevel@tonic-gate 	if (modes & MOD_MAXERROR)
1727c478bd9Sstevel@tonic-gate 		time_maxerror = ntv.maxerror;
1737c478bd9Sstevel@tonic-gate 	if (modes & MOD_ESTERROR)
1747c478bd9Sstevel@tonic-gate 		time_esterror = ntv.esterror;
1757c478bd9Sstevel@tonic-gate 	if (modes & MOD_STATUS) {
1767c478bd9Sstevel@tonic-gate 		time_status &= STA_RONLY;
1777c478bd9Sstevel@tonic-gate 		time_status |= ntv.status & ~STA_RONLY;
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 	if (modes & MOD_TIMECONST)
1807c478bd9Sstevel@tonic-gate 		time_constant = ntv.constant;
1817c478bd9Sstevel@tonic-gate 	if (modes & MOD_OFFSET)
1827c478bd9Sstevel@tonic-gate 		clock_update(ntv.offset);
183ea3cb02bSAndy Fiddaman 	/*
184ea3cb02bSAndy Fiddaman 	 * clock_update() updates time_freq so keep MOD_FREQUENCY after
185ea3cb02bSAndy Fiddaman 	 * MOD_OFFSET.
186ea3cb02bSAndy Fiddaman 	 */
187*c538cdc5SAndy Fiddaman 	if (modes & MOD_FREQUENCY) {
1884e98c196Sblu 		time_freq = ntv.freq - pps_freq;
189*c538cdc5SAndy Fiddaman 
190*c538cdc5SAndy Fiddaman 		/*
191*c538cdc5SAndy Fiddaman 		 * If the frequency offset was adjusted, then set tod_needsync
192*c538cdc5SAndy Fiddaman 		 * since it implies someone is watching over the system clock.
193*c538cdc5SAndy Fiddaman 		 */
194*c538cdc5SAndy Fiddaman 		int s = hr_clock_lock();
195*c538cdc5SAndy Fiddaman 		tod_needsync = 1;
196*c538cdc5SAndy Fiddaman 		hr_clock_unlock(s);
197*c538cdc5SAndy Fiddaman 	}
1987c478bd9Sstevel@tonic-gate 	/*
1997c478bd9Sstevel@tonic-gate 	 * Retrieve all clock variables
2007c478bd9Sstevel@tonic-gate 	 */
2017c478bd9Sstevel@tonic-gate 	ntv.offset = time_offset / SCALE_UPDATE;
2027c478bd9Sstevel@tonic-gate 	ntv.freq = time_freq + pps_freq;
2037c478bd9Sstevel@tonic-gate 	ntv.maxerror = time_maxerror;
2047c478bd9Sstevel@tonic-gate 	ntv.esterror = time_esterror;
2057c478bd9Sstevel@tonic-gate 	ntv.status = time_status;
2067c478bd9Sstevel@tonic-gate 	ntv.constant = time_constant;
2077c478bd9Sstevel@tonic-gate 	ntv.precision = time_precision;
2087c478bd9Sstevel@tonic-gate 	ntv.tolerance = time_tolerance;
2097c478bd9Sstevel@tonic-gate 	ntv.shift = pps_shift;
2107c478bd9Sstevel@tonic-gate 	ntv.ppsfreq = pps_freq;
2117c478bd9Sstevel@tonic-gate 	ntv.jitter = pps_jitter >> PPS_AVG;
2127c478bd9Sstevel@tonic-gate 	ntv.stabil = pps_stabil;
2137c478bd9Sstevel@tonic-gate 	ntv.calcnt = pps_calcnt;
2147c478bd9Sstevel@tonic-gate 	ntv.errcnt = pps_errcnt;
2157c478bd9Sstevel@tonic-gate 	ntv.jitcnt = pps_jitcnt;
2167c478bd9Sstevel@tonic-gate 	ntv.stbcnt = pps_stbcnt;
2177c478bd9Sstevel@tonic-gate 	mutex_exit(&tod_lock);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (copyout(&ntv, tp, sizeof (ntv)))
2207c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * Status word error decode.  See comments in
2247c478bd9Sstevel@tonic-gate 	 * ntp_gettime() routine.
2257c478bd9Sstevel@tonic-gate 	 */
2267c478bd9Sstevel@tonic-gate 	if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
2277c478bd9Sstevel@tonic-gate 	    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
2287c478bd9Sstevel@tonic-gate 	    !(time_status & STA_PPSSIGNAL)) ||
2297c478bd9Sstevel@tonic-gate 	    (time_status & STA_PPSTIME &&
2307c478bd9Sstevel@tonic-gate 	    time_status & STA_PPSJITTER) ||
2317c478bd9Sstevel@tonic-gate 	    (time_status & STA_PPSFREQ &&
2327c478bd9Sstevel@tonic-gate 	    time_status & (STA_PPSWANDER | STA_PPSERROR)))
2337c478bd9Sstevel@tonic-gate 		return (TIME_ERROR);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (time_state);
2367c478bd9Sstevel@tonic-gate }
237