File: ntp_loopfilter.c

package info (click to toggle)
xntp3 5.93-2
  • links: PTS
  • area: main
  • in suites: hamm
  • size: 7,644 kB
  • ctags: 7,419
  • sloc: ansic: 59,474; perl: 3,633; sh: 2,623; awk: 417; makefile: 311; asm: 37
file content (754 lines) | stat: -rw-r--r-- 21,728 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
/*
 * ntp_loopfilter.c - implements the NTP loop filter algorithm
 *
 */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>


#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"

#if defined(VMS) && defined(VMS_LOCALUNIT)	/*wjm*/
#include "ntp_refclock.h"
#endif /* VMS */
#ifdef KERNEL_PLL
#include <sys/timex.h>
#ifdef NTP_SYSCALLS_STD
#define ntp_gettime(t)  syscall(SYS_ntp_gettime, (t))
#define ntp_adjtime(t)  syscall(SYS_ntp_adjtime, (t))
#else /* NOT NTP_SYSCALLS_STD */
#ifdef HAVE___NTP_GETTIME
#define ntp_gettime(t)  __ntp_gettime((t))
#endif /* HAVE___NTP_GETTIME */
#ifdef HAVE___ADJTIMEX
#define ntp_adjtime(t)  __adjtimex((t))
#endif
#endif /* NOT NTP_SYSCALLS_STD */

#endif /* KERNEL_PLL */

/*
 * The loop filter is implemented in slavish adherence to the
 * specification (Section 5), except that for consistency we
 * mostly carry the quantities in the same units as appendix G.
 *
 * Kernel PLL/PPS state machine
 *
 * The following state machine is used when the kernel PLL modifications
 * described in the README.kernel file are present.
 *
 * Each update to a prefer peer sets pps_update true if it survives the
 * intersection algorithm and its time is within range. The PPS time
 * discipline is enabled (STA_PPSTIME bit set in the status word) when
 * pps_update is true and the PPS frequency discipline is enabled. If
 * the PPS time discipline is enabled and the kernel reports a PPS
 * signal is present, the pps_control variable is set to the current
 * time. If the current time is later than pps_control by PPS_MAXAGE
 * (120 s), this variable is set to zero.
 *
 * The pll_enable switch can be set both at configuration time and at
 * run time using xntpdc. If true, the kernel modifications are active
 * as described above; if false, the kernel is bypassed entirely (except
 * for the PPS frequency update, if enabled) and the daemon PLL used
 * instead. 
 */
#define RSH_DRIFT_TO_ADJ (CLOCK_DSCALE - 16)
#define RSH_FRAC_TO_FREQ (CLOCK_FREQ - RSH_DRIFT_TO_ADJ)
#define PPS_MAXAGE 120		/* kernel pps signal timeout (s) */

/*
 * Program variables
 */
l_fp last_offset;		/* last clock offset */
u_long last_time;		/* time of last clock update (s) */
u_fp clock_stability;		/* clock stability (ppm) */
s_fp clock_frequency;		/* clock frequency error (ppm) */
s_fp drift_comp;		/* pll frequency (ppm) */
static long clock_adjust;	/* clock adjust (fraction only) */
static int time_constant;	/* pll time constant */
static s_fp max_comp;		/* max frequency offset (ppm) */
int tc_counter;			/* poll-adjust counter */
int pll_status;			/* status bits for kernel pll */
volatile int pll_control;	/* true if working kernel pll */
int pll_enable;			/* true if pll enabled */
u_long pps_control;		/* last pps sample time */
int pps_update;			/* pps update valid */
int fdpps = -1;			/* pps file descriptor */
int pps_enable;			/* pps disabled by default */
char cutout;			/* override for max capture range */
extern	l_fp sys_clock_offset;	/* correction for current system time */

/*
 * Imported from the ntp_proto module
 */
extern s_fp sys_rootdelay;	/* root delay */
extern u_fp sys_rootdispersion;	/* root dispersion */
extern struct peer *sys_peer;	/* system peer pointer */
extern u_char sys_poll;		/* log2 of system poll interval */
extern u_char sys_leap;		/* system leap bits */
extern l_fp sys_refskew;	/* accumulated skew since last update */
extern u_fp sys_maxd[];		/* total dispersion history */

/*
 * Imported from ntp_io.c
 */
extern struct interface *loopback_interface;

/*
 * Imported from ntpd module
 */
extern int debug;		/* global debug flag */
extern int correct_any;

/*
 * Imported from timer module
 */
