1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Richard P. Curnow 1997-2003
6 * Copyright (C) Miroslav Lichvar 2009-2018, 2020
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 **********************************************************************
22
23 =======================================================================
24
25 This module keeps track of the source which we are claiming to be
26 our reference, for the purposes of generating outgoing NTP packets */
27
28 #include "config.h"
29
30 #include "sysincl.h"
31
32 #include "memory.h"
33 #include "reference.h"
34 #include "util.h"
35 #include "conf.h"
36 #include "logging.h"
37 #include "local.h"
38 #include "sched.h"
39
40 /* ================================================== */
41
42 /* The minimum allowed skew */
43 #define MIN_SKEW 1.0e-12
44
45 /* The update interval of the reference in the local reference mode */
46 #define LOCAL_REF_UPDATE_INTERVAL 64.0
47
48 /* Interval between updates of the drift file */
49 #define MAX_DRIFTFILE_AGE 3600.0
50
51 static int are_we_synchronised;
52 static int enable_local_stratum;
53 static int local_stratum;
54 static int local_orphan;
55 static double local_distance;
56 static struct timespec local_ref_time;
57 static NTP_Leap our_leap_status;
58 static int our_leap_sec;
59 static int our_tai_offset;
60 static int our_stratum;
61 static uint32_t our_ref_id;
62 static IPAddr our_ref_ip;
63 static struct timespec our_ref_time;
64 static double our_skew;
65 static double our_residual_freq;
66 static double our_root_delay;
67 static double our_root_dispersion;
68 static double our_offset_sd;
69 static double our_frequency_sd;
70
71 static double max_update_skew;
72
73 static double last_offset;
74 static double avg2_offset;
75 static int avg2_moving;
76
77 static double correction_time_ratio;
78
79 /* Flag indicating that we are initialised */
80 static int initialised = 0;
81
82 /* Current operating mode */
83 static REF_Mode mode;
84
85 /* Threshold and update limit for stepping clock */
86 static int make_step_limit;
87 static double make_step_threshold;
88
89 /* Number of updates before offset checking, number of ignored updates
90 before exiting and the maximum allowed offset */
91 static int max_offset_delay;
92 static int max_offset_ignore;
93 static double max_offset;
94
95 /* Threshold for logging clock changes to syslog */
96 static double log_change_threshold;
97
98 /* Flag, threshold and user for sending mail notification on large clock changes */
99 static int do_mail_change;
100 static double mail_change_threshold;
101 static char *mail_change_user;
102
103 /* Handler for mode ending */
104 static REF_ModeEndHandler mode_end_handler = NULL;
105
106 /* Filename of the drift file. */
107 static char *drift_file=NULL;
108 static double drift_file_age;
109
110 static void update_drift_file(double, double);
111
112 /* Leap second handling mode */
113 static REF_LeapMode leap_mode;
114
115 /* Time of UTC midnight of the upcoming or previous leap second */
116 static time_t leap_when;
117
118 /* Flag indicating the clock was recently corrected for leap second and it may
119 not have correct time yet (missing 23:59:60 in the UTC time scale) */
120 static int leap_in_progress;
121
122 /* Timer for the leap second handler */
123 static SCH_TimeoutID leap_timeout_id;
124
125 /* Name of a system timezone containing leap seconds occuring at midnight */
126 static char *leap_tzname;
127
128 /* ================================================== */
129
130 static LOG_FileID logfileid;
131
132 /* ================================================== */
133
134 /* Exponential moving averages of absolute clock frequencies
135 used as a fallback when synchronisation is lost. */
136
137 struct fb_drift {
138 double freq;
139 double secs;
140 };
141
142 static int fb_drift_min;
143 static int fb_drift_max;
144
145 static struct fb_drift *fb_drifts = NULL;
146 static int next_fb_drift;
147 static SCH_TimeoutID fb_drift_timeout_id;
148
149 /* Monotonic timestamp of the last reference update */
150 static double last_ref_update;
151 static double last_ref_update_interval;
152
153 /* ================================================== */
154
155 static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
156 static void update_leap_status(NTP_Leap leap, time_t now, int reset);
157
158 /* ================================================== */
159
160 static void
handle_slew(struct timespec * raw,struct timespec * cooked,double dfreq,double doffset,LCL_ChangeType change_type,void * anything)161 handle_slew(struct timespec *raw,
162 struct timespec *cooked,
163 double dfreq,
164 double doffset,
165 LCL_ChangeType change_type,
166 void *anything)
167 {
168 double delta;
169 struct timespec now;
170
171 if (!UTI_IsZeroTimespec(&our_ref_time))
172 UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
173
174 if (change_type == LCL_ChangeUnknownStep) {
175 last_ref_update = 0.0;
176 REF_SetUnsynchronised();
177 }
178
179 /* When the clock was stepped, check if that doesn't change our leap status
180 and also reset the leap timeout to undo the shift in the scheduler */
181 if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
182 LCL_ReadRawTime(&now);
183 update_leap_status(our_leap_status, now.tv_sec, 1);
184 }
185 }
186
187 /* ================================================== */
188
189 void
REF_Initialise(void)190 REF_Initialise(void)
191 {
192 FILE *in;
193 double file_freq_ppm, file_skew_ppm;
194 double our_frequency_ppm;
195 int tai_offset;
196
197 mode = REF_ModeNormal;
198 are_we_synchronised = 0;
199 our_leap_status = LEAP_Unsynchronised;
200 our_leap_sec = 0;
201 our_tai_offset = 0;
202 initialised = 1;
203 our_root_dispersion = 1.0;
204 our_root_delay = 1.0;
205 our_frequency_ppm = 0.0;
206 our_skew = 1.0; /* i.e. rather bad */
207 our_residual_freq = 0.0;
208 our_frequency_sd = 0.0;
209 our_offset_sd = 0.0;
210 drift_file_age = 0.0;
211
212 /* Now see if we can get the drift file opened */
213 drift_file = CNF_GetDriftFile();
214 if (drift_file) {
215 in = UTI_OpenFile(NULL, drift_file, NULL, 'r', 0);
216 if (in) {
217 if (fscanf(in, "%lf%lf", &file_freq_ppm, &file_skew_ppm) == 2) {
218 /* We have read valid data */
219 our_frequency_ppm = file_freq_ppm;
220 our_skew = 1.0e-6 * file_skew_ppm;
221 if (our_skew < MIN_SKEW)
222 our_skew = MIN_SKEW;
223 LOG(LOGS_INFO, "Frequency %.3f +/- %.3f ppm read from %s",
224 file_freq_ppm, file_skew_ppm, drift_file);
225 LCL_SetAbsoluteFrequency(our_frequency_ppm);
226 } else {
227 LOG(LOGS_WARN, "Could not read valid frequency and skew from driftfile %s",
228 drift_file);
229 }
230 fclose(in);
231 }
232 }
233
234 if (our_frequency_ppm == 0.0) {
235 our_frequency_ppm = LCL_ReadAbsoluteFrequency();
236 if (our_frequency_ppm != 0.0) {
237 LOG(LOGS_INFO, "Initial frequency %.3f ppm", our_frequency_ppm);
238 }
239 }
240
241 logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
242 " Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr. Root delay Root disp. Max. error")
243 : -1;
244
245 max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
246
247 correction_time_ratio = CNF_GetCorrectionTimeRatio();
248
249 enable_local_stratum = CNF_AllowLocalReference(&local_stratum, &local_orphan, &local_distance);
250 UTI_ZeroTimespec(&local_ref_time);
251
252 leap_when = 0;
253 leap_timeout_id = 0;
254 leap_in_progress = 0;
255 leap_mode = CNF_GetLeapSecMode();
256 /* Switch to step mode if the system driver doesn't support leap */
257 if (leap_mode == REF_LeapModeSystem && !LCL_CanSystemLeap())
258 leap_mode = REF_LeapModeStep;
259
260 leap_tzname = CNF_GetLeapSecTimezone();
261 if (leap_tzname) {
262 /* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
263 if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
264 get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) {
265 LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
266 } else {
267 LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
268 leap_tzname = NULL;
269 }
270 }
271
272 CNF_GetMakeStep(&make_step_limit, &make_step_threshold);
273 CNF_GetMaxChange(&max_offset_delay, &max_offset_ignore, &max_offset);
274 CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
275 log_change_threshold = CNF_GetLogChange();
276
277 CNF_GetFallbackDrifts(&fb_drift_min, &fb_drift_max);
278
279 if (fb_drift_max >= fb_drift_min && fb_drift_min > 0) {
280 fb_drifts = MallocArray(struct fb_drift, fb_drift_max - fb_drift_min + 1);
281 memset(fb_drifts, 0, sizeof (struct fb_drift) * (fb_drift_max - fb_drift_min + 1));
282 next_fb_drift = 0;
283 fb_drift_timeout_id = 0;
284 }
285
286 UTI_ZeroTimespec(&our_ref_time);
287 last_ref_update = 0.0;
288 last_ref_update_interval = 0.0;
289
290 LCL_AddParameterChangeHandler(handle_slew, NULL);
291
292 /* Make first entry in tracking log */
293 REF_SetUnsynchronised();
294 }
295
296 /* ================================================== */
297
298 void
REF_Finalise(void)299 REF_Finalise(void)
300 {
301 update_leap_status(LEAP_Unsynchronised, 0, 0);
302
303 if (drift_file) {
304 update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
305 }
306
307 LCL_RemoveParameterChangeHandler(handle_slew, NULL);
308
309 Free(fb_drifts);
310
311 initialised = 0;
312 }
313
314 /* ================================================== */
315
REF_SetMode(REF_Mode new_mode)316 void REF_SetMode(REF_Mode new_mode)
317 {
318 mode = new_mode;
319 }
320
321 /* ================================================== */
322
323 REF_Mode
REF_GetMode(void)324 REF_GetMode(void)
325 {
326 return mode;
327 }
328
329 /* ================================================== */
330
331 void
REF_SetModeEndHandler(REF_ModeEndHandler handler)332 REF_SetModeEndHandler(REF_ModeEndHandler handler)
333 {
334 mode_end_handler = handler;
335 }
336
337 /* ================================================== */
338
339 REF_LeapMode
REF_GetLeapMode(void)340 REF_GetLeapMode(void)
341 {
342 return leap_mode;
343 }
344
345 /* ================================================== */
346 /* Update the drift coefficients to the file. */
347
348 static void
update_drift_file(double freq_ppm,double skew)349 update_drift_file(double freq_ppm, double skew)
350 {
351 FILE *out;
352
353 /* Create a temporary file with a '.tmp' extension. */
354 out = UTI_OpenFile(NULL, drift_file, ".tmp", 'w', 0644);
355 if (!out)
356 return;
357
358 /* Write the frequency and skew parameters in ppm */
359 fprintf(out, "%20.6f %20.6f\n", freq_ppm, 1.0e6 * skew);
360 fclose(out);
361
362 /* Rename the temporary file to the correct location */
363 if (!UTI_RenameTempFile(NULL, drift_file, ".tmp", NULL))
364 ;
365 }
366
367 /* ================================================== */
368
369 static void
update_fb_drifts(double freq_ppm,double update_interval)370 update_fb_drifts(double freq_ppm, double update_interval)
371 {
372 int i, secs;
373
374 assert(are_we_synchronised);
375
376 if (next_fb_drift > 0) {
377 #if 0
378 /* Reset drifts that were used when we were unsynchronised */
379 for (i = 0; i < next_fb_drift - fb_drift_min; i++)
380 fb_drifts[i].secs = 0.0;
381 #endif
382 next_fb_drift = 0;
383 }
384
385 SCH_RemoveTimeout(fb_drift_timeout_id);
386 fb_drift_timeout_id = 0;
387
388 if (update_interval < 1.0 || update_interval > last_ref_update_interval * 4.0)
389 return;
390
391 for (i = 0; i < fb_drift_max - fb_drift_min + 1; i++) {
392 secs = 1 << (i + fb_drift_min);
393 if (fb_drifts[i].secs < secs) {
394 /* Calculate average over 2 * secs interval before switching to
395 exponential updating */
396 fb_drifts[i].freq = (fb_drifts[i].freq * fb_drifts[i].secs +
397 update_interval * 0.5 * freq_ppm) / (update_interval * 0.5 + fb_drifts[i].secs);
398 fb_drifts[i].secs += update_interval * 0.5;
399 } else {
400 /* Update exponential moving average. The smoothing factor for update
401 interval equal to secs is about 0.63, for half interval about 0.39,
402 for double interval about 0.86. */
403 fb_drifts[i].freq += (1 - 1.0 / exp(update_interval / secs)) *
404 (freq_ppm - fb_drifts[i].freq);
405 }
406
407 DEBUG_LOG("Fallback drift %d updated: %f ppm %f seconds",
408 i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
409 }
410 }
411
412 /* ================================================== */
413
414 static void
fb_drift_timeout(void * arg)415 fb_drift_timeout(void *arg)
416 {
417 assert(next_fb_drift >= fb_drift_min && next_fb_drift <= fb_drift_max);
418
419 fb_drift_timeout_id = 0;
420
421 DEBUG_LOG("Fallback drift %d active: %f ppm",
422 next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
423 LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
424 REF_SetUnsynchronised();
425 }
426
427 /* ================================================== */
428
429 static void
schedule_fb_drift(void)430 schedule_fb_drift(void)
431 {
432 int i, c, secs;
433 double unsynchronised, now;
434
435 if (fb_drift_timeout_id)
436 return; /* already scheduled */
437
438 now = SCH_GetLastEventMonoTime();
439 unsynchronised = now - last_ref_update;
440
441 for (c = secs = 0, i = fb_drift_min; i <= fb_drift_max; i++) {
442 secs = 1 << i;
443
444 if (fb_drifts[i - fb_drift_min].secs < secs)
445 continue;
446
447 if (unsynchronised < secs && i > next_fb_drift)
448 break;
449
450 c = i;
451 }
452
453 if (c > next_fb_drift) {
454 LCL_SetAbsoluteFrequency(fb_drifts[c - fb_drift_min].freq);
455 next_fb_drift = c;
456 DEBUG_LOG("Fallback drift %d set", c);
457 }
458
459 if (i <= fb_drift_max) {
460 next_fb_drift = i;
461 fb_drift_timeout_id = SCH_AddTimeoutByDelay(secs - unsynchronised, fb_drift_timeout, NULL);
462 DEBUG_LOG("Fallback drift %d scheduled", i);
463 }
464 }
465
466 /* ================================================== */
467
468 static void
end_ref_mode(int result)469 end_ref_mode(int result)
470 {
471 mode = REF_ModeIgnore;
472
473 /* Dispatch the handler */
474 if (mode_end_handler)
475 (mode_end_handler)(result);
476 }
477
478 /* ================================================== */
479
480 #define BUFLEN 255
481 #define S_MAX_USER_LEN "128"
482
483 static void
maybe_log_offset(double offset,time_t now)484 maybe_log_offset(double offset, time_t now)
485 {
486 double abs_offset;
487 FILE *p;
488 char buffer[BUFLEN], host[BUFLEN];
489 struct tm *tm;
490
491 abs_offset = fabs(offset);
492
493 if (abs_offset > log_change_threshold) {
494 LOG(LOGS_WARN, "System clock wrong by %.6f seconds", -offset);
495 }
496
497 if (do_mail_change &&
498 (abs_offset > mail_change_threshold)) {
499 snprintf(buffer, sizeof (buffer), "%s -t", MAIL_PROGRAM);
500 p = popen(buffer, "w");
501 if (p) {
502 if (gethostname(host, sizeof(host)) < 0) {
503 strcpy(host, "<UNKNOWN>");
504 }
505 host[sizeof (host) - 1] = '\0';
506
507 fprintf(p, "To: %s\n", mail_change_user);
508 fprintf(p, "Subject: chronyd reports change to system clock on node [%s]\n", host);
509 fputs("\n", p);
510
511 tm = localtime(&now);
512 if (tm) {
513 strftime(buffer, sizeof (buffer),
514 "On %A, %d %B %Y\n with the system clock reading %H:%M:%S (%Z)", tm);
515 fputs(buffer, p);
516 }
517
518 /* If offset < 0 the local clock is slow, so we are applying a
519 positive change to it to bring it into line, hence the
520 negation of 'offset' in the next statement (and earlier) */
521 fprintf(p,
522 "\n\nchronyd started to apply an adjustment of %.3f seconds to it,\n"
523 " which exceeded the reporting threshold of %.3f seconds\n\n",
524 -offset, mail_change_threshold);
525 pclose(p);
526 } else {
527 LOG(LOGS_ERR, "Could not send mail notification to user %s\n",
528 mail_change_user);
529 }
530 }
531
532 }
533
534 /* ================================================== */
535
536 static int
is_step_limit_reached(double offset,double offset_correction)537 is_step_limit_reached(double offset, double offset_correction)
538 {
539 if (make_step_limit == 0) {
540 return 0;
541 } else if (make_step_limit > 0) {
542 make_step_limit--;
543 }
544 return fabs(offset - offset_correction) > make_step_threshold;
545 }
546
547 /* ================================================== */
548
549 static int
is_offset_ok(double offset)550 is_offset_ok(double offset)
551 {
552 if (max_offset_delay < 0)
553 return 1;
554
555 if (max_offset_delay > 0) {
556 max_offset_delay--;
557 return 1;
558 }
559
560 if (fabs(offset) > max_offset) {
561 LOG(LOGS_WARN,
562 "Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
563 -offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
564 if (!max_offset_ignore)
565 end_ref_mode(0);
566 else if (max_offset_ignore > 0)
567 max_offset_ignore--;
568 return 0;
569 }
570 return 1;
571 }
572
573 /* ================================================== */
574
575 static int
is_leap_second_day(time_t when)576 is_leap_second_day(time_t when)
577 {
578 struct tm *stm;
579
580 stm = gmtime(&when);
581 if (!stm)
582 return 0;
583
584 /* Allow leap second only on the last day of June and December */
585 return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
586 (stm->tm_mon == 11 && stm->tm_mday == 31);
587 }
588
589 /* ================================================== */
590
591 static NTP_Leap
get_tz_leap(time_t when,int * tai_offset)592 get_tz_leap(time_t when, int *tai_offset)
593 {
594 static time_t last_tz_leap_check;
595 static NTP_Leap tz_leap;
596 static int tz_tai_offset;
597
598 struct tm stm, *tm;
599 time_t t;
600 char *tz_env, tz_orig[128];
601
602 *tai_offset = tz_tai_offset;
603
604 /* Do this check at most twice a day */
605 when = when / (12 * 3600) * (12 * 3600);
606 if (last_tz_leap_check == when)
607 return tz_leap;
608
609 last_tz_leap_check = when;
610 tz_leap = LEAP_Normal;
611 tz_tai_offset = 0;
612
613 tm = gmtime(&when);
614 if (!tm)
615 return tz_leap;
616
617 stm = *tm;
618
619 /* Temporarily switch to the timezone containing leap seconds */
620 tz_env = getenv("TZ");
621 if (tz_env) {
622 if (strlen(tz_env) >= sizeof (tz_orig))
623 return tz_leap;
624 strcpy(tz_orig, tz_env);
625 }
626 setenv("TZ", leap_tzname, 1);
627 tzset();
628
629 /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
630 t = mktime(&stm);
631 if (t != -1)
632 tz_tai_offset = t - when + 10;
633
634 /* Set the time to 23:59:60 and see how it overflows in mktime() */
635 stm.tm_sec = 60;
636 stm.tm_min = 59;
637 stm.tm_hour = 23;
638
639 t = mktime(&stm);
640
641 if (tz_env)
642 setenv("TZ", tz_orig, 1);
643 else
644 unsetenv("TZ");
645 tzset();
646
647 if (t == -1)
648 return tz_leap;
649
650 if (stm.tm_sec == 60)
651 tz_leap = LEAP_InsertSecond;
652 else if (stm.tm_sec == 1)
653 tz_leap = LEAP_DeleteSecond;
654
655 *tai_offset = tz_tai_offset;
656
657 return tz_leap;
658 }
659
660 /* ================================================== */
661
662 static void
leap_end_timeout(void * arg)663 leap_end_timeout(void *arg)
664 {
665 leap_timeout_id = 0;
666 leap_in_progress = 0;
667
668 if (our_tai_offset)
669 our_tai_offset += our_leap_sec;
670 our_leap_sec = 0;
671
672 if (leap_mode == REF_LeapModeSystem)
673 LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
674
675 if (our_leap_status == LEAP_InsertSecond ||
676 our_leap_status == LEAP_DeleteSecond)
677 our_leap_status = LEAP_Normal;
678 }
679
680 /* ================================================== */
681
682 static void
leap_start_timeout(void * arg)683 leap_start_timeout(void *arg)
684 {
685 leap_in_progress = 1;
686
687 switch (leap_mode) {
688 case REF_LeapModeSystem:
689 DEBUG_LOG("Waiting for system clock leap second correction");
690 break;
691 case REF_LeapModeSlew:
692 LCL_NotifyLeap(our_leap_sec);
693 LCL_AccumulateOffset(our_leap_sec, 0.0);
694 LOG(LOGS_WARN, "Adjusting system clock for leap second");
695 break;
696 case REF_LeapModeStep:
697 LCL_NotifyLeap(our_leap_sec);
698 LCL_ApplyStepOffset(our_leap_sec);
699 LOG(LOGS_WARN, "System clock was stepped for leap second");
700 break;
701 case REF_LeapModeIgnore:
702 LOG(LOGS_WARN, "Ignoring leap second");
703 break;
704 default:
705 break;
706 }
707
708 /* Wait until the leap second is over with some extra room to be safe */
709 leap_timeout_id = SCH_AddTimeoutByDelay(2.0, leap_end_timeout, NULL);
710 }
711
712 /* ================================================== */
713
714 static void
set_leap_timeout(time_t now)715 set_leap_timeout(time_t now)
716 {
717 struct timespec when;
718
719 /* Stop old timer if there is one */
720 SCH_RemoveTimeout(leap_timeout_id);
721 leap_timeout_id = 0;
722 leap_in_progress = 0;
723
724 if (!our_leap_sec)
725 return;
726
727 leap_when = (now / (24 * 3600) + 1) * (24 * 3600);
728
729 /* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC. If the clock
730 will be corrected by the system, timeout slightly sooner to be sure it
731 will happen before the system correction. */
732 when.tv_sec = leap_when;
733 when.tv_nsec = 0;
734 if (our_leap_sec < 0)
735 when.tv_sec--;
736 if (leap_mode == REF_LeapModeSystem) {
737 when.tv_sec--;
738 when.tv_nsec = 500000000;
739 }
740
741 leap_timeout_id = SCH_AddTimeout(&when, leap_start_timeout, NULL);
742 }
743
744 /* ================================================== */
745
746 static void
update_leap_status(NTP_Leap leap,time_t now,int reset)747 update_leap_status(NTP_Leap leap, time_t now, int reset)
748 {
749 NTP_Leap tz_leap;
750 int leap_sec, tai_offset;
751
752 leap_sec = 0;
753 tai_offset = 0;
754
755 if (leap_tzname && now) {
756 tz_leap = get_tz_leap(now, &tai_offset);
757 if (leap == LEAP_Normal)
758 leap = tz_leap;
759 }
760
761 if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
762 /* Check that leap second is allowed today */
763
764 if (is_leap_second_day(now)) {
765 if (leap == LEAP_InsertSecond) {
766 leap_sec = 1;
767 } else {
768 leap_sec = -1;
769 }
770 } else {
771 leap = LEAP_Normal;
772 }
773 }
774
775 if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
776 && !REF_IsLeapSecondClose(NULL, 0.0)) {
777 our_leap_sec = leap_sec;
778 our_tai_offset = tai_offset;
779
780 switch (leap_mode) {
781 case REF_LeapModeSystem:
782 LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
783 /* Fall through */
784 case REF_LeapModeSlew:
785 case REF_LeapModeStep:
786 case REF_LeapModeIgnore:
787 set_leap_timeout(now);
788 break;
789 default:
790 assert(0);
791 break;
792 }
793 } else if (reset) {
794 set_leap_timeout(now);
795 }
796
797 our_leap_status = leap;
798 }
799
800 /* ================================================== */
801
802 static double
get_root_dispersion(struct timespec * ts)803 get_root_dispersion(struct timespec *ts)
804 {
805 if (UTI_IsZeroTimespec(&our_ref_time))
806 return 1.0;
807
808 return our_root_dispersion +
809 fabs(UTI_DiffTimespecsToDouble(ts, &our_ref_time)) *
810 (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError());
811 }
812
813 /* ================================================== */
814
815 static void
update_sync_status(struct timespec * now)816 update_sync_status(struct timespec *now)
817 {
818 double elapsed;
819
820 elapsed = fabs(UTI_DiffTimespecsToDouble(now, &our_ref_time));
821
822 LCL_SetSyncStatus(are_we_synchronised,
823 our_offset_sd + elapsed * our_frequency_sd,
824 our_root_delay / 2.0 + get_root_dispersion(now));
825 }
826
827 /* ================================================== */
828
829 static void
write_log(struct timespec * now,int combined_sources,double freq,double offset,double offset_sd,double uncorrected_offset,double orig_root_distance)830 write_log(struct timespec *now, int combined_sources, double freq,
831 double offset, double offset_sd, double uncorrected_offset,
832 double orig_root_distance)
833 {
834 const char leap_codes[4] = {'N', '+', '-', '?'};
835 double root_dispersion, max_error;
836 static double last_sys_offset = 0.0;
837
838 if (logfileid == -1)
839 return;
840
841 max_error = orig_root_distance + fabs(last_sys_offset);
842 root_dispersion = get_root_dispersion(now);
843 last_sys_offset = offset - uncorrected_offset;
844
845 LOG_FileWrite(logfileid,
846 "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e %10.3e %10.3e %10.3e",
847 UTI_TimeToLogForm(now->tv_sec),
848 our_ref_ip.family != IPADDR_UNSPEC ?
849 UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
850 our_stratum, freq, 1.0e6 * our_skew, offset,
851 leap_codes[our_leap_status], combined_sources, offset_sd,
852 uncorrected_offset, our_root_delay, root_dispersion, max_error);
853 }
854
855 /* ================================================== */
856
857 static void
special_mode_sync(int valid,double offset)858 special_mode_sync(int valid, double offset)
859 {
860 int step;
861
862 switch (mode) {
863 case REF_ModeInitStepSlew:
864 if (!valid) {
865 LOG(LOGS_WARN, "No suitable source for initstepslew");
866 end_ref_mode(0);
867 break;
868 }
869
870 step = fabs(offset) >= CNF_GetInitStepThreshold();
871
872 LOG(LOGS_INFO, "System's initial offset : %.6f seconds %s of true (%s)",
873 fabs(offset), offset >= 0 ? "fast" : "slow", step ? "step" : "slew");
874
875 if (step)
876 LCL_ApplyStepOffset(offset);
877 else
878 LCL_AccumulateOffset(offset, 0.0);
879
880 end_ref_mode(1);
881
882 break;
883 case REF_ModeUpdateOnce:
884 case REF_ModePrintOnce:
885 if (!valid) {
886 LOG(LOGS_WARN, "No suitable source for synchronisation");
887 end_ref_mode(0);
888 break;
889 }
890
891 step = mode == REF_ModeUpdateOnce;
892
893 LOG(LOGS_INFO, "System clock wrong by %.6f seconds (%s)",
894 -offset, step ? "step" : "ignored");
895
896 if (step)
897 LCL_ApplyStepOffset(offset);
898
899 end_ref_mode(1);
900
901 break;
902 case REF_ModeIgnore:
903 /* Do nothing until the mode is changed */
904 break;
905 default:
906 assert(0);
907 }
908 }
909
910 /* ================================================== */
911
912 static void
get_clock_estimates(int manual,double measured_freq,double measured_skew,double * estimated_freq,double * estimated_skew,double * residual_freq)913 get_clock_estimates(int manual,
914 double measured_freq, double measured_skew,
915 double *estimated_freq, double *estimated_skew,
916 double *residual_freq)
917 {
918 double gain, expected_freq, expected_skew, extra_skew;
919
920 /* We assume that the local clock is running according to our previously
921 determined value */
922 expected_freq = 0.0;
923 expected_skew = our_skew;
924
925 /* Set new frequency based on weighted average of the expected and measured
926 skew. Disable updates that are based on totally unreliable frequency
927 information unless it is a manual reference. */
928 if (manual) {
929 gain = 1.0;
930 } else if (fabs(measured_skew) > max_update_skew) {
931 DEBUG_LOG("Skew %f too large to track", measured_skew);
932 gain = 0.0;
933 } else {
934 gain = 3.0 * SQUARE(expected_skew) /
935 (3.0 * SQUARE(expected_skew) + SQUARE(measured_skew));
936 }
937
938 gain = CLAMP(0.0, gain, 1.0);
939
940 *estimated_freq = expected_freq + gain * (measured_freq - expected_freq);
941 *residual_freq = measured_freq - *estimated_freq;
942
943 extra_skew = sqrt(SQUARE(expected_freq - *estimated_freq) * (1.0 - gain) +
944 SQUARE(measured_freq - *estimated_freq) * gain);
945
946 *estimated_skew = expected_skew + gain * (measured_skew - expected_skew) + extra_skew;
947 }
948
949 /* ================================================== */
950
951 static void
fuzz_ref_time(struct timespec * ts)952 fuzz_ref_time(struct timespec *ts)
953 {
954 uint32_t rnd;
955
956 /* Add a random value from interval [-1.0, 0.0] */
957 UTI_GetRandomBytes(&rnd, sizeof (rnd));
958 UTI_AddDoubleToTimespec(ts, -(double)rnd / (uint32_t)-1, ts);
959 }
960
961 /* ================================================== */
962
963 void
REF_SetReference(int stratum,NTP_Leap leap,int combined_sources,uint32_t ref_id,IPAddr * ref_ip,struct timespec * ref_time,double offset,double offset_sd,double frequency,double frequency_sd,double skew,double root_delay,double root_dispersion)964 REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
965 uint32_t ref_id, IPAddr *ref_ip, struct timespec *ref_time,
966 double offset, double offset_sd,
967 double frequency, double frequency_sd, double skew,
968 double root_delay, double root_dispersion)
969 {
970 double uncorrected_offset, accumulate_offset, step_offset;
971 double residual_frequency, local_abs_frequency;
972 double elapsed, mono_now, update_interval, correction_rate, orig_root_distance;
973 struct timespec now, raw_now;
974 int manual;
975
976 assert(initialised);
977
978 /* Special modes are implemented elsewhere */
979 if (mode != REF_ModeNormal) {
980 special_mode_sync(1, offset);
981 return;
982 }
983
984 manual = leap == LEAP_Unsynchronised;
985
986 mono_now = SCH_GetLastEventMonoTime();
987 LCL_ReadRawTime(&raw_now);
988 LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
989 UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
990
991 elapsed = UTI_DiffTimespecsToDouble(&now, ref_time);
992 offset += elapsed * frequency;
993
994 if (last_ref_update != 0.0) {
995 update_interval = mono_now - last_ref_update;
996 } else {
997 update_interval = 0.0;
998 }
999
1000 /* Get new estimates of the frequency and skew including the new data */
1001 get_clock_estimates(manual, frequency, skew,
1002 &frequency, &skew, &residual_frequency);
1003
1004 if (!is_offset_ok(offset))
1005 return;
1006
1007 orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
1008
1009 are_we_synchronised = leap != LEAP_Unsynchronised;
1010 our_stratum = stratum + 1;
1011 our_ref_id = ref_id;
1012 if (ref_ip)
1013 our_ref_ip = *ref_ip;
1014 else
1015 our_ref_ip.family = IPADDR_UNSPEC;
1016 our_ref_time = *ref_time;
1017 our_skew = skew;
1018 our_residual_freq = residual_frequency;
1019 our_root_delay = root_delay;
1020 our_root_dispersion = root_dispersion;
1021 our_frequency_sd = frequency_sd;
1022 our_offset_sd = offset_sd;
1023 last_ref_update = mono_now;
1024 last_ref_update_interval = update_interval;
1025 last_offset = offset;
1026
1027 /* We want to correct the offset quickly, but we also want to keep the
1028 frequency error caused by the correction itself low.
1029
1030 Define correction rate as the area of the region bounded by the graph of
1031 offset corrected in time. Set the rate so that the time needed to correct
1032 an offset equal to the current sourcestats stddev will be equal to the
1033 update interval multiplied by the correction time ratio (assuming linear
1034 adjustment). The offset and the time needed to make the correction are
1035 inversely proportional.
1036
1037 This is only a suggestion and it's up to the system driver how the
1038 adjustment will be executed. */
1039
1040 correction_rate = correction_time_ratio * 0.5 * offset_sd * update_interval;
1041
1042 /* Check if the clock should be stepped */
1043 if (is_step_limit_reached(offset, uncorrected_offset)) {
1044 /* Cancel the uncorrected offset and correct the total offset by step */
1045 accumulate_offset = uncorrected_offset;
1046 step_offset = offset - uncorrected_offset;
1047 } else {
1048 accumulate_offset = offset;
1049 step_offset = 0.0;
1050 }
1051
1052 /* Adjust the clock */
1053 LCL_AccumulateFrequencyAndOffset(frequency, accumulate_offset, correction_rate);
1054
1055 maybe_log_offset(offset, raw_now.tv_sec);
1056
1057 if (step_offset != 0.0) {
1058 if (LCL_ApplyStepOffset(step_offset))
1059 LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", -step_offset);
1060 }
1061
1062 update_leap_status(leap, raw_now.tv_sec, 0);
1063 update_sync_status(&now);
1064
1065 /* Add a random error of up to one second to the reference time to make it
1066 less useful when disclosed to NTP and cmdmon clients for estimating
1067 receive timestamps in the interleaved symmetric NTP mode */
1068 fuzz_ref_time(&our_ref_time);
1069
1070 local_abs_frequency = LCL_ReadAbsoluteFrequency();
1071
1072 write_log(&now, combined_sources, local_abs_frequency,
1073 offset, offset_sd, uncorrected_offset, orig_root_distance);
1074
1075 if (drift_file) {
1076 /* Update drift file at most once per hour */
1077 drift_file_age += update_interval;
1078 if (drift_file_age >= MAX_DRIFTFILE_AGE) {
1079 update_drift_file(local_abs_frequency, our_skew);
1080 drift_file_age = 0.0;
1081 }
1082 }
1083
1084 /* Update fallback drifts */
1085 if (fb_drifts && are_we_synchronised) {
1086 update_fb_drifts(local_abs_frequency, update_interval);
1087 schedule_fb_drift();
1088 }
1089
1090 /* Update the moving average of squares of offset, quickly on start */
1091 if (avg2_moving) {
1092 avg2_offset += 0.1 * (SQUARE(offset) - avg2_offset);
1093 } else {
1094 if (avg2_offset > 0.0 && avg2_offset < SQUARE(offset))
1095 avg2_moving = 1;
1096 avg2_offset = SQUARE(offset);
1097 }
1098 }
1099
1100 /* ================================================== */
1101
1102 void
REF_SetManualReference(struct timespec * ref_time,double offset,double frequency,double skew)1103 REF_SetManualReference
1104 (
1105 struct timespec *ref_time,
1106 double offset,
1107 double frequency,
1108 double skew
1109 )
1110 {
1111 /* We are not synchronised to an external source, as such. This is
1112 only supposed to be used with the local source option, really.
1113 Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
1114 REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
1115 ref_time, offset, 0.0, frequency, skew, skew, 0.0, 0.0);
1116 }
1117
1118 /* ================================================== */
1119
1120 void
REF_SetUnsynchronised(void)1121 REF_SetUnsynchronised(void)
1122 {
1123 /* Variables required for logging to statistics log */
1124 struct timespec now, now_raw;
1125 double uncorrected_offset;
1126
1127 assert(initialised);
1128
1129 /* Special modes are implemented elsewhere */
1130 if (mode != REF_ModeNormal) {
1131 special_mode_sync(0, 0.0);
1132 return;
1133 }
1134
1135 LCL_ReadRawTime(&now_raw);
1136 LCL_GetOffsetCorrection(&now_raw, &uncorrected_offset, NULL);
1137 UTI_AddDoubleToTimespec(&now_raw, uncorrected_offset, &now);
1138
1139 if (fb_drifts) {
1140 schedule_fb_drift();
1141 }
1142
1143 update_leap_status(LEAP_Unsynchronised, 0, 0);
1144 our_ref_ip.family = IPADDR_INET4;
1145 our_ref_ip.addr.in4 = 0;
1146 our_stratum = 0;
1147 are_we_synchronised = 0;
1148
1149 LCL_SetSyncStatus(0, 0.0, 0.0);
1150
1151 write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
1152 our_root_delay / 2.0 + get_root_dispersion(&now));
1153 }
1154
1155 /* ================================================== */
1156
1157 void
REF_UpdateLeapStatus(NTP_Leap leap)1158 REF_UpdateLeapStatus(NTP_Leap leap)
1159 {
1160 struct timespec raw_now, now;
1161
1162 /* Wait for a full reference update if not already synchronised */
1163 if (!are_we_synchronised)
1164 return;
1165
1166 SCH_GetLastEventTime(&now, NULL, &raw_now);
1167
1168 update_leap_status(leap, raw_now.tv_sec, 0);
1169
1170 /* Update also the synchronisation status */
1171 update_sync_status(&now);
1172 }
1173
1174 /* ================================================== */
1175
1176 void
REF_GetReferenceParams(struct timespec * local_time,int * is_synchronised,NTP_Leap * leap_status,int * stratum,uint32_t * ref_id,struct timespec * ref_time,double * root_delay,double * root_dispersion)1177 REF_GetReferenceParams
1178 (
1179 struct timespec *local_time,
1180 int *is_synchronised,
1181 NTP_Leap *leap_status,
1182 int *stratum,
1183 uint32_t *ref_id,
1184 struct timespec *ref_time,
1185 double *root_delay,
1186 double *root_dispersion
1187 )
1188 {
1189 double dispersion, delta;
1190
1191 assert(initialised);
1192
1193 if (are_we_synchronised) {
1194 dispersion = get_root_dispersion(local_time);
1195 } else {
1196 dispersion = 0.0;
1197 }
1198
1199 /* Local reference is active when enabled and the clock is not synchronised
1200 or the root distance exceeds the threshold */
1201
1202 if (are_we_synchronised &&
1203 !(enable_local_stratum && our_root_delay / 2 + dispersion > local_distance)) {
1204
1205 *is_synchronised = 1;
1206
1207 *stratum = our_stratum;
1208
1209 *leap_status = !leap_in_progress ? our_leap_status : LEAP_Unsynchronised;
1210 *ref_id = our_ref_id;
1211 *ref_time = our_ref_time;
1212 *root_delay = our_root_delay;
1213 *root_dispersion = dispersion;
1214
1215 } else if (enable_local_stratum) {
1216
1217 *is_synchronised = 0;
1218
1219 *stratum = local_stratum;
1220 *ref_id = NTP_REFID_LOCAL;
1221
1222 /* Keep the reference timestamp up to date. Adjust the timestamp to make
1223 sure that the transmit timestamp cannot come before this (which might
1224 fail a test of an NTP client). */
1225 delta = UTI_DiffTimespecsToDouble(local_time, &local_ref_time);
1226 if (delta > LOCAL_REF_UPDATE_INTERVAL || delta < 1.0) {
1227 UTI_AddDoubleToTimespec(local_time, -1.0, &local_ref_time);
1228 fuzz_ref_time(&local_ref_time);
1229 }
1230
1231 *ref_time = local_ref_time;
1232
1233 /* Not much else we can do for leap second bits - maybe need to
1234 have a way for the administrator to feed leap bits in */
1235 *leap_status = LEAP_Normal;
1236
1237 *root_delay = 0.0;
1238 *root_dispersion = 0.0;
1239
1240 } else {
1241
1242 *is_synchronised = 0;
1243
1244 *leap_status = LEAP_Unsynchronised;
1245 *stratum = NTP_MAX_STRATUM;
1246 *ref_id = NTP_REFID_UNSYNC;
1247 UTI_ZeroTimespec(ref_time);
1248 /* These values seem to be standard for a client, and
1249 any peer or client of ours will ignore them anyway because
1250 we don't claim to be synchronised */
1251 *root_dispersion = 1.0;
1252 *root_delay = 1.0;
1253
1254 }
1255 }
1256
1257 /* ================================================== */
1258
1259 int
REF_GetOurStratum(void)1260 REF_GetOurStratum(void)
1261 {
1262 struct timespec now_cooked, ref_time;
1263 int synchronised, stratum;
1264 NTP_Leap leap_status;
1265 uint32_t ref_id;
1266 double root_delay, root_dispersion;
1267
1268 SCH_GetLastEventTime(&now_cooked, NULL, NULL);
1269 REF_GetReferenceParams(&now_cooked, &synchronised, &leap_status, &stratum,
1270 &ref_id, &ref_time, &root_delay, &root_dispersion);
1271
1272 return stratum;
1273 }
1274
1275 /* ================================================== */
1276
1277 int
REF_GetOrphanStratum(void)1278 REF_GetOrphanStratum(void)
1279 {
1280 if (!enable_local_stratum || !local_orphan || mode != REF_ModeNormal)
1281 return NTP_MAX_STRATUM;
1282 return local_stratum;
1283 }
1284
1285 /* ================================================== */
1286
1287 double
REF_GetSkew(void)1288 REF_GetSkew(void)
1289 {
1290 return our_skew;
1291 }
1292
1293 /* ================================================== */
1294
1295 void
REF_ModifyMaxupdateskew(double new_max_update_skew)1296 REF_ModifyMaxupdateskew(double new_max_update_skew)
1297 {
1298 max_update_skew = new_max_update_skew * 1.0e-6;
1299 }
1300
1301 /* ================================================== */
1302
1303 void
REF_ModifyMakestep(int limit,double threshold)1304 REF_ModifyMakestep(int limit, double threshold)
1305 {
1306 make_step_limit = limit;
1307 make_step_threshold = threshold;
1308 }
1309
1310 /* ================================================== */
1311
1312 void
REF_EnableLocal(int stratum,double distance,int orphan)1313 REF_EnableLocal(int stratum, double distance, int orphan)
1314 {
1315 enable_local_stratum = 1;
1316 local_stratum = CLAMP(1, stratum, NTP_MAX_STRATUM - 1);
1317 local_distance = distance;
1318 local_orphan = !!orphan;
1319 }
1320
1321 /* ================================================== */
1322
1323 void
REF_DisableLocal(void)1324 REF_DisableLocal(void)
1325 {
1326 enable_local_stratum = 0;
1327 }
1328
1329 /* ================================================== */
1330
1331 #define LEAP_SECOND_CLOSE 5
1332
1333 static int
is_leap_close(time_t t)1334 is_leap_close(time_t t)
1335 {
1336 return leap_when != 0 &&
1337 t >= leap_when - LEAP_SECOND_CLOSE && t < leap_when + LEAP_SECOND_CLOSE;
1338 }
1339
1340 /* ================================================== */
1341
REF_IsLeapSecondClose(struct timespec * ts,double offset)1342 int REF_IsLeapSecondClose(struct timespec *ts, double offset)
1343 {
1344 struct timespec now, now_raw;
1345
1346 SCH_GetLastEventTime(&now, NULL, &now_raw);
1347
1348 if (is_leap_close(now.tv_sec) || is_leap_close(now_raw.tv_sec))
1349 return 1;
1350
1351 if (ts && (is_leap_close(ts->tv_sec) || is_leap_close(ts->tv_sec + offset)))
1352 return 1;
1353
1354 return 0;
1355 }
1356
1357 /* ================================================== */
1358
1359 int
REF_GetTaiOffset(struct timespec * ts)1360 REF_GetTaiOffset(struct timespec *ts)
1361 {
1362 int tai_offset;
1363
1364 get_tz_leap(ts->tv_sec, &tai_offset);
1365
1366 return tai_offset;
1367 }
1368
1369 /* ================================================== */
1370
1371 void
REF_GetTrackingReport(RPT_TrackingReport * rep)1372 REF_GetTrackingReport(RPT_TrackingReport *rep)
1373 {
1374 struct timespec now_raw, now_cooked;
1375 double correction;
1376 int synchronised;
1377
1378 LCL_ReadRawTime(&now_raw);
1379 LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
1380 UTI_AddDoubleToTimespec(&now_raw, correction, &now_cooked);
1381
1382 REF_GetReferenceParams(&now_cooked, &synchronised,
1383 &rep->leap_status, &rep->stratum,
1384 &rep->ref_id, &rep->ref_time,
1385 &rep->root_delay, &rep->root_dispersion);
1386
1387 if (rep->stratum == NTP_MAX_STRATUM && !synchronised)
1388 rep->stratum = 0;
1389
1390 rep->ip_addr.family = IPADDR_UNSPEC;
1391 rep->current_correction = correction;
1392 rep->freq_ppm = LCL_ReadAbsoluteFrequency();
1393 rep->resid_freq_ppm = 0.0;
1394 rep->skew_ppm = 0.0;
1395 rep->last_update_interval = last_ref_update_interval;
1396 rep->last_offset = last_offset;
1397 rep->rms_offset = sqrt(avg2_offset);
1398
1399 if (synchronised) {
1400 rep->ip_addr = our_ref_ip;
1401 rep->resid_freq_ppm = 1.0e6 * our_residual_freq;
1402 rep->skew_ppm = 1.0e6 * our_skew;
1403 }
1404 }
1405