1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino * Copyright (c) 2005 The DragonFly Project. All rights reserved.
3*86d7f5d3SJohn Marino *
4*86d7f5d3SJohn Marino * This code is derived from software contributed to The DragonFly Project
5*86d7f5d3SJohn Marino * by Matthew Dillon <dillon@backplane.com>
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
8*86d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
9*86d7f5d3SJohn Marino * are met:
10*86d7f5d3SJohn Marino *
11*86d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
12*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
13*86d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
14*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in
15*86d7f5d3SJohn Marino * the documentation and/or other materials provided with the
16*86d7f5d3SJohn Marino * distribution.
17*86d7f5d3SJohn Marino * 3. Neither the name of The DragonFly Project nor the names of its
18*86d7f5d3SJohn Marino * contributors may be used to endorse or promote products derived
19*86d7f5d3SJohn Marino * from this software without specific, prior written permission.
20*86d7f5d3SJohn Marino *
21*86d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*86d7f5d3SJohn Marino * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*86d7f5d3SJohn Marino * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*86d7f5d3SJohn Marino * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25*86d7f5d3SJohn Marino * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*86d7f5d3SJohn Marino * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*86d7f5d3SJohn Marino * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*86d7f5d3SJohn Marino * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*86d7f5d3SJohn Marino * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*86d7f5d3SJohn Marino * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*86d7f5d3SJohn Marino * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*86d7f5d3SJohn Marino * SUCH DAMAGE.
33*86d7f5d3SJohn Marino *
34*86d7f5d3SJohn Marino * $DragonFly: src/usr.sbin/dntpd/system.c,v 1.9 2007/07/11 00:18:00 swildner Exp $
35*86d7f5d3SJohn Marino */
36*86d7f5d3SJohn Marino
37*86d7f5d3SJohn Marino #include "defs.h"
38*86d7f5d3SJohn Marino #include <sys/sysctl.h>
39*86d7f5d3SJohn Marino #include <sys/timex.h>
40*86d7f5d3SJohn Marino
41*86d7f5d3SJohn Marino /*
42*86d7f5d3SJohn Marino * If a system has multiple independant time-correcting mechanisms, this
43*86d7f5d3SJohn Marino * function should clear out any corrections on those mechanisms that we
44*86d7f5d3SJohn Marino * will NOT be using. We can leave a prior correction intact on the
45*86d7f5d3SJohn Marino * mechanism that we ARE using.
46*86d7f5d3SJohn Marino *
47*86d7f5d3SJohn Marino * However, it is usually a good idea to clean out any offset correction
48*86d7f5d3SJohn Marino * that is still in progress anyway. We leave the frequency correction
49*86d7f5d3SJohn Marino * intact.
50*86d7f5d3SJohn Marino */
51*86d7f5d3SJohn Marino void
sysntp_clear_alternative_corrections(void)52*86d7f5d3SJohn Marino sysntp_clear_alternative_corrections(void)
53*86d7f5d3SJohn Marino {
54*86d7f5d3SJohn Marino struct timex ntp;
55*86d7f5d3SJohn Marino int64_t offset;
56*86d7f5d3SJohn Marino
57*86d7f5d3SJohn Marino if (no_update_opt)
58*86d7f5d3SJohn Marino return;
59*86d7f5d3SJohn Marino
60*86d7f5d3SJohn Marino /*
61*86d7f5d3SJohn Marino * Clear the ntp interface. We will use the sysctl interface
62*86d7f5d3SJohn Marino * (XXX)
63*86d7f5d3SJohn Marino */
64*86d7f5d3SJohn Marino bzero(&ntp, sizeof(ntp));
65*86d7f5d3SJohn Marino ntp.modes = MOD_OFFSET | MOD_FREQUENCY;
66*86d7f5d3SJohn Marino ntp.offset = 0;
67*86d7f5d3SJohn Marino ntp.freq = 0;
68*86d7f5d3SJohn Marino ntp_adjtime(&ntp);
69*86d7f5d3SJohn Marino
70*86d7f5d3SJohn Marino /*
71*86d7f5d3SJohn Marino * Clean out any offset still being applied to real time. Leave
72*86d7f5d3SJohn Marino * any prior frequency correction intact.
73*86d7f5d3SJohn Marino */
74*86d7f5d3SJohn Marino offset = 0;
75*86d7f5d3SJohn Marino sysctlbyname("kern.ntp.delta", NULL, 0, &offset, sizeof(offset));
76*86d7f5d3SJohn Marino }
77*86d7f5d3SJohn Marino
78*86d7f5d3SJohn Marino /*
79*86d7f5d3SJohn Marino * Obtain a timestamp that contains ONLY corrections made by the system
80*86d7f5d3SJohn Marino * to the base time. The actual value of the timestamp is not relevant,
81*86d7f5d3SJohn Marino * only the delta from two queries to this routine.
82*86d7f5d3SJohn Marino *
83*86d7f5d3SJohn Marino * This is used by DNTPD to determine what corrections the system has made
84*86d7f5d3SJohn Marino * to the system's real time so DNTPD can uncorrect them for the purpose
85*86d7f5d3SJohn Marino * of calculating the linear regression.
86*86d7f5d3SJohn Marino */
87*86d7f5d3SJohn Marino void
sysntp_getbasetime(struct timeval * tvp)88*86d7f5d3SJohn Marino sysntp_getbasetime(struct timeval *tvp)
89*86d7f5d3SJohn Marino {
90*86d7f5d3SJohn Marino struct timespec ts;
91*86d7f5d3SJohn Marino int error;
92*86d7f5d3SJohn Marino size_t ts_size;
93*86d7f5d3SJohn Marino
94*86d7f5d3SJohn Marino ts_size = sizeof(ts);
95*86d7f5d3SJohn Marino error = sysctlbyname("kern.basetime", &ts, &ts_size, NULL, 0);
96*86d7f5d3SJohn Marino if (error < 0) {
97*86d7f5d3SJohn Marino logerr("sysctlbyname(\"kern.basetime\") failed, cannot continue");
98*86d7f5d3SJohn Marino exit(1);
99*86d7f5d3SJohn Marino }
100*86d7f5d3SJohn Marino ts_to_tv(&ts, tvp);
101*86d7f5d3SJohn Marino }
102*86d7f5d3SJohn Marino
103*86d7f5d3SJohn Marino /*
104*86d7f5d3SJohn Marino * Return 1 if an offset correction is still running, 0 if it isn't.
105*86d7f5d3SJohn Marino */
106*86d7f5d3SJohn Marino int
sysntp_offset_correction_is_running(void)107*86d7f5d3SJohn Marino sysntp_offset_correction_is_running(void)
108*86d7f5d3SJohn Marino {
109*86d7f5d3SJohn Marino int64_t delta;
110*86d7f5d3SJohn Marino size_t delta_len;
111*86d7f5d3SJohn Marino
112*86d7f5d3SJohn Marino delta_len = sizeof(delta);
113*86d7f5d3SJohn Marino if (sysctlbyname("kern.ntp.delta", &delta, &delta_len, NULL, 0) == 0) {
114*86d7f5d3SJohn Marino if (delta != 0)
115*86d7f5d3SJohn Marino return(1);
116*86d7f5d3SJohn Marino }
117*86d7f5d3SJohn Marino return(0);
118*86d7f5d3SJohn Marino }
119*86d7f5d3SJohn Marino
120*86d7f5d3SJohn Marino /*
121*86d7f5d3SJohn Marino * The offset error is passed as seconds per second. Only fairly small
122*86d7f5d3SJohn Marino * offsets are passed to this function (see sysntp_correct_course_offset()
123*86d7f5d3SJohn Marino * for large corrections). This function may request that the offset
124*86d7f5d3SJohn Marino * be corrected by shifting the frequency by returning the frequency shift
125*86d7f5d3SJohn Marino * (usually a small number in the 1E-6 range) (NOT YET IMPLEMENTED).
126*86d7f5d3SJohn Marino *
127*86d7f5d3SJohn Marino * The 64 bit delta is calculated as nanoseconds per second. Since we are
128*86d7f5d3SJohn Marino * passed an offset error we must negate the result to correct the error.
129*86d7f5d3SJohn Marino *
130*86d7f5d3SJohn Marino * Because offset corrections skew the accuracy of the clock while the
131*86d7f5d3SJohn Marino * correction is in progress, we do not want to use them once we are
132*86d7f5d3SJohn Marino * reasonably well synchronized. We can make small offset corrections
133*86d7f5d3SJohn Marino * by shifting the frequency a bit. XXX
134*86d7f5d3SJohn Marino */
135*86d7f5d3SJohn Marino double
sysntp_correct_offset(double offset)136*86d7f5d3SJohn Marino sysntp_correct_offset(double offset)
137*86d7f5d3SJohn Marino {
138*86d7f5d3SJohn Marino int64_t delta;
139*86d7f5d3SJohn Marino
140*86d7f5d3SJohn Marino /*
141*86d7f5d3SJohn Marino * Course correction
142*86d7f5d3SJohn Marino */
143*86d7f5d3SJohn Marino if (offset < -0.001 || offset > 0.001) {
144*86d7f5d3SJohn Marino logdebug(1, "issuing offset adjustment: %7.6fs", -offset);
145*86d7f5d3SJohn Marino if (no_update_opt)
146*86d7f5d3SJohn Marino logdebug(1, " (UPDATES DISABLED)");
147*86d7f5d3SJohn Marino logdebug(1, "\n");
148*86d7f5d3SJohn Marino delta = -(int64_t)(offset * 1.0E+9);
149*86d7f5d3SJohn Marino if (no_update_opt == 0)
150*86d7f5d3SJohn Marino sysctlbyname("kern.ntp.delta", NULL, 0, &delta, sizeof(delta));
151*86d7f5d3SJohn Marino return(0.0);
152*86d7f5d3SJohn Marino }
153*86d7f5d3SJohn Marino
154*86d7f5d3SJohn Marino /*
155*86d7f5d3SJohn Marino * Fine correction - do it by adjusting the frequency.
156*86d7f5d3SJohn Marino * XXX
157*86d7f5d3SJohn Marino */
158*86d7f5d3SJohn Marino return(0.0);
159*86d7f5d3SJohn Marino }
160*86d7f5d3SJohn Marino
161*86d7f5d3SJohn Marino /*
162*86d7f5d3SJohn Marino * This function is used for what should be a one-time correction on
163*86d7f5d3SJohn Marino * startup.
164*86d7f5d3SJohn Marino */
165*86d7f5d3SJohn Marino double
sysntp_correct_course_offset(double offset)166*86d7f5d3SJohn Marino sysntp_correct_course_offset(double offset)
167*86d7f5d3SJohn Marino {
168*86d7f5d3SJohn Marino struct timeval tv;
169*86d7f5d3SJohn Marino struct tm *tp;
170*86d7f5d3SJohn Marino time_t t;
171*86d7f5d3SJohn Marino char buf[64];
172*86d7f5d3SJohn Marino
173*86d7f5d3SJohn Marino offset = -offset; /* if we are ahead, correct backwards, and vise versa*/
174*86d7f5d3SJohn Marino if (gettimeofday(&tv, NULL) == 0) {
175*86d7f5d3SJohn Marino tv_add_offset(&tv, offset);
176*86d7f5d3SJohn Marino if (no_update_opt == 0 && settimeofday(&tv, NULL) < 0) {
177*86d7f5d3SJohn Marino logerr("settimeofday");
178*86d7f5d3SJohn Marino } else {
179*86d7f5d3SJohn Marino logdebug(1, "issuing COARSE offset adjustment: %7.6fs, ",
180*86d7f5d3SJohn Marino offset);
181*86d7f5d3SJohn Marino t = tv.tv_sec;
182*86d7f5d3SJohn Marino tp = localtime(&t);
183*86d7f5d3SJohn Marino strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", tp);
184*86d7f5d3SJohn Marino logdebug(1, "%s.%03ld", buf, tv.tv_usec / 1000);
185*86d7f5d3SJohn Marino if (no_update_opt)
186*86d7f5d3SJohn Marino logdebug(1, " (UPDATES DISABLED)");
187*86d7f5d3SJohn Marino if (quickset_opt)
188*86d7f5d3SJohn Marino logdebug(1, " (ONE-TIME QUICKSET)");
189*86d7f5d3SJohn Marino logdebug(1, "\n");
190*86d7f5d3SJohn Marino }
191*86d7f5d3SJohn Marino } else {
192*86d7f5d3SJohn Marino logerr("gettimeofday");
193*86d7f5d3SJohn Marino }
194*86d7f5d3SJohn Marino return(0.0);
195*86d7f5d3SJohn Marino }
196*86d7f5d3SJohn Marino
197*86d7f5d3SJohn Marino /*
198*86d7f5d3SJohn Marino * freq is passed as seconds per second.
199*86d7f5d3SJohn Marino *
200*86d7f5d3SJohn Marino * The calculated 64 bit correction is nanoseconds per second shifted
201*86d7f5d3SJohn Marino * left 32.
202*86d7f5d3SJohn Marino *
203*86d7f5d3SJohn Marino * Frequency errors greater then 1 second per second will not be corrected.
204*86d7f5d3SJohn Marino * It doesn't hurt to continue correcting the frequency.
205*86d7f5d3SJohn Marino */
206*86d7f5d3SJohn Marino void
sysntp_correct_freq(double freq)207*86d7f5d3SJohn Marino sysntp_correct_freq(double freq)
208*86d7f5d3SJohn Marino {
209*86d7f5d3SJohn Marino static double last_freq;
210*86d7f5d3SJohn Marino int64_t delta;
211*86d7f5d3SJohn Marino int loglevel;
212*86d7f5d3SJohn Marino
213*86d7f5d3SJohn Marino if (last_freq == 0.0 || fabs(freq - last_freq) >= 20.0E-6)
214*86d7f5d3SJohn Marino loglevel = 1;
215*86d7f5d3SJohn Marino else if (fabs(freq - last_freq) >= 5.0E-6)
216*86d7f5d3SJohn Marino loglevel = 2;
217*86d7f5d3SJohn Marino else
218*86d7f5d3SJohn Marino loglevel = 3;
219*86d7f5d3SJohn Marino last_freq = freq;
220*86d7f5d3SJohn Marino
221*86d7f5d3SJohn Marino if (freq >= -1.0 && freq < 1.0) {
222*86d7f5d3SJohn Marino logdebug(loglevel, "issuing frequency adjustment: %6.3fppm",
223*86d7f5d3SJohn Marino -freq * 1000000.0);
224*86d7f5d3SJohn Marino if (no_update_opt)
225*86d7f5d3SJohn Marino logdebug(loglevel, " (UPDATES DISABLED)");
226*86d7f5d3SJohn Marino logdebug(loglevel, "\n");
227*86d7f5d3SJohn Marino delta = -((int64_t)(freq * 1.0E+9) << 32);
228*86d7f5d3SJohn Marino if (no_update_opt == 0)
229*86d7f5d3SJohn Marino sysctlbyname("kern.ntp.permanent", NULL, 0, &delta, sizeof(delta));
230*86d7f5d3SJohn Marino }
231*86d7f5d3SJohn Marino }
232*86d7f5d3SJohn Marino
233