extern u_long current_time;	/* like it says, in seconds */

/*
 * Imported from leap module
 */
extern u_char leapbits;		/* sanitized leap bits */

#if defined(KERNEL_PLL)
#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \
   MOD_STATUS | MOD_TIMECONST)
#ifdef NTP_SYSCALLS_STD
#ifdef DECL_SYSCALL
	extern int syscall	P((int, void *, ...));
#endif /* DECL_SYSCALL */
#endif /* NTP_SYSCALLS_STD */
void pll_trap		P((int));
#ifdef SIGSYS
static struct sigaction sigsys;	/* current sigaction status */
static struct sigaction newsigsys; /* new sigaction status */
static sigjmp_buf env;		/* environment var. for pll_trap() */
#endif /* SIGSYS */
#endif /* KERNEL_PLL */
#if defined(GDT_SURVEYING)
extern long sys_clock;		/* imported from ntp_proto */
extern l_fp gdt_rsadj;		/* running sum of adjustments to time */
#endif /* GDT_SURVEYING */

/*
 * init_loopfilter - initialize loop filter data
 */
void
init_loopfilter()
{
extern u_long tsf_maxslew;
u_long tsf_limit;

	/*
	 * Limit for drift_comp, minimum of two values. The first is to
	 * avoid signed overflow, the second to keep within 75% of the
	 * maximum adjustment possible in adj_systime().
	 */
	max_comp = 0x7fff0000;
#if defined(SCO3_TICKADJ) || defined(SCO5_TICKADJ)
	tsf_limit = tsf_maxslew;
#else
	tsf_limit = ((tsf_maxslew >> 1) + (tsf_maxslew >> 2));
#endif /* not SCO[35]_TICKADJ */
	if ((max_comp >> RSH_DRIFT_TO_ADJ) > (s_fp) tsf_limit)
		max_comp = tsf_limit << RSH_DRIFT_TO_ADJ;

	/*
	 * Reset clockworks
	 */
	drift_comp = 0;
	clock_adjust = 0;
	tc_counter = 0;
	sys_poll = NTP_MINPOLL;

	last_time = 0;
	clock_frequency = 0;
	clock_stability = 0;
	pps_update = pps_control = 0;
}

/*
 * local_clock - the NTP logical clock loop filter.  Returns 1 if the
 *	clock was stepped, 0 if it was slewed and -1 if it is hopeless.
 */
