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 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 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