17c478bd9Sstevel@tonic-gate /*
2*4e98c196Sblu * 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
207c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
217c478bd9Sstevel@tonic-gate
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Modification history kern_ntptime.c
247c478bd9Sstevel@tonic-gate *
257c478bd9Sstevel@tonic-gate * 24 Sep 94 David L. Mills
267c478bd9Sstevel@tonic-gate * Tightened code at exits.
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate * 24 Mar 94 David L. Mills
297c478bd9Sstevel@tonic-gate * Revised syscall interface to include new variables for PPS
307c478bd9Sstevel@tonic-gate * time discipline.
317c478bd9Sstevel@tonic-gate *
327c478bd9Sstevel@tonic-gate * 14 Feb 94 David L. Mills
337c478bd9Sstevel@tonic-gate * Added code for external clock
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate * 28 Nov 93 David L. Mills
367c478bd9Sstevel@tonic-gate * Revised frequency scaling to conform with adjusted parameters
377c478bd9Sstevel@tonic-gate *
387c478bd9Sstevel@tonic-gate * 17 Sep 93 David L. Mills
397c478bd9Sstevel@tonic-gate * Created file
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * ntp_gettime(), ntp_adjtime() - precision time interface
437c478bd9Sstevel@tonic-gate *
447c478bd9Sstevel@tonic-gate * These routines consitute the Network Time Protocol (NTP) interfaces
457c478bd9Sstevel@tonic-gate * for user and daemon application programs. The ntp_gettime() routine
467c478bd9Sstevel@tonic-gate * provides the time, maximum error (synch distance) and estimated error
477c478bd9Sstevel@tonic-gate * (dispersion) to client user application programs. The ntp_adjtime()
487c478bd9Sstevel@tonic-gate * routine is used by the NTP daemon to adjust the system clock to an
497c478bd9Sstevel@tonic-gate * externally derived time. The time offset and related variables set by
507c478bd9Sstevel@tonic-gate * this routine are used by clock() to adjust the phase and
517c478bd9Sstevel@tonic-gate * frequency of the phase-lock loop which controls the system clock.
527c478bd9Sstevel@tonic-gate */
537c478bd9Sstevel@tonic-gate #include <sys/param.h>
547c478bd9Sstevel@tonic-gate #include <sys/user.h>
557c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
567c478bd9Sstevel@tonic-gate #include <sys/proc.h>
577c478bd9Sstevel@tonic-gate #include <sys/time.h>
587c478bd9Sstevel@tonic-gate #include <sys/systm.h>
597c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
607c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
617c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
627c478bd9Sstevel@tonic-gate #include <sys/timer.h>
637c478bd9Sstevel@tonic-gate #include <sys/debug.h>
647c478bd9Sstevel@tonic-gate #include <sys/timex.h>
657c478bd9Sstevel@tonic-gate #include <sys/model.h>
667c478bd9Sstevel@tonic-gate #include <sys/policy.h>
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate * ntp_gettime() - NTP user application interface
707c478bd9Sstevel@tonic-gate */
717c478bd9Sstevel@tonic-gate int
ntp_gettime(struct ntptimeval * tp)727c478bd9Sstevel@tonic-gate ntp_gettime(struct ntptimeval *tp)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate timestruc_t tod;
757c478bd9Sstevel@tonic-gate struct ntptimeval ntv;
767c478bd9Sstevel@tonic-gate model_t datamodel = get_udatamodel();
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate gethrestime(&tod);
797c478bd9Sstevel@tonic-gate if (tod.tv_sec > TIME32_MAX)
807c478bd9Sstevel@tonic-gate return (set_errno(EOVERFLOW));
817c478bd9Sstevel@tonic-gate ntv.time.tv_sec = tod.tv_sec;
827c478bd9Sstevel@tonic-gate ntv.time.tv_usec = tod.tv_nsec / (NANOSEC / MICROSEC);
837c478bd9Sstevel@tonic-gate ntv.maxerror = time_maxerror;
847c478bd9Sstevel@tonic-gate ntv.esterror = time_esterror;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) {
877c478bd9Sstevel@tonic-gate if (copyout(&ntv, tp, sizeof (ntv)))
887c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
897c478bd9Sstevel@tonic-gate } else {
907c478bd9Sstevel@tonic-gate struct ntptimeval32 ntv32;
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate if (TIMEVAL_OVERFLOW(&ntv.time))
937c478bd9Sstevel@tonic-gate return (set_errno(EOVERFLOW));
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate TIMEVAL_TO_TIMEVAL32(&ntv32.time, &ntv.time);
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate ntv32.maxerror = ntv.maxerror;
987c478bd9Sstevel@tonic-gate ntv32.esterror = ntv.esterror;
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate if (copyout(&ntv32, tp, sizeof (ntv32)))
1017c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * Status word error decode. If any of these conditions
1067c478bd9Sstevel@tonic-gate * occur, an error is returned, instead of the status
1077c478bd9Sstevel@tonic-gate * word. Most applications will care only about the fact
1087c478bd9Sstevel@tonic-gate * the system clock may not be trusted, not about the
1097c478bd9Sstevel@tonic-gate * details.
1107c478bd9Sstevel@tonic-gate *
1117c478bd9Sstevel@tonic-gate * Hardware or software error
1127c478bd9Sstevel@tonic-gate */
1137c478bd9Sstevel@tonic-gate if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate * PPS signal lost when either time or frequency
1167c478bd9Sstevel@tonic-gate * synchronization requested
1177c478bd9Sstevel@tonic-gate */
1187c478bd9Sstevel@tonic-gate (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
1197c478bd9Sstevel@tonic-gate !(time_status & STA_PPSSIGNAL)) ||
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate * PPS jitter exceeded when time synchronization
1237c478bd9Sstevel@tonic-gate * requested
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate (time_status & STA_PPSTIME && time_status & STA_PPSJITTER) ||
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate * PPS wander exceeded or calibration error when
1297c478bd9Sstevel@tonic-gate * frequency synchronization requested
1307c478bd9Sstevel@tonic-gate */
1317c478bd9Sstevel@tonic-gate (time_status & STA_PPSFREQ && time_status &
1327c478bd9Sstevel@tonic-gate (STA_PPSWANDER | STA_PPSERROR)))
1337c478bd9Sstevel@tonic-gate return (TIME_ERROR);
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate return (time_state);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate * ntp_adjtime() - NTP daemon application interface
1407c478bd9Sstevel@tonic-gate */
1417c478bd9Sstevel@tonic-gate int
ntp_adjtime(struct timex * tp)1427c478bd9Sstevel@tonic-gate ntp_adjtime(struct timex *tp)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate struct timex ntv;
1457c478bd9Sstevel@tonic-gate int modes;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate if (copyin(tp, &ntv, sizeof (ntv)))
1487c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate * Update selected clock variables - only privileged users can
1527c478bd9Sstevel@tonic-gate * change anything. Note that there is no error checking here on
1537c478bd9Sstevel@tonic-gate * the assumption privileged users know what they're doing.
1547c478bd9Sstevel@tonic-gate */
1557c478bd9Sstevel@tonic-gate modes = ntv.modes;
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate if (modes != 0 && secpolicy_settime(CRED()) != 0)
1587c478bd9Sstevel@tonic-gate return (set_errno(EPERM));
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate if (ntv.constant < 0 || ntv.constant > 30)
1617c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock);
1647c478bd9Sstevel@tonic-gate if (modes & MOD_MAXERROR)
1657c478bd9Sstevel@tonic-gate time_maxerror = ntv.maxerror;
1667c478bd9Sstevel@tonic-gate if (modes & MOD_ESTERROR)
1677c478bd9Sstevel@tonic-gate time_esterror = ntv.esterror;
1687c478bd9Sstevel@tonic-gate if (modes & MOD_STATUS) {
1697c478bd9Sstevel@tonic-gate time_status &= STA_RONLY;
1707c478bd9Sstevel@tonic-gate time_status |= ntv.status & ~STA_RONLY;
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate if (modes & MOD_TIMECONST)
1737c478bd9Sstevel@tonic-gate time_constant = ntv.constant;
1747c478bd9Sstevel@tonic-gate if (modes & MOD_OFFSET)
1757c478bd9Sstevel@tonic-gate clock_update(ntv.offset);
176*4e98c196Sblu if (modes & MOD_FREQUENCY)
177*4e98c196Sblu time_freq = ntv.freq - pps_freq;
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate * Retrieve all clock variables
1807c478bd9Sstevel@tonic-gate */
1817c478bd9Sstevel@tonic-gate ntv.offset = time_offset / SCALE_UPDATE;
1827c478bd9Sstevel@tonic-gate ntv.freq = time_freq + pps_freq;
1837c478bd9Sstevel@tonic-gate ntv.maxerror = time_maxerror;
1847c478bd9Sstevel@tonic-gate ntv.esterror = time_esterror;
1857c478bd9Sstevel@tonic-gate ntv.status = time_status;
1867c478bd9Sstevel@tonic-gate ntv.constant = time_constant;
1877c478bd9Sstevel@tonic-gate ntv.precision = time_precision;
1887c478bd9Sstevel@tonic-gate ntv.tolerance = time_tolerance;
1897c478bd9Sstevel@tonic-gate ntv.shift = pps_shift;
1907c478bd9Sstevel@tonic-gate ntv.ppsfreq = pps_freq;
1917c478bd9Sstevel@tonic-gate ntv.jitter = pps_jitter >> PPS_AVG;
1927c478bd9Sstevel@tonic-gate ntv.stabil = pps_stabil;
1937c478bd9Sstevel@tonic-gate ntv.calcnt = pps_calcnt;
1947c478bd9Sstevel@tonic-gate ntv.errcnt = pps_errcnt;
1957c478bd9Sstevel@tonic-gate ntv.jitcnt = pps_jitcnt;
1967c478bd9Sstevel@tonic-gate ntv.stbcnt = pps_stbcnt;
1977c478bd9Sstevel@tonic-gate mutex_exit(&tod_lock);
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate if (copyout(&ntv, tp, sizeof (ntv)))
2007c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate * Status word error decode. See comments in
2047c478bd9Sstevel@tonic-gate * ntp_gettime() routine.
2057c478bd9Sstevel@tonic-gate */
2067c478bd9Sstevel@tonic-gate if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
2077c478bd9Sstevel@tonic-gate (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
2087c478bd9Sstevel@tonic-gate !(time_status & STA_PPSSIGNAL)) ||
2097c478bd9Sstevel@tonic-gate (time_status & STA_PPSTIME &&
2107c478bd9Sstevel@tonic-gate time_status & STA_PPSJITTER) ||
2117c478bd9Sstevel@tonic-gate (time_status & STA_PPSFREQ &&
2127c478bd9Sstevel@tonic-gate time_status & (STA_PPSWANDER | STA_PPSERROR)))
2137c478bd9Sstevel@tonic-gate return (TIME_ERROR);
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate return (time_state);
2167c478bd9Sstevel@tonic-gate }
217