Merge illumos-gate
[unleashed.git] / kernel / syscall / ntptime.c
blob631277ab41d6ce17f4f6dffcb70dbdd7c2315f01
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * Copyright (c) David L. Mills 1993, 1994
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.
20 #pragma ident "%Z%%M% %I% %E% SMI"
23 * Modification history kern_ntptime.c
25 * 24 Sep 94 David L. Mills
26 * Tightened code at exits.
28 * 24 Mar 94 David L. Mills
29 * Revised syscall interface to include new variables for PPS
30 * time discipline.
32 * 14 Feb 94 David L. Mills
33 * Added code for external clock
35 * 28 Nov 93 David L. Mills
36 * Revised frequency scaling to conform with adjusted parameters
38 * 17 Sep 93 David L. Mills
39 * Created file
42 * ntp_gettime(), ntp_adjtime() - precision time interface
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.
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>
69 * ntp_gettime() - NTP user application interface
71 int
72 ntp_gettime(struct ntptimeval *tp)
74 timestruc_t tod;
75 struct ntptimeval ntv;
76 model_t datamodel = get_udatamodel();
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;
86 if (datamodel == DATAMODEL_NATIVE) {
87 if (copyout(&ntv, tp, sizeof (ntv)))
88 return (set_errno(EFAULT));
89 } else {
90 struct ntptimeval32 ntv32;
92 if (TIMEVAL_OVERFLOW(&ntv.time))
93 return (set_errno(EOVERFLOW));
95 TIMEVAL_TO_TIMEVAL32(&ntv32.time, &ntv.time);
97 ntv32.maxerror = ntv.maxerror;
98 ntv32.esterror = ntv.esterror;
100 if (copyout(&ntv32, tp, sizeof (ntv32)))
101 return (set_errno(EFAULT));
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.
111 * Hardware or software error
113 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
115 * PPS signal lost when either time or frequency
116 * synchronization requested
118 (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
119 !(time_status & STA_PPSSIGNAL)) ||
122 * PPS jitter exceeded when time synchronization
123 * requested
125 (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) ||
128 * PPS wander exceeded or calibration error when
129 * frequency synchronization requested
131 (time_status & STA_PPSFREQ && time_status &
132 (STA_PPSWANDER | STA_PPSERROR)))
133 return (TIME_ERROR);
135 return (time_state);
139 * ntp_adjtime() - NTP daemon application interface
142 ntp_adjtime(struct timex *tp)
144 struct timex ntv;
145 int modes;
147 if (copyin(tp, &ntv, sizeof (ntv)))
148 return (set_errno(EFAULT));
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.
155 modes = ntv.modes;
157 if (modes != 0 && secpolicy_settime(CRED()) != 0)
158 return (set_errno(EPERM));
160 if (ntv.constant < 0 || ntv.constant > 30)
161 return (set_errno(EINVAL));
163 mutex_enter(&tod_lock);
164 if (modes & MOD_MAXERROR)
165 time_maxerror = ntv.maxerror;
166 if (modes & MOD_ESTERROR)
167 time_esterror = ntv.esterror;
168 if (modes & MOD_STATUS) {
169 time_status &= STA_RONLY;
170 time_status |= ntv.status & ~STA_RONLY;
172 if (modes & MOD_TIMECONST)
173 time_constant = ntv.constant;
174 if (modes & MOD_OFFSET)
175 clock_update(ntv.offset);
176 if (modes & MOD_FREQUENCY)
177 time_freq = ntv.freq - pps_freq;
179 * Retrieve all clock variables
181 ntv.offset = time_offset / SCALE_UPDATE;
182 ntv.freq = time_freq + pps_freq;
183 ntv.maxerror = time_maxerror;
184 ntv.esterror = time_esterror;
185 ntv.status = time_status;
186 ntv.constant = time_constant;
187 ntv.precision = time_precision;
188 ntv.tolerance = time_tolerance;
189 ntv.shift = pps_shift;
190 ntv.ppsfreq = pps_freq;
191 ntv.jitter = pps_jitter >> PPS_AVG;
192 ntv.stabil = pps_stabil;
193 ntv.calcnt = pps_calcnt;
194 ntv.errcnt = pps_errcnt;
195 ntv.jitcnt = pps_jitcnt;
196 ntv.stbcnt = pps_stbcnt;
197 mutex_exit(&tod_lock);
199 if (copyout(&ntv, tp, sizeof (ntv)))
200 return (set_errno(EFAULT));
203 * Status word error decode. See comments in
204 * ntp_gettime() routine.
206 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
207 (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
208 !(time_status & STA_PPSSIGNAL)) ||
209 (time_status & STA_PPSTIME &&
210 time_status & STA_PPSJITTER) ||
211 (time_status & STA_PPSFREQ &&
212 time_status & (STA_PPSWANDER | STA_PPSERROR)))
213 return (TIME_ERROR);
215 return (time_state);