xref: /titanic_44/usr/src/uts/common/syscall/ntptime.c (revision 5151fb1220e0ceafdc172203863c73da4285c170)
1 /*
2  * Copyright 1994,1996-2003 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
21 
22 /*
23  * Modification history kern_ntptime.c
24  *
25  * 24 Sep 94	David L. Mills
26  *	Tightened code at exits.
27  *
28  * 24 Mar 94	David L. Mills
29  *	Revised syscall interface to include new variables for PPS
30  *	time discipline.
31  *
32  * 14 Feb 94	David L. Mills
33  *	Added code for external clock
34  *
35  * 28 Nov 93	David L. Mills
36  *	Revised frequency scaling to conform with adjusted parameters
37  *
38  * 17 Sep 93	David L. Mills
39  *	Created file
40  */
41 /*
42  * ntp_gettime(), ntp_adjtime() - precision time interface
43  *
44  * These routines consitute the Network Time Protocol (NTP) interfaces
45  * for user and daemon application programs. The ntp_gettime() routine
46  * provides the time, maximum error (synch distance) and estimated error
47  * (dispersion) to client user application programs. The ntp_adjtime()
48  * routine is used by the NTP daemon to adjust the system clock to an
49  * externally derived time. The time offset and related variables set by
50  * this routine are used by clock() to adjust the phase and
51  * frequency of the phase-lock loop which controls the system clock.
52  */
53 #include <sys/param.h>
54 #include <sys/user.h>
55 #include <sys/vnode.h>
56 #include <sys/proc.h>
57 #include <sys/time.h>
58 #include <sys/systm.h>
59 #include <sys/kmem.h>
60 #include <sys/cmn_err.h>
61 #include <sys/cpuvar.h>
62 #include <sys/timer.h>
63 #include <sys/debug.h>
64 #include <sys/timex.h>
65 #include <sys/model.h>
66 #include <sys/policy.h>
67 
68 /*
69  * ntp_gettime() - NTP user application interface
70  */
71 int
72 ntp_gettime(struct ntptimeval *tp)
73 {
74 	timestruc_t tod;
75 	struct ntptimeval ntv;
76 	model_t datamodel = get_udatamodel();
77 
78 	gethrestime(&tod);
79 	if (tod.tv_sec > TIME32_MAX)
80 		return (set_errno(EOVERFLOW));
81 	ntv.time.tv_sec = tod.tv_sec;
82 	ntv.time.tv_usec = tod.tv_nsec / (NANOSEC / MICROSEC);
83 	ntv.maxerror = time_maxerror;
84 	ntv.esterror = time_esterror;
85 
86 	if (datamodel == DATAMODEL_NATIVE) {
87 		if (copyout(&ntv, tp, sizeof (ntv)))
88 			return (set_errno(EFAULT));
89 	} else {
90 		struct ntptimeval32 ntv32;
91 
92 		if (TIMEVAL_OVERFLOW(&ntv.time))
93 			return (set_errno(EOVERFLOW));
94 
95 		TIMEVAL_TO_TIMEVAL32(&ntv32.time, &ntv.time);
96 
97 		ntv32.maxerror = ntv.maxerror;
98 		ntv32.esterror = ntv.esterror;
99 
100 		if (copyout(&ntv32, tp, sizeof (ntv32)))
101 			return (set_errno(EFAULT));
102 	}
103 
104 	/*
105 	 * Status word error decode. If any of these conditions
106 	 * occur, an error is returned, instead of the status
107 	 * word. Most applications will care only about the fact
108 	 * the system clock may not be trusted, not about the
109 	 * details.
110 	 *
111 	 * Hardware or software error
112 	 */
113 	if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
114 	/*
115 	 * PPS signal lost when either time or frequency
116 	 * synchronization requested
117 	 */
118 	    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
119 		!(time_status & STA_PPSSIGNAL)) ||
120 
121 	/*
122 	 * PPS jitter exceeded when time synchronization
123 	 * requested
124 	 */
125 	    (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) ||
126 
127 	/*
128 	 * PPS wander exceeded or calibration error when
129 	 * frequency synchronization requested
130 	 */
131 	    (time_status & STA_PPSFREQ && time_status &
132 		(STA_PPSWANDER | STA_PPSERROR)))
133 		return (TIME_ERROR);
134 
135 	return (time_state);
136 }
137 
138 /*
139  * ntp_adjtime() - NTP daemon application interface
140  */
141 int
142 ntp_adjtime(struct timex *tp)
143 {
144 	struct timex ntv;
145 	int modes;
146 
147 	if (copyin(tp, &ntv, sizeof (ntv)))
148 		return (set_errno(EFAULT));
149 
150 	/*
151 	 * Update selected clock variables - only privileged users can
152 	 * change anything. Note that there is no error checking here on
153 	 * the assumption privileged users know what they're doing.
154 	 */
155 	modes = ntv.modes;
156 
157 	if (modes != 0 && secpolicy_settime(CRED()) != 0)
158 		return (set_errno(EPERM));
159 
160 	if (ntv.constant < 0 || ntv.constant > 30)
161 		return (set_errno(EINVAL));
162 
163 	mutex_enter(&tod_lock);
164 	if (modes & MOD_FREQUENCY)
165 		time_freq = ntv.freq - pps_freq;
166 	if (modes & MOD_MAXERROR)
167 		time_maxerror = ntv.maxerror;
168 	if (modes & MOD_ESTERROR)
169 		time_esterror = ntv.esterror;
170 	if (modes & MOD_STATUS) {
171 		time_status &= STA_RONLY;
172 		time_status |= ntv.status & ~STA_RONLY;
173 	}
174 	if (modes & MOD_TIMECONST)
175 		time_constant = ntv.constant;
176 
177 	if (modes & MOD_OFFSET)
178 		clock_update(ntv.offset);
179 
180 	/*
181 	 * Retrieve all clock variables
182 	 */
183 	ntv.offset = time_offset / SCALE_UPDATE;
184 	ntv.freq = time_freq + pps_freq;
185 	ntv.maxerror = time_maxerror;
186 	ntv.esterror = time_esterror;
187 	ntv.status = time_status;
188 	ntv.constant = time_constant;
189 	ntv.precision = time_precision;
190 	ntv.tolerance = time_tolerance;
191 	ntv.shift = pps_shift;
192 	ntv.ppsfreq = pps_freq;
193 	ntv.jitter = pps_jitter >> PPS_AVG;
194 	ntv.stabil = pps_stabil;
195 	ntv.calcnt = pps_calcnt;
196 	ntv.errcnt = pps_errcnt;
197 	ntv.jitcnt = pps_jitcnt;
198 	ntv.stbcnt = pps_stbcnt;
199 	mutex_exit(&tod_lock);
200 
201 	if (copyout(&ntv, tp, sizeof (ntv)))
202 		return (set_errno(EFAULT));
203 
204 	/*
205 	 * Status word error decode.  See comments in
206 	 * ntp_gettime() routine.
207 	 */
208 	if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
209 	    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
210 	    !(time_status & STA_PPSSIGNAL)) ||
211 	    (time_status & STA_PPSTIME &&
212 	    time_status & STA_PPSJITTER) ||
213 	    (time_status & STA_PPSFREQ &&
214 	    time_status & (STA_PPSWANDER | STA_PPSERROR)))
215 		return (TIME_ERROR);
216 
217 	return (time_state);
218 }
219