xref: /illumos-gate/usr/src/uts/common/syscall/ntptime.c (revision f3682895b2a97c009685f16e8a4e5d3dc80e11f2)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) David L. Mills 1993, 1994
8  *
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted, provided
11  * that the above copyright notice appears in all copies and that both the
12  * copyright notice and this permission notice appear in supporting
13  * documentation, and that the name University of Delaware not be used in
14  * advertising or publicity pertaining to distribution of the software
15  * without specific, written prior permission.	The University of Delaware
16  * makes no representations about the suitability this software for any
17  * purpose.  It is provided "as is" without express or implied warranty.
18  */
19 
20 /*
21  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
22  */
23 
24 /*
25  * Modification history kern_ntptime.c
26  *
27  * 24 Sep 94	David L. Mills
28  *	Tightened code at exits.
29  *
30  * 24 Mar 94	David L. Mills
31  *	Revised syscall interface to include new variables for PPS
32  *	time discipline.
33  *
34  * 14 Feb 94	David L. Mills
35  *	Added code for external clock
36  *
37  * 28 Nov 93	David L. Mills
38  *	Revised frequency scaling to conform with adjusted parameters
39  *
40  * 17 Sep 93	David L. Mills
41  *	Created file
42  */
43 /*
44  * ntp_gettime(), ntp_adjtime() - precision time interface
45  *
46  * These routines consitute the Network Time Protocol (NTP) interfaces
47  * for user and daemon application programs. The ntp_gettime() routine
48  * provides the time, maximum error (synch distance) and estimated error
49  * (dispersion) to client user application programs. The ntp_adjtime()
50  * routine is used by the NTP daemon to adjust the system clock to an
51  * externally derived time. The time offset and related variables set by
52  * this routine are used by clock() to adjust the phase and
53  * frequency of the phase-lock loop which controls the system clock.
54  */
55 #include <sys/param.h>
56 #include <sys/user.h>
57 #include <sys/vnode.h>
58 #include <sys/proc.h>
59 #include <sys/time.h>
60 #include <sys/systm.h>
61 #include <sys/kmem.h>
62 #include <sys/cmn_err.h>
63 #include <sys/cpuvar.h>
64 #include <sys/timer.h>
65 #include <sys/debug.h>
66 #include <sys/timex.h>
67 #include <sys/model.h>
68 #include <sys/policy.h>
69 
70 /*
71  * ntp_gettime() - NTP user application interface
72  */
73 int
74 ntp_gettime(struct ntptimeval *tp)
75 {
76 	timestruc_t tod;
77 	struct ntptimeval ntv;
78 	model_t datamodel = get_udatamodel();
79 
80 	gethrestime(&tod);
81 	if (tod.tv_sec > TIME32_MAX)
82 		return (set_errno(EOVERFLOW));
83 	ntv.time.tv_sec = tod.tv_sec;
84 	ntv.time.tv_usec = tod.tv_nsec / (NANOSEC / MICROSEC);
85 	ntv.maxerror = time_maxerror;
86 	ntv.esterror = time_esterror;
87 
88 	if (datamodel == DATAMODEL_NATIVE) {
89 		if (copyout(&ntv, tp, sizeof (ntv)))
90 			return (set_errno(EFAULT));
91 	} else {
92 		struct ntptimeval32 ntv32;
93 
94 		if (TIMEVAL_OVERFLOW(&ntv.time))
95 			return (set_errno(EOVERFLOW));
96 
97 		TIMEVAL_TO_TIMEVAL32(&ntv32.time, &ntv.time);
98 
99 		ntv32.maxerror = ntv.maxerror;
100 		ntv32.esterror = ntv.esterror;
101 
102 		if (copyout(&ntv32, tp, sizeof (ntv32)))
103 			return (set_errno(EFAULT));
104 	}
105 
106 	/*
107 	 * Status word error decode. If any of these conditions
108 	 * occur, an error is returned, instead of the status
109 	 * word. Most applications will care only about the fact
110 	 * the system clock may not be trusted, not about the
111 	 * details.
112 	 *
113 	 * Hardware or software error
114 	 */
115 	if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
116 	/*
117 	 * PPS signal lost when either time or frequency
118 	 * synchronization requested
119 	 */
120 	    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
121 	    !(time_status & STA_PPSSIGNAL)) ||
122 
123 	/*
124 	 * PPS jitter exceeded when time synchronization
125 	 * requested
126 	 */
127 	    (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) ||
128 
129 	/*
130 	 * PPS wander exceeded or calibration error when
131 	 * frequency synchronization requested
132 	 */
133 	    (time_status & STA_PPSFREQ &&
134 	    time_status & (STA_PPSWANDER | STA_PPSERROR))) {
135 		return (TIME_ERROR);
136 	}
137 
138 	return (time_state);
139 }
140 
141 /*
142  * ntp_adjtime() - NTP daemon application interface
143  */
144 int
145 ntp_adjtime(struct timex *tp)
146 {
147 	struct timex ntv;
148 	int modes;
149 
150 	if (copyin(tp, &ntv, sizeof (ntv)))
151 		return (set_errno(EFAULT));
152 
153 	/*
154 	 * Update selected clock variables - only privileged users can
155 	 * change anything. Note that there is no error checking here on
156 	 * the assumption privileged users know what they're doing.
157 	 */
158 	modes = ntv.modes;
159 
160 	if (modes != 0 && secpolicy_settime(CRED()) != 0)
161 		return (set_errno(EPERM));
162 
163 	/*
164 	 * If the time constant is being set, validate it first so that
165 	 * no changes are made if it is out of range.
166 	 */
167 	if ((modes & MOD_TIMECONST) && (ntv.constant < 0 || ntv.constant > 30))
168 		return (set_errno(EINVAL));
169 
170 	mutex_enter(&tod_lock);
171 	if (modes & MOD_MAXERROR)
172 		time_maxerror = ntv.maxerror;
173 	if (modes & MOD_ESTERROR)
174 		time_esterror = ntv.esterror;
175 	if (modes & MOD_STATUS) {
176 		time_status &= STA_RONLY;
177 		time_status |= ntv.status & ~STA_RONLY;
178 	}
179 	if (modes & MOD_TIMECONST)
180 		time_constant = ntv.constant;
181 	if (modes & MOD_OFFSET)
182 		clock_update(ntv.offset);
183 	/*
184 	 * clock_update() updates time_freq so keep MOD_FREQUENCY after
185 	 * MOD_OFFSET.
186 	 */
187 	if (modes & MOD_FREQUENCY) {
188 		time_freq = ntv.freq - pps_freq;
189 
190 		/*
191 		 * If the frequency offset was adjusted, then set tod_needsync
192 		 * since it implies someone is watching over the system clock.
193 		 */
194 		int s = hr_clock_lock();
195 		tod_needsync = 1;
196 		hr_clock_unlock(s);
197 	}
198 	/*
199 	 * Retrieve all clock variables
200 	 */
201 	ntv.offset = time_offset / SCALE_UPDATE;
202 	ntv.freq = time_freq + pps_freq;
203 	ntv.maxerror = time_maxerror;
204 	ntv.esterror = time_esterror;
205 	ntv.status = time_status;
206 	ntv.constant = time_constant;
207 	ntv.precision = time_precision;
208 	ntv.tolerance = time_tolerance;
209 	ntv.shift = pps_shift;
210 	ntv.ppsfreq = pps_freq;
211 	ntv.jitter = pps_jitter >> PPS_AVG;
212 	ntv.stabil = pps_stabil;
213 	ntv.calcnt = pps_calcnt;
214 	ntv.errcnt = pps_errcnt;
215 	ntv.jitcnt = pps_jitcnt;
216 	ntv.stbcnt = pps_stbcnt;
217 	mutex_exit(&tod_lock);
218 
219 	if (copyout(&ntv, tp, sizeof (ntv)))
220 		return (set_errno(EFAULT));
221 
222 	/*
223 	 * Status word error decode.  See comments in
224 	 * ntp_gettime() routine.
225 	 */
226 	if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
227 	    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
228 	    !(time_status & STA_PPSSIGNAL)) ||
229 	    (time_status & STA_PPSTIME &&
230 	    time_status & STA_PPSJITTER) ||
231 	    (time_status & STA_PPSFREQ &&
232 	    time_status & (STA_PPSWANDER | STA_PPSERROR)))
233 		return (TIME_ERROR);
234 
235 	return (time_state);
236 }
237