int
local_clock(fp_offset, peer, fastset)
	l_fp *fp_offset;	/* best offset estimate */
	struct peer *peer;	/* synch source peer structure */
	int fastset;		/* from ntp_proto - just left unsynch
				   state */
{
	long offset;
	long tmp;
	l_fp ftmp;
	s_fp stmp;
	long interval;
#if defined(KERNEL_PLL)
	struct timex ntv;
#endif /* KERNEL_PLL */

	if (last_time == 0)
		last_time = current_time;
	interval = current_time - last_time;
	 if (interval < 1)
		interval = 1;
	time_constant = min(peer->ppoll, sys_poll) - 4;
	clock_adjust = 0;
	offset = fp_offset->l_f;

#ifdef DEBUG
	if (debug > 1)
		printf(
		    "local_clock: offset %s peer %s interval %ld cutout %d)\n",
		    lfptoa(fp_offset, 6), ntoa(&peer->srcadr), interval,
		    cutout);
#endif

	/*
	 * If the clock is way off, don't tempt fate by correcting it.
	 */
	ftmp = *fp_offset;
	if (L_ISNEG(&ftmp))
		L_NEG(&ftmp);
	if (ftmp.l_ui >= CLOCK_WAYTOOBIG && !correct_any) {
		msyslog(LOG_ERR,
 		    "time error %s is way too large (set clock manually)",
		     lfptoa(fp_offset, 6));
		return (-1);

	/*
	 * If the magnitude of the offset is greater than CLOCK_MAX (128
	 * ms), reset the poll interval and wait for further
	 * instructions. Note that the cutout switch is set when the
	 * time is stepped, possibly because the frequency error is off
	 * planet. In that case all sanity checks are disabled and the
	 * discipine loop is on its own. Presumably, the loop will
	 * eventually capture the wayward oscillator (if less than 500
	 * ppm off planet) and converge, which will then reset the
	 * cutout switch.
	 */
	} else if (ftmp.l_ui > CLOCK_MAX_I || ftmp.l_f < 0
		   || (ftmp.l_ui == CLOCK_MAX_I && ftmp.l_uf >= CLOCK_MAX_F
		       && !cutout)) {
		tc_counter = 0;
		sys_poll = peer->minpoll;

		/*
		 * Either we are not in synchronization, or we have gone
		 * CLOCK_MINSTEP (900 s) since the last acceptable
		 * update. We step the clock and leave the frequency
		 * alone. Since the clock filter has been reset, the
		 * dispersions will be high upon recovery. The cutout
		 * switch will prevent the usual sanity checks in the
		 * interest of snatching a possibly wayward oscillator.
		 * Chez nous silicon.
		 */
		if (fastset || interval > CLOCK_MINSTEP) {
			step_systime(fp_offset);
			NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT)
			    msyslog(LOG_NOTICE, "time reset (%s) %s s",
#ifdef SLEWALWAYS
			    "slew",
#else
			    "step",
#endif
			    lfptoa(fp_offset, 6));
			cutout = 1;
			L_CLR(&last_offset);
			last_time = current_time;
			return (1);

		/*
		 * The local clock is out of range, but we haven't
		 * allowed enough time for the peer (usually a radio
		 * clock) to recover after a leap second. Pretend we wuz
		 * never here.
		 */
		} else {
			return (0);
		}

	/*
	 * This code segment works when the clock-adjustment code is
	 * implemented in the kernel, which at present is only in the
	 * (modified) HP 9, SunOS 4, Ultrix 4 and OSF/1 kernels. In the
	 * case of the DECstation 5000/240 and Alpha AXP, additional
	 * kernel modifications provide a true microsecond clock. We
	 * know the scaling of the frequency variable (s_fp) is the same
	 * as the kernel variable (1 << SHIFT_USEC = 16).
	 */
#if defined(KERNEL_PLL)
	} else if (pll_control && pll_enable) {
		l_fp pps_offset;
		u_fp pps_dispersion;

		/*
		 * We initialize the structure for the ntp_adjtime()
		 * system call. We have to convert everything to
		 * microseconds first. Afterwards, remember the
		 * frequency offset for the drift file.
		 */
		memset((char *)&ntv,  0, sizeof ntv);
		ntv.modes = MOD_BITS;
		if (offset >= 0) {
			TSFTOTVU(offset, ntv.offset);
		} else {
			TSFTOTVU(-offset, ntv.offset);
			ntv.offset = -ntv.offset;
		}
		ntv.esterror = sys_rootdispersion << 4;
		ntv.maxerror = ntv.esterror + (sys_rootdelay << 2);
		ntv.constant = min(peer->ppoll, sys_poll) - 4;
		ntv.status = STA_PLL;
		if (pps_enable)
			ntv.status |= STA_PPSFREQ;
		if (pps_update && pps_enable)
			ntv.status |= STA_PPSTIME;

		/*
		 * Set the leap bits in the status word.
		 */
		if (sys_leap & LEAP_ADDSECOND && sys_leap & LEAP_DELSECOND)
			ntv.status |= STA_UNSYNC;
		else if (sys_leap & LEAP_ADDSECOND)
			ntv.status |= STA_INS;
		else if (sys_leap & LEAP_DELSECOND)
			ntv.status |= STA_DEL;

		/*
		 * This astonishingly intricate wonder juggles the
		 * status bits so that the kernel loop behaves as the
		 * daemon loop; viz., selects the FLL when necessary,
		 * etc. See the comments following the #endif for
		 * explanation.
		 */
		if (sys_maxd[0] > CLOCK_MAX_FP && !cutout)
			ntv.status |= STA_FLL | STA_FREQHOLD;
		else if (sys_maxd[0] > sys_maxd[1] + sys_maxd[2] &&
		     !cutout)
			return (0);
		else if (interval >= CLOCK_MAXSEC && peer->maxpoll > 10)
			ntv.status |= STA_FLL;
		if (ntp_adjtime(&ntv) == TIME_ERROR)
			if (ntv.status != pll_status)
				msyslog(LOG_ERR,
				    "kernel pll status change %x",
				    ntv.status);
		drift_comp = ntv.freq;
		pll_status = ntv.status;

		/*
		 * If the kernel pps discipline is working, monitor its
		 * performance.
		 */
		if (pll_status & STA_PPSTIME && pll_status &
		    STA_PPSSIGNAL && ntv.shift)	{
			if (ntv.offset >= 0)
				TVUTOTSF(ntv.offset, offset);
			else {
				TVUTOTSF(-ntv.offset, offset);
				offset = -offset;
			}
		L_CLR(&pps_offset);
		L_ADDF(&pps_offset, offset);
		TVUTOTSF(ntv.jitter, tmp);
		pps_dispersion = (tmp >> 16) & 0xffff;
		if (!pps_control)
			NLOG(NLOG_SYSEVENT) /* conditional syslog */
			    msyslog(LOG_INFO, "pps sync enabled");
		pps_control = current_time;
		record_peer_stats(&loopback_interface->sin,
		    ctlsysstatus(), fp_offset, 0, pps_dispersion);
	}
#endif /* KERNEL_PLL */

	/*
	 * If the noise exceeds CLOCK_MAX_FP (128 ms), just set the
	 * clock and leave the frequency alone.
	 */
	} else if (sys_maxd[0] > CLOCK_MAX_FP && !cutout) {
#if DEBUG
		if (debug)
			printf("local_clock: dispersion exceeded %s\n",
			    ufptoa(sys_maxd[0], 5));
#endif /* DEBUG */

	/*
	 * If the noise has increased substantially over previous
	 * values, consider it a spike and ignore it. The factor of two
	 * is hard-coded.
	 */
	} else if (sys_maxd[0] > sys_maxd[1] + sys_maxd[2] && !cutout) {
#if DEBUG
		if (debug)
			printf("local_clock: spike ignored %s\n",
			    ufptoa(sys_maxd[0], 5));
#endif /* DEBUG */
		return (0);

	/*
	 * If this is the local-clock reference driver, we don't want to
	 * fidget the frequency, just fall out of the conditional and
	 * set the time.
	 */
	} else if (peer->refclktype == REFCLK_LOCALCLOCK) {

	/*
	 * If the interval between corrections is less than the Allan
	 * variance intercept point, we use a phase-lock loop to compute
	 * new values of time and frequency. The bandwidth is controlled
	 * by the time constant, which is adjusted in response to the
	 * phase error and dispersion.
	 */ 
	} else if (interval < CLOCK_MAXSEC
		   || peer->maxpoll <= NTP_MAXDPOLL) {
		long ltmp = interval;

		tmp = NTP_MAXDPOLL;
		while (ltmp < (1 << NTP_MAXDPOLL)) {
			tmp--;
			ltmp <<= 1;
		}
		tmp = RSH_FRAC_TO_FREQ - tmp + time_constant + time_constant;
		if (offset < 0)
			drift_comp -= -offset >> tmp;
		else
			drift_comp += offset >> tmp;

	/*
	 * If the interval between corrections is greater than the Allan
	 * variance intercept point, we use a hybrid frequency-lock loop
	 * to compute new values of phase and frequency. The following
	 * code is based on ideas suggested by Judah Levine of NIST and
	 * used in his "lockclock" implementation of ACTS. The magic
	 * factor of 4 in the left shift is to convert from s_fp to ppm.
	 */
	} else {
		time_constant = 2;
		stmp = (offset / interval) << 4;
		if (stmp < 0)
			drift_comp -= -stmp >> CLOCK_G;
		else
			drift_comp += stmp >> CLOCK_G;
	}
	clock_adjust = offset;

	/*
	 * As a sanity check, we clamp the frequency not to exceed the
	 * slew rate of the stock Unix adjtime() system call. Kick off
	 * the cutout switch if the dispersion falls below CLOCK_MAX_FP
	 * (128 ms).
	 */
	if (drift_comp > max_comp)
		drift_comp = max_comp;
	else if (drift_comp < -max_comp)
		drift_comp = -max_comp;
	stmp = LFPTOFP(fp_offset);
	if (stmp < 0)
		stmp = -stmp;
	if (stmp < CLOCK_MAX_FP)
		cutout = 0;
	if (interval > (1 << (peer->minpoll - 1))) {

		/*
		 * Determine when to adjust the poll interval. We do
		 * this regardless of what source controls the loop,
		 * since we might flap back and forth between sources.
		 */
		if (stmp > (s_fp)sys_maxd[0]) {
			tc_counter -= (int)sys_poll << 1;
			if (tc_counter < -CLOCK_LIMIT) {
				tc_counter = -CLOCK_LIMIT;
				if (sys_poll > peer->minpoll) {
					sys_poll--;
					tc_counter = 0;
				}
			}
		} else {
			tc_counter += (int)sys_poll;
			if (tc_counter > CLOCK_LIMIT) {
				tc_counter = CLOCK_LIMIT;
				if (sys_poll < peer->maxpoll) {
					sys_poll++;
					tc_counter = 0;
			}
		}
	}

	/*
	 * Calculate the frequency offset and frequency
	 * stability. These are useful for performance
	 * monitoring, but do not affect the loop variables. The
	 * results are scaled as a s_fp in ppm, because we know
	 * more than we should.
	 */
	ftmp = *fp_offset;
	L_SUB(&ftmp, &last_offset);
	clock_frequency = (LFPTOFP(&ftmp) / interval) << 20;
	if (clock_frequency < -max_comp)
		clock_frequency = -max_comp;
	else if (clock_frequency > max_comp)
		clock_frequency = max_comp;
	stmp = clock_frequency;
	if (stmp < 0)
		stmp = -stmp;
	stmp -= clock_stability;
	if (stmp < 0)
		clock_stability -= -stmp >> NTP_MAXD;
	else
		clock_stability += stmp >> NTP_MAXD;
	}
	last_offset = *fp_offset;
	last_time = current_time;
#ifdef DEBUG
	if (debug > 1)
		printf(
		    "local_clock: phase %s freq %s disp %s poll %d count %d\n",
		    mfptoa((clock_adjust < 0 ? -1 : 0), clock_adjust, 6),
		    fptoa(drift_comp, 3), fptoa(sys_maxd[0], 5),
		    sys_poll, tc_counter);
#endif /* DEBUG */

	(void) record_loop_stats(fp_offset, drift_comp, (unsigned)sys_poll);
	
	/*
	 * Whew. I've had enough.
	 */
	return (0);
}


/*
 * adj_host_clock - Called once every second to update the local clock.
 */
void
adj_host_clock()
{
	register long adjustment;
	l_fp offset;

	/*
	 * Update the dispersion since the last update. Don't allow
	 * frequency measurements over periods longer than NTP_MAXAGE
	 * (86400 s = one day).
	 */
	if (current_time - last_time > NTP_MAXAGE)
		last_time = 0;
	L_ADDUF(&sys_refskew, NTP_SKEWINC);

	/*
	 * Declare PPS kernel unsync if the pps signal has not been
	 * heard for a few minutes.
	 */
	if (pps_control && current_time - pps_control > PPS_MAXAGE) {
		if (pps_control)
		    NLOG(NLOG_SYSEVENT) /* conditional if clause */
		    msyslog(LOG_INFO, "pps sync disabled");
		pps_control = 0;
	}

 	/*
 	 * If the phase-lock loop is not implemented in the kernel, we
	 * do it the hard way using incremental adjustments and the
	 * adjtime() system call.
	 */
	if (pll_control && pll_enable)
		return;
	adjustment = clock_adjust;
	if (adjustment < 0)
		adjustment = -(-adjustment >> (CLOCK_PHASE + time_constant));
	else
		adjustment >>= CLOCK_PHASE + time_constant;
	clock_adjust -= adjustment;
	if (drift_comp < 0)
		adjustment -= -drift_comp >> RSH_DRIFT_TO_ADJ;
	else
		adjustment += drift_comp >> RSH_DRIFT_TO_ADJ;

	/*
	 * Intricate wrinkle. If the local clock driver is in use and
	 * selected for synchronization, somebody else may be tinker the
	 * adjtime() syscall. In this case we have to avoid calling
	 * adjtime(), since that may truncate the other guy's requests.
	 * That means the local clock fudge time and frequency
	 * adjustments don't work in that case. Caveat empty.
	 */
	if (sys_peer) {
		if (sys_peer->refclktype == REFCLK_LOCALCLOCK &&
		    sys_peer->flags & FLAG_PREFER) {
                       /* I think that sys_clock_offset might be jammed
                        * to exactly zero now.  It might have had a
                        * small residual before things switched to the
                        * local refclock prefer at lower stratum, or a
                        * glitch might have happened during interrupts
                        * when the external control jumped the time */
	                L_CLR(&sys_clock_offset);
			return;
		}
 	}
	L_CLR(&offset);
	L_ADDF(&offset, adjustment);
	adj_systime(&offset);
}


/*
 * adj_frequency - adjust local clock frequency
 */
void
adj_frequency(freq)
     s_fp freq;			/* frequency (ppm) */
{
#if defined(KERNEL_PLL)
	struct timex ntv;
#endif /* KERNEL_PLL */

	/*
	 * This routine adjusts the frequency offset. It is used by the
	 * local clock driver to adjust frequency when no external
	 * discipline source is available and by the acts driver when
	 * the interval between updates is greater than 1 << NTP_MAXPOLL.
	 * Note that the maximum offset is limited by max_comp when
	 * the daemon pll is used, but the maximum may be different
	 * when the kernel pll is used.
	 */
	drift_comp += freq;
	if (drift_comp > max_comp)
		drift_comp = max_comp;
	else if (drift_comp < -max_comp)
		drift_comp = -max_comp;
#if defined(KERNEL_PLL)
	/*
	 * If the phase-lock code is implemented in the kernel, set the
	 * kernel frequency as well, but be sure to set drift_comp to
	 * the actual frequency.
	 */
	if (!(pll_control && pll_enable))
		return;
	memset((char *)&ntv, 0, sizeof ntv);
	ntv.modes = MOD_FREQUENCY;
	ntv.freq = freq + drift_comp;
	if (ntp_adjtime(&ntv) < 0)
		msyslog(LOG_ERR,
		    "adj_frequency: ntp_adjtime failed: %m");
	drift_comp = ntv.freq;
#endif /* KERNEL_PLL */
}


/*
 * loop_config - configure the loop filter
 */
void
loop_config(item, lfp_value)
	int item;
	l_fp *lfp_value;
{
#if defined(KERNEL_PLL)
	struct timex ntv;
#endif /* KERNEL_PLL */

#ifdef DEBUG
	if (debug)
		printf("loop_config %d %s\n",
		    item, lfptoa(lfp_value, 3));
#endif
	switch (item) {

	case LOOP_DRIFTCOMP:
		drift_comp = LFPTOFP(lfp_value);
		if (drift_comp > max_comp)
			drift_comp = max_comp;
		if (drift_comp < -max_comp)
			drift_comp = -max_comp;

#if defined(KERNEL_PLL)
		/*
		 * If the phase-lock code is implemented in the kernel,
		 * give the time_constant and saved frequency offset to
		 * the kernel. If not, no harm is done. We do this
		 * whether or not the use of the kernel mods is
		 * requested, in order to clear out the trash from
		 * possible prior customers.
		 */
		memset((char *)&ntv, 0, sizeof ntv);
		pll_control = 1;
		ntv.modes = MOD_BITS | MOD_FREQUENCY;
		ntv.freq = drift_comp;
		ntv.maxerror = NTP_MAXDISPERSE;
		ntv.esterror = NTP_MAXDISPERSE;
		ntv.status = STA_PLL | STA_UNSYNC;
		ntv.constant = sys_poll - 4;
#ifdef SIGSYS
		newsigsys.sa_handler = pll_trap;
		newsigsys.sa_flags = 0;
		if ((sigaction(SIGSYS, &newsigsys, &sigsys)))
		msyslog(LOG_ERR,
		    "sigaction() fails to save SIGSYS trap: %m");

		/*
		 * Note ntp_adjtime() normally fails on the first call,
		 * since we deliberately set the clock unsynchronized.
		 * Use sigsetjmp() to save state and then call
		 * ntp_adjtime(); if it fails, then siglongjmp() is used
		 * to return control
		 */
		if (sigsetjmp(env, 1) == 0) {
#endif /* SIGSYS */
			if (ntp_adjtime(&ntv) < 0) {
				msyslog(LOG_ERR,
				    "loop_config: ntp_adjtime() failed: %m");
			}
#ifdef SIGSYS
		}
		if ((sigaction(SIGSYS, &sigsys, (struct sigaction
		    *)NULL)))
			msyslog(LOG_ERR,
			    "sigaction() fails to restore SIGSYS trap: %m");
#endif /* SIGSYS */
		if (pll_control)
			NLOG(NLOG_SYSEVENT)	/* conditional syslog */
			    msyslog(LOG_NOTICE,
			    "using kernel phase-lock loop %04x", ntv.status);
		else
			NLOG(NLOG_SYSEVENT)	/* conditional syslog */
			    msyslog(LOG_NOTICE,
			    "using xntpd phase-lock loop");
#endif /* KERNEL_PLL */
		break;

	default:
		/* sigh */
		break;
	}
}


#if defined(KERNEL_PLL) && defined(SIGSYS)
/*
 * _trap - trap processor for undefined syscalls
 *
 * This nugget is called by the kernel when the SYS_ntp_adjtime()
 * syscall bombs because the silly thing has not been implemented in
 * the kernel. In this case the phase-lock loop is emulated by
 * the stock adjtime() syscall and a lot of indelicate abuse.
 */
RETSIGTYPE
pll_trap(arg)
	int arg;
{
	pll_control = 0;
	siglongjmp(env, 1);
}
#endif /* KERNEL_PLL && SIGSYS */