Home | History | Annotate | Download | only in syscall
      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 #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_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;
    171 	}
    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;
    178 	/*
    179 	 * Retrieve all clock variables
    180 	 */
    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);
    198 
    199 	if (copyout(&ntv, tp, sizeof (ntv)))
    200 		return (set_errno(EFAULT));
    201 
    202 	/*
    203 	 * Status word error decode.  See comments in
    204 	 * ntp_gettime() routine.
    205 	 */
    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);
    214 
    215 	return (time_state);
    216 }
    217