summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
committerdelphij <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
commit2a25cee78ab1d37e7d2bc40ae675646974d99f56 (patch)
treeb0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/ntpd
parenta0741a75537b2e0514472ac3b28afc55a7846c30 (diff)
downloadFreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.zip
FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.tar.gz
MFC r280849,280915-280916,281015-281016,282097,282408,282415,283542,
284864,285169-285170,285435: ntp 4.2.8p3. Relnotes: yes Approved by: re (?)
Diffstat (limited to 'contrib/ntp/ntpd')
-rw-r--r--contrib/ntp/ntpd/Makefile.am493
-rw-r--r--contrib/ntp/ntpd/Makefile.in1936
-rw-r--r--contrib/ntp/ntpd/check_y2k.c1
-rw-r--r--contrib/ntp/ntpd/cmd_args.c165
-rw-r--r--contrib/ntp/ntpd/complete.conf.in69
-rw-r--r--contrib/ntp/ntpd/declcond.h21
-rw-r--r--contrib/ntp/ntpd/invoke-ntp.conf.menu1
-rw-r--r--contrib/ntp/ntpd/invoke-ntp.conf.texi2677
-rw-r--r--contrib/ntp/ntpd/invoke-ntp.keys.menu1
-rw-r--r--contrib/ntp/ntpd/invoke-ntp.keys.texi125
-rw-r--r--contrib/ntp/ntpd/invoke-ntpd.menu (renamed from contrib/ntp/ntpd/ntpd-opts.menu)0
-rw-r--r--contrib/ntp/ntpd/invoke-ntpd.texi719
-rw-r--r--contrib/ntp/ntpd/keyword-gen-utd1
-rw-r--r--contrib/ntp/ntpd/keyword-gen.c755
-rw-r--r--contrib/ntp/ntpd/ntp.conf.5man3052
-rw-r--r--contrib/ntp/ntpd/ntp.conf.5mdoc2853
-rw-r--r--contrib/ntp/ntpd/ntp.conf.def2840
-rw-r--r--contrib/ntp/ntpd/ntp.conf.html2663
-rw-r--r--contrib/ntp/ntpd/ntp.conf.man.in3052
-rw-r--r--contrib/ntp/ntpd/ntp.conf.mdoc.in2853
-rw-r--r--contrib/ntp/ntpd/ntp.conf.texi49
-rw-r--r--contrib/ntp/ntpd/ntp.keys.5man173
-rw-r--r--contrib/ntp/ntpd/ntp.keys.5mdoc158
-rw-r--r--contrib/ntp/ntpd/ntp.keys.def152
-rw-r--r--contrib/ntp/ntpd/ntp.keys.html200
-rw-r--r--contrib/ntp/ntpd/ntp.keys.man.in173
-rw-r--r--contrib/ntp/ntpd/ntp.keys.mdoc.in158
-rw-r--r--contrib/ntp/ntpd/ntp.keys.texi49
-rw-r--r--contrib/ntp/ntpd/ntp_config.c6517
-rw-r--r--contrib/ntp/ntpd/ntp_control.c4408
-rw-r--r--contrib/ntp/ntpd/ntp_crypto.c3360
-rw-r--r--contrib/ntp/ntpd/ntp_filegen.c611
-rw-r--r--contrib/ntp/ntpd/ntp_intres.c1185
-rw-r--r--contrib/ntp/ntpd/ntp_io.c5359
-rw-r--r--contrib/ntp/ntpd/ntp_keyword.h1068
-rw-r--r--contrib/ntp/ntpd/ntp_leapsec.c1186
-rw-r--r--contrib/ntp/ntpd/ntp_leapsec.h276
-rw-r--r--contrib/ntp/ntpd/ntp_loopfilter.c1271
-rw-r--r--contrib/ntp/ntpd/ntp_monitor.c572
-rw-r--r--contrib/ntp/ntpd/ntp_parser.c3888
-rw-r--r--contrib/ntp/ntpd/ntp_parser.h485
-rw-r--r--contrib/ntp/ntpd/ntp_peer.c1285
-rw-r--r--contrib/ntp/ntpd/ntp_prio_q.c238
-rw-r--r--contrib/ntp/ntpd/ntp_proto.c4316
-rw-r--r--contrib/ntp/ntpd/ntp_refclock.c801
-rw-r--r--contrib/ntp/ntpd/ntp_request.c2016
-rw-r--r--contrib/ntp/ntpd/ntp_restrict.c986
-rw-r--r--contrib/ntp/ntpd/ntp_scanner.c935
-rw-r--r--contrib/ntp/ntpd/ntp_scanner.h142
-rw-r--r--contrib/ntp/ntpd/ntp_signd.c239
-rw-r--r--contrib/ntp/ntpd/ntp_timer.c701
-rw-r--r--contrib/ntp/ntpd/ntp_util.c878
-rw-r--r--contrib/ntp/ntpd/ntpd-opts.c2113
-rw-r--r--contrib/ntp/ntpd/ntpd-opts.def606
-rw-r--r--contrib/ntp/ntpd/ntpd-opts.h320
-rw-r--r--contrib/ntp/ntpd/ntpd-opts.texi496
-rw-r--r--contrib/ntp/ntpd/ntpd.1296
-rw-r--r--contrib/ntp/ntpd/ntpd.1ntpdman1001
-rw-r--r--contrib/ntp/ntpd/ntpd.1ntpdmdoc904
-rw-r--r--contrib/ntp/ntpd/ntpd.c1467
-rw-r--r--contrib/ntp/ntpd/ntpd.html1019
-rw-r--r--contrib/ntp/ntpd/ntpd.man.in1001
-rw-r--r--contrib/ntp/ntpd/ntpd.mdoc.in904
-rw-r--r--contrib/ntp/ntpd/ntpd.texi113
-rw-r--r--contrib/ntp/ntpd/ntpdbase-opts.def296
-rw-r--r--contrib/ntp/ntpd/ntpdsim-opts.c1262
-rw-r--r--contrib/ntp/ntpd/ntpdsim-opts.def15
-rw-r--r--contrib/ntp/ntpd/ntpdsim-opts.h422
-rw-r--r--contrib/ntp/ntpd/ntpdsim-opts.menu1
-rw-r--r--contrib/ntp/ntpd/ntpdsim-opts.texi568
-rw-r--r--contrib/ntp/ntpd/ntpdsim.1357
-rw-r--r--contrib/ntp/ntpd/ntpsim.c856
-rw-r--r--contrib/ntp/ntpd/rc_cmdlength.c35
-rw-r--r--contrib/ntp/ntpd/refclock_acts.c906
-rw-r--r--contrib/ntp/ntpd/refclock_arbiter.c106
-rw-r--r--contrib/ntp/ntpd/refclock_arc.c380
-rw-r--r--contrib/ntp/ntpd/refclock_as2201.c58
-rw-r--r--contrib/ntp/ntpd/refclock_atom.c408
-rw-r--r--contrib/ntp/ntpd/refclock_bancomm.c185
-rw-r--r--contrib/ntp/ntpd/refclock_chronolog.c46
-rw-r--r--contrib/ntp/ntpd/refclock_chu.c758
-rw-r--r--contrib/ntp/ntpd/refclock_conf.c29
-rw-r--r--contrib/ntp/ntpd/refclock_datum.c213
-rw-r--r--contrib/ntp/ntpd/refclock_dumbclock.c85
-rw-r--r--contrib/ntp/ntpd/refclock_fg.c234
-rw-r--r--contrib/ntp/ntpd/refclock_gpsdjson.c2210
-rw-r--r--contrib/ntp/ntpd/refclock_gpsvme.c27
-rw-r--r--contrib/ntp/ntpd/refclock_heath.c33
-rw-r--r--contrib/ntp/ntpd/refclock_hopfpci.c51
-rw-r--r--contrib/ntp/ntpd/refclock_hopfser.c79
-rw-r--r--contrib/ntp/ntpd/refclock_hpgps.c75
-rw-r--r--contrib/ntp/ntpd/refclock_irig.c819
-rw-r--r--contrib/ntp/ntpd/refclock_jjy.c4652
-rw-r--r--contrib/ntp/ntpd/refclock_jupiter.c235
-rw-r--r--contrib/ntp/ntpd/refclock_leitch.c100
-rw-r--r--contrib/ntp/ntpd/refclock_local.c88
-rw-r--r--contrib/ntp/ntpd/refclock_msfees.c80
-rw-r--r--contrib/ntp/ntpd/refclock_mx4200.c137
-rw-r--r--contrib/ntp/ntpd/refclock_neoclock4x.c107
-rw-r--r--contrib/ntp/ntpd/refclock_nmea.c2268
-rw-r--r--contrib/ntp/ntpd/refclock_oncore.c1689
-rw-r--r--contrib/ntp/ntpd/refclock_palisade.c1078
-rw-r--r--contrib/ntp/ntpd/refclock_palisade.h72
-rw-r--r--contrib/ntp/ntpd/refclock_parse.c1717
-rw-r--r--contrib/ntp/ntpd/refclock_pcf.c19
-rw-r--r--contrib/ntp/ntpd/refclock_pst.c44
-rw-r--r--contrib/ntp/ntpd/refclock_ripencc.c3569
-rw-r--r--contrib/ntp/ntpd/refclock_shm.c696
-rw-r--r--contrib/ntp/ntpd/refclock_tpro.c46
-rw-r--r--contrib/ntp/ntpd/refclock_trak.c359
-rw-r--r--contrib/ntp/ntpd/refclock_true.c424
-rw-r--r--contrib/ntp/ntpd/refclock_tsyncpci.c912
-rw-r--r--contrib/ntp/ntpd/refclock_tt560.c22
-rw-r--r--contrib/ntp/ntpd/refclock_ulink.c75
-rw-r--r--contrib/ntp/ntpd/refclock_wwv.c456
-rw-r--r--contrib/ntp/ntpd/refclock_wwvb.c236
-rw-r--r--contrib/ntp/ntpd/refclock_zyfer.c67
117 files changed, 79193 insertions, 28821 deletions
diff --git a/contrib/ntp/ntpd/Makefile.am b/contrib/ntp/ntpd/Makefile.am
index 6896b45..c94f7c0 100644
--- a/contrib/ntp/ntpd/Makefile.am
+++ b/contrib/ntp/ntpd/Makefile.am
@@ -1,108 +1,439 @@
-AUTOMAKE_OPTIONS= ../util/ansi2knr
+NULL=
-bindir= ${exec_prefix}/${BINSUBDIR}
-
-bin_PROGRAMS= ntpd @MAKE_NTPDSIM@
+bin_PROGRAMS= $(NTPD_DB) $(NTPDSIM_DB)
+libexec_PROGRAMS= $(NTPD_DL) $(NTPDSIM_DL)
+sbin_PROGRAMS= $(NTPD_DS) $(NTPDSIM_DS)
noinst_LIBRARIES= libntpd.a
-AM_CPPFLAGS= -I$(top_srcdir)/include -I../include $(LIBOPTS_CFLAGS)
+AM_CFLAGS = $(CFLAGS_NTP)
+
+AM_CPPFLAGS = $(NTP_INCS)
+AM_CPPFLAGS += $(LIBOPTS_CFLAGS)
+AM_CPPFLAGS += $(CPPFLAGS_NTP)
+
+AM_LDFLAGS = $(LDFLAGS_NTP)
+
# LDADD might need RESLIB and ADJLIB.
-LDADD= version.o libntpd.a @LIBPARSE@
-
-BUILT_SOURCES= ntpd-opts.c ntpd-opts.h ntpd.1 ntpd-opts.texi ntpd-opts.menu
-man_MANS= ntpd.1
-
-BUILT_SOURCES+= ntpdsim-opts.c ntpdsim-opts.h ntpdsim.1 ntpdsim-opts.texi ntpdsim-opts.menu
-man_MANS+= ntpdsim.1
-
-# ntpd may need:
-# log10 refclock_wwv.o
-# sqrt ntp_control.o
-# floor refclock_wwv.o
-# which are (usually) provided by -lm.
-ntpd_LDADD = $(LDADD) -lm @LCRYPTO@ $(LIBOPTS_LDADD) ../libntp/libntp.a
-ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a -lm @LCRYPTO@ $(LIBOPTS_LDADD)
-ntpdsim_CFLAGS = $(CFLAGS) -DSIM
-check_y2k_LDADD = $(LDADD) ../libntp/libntp.a
-DISTCLEANFILES = .version version.c
-EXTRA_DIST = ntpd-opts.def ntpdbase-opts.def ntpdsim-opts.def \
+LDADD = version.o libntpd.a $(LIBPARSE)
+AM_YFLAGS = -d -t -r all
+
+if SAVECONFIG_ENABLED
+if NTP_CROSSCOMPILE
+CHECK_SAVECONFIG=
+else
+CHECK_SAVECONFIG= check-saveconfig
+endif
+else !SAVECONFIG_ENABLED
+CHECK_SAVECONFIG=
+endif
+
+#
+# VPHACK and VPHACK_AFTER are enabled on non-GNU makes (such as
+# BSD make) to work around issues specific to compiling
+# ntp_parser.y into ntp_parser.h and ntp_parser.c in a VPATH
+# configuration where we would like (for a change) the output
+# files ntp_parser.[ch] to be placed in the source directory,
+# as opposed to the build directory. This allows a single
+# host of a flock configured with Bison to update ntp_parser.[ch]
+# used by the rest.
+#
+
+if VPATH_HACK
+VPHACK= vphack
+VPHACK_AFTER= vphack_after
+else
+VPHACK=
+VPHACK_AFTER=
+endif
+
+vphack:
+ test -e ntp_parser.c || ln -s $(srcdir)/ntp_parser.c .
+ test -e ntp_parser.h || ln -s $(srcdir)/ntp_parser.h .
+
+#
+# ylwrap script which invokes Bison replaces ntp_parser.h
+# symlink with the updated file, when ntp_parser.h changes.
+# vphack_after detects this and copies the updated file to srcdir
+# and re-creates the ntp_parser.h symlink in its place.
+#
+
+vphack_after:
+ test -L ntp_parser.h || ( \
+ mv ntp_parser.h $(srcdir)/ntp_parser.h && \
+ ln -s $(srcdir)/ntp_parser.h . \
+ )
+
+# BUILT_SOURCES which should also be in EXTRA_DIST
+B_S_DIST= \
+ $(srcdir)/ntpd-opts.c \
+ $(srcdir)/ntpd-opts.h \
+ $(NULL)
+
+BUILT_SOURCES= \
+ $(VPHACK) \
+ $(LIBPARSE) \
+ ntp_parser.c \
+ ntp_parser.h \
+ $(VPHACK_AFTER) \
+ $(B_S_DIST) \
+ $(NULL)
+
+man1_MANS=
+man5_MANS= ntp.conf.5 ntp.keys.5
+man8_MANS=
+man_MANS= ntpd.$(NTPD_MS)
+
+# ntpdsim.1 is a remnant along with all the ntpdsim-opts.* files, the
+# simulator currently uses ntpd-opts.[ch]. This also means there is no
+# longer a reason to have ntpdbase-opts.def split off of ntpd-opts.def.
+
+LDADD_NTPD_COMMON = $(LDADD_LIBNTP) $(LIBOPTS_LDADD) $(PTHREAD_LIBS)
+LDADD_NTPD_COMMON += $(LIBM) $(LDADD_NTP) $(LSCF)
+ntpd_LDADD = $(LDADD) ../libntp/libntp.a $(LDADD_NTPD_COMMON) $(LDADD_LIBUTIL)
+ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a $(LDADD_NTPD_COMMON)
+ntpdsim_CPPFLAGS = $(AM_CPPFLAGS) -DSIM
+check_y2k_LDADD = $(LDADD) ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(LDADD_LIBNTP) $(PTHREAD_LIBS)
+## we don't want $(LDADD) in keyword_gen_LDADD
+keyword_gen_LDADD = ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(PTHREAD_LIBS)
+
+DISTCLEANFILES = \
+ keyword-gen \
+ .version \
+ version.c \
+ config.log \
+ $(man5_MANS) \
+ $(man_MANS) \
+ $(NULL)
+
+CLEANFILES = \
+ check-saveconfig \
+ compsave.conf \
+ k-g-u-submake \
+ $(EXTRA_PROGRAMS) \
+ $(NULL)
+
+EXTRA_DIST = \
+ complete.conf.in \
+ invoke-ntp.conf.menu \
+ invoke-ntp.conf.texi \
+ invoke-ntp.keys.menu \
+ invoke-ntp.keys.texi \
+ invoke-ntpd.menu \
+ invoke-ntpd.texi \
+ keyword-gen-utd \
+ ntp.conf.5man \
+ ntp.conf.5mdoc \
+ ntp.conf.def \
+ ntp.conf.man.in \
+ ntp.conf.mdoc.in \
+ ntp.conf.html \
+ ntp.conf.texi \
+ ntp.keys.5man \
+ ntp.keys.5mdoc \
+ ntp.keys.def \
+ ntp.keys.man.in \
+ ntp.keys.mdoc.in \
+ ntp.keys.html \
+ ntp.keys.texi \
+ ntpd-opts.def \
+ ntpd.1ntpdman \
+ ntpd.1ntpdmdoc \
+ ntpd.man.in \
+ ntpd.mdoc.in \
+ ntpd.html \
+ ntpd.texi \
+ ntpdbase-opts.def \
refclock_msfees.c \
- refclock_trak.c \
- $(BUILT_SOURCES)
-ETAGS_ARGS = Makefile.am
+ $(B_S_DIST) \
+ $(NULL)
+
### Y2Kfixes
check_PROGRAMS = @MAKE_CHECK_Y2K@
-EXTRA_PROGRAMS = check_y2k ntpdsim
-run_ag = cd $(srcdir) && autogen -L ../include --writable
-std_def_list= $(top_srcdir)/include/debug-opt.def \
- $(top_srcdir)/include/autogen-version.def \
- $(top_srcdir)/include/copyright.def \
- $(top_srcdir)/include/version.def
-
-check-local: @MAKE_CHECK_Y2K@
- test -z "@MAKE_CHECK_Y2K@" || ./@MAKE_CHECK_Y2K@
-
-# SIM: cmd_args.c ntp_config.c ntp_io.c ntpd.c + ntpsim.c (include/ntpsim.h)
-# ntp_resolver.c is presently unused...
-ntpd_SOURCES = cmd_args.c ntp_config.c ntp_io.c ntpd.c ntpd-opts.c ntpd-opts.h
-ntpdsim_SOURCES = $(ntpd_SOURCES) ntpsim.c ntpdsim-opts.c ntpdsim-opts.h
-libntpd_a_SOURCES = jupiter.h ntp_control.c \
- ntp_crypto.c ntp_filegen.c \
- ntp_intres.c ntp_loopfilter.c ntp_monitor.c ntp_peer.c \
- ntp_proto.c ntp_refclock.c ntp_request.c \
- ntp_restrict.c ntp_timer.c ntp_util.c \
- ppsapi_timepps.h \
- refclock_acts.c refclock_arbiter.c refclock_arc.c refclock_as2201.c \
- refclock_atom.c refclock_bancomm.c refclock_chronolog.c \
- refclock_chu.c refclock_conf.c refclock_datum.c refclock_dumbclock.c \
- refclock_fg.c refclock_gpsvme.c refclock_heath.c refclock_hopfser.c \
- refclock_hopfpci.c refclock_hpgps.c refclock_irig.c refclock_jjy.c \
- refclock_jupiter.c refclock_leitch.c refclock_local.c \
- refclock_mx4200.c refclock_neoclock4x.c \
- refclock_nmea.c refclock_oncore.c refclock_palisade.c \
- refclock_palisade.h refclock_parse.c \
- refclock_pcf.c refclock_pst.c refclock_ripencc.c refclock_shm.c \
- refclock_tpro.c refclock_true.c refclock_tt560.c \
- refclock_ulink.c refclock_wwv.c refclock_wwvb.c \
- refclock_zyfer.c
+EXTRA_PROGRAMS = check_y2k keyword-gen ntpd ntpdsim
+
+html_DATA= \
+ $(srcdir)/ntp.conf.html \
+ $(srcdir)/ntp.keys.html \
+ $(srcdir)/ntpd.html \
+ $(NULL)
+
+noinst_DATA = \
+ $(srcdir)/invoke-ntp.conf.menu \
+ $(srcdir)/invoke-ntp.conf.texi \
+ $(srcdir)/invoke-ntp.keys.menu \
+ $(srcdir)/invoke-ntp.keys.texi \
+ $(srcdir)/invoke-ntpd.menu \
+ $(srcdir)/invoke-ntpd.texi \
+ $(srcdir)/ntp.conf.man.in \
+ $(srcdir)/ntp.conf.mdoc.in \
+ $(srcdir)/ntp.keys.man.in \
+ $(srcdir)/ntp.keys.mdoc.in \
+ $(srcdir)/ntpd.man.in \
+ $(srcdir)/ntpd.mdoc.in \
+ $(NULL)
+
+noinst_HEADERS = \
+ declcond.h \
+ ntp_leapsec.h \
+ $(NULL)
+
+install-data-local: install-html
+
+run_ag= cd $(srcdir) && env PATH="$(abs_builddir):$(PATH)" AUTOGEN_DNE_DATE=-D \
+ autogen -L ../sntp/include -L ../sntp/ag-tpl --writable
+std_def_list = \
+ $(top_srcdir)/sntp/include/debug-opt.def \
+ $(top_srcdir)/sntp/include/autogen-version.def \
+ $(top_srcdir)/sntp/include/copyright.def \
+ $(top_srcdir)/sntp/include/homerc.def \
+ $(top_srcdir)/sntp/include/ntp.lic \
+ $(top_srcdir)/sntp/include/version.def \
+ $(NULL)
+
+check-local: $(MAKE_CHECK_Y2K) $(CHECK_SAVECONFIG)
+ test -z "$(MAKE_CHECK_Y2K)" || ./$(MAKE_CHECK_Y2K)
+
+ntpd_SOURCES = \
+ ntp_config.c \
+ ntp_keyword.h \
+ ntp_io.c \
+ ntp_parser.y \
+ ntp_scanner.c \
+ ntp_scanner.h \
+ ntpd.c \
+ ntpd-opts.c \
+ ntpd-opts.h \
+ $(NULL)
+
+ntpdsim_SOURCES = \
+ $(ntpd_SOURCES) \
+ ntp_prio_q.c \
+ ntpsim.c \
+ $(NULL)
+
+# libntpd_a_SOURCES do not use #ifdef SIM
+
+libntpd_a_SOURCES = \
+ cmd_args.c \
+ jupiter.h \
+ ntp_control.c \
+ ntp_crypto.c \
+ ntp_filegen.c \
+ ntp_leapsec.c \
+ ntp_loopfilter.c \
+ ntp_monitor.c \
+ ntp_peer.c \
+ ntp_proto.c \
+ ntp_refclock.c \
+ ntp_request.c \
+ ntp_restrict.c \
+ ntp_signd.c \
+ ntp_timer.c \
+ ntp_util.c \
+ ppsapi_timepps.h \
+ rc_cmdlength.c \
+ refclock_acts.c \
+ refclock_arbiter.c \
+ refclock_arc.c \
+ refclock_as2201.c \
+ refclock_atom.c \
+ refclock_bancomm.c \
+ refclock_chronolog.c \
+ refclock_chu.c \
+ refclock_conf.c \
+ refclock_datum.c \
+ refclock_dumbclock.c \
+ refclock_fg.c \
+ refclock_gpsdjson.c \
+ refclock_gpsvme.c \
+ refclock_heath.c \
+ refclock_hopfser.c \
+ refclock_hopfpci.c \
+ refclock_hpgps.c \
+ refclock_irig.c \
+ refclock_jjy.c \
+ refclock_jupiter.c \
+ refclock_leitch.c \
+ refclock_local.c \
+ refclock_mx4200.c \
+ refclock_neoclock4x.c \
+ refclock_nmea.c \
+ refclock_oncore.c \
+ refclock_palisade.c \
+ refclock_palisade.h \
+ refclock_parse.c \
+ refclock_pcf.c \
+ refclock_pst.c \
+ refclock_ripencc.c \
+ refclock_shm.c \
+ refclock_tpro.c \
+ refclock_true.c \
+ refclock_tt560.c \
+ refclock_ulink.c \
+ refclock_wwv.c \
+ refclock_wwvb.c \
+ refclock_zyfer.c \
+ refclock_tsyncpci.c \
+ $(NULL)
+
+k-g-u-submake: keyword-gen
+ ./keyword-gen $(srcdir)/ntp_parser.h > k-g.out
+ @grep -v diff_ignore_line < k-g.out > cmp1
+ @grep -v diff_ignore_line < $(srcdir)/ntp_keyword.h > cmp2
+ @cmp cmp1 cmp2 > /dev/null || \
+ { mv -f k-g.out $(srcdir)/ntp_keyword.h && \
+ echo 'Generated changed ntp_keyword.h.' ;}
+ @[ ! -f k-g.out ] || \
+ { rm k-g.out && echo 'ntp_keyword.h is up to date.' ;}
+ @rm cmp1 cmp2
+ @echo 'keyword-gen and ntp_keyword.h are up to date.' > $@
+
+$(srcdir)/keyword-gen-utd: $(srcdir)/keyword-gen.c $(srcdir)/ntp_parser.h
+ $(MAKE) $(AM_MAKEFLAGS) k-g-u-submake # avoid explicit dependency
+ grep diff_ignore_line $(srcdir)/ntp_keyword.h > k-g-u
+ mv -f k-g-u $@
+
+$(srcdir)/ntp_keyword.h: $(srcdir)/keyword-gen-utd
+ @: do-nothing action to avoid default SCCS get
+ @: .h updated if needed by k-g-u-submake rule
$(srcdir)/ntpd-opts.h: $(srcdir)/ntpd-opts.c
+ @: do-nothing action to avoid default SCCS get, .h built with .c
+
$(srcdir)/ntpd-opts.c: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
$(run_ag) ntpd-opts.def
-$(srcdir)/ntpd.1: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
- $(run_ag) -Tagman1.tpl -bntpd ntpd-opts.def
+###
-$(srcdir)/ntpd-opts.texi $(srcdir)/ntpd-opts.menu: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
- $(run_ag) -Taginfo.tpl -DLEVEL=section ntpd-opts.def
+$(srcdir)/ntpd.1ntpdman: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=1ntpdman -Tagman-cmd.tpl ntpd-opts.def
-$(srcdir)/ntpdsim-opts.h: $(srcdir)/ntpdsim-opts.c
-$(srcdir)/ntpdsim-opts.c: $(srcdir)/ntpdsim-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list) $(top_srcdir)/include/homerc.def
- $(run_ag) ntpdsim-opts.def
+$(srcdir)/ntpd.man.in: $(srcdir)/ntpd.1ntpdman $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntpd.1ntpdman > $(srcdir)/ntpd.man.in+
+ mv $(srcdir)/ntpd.man.in+ $(srcdir)/ntpd.man.in
-$(srcdir)/ntpdsim.1: $(srcdir)/ntpdsim-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list) $(top_srcdir)/include/homerc.def
- $(run_ag) -Tagman1.tpl -bntpdsim ntpdsim-opts.def
+###
-$(srcdir)/ntpdsim-opts.texi $(srcdir)/ntpdsim-opts.menu: $(srcdir)/ntpdsim-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list) $(top_srcdir)/include/homerc.def
- $(run_ag) -Taginfo.tpl -DLEVEL=section ntpdsim-opts.def
+$(srcdir)/ntpd.1ntpdmdoc: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=1ntpdmdoc -Tagmdoc-cmd.tpl ntpd-opts.def
+
+$(srcdir)/ntpd.mdoc.in: $(srcdir)/ntpd.1ntpdmdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntpd.1ntpdmdoc > $(srcdir)/ntpd.mdoc.in+
+ mv $(srcdir)/ntpd.mdoc.in+ $(srcdir)/ntpd.mdoc.in
+
+###
+
+ntpd.$(NTPD_MS): $(srcdir)/ntpd.$(MANTAGFMT).in $(top_builddir)/config.status
+ $(top_builddir)/config.status --file=ntpd.$(NTPD_MS)+:$(srcdir)/ntpd.$(MANTAGFMT).in
+ mv ntpd.$(NTPD_MS)+ ntpd.$(NTPD_MS)
+
+###
+
+$(srcdir)/invoke-ntp.conf.menu: $(srcdir)/invoke-ntp.conf.texi
+ @: do-nothing action to avoid default SCCS get, .menu built with .texi
+
+$(srcdir)/invoke-ntp.conf.texi: $(srcdir)/ntp.conf.def $(std_def_list)
+ $(run_ag) -Tagtexi-file.tpl -DLEVEL=section ntp.conf.def
+
+$(srcdir)/invoke-ntp.keys.menu: $(srcdir)/invoke-ntp.keys.texi
+ @: do-nothing action to avoid default SCCS get, .menu built with .texi
+
+$(srcdir)/invoke-ntp.keys.texi: $(srcdir)/ntp.keys.def $(std_def_list)
+ $(run_ag) -Tagtexi-file.tpl -DLEVEL=section ntp.keys.def
+
+$(srcdir)/ntp.conf.html: $(srcdir)/ntp.conf.texi $(top_srcdir)/sntp/include/version.texi
+ cd $(srcdir) && ( makeinfo --force --html --no-split -o ntp.conf.html ntp.conf.texi || true )
+
+$(srcdir)/ntp.keys.html: $(srcdir)/ntp.keys.texi $(top_srcdir)/sntp/include/version.texi
+ cd $(srcdir) && ( makeinfo --force --html --no-split -o ntp.keys.html ntp.keys.texi || true )
+
+$(srcdir)/ntpd.html: $(srcdir)/ntpd.texi $(top_srcdir)/sntp/include/version.texi
+ cd $(srcdir) && ( makeinfo --force --html --no-split -o ntpd.html ntpd.texi || true )
+
+###
+
+$(srcdir)/ntp.conf.5man: $(srcdir)/ntp.conf.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5man -Tagman-cmd.tpl ntp.conf.def
+
+$(srcdir)/ntp.conf.man.in: $(srcdir)/ntp.conf.5man $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.conf.5man > $(srcdir)/ntp.conf.man.in+
+ mv $(srcdir)/ntp.conf.man.in+ $(srcdir)/ntp.conf.man.in
+
+###
+
+$(srcdir)/ntp.conf.5mdoc: $(srcdir)/ntp.conf.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5mdoc -Tagmdoc-cmd.tpl ntp.conf.def
+
+$(srcdir)/ntp.conf.mdoc.in: $(srcdir)/ntp.conf.5mdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.conf.5mdoc > $(srcdir)/ntp.conf.mdoc.in+
+ mv $(srcdir)/ntp.conf.mdoc.in+ $(srcdir)/ntp.conf.mdoc.in
+
+###
+
+ntp.conf.5: $(srcdir)/ntp.conf.$(MANTAGFMT).in $(top_builddir)/config.status
+ $(top_builddir)/config.status --file=ntp.conf.5+:$(srcdir)/ntp.conf.$(MANTAGFMT).in
+ mv ntp.conf.5+ ntp.conf.5
+
+###
+
+$(srcdir)/ntp.keys.5man: $(srcdir)/ntp.keys.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5man -Tagman-file.tpl ntp.keys.def
+
+$(srcdir)/ntp.keys.man.in: $(srcdir)/ntp.keys.5man $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.keys.5man > $(srcdir)/ntp.keys.man.in+
+ mv $(srcdir)/ntp.keys.man.in+ $(srcdir)/ntp.keys.man.in
+
+###
+
+$(srcdir)/ntp.keys.5mdoc: $(srcdir)/ntp.keys.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5mdoc -Tagmdoc-file.tpl ntp.keys.def
+
+$(srcdir)/ntp.keys.mdoc.in: $(srcdir)/ntp.keys.5mdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.keys.5mdoc > $(srcdir)/ntp.keys.mdoc.in+
+ mv $(srcdir)/ntp.keys.mdoc.in+ $(srcdir)/ntp.keys.mdoc.in
+
+###
+
+ntp.keys.5: $(srcdir)/ntp.keys.$(MANTAGFMT).in $(top_builddir)/config.status
+ $(top_builddir)/config.status --file=ntp.keys.5+:$(srcdir)/ntp.keys.$(MANTAGFMT).in
+ mv ntp.keys.5+ ntp.keys.5
+
+###
+
+$(srcdir)/invoke-ntpd.menu: $(srcdir)/invoke-ntpd.texi
+ @: do-nothing action to avoid default SCCS get, .menu built with .texi
+
+$(srcdir)/invoke-ntpd.texi: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
+ $(run_ag) -Tagtexi-cmd.tpl -DLEVEL=section ntpd-opts.def
+ $(top_srcdir)/scripts/build/check--help $@
$(PROGRAMS): $(LDADD)
-../libntp/libntp.a:
- cd ../libntp && $(MAKE) libntp.a
+compsave.conf: ntpd complete.conf
+ ./ntpd --configfile complete.conf --saveconfigquit $@
+
+check-saveconfig: complete.conf compsave.conf
+ -diff -u complete.conf compsave.conf
+ cmp complete.conf compsave.conf && echo stamp > $@
../libntp/libntpsim.a:
- cd ../libntp && $(MAKE) libntpsim.a
+ cd ../libntp && $(MAKE) $(AM_MAKEFLAGS) libntpsim.a
../libparse/libparse.a:
- cd ../libparse && $(MAKE)
+ cd ../libparse && $(MAKE) $(AM_MAKEFLAGS) check-libparse
+
+$(top_srcdir)/sntp/scm-rev:
+ cd ../sntp && $(MAKE) $(AM_MAKEFLAGS) check-scm-rev
-$(top_srcdir)/version :
- cd $(top_srcdir) && $(MAKE) version
+version.c: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ Makefile $(top_srcdir)/sntp/scm-rev
+ env CSET=`cat $(top_srcdir)/sntp/scm-rev` $(top_builddir)/scripts/build/mkver ntpd
-version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ Makefile $(top_srcdir)/version
- env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpd
- $(COMPILE) -c version.c
+version.o: version.c
+ env CCACHE_DISABLE=1 $(COMPILE) -c version.c -o version.o
-include ../bincheck.mf
+include $(top_srcdir)/bincheck.mf
+include $(top_srcdir)/check-libopts.mf
+include $(top_srcdir)/sntp/check-libntp.mf
+include $(top_srcdir)/depsver.mf
+include $(top_srcdir)/includes.mf
diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in
index 6ccb13b..7f30846 100644
--- a/contrib/ntp/ntpd/Makefile.in
+++ b/contrib/ntp/ntpd/Makefile.in
@@ -1,9 +1,8 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
-# Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -20,7 +19,64 @@
# subdir to warn folks if there is another version there.
+
+
VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -39,95 +95,184 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-ANSI2KNR = ../util/ansi2knr
-bin_PROGRAMS = ntpd$(EXEEXT) @MAKE_NTPDSIM@
-EXTRA_PROGRAMS = check_y2k$(EXEEXT) ntpdsim$(EXEEXT)
-DIST_COMMON = $(srcdir)/../bincheck.mf $(srcdir)/Makefile.am \
- $(srcdir)/Makefile.in
+EXTRA_PROGRAMS = check_y2k$(EXEEXT) keyword-gen$(EXEEXT) ntpd$(EXEEXT) \
+ ntpdsim$(EXEEXT)
subdir = ntpd
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
- $(top_srcdir)/m4/define_dir.m4 \
- $(top_srcdir)/m4/hs_ulong_const.m4 \
- $(top_srcdir)/m4/os_cflags.m4 $(top_srcdir)/version.m4 \
- $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/sntp/libopts/m4/libopts.m4 \
+ $(top_srcdir)/sntp/libopts/m4/stdnoreturn.m4 \
+ $(top_srcdir)/sntp/m4/ax_c99_struct_init.m4 \
+ $(top_srcdir)/sntp/m4/define_dir.m4 \
+ $(top_srcdir)/sntp/m4/hms_search_lib.m4 \
+ $(top_srcdir)/sntp/m4/libtool.m4 \
+ $(top_srcdir)/sntp/m4/ltoptions.m4 \
+ $(top_srcdir)/sntp/m4/ltsugar.m4 \
+ $(top_srcdir)/sntp/m4/ltversion.m4 \
+ $(top_srcdir)/sntp/m4/lt~obsolete.m4 \
+ $(top_srcdir)/sntp/m4/ntp_cacheversion.m4 \
+ $(top_srcdir)/sntp/m4/ntp_compiler.m4 \
+ $(top_srcdir)/sntp/m4/ntp_crosscompile.m4 \
+ $(top_srcdir)/sntp/m4/ntp_crypto_rand.m4 \
+ $(top_srcdir)/sntp/m4/ntp_debug.m4 \
+ $(top_srcdir)/sntp/m4/ntp_dir_sep.m4 \
+ $(top_srcdir)/sntp/m4/ntp_facilitynames.m4 \
+ $(top_srcdir)/sntp/m4/ntp_googletest.m4 \
+ $(top_srcdir)/sntp/m4/ntp_ipv6.m4 \
+ $(top_srcdir)/sntp/m4/ntp_lib_m.m4 \
+ $(top_srcdir)/sntp/m4/ntp_libevent.m4 \
+ $(top_srcdir)/sntp/m4/ntp_libntp.m4 \
+ $(top_srcdir)/sntp/m4/ntp_lineeditlibs.m4 \
+ $(top_srcdir)/sntp/m4/ntp_locinfo.m4 \
+ $(top_srcdir)/sntp/m4/ntp_openssl.m4 \
+ $(top_srcdir)/sntp/m4/ntp_pkg_config.m4 \
+ $(top_srcdir)/sntp/m4/ntp_prog_cc.m4 \
+ $(top_srcdir)/sntp/m4/ntp_rlimit.m4 \
+ $(top_srcdir)/sntp/m4/ntp_sntp.m4 \
+ $(top_srcdir)/sntp/m4/ntp_unitytest.m4 \
+ $(top_srcdir)/sntp/m4/ntp_ver_suffix.m4 \
+ $(top_srcdir)/sntp/m4/ntp_vpathhack.m4 \
+ $(top_srcdir)/sntp/m4/openldap-thread-check.m4 \
+ $(top_srcdir)/sntp/m4/openldap.m4 \
+ $(top_srcdir)/sntp/m4/os_cflags.m4 \
+ $(top_srcdir)/sntp/m4/snprintf.m4 \
+ $(top_srcdir)/sntp/m4/version.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_FILES = complete.conf
CONFIG_CLEAN_VPATH_FILES =
LIBRARIES = $(noinst_LIBRARIES)
ARFLAGS = @ARFLAGS@
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
libntpd_a_AR = $(AR) $(ARFLAGS)
libntpd_a_LIBADD =
-am_libntpd_a_OBJECTS = ntp_control$U.$(OBJEXT) ntp_crypto$U.$(OBJEXT) \
- ntp_filegen$U.$(OBJEXT) ntp_intres$U.$(OBJEXT) \
- ntp_loopfilter$U.$(OBJEXT) ntp_monitor$U.$(OBJEXT) \
- ntp_peer$U.$(OBJEXT) ntp_proto$U.$(OBJEXT) \
- ntp_refclock$U.$(OBJEXT) ntp_request$U.$(OBJEXT) \
- ntp_restrict$U.$(OBJEXT) ntp_timer$U.$(OBJEXT) \
- ntp_util$U.$(OBJEXT) refclock_acts$U.$(OBJEXT) \
- refclock_arbiter$U.$(OBJEXT) refclock_arc$U.$(OBJEXT) \
- refclock_as2201$U.$(OBJEXT) refclock_atom$U.$(OBJEXT) \
- refclock_bancomm$U.$(OBJEXT) refclock_chronolog$U.$(OBJEXT) \
- refclock_chu$U.$(OBJEXT) refclock_conf$U.$(OBJEXT) \
- refclock_datum$U.$(OBJEXT) refclock_dumbclock$U.$(OBJEXT) \
- refclock_fg$U.$(OBJEXT) refclock_gpsvme$U.$(OBJEXT) \
- refclock_heath$U.$(OBJEXT) refclock_hopfser$U.$(OBJEXT) \
- refclock_hopfpci$U.$(OBJEXT) refclock_hpgps$U.$(OBJEXT) \
- refclock_irig$U.$(OBJEXT) refclock_jjy$U.$(OBJEXT) \
- refclock_jupiter$U.$(OBJEXT) refclock_leitch$U.$(OBJEXT) \
- refclock_local$U.$(OBJEXT) refclock_mx4200$U.$(OBJEXT) \
- refclock_neoclock4x$U.$(OBJEXT) refclock_nmea$U.$(OBJEXT) \
- refclock_oncore$U.$(OBJEXT) refclock_palisade$U.$(OBJEXT) \
- refclock_parse$U.$(OBJEXT) refclock_pcf$U.$(OBJEXT) \
- refclock_pst$U.$(OBJEXT) refclock_ripencc$U.$(OBJEXT) \
- refclock_shm$U.$(OBJEXT) refclock_tpro$U.$(OBJEXT) \
- refclock_true$U.$(OBJEXT) refclock_tt560$U.$(OBJEXT) \
- refclock_ulink$U.$(OBJEXT) refclock_wwv$U.$(OBJEXT) \
- refclock_wwvb$U.$(OBJEXT) refclock_zyfer$U.$(OBJEXT)
+am__objects_1 =
+am_libntpd_a_OBJECTS = cmd_args.$(OBJEXT) ntp_control.$(OBJEXT) \
+ ntp_crypto.$(OBJEXT) ntp_filegen.$(OBJEXT) \
+ ntp_leapsec.$(OBJEXT) ntp_loopfilter.$(OBJEXT) \
+ ntp_monitor.$(OBJEXT) ntp_peer.$(OBJEXT) ntp_proto.$(OBJEXT) \
+ ntp_refclock.$(OBJEXT) ntp_request.$(OBJEXT) \
+ ntp_restrict.$(OBJEXT) ntp_signd.$(OBJEXT) ntp_timer.$(OBJEXT) \
+ ntp_util.$(OBJEXT) rc_cmdlength.$(OBJEXT) \
+ refclock_acts.$(OBJEXT) refclock_arbiter.$(OBJEXT) \
+ refclock_arc.$(OBJEXT) refclock_as2201.$(OBJEXT) \
+ refclock_atom.$(OBJEXT) refclock_bancomm.$(OBJEXT) \
+ refclock_chronolog.$(OBJEXT) refclock_chu.$(OBJEXT) \
+ refclock_conf.$(OBJEXT) refclock_datum.$(OBJEXT) \
+ refclock_dumbclock.$(OBJEXT) refclock_fg.$(OBJEXT) \
+ refclock_gpsdjson.$(OBJEXT) refclock_gpsvme.$(OBJEXT) \
+ refclock_heath.$(OBJEXT) refclock_hopfser.$(OBJEXT) \
+ refclock_hopfpci.$(OBJEXT) refclock_hpgps.$(OBJEXT) \
+ refclock_irig.$(OBJEXT) refclock_jjy.$(OBJEXT) \
+ refclock_jupiter.$(OBJEXT) refclock_leitch.$(OBJEXT) \
+ refclock_local.$(OBJEXT) refclock_mx4200.$(OBJEXT) \
+ refclock_neoclock4x.$(OBJEXT) refclock_nmea.$(OBJEXT) \
+ refclock_oncore.$(OBJEXT) refclock_palisade.$(OBJEXT) \
+ refclock_parse.$(OBJEXT) refclock_pcf.$(OBJEXT) \
+ refclock_pst.$(OBJEXT) refclock_ripencc.$(OBJEXT) \
+ refclock_shm.$(OBJEXT) refclock_tpro.$(OBJEXT) \
+ refclock_true.$(OBJEXT) refclock_tt560.$(OBJEXT) \
+ refclock_ulink.$(OBJEXT) refclock_wwv.$(OBJEXT) \
+ refclock_wwvb.$(OBJEXT) refclock_zyfer.$(OBJEXT) \
+ refclock_tsyncpci.$(OBJEXT) $(am__objects_1)
libntpd_a_OBJECTS = $(am_libntpd_a_OBJECTS)
-am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
-PROGRAMS = $(bin_PROGRAMS)
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \
+ "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" \
+ "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" \
+ "$(DESTDIR)$(htmldir)"
+PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(sbin_PROGRAMS)
check_y2k_SOURCES = check_y2k.c
-check_y2k_OBJECTS = check_y2k$U.$(OBJEXT)
-am__DEPENDENCIES_1 = version.o libntpd.a
-check_y2k_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libntp/libntp.a
-am_ntpd_OBJECTS = cmd_args$U.$(OBJEXT) ntp_config$U.$(OBJEXT) \
- ntp_io$U.$(OBJEXT) ntpd$U.$(OBJEXT) ntpd-opts$U.$(OBJEXT)
+check_y2k_OBJECTS = check_y2k.$(OBJEXT)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = version.o libntpd.a $(am__DEPENDENCIES_1)
+check_y2k_DEPENDENCIES = $(am__DEPENDENCIES_2) ../libntp/libntp.a \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+keyword_gen_SOURCES = keyword-gen.c
+keyword_gen_OBJECTS = keyword-gen.$(OBJEXT)
+keyword_gen_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_ntpd_OBJECTS = ntp_config.$(OBJEXT) ntp_io.$(OBJEXT) \
+ ntp_parser.$(OBJEXT) ntp_scanner.$(OBJEXT) ntpd.$(OBJEXT) \
+ ntpd-opts.$(OBJEXT) $(am__objects_1)
ntpd_OBJECTS = $(am_ntpd_OBJECTS)
-am__DEPENDENCIES_2 =
-ntpd_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
- ../libntp/libntp.a
-am__objects_1 = ntpdsim-cmd_args$U.$(OBJEXT) \
- ntpdsim-ntp_config$U.$(OBJEXT) ntpdsim-ntp_io$U.$(OBJEXT) \
- ntpdsim-ntpd$U.$(OBJEXT) ntpdsim-ntpd-opts$U.$(OBJEXT)
-am_ntpdsim_OBJECTS = $(am__objects_1) ntpdsim-ntpsim$U.$(OBJEXT) \
- ntpdsim-ntpdsim-opts$U.$(OBJEXT)
+am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ntpd_DEPENDENCIES = $(am__DEPENDENCIES_2) ../libntp/libntp.a \
+ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
+am__objects_2 = ntpdsim-ntp_config.$(OBJEXT) ntpdsim-ntp_io.$(OBJEXT) \
+ ntpdsim-ntp_parser.$(OBJEXT) ntpdsim-ntp_scanner.$(OBJEXT) \
+ ntpdsim-ntpd.$(OBJEXT) ntpdsim-ntpd-opts.$(OBJEXT) \
+ $(am__objects_1)
+am_ntpdsim_OBJECTS = $(am__objects_2) ntpdsim-ntp_prio_q.$(OBJEXT) \
+ ntpdsim-ntpsim.$(OBJEXT) $(am__objects_1)
ntpdsim_OBJECTS = $(am_ntpdsim_OBJECTS)
-ntpdsim_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libntp/libntpsim.a \
- $(am__DEPENDENCIES_2)
-ntpdsim_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
- --mode=link $(CCLD) $(ntpdsim_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
- $(LDFLAGS) -o $@
+ntpdsim_DEPENDENCIES = $(am__DEPENDENCIES_2) ../libntp/libntpsim.a \
+ $(am__DEPENDENCIES_3)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
-depcomp = $(SHELL) $(top_srcdir)/depcomp
+depcomp = $(SHELL) $(top_srcdir)/sntp/libevent/build-aux/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
- --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
CCLD = $(CC)
-LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
- --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
- $(LDFLAGS) -o $@
-SOURCES = $(libntpd_a_SOURCES) check_y2k.c $(ntpd_SOURCES) \
- $(ntpdsim_SOURCES)
-DIST_SOURCES = $(libntpd_a_SOURCES) check_y2k.c $(ntpd_SOURCES) \
- $(ntpdsim_SOURCES)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+ -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_@AM_V@)
+am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
+am__v_YACC_0 = @echo " YACC " $@;
+am__v_YACC_1 =
+YLWRAP = $(top_srcdir)/sntp/libevent/build-aux/ylwrap
+SOURCES = $(libntpd_a_SOURCES) check_y2k.c keyword-gen.c \
+ $(ntpd_SOURCES) $(ntpdsim_SOURCES)
+DIST_SOURCES = $(libntpd_a_SOURCES) check_y2k.c keyword-gen.c \
+ $(ntpd_SOURCES) $(ntpdsim_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -149,49 +294,113 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
NROFF = nroff
-MANS = $(man_MANS)
+MANS = $(man1_MANS) $(man5_MANS) $(man8_MANS) $(man_MANS)
+DATA = $(html_DATA) $(noinst_DATA)
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/complete.conf.in \
+ $(top_srcdir)/bincheck.mf $(top_srcdir)/check-libopts.mf \
+ $(top_srcdir)/depsver.mf $(top_srcdir)/includes.mf \
+ $(top_srcdir)/sntp/check-libntp.mf \
+ $(top_srcdir)/sntp/libevent/build-aux/depcomp \
+ $(top_srcdir)/sntp/libevent/build-aux/ylwrap ntp_parser.c \
+ ntp_parser.h
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
-ARLIB_DIR = @ARLIB_DIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
-BINSUBDIR = @BINSUBDIR@
+CALC_TICKADJ_DB = @CALC_TICKADJ_DB@
+CALC_TICKADJ_DL = @CALC_TICKADJ_DL@
+CALC_TICKADJ_DS = @CALC_TICKADJ_DS@
+CALC_TICKADJ_MS = @CALC_TICKADJ_MS@
+CALC_TICKADJ_NI = @CALC_TICKADJ_NI@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CFLAGS_NTP = @CFLAGS_NTP@
CHUTEST = @CHUTEST@
-CLKTEST = @CLKTEST@
+CONFIG_SHELL = @CONFIG_SHELL@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_LIBEVENT = @CPPFLAGS_LIBEVENT@
+CPPFLAGS_NTP = @CPPFLAGS_NTP@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DCFD = @DCFD@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
-ECHO = @ECHO@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
-EF_LIBS = @EF_LIBS@
-EF_PROGS = @EF_PROGS@
+EDITLINE_LIBS = @EDITLINE_LIBS@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+FGREP = @FGREP@
GREP = @GREP@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_CPPFLAGS = @GTEST_CPPFLAGS@
+GTEST_CXXFLAGS = @GTEST_CXXFLAGS@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_LIBS = @GTEST_LIBS@
HAVE_INLINE = @HAVE_INLINE@
+HAVE_LEAPSMEARINTERVAL = @HAVE_LEAPSMEARINTERVAL@
+HAVE_RLIMIT_MEMLOCK = @HAVE_RLIMIT_MEMLOCK@
+HAVE_RLIMIT_STACK = @HAVE_RLIMIT_STACK@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LCRYPTO = @LCRYPTO@
+LD = @LD@
+LDADD_LIBEVENT = @LDADD_LIBEVENT@
+LDADD_LIBNTP = @LDADD_LIBNTP@
+LDADD_LIBUTIL = @LDADD_LIBUTIL@
+LDADD_NLIST = @LDADD_NLIST@
+LDADD_NTP = @LDADD_NTP@
LDFLAGS = @LDFLAGS@
+LDFLAGS_NTP = @LDFLAGS_NTP@
+LIBISC_PTHREADS_NOTHREADS = @LIBISC_PTHREADS_NOTHREADS@
+LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBOPTS_CFLAGS = @LIBOPTS_CFLAGS@
LIBOPTS_DIR = @LIBOPTS_DIR@
@@ -199,6 +408,8 @@ LIBOPTS_LDADD = @LIBOPTS_LDADD@
LIBPARSE = @LIBPARSE@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LIPO = @LIPO@
LN_S = @LN_S@
LSCF = @LSCF@
LTLIBOBJS = @LTLIBOBJS@
@@ -210,15 +421,76 @@ MAKE_LIBNTPSIM = @MAKE_LIBNTPSIM@
MAKE_LIBPARSE = @MAKE_LIBPARSE@
MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@
MAKE_NTPDSIM = @MAKE_NTPDSIM@
+MAKE_NTPSNMPD = @MAKE_NTPSNMPD@
MAKE_NTPTIME = @MAKE_NTPTIME@
MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@
MAKE_TICKADJ = @MAKE_TICKADJ@
MAKE_TIMETRIM = @MAKE_TIMETRIM@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MANTAGFMT = @MANTAGFMT@
MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NTPDATE_DB = @NTPDATE_DB@
+NTPDATE_DL = @NTPDATE_DL@
+NTPDATE_DS = @NTPDATE_DS@
+NTPDATE_MS = @NTPDATE_MS@
+NTPDATE_NI = @NTPDATE_NI@
+NTPDC_DB = @NTPDC_DB@
+NTPDC_DL = @NTPDC_DL@
+NTPDC_DS = @NTPDC_DS@
+NTPDC_MS = @NTPDC_MS@
+NTPDC_NI = @NTPDC_NI@
+NTPDSIM_DB = @NTPDSIM_DB@
+NTPDSIM_DL = @NTPDSIM_DL@
+NTPDSIM_DS = @NTPDSIM_DS@
+NTPDSIM_MS = @NTPDSIM_MS@
+NTPDSIM_NI = @NTPDSIM_NI@
+NTPD_DB = @NTPD_DB@
+NTPD_DL = @NTPD_DL@
+NTPD_DS = @NTPD_DS@
+NTPD_MS = @NTPD_MS@
+NTPD_NI = @NTPD_NI@
+NTPQ_DB = @NTPQ_DB@
+NTPQ_DL = @NTPQ_DL@
+NTPQ_DS = @NTPQ_DS@
+NTPQ_MS = @NTPQ_MS@
+NTPQ_NI = @NTPQ_NI@
+NTPSNMPD_DB = @NTPSNMPD_DB@
+NTPSNMPD_DL = @NTPSNMPD_DL@
+NTPSNMPD_DS = @NTPSNMPD_DS@
+NTPSNMPD_MS = @NTPSNMPD_MS@
+NTPSNMPD_NI = @NTPSNMPD_NI@
+NTPSWEEP_DB = @NTPSWEEP_DB@
+NTPSWEEP_DL = @NTPSWEEP_DL@
+NTPSWEEP_DS = @NTPSWEEP_DS@
+NTPSWEEP_MS = @NTPSWEEP_MS@
+NTPSWEEP_NI = @NTPSWEEP_NI@
+NTPTIME_DB = @NTPTIME_DB@
+NTPTIME_DL = @NTPTIME_DL@
+NTPTIME_DS = @NTPTIME_DS@
+NTPTIME_MS = @NTPTIME_MS@
+NTPTIME_NI = @NTPTIME_NI@
+NTPTRACE_DB = @NTPTRACE_DB@
+NTPTRACE_DL = @NTPTRACE_DL@
+NTPTRACE_DS = @NTPTRACE_DS@
+NTPTRACE_MS = @NTPTRACE_MS@
+NTPTRACE_NI = @NTPTRACE_NI@
+NTP_KEYGEN_DB = @NTP_KEYGEN_DB@
+NTP_KEYGEN_DL = @NTP_KEYGEN_DL@
+NTP_KEYGEN_DS = @NTP_KEYGEN_DS@
+NTP_KEYGEN_MS = @NTP_KEYGEN_MS@
+NTP_KEYGEN_NI = @NTP_KEYGEN_NI@
+NTP_KEYSDIR = @NTP_KEYSDIR@
+NTP_WAIT_DB = @NTP_WAIT_DB@
+NTP_WAIT_DL = @NTP_WAIT_DL@
+NTP_WAIT_DS = @NTP_WAIT_DS@
+NTP_WAIT_MS = @NTP_WAIT_MS@
+NTP_WAIT_NI = @NTP_WAIT_NI@
+OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL = @OPENSSL@
-OPENSSL_INC = @OPENSSL_INC@
-OPENSSL_LIB = @OPENSSL_LIB@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
@@ -226,29 +498,65 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_NET_SNMP_CONFIG = @PATH_NET_SNMP_CONFIG@
PATH_PERL = @PATH_PERL@
+PATH_RUBY = @PATH_RUBY@
PATH_SEPARATOR = @PATH_SEPARATOR@
-PATH_SH = @PATH_SH@
+PATH_TEST = @PATH_TEST@
+PERLLIBDIR = @PERLLIBDIR@
+PKG_CONFIG = @PKG_CONFIG@
+POSIX_SHELL = @POSIX_SHELL@
PROPDELAY = @PROPDELAY@
+PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
-READLINE_LIBS = @READLINE_LIBS@
+SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+SNMP_CFLAGS = @SNMP_CFLAGS@
+SNMP_CPPFLAGS = @SNMP_CPPFLAGS@
+SNMP_LIBS = @SNMP_LIBS@
+SNTP = @SNTP@
+SNTP_DB = @SNTP_DB@
+SNTP_DL = @SNTP_DL@
+SNTP_DS = @SNTP_DS@
+SNTP_MS = @SNTP_MS@
+SNTP_NI = @SNTP_NI@
+STDNORETURN_H = @STDNORETURN_H@
STRIP = @STRIP@
TESTDCF = @TESTDCF@
-U = @U@
+TICKADJ_DB = @TICKADJ_DB@
+TICKADJ_DL = @TICKADJ_DL@
+TICKADJ_DS = @TICKADJ_DS@
+TICKADJ_MS = @TICKADJ_MS@
+TICKADJ_NI = @TICKADJ_NI@
+TIMETRIM_DB = @TIMETRIM_DB@
+TIMETRIM_DL = @TIMETRIM_DL@
+TIMETRIM_DS = @TIMETRIM_DS@
+TIMETRIM_MS = @TIMETRIM_MS@
+TIMETRIM_NI = @TIMETRIM_NI@
+UPDATE_LEAP_DB = @UPDATE_LEAP_DB@
+UPDATE_LEAP_DL = @UPDATE_LEAP_DL@
+UPDATE_LEAP_DS = @UPDATE_LEAP_DS@
+UPDATE_LEAP_MS = @UPDATE_LEAP_MS@
+UPDATE_LEAP_NI = @UPDATE_LEAP_NI@
VERSION = @VERSION@
+VER_SUFFIX = @VER_SUFFIX@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
-bindir = ${exec_prefix}/${BINSUBDIR}
+bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
@@ -289,71 +597,240 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-AUTOMAKE_OPTIONS = ../util/ansi2knr
+NULL =
+bin_PROGRAMS = $(NTPD_DB) $(NTPDSIM_DB)
+libexec_PROGRAMS = $(NTPD_DL) $(NTPDSIM_DL)
+sbin_PROGRAMS = $(NTPD_DS) $(NTPDSIM_DS)
noinst_LIBRARIES = libntpd.a
-AM_CPPFLAGS = -I$(top_srcdir)/include -I../include $(LIBOPTS_CFLAGS)
+AM_CFLAGS = $(CFLAGS_NTP)
+AM_CPPFLAGS = $(NTP_INCS) $(LIBOPTS_CFLAGS) $(CPPFLAGS_NTP)
+AM_LDFLAGS = $(LDFLAGS_NTP)
+
# LDADD might need RESLIB and ADJLIB.
-LDADD = version.o libntpd.a @LIBPARSE@
-BUILT_SOURCES = ntpd-opts.c ntpd-opts.h ntpd.1 ntpd-opts.texi \
- ntpd-opts.menu ntpdsim-opts.c ntpdsim-opts.h ntpdsim.1 \
- ntpdsim-opts.texi ntpdsim-opts.menu
-man_MANS = ntpd.1 ntpdsim.1
-
-# ntpd may need:
-# log10 refclock_wwv.o
-# sqrt ntp_control.o
-# floor refclock_wwv.o
-# which are (usually) provided by -lm.
-ntpd_LDADD = $(LDADD) -lm @LCRYPTO@ $(LIBOPTS_LDADD) ../libntp/libntp.a
-ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a -lm @LCRYPTO@ $(LIBOPTS_LDADD)
-ntpdsim_CFLAGS = $(CFLAGS) -DSIM
-check_y2k_LDADD = $(LDADD) ../libntp/libntp.a
-DISTCLEANFILES = .version version.c
-EXTRA_DIST = ntpd-opts.def ntpdbase-opts.def ntpdsim-opts.def \
+LDADD = version.o libntpd.a $(LIBPARSE)
+AM_YFLAGS = -d -t -r all
+@NTP_CROSSCOMPILE_FALSE@@SAVECONFIG_ENABLED_TRUE@CHECK_SAVECONFIG = check-saveconfig
+@NTP_CROSSCOMPILE_TRUE@@SAVECONFIG_ENABLED_TRUE@CHECK_SAVECONFIG =
+@SAVECONFIG_ENABLED_FALSE@CHECK_SAVECONFIG =
+@VPATH_HACK_FALSE@VPHACK =
+
+#
+# VPHACK and VPHACK_AFTER are enabled on non-GNU makes (such as
+# BSD make) to work around issues specific to compiling
+# ntp_parser.y into ntp_parser.h and ntp_parser.c in a VPATH
+# configuration where we would like (for a change) the output
+# files ntp_parser.[ch] to be placed in the source directory,
+# as opposed to the build directory. This allows a single
+# host of a flock configured with Bison to update ntp_parser.[ch]
+# used by the rest.
+#
+@VPATH_HACK_TRUE@VPHACK = vphack
+@VPATH_HACK_FALSE@VPHACK_AFTER =
+@VPATH_HACK_TRUE@VPHACK_AFTER = vphack_after
+
+# BUILT_SOURCES which should also be in EXTRA_DIST
+B_S_DIST = \
+ $(srcdir)/ntpd-opts.c \
+ $(srcdir)/ntpd-opts.h \
+ $(NULL)
+
+BUILT_SOURCES = $(VPHACK) $(LIBPARSE) ntp_parser.c ntp_parser.h \
+ $(VPHACK_AFTER) $(B_S_DIST) $(NULL) check-libopts check-libntp \
+ .deps-ver
+man1_MANS =
+man5_MANS = ntp.conf.5 ntp.keys.5
+man8_MANS =
+man_MANS = ntpd.$(NTPD_MS)
+
+# ntpdsim.1 is a remnant along with all the ntpdsim-opts.* files, the
+# simulator currently uses ntpd-opts.[ch]. This also means there is no
+# longer a reason to have ntpdbase-opts.def split off of ntpd-opts.def.
+LDADD_NTPD_COMMON = $(LDADD_LIBNTP) $(LIBOPTS_LDADD) $(PTHREAD_LIBS) \
+ $(LIBM) $(LDADD_NTP) $(LSCF)
+ntpd_LDADD = $(LDADD) ../libntp/libntp.a $(LDADD_NTPD_COMMON) $(LDADD_LIBUTIL)
+ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a $(LDADD_NTPD_COMMON)
+ntpdsim_CPPFLAGS = $(AM_CPPFLAGS) -DSIM
+check_y2k_LDADD = $(LDADD) ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(LDADD_LIBNTP) $(PTHREAD_LIBS)
+keyword_gen_LDADD = ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(PTHREAD_LIBS)
+DISTCLEANFILES = \
+ keyword-gen \
+ .version \
+ version.c \
+ config.log \
+ $(man5_MANS) \
+ $(man_MANS) \
+ $(NULL)
+
+CLEANFILES = check-saveconfig compsave.conf k-g-u-submake \
+ $(EXTRA_PROGRAMS) $(NULL) check-libopts check-libntp .deps-ver
+EXTRA_DIST = \
+ complete.conf.in \
+ invoke-ntp.conf.menu \
+ invoke-ntp.conf.texi \
+ invoke-ntp.keys.menu \
+ invoke-ntp.keys.texi \
+ invoke-ntpd.menu \
+ invoke-ntpd.texi \
+ keyword-gen-utd \
+ ntp.conf.5man \
+ ntp.conf.5mdoc \
+ ntp.conf.def \
+ ntp.conf.man.in \
+ ntp.conf.mdoc.in \
+ ntp.conf.html \
+ ntp.conf.texi \
+ ntp.keys.5man \
+ ntp.keys.5mdoc \
+ ntp.keys.def \
+ ntp.keys.man.in \
+ ntp.keys.mdoc.in \
+ ntp.keys.html \
+ ntp.keys.texi \
+ ntpd-opts.def \
+ ntpd.1ntpdman \
+ ntpd.1ntpdmdoc \
+ ntpd.man.in \
+ ntpd.mdoc.in \
+ ntpd.html \
+ ntpd.texi \
+ ntpdbase-opts.def \
refclock_msfees.c \
- refclock_trak.c \
- $(BUILT_SOURCES)
+ $(B_S_DIST) \
+ $(NULL)
+
-ETAGS_ARGS = Makefile.am
### Y2Kfixes
check_PROGRAMS = @MAKE_CHECK_Y2K@
-run_ag = cd $(srcdir) && autogen -L ../include --writable
-std_def_list = $(top_srcdir)/include/debug-opt.def \
- $(top_srcdir)/include/autogen-version.def \
- $(top_srcdir)/include/copyright.def \
- $(top_srcdir)/include/version.def
-
-
-# SIM: cmd_args.c ntp_config.c ntp_io.c ntpd.c + ntpsim.c (include/ntpsim.h)
-# ntp_resolver.c is presently unused...
-ntpd_SOURCES = cmd_args.c ntp_config.c ntp_io.c ntpd.c ntpd-opts.c ntpd-opts.h
-ntpdsim_SOURCES = $(ntpd_SOURCES) ntpsim.c ntpdsim-opts.c ntpdsim-opts.h
-libntpd_a_SOURCES = jupiter.h ntp_control.c \
- ntp_crypto.c ntp_filegen.c \
- ntp_intres.c ntp_loopfilter.c ntp_monitor.c ntp_peer.c \
- ntp_proto.c ntp_refclock.c ntp_request.c \
- ntp_restrict.c ntp_timer.c ntp_util.c \
- ppsapi_timepps.h \
- refclock_acts.c refclock_arbiter.c refclock_arc.c refclock_as2201.c \
- refclock_atom.c refclock_bancomm.c refclock_chronolog.c \
- refclock_chu.c refclock_conf.c refclock_datum.c refclock_dumbclock.c \
- refclock_fg.c refclock_gpsvme.c refclock_heath.c refclock_hopfser.c \
- refclock_hopfpci.c refclock_hpgps.c refclock_irig.c refclock_jjy.c \
- refclock_jupiter.c refclock_leitch.c refclock_local.c \
- refclock_mx4200.c refclock_neoclock4x.c \
- refclock_nmea.c refclock_oncore.c refclock_palisade.c \
- refclock_palisade.h refclock_parse.c \
- refclock_pcf.c refclock_pst.c refclock_ripencc.c refclock_shm.c \
- refclock_tpro.c refclock_true.c refclock_tt560.c \
- refclock_ulink.c refclock_wwv.c refclock_wwvb.c \
- refclock_zyfer.c
-
+html_DATA = \
+ $(srcdir)/ntp.conf.html \
+ $(srcdir)/ntp.keys.html \
+ $(srcdir)/ntpd.html \
+ $(NULL)
+
+noinst_DATA = \
+ $(srcdir)/invoke-ntp.conf.menu \
+ $(srcdir)/invoke-ntp.conf.texi \
+ $(srcdir)/invoke-ntp.keys.menu \
+ $(srcdir)/invoke-ntp.keys.texi \
+ $(srcdir)/invoke-ntpd.menu \
+ $(srcdir)/invoke-ntpd.texi \
+ $(srcdir)/ntp.conf.man.in \
+ $(srcdir)/ntp.conf.mdoc.in \
+ $(srcdir)/ntp.keys.man.in \
+ $(srcdir)/ntp.keys.mdoc.in \
+ $(srcdir)/ntpd.man.in \
+ $(srcdir)/ntpd.mdoc.in \
+ $(NULL)
+
+noinst_HEADERS = \
+ declcond.h \
+ ntp_leapsec.h \
+ $(NULL)
+
+run_ag = cd $(srcdir) && env PATH="$(abs_builddir):$(PATH)" AUTOGEN_DNE_DATE=-D \
+ autogen -L ../sntp/include -L ../sntp/ag-tpl --writable
+
+std_def_list = \
+ $(top_srcdir)/sntp/include/debug-opt.def \
+ $(top_srcdir)/sntp/include/autogen-version.def \
+ $(top_srcdir)/sntp/include/copyright.def \
+ $(top_srcdir)/sntp/include/homerc.def \
+ $(top_srcdir)/sntp/include/ntp.lic \
+ $(top_srcdir)/sntp/include/version.def \
+ $(NULL)
+
+ntpd_SOURCES = \
+ ntp_config.c \
+ ntp_keyword.h \
+ ntp_io.c \
+ ntp_parser.y \
+ ntp_scanner.c \
+ ntp_scanner.h \
+ ntpd.c \
+ ntpd-opts.c \
+ ntpd-opts.h \
+ $(NULL)
+
+ntpdsim_SOURCES = \
+ $(ntpd_SOURCES) \
+ ntp_prio_q.c \
+ ntpsim.c \
+ $(NULL)
+
+
+# libntpd_a_SOURCES do not use #ifdef SIM
+libntpd_a_SOURCES = \
+ cmd_args.c \
+ jupiter.h \
+ ntp_control.c \
+ ntp_crypto.c \
+ ntp_filegen.c \
+ ntp_leapsec.c \
+ ntp_loopfilter.c \
+ ntp_monitor.c \
+ ntp_peer.c \
+ ntp_proto.c \
+ ntp_refclock.c \
+ ntp_request.c \
+ ntp_restrict.c \
+ ntp_signd.c \
+ ntp_timer.c \
+ ntp_util.c \
+ ppsapi_timepps.h \
+ rc_cmdlength.c \
+ refclock_acts.c \
+ refclock_arbiter.c \
+ refclock_arc.c \
+ refclock_as2201.c \
+ refclock_atom.c \
+ refclock_bancomm.c \
+ refclock_chronolog.c \
+ refclock_chu.c \
+ refclock_conf.c \
+ refclock_datum.c \
+ refclock_dumbclock.c \
+ refclock_fg.c \
+ refclock_gpsdjson.c \
+ refclock_gpsvme.c \
+ refclock_heath.c \
+ refclock_hopfser.c \
+ refclock_hopfpci.c \
+ refclock_hpgps.c \
+ refclock_irig.c \
+ refclock_jjy.c \
+ refclock_jupiter.c \
+ refclock_leitch.c \
+ refclock_local.c \
+ refclock_mx4200.c \
+ refclock_neoclock4x.c \
+ refclock_nmea.c \
+ refclock_oncore.c \
+ refclock_palisade.c \
+ refclock_palisade.h \
+ refclock_parse.c \
+ refclock_pcf.c \
+ refclock_pst.c \
+ refclock_ripencc.c \
+ refclock_shm.c \
+ refclock_tpro.c \
+ refclock_true.c \
+ refclock_tt560.c \
+ refclock_ulink.c \
+ refclock_wwv.c \
+ refclock_wwvb.c \
+ refclock_zyfer.c \
+ refclock_tsyncpci.c \
+ $(NULL)
+
+NTP_INCS = -I$(top_srcdir)/include -I$(top_srcdir)/lib/isc/include \
+ -I$(top_srcdir)/lib/isc/$(LIBISC_PTHREADS_NOTHREADS)/include \
+ -I$(top_srcdir)/lib/isc/unix/include
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
-.SUFFIXES: .c .lo .o .obj
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../bincheck.mf $(am__configure_deps)
+.SUFFIXES: .c .lo .o .obj .y
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/bincheck.mf $(top_srcdir)/check-libopts.mf $(top_srcdir)/sntp/check-libntp.mf $(top_srcdir)/depsver.mf $(top_srcdir)/includes.mf $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -365,7 +842,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../bincheck.mf $(am__con
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ntpd/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign ntpd/Makefile
-.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -374,6 +850,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
+$(top_srcdir)/bincheck.mf $(top_srcdir)/check-libopts.mf $(top_srcdir)/sntp/check-libntp.mf $(top_srcdir)/depsver.mf $(top_srcdir)/includes.mf $(am__empty):
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -383,23 +860,31 @@ $(top_srcdir)/configure: $(am__configure_deps)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
+complete.conf: $(top_builddir)/config.status $(srcdir)/complete.conf.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
-libntpd.a: $(libntpd_a_OBJECTS) $(libntpd_a_DEPENDENCIES)
- -rm -f libntpd.a
- $(libntpd_a_AR) libntpd.a $(libntpd_a_OBJECTS) $(libntpd_a_LIBADD)
- $(RANLIB) libntpd.a
+
+libntpd.a: $(libntpd_a_OBJECTS) $(libntpd_a_DEPENDENCIES) $(EXTRA_libntpd_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libntpd.a
+ $(AM_V_AR)$(libntpd_a_AR) libntpd.a $(libntpd_a_OBJECTS) $(libntpd_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libntpd.a
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
- test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
- while read p p1; do if test -f $$p || test -f $$p1; \
- then echo "$$p"; echo "$$p"; else :; fi; \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
- sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
@@ -420,7 +905,8 @@ uninstall-binPROGRAMS:
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
- -e 's/$$/$(EXEEXT)/' `; \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
@@ -442,387 +928,359 @@ clean-checkPROGRAMS:
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
-check_y2k$(EXEEXT): $(check_y2k_OBJECTS) $(check_y2k_DEPENDENCIES)
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+check_y2k$(EXEEXT): $(check_y2k_OBJECTS) $(check_y2k_DEPENDENCIES) $(EXTRA_check_y2k_DEPENDENCIES)
@rm -f check_y2k$(EXEEXT)
- $(LINK) $(check_y2k_OBJECTS) $(check_y2k_LDADD) $(LIBS)
-ntpd$(EXEEXT): $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(check_y2k_OBJECTS) $(check_y2k_LDADD) $(LIBS)
+
+keyword-gen$(EXEEXT): $(keyword_gen_OBJECTS) $(keyword_gen_DEPENDENCIES) $(EXTRA_keyword_gen_DEPENDENCIES)
+ @rm -f keyword-gen$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(keyword_gen_OBJECTS) $(keyword_gen_LDADD) $(LIBS)
+ntp_parser.h: ntp_parser.c
+ @if test ! -f $@; then rm -f ntp_parser.c; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) ntp_parser.c; else :; fi
+
+ntpd$(EXEEXT): $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES) $(EXTRA_ntpd_DEPENDENCIES)
@rm -f ntpd$(EXEEXT)
- $(LINK) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS)
-ntpdsim$(EXEEXT): $(ntpdsim_OBJECTS) $(ntpdsim_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS)
+
+ntpdsim$(EXEEXT): $(ntpdsim_OBJECTS) $(ntpdsim_DEPENDENCIES) $(EXTRA_ntpdsim_DEPENDENCIES)
@rm -f ntpdsim$(EXEEXT)
- $(ntpdsim_LINK) $(ntpdsim_OBJECTS) $(ntpdsim_LDADD) $(LIBS)
+ $(AM_V_CCLD)$(LINK) $(ntpdsim_OBJECTS) $(ntpdsim_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
-../util/ansi2knr:
- $(am__cd) ../util && $(MAKE) $(AM_MAKEFLAGS) ./ansi2knr
-
-mostlyclean-kr:
- -test "$U" = "" || rm -f *_.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_y2k$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd_args$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_config$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_control$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_crypto$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_filegen$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_intres$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_io$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_loopfilter$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_monitor$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_peer$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_proto$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_refclock$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_request$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_restrict$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_timer$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_util$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpd$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpd-opts$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-cmd_args$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_config$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_io$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpd$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpd-opts$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpdsim-opts$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpsim$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_acts$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_arbiter$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_arc$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_as2201$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_atom$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_bancomm$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_chronolog$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_chu$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_conf$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_datum$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_dumbclock$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_fg$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_gpsvme$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_heath$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hopfpci$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hopfser$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hpgps$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_irig$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_jjy$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_jupiter$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_leitch$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_local$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_mx4200$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_neoclock4x$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_nmea$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_oncore$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_palisade$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_parse$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_pcf$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_pst$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ripencc$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_shm$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tpro$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_true$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tt560$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ulink$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_wwv$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_wwvb$U.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_zyfer$U.Po@am__quote@
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_y2k.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd_args.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyword-gen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_control.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_crypto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_filegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_io.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_leapsec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_loopfilter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_peer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_proto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_refclock.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_request.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_restrict.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_scanner.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_signd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_timer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpd-opts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_io.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_prio_q.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_scanner.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpd-opts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpsim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rc_cmdlength.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_acts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_arbiter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_arc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_as2201.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_atom.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_bancomm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_chronolog.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_chu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_conf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_datum.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_dumbclock.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_fg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_gpsdjson.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_gpsvme.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_heath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hopfpci.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hopfser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hpgps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_irig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_jjy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_jupiter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_leitch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_local.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_mx4200.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_neoclock4x.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_nmea.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_oncore.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_palisade.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_parse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_pcf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_pst.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ripencc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_shm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tpro.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_true.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tsyncpci.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tt560.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ulink.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_wwv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_wwvb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_zyfer.Po@am__quote@
.c.o:
-@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
-@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
-@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+ntpdsim-ntp_config.o: ntp_config.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_config.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_config.Tpo -c -o ntpdsim-ntp_config.o `test -f 'ntp_config.c' || echo '$(srcdir)/'`ntp_config.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_config.Tpo $(DEPDIR)/ntpdsim-ntp_config.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_config.c' object='ntpdsim-ntp_config.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_config.o `test -f 'ntp_config.c' || echo '$(srcdir)/'`ntp_config.c
+
+ntpdsim-ntp_config.obj: ntp_config.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_config.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_config.Tpo -c -o ntpdsim-ntp_config.obj `if test -f 'ntp_config.c'; then $(CYGPATH_W) 'ntp_config.c'; else $(CYGPATH_W) '$(srcdir)/ntp_config.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_config.Tpo $(DEPDIR)/ntpdsim-ntp_config.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_config.c' object='ntpdsim-ntp_config.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_config.obj `if test -f 'ntp_config.c'; then $(CYGPATH_W) 'ntp_config.c'; else $(CYGPATH_W) '$(srcdir)/ntp_config.c'; fi`
-ntpdsim-cmd_args$U.o: cmd_args$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-cmd_args$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-cmd_args$U.Tpo -c -o ntpdsim-cmd_args$U.o `test -f 'cmd_args$U.c' || echo '$(srcdir)/'`cmd_args$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-cmd_args$U.Tpo $(DEPDIR)/ntpdsim-cmd_args$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmd_args$U.c' object='ntpdsim-cmd_args$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_io.o: ntp_io.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_io.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_io.Tpo -c -o ntpdsim-ntp_io.o `test -f 'ntp_io.c' || echo '$(srcdir)/'`ntp_io.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_io.Tpo $(DEPDIR)/ntpdsim-ntp_io.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_io.c' object='ntpdsim-ntp_io.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-cmd_args$U.o `test -f 'cmd_args$U.c' || echo '$(srcdir)/'`cmd_args$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_io.o `test -f 'ntp_io.c' || echo '$(srcdir)/'`ntp_io.c
-ntpdsim-cmd_args$U.obj: cmd_args$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-cmd_args$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-cmd_args$U.Tpo -c -o ntpdsim-cmd_args$U.obj `if test -f 'cmd_args$U.c'; then $(CYGPATH_W) 'cmd_args$U.c'; else $(CYGPATH_W) '$(srcdir)/cmd_args$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-cmd_args$U.Tpo $(DEPDIR)/ntpdsim-cmd_args$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmd_args$U.c' object='ntpdsim-cmd_args$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_io.obj: ntp_io.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_io.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_io.Tpo -c -o ntpdsim-ntp_io.obj `if test -f 'ntp_io.c'; then $(CYGPATH_W) 'ntp_io.c'; else $(CYGPATH_W) '$(srcdir)/ntp_io.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_io.Tpo $(DEPDIR)/ntpdsim-ntp_io.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_io.c' object='ntpdsim-ntp_io.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-cmd_args$U.obj `if test -f 'cmd_args$U.c'; then $(CYGPATH_W) 'cmd_args$U.c'; else $(CYGPATH_W) '$(srcdir)/cmd_args$U.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_io.obj `if test -f 'ntp_io.c'; then $(CYGPATH_W) 'ntp_io.c'; else $(CYGPATH_W) '$(srcdir)/ntp_io.c'; fi`
-ntpdsim-ntp_config$U.o: ntp_config$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_config$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_config$U.Tpo -c -o ntpdsim-ntp_config$U.o `test -f 'ntp_config$U.c' || echo '$(srcdir)/'`ntp_config$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntp_config$U.Tpo $(DEPDIR)/ntpdsim-ntp_config$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_config$U.c' object='ntpdsim-ntp_config$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_parser.o: ntp_parser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_parser.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_parser.Tpo -c -o ntpdsim-ntp_parser.o `test -f 'ntp_parser.c' || echo '$(srcdir)/'`ntp_parser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_parser.Tpo $(DEPDIR)/ntpdsim-ntp_parser.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_parser.c' object='ntpdsim-ntp_parser.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_config$U.o `test -f 'ntp_config$U.c' || echo '$(srcdir)/'`ntp_config$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_parser.o `test -f 'ntp_parser.c' || echo '$(srcdir)/'`ntp_parser.c
-ntpdsim-ntp_config$U.obj: ntp_config$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_config$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_config$U.Tpo -c -o ntpdsim-ntp_config$U.obj `if test -f 'ntp_config$U.c'; then $(CYGPATH_W) 'ntp_config$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_config$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntp_config$U.Tpo $(DEPDIR)/ntpdsim-ntp_config$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_config$U.c' object='ntpdsim-ntp_config$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_parser.obj: ntp_parser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_parser.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_parser.Tpo -c -o ntpdsim-ntp_parser.obj `if test -f 'ntp_parser.c'; then $(CYGPATH_W) 'ntp_parser.c'; else $(CYGPATH_W) '$(srcdir)/ntp_parser.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_parser.Tpo $(DEPDIR)/ntpdsim-ntp_parser.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_parser.c' object='ntpdsim-ntp_parser.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_config$U.obj `if test -f 'ntp_config$U.c'; then $(CYGPATH_W) 'ntp_config$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_config$U.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_parser.obj `if test -f 'ntp_parser.c'; then $(CYGPATH_W) 'ntp_parser.c'; else $(CYGPATH_W) '$(srcdir)/ntp_parser.c'; fi`
-ntpdsim-ntp_io$U.o: ntp_io$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_io$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_io$U.Tpo -c -o ntpdsim-ntp_io$U.o `test -f 'ntp_io$U.c' || echo '$(srcdir)/'`ntp_io$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntp_io$U.Tpo $(DEPDIR)/ntpdsim-ntp_io$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_io$U.c' object='ntpdsim-ntp_io$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_scanner.o: ntp_scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_scanner.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_scanner.Tpo -c -o ntpdsim-ntp_scanner.o `test -f 'ntp_scanner.c' || echo '$(srcdir)/'`ntp_scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_scanner.Tpo $(DEPDIR)/ntpdsim-ntp_scanner.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_scanner.c' object='ntpdsim-ntp_scanner.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_io$U.o `test -f 'ntp_io$U.c' || echo '$(srcdir)/'`ntp_io$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_scanner.o `test -f 'ntp_scanner.c' || echo '$(srcdir)/'`ntp_scanner.c
-ntpdsim-ntp_io$U.obj: ntp_io$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_io$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_io$U.Tpo -c -o ntpdsim-ntp_io$U.obj `if test -f 'ntp_io$U.c'; then $(CYGPATH_W) 'ntp_io$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_io$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntp_io$U.Tpo $(DEPDIR)/ntpdsim-ntp_io$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_io$U.c' object='ntpdsim-ntp_io$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_scanner.obj: ntp_scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_scanner.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_scanner.Tpo -c -o ntpdsim-ntp_scanner.obj `if test -f 'ntp_scanner.c'; then $(CYGPATH_W) 'ntp_scanner.c'; else $(CYGPATH_W) '$(srcdir)/ntp_scanner.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_scanner.Tpo $(DEPDIR)/ntpdsim-ntp_scanner.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_scanner.c' object='ntpdsim-ntp_scanner.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_io$U.obj `if test -f 'ntp_io$U.c'; then $(CYGPATH_W) 'ntp_io$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_io$U.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_scanner.obj `if test -f 'ntp_scanner.c'; then $(CYGPATH_W) 'ntp_scanner.c'; else $(CYGPATH_W) '$(srcdir)/ntp_scanner.c'; fi`
-ntpdsim-ntpd$U.o: ntpd$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd$U.Tpo -c -o ntpdsim-ntpd$U.o `test -f 'ntpd$U.c' || echo '$(srcdir)/'`ntpd$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpd$U.Tpo $(DEPDIR)/ntpdsim-ntpd$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd$U.c' object='ntpdsim-ntpd$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntpd.o: ntpd.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd.Tpo -c -o ntpdsim-ntpd.o `test -f 'ntpd.c' || echo '$(srcdir)/'`ntpd.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntpd.Tpo $(DEPDIR)/ntpdsim-ntpd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntpd.c' object='ntpdsim-ntpd.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd$U.o `test -f 'ntpd$U.c' || echo '$(srcdir)/'`ntpd$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd.o `test -f 'ntpd.c' || echo '$(srcdir)/'`ntpd.c
-ntpdsim-ntpd$U.obj: ntpd$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd$U.Tpo -c -o ntpdsim-ntpd$U.obj `if test -f 'ntpd$U.c'; then $(CYGPATH_W) 'ntpd$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpd$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpd$U.Tpo $(DEPDIR)/ntpdsim-ntpd$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd$U.c' object='ntpdsim-ntpd$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntpd.obj: ntpd.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd.Tpo -c -o ntpdsim-ntpd.obj `if test -f 'ntpd.c'; then $(CYGPATH_W) 'ntpd.c'; else $(CYGPATH_W) '$(srcdir)/ntpd.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntpd.Tpo $(DEPDIR)/ntpdsim-ntpd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntpd.c' object='ntpdsim-ntpd.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd$U.obj `if test -f 'ntpd$U.c'; then $(CYGPATH_W) 'ntpd$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpd$U.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd.obj `if test -f 'ntpd.c'; then $(CYGPATH_W) 'ntpd.c'; else $(CYGPATH_W) '$(srcdir)/ntpd.c'; fi`
-ntpdsim-ntpd-opts$U.o: ntpd-opts$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd-opts$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd-opts$U.Tpo -c -o ntpdsim-ntpd-opts$U.o `test -f 'ntpd-opts$U.c' || echo '$(srcdir)/'`ntpd-opts$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpd-opts$U.Tpo $(DEPDIR)/ntpdsim-ntpd-opts$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd-opts$U.c' object='ntpdsim-ntpd-opts$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntpd-opts.o: ntpd-opts.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd-opts.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd-opts.Tpo -c -o ntpdsim-ntpd-opts.o `test -f 'ntpd-opts.c' || echo '$(srcdir)/'`ntpd-opts.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntpd-opts.Tpo $(DEPDIR)/ntpdsim-ntpd-opts.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntpd-opts.c' object='ntpdsim-ntpd-opts.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd-opts$U.o `test -f 'ntpd-opts$U.c' || echo '$(srcdir)/'`ntpd-opts$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd-opts.o `test -f 'ntpd-opts.c' || echo '$(srcdir)/'`ntpd-opts.c
-ntpdsim-ntpd-opts$U.obj: ntpd-opts$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd-opts$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd-opts$U.Tpo -c -o ntpdsim-ntpd-opts$U.obj `if test -f 'ntpd-opts$U.c'; then $(CYGPATH_W) 'ntpd-opts$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpd-opts$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpd-opts$U.Tpo $(DEPDIR)/ntpdsim-ntpd-opts$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd-opts$U.c' object='ntpdsim-ntpd-opts$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntpd-opts.obj: ntpd-opts.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd-opts.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpd-opts.Tpo -c -o ntpdsim-ntpd-opts.obj `if test -f 'ntpd-opts.c'; then $(CYGPATH_W) 'ntpd-opts.c'; else $(CYGPATH_W) '$(srcdir)/ntpd-opts.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntpd-opts.Tpo $(DEPDIR)/ntpdsim-ntpd-opts.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntpd-opts.c' object='ntpdsim-ntpd-opts.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd-opts$U.obj `if test -f 'ntpd-opts$U.c'; then $(CYGPATH_W) 'ntpd-opts$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpd-opts$U.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd-opts.obj `if test -f 'ntpd-opts.c'; then $(CYGPATH_W) 'ntpd-opts.c'; else $(CYGPATH_W) '$(srcdir)/ntpd-opts.c'; fi`
-ntpdsim-ntpsim$U.o: ntpsim$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpsim$U.Tpo -c -o ntpdsim-ntpsim$U.o `test -f 'ntpsim$U.c' || echo '$(srcdir)/'`ntpsim$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpsim$U.Tpo $(DEPDIR)/ntpdsim-ntpsim$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpsim$U.c' object='ntpdsim-ntpsim$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_prio_q.o: ntp_prio_q.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_prio_q.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_prio_q.Tpo -c -o ntpdsim-ntp_prio_q.o `test -f 'ntp_prio_q.c' || echo '$(srcdir)/'`ntp_prio_q.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_prio_q.Tpo $(DEPDIR)/ntpdsim-ntp_prio_q.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_prio_q.c' object='ntpdsim-ntp_prio_q.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpsim$U.o `test -f 'ntpsim$U.c' || echo '$(srcdir)/'`ntpsim$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_prio_q.o `test -f 'ntp_prio_q.c' || echo '$(srcdir)/'`ntp_prio_q.c
-ntpdsim-ntpsim$U.obj: ntpsim$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpsim$U.Tpo -c -o ntpdsim-ntpsim$U.obj `if test -f 'ntpsim$U.c'; then $(CYGPATH_W) 'ntpsim$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpsim$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpsim$U.Tpo $(DEPDIR)/ntpdsim-ntpsim$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpsim$U.c' object='ntpdsim-ntpsim$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntp_prio_q.obj: ntp_prio_q.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_prio_q.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntp_prio_q.Tpo -c -o ntpdsim-ntp_prio_q.obj `if test -f 'ntp_prio_q.c'; then $(CYGPATH_W) 'ntp_prio_q.c'; else $(CYGPATH_W) '$(srcdir)/ntp_prio_q.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntp_prio_q.Tpo $(DEPDIR)/ntpdsim-ntp_prio_q.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntp_prio_q.c' object='ntpdsim-ntp_prio_q.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpsim$U.obj `if test -f 'ntpsim$U.c'; then $(CYGPATH_W) 'ntpsim$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpsim$U.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_prio_q.obj `if test -f 'ntp_prio_q.c'; then $(CYGPATH_W) 'ntp_prio_q.c'; else $(CYGPATH_W) '$(srcdir)/ntp_prio_q.c'; fi`
-ntpdsim-ntpdsim-opts$U.o: ntpdsim-opts$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpdsim-opts$U.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpdsim-opts$U.Tpo -c -o ntpdsim-ntpdsim-opts$U.o `test -f 'ntpdsim-opts$U.c' || echo '$(srcdir)/'`ntpdsim-opts$U.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpdsim-opts$U.Tpo $(DEPDIR)/ntpdsim-ntpdsim-opts$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpdsim-opts$U.c' object='ntpdsim-ntpdsim-opts$U.o' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntpsim.o: ntpsim.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim.o -MD -MP -MF $(DEPDIR)/ntpdsim-ntpsim.Tpo -c -o ntpdsim-ntpsim.o `test -f 'ntpsim.c' || echo '$(srcdir)/'`ntpsim.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntpsim.Tpo $(DEPDIR)/ntpdsim-ntpsim.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntpsim.c' object='ntpdsim-ntpsim.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpdsim-opts$U.o `test -f 'ntpdsim-opts$U.c' || echo '$(srcdir)/'`ntpdsim-opts$U.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpsim.o `test -f 'ntpsim.c' || echo '$(srcdir)/'`ntpsim.c
-ntpdsim-ntpdsim-opts$U.obj: ntpdsim-opts$U.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpdsim-opts$U.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpdsim-opts$U.Tpo -c -o ntpdsim-ntpdsim-opts$U.obj `if test -f 'ntpdsim-opts$U.c'; then $(CYGPATH_W) 'ntpdsim-opts$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpdsim-opts$U.c'; fi`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ntpdsim-ntpdsim-opts$U.Tpo $(DEPDIR)/ntpdsim-ntpdsim-opts$U.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpdsim-opts$U.c' object='ntpdsim-ntpdsim-opts$U.obj' libtool=no @AMDEPBACKSLASH@
+ntpdsim-ntpsim.obj: ntpsim.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim.obj -MD -MP -MF $(DEPDIR)/ntpdsim-ntpsim.Tpo -c -o ntpdsim-ntpsim.obj `if test -f 'ntpsim.c'; then $(CYGPATH_W) 'ntpsim.c'; else $(CYGPATH_W) '$(srcdir)/ntpsim.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ntpdsim-ntpsim.Tpo $(DEPDIR)/ntpdsim-ntpsim.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntpsim.c' object='ntpdsim-ntpsim.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpdsim-opts$U.obj `if test -f 'ntpdsim-opts$U.c'; then $(CYGPATH_W) 'ntpdsim-opts$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpdsim-opts$U.c'; fi`
-check_y2k_.c: check_y2k.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/check_y2k.c; then echo $(srcdir)/check_y2k.c; else echo check_y2k.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-cmd_args_.c: cmd_args.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/cmd_args.c; then echo $(srcdir)/cmd_args.c; else echo cmd_args.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_config_.c: ntp_config.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_config.c; then echo $(srcdir)/ntp_config.c; else echo ntp_config.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_control_.c: ntp_control.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_control.c; then echo $(srcdir)/ntp_control.c; else echo ntp_control.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_crypto_.c: ntp_crypto.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_crypto.c; then echo $(srcdir)/ntp_crypto.c; else echo ntp_crypto.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_filegen_.c: ntp_filegen.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_filegen.c; then echo $(srcdir)/ntp_filegen.c; else echo ntp_filegen.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_intres_.c: ntp_intres.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_intres.c; then echo $(srcdir)/ntp_intres.c; else echo ntp_intres.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_io_.c: ntp_io.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_io.c; then echo $(srcdir)/ntp_io.c; else echo ntp_io.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_loopfilter_.c: ntp_loopfilter.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_loopfilter.c; then echo $(srcdir)/ntp_loopfilter.c; else echo ntp_loopfilter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_monitor_.c: ntp_monitor.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_monitor.c; then echo $(srcdir)/ntp_monitor.c; else echo ntp_monitor.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_peer_.c: ntp_peer.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_peer.c; then echo $(srcdir)/ntp_peer.c; else echo ntp_peer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_proto_.c: ntp_proto.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_proto.c; then echo $(srcdir)/ntp_proto.c; else echo ntp_proto.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_refclock_.c: ntp_refclock.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_refclock.c; then echo $(srcdir)/ntp_refclock.c; else echo ntp_refclock.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_request_.c: ntp_request.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_request.c; then echo $(srcdir)/ntp_request.c; else echo ntp_request.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_restrict_.c: ntp_restrict.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_restrict.c; then echo $(srcdir)/ntp_restrict.c; else echo ntp_restrict.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_timer_.c: ntp_timer.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_timer.c; then echo $(srcdir)/ntp_timer.c; else echo ntp_timer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntp_util_.c: ntp_util.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_util.c; then echo $(srcdir)/ntp_util.c; else echo ntp_util.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntpd_.c: ntpd.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpd.c; then echo $(srcdir)/ntpd.c; else echo ntpd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntpd-opts_.c: ntpd-opts.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpd-opts.c; then echo $(srcdir)/ntpd-opts.c; else echo ntpd-opts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntpdsim-opts_.c: ntpdsim-opts.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpdsim-opts.c; then echo $(srcdir)/ntpdsim-opts.c; else echo ntpdsim-opts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-ntpsim_.c: ntpsim.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpsim.c; then echo $(srcdir)/ntpsim.c; else echo ntpsim.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_acts_.c: refclock_acts.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_acts.c; then echo $(srcdir)/refclock_acts.c; else echo refclock_acts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_arbiter_.c: refclock_arbiter.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_arbiter.c; then echo $(srcdir)/refclock_arbiter.c; else echo refclock_arbiter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_arc_.c: refclock_arc.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_arc.c; then echo $(srcdir)/refclock_arc.c; else echo refclock_arc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_as2201_.c: refclock_as2201.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_as2201.c; then echo $(srcdir)/refclock_as2201.c; else echo refclock_as2201.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_atom_.c: refclock_atom.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_atom.c; then echo $(srcdir)/refclock_atom.c; else echo refclock_atom.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_bancomm_.c: refclock_bancomm.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_bancomm.c; then echo $(srcdir)/refclock_bancomm.c; else echo refclock_bancomm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_chronolog_.c: refclock_chronolog.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_chronolog.c; then echo $(srcdir)/refclock_chronolog.c; else echo refclock_chronolog.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_chu_.c: refclock_chu.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_chu.c; then echo $(srcdir)/refclock_chu.c; else echo refclock_chu.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_conf_.c: refclock_conf.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_conf.c; then echo $(srcdir)/refclock_conf.c; else echo refclock_conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_datum_.c: refclock_datum.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_datum.c; then echo $(srcdir)/refclock_datum.c; else echo refclock_datum.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_dumbclock_.c: refclock_dumbclock.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_dumbclock.c; then echo $(srcdir)/refclock_dumbclock.c; else echo refclock_dumbclock.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_fg_.c: refclock_fg.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_fg.c; then echo $(srcdir)/refclock_fg.c; else echo refclock_fg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_gpsvme_.c: refclock_gpsvme.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_gpsvme.c; then echo $(srcdir)/refclock_gpsvme.c; else echo refclock_gpsvme.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_heath_.c: refclock_heath.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_heath.c; then echo $(srcdir)/refclock_heath.c; else echo refclock_heath.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_hopfpci_.c: refclock_hopfpci.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hopfpci.c; then echo $(srcdir)/refclock_hopfpci.c; else echo refclock_hopfpci.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_hopfser_.c: refclock_hopfser.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hopfser.c; then echo $(srcdir)/refclock_hopfser.c; else echo refclock_hopfser.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_hpgps_.c: refclock_hpgps.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hpgps.c; then echo $(srcdir)/refclock_hpgps.c; else echo refclock_hpgps.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_irig_.c: refclock_irig.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_irig.c; then echo $(srcdir)/refclock_irig.c; else echo refclock_irig.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_jjy_.c: refclock_jjy.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_jjy.c; then echo $(srcdir)/refclock_jjy.c; else echo refclock_jjy.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_jupiter_.c: refclock_jupiter.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_jupiter.c; then echo $(srcdir)/refclock_jupiter.c; else echo refclock_jupiter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_leitch_.c: refclock_leitch.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_leitch.c; then echo $(srcdir)/refclock_leitch.c; else echo refclock_leitch.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_local_.c: refclock_local.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_local.c; then echo $(srcdir)/refclock_local.c; else echo refclock_local.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_mx4200_.c: refclock_mx4200.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_mx4200.c; then echo $(srcdir)/refclock_mx4200.c; else echo refclock_mx4200.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_neoclock4x_.c: refclock_neoclock4x.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_neoclock4x.c; then echo $(srcdir)/refclock_neoclock4x.c; else echo refclock_neoclock4x.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_nmea_.c: refclock_nmea.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_nmea.c; then echo $(srcdir)/refclock_nmea.c; else echo refclock_nmea.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_oncore_.c: refclock_oncore.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_oncore.c; then echo $(srcdir)/refclock_oncore.c; else echo refclock_oncore.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_palisade_.c: refclock_palisade.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_palisade.c; then echo $(srcdir)/refclock_palisade.c; else echo refclock_palisade.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_parse_.c: refclock_parse.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_parse.c; then echo $(srcdir)/refclock_parse.c; else echo refclock_parse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_pcf_.c: refclock_pcf.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_pcf.c; then echo $(srcdir)/refclock_pcf.c; else echo refclock_pcf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_pst_.c: refclock_pst.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_pst.c; then echo $(srcdir)/refclock_pst.c; else echo refclock_pst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_ripencc_.c: refclock_ripencc.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ripencc.c; then echo $(srcdir)/refclock_ripencc.c; else echo refclock_ripencc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_shm_.c: refclock_shm.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_shm.c; then echo $(srcdir)/refclock_shm.c; else echo refclock_shm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_tpro_.c: refclock_tpro.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_tpro.c; then echo $(srcdir)/refclock_tpro.c; else echo refclock_tpro.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_true_.c: refclock_true.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_true.c; then echo $(srcdir)/refclock_true.c; else echo refclock_true.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_tt560_.c: refclock_tt560.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_tt560.c; then echo $(srcdir)/refclock_tt560.c; else echo refclock_tt560.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_ulink_.c: refclock_ulink.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ulink.c; then echo $(srcdir)/refclock_ulink.c; else echo refclock_ulink.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_wwv_.c: refclock_wwv.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_wwv.c; then echo $(srcdir)/refclock_wwv.c; else echo refclock_wwv.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_wwvb_.c: refclock_wwvb.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_wwvb.c; then echo $(srcdir)/refclock_wwvb.c; else echo refclock_wwvb.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-refclock_zyfer_.c: refclock_zyfer.c $(ANSI2KNR)
- $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_zyfer.c; then echo $(srcdir)/refclock_zyfer.c; else echo refclock_zyfer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
-check_y2k_.$(OBJEXT) check_y2k_.lo cmd_args_.$(OBJEXT) cmd_args_.lo \
-ntp_config_.$(OBJEXT) ntp_config_.lo ntp_control_.$(OBJEXT) \
-ntp_control_.lo ntp_crypto_.$(OBJEXT) ntp_crypto_.lo \
-ntp_filegen_.$(OBJEXT) ntp_filegen_.lo ntp_intres_.$(OBJEXT) \
-ntp_intres_.lo ntp_io_.$(OBJEXT) ntp_io_.lo ntp_loopfilter_.$(OBJEXT) \
-ntp_loopfilter_.lo ntp_monitor_.$(OBJEXT) ntp_monitor_.lo \
-ntp_peer_.$(OBJEXT) ntp_peer_.lo ntp_proto_.$(OBJEXT) ntp_proto_.lo \
-ntp_refclock_.$(OBJEXT) ntp_refclock_.lo ntp_request_.$(OBJEXT) \
-ntp_request_.lo ntp_restrict_.$(OBJEXT) ntp_restrict_.lo \
-ntp_timer_.$(OBJEXT) ntp_timer_.lo ntp_util_.$(OBJEXT) ntp_util_.lo \
-ntpd_.$(OBJEXT) ntpd_.lo ntpd-opts_.$(OBJEXT) ntpd-opts_.lo \
-ntpdsim-opts_.$(OBJEXT) ntpdsim-opts_.lo ntpsim_.$(OBJEXT) ntpsim_.lo \
-refclock_acts_.$(OBJEXT) refclock_acts_.lo refclock_arbiter_.$(OBJEXT) \
-refclock_arbiter_.lo refclock_arc_.$(OBJEXT) refclock_arc_.lo \
-refclock_as2201_.$(OBJEXT) refclock_as2201_.lo \
-refclock_atom_.$(OBJEXT) refclock_atom_.lo refclock_bancomm_.$(OBJEXT) \
-refclock_bancomm_.lo refclock_chronolog_.$(OBJEXT) \
-refclock_chronolog_.lo refclock_chu_.$(OBJEXT) refclock_chu_.lo \
-refclock_conf_.$(OBJEXT) refclock_conf_.lo refclock_datum_.$(OBJEXT) \
-refclock_datum_.lo refclock_dumbclock_.$(OBJEXT) \
-refclock_dumbclock_.lo refclock_fg_.$(OBJEXT) refclock_fg_.lo \
-refclock_gpsvme_.$(OBJEXT) refclock_gpsvme_.lo \
-refclock_heath_.$(OBJEXT) refclock_heath_.lo \
-refclock_hopfpci_.$(OBJEXT) refclock_hopfpci_.lo \
-refclock_hopfser_.$(OBJEXT) refclock_hopfser_.lo \
-refclock_hpgps_.$(OBJEXT) refclock_hpgps_.lo refclock_irig_.$(OBJEXT) \
-refclock_irig_.lo refclock_jjy_.$(OBJEXT) refclock_jjy_.lo \
-refclock_jupiter_.$(OBJEXT) refclock_jupiter_.lo \
-refclock_leitch_.$(OBJEXT) refclock_leitch_.lo \
-refclock_local_.$(OBJEXT) refclock_local_.lo \
-refclock_mx4200_.$(OBJEXT) refclock_mx4200_.lo \
-refclock_neoclock4x_.$(OBJEXT) refclock_neoclock4x_.lo \
-refclock_nmea_.$(OBJEXT) refclock_nmea_.lo refclock_oncore_.$(OBJEXT) \
-refclock_oncore_.lo refclock_palisade_.$(OBJEXT) refclock_palisade_.lo \
-refclock_parse_.$(OBJEXT) refclock_parse_.lo refclock_pcf_.$(OBJEXT) \
-refclock_pcf_.lo refclock_pst_.$(OBJEXT) refclock_pst_.lo \
-refclock_ripencc_.$(OBJEXT) refclock_ripencc_.lo \
-refclock_shm_.$(OBJEXT) refclock_shm_.lo refclock_tpro_.$(OBJEXT) \
-refclock_tpro_.lo refclock_true_.$(OBJEXT) refclock_true_.lo \
-refclock_tt560_.$(OBJEXT) refclock_tt560_.lo refclock_ulink_.$(OBJEXT) \
-refclock_ulink_.lo refclock_wwv_.$(OBJEXT) refclock_wwv_.lo \
-refclock_wwvb_.$(OBJEXT) refclock_wwvb_.lo refclock_zyfer_.$(OBJEXT) \
-refclock_zyfer_.lo : $(ANSI2KNR)
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ntpdsim_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpsim.obj `if test -f 'ntpsim.c'; then $(CYGPATH_W) 'ntpsim.c'; else $(CYGPATH_W) '$(srcdir)/ntpsim.c'; fi`
+
+.y.c:
+ $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
-install-man1: $(man_MANS)
+install-man1: $(man1_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
- test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
- @list=''; test -n "$(man1dir)" || exit 0; \
- { for i in $$list; do echo "$$i"; done; \
- l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
- sed -n '/\.1[a-z]*$$/p'; \
+ @list1='$(man1_MANS)'; \
+ list2='$(man_MANS)'; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
} | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \
@@ -845,36 +1303,130 @@ install-man1: $(man_MANS)
uninstall-man1:
@$(NORMAL_UNINSTALL)
- @list=''; test -n "$(man1dir)" || exit 0; \
+ @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \
files=`{ for i in $$list; do echo "$$i"; done; \
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
sed -n '/\.1[a-z]*$$/p'; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
- test -z "$$files" || { \
- echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(man1dir)" && rm -f $$files; }
-
-ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
- list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
- mkid -fID $$unique
-tags: TAGS
-
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
- $(TAGS_FILES) $(LISP)
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-man5: $(man5_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1='$(man5_MANS)'; \
+ list2='$(man_MANS)'; \
+ test -n "$(man5dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.5[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.5[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1='$(man8_MANS)'; \
+ list2='$(man_MANS)'; \
+ test -n "$(man8dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.8[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.8[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
+install-htmlDATA: $(html_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(html_DATA)'; test -n "$(htmldir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \
+ done
+
+uninstall-htmlDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(html_DATA)'; test -n "$(htmldir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(htmldir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
- list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
@@ -886,15 +1438,11 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$$unique; \
fi; \
fi
-ctags: CTAGS
-CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
- $(TAGS_FILES) $(LISP)
- list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
@@ -903,24 +1451,26 @@ GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
- @list='$(MANS)'; if test -n "$$list"; then \
- list=`for p in $$list; do \
- if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
- if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
- if test -n "$$list" && \
- grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
- echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
- grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \
- echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \
- echo " typically \`make maintainer-clean' will remove them" >&2; \
- exit 1; \
- else :; fi; \
- else :; fi
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
@@ -955,9 +1505,9 @@ check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-local
check: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) check-am
-all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS)
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS) $(DATA) $(HEADERS)
installdirs:
- for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(htmldir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
@@ -971,13 +1521,19 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
mostlyclean-generic:
clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -987,11 +1543,14 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
+ -rm -f ntp_parser.c
+ -rm -f ntp_parser.h
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
clean: clean-am
clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
- clean-libtool clean-noinstLIBRARIES mostlyclean-am
+ clean-libexecPROGRAMS clean-libtool clean-noinstLIBRARIES \
+ clean-sbinPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
@@ -1011,13 +1570,14 @@ info: info-am
info-am:
-install-data-am: install-man
+install-data-am: install-data-local install-htmlDATA install-man
install-dvi: install-dvi-am
install-dvi-am:
-install-exec-am: install-binPROGRAMS
+install-exec-am: install-binPROGRAMS install-libexecPROGRAMS \
+ install-sbinPROGRAMS
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
install-html: install-html-am
@@ -1028,7 +1588,7 @@ install-info: install-info-am
install-info-am:
-install-man: install-man1
+install-man: install-man1 install-man5 install-man8
install-pdf: install-pdf-am
@@ -1047,7 +1607,7 @@ maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
-mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr \
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
@@ -1058,84 +1618,298 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-binPROGRAMS uninstall-man
+uninstall-am: uninstall-binPROGRAMS uninstall-htmlDATA \
+ uninstall-libexecPROGRAMS uninstall-man uninstall-sbinPROGRAMS
-uninstall-man: uninstall-man1
+uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8
-.MAKE: ../util/ansi2knr all check check-am install install-am \
- install-exec-am install-strip
+.MAKE: all check check-am install install-am install-exec-am \
+ install-strip
-.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \
clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
- clean-libtool clean-noinstLIBRARIES ctags distclean \
+ clean-libexecPROGRAMS clean-libtool clean-noinstLIBRARIES \
+ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-binPROGRAMS install-data \
- install-data-am install-dvi install-dvi-am install-exec \
- install-exec-am install-exec-hook install-html install-html-am \
- install-info install-info-am install-man install-man1 \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip installcheck installcheck-am installdirs \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-kr \
- mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
- uninstall-am uninstall-binPROGRAMS uninstall-man \
- uninstall-man1
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-exec-hook install-html \
+ install-html-am install-htmlDATA install-info install-info-am \
+ install-libexecPROGRAMS install-man install-man1 install-man5 \
+ install-man8 install-pdf install-pdf-am install-ps \
+ install-ps-am install-sbinPROGRAMS install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-htmlDATA uninstall-libexecPROGRAMS uninstall-man \
+ uninstall-man1 uninstall-man5 uninstall-man8 \
+ uninstall-sbinPROGRAMS
+
+.PRECIOUS: Makefile
-check-local: @MAKE_CHECK_Y2K@
- test -z "@MAKE_CHECK_Y2K@" || ./@MAKE_CHECK_Y2K@
+vphack:
+ test -e ntp_parser.c || ln -s $(srcdir)/ntp_parser.c .
+ test -e ntp_parser.h || ln -s $(srcdir)/ntp_parser.h .
+
+#
+# ylwrap script which invokes Bison replaces ntp_parser.h
+# symlink with the updated file, when ntp_parser.h changes.
+# vphack_after detects this and copies the updated file to srcdir
+# and re-creates the ntp_parser.h symlink in its place.
+#
+
+vphack_after:
+ test -L ntp_parser.h || ( \
+ mv ntp_parser.h $(srcdir)/ntp_parser.h && \
+ ln -s $(srcdir)/ntp_parser.h . \
+ )
+
+install-data-local: install-html
+
+check-local: $(MAKE_CHECK_Y2K) $(CHECK_SAVECONFIG)
+ test -z "$(MAKE_CHECK_Y2K)" || ./$(MAKE_CHECK_Y2K)
+
+k-g-u-submake: keyword-gen
+ ./keyword-gen $(srcdir)/ntp_parser.h > k-g.out
+ @grep -v diff_ignore_line < k-g.out > cmp1
+ @grep -v diff_ignore_line < $(srcdir)/ntp_keyword.h > cmp2
+ @cmp cmp1 cmp2 > /dev/null || \
+ { mv -f k-g.out $(srcdir)/ntp_keyword.h && \
+ echo 'Generated changed ntp_keyword.h.' ;}
+ @[ ! -f k-g.out ] || \
+ { rm k-g.out && echo 'ntp_keyword.h is up to date.' ;}
+ @rm cmp1 cmp2
+ @echo 'keyword-gen and ntp_keyword.h are up to date.' > $@
+
+$(srcdir)/keyword-gen-utd: $(srcdir)/keyword-gen.c $(srcdir)/ntp_parser.h
+ $(MAKE) $(AM_MAKEFLAGS) k-g-u-submake # avoid explicit dependency
+ grep diff_ignore_line $(srcdir)/ntp_keyword.h > k-g-u
+ mv -f k-g-u $@
+
+$(srcdir)/ntp_keyword.h: $(srcdir)/keyword-gen-utd
+ @: do-nothing action to avoid default SCCS get
+ @: .h updated if needed by k-g-u-submake rule
$(srcdir)/ntpd-opts.h: $(srcdir)/ntpd-opts.c
+ @: do-nothing action to avoid default SCCS get, .h built with .c
+
$(srcdir)/ntpd-opts.c: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
$(run_ag) ntpd-opts.def
-$(srcdir)/ntpd.1: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
- $(run_ag) -Tagman1.tpl -bntpd ntpd-opts.def
+###
-$(srcdir)/ntpd-opts.texi $(srcdir)/ntpd-opts.menu: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
- $(run_ag) -Taginfo.tpl -DLEVEL=section ntpd-opts.def
+$(srcdir)/ntpd.1ntpdman: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=1ntpdman -Tagman-cmd.tpl ntpd-opts.def
-$(srcdir)/ntpdsim-opts.h: $(srcdir)/ntpdsim-opts.c
-$(srcdir)/ntpdsim-opts.c: $(srcdir)/ntpdsim-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list) $(top_srcdir)/include/homerc.def
- $(run_ag) ntpdsim-opts.def
+$(srcdir)/ntpd.man.in: $(srcdir)/ntpd.1ntpdman $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntpd.1ntpdman > $(srcdir)/ntpd.man.in+
+ mv $(srcdir)/ntpd.man.in+ $(srcdir)/ntpd.man.in
-$(srcdir)/ntpdsim.1: $(srcdir)/ntpdsim-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list) $(top_srcdir)/include/homerc.def
- $(run_ag) -Tagman1.tpl -bntpdsim ntpdsim-opts.def
+###
-$(srcdir)/ntpdsim-opts.texi $(srcdir)/ntpdsim-opts.menu: $(srcdir)/ntpdsim-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list) $(top_srcdir)/include/homerc.def
- $(run_ag) -Taginfo.tpl -DLEVEL=section ntpdsim-opts.def
+$(srcdir)/ntpd.1ntpdmdoc: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=1ntpdmdoc -Tagmdoc-cmd.tpl ntpd-opts.def
+
+$(srcdir)/ntpd.mdoc.in: $(srcdir)/ntpd.1ntpdmdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntpd.1ntpdmdoc > $(srcdir)/ntpd.mdoc.in+
+ mv $(srcdir)/ntpd.mdoc.in+ $(srcdir)/ntpd.mdoc.in
+
+###
+
+ntpd.$(NTPD_MS): $(srcdir)/ntpd.$(MANTAGFMT).in $(top_builddir)/config.status
+ $(top_builddir)/config.status --file=ntpd.$(NTPD_MS)+:$(srcdir)/ntpd.$(MANTAGFMT).in
+ mv ntpd.$(NTPD_MS)+ ntpd.$(NTPD_MS)
+
+###
+
+$(srcdir)/invoke-ntp.conf.menu: $(srcdir)/invoke-ntp.conf.texi
+ @: do-nothing action to avoid default SCCS get, .menu built with .texi
+
+$(srcdir)/invoke-ntp.conf.texi: $(srcdir)/ntp.conf.def $(std_def_list)
+ $(run_ag) -Tagtexi-file.tpl -DLEVEL=section ntp.conf.def
+
+$(srcdir)/invoke-ntp.keys.menu: $(srcdir)/invoke-ntp.keys.texi
+ @: do-nothing action to avoid default SCCS get, .menu built with .texi
+
+$(srcdir)/invoke-ntp.keys.texi: $(srcdir)/ntp.keys.def $(std_def_list)
+ $(run_ag) -Tagtexi-file.tpl -DLEVEL=section ntp.keys.def
+
+$(srcdir)/ntp.conf.html: $(srcdir)/ntp.conf.texi $(top_srcdir)/sntp/include/version.texi
+ cd $(srcdir) && ( makeinfo --force --html --no-split -o ntp.conf.html ntp.conf.texi || true )
+
+$(srcdir)/ntp.keys.html: $(srcdir)/ntp.keys.texi $(top_srcdir)/sntp/include/version.texi
+ cd $(srcdir) && ( makeinfo --force --html --no-split -o ntp.keys.html ntp.keys.texi || true )
+
+$(srcdir)/ntpd.html: $(srcdir)/ntpd.texi $(top_srcdir)/sntp/include/version.texi
+ cd $(srcdir) && ( makeinfo --force --html --no-split -o ntpd.html ntpd.texi || true )
+
+###
+
+$(srcdir)/ntp.conf.5man: $(srcdir)/ntp.conf.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5man -Tagman-cmd.tpl ntp.conf.def
+
+$(srcdir)/ntp.conf.man.in: $(srcdir)/ntp.conf.5man $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.conf.5man > $(srcdir)/ntp.conf.man.in+
+ mv $(srcdir)/ntp.conf.man.in+ $(srcdir)/ntp.conf.man.in
+
+###
+
+$(srcdir)/ntp.conf.5mdoc: $(srcdir)/ntp.conf.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5mdoc -Tagmdoc-cmd.tpl ntp.conf.def
+
+$(srcdir)/ntp.conf.mdoc.in: $(srcdir)/ntp.conf.5mdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.conf.5mdoc > $(srcdir)/ntp.conf.mdoc.in+
+ mv $(srcdir)/ntp.conf.mdoc.in+ $(srcdir)/ntp.conf.mdoc.in
+
+###
+
+ntp.conf.5: $(srcdir)/ntp.conf.$(MANTAGFMT).in $(top_builddir)/config.status
+ $(top_builddir)/config.status --file=ntp.conf.5+:$(srcdir)/ntp.conf.$(MANTAGFMT).in
+ mv ntp.conf.5+ ntp.conf.5
+
+###
+
+$(srcdir)/ntp.keys.5man: $(srcdir)/ntp.keys.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5man -Tagman-file.tpl ntp.keys.def
+
+$(srcdir)/ntp.keys.man.in: $(srcdir)/ntp.keys.5man $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.keys.5man > $(srcdir)/ntp.keys.man.in+
+ mv $(srcdir)/ntp.keys.man.in+ $(srcdir)/ntp.keys.man.in
+
+###
+
+$(srcdir)/ntp.keys.5mdoc: $(srcdir)/ntp.keys.def $(std_def_list)
+ $(run_ag) -DMAN_SECTION=5mdoc -Tagmdoc-file.tpl ntp.keys.def
+
+$(srcdir)/ntp.keys.mdoc.in: $(srcdir)/ntp.keys.5mdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed
+ sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp.keys.5mdoc > $(srcdir)/ntp.keys.mdoc.in+
+ mv $(srcdir)/ntp.keys.mdoc.in+ $(srcdir)/ntp.keys.mdoc.in
+
+###
+
+ntp.keys.5: $(srcdir)/ntp.keys.$(MANTAGFMT).in $(top_builddir)/config.status
+ $(top_builddir)/config.status --file=ntp.keys.5+:$(srcdir)/ntp.keys.$(MANTAGFMT).in
+ mv ntp.keys.5+ ntp.keys.5
+
+###
+
+$(srcdir)/invoke-ntpd.menu: $(srcdir)/invoke-ntpd.texi
+ @: do-nothing action to avoid default SCCS get, .menu built with .texi
+
+$(srcdir)/invoke-ntpd.texi: $(srcdir)/ntpd-opts.def $(srcdir)/ntpdbase-opts.def $(std_def_list)
+ $(run_ag) -Tagtexi-cmd.tpl -DLEVEL=section ntpd-opts.def
+ $(top_srcdir)/scripts/build/check--help $@
$(PROGRAMS): $(LDADD)
-../libntp/libntp.a:
- cd ../libntp && $(MAKE) libntp.a
+compsave.conf: ntpd complete.conf
+ ./ntpd --configfile complete.conf --saveconfigquit $@
+
+check-saveconfig: complete.conf compsave.conf
+ -diff -u complete.conf compsave.conf
+ cmp complete.conf compsave.conf && echo stamp > $@
../libntp/libntpsim.a:
- cd ../libntp && $(MAKE) libntpsim.a
+ cd ../libntp && $(MAKE) $(AM_MAKEFLAGS) libntpsim.a
../libparse/libparse.a:
- cd ../libparse && $(MAKE)
+ cd ../libparse && $(MAKE) $(AM_MAKEFLAGS) check-libparse
-$(top_srcdir)/version :
- cd $(top_srcdir) && $(MAKE) version
+$(top_srcdir)/sntp/scm-rev:
+ cd ../sntp && $(MAKE) $(AM_MAKEFLAGS) check-scm-rev
-version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ Makefile $(top_srcdir)/version
- env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpd
- $(COMPILE) -c version.c
+version.c: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ Makefile $(top_srcdir)/sntp/scm-rev
+ env CSET=`cat $(top_srcdir)/sntp/scm-rev` $(top_builddir)/scripts/build/mkver ntpd
+
+version.o: version.c
+ env CCACHE_DISABLE=1 $(COMPILE) -c version.c -o version.o
install-exec-hook:
- @case ${BINSUBDIR} in \
- bin) ODIR=${exec_prefix}/sbin ;; \
- sbin) ODIR=${exec_prefix}/bin ;; \
- esac; \
- test -z "${bin_PROGRAMS}${bin_SCRIPTS}" \
- || for i in ${bin_PROGRAMS} ${bin_SCRIPTS} " "; do \
- test ! -f $$ODIR/$$i || echo "*** $$i is also in $$ODIR!"; \
+ @test -z "${bin_PROGRAMS}${bin_SCRIPTS}" \
+ || for i in ${bin_PROGRAMS} ${bin_SCRIPTS} " "; do \
+ test ! -f ${sbindir}/$$i \
+ || echo "*** $$i is also in ${sbindir}!"; \
+ done
+ @test -z "${sbin_PROGRAMS}${asbin_SCRIPTS}" \
+ || for i in ${sbin_PROGRAMS} ${sbin_SCRIPTS} " "; do \
+ test ! -f ${bindir}/$$i \
+ || echo "*** $$i is also in ${bindir}!"; \
done
#
+check-libopts: ../sntp/libopts/libopts.la
+ @echo stamp > $@
+
+../sntp/libopts/libopts.la:
+ -cd ../sntp/libopts && $(MAKE) $(AM_MAKEFLAGS) libopts.la
+
+check-libntp: ../libntp/libntp.a
+ @echo stamp > $@
+
+../libntp/libntp.a:
+ cd ../libntp && $(MAKE) $(AM_MAKEFLAGS) libntp.a
+$(DEPDIR)/deps-ver: $(top_srcdir)/deps-ver
+ @[ -f $@ ] || \
+ cp $(top_srcdir)/deps-ver $@
+ @[ -w $@ ] || \
+ chmod ug+w $@
+ @cmp $(top_srcdir)/deps-ver $@ > /dev/null || ( \
+ $(MAKE) $(AM_MAKEFLAGS) clean && \
+ echo -n "Prior $(subdir)/$(DEPDIR) version " && \
+ cat $@ && \
+ rm -rf $(DEPDIR) && \
+ mkdir $(DEPDIR) && \
+ case "$(top_builddir)" in \
+ .) \
+ ./config.status Makefile depfiles \
+ ;; \
+ *) \
+ cd "$(top_builddir)" && \
+ ./config.status $(subdir)/Makefile depfiles && \
+ cd $(subdir) \
+ ;; \
+ esac && \
+ echo -n "Cleaned $(subdir)/$(DEPDIR) version " && \
+ cat $(top_srcdir)/deps-ver \
+ )
+ cp $(top_srcdir)/deps-ver $@
+
+.deps-ver: $(top_srcdir)/deps-ver
+ @[ ! -d $(DEPDIR) ] || $(MAKE) $(AM_MAKEFLAGS) $(DEPDIR)/deps-ver
+ @touch $@
+
+#
+# depsver.mf included in Makefile.am for directories with .deps
+#
+# When building in the same directory with sources that change over
+# time, such as when tracking using bk, the .deps files can become
+# stale with respect to moved, deleted, or superceded headers. Most
+# commonly, this would exhibit as make reporting a failure to make a
+# header file which is no longer in the location given. To address
+# this issue, we use a deps-ver file which is updated with each change
+# that breaks old .deps files. A copy of deps-ver is made into
+# $(DEPDIR) if not already present. If $(DEPDIR)/deps-ver is present
+# with different contents than deps-ver, we make clean to ensure all
+# .o files built before the incompatible change are rebuilt along with
+# their updated .deps files, then remove $(DEPDIR) and recreate it as
+# empty stubs.
+#
+# It is normal when configured with --disable-dependency-tracking for
+# the DEPDIR to not have been created. For this reason, we use the
+# intermediate target .deps-ver, which invokes make recursively if
+# DEPDIR exists.
+#
+# If you modify depsver.mf, please make the changes to the master
+# copy, the one in sntp is copied by the bootstrap script from it.
+#
+# This comment block follows rather than leads the related code so that
+# it stays with it in the generated Makefile.in and Makefile.
+#
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/contrib/ntp/ntpd/check_y2k.c b/contrib/ntp/ntpd/check_y2k.c
index 6b83115..12d1a59 100644
--- a/contrib/ntp/ntpd/check_y2k.c
+++ b/contrib/ntp/ntpd/check_y2k.c
@@ -104,7 +104,6 @@
#define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
-volatile int debug = 0; /* debugging requests for parse stuff */
char const *progname = "check_y2k";
long
diff --git a/contrib/ntp/ntpd/cmd_args.c b/contrib/ntp/ntpd/cmd_args.c
index 7843bc3..14e86f7 100644
--- a/contrib/ntp/ntpd/cmd_args.c
+++ b/contrib/ntp/ntpd/cmd_args.c
@@ -7,23 +7,15 @@
#include "ntpd.h"
#include "ntp_stdlib.h"
+#include "ntp_config.h"
#include "ntp_cmdargs.h"
-#ifdef SIM
-# include "ntpsim.h"
-# include "ntpdsim-opts.h"
-# define OPTSTRUCT ntpdsimOptions
-#else
-# include "ntpd-opts.h"
-# define OPTSTRUCT ntpdOptions
-#endif /* SIM */
+#include "ntpd-opts.h"
/*
* Definitions of things either imported from or exported to outside
*/
extern char const *progname;
-extern const char *specific_interface;
-extern short default_ai_family;
#ifdef HAVE_NETINFO
extern int check_netinfo;
@@ -31,39 +23,41 @@ extern int check_netinfo;
/*
- * getCmdOpts - get command line options
+ * getCmdOpts - apply most command line options
+ *
+ * A few options are examined earlier in ntpd.c ntpdmain() and
+ * ports/winnt/ntpd/ntservice.c main().
*/
void
getCmdOpts(
- int argc,
- char *argv[]
+ int argc,
+ char ** argv
)
{
extern const char *config_file;
int errflg;
- tOptions *myOptions = &OPTSTRUCT;
/*
* Initialize, initialize
*/
errflg = 0;
- switch (WHICH_IDX_IPV4) {
- case INDEX_OPT_IPV4:
- default_ai_family = AF_INET;
- break;
- case INDEX_OPT_IPV6:
- default_ai_family = AF_INET6;
- break;
- default:
- /* ai_fam_templ = ai_fam_default; */
- break;
- }
+ if (ipv4_works && ipv6_works) {
+ if (HAVE_OPT( IPV4 ))
+ ipv6_works = 0;
+ else if (HAVE_OPT( IPV6 ))
+ ipv4_works = 0;
+ } else if (!ipv4_works && !ipv6_works) {
+ msyslog(LOG_ERR, "Neither IPv4 nor IPv6 networking detected, fatal.");
+ exit(1);
+ } else if (HAVE_OPT( IPV4 ) && !ipv4_works)
+ msyslog(LOG_WARNING, "-4/--ipv4 ignored, IPv4 networking not found.");
+ else if (HAVE_OPT( IPV6 ) && !ipv6_works)
+ msyslog(LOG_WARNING, "-6/--ipv6 ignored, IPv6 networking not found.");
if (HAVE_OPT( AUTHREQ ))
proto_config(PROTO_AUTHENTICATE, 1, 0., NULL);
-
- if (HAVE_OPT( AUTHNOREQ ))
+ else if (HAVE_OPT( AUTHNOREQ ))
proto_config(PROTO_AUTHENTICATE, 0, 0., NULL);
if (HAVE_OPT( BCASTSYNC ))
@@ -82,24 +76,15 @@ getCmdOpts(
if (HAVE_OPT( PANICGATE ))
allow_panic = TRUE;
- if (HAVE_OPT( JAILDIR )) {
+ if (HAVE_OPT( FORCE_STEP_ONCE ))
+ force_step_once = TRUE;
+
#ifdef HAVE_DROPROOT
- droproot = 1;
- chrootdir = OPT_ARG( JAILDIR );
-#else
- fprintf(stderr,
- "command line -i option (jaildir) is not supported by this binary"
-# ifndef SYS_WINNT
- ",\n" "can not drop root privileges. See configure options\n"
- "--enable-clockctl and --enable-linuxcaps.\n");
-# else
- ".\n");
-# endif
- msyslog(LOG_ERR,
- "command line -i option (jaildir) is not supported by this binary.");
- errflg++;
-#endif
+ if (HAVE_OPT( JAILDIR )) {
+ droproot = 1;
+ chrootdir = OPT_ARG( JAILDIR );
}
+#endif
if (HAVE_OPT( KEYFILE ))
getauthkeys(OPT_ARG( KEYFILE ));
@@ -146,40 +131,33 @@ getCmdOpts(
} while (--ct > 0);
}
- if (HAVE_OPT( USER )) {
#ifdef HAVE_DROPROOT
- char *ntp_optarg = OPT_ARG( USER );
-
+ if (HAVE_OPT( USER )) {
droproot = 1;
- user = emalloc(strlen(ntp_optarg) + 1);
- (void)strncpy(user, ntp_optarg, strlen(ntp_optarg) + 1);
- group = rindex(user, ':');
- if (group)
+ user = estrdup(OPT_ARG( USER ));
+ group = strrchr(user, ':');
+ if (group != NULL) {
+ size_t len;
+
*group++ = '\0'; /* get rid of the ':' */
-#else
- fprintf(stderr,
- "command line -u/--user option is not supported by this binary"
-# ifndef SYS_WINNT
- ",\n" "can not drop root privileges. See configure options\n"
- "--enable-clockctl and --enable-linuxcaps.\n");
-# else
- ".\n");
-# endif
- msyslog(LOG_ERR,
- "command line -u/--user option is not supported by this binary.");
- errflg++;
-#endif
+ len = group - user;
+ group = estrdup(group);
+ user = erealloc(user, len);
+ }
}
+#endif
if (HAVE_OPT( VAR )) {
- int ct = STACKCT_OPT( VAR );
- const char** pp = STACKLST_OPT( VAR );
+ int ct;
+ const char ** pp;
+ const char * v_assign;
- do {
- const char* my_ntp_optarg = *pp++;
+ ct = STACKCT_OPT( VAR );
+ pp = STACKLST_OPT( VAR );
- set_sys_var(my_ntp_optarg, strlen(my_ntp_optarg)+1,
- (u_short) (RW));
+ do {
+ v_assign = *pp++;
+ set_sys_var(v_assign, strlen(v_assign) + 1, RW);
} while (--ct > 0);
}
@@ -196,57 +174,32 @@ getCmdOpts(
}
if (HAVE_OPT( SLEW ))
- clock_max = 600;
+ loop_config(LOOP_MAX, 600);
if (HAVE_OPT( UPDATEINTERVAL )) {
long val = OPT_VALUE_UPDATEINTERVAL;
-
+
if (val >= 0)
interface_interval = val;
else {
- fprintf(stderr,
+ fprintf(stderr,
"command line interface update interval %ld must not be negative\n",
val);
- msyslog(LOG_ERR,
+ msyslog(LOG_ERR,
"command line interface update interval %ld must not be negative",
val);
errflg++;
}
}
-#ifdef SIM
- if (HAVE_OPT( SIMBROADCASTDELAY ))
- sscanf(OPT_ARG( SIMBROADCASTDELAY ), "%lf", &ntp_node.bdly);
-
- if (HAVE_OPT( PHASENOISE ))
- sscanf(OPT_ARG( PHASENOISE ), "%lf", &ntp_node.snse);
-
- if (HAVE_OPT( SIMSLEW ))
- sscanf(OPT_ARG( SIMSLEW ), "%lf", &ntp_node.slew);
- if (HAVE_OPT( SERVERTIME ))
- sscanf(OPT_ARG( SERVERTIME ), "%lf", &ntp_node.clk_time);
- if (HAVE_OPT( ENDSIMTIME ))
- sscanf(OPT_ARG( ENDSIMTIME ), "%lf", &ntp_node.sim_time);
-
- if (HAVE_OPT( FREQERR ))
- sscanf(OPT_ARG( FREQERR ), "%lf", &ntp_node.ferr);
-
- if (HAVE_OPT( WALKNOISE ))
- sscanf(OPT_ARG( WALKNOISE ), "%lf", &ntp_node.fnse);
-
- if (HAVE_OPT( NDELAY ))
- sscanf(OPT_ARG( NDELAY ), "%lf", &ntp_node.ndly);
-
- if (HAVE_OPT( PDELAY ))
- sscanf(OPT_ARG( PDELAY ), "%lf", &ntp_node.pdly);
-
-#endif /* SIM */
-
- if (errflg || argc) {
- if (argc)
- fprintf(stderr, "argc after processing is <%d>\n", argc);
- optionUsage(myOptions, 2);
+ /* save list of servers from cmd line for config_peers() use */
+ if (argc > 0) {
+ cmdline_server_count = argc;
+ cmdline_servers = argv;
}
- return;
+
+ /* display usage & exit with any option processing errors */
+ if (errflg)
+ optionUsage(&ntpdOptions, 2); /* does not return */
}
diff --git a/contrib/ntp/ntpd/complete.conf.in b/contrib/ntp/ntpd/complete.conf.in
new file mode 100644
index 0000000..747a48f
--- /dev/null
+++ b/contrib/ntp/ntpd/complete.conf.in
@@ -0,0 +1,69 @@
+saveconfigdir "/etc/ntp/conf"
+driftfile "/etc/ntp.drift" 1e-7
+logfile "/var/log/ntp.log"
+leapfile "/etc/ntp.leapseconds"
+@HAVE_LEAPSMEARINTERVAL@
+nonvolatile 1e-7
+ident "udent"
+dscp 46
+logconfig =allall -allinfo -allevents -allstatistics -allstatus +allall -clockinfo -clockevents -clockstatistics -clockstatus +clockall -syncinfo -syncevents -syncstatistics -syncstatus +syncall -sysinfo -sysevents -sysstatistics -sysstatus +sysall
+statsdir "/etc/ntp/stats"
+statistics clockstats cryptostats loopstats peerstats protostats rawstats sysstats timingstats
+filegen clockstats file clockstats type none enable
+filegen cryptostats file cryptostats type pid link disable
+filegen loopstats file loopstats type day nolink enable
+filegen peerstats file peerstats type week enable
+filegen protostats file stats type month enable
+filegen rawstats file rawstats type year nolink enable
+filegen sysstats file sysstats type age enable
+filegen timingstats file timingstats type none disable
+crypto digest md5 host myhostname ident wedent pw cryptopass randfile /.rnd
+revoke 10
+keysdir "/etc/ntp/keys"
+keys "/etc/ntp.keys"
+trustedkey 1 2 3 4 5 6 7 8 9 10 11 12 (14 ... 16) 18 (32768 ... 65534)
+controlkey 12
+requestkey 12
+enable auth ntp monitor stats
+disable bclient calibrate kernel mode7
+tos beacon 3600 ceiling 16 cohort 0 floor 1 maxclock 10 maxdist 1.5 minclock 3 mindist 0.001 minsane 1 orphan 16 orphanwait 300
+rlimit@HAVE_RLIMIT_MEMLOCK@@HAVE_RLIMIT_STACK@
+tinker allan 1500 dispersion 15 freq 0 huffpuff 7200 panic 1000 step 0.128 stepout 900 tick 0.01
+broadcastclient
+server 127.127.1.0 mode 4294967295 prefer true
+fudge 127.127.1.0 time1 0 time2 1.1 stratum 7 refid Abcd
+pool 0.north-america.pool.ntp.org. iburst preempt
+server 1.north-america.pool.ntp.org. iburst
+server -4 2.north-america.pool.ntp.org. minpoll 6 maxpoll 10 iburst
+server -6 ntp.davehart.net. minpoll 6 maxpoll 10 version 5 burst iburst
+peer -6 davehart.broker.freenet6.net. ident "autokey-group" xleave autokey
+peer -4 192.168.192.168 key 1 noselect
+server [fe80::123%1]
+broadcast 192.168.192.255
+manycastclient 224.0.1.1
+manycastclient ff05::101
+manycastserver 224.0.1.1 ff05::101
+multicastclient 224.0.1.1 ff05::101
+mru maxage 64 mindepth 600 initalloc 600 initmem 16 incalloc 99 incmem 4 maxdepth 1024 maxmem 4096
+discard minimum 1 average 3 monitor 3000
+restrict default
+restrict default nomodify limited kod noserve nomrulist
+restrict source
+restrict source nomodify limited kod
+restrict trusted.host.name.example.com. nomodify
+restrict [fe80::1] mask [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]
+restrict 127.0.0.1 mask 255.255.255.255
+restrict ::1
+interface drop ipv6
+interface ignore ipv4
+interface drop wildcard
+interface listen eth0
+interface listen ipv6
+interface listen 192.168.192.0/24
+interface listen 192.168.193.1
+phone "ATDT13034944774" "ATDT12027621594"
+setvar varnondef = "this variable does not have default after the value"
+setvar vanity = "name plate" default
+trap 127.0.0.1 interface 127.0.0.1 port 1234
+trap 127.0.0.2
+reset allpeers auth ctl io mem sys timer
diff --git a/contrib/ntp/ntpd/declcond.h b/contrib/ntp/ntpd/declcond.h
new file mode 100644
index 0000000..870e5a7
--- /dev/null
+++ b/contrib/ntp/ntpd/declcond.h
@@ -0,0 +1,21 @@
+/*
+ * declcond.h - declarations conditionalized for ntpd
+ *
+ * The NTP reference implementation distribution includes two distinct
+ * declcond.h files, one in ntpd/ used only by ntpd, and another in
+ * include/ used by libntp and utilities. This relies on the source
+ * file's directory being ahead of include/ in the include search.
+ *
+ * The ntpd variant of declcond.h declares "debug" only #ifdef DEBUG,
+ * as the --disable-debugging version of ntpd should not reference
+ * "debug". The libntp and utilities variant always declares debug,
+ * as it is used in those codebases even without DEBUG defined.
+ */
+#ifndef DECLCOND_H
+#define DECLCOND_H
+
+#ifdef DEBUG /* uncommented in ntpd/declcond.h */
+extern int debug;
+#endif /* uncommented in ntpd/declcond.h */
+
+#endif /* DECLCOND_H */
diff --git a/contrib/ntp/ntpd/invoke-ntp.conf.menu b/contrib/ntp/ntpd/invoke-ntp.conf.menu
new file mode 100644
index 0000000..e5c6ef3
--- /dev/null
+++ b/contrib/ntp/ntpd/invoke-ntp.conf.menu
@@ -0,0 +1 @@
+* ntp.conf Notes:: Notes about ntp.conf
diff --git a/contrib/ntp/ntpd/invoke-ntp.conf.texi b/contrib/ntp/ntpd/invoke-ntp.conf.texi
new file mode 100644
index 0000000..d7a9d13
--- /dev/null
+++ b/contrib/ntp/ntpd/invoke-ntp.conf.texi
@@ -0,0 +1,2677 @@
+@node ntp.conf Notes
+@section Notes about ntp.conf
+@pindex ntp.conf
+@cindex Network Time Protocol (NTP) daemon configuration file format
+@ignore
+#
+# EDIT THIS FILE WITH CAUTION (invoke-ntp.conf.texi)
+#
+# It has been AutoGen-ed June 29, 2015 at 04:30:28 PM by AutoGen 5.18.5
+# From the definitions ntp.conf.def
+# and the template file agtexi-file.tpl
+@end ignore
+
+
+
+The
+@code{ntp.conf}
+configuration file is read at initial startup by the
+@code{ntpd(1ntpdmdoc)}
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+@file{/etc}
+directory,
+but could be installed elsewhere
+(see the daemon's
+@code{-c}
+command line option).
+
+The file format is similar to other
+@sc{unix}
+configuration files.
+Comments begin with a
+@quoteleft{}#@quoteright{}
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+
+The rest of this page describes the configuration and control options.
+The
+"Notes on Configuring NTP and Setting up an NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp})
+contains an extended discussion of these options.
+In addition to the discussion of general
+@ref{Configuration Options},
+there are sections describing the following supported functionality
+and the options used to control it:
+@itemize @bullet
+@item
+@ref{Authentication Support}
+@item
+@ref{Monitoring Support}
+@item
+@ref{Access Control Support}
+@item
+@ref{Automatic NTP Configuration Options}
+@item
+@ref{Reference Clock Support}
+@item
+@ref{Miscellaneous Options}
+@end itemize
+
+Following these is a section describing
+@ref{Miscellaneous Options}.
+While there is a rich set of options available,
+the only required option is one or more
+@code{pool},
+@code{server},
+@code{peer},
+@code{broadcast}
+or
+@code{manycastclient}
+commands.
+@node Configuration Support
+@subsection Configuration Support
+Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+@subsubsection Configuration Commands
+The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+
+If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+@quotedblleft{}:@quotedblright{}
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+
+Note that in contexts where a host name is expected, a
+@code{-4}
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+@code{-6}
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+@table @asis
+@item @code{pool} @kbd{address} @code{[@code{burst}]} @code{[@code{iburst}]} @code{[@code{version} @kbd{version}]} @code{[@code{prefer}]} @code{[@code{minpoll} @kbd{minpoll}]} @code{[@code{maxpoll} @kbd{maxpoll}]}
+@item @code{server} @kbd{address} @code{[@code{key} @kbd{key} @kbd{|} @code{autokey}]} @code{[@code{burst}]} @code{[@code{iburst}]} @code{[@code{version} @kbd{version}]} @code{[@code{prefer}]} @code{[@code{minpoll} @kbd{minpoll}]} @code{[@code{maxpoll} @kbd{maxpoll}]}
+@item @code{peer} @kbd{address} @code{[@code{key} @kbd{key} @kbd{|} @code{autokey}]} @code{[@code{version} @kbd{version}]} @code{[@code{prefer}]} @code{[@code{minpoll} @kbd{minpoll}]} @code{[@code{maxpoll} @kbd{maxpoll}]}
+@item @code{broadcast} @kbd{address} @code{[@code{key} @kbd{key} @kbd{|} @code{autokey}]} @code{[@code{version} @kbd{version}]} @code{[@code{prefer}]} @code{[@code{minpoll} @kbd{minpoll}]} @code{[@code{ttl} @kbd{ttl}]}
+@item @code{manycastclient} @kbd{address} @code{[@code{key} @kbd{key} @kbd{|} @code{autokey}]} @code{[@code{version} @kbd{version}]} @code{[@code{prefer}]} @code{[@code{minpoll} @kbd{minpoll}]} @code{[@code{maxpoll} @kbd{maxpoll}]} @code{[@code{ttl} @kbd{ttl}]}
+@end table
+
+These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+@kbd{address}
+can be
+either a DNS name or an IP address in dotted-quad notation.
+Additional information on association behavior can be found in the
+"Association Management"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+@table @asis
+@item @code{pool}
+For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+@item @code{server}
+For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+@emph{not}
+be used for type
+b or m addresses.
+@item @code{peer}
+For type s addresses (only), this command mobilizes a
+persistent symmetric-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+@item @code{broadcast}
+For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+@kbd{address}
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+@code{broadcastclient}
+or
+@code{multicastclient}
+commands
+below.
+@item @code{manycastclient}
+For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+@code{manycastserver}
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+@code{manycastserver}
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+@kbd{address}
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+@code{server}
+command.
+The remaining servers are discarded as if never
+heard.
+@end table
+
+Options:
+@table @asis
+@item @code{autokey}
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+@ref{Authentication Options}.
+@item @code{burst}
+when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+@code{server}
+command and s addresses.
+@item @code{iburst}
+When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+@code{server}
+command and s addresses and when
+@code{ntpd(1ntpdmdoc)}
+is started with the
+@code{-q}
+option.
+@item @code{key} @kbd{key}
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+@kbd{key}
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+@item @code{minpoll} @kbd{minpoll}
+@item @code{maxpoll} @kbd{maxpoll}
+These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+@code{maxpoll}
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+@code{minpoll}
+option to a lower limit of 4 (16 s).
+@item @code{noselect}
+Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+@item @code{prefer}
+Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp})
+for further information.
+@item @code{ttl} @kbd{ttl}
+This option is used only with broadcast server and manycast
+client modes.
+It specifies the time-to-live
+@kbd{ttl}
+to
+use on broadcast server and multicast server and the maximum
+@kbd{ttl}
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+@item @code{version} @kbd{version}
+Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1-4 are the choices, with version 4 the
+default.
+@end table
+@subsubsection Auxiliary Commands
+@table @asis
+@item @code{broadcastclient}
+This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric-key or public-key
+authentication as described in
+@ref{Authentication Options}.
+@item @code{manycastserver} @kbd{address} @kbd{...}
+This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric-key or public-key
+authentication as described in
+@ref{Authentication Options}.
+@item @code{multicastclient} @kbd{address} @kbd{...}
+This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric-key or
+public-key authentication as described in
+@ref{Authentication Options}.
+@item @code{mdnstries} @kbd{number}
+If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+@code{mdnstries}
+times.
+After all,
+@code{ntpd}
+may be starting before mDNS.
+The default value for
+@code{mdnstries}
+is 5.
+@end table
+@node Authentication Support
+@subsection Authentication Support
+Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed-MD5.
+Either algorithm computes a message digest, or one-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+
+NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+
+While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+
+Authentication is configured separately for each association
+using the
+@code{key}
+or
+@code{autokey}
+subcommand on the
+@code{peer},
+@code{server},
+@code{broadcast}
+and
+@code{manycastclient}
+configuration commands as described in
+@ref{Configuration Options}
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+
+Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+
+The
+@code{auth}
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+@code{enable}
+and
+@code{disable}
+commands and also by remote
+configuration commands sent by a
+@code{ntpdc(1ntpdcmdoc)}
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+@code{auth}
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+
+An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+@ref{Automatic NTP Configuration Options}
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+
+The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+@code{http://www.ntp.org/}.
+@subsubsection Symmetric-Key Cryptography
+The original RFC-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+@file{ntp.keys},
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+utility programs.
+
+When
+@code{ntpd(1ntpdmdoc)}
+is first started, it reads the key file specified in the
+@code{keys}
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+@code{trusted}
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+@code{ntpdc(1ntpdcmdoc)}.
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+@code{requestkey}
+command selects the key used as the password for the
+@code{ntpdc(1ntpdcmdoc)}
+utility, while the
+@code{controlkey}
+command selects the key used as the password for the
+@code{ntpq(1ntpqmdoc)}
+utility.
+@subsubsection Public Key Cryptography
+NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+
+The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S-KEY scheme,
+in which a pseudo-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+@ref{Autonomous Authentication}
+page.
+
+The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+@code{ntp-keygen(1ntpkeygenmdoc)}
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+@code{md5WithRSAEncryption},
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+
+NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+@subsubsection Naming and Addressing
+It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+
+By convention, the name of an Autokey host is the name returned
+by the Unix
+@code{gethostname(2)}
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+
+It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+@subsubsection Operation
+A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+
+The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+@code{server}
+or
+@code{peer}
+configuration command and no
+@code{key}
+or
+@code{autokey}
+subcommands are present, the association is not
+authenticated; if the
+@code{key}
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+@code{autokey}
+subcommand is present, the association is authenticated
+using Autokey.
+
+When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+
+Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+
+Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto-NAK, which tells her
+something broke.
+She can see the evidence using the
+@code{ntpq(1ntpqmdoc)}
+program.
+
+Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+
+It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+@subsubsection Key Management
+The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+@code{ntp-keygen(1ntpkeygenmdoc)}
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+
+Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+@code{trustRoot};.
+Other extension fields are ignored.
+@subsubsection Authentication Commands
+@table @asis
+@item @code{autokey} @code{[@kbd{logsec}]}
+Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+@item @code{controlkey} @kbd{key}
+Specifies the key identifier to use with the
+@code{ntpq(1ntpqmdoc)}
+utility, which uses the standard
+protocol defined in RFC-1305.
+The
+@kbd{key}
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+@item @code{crypto} @code{[@code{cert} @kbd{file}]} @code{[@code{leap} @kbd{file}]} @code{[@code{randfile} @kbd{file}]} @code{[@code{host} @kbd{file}]} @code{[@code{sign} @kbd{file}]} @code{[@code{gq} @kbd{file}]} @code{[@code{gqpar} @kbd{file}]} @code{[@code{iffpar} @kbd{file}]} @code{[@code{mvpar} @kbd{file}]} @code{[@code{pw} @kbd{password}]}
+This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+@code{keysdir}
+command or default
+@file{/usr/local/etc}.
+Following are the subcommands:
+@table @asis
+@item @code{cert} @kbd{file}
+Specifies the location of the required host public certificate file.
+This overrides the link
+@file{ntpkey_cert_}@kbd{hostname}
+in the keys directory.
+@item @code{gqpar} @kbd{file}
+Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+@file{ntpkey_gq_}@kbd{hostname}
+in the keys directory.
+@item @code{host} @kbd{file}
+Specifies the location of the required host key file.
+This overrides
+the link
+@file{ntpkey_key_}@kbd{hostname}
+in the keys directory.
+@item @code{iffpar} @kbd{file}
+Specifies the location of the optional IFF parameters file.This
+overrides the link
+@file{ntpkey_iff_}@kbd{hostname}
+in the keys directory.
+@item @code{leap} @kbd{file}
+Specifies the location of the optional leapsecond file.
+This overrides the link
+@file{ntpkey_leap}
+in the keys directory.
+@item @code{mvpar} @kbd{file}
+Specifies the location of the optional MV parameters file.
+This
+overrides the link
+@file{ntpkey_mv_}@kbd{hostname}
+in the keys directory.
+@item @code{pw} @kbd{password}
+Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+@item @code{randfile} @kbd{file}
+Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+@item @code{sign} @kbd{file}
+Specifies the location of the optional sign key file.
+This overrides
+the link
+@file{ntpkey_sign_}@kbd{hostname}
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+@end table
+@item @code{keys} @kbd{keyfile}
+Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+@code{ntpd(1ntpdmdoc)},
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+when operating with symmetric key cryptography.
+This is the same operation as the
+@code{-k}
+command line option.
+@item @code{keysdir} @kbd{path}
+This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+@file{/usr/local/etc/}.
+@item @code{requestkey} @kbd{key}
+Specifies the key identifier to use with the
+@code{ntpdc(1ntpdcmdoc)}
+utility program, which uses a
+proprietary protocol specific to this implementation of
+@code{ntpd(1ntpdmdoc)}.
+The
+@kbd{key}
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+@item @code{revoke} @kbd{logsec}
+Specifies the interval between re-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+@item @code{trustedkey} @kbd{key} @kbd{...}
+Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+@kbd{key}
+arguments are 32-bit unsigned
+integers with values from 1 to 65,534.
+@end table
+@subsubsection Error Codes
+The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+@table @asis
+@item 101
+(bad field format or length)
+The packet has invalid version, length or format.
+@item 102
+(bad timestamp)
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+@item 103
+(bad filestamp)
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+@item 104
+(bad or missing public key)
+The public key is missing, has incorrect format or is an unsupported type.
+@item 105
+(unsupported digest type)
+The server requires an unsupported digest/signature scheme.
+@item 106
+(mismatched digest types)
+Not used.
+@item 107
+(bad signature length)
+The signature length does not match the current public key.
+@item 108
+(signature not verified)
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+@item 109
+(certificate not verified)
+The certificate is invalid or signed with the wrong key.
+@item 110
+(certificate not verified)
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+@item 111
+(bad or missing cookie)
+The cookie is missing, corrupted or bogus.
+@item 112
+(bad or missing leapseconds table)
+The leapseconds table is missing, corrupted or bogus.
+@item 113
+(bad or missing certificate)
+The certificate is missing, corrupted or bogus.
+@item 114
+(bad or missing identity)
+The identity key is missing, corrupt or bogus.
+@end table
+@node Monitoring Support
+@subsection Monitoring Support
+@code{ntpd(1ntpdmdoc)}
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+@code{statistics}
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+@file{./scripts}
+directory of this distribution.
+Using
+these facilities and
+@sc{unix}
+@code{cron(8)}
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+@subsubsection Monitoring Commands
+@table @asis
+@item @code{statistics} @kbd{name} @kbd{...}
+Enables writing of statistics records.
+Currently, eight kinds of
+@kbd{name}
+statistics are supported.
+@table @asis
+@item @code{clockstats}
+Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+@code{clockstats}:
+@verbatim
+49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+@end verbatim
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+@item @code{cryptostats}
+This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+@code{cryptostats}:
+@verbatim
+49213 525.624 127.127.4.1 message
+@end verbatim
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+@ref{Authentication Options}
+section for further information.
+@item @code{loopstats}
+Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+@code{loopstats}:
+@verbatim
+50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+@end verbatim
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million -
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+@item @code{peerstats}
+Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+@code{peerstats}:
+@verbatim
+48773 10847.650 127.127.4.1 9714 -0.001605376 0.000000000 0.001424877 0.000958674
+@end verbatim
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+@item @code{rawstats}
+Enables recording of raw-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+@code{rawstats}:
+@verbatim
+50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+@end verbatim
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+@item @code{sysstats}
+Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+@code{sysstats}:
+@verbatim
+50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+@end verbatim
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+@table @asis
+@item Time since restart @code{36000}
+Time in hours since the system was last rebooted.
+@item Packets received @code{81965}
+Total number of packets received.
+@item Packets processed @code{0}
+Number of packets received in response to previous packets sent
+@item Current version @code{9546}
+Number of packets matching the current NTP version.
+@item Previous version @code{56}
+Number of packets matching the previous NTP version.
+@item Bad version @code{71793}
+Number of packets matching neither NTP version.
+@item Access denied @code{512}
+Number of packets denied access for any reason.
+@item Bad length or format @code{540}
+Number of packets with invalid length, format or port number.
+@item Bad authentication @code{10}
+Number of packets not verified as authentic.
+@item Rate exceeded @code{147}
+Number of packets discarded due to rate limitation.
+@end table
+@item @code{statsdir} @kbd{directory_path}
+Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+@code{filegen}
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+@item @code{filegen} @kbd{name} @code{[@code{file} @kbd{filename}]} @code{[@code{type} @kbd{typename}]} @code{[@code{link} | @code{nolink}]} @code{[@code{enable} | @code{disable}]}
+Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+
+Note that this command can be sent from the
+@code{ntpdc(1ntpdcmdoc)}
+program running at a remote location.
+@table @asis
+@item @code{name}
+This is the type of the statistics records, as shown in the
+@code{statistics}
+command.
+@item @code{file} @kbd{filename}
+This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+@code{prefix},
+@code{filename}
+and
+@code{suffix}:
+@table @asis
+@item @code{prefix}
+This is a constant filename path.
+It is not subject to
+modifications via the
+@kbd{filegen}
+option.
+It is defined by the
+server, usually specified as a compile-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+@kbd{loopstats}
+and
+@kbd{peerstats}
+generation can be configured using the
+@kbd{statsdir}
+option explained above.
+@item @code{filename}
+This string is directly concatenated to the prefix mentioned
+above (no intervening
+@quoteleft{}/@quoteright{}).
+This can be modified using
+the file argument to the
+@kbd{filegen}
+statement.
+No
+@file{..}
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+@kbd{prefix}.
+@item @code{suffix}
+This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+@end table
+@item @code{type} @kbd{typename}
+A file generation set is characterized by its type.
+The following
+types are supported:
+@table @asis
+@item @code{none}
+The file set is actually a single plain file.
+@item @code{pid}
+One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+@code{ntpd(1ntpdmdoc)}
+server incarnations.
+The set member filename is built by appending a
+@quoteleft{}.@quoteright{}
+to concatenated
+@kbd{prefix}
+and
+@kbd{filename}
+strings, and
+appending the decimal representation of the process ID of the
+@code{ntpd(1ntpdmdoc)}
+server process.
+@item @code{day}
+One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+@quoteleft{}.@quoteright{}
+and a day specification in
+the form
+@code{YYYYMMdd}.
+@code{YYYY}
+is a 4-digit year number (e.g., 1992).
+@code{MM}
+is a two digit month number.
+@code{dd}
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+@kbd{prefix}
+@kbd{filename}.19921210.
+@item @code{week}
+Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day-of-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4-digit year number, the letter
+@code{W},
+and a 2-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.No . Ns Ar 1992W1 .
+@item @code{month}
+One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4-digit year number, and
+a 2-digit month.
+@item @code{year}
+One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+@item @code{age}
+This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+@code{a},
+and an 8-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24-hour period.
+Information is only written to a file generation by specifying
+@code{enable};
+output is prevented by specifying
+@code{disable}.
+@end table
+@item @code{link} | @code{nolink}
+It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+@code{link}
+and disabled using
+@code{nolink}.
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+@code{C},
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+@item @code{enable} @code{|} @code{disable}
+Enables or disables the recording function.
+@end table
+@end table
+@end table
+@node Access Control Support
+@subsection Access Control Support
+The
+@code{ntpd(1ntpdmdoc)}
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+"Notes on Configuring NTP and Setting up a NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+
+The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+
+Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+@subsubsection The Kiss-of-Death Packet
+Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss-of-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four-byte
+ASCII code.
+If the
+@code{noserve}
+or
+@code{notrust}
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+@code{limited}
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+
+A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+@subsubsection Access Control Commands
+@table @asis
+@item @code{discard} @code{[@code{average} @kbd{avg}]} @code{[@code{minimum} @kbd{min}]} @code{[@code{monitor} @kbd{prob}]}
+Set the parameters of the
+@code{limited}
+facility which protects the server from
+client abuse.
+The
+@code{average}
+subcommand specifies the minimum average packet
+spacing, while the
+@code{minimum}
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss-o'-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate-control window.
+@item @code{restrict} @code{address} @code{[@code{mask} @kbd{mask}]} @code{[@kbd{flag} @kbd{...}]}
+The
+@kbd{address}
+argument expressed in
+dotted-quad form is the address of a host or network.
+Alternatively, the
+@kbd{address}
+argument can be a valid host DNS name.
+The
+@kbd{mask}
+argument expressed in dotted-quad form defaults to
+@code{255.255.255.255},
+meaning that the
+@kbd{address}
+is treated as the address of an individual host.
+A default entry (address
+@code{0.0.0.0},
+mask
+@code{0.0.0.0})
+is always included and is always the first entry in the list.
+Note that text string
+@code{default},
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+@code{flag}
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+@table @asis
+@item @code{ignore}
+Deny packets of all kinds, including
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+queries.
+@item @code{kod}
+If this flag is set when an access violation occurs, a kiss-o'-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+@item @code{limited}
+Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+@code{ntpd(1ntpdmdoc)}.
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+@code{limited}
+flag.
+@item @code{lowpriotrap}
+Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+@item @code{nomodify}
+Deny
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+@item @code{noquery}
+Deny
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+queries.
+Time service is not affected.
+@item @code{nopeer}
+Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+@code{pool}
+associations, so if you want to use servers from a
+@code{pool}
+directive and also want to use
+@code{nopeer}
+by default, you'll want a
+@code{restrict source ...} @code{line} @code{as} @code{well} @code{that} @code{does}
+@item not
+include the
+@code{nopeer}
+directive.
+@item @code{noserve}
+Deny all packets except
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+queries.
+@item @code{notrap}
+Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+@item @code{notrust}
+Deny service unless the packet is cryptographically authenticated.
+@item @code{ntpport}
+This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+@code{ntpport}
+and
+@code{non-ntpport}
+may
+be specified.
+The
+@code{ntpport}
+is considered more specific and
+is sorted later in the list.
+@item @code{version}
+Deny packets that do not match the current NTP version.
+@end table
+
+Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+@end table
+@node Automatic NTP Configuration Options
+@subsection Automatic NTP Configuration Options
+@subsubsection Manycasting
+Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+
+Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+
+Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+@code{http://www.openssl.org/}.
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+
+A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+@code{D}
+or IPv6 prefix
+@code{FF})
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time-to-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+
+Manycast servers configured with the
+@code{manycastserver}
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+
+The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+
+The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+@code{manycastclient},
+@code{tos}
+and
+@code{ttl}
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+@code{minpoll}
+value specified in the
+@code{manycastclient},
+command and, under normal circumstances, increments to the
+@code{maxpolll}
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+
+The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+@code{minclock}
+and
+@code{minsane}
+values specified in the
+@code{tos}
+configuration command.
+At least
+@code{minsane}
+candidate servers must be available and the mitigation
+algorithms produce at least
+@code{minclock}
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+@code{minsane}
+defaults to 1 and
+@code{minclock}
+defaults to 3.
+For manycast service
+@code{minsane}
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+
+If at least
+@code{minclock}
+servers are found, the manycast poll interval is immediately
+set to eight times
+@code{maxpoll}.
+If less than
+@code{minclock}
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+@code{maxpoll}.
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+
+Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+@code{ttl}
+configuration command can be
+used to modify the values to match the scope rules.
+
+It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+@code{tos}
+command can be used to modify this behavior.
+Servers with stratum below
+@code{floor}
+or above
+@code{ceiling}
+specified in the
+@code{tos}
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+@code{minclock}.
+
+The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+@code{minclock},
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+@code{maxpoll}
+is 12 (4,096 s).
+
+It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+@code{multicastclient}
+and
+@code{multicastserver}
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+
+The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+@code{tos}
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+@code{floor}
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+
+Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re-associate accordingly.
+
+Some administrators prefer to avoid running
+@code{ntpd(1ntpdmdoc)}
+continuously and run either
+@code{ntpdate(8)}
+or
+@code{ntpd(1ntpdmdoc)}
+@code{-q}
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+@code{ntpd(1ntpdmdoc)}
+@code{-q}.
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+@subsubsection Manycast Interactions with Autokey
+Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+
+About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+@subsubsection Manycast Options
+@table @asis
+@item @code{tos} @code{[@code{ceiling} @kbd{ceiling} | @code{cohort} @code{@{} @code{0} | @code{1} @code{@}} | @code{floor} @kbd{floor} | @code{minclock} @kbd{minclock} | @code{minsane} @kbd{minsane}]}
+This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+@table @asis
+@item @code{ceiling} @kbd{ceiling}
+Peers with strata above
+@code{ceiling}
+will be discarded if there are at least
+@code{minclock}
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+@item @code{cohort} @code{@{0 | 1@}}
+This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+@item @code{floor} @kbd{floor}
+Peers with strata below
+@code{floor}
+will be discarded if there are at least
+@code{minclock}
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+@item @code{minclock} @kbd{minclock}
+The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+@code{minclock}
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+@item @code{minsane} @kbd{minsane}
+This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+@code{minsane}
+should be at least 4 in order to detect and discard
+a single falseticker.
+@end table
+@item @code{ttl} @kbd{hop} @kbd{...}
+This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding-ring search.
+The default is eight
+multiples of 32 starting at 31.
+@end table
+@node Reference Clock Support
+@subsection Reference Clock Support
+The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+Additional information can be found in the pages linked
+there, including the
+"Debugging Hints for Reference Clock Drivers"
+and
+"How To Write a Reference Clock Driver"
+pages
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+In addition, support for a PPS
+signal is available as described in the
+"Pulse-per-second (PPS) Signal Interfacing"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+"Line Disciplines and Streams Drivers"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+
+A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+
+For the purposes of configuration,
+@code{ntpd(1ntpdmdoc)}
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+@code{127.127.}@kbd{t}.@kbd{u},
+where
+@kbd{t}
+is an integer
+denoting the clock type and
+@kbd{u}
+indicates the unit
+number in the range 0-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+
+The
+@code{server}
+command is used to configure a reference
+clock, where the
+@kbd{address}
+argument in that command
+is the clock address.
+The
+@code{key},
+@code{version}
+and
+@code{ttl}
+options are not used for reference clock support.
+The
+@code{mode}
+option is added for reference clock support, as
+described below.
+The
+@code{prefer}
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+"Mitigation Rules and the prefer Keyword"
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp})
+page.
+The
+@code{minpoll}
+and
+@code{maxpoll}
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+
+The
+@code{fudge}
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+@code{server}
+command.
+The
+@kbd{address}
+argument specifies the clock address.
+The
+@code{refid}
+and
+@code{stratum}
+options can be used to
+override the defaults for the device.
+There are two optional
+device-dependent time offsets and four flags that can be included
+in the
+@code{fudge}
+command as well.
+
+The stratum number of a reference clock is by default zero.
+Since the
+@code{ntpd(1ntpdmdoc)}
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+@code{stratum}
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse-per-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+@code{refid}
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+@subsubsection Reference Clock Commands
+@table @asis
+@item @code{server} @code{127.127.}@kbd{t}.@kbd{u} @code{[@code{prefer}]} @code{[@code{mode} @kbd{int}]} @code{[@code{minpoll} @kbd{int}]} @code{[@code{maxpoll} @kbd{int}]}
+This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+@table @asis
+@item @code{prefer}
+Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp})
+for further information.
+@item @code{mode} @kbd{int}
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+@item @code{minpoll} @kbd{int}
+@item @code{maxpoll} @kbd{int}
+These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+@code{minpoll}
+and
+@code{maxpoll}
+default to 6 (64 s).
+For modem reference clocks,
+@code{minpoll}
+defaults to 10 (17.1 m) and
+@code{maxpoll}
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+@end table
+@item @code{fudge} @code{127.127.}@kbd{t}.@kbd{u} @code{[@code{time1} @kbd{sec}]} @code{[@code{time2} @kbd{sec}]} @code{[@code{stratum} @kbd{int}]} @code{[@code{refid} @kbd{string}]} @code{[@code{mode} @kbd{int}]} @code{[@code{flag1} @code{0} @code{|} @code{1}]} @code{[@code{flag2} @code{0} @code{|} @code{1}]} @code{[@code{flag3} @code{0} @code{|} @code{1}]} @code{[@code{flag4} @code{0} @code{|} @code{1}]}
+This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+@code{server}
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+@code{ntpdc(1ntpdcmdoc)}
+program.
+The options are interpreted as
+follows:
+@table @asis
+@item @code{time1} @kbd{sec}
+Specifies a constant to be added to the time offset produced by
+the driver, a fixed-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+@code{enable}
+command described in
+@ref{Miscellaneous Options}
+page and operates as described in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+@item @code{time2} @kbd{secs}
+Specifies a fixed-point decimal number in seconds, which is
+interpreted in a driver-dependent way.
+See the descriptions of
+specific drivers in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+@file{/usr/share/doc/ntp}).
+@item @code{stratum} @kbd{int}
+Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+@item @code{refid} @kbd{string}
+Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+@item @code{mode} @kbd{int}
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+@item @code{flag1} @code{0} @code{|} @code{1}
+@item @code{flag2} @code{0} @code{|} @code{1}
+@item @code{flag3} @code{0} @code{|} @code{1}
+@item @code{flag4} @code{0} @code{|} @code{1}
+These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+@code{flag4}
+is used to enable recording monitoring
+data to the
+@code{clockstats}
+file configured with the
+@code{filegen}
+command.
+Further information on the
+@code{filegen}
+command can be found in
+@ref{Monitoring Options}.
+@end table
+@end table
+@node Miscellaneous Options
+@subsection Miscellaneous Options
+@table @asis
+@item @code{broadcastdelay} @kbd{seconds}
+The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+@item @code{calldelay} @kbd{delay}
+This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+@item @code{driftfile} @kbd{driftfile}
+This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+@code{-f}
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+
+The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts-per-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+@code{ntpd(1ntpdmdoc)}
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+@item @code{dscp} @kbd{value}
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6-bit code. The default value is 46, signifying Expedited Forwarding.
+@item @code{enable} @code{[@code{auth} | @code{bclient} | @code{calibrate} | @code{kernel} | @code{mode7} | @code{monitor} | @code{ntp} | @code{stats}]}
+@item @code{disable} @code{[@code{auth} | @code{bclient} | @code{calibrate} | @code{kernel} | @code{mode7} | @code{monitor} | @code{ntp} | @code{stats}]}
+Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+@code{ntpdc(1ntpdcmdoc)}
+utility program.
+@table @asis
+@item @code{auth}
+Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+@code{enable}.
+@item @code{bclient}
+Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+@code{multicastclient}
+command with default
+address.
+The default for this flag is
+@code{disable}.
+@item @code{calibrate}
+Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+@code{disable}.
+@item @code{kernel}
+Enables the kernel time discipline, if available.
+The default for this
+flag is
+@code{enable}
+if support is available, otherwise
+@code{disable}.
+@item @code{mode7}
+Enables processing of NTP mode 7 implementation-specific requests
+which are used by the deprecated
+@code{ntpdc(1ntpdcmdoc)}
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+@code{ntpq(1ntpqmdoc)}.
+The
+@code{ntpq(1ntpqmdoc)}
+program provides the same capabilities as
+@code{ntpdc(1ntpdcmdoc)}
+using standard mode 6 requests.
+@item @code{monitor}
+Enables the monitoring facility.
+See the
+@code{ntpdc(1ntpdcmdoc)}
+program
+and the
+@code{monlist}
+command or further information.
+The
+default for this flag is
+@code{enable}.
+@item @code{ntp}
+Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+@code{enable}.
+@item @code{stats}
+Enables the statistics facility.
+See the
+@ref{Monitoring Options}
+section for further information.
+The default for this flag is
+@code{disable}.
+@end table
+@item @code{includefile} @kbd{includefile}
+This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+@code{ntpd(1ntpdmdoc)}
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+@item @code{leapsmearinterval} @kbd{seconds}
+This EXPERIMENTAL option is only available if
+@code{ntpd(1ntpdmdoc)}
+was built with the
+@code{--enable-leap-smear}
+option to the
+@code{configure}
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+@item @code{logconfig} @kbd{configkeyword}
+This command controls the amount and type of output written to
+the system
+@code{syslog(3)}
+facility or the alternate
+@code{logfile}
+log file.
+By default, all output is turned on.
+All
+@kbd{configkeyword}
+keywords can be prefixed with
+@quoteleft{}=@quoteright{},
+@quoteleft{}+@quoteright{}
+and
+@quoteleft{}-@quoteright{},
+where
+@quoteleft{}=@quoteright{}
+sets the
+@code{syslog(3)}
+priority mask,
+@quoteleft{}+@quoteright{}
+adds and
+@quoteleft{}-@quoteright{}
+removes
+messages.
+@code{syslog(3)}
+messages can be controlled in four
+classes
+(@code{clock}, @code{peer}, @code{sys} and @code{sync}).
+Within these classes four types of messages can be
+controlled: informational messages
+(@code{info}),
+event messages
+(@code{events}),
+statistics messages
+(@code{statistics})
+and
+status messages
+(@code{status}).
+
+Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+@code{all}
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+@code{all}
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+@verbatim
+logconfig =syncstatus +sysevents
+@end verbatim
+
+This would just list the synchronizations state of
+@code{ntpd(1ntpdmdoc)}
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+@verbatim
+logconfig =syncall +clockall
+@end verbatim
+
+This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+@item @code{logfile} @kbd{logfile}
+This command specifies the location of an alternate log file to
+be used instead of the default system
+@code{syslog(3)}
+facility.
+This is the same operation as the -l command line option.
+@item @code{setvar} @kbd{variable} @code{[@code{default}]}
+This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+@code{name}@code{=}@kbd{value}
+is followed by the
+@code{default}
+keyword, the
+variable will be listed as part of the default system variables
+(@code{rv} command)).
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+@code{setvar}
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+@code{sys_var_list}
+holds
+the names of all system variables.
+The
+@code{peer_var_list}
+holds
+the names of all peer variables and the
+@code{clock_var_list}
+holds the names of the reference clock variables.
+@item @code{tinker} @code{[@code{allan} @kbd{allan} | @code{dispersion} @kbd{dispersion} | @code{freq} @kbd{freq} | @code{huffpuff} @kbd{huffpuff} | @code{panic} @kbd{panic} | @code{step} @kbd{step} | @code{stepback} @kbd{stepback} | @code{stepfwd} @kbd{stepfwd} | @code{stepout} @kbd{stepout}]}
+This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+
+The variables operate as follows:
+@table @asis
+@item @code{allan} @kbd{allan}
+The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+@item @code{dispersion} @kbd{dispersion}
+The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+@item @code{freq} @kbd{freq}
+The argument becomes the initial value of the frequency offset in
+parts-per-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+@item @code{huffpuff} @kbd{huffpuff}
+The argument becomes the new value for the experimental
+huff-n'-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+@item @code{panic} @kbd{panic}
+The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+@item @code{step} @kbd{step}
+The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+@item @code{stepback} @kbd{stepback}
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+@item @code{stepfwd} @kbd{stepfwd}
+As for stepback, but for the forward direction.
+@item @code{stepout} @kbd{stepout}
+The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+@end table
+@item @code{rlimit} @code{[@code{memlock} @kbd{Nmegabytes} | @code{stacksize} @kbd{N4kPages} @code{filenum} @kbd{Nfiledescriptors}]}
+@table @asis
+@item @code{memlock} @kbd{Nmegabytes}
+Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+@code{-i}
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+@item @code{stacksize} @kbd{N4kPages}
+Specifies the maximum size of the process stack on systems with the
+@code{mlockall()}
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+@item @code{filenum} @kbd{Nfiledescriptors}
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+@end table
+@item @code{trap} @kbd{host_address} @code{[@code{port} @kbd{port_number}]} @code{[@code{interface} @kbd{interface_address}]}
+This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+
+The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+@item @code{hop} @kbd{...}
+This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding-ring search.
+The default is eight multiples of 32 starting at
+31.
+@end table
+
+This section was generated by @strong{AutoGen},
+using the @code{agtexi-cmd} template and the option descriptions for the @code{ntp.conf} program.
+This software is released under the NTP license, <http://ntp.org/license>.
+
+@menu
+* ntp.conf Files:: Files
+* ntp.conf See Also:: See Also
+* ntp.conf Bugs:: Bugs
+* ntp.conf Notes:: Notes
+@end menu
+
+@node ntp.conf Files
+@subsection ntp.conf Files
+@table @asis
+@item @file{/etc/ntp.conf}
+the default name of the configuration file
+@item @file{ntp.keys}
+private MD5 keys
+@item @file{ntpkey}
+RSA private key
+@item @file{ntpkey_}@kbd{host}
+RSA public key
+@item @file{ntp_dh}
+Diffie-Hellman agreement parameters
+@end table
+@node ntp.conf See Also
+@subsection ntp.conf See Also
+@code{ntpd(1ntpdmdoc)},
+@code{ntpdc(1ntpdcmdoc)},
+@code{ntpq(1ntpqmdoc)}
+
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+@code{http://www.ntp.org/}.
+A snapshot of this documentation is available in HTML format in
+@file{/usr/share/doc/ntp}.
+@*
+
+@*
+David L. Mills, @emph{Network Time Protocol (Version 4)}, RFC5905
+@node ntp.conf Bugs
+@subsection ntp.conf Bugs
+The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+
+The
+@file{ntpkey_}@kbd{host}
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+@node ntp.conf Notes
+@subsection ntp.conf Notes
+This document was derived from FreeBSD.
diff --git a/contrib/ntp/ntpd/invoke-ntp.keys.menu b/contrib/ntp/ntpd/invoke-ntp.keys.menu
new file mode 100644
index 0000000..2185e4b
--- /dev/null
+++ b/contrib/ntp/ntpd/invoke-ntp.keys.menu
@@ -0,0 +1 @@
+* ntp.keys Notes:: Notes about ntp.keys
diff --git a/contrib/ntp/ntpd/invoke-ntp.keys.texi b/contrib/ntp/ntpd/invoke-ntp.keys.texi
new file mode 100644
index 0000000..622c4ff
--- /dev/null
+++ b/contrib/ntp/ntpd/invoke-ntp.keys.texi
@@ -0,0 +1,125 @@
+@node ntp.keys Notes
+@section Notes about ntp.keys
+@pindex ntp.keys
+@cindex NTP symmetric key file format
+@ignore
+#
+# EDIT THIS FILE WITH CAUTION (invoke-ntp.keys.texi)
+#
+# It has been AutoGen-ed June 29, 2015 at 04:30:31 PM by AutoGen 5.18.5
+# From the definitions ntp.keys.def
+# and the template file agtexi-file.tpl
+@end ignore
+
+
+
+This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+"Authentication Support"
+section of the
+@code{ntp.conf(5)}
+page.
+
+@code{ntpd(8)}
+reads its keys from a file specified using the
+@code{-k}
+command line option or the
+@code{keys}
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+
+The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+
+@example
+@kbd{keyno} @kbd{type} @kbd{key}
+@end example
+
+where
+@kbd{keyno}
+is a positive integer (between 1 and 65534),
+@kbd{type}
+is the message digest algorithm,
+and
+@kbd{key}
+is the key itself.
+
+The
+@kbd{key}
+may be given in a format
+controlled by the
+@kbd{type}
+field.
+The
+@kbd{type}
+@code{MD5}
+is always supported.
+If
+@code{ntpd}
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140-2 is required the
+@kbd{type}
+must be either
+@code{SHA}
+or
+@code{SHA1}.
+
+What follows are some key types, and corresponding formats:
+
+@table @asis
+@item @code{MD5}
+The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+@code{#}
+(which is the "start of comment" character).
+
+@item @code{SHA}
+@item @code{SHA1}
+@item @code{RMD160}
+The key is a hex-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+@end table
+
+Note that the keys used by the
+@code{ntpq(8)}
+and
+@code{ntpdc(8)}
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+
+This section was generated by @strong{AutoGen},
+using the @code{agtexi-cmd} template and the option descriptions for the @code{ntp.keys} program.
+This software is released under the NTP license, <http://ntp.org/license>.
+
+@menu
+* ntp.keys Files:: Files
+* ntp.keys See Also:: See Also
+* ntp.keys Notes:: Notes
+@end menu
+
+@node ntp.keys Files
+@subsection ntp.keys Files
+@table @asis
+@item @file{/etc/ntp.keys}
+the default name of the configuration file
+@end table
+@node ntp.keys See Also
+@subsection ntp.keys See Also
+@code{ntp.conf(5)},
+@code{ntpd(1ntpdmdoc)},
+@code{ntpdate(1ntpdatemdoc)},
+@code{ntpdc(1ntpdcmdoc)},
+@code{sntp(1sntpmdoc)}
+@node ntp.keys Notes
+@subsection ntp.keys Notes
+This document was derived from FreeBSD.
diff --git a/contrib/ntp/ntpd/ntpd-opts.menu b/contrib/ntp/ntpd/invoke-ntpd.menu
index 3425d82..3425d82 100644
--- a/contrib/ntp/ntpd/ntpd-opts.menu
+++ b/contrib/ntp/ntpd/invoke-ntpd.menu
diff --git a/contrib/ntp/ntpd/invoke-ntpd.texi b/contrib/ntp/ntpd/invoke-ntpd.texi
new file mode 100644
index 0000000..6936dda
--- /dev/null
+++ b/contrib/ntp/ntpd/invoke-ntpd.texi
@@ -0,0 +1,719 @@
+@node ntpd Invocation
+@section Invoking ntpd
+@pindex ntpd
+@cindex NTP daemon program
+@ignore
+#
+# EDIT THIS FILE WITH CAUTION (invoke-ntpd.texi)
+#
+# It has been AutoGen-ed June 29, 2015 at 04:30:33 PM by AutoGen 5.18.5
+# From the definitions ntpd-opts.def
+# and the template file agtexi-cmd.tpl
+@end ignore
+
+
+
+The
+@code{ntpd}
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC-5905,
+but also retains compatibility with
+version 3, as defined by RFC-1305, and versions 1
+and 2, as defined by RFC-1059 and RFC-1119, respectively.
+
+The
+@code{ntpd}
+utility does most computations in 64-bit floating point
+arithmetic and does relatively clumsy 64-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+
+Ordinarily,
+@code{ntpd}
+reads the
+@code{ntp.conf(5)}
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+
+If NetInfo support is built into
+@code{ntpd}
+then
+@code{ntpd}
+will attempt to read its configuration from the
+NetInfo if the default
+@code{ntp.conf(5)}
+file cannot be read and no file is
+specified by the
+@code{-c}
+option.
+
+Various internal
+@code{ntpd}
+variables can be displayed and
+configuration options altered while the
+@code{ntpd}
+is running
+using the
+@code{ntpq(1ntpqmdoc)}
+and
+@code{ntpdc(1ntpdcmdoc)}
+utility programs.
+
+When
+@code{ntpd}
+starts it looks at the value of
+@code{umask(2)},
+and if zero
+@code{ntpd}
+will set the
+@code{umask(2)}
+to 022.
+
+This section was generated by @strong{AutoGen},
+using the @code{agtexi-cmd} template and the option descriptions for the @code{ntpd} program.
+This software is released under the NTP license, <http://ntp.org/license>.
+
+@menu
+* ntpd usage:: ntpd help/usage (@option{--help})
+* ntpd ipv4:: ipv4 option (-4)
+* ntpd ipv6:: ipv6 option (-6)
+* ntpd authreq:: authreq option (-a)
+* ntpd authnoreq:: authnoreq option (-A)
+* ntpd configfile:: configfile option (-c)
+* ntpd driftfile:: driftfile option (-f)
+* ntpd panicgate:: panicgate option (-g)
+* ntpd force-step-once:: force-step-once option (-G)
+* ntpd jaildir:: jaildir option (-i)
+* ntpd interface:: interface option (-I)
+* ntpd keyfile:: keyfile option (-k)
+* ntpd logfile:: logfile option (-l)
+* ntpd novirtualips:: novirtualips option (-L)
+* ntpd modifymmtimer:: modifymmtimer option (-M)
+* ntpd nice:: nice option (-N)
+* ntpd pidfile:: pidfile option (-p)
+* ntpd priority:: priority option (-P)
+* ntpd quit:: quit option (-q)
+* ntpd propagationdelay:: propagationdelay option (-r)
+* ntpd saveconfigquit:: saveconfigquit option
+* ntpd statsdir:: statsdir option (-s)
+* ntpd trustedkey:: trustedkey option (-t)
+* ntpd user:: user option (-u)
+* ntpd updateinterval:: updateinterval option (-U)
+* ntpd wait-sync:: wait-sync option (-w)
+* ntpd slew:: slew option (-x)
+* ntpd usepcc:: usepcc option
+* ntpd pccfreq:: pccfreq option
+* ntpd mdns:: mdns option (-m)
+* ntpd config:: presetting/configuring ntpd
+* ntpd exit status:: exit status
+* ntpd Usage:: Usage
+* ntpd Files:: Files
+* ntpd See Also:: See Also
+* ntpd Bugs:: Bugs
+* ntpd Notes:: Notes
+@end menu
+
+@node ntpd usage
+@subsection ntpd help/usage (@option{--help})
+@cindex ntpd help
+
+This is the automatically generated usage text for ntpd.
+
+The text printed is the same whether selected with the @code{help} option
+(@option{--help}) or the @code{more-help} option (@option{--more-help}). @code{more-help} will print
+the usage text by passing it through a pager program.
+@code{more-help} is disabled on platforms without a working
+@code{fork(2)} function. The @code{PAGER} environment variable is
+used to select the program, defaulting to @file{more}. Both will exit
+with a status code of 0.
+
+@exampleindent 0
+@example
+ntpd - NTP daemon program - Ver. 4.2.8p3
+Usage: ntpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... \
+ [ <server1> ... <serverN> ]
+ Flg Arg Option-Name Description
+ -4 no ipv4 Force IPv4 DNS name resolution
+ - prohibits the option 'ipv6'
+ -6 no ipv6 Force IPv6 DNS name resolution
+ - prohibits the option 'ipv4'
+ -a no authreq Require crypto authentication
+ - prohibits the option 'authnoreq'
+ -A no authnoreq Do not require crypto authentication
+ - prohibits the option 'authreq'
+ -b no bcastsync Allow us to sync to broadcast servers
+ -c Str configfile configuration file name
+ -d no debug-level Increase debug verbosity level
+ - may appear multiple times
+ -D Num set-debug-level Set the debug verbosity level
+ - may appear multiple times
+ -f Str driftfile frequency drift file name
+ -g no panicgate Allow the first adjustment to be Big
+ - may appear multiple times
+ -G no force-step-once Step any initial offset correction.
+ -i Str jaildir Jail directory
+ -I Str interface Listen on an interface name or address
+ - may appear multiple times
+ -k Str keyfile path to symmetric keys
+ -l Str logfile path to the log file
+ -L no novirtualips Do not listen to virtual interfaces
+ -n no nofork Do not fork
+ - prohibits the option 'wait-sync'
+ -N no nice Run at high priority
+ -p Str pidfile path to the PID file
+ -P Num priority Process priority
+ -q no quit Set the time and quit
+ - prohibits these options:
+ saveconfigquit
+ wait-sync
+ -r Str propagationdelay Broadcast/propagation delay
+ Str saveconfigquit Save parsed configuration and quit
+ - prohibits these options:
+ quit
+ wait-sync
+ -s Str statsdir Statistics file location
+ -t Str trustedkey Trusted key number
+ - may appear multiple times
+ -u Str user Run as userid (or userid:groupid)
+ -U Num updateinterval interval in seconds between scans for new or dropped interfaces
+ Str var make ARG an ntp variable (RW)
+ - may appear multiple times
+ Str dvar make ARG an ntp variable (RW|DEF)
+ - may appear multiple times
+ -w Num wait-sync Seconds to wait for first clock sync
+ - prohibits these options:
+ nofork
+ quit
+ saveconfigquit
+ -x no slew Slew up to 600 seconds
+ opt version output version information and exit
+ -? no help display extended usage information and exit
+ -! no more-help extended usage information passed thru pager
+
+Options are specified by doubled hyphens and their name or by a single
+hyphen and the flag character.
+
+
+The following option preset mechanisms are supported:
+ - examining environment variables named NTPD_*
+
+Please send bug reports to: <http://bugs.ntp.org, bugs@@ntp.org>
+@end example
+@exampleindent 4
+
+@node ntpd ipv4
+@subsection ipv4 option (-4)
+@cindex ntpd-ipv4
+
+This is the ``force ipv4 dns name resolution'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must not appear in combination with any of the following options:
+ipv6.
+@end itemize
+
+Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+@node ntpd ipv6
+@subsection ipv6 option (-6)
+@cindex ntpd-ipv6
+
+This is the ``force ipv6 dns name resolution'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must not appear in combination with any of the following options:
+ipv4.
+@end itemize
+
+Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+@node ntpd authreq
+@subsection authreq option (-a)
+@cindex ntpd-authreq
+
+This is the ``require crypto authentication'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must not appear in combination with any of the following options:
+authnoreq.
+@end itemize
+
+Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+@node ntpd authnoreq
+@subsection authnoreq option (-A)
+@cindex ntpd-authnoreq
+
+This is the ``do not require crypto authentication'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must not appear in combination with any of the following options:
+authreq.
+@end itemize
+
+Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+@node ntpd configfile
+@subsection configfile option (-c)
+@cindex ntpd-configfile
+
+This is the ``configuration file name'' option.
+This option takes a string argument.
+The name and path of the configuration file,
+@file{/etc/ntp.conf}
+by default.
+@node ntpd driftfile
+@subsection driftfile option (-f)
+@cindex ntpd-driftfile
+
+This is the ``frequency drift file name'' option.
+This option takes a string argument.
+The name and path of the frequency file,
+@file{/etc/ntp.drift}
+by default.
+This is the same operation as the
+@code{driftfile} @kbd{driftfile}
+configuration specification in the
+@file{/etc/ntp.conf}
+file.
+@node ntpd panicgate
+@subsection panicgate option (-g)
+@cindex ntpd-panicgate
+
+This is the ``allow the first adjustment to be big'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+may appear an unlimited number of times.
+@end itemize
+
+Normally,
+@code{ntpd}
+exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
+@code{ntpd}
+will exit with a message to the system log. This option can be used with the
+@code{-q}
+and
+@code{-x}
+options.
+See the
+@code{tinker}
+configuration file directive for other options.
+@node ntpd force-step-once
+@subsection force-step-once option (-G)
+@cindex ntpd-force-step-once
+
+This is the ``step any initial offset correction.'' option.
+Normally,
+@code{ntpd}
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the @code{tinker} configuration file directive for other options.
+@node ntpd jaildir
+@subsection jaildir option (-i)
+@cindex ntpd-jaildir
+
+This is the ``jail directory'' option.
+This option takes a string argument.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{HAVE_DROPROOT} during the compilation.
+@end itemize
+
+Chroot the server to the directory
+@kbd{jaildir}
+.
+This option also implies that the server attempts to drop root privileges at startup.
+You may need to also specify a
+@code{-u}
+option.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+@code{--enable-clockctl}) or Linux (configure with
+@code{--enable-linuxcaps}) or Solaris (configure with @code{--enable-solarisprivs}).
+@node ntpd interface
+@subsection interface option (-I)
+@cindex ntpd-interface
+
+This is the ``listen on an interface name or address'' option.
+This option takes a string argument @file{iface}.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+may appear an unlimited number of times.
+@end itemize
+
+Open the network address given, or all the addresses associated with the
+given interface name. This option may appear multiple times. This option
+also implies not opening other addresses, except wildcard and localhost.
+This option is deprecated. Please consider using the configuration file
+@code{interface} command, which is more versatile.
+@node ntpd keyfile
+@subsection keyfile option (-k)
+@cindex ntpd-keyfile
+
+This is the ``path to symmetric keys'' option.
+This option takes a string argument.
+Specify the name and path of the symmetric key file.
+@file{/etc/ntp.keys}
+is the default.
+This is the same operation as the
+@code{keys} @kbd{keyfile}
+configuration file directive.
+@node ntpd logfile
+@subsection logfile option (-l)
+@cindex ntpd-logfile
+
+This is the ``path to the log file'' option.
+This option takes a string argument.
+Specify the name and path of the log file.
+The default is the system log file.
+This is the same operation as the
+@code{logfile} @kbd{logfile}
+configuration file directive.
+@node ntpd novirtualips
+@subsection novirtualips option (-L)
+@cindex ntpd-novirtualips
+
+This is the ``do not listen to virtual interfaces'' option.
+Do not listen to virtual interfaces, defined as those with
+names containing a colon. This option is deprecated. Please
+consider using the configuration file @code{interface} command, which
+is more versatile.
+@node ntpd modifymmtimer
+@subsection modifymmtimer option (-M)
+@cindex ntpd-modifymmtimer
+
+This is the ``modify multimedia timer (windows only)'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{SYS_WINNT} during the compilation.
+@end itemize
+
+Set the Windows Multimedia Timer to highest resolution. This
+ensures the resolution does not change while ntpd is running,
+avoiding timekeeping glitches associated with changes.
+@node ntpd nice
+@subsection nice option (-N)
+@cindex ntpd-nice
+
+This is the ``run at high priority'' option.
+To the extent permitted by the operating system, run
+@code{ntpd}
+at the highest priority.
+@node ntpd pidfile
+@subsection pidfile option (-p)
+@cindex ntpd-pidfile
+
+This is the ``path to the pid file'' option.
+This option takes a string argument.
+Specify the name and path of the file used to record
+@code{ntpd}'s
+process ID.
+This is the same operation as the
+@code{pidfile} @kbd{pidfile}
+configuration file directive.
+@node ntpd priority
+@subsection priority option (-P)
+@cindex ntpd-priority
+
+This is the ``process priority'' option.
+This option takes a number argument.
+To the extent permitted by the operating system, run
+@code{ntpd}
+at the specified
+@code{sched_setscheduler(SCHED_FIFO)}
+priority.
+@node ntpd quit
+@subsection quit option (-q)
+@cindex ntpd-quit
+
+This is the ``set the time and quit'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must not appear in combination with any of the following options:
+saveconfigquit, wait-sync.
+@end itemize
+
+@code{ntpd}
+will not daemonize and will exit after the clock is first
+synchronized. This behavior mimics that of the
+@code{ntpdate}
+program, which will soon be replaced with a shell script.
+The
+@code{-g}
+and
+@code{-x}
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+@node ntpd propagationdelay
+@subsection propagationdelay option (-r)
+@cindex ntpd-propagationdelay
+
+This is the ``broadcast/propagation delay'' option.
+This option takes a string argument.
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+@node ntpd saveconfigquit
+@subsection saveconfigquit option
+@cindex ntpd-saveconfigquit
+
+This is the ``save parsed configuration and quit'' option.
+This option takes a string argument.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{SAVECONFIG} during the compilation.
+@item
+must not appear in combination with any of the following options:
+quit, wait-sync.
+@end itemize
+
+Cause @code{ntpd} to parse its startup configuration file and save an
+equivalent to the given filename and exit. This option was
+designed for automated testing.
+@node ntpd statsdir
+@subsection statsdir option (-s)
+@cindex ntpd-statsdir
+
+This is the ``statistics file location'' option.
+This option takes a string argument.
+Specify the directory path for files created by the statistics facility.
+This is the same operation as the
+@code{statsdir} @kbd{statsdir}
+configuration file directive.
+@node ntpd trustedkey
+@subsection trustedkey option (-t)
+@cindex ntpd-trustedkey
+
+This is the ``trusted key number'' option.
+This option takes a string argument @file{tkey}.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+may appear an unlimited number of times.
+@end itemize
+
+Add the specified key number to the trusted key list.
+@node ntpd user
+@subsection user option (-u)
+@cindex ntpd-user
+
+This is the ``run as userid (or userid:groupid)'' option.
+This option takes a string argument.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{HAVE_DROPROOT} during the compilation.
+@end itemize
+
+Specify a user, and optionally a group, to switch to.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+@code{--enable-clockctl}) or Linux (configure with
+@code{--enable-linuxcaps}) or Solaris (configure with @code{--enable-solarisprivs}).
+@node ntpd updateinterval
+@subsection updateinterval option (-U)
+@cindex ntpd-updateinterval
+
+This is the ``interval in seconds between scans for new or dropped interfaces'' option.
+This option takes a number argument.
+Give the time in seconds between two scans for new or dropped interfaces.
+For systems with routing socket support the scans will be performed shortly after the interface change
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+@node ntpd wait-sync
+@subsection wait-sync option (-w)
+@cindex ntpd-wait-sync
+
+This is the ``seconds to wait for first clock sync'' option.
+This option takes a number argument.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{HAVE_WORKING_FORK} during the compilation.
+@item
+must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+@end itemize
+
+If greater than zero, alters @code{ntpd}'s behavior when forking to
+daemonize. Instead of exiting with status 0 immediately after
+the fork, the parent waits up to the specified number of
+seconds for the child to first synchronize the clock. The exit
+status is zero (success) if the clock was synchronized,
+otherwise it is @code{ETIMEDOUT}.
+This provides the option for a script starting @code{ntpd} to easily
+wait for the first set of the clock before proceeding.
+@node ntpd slew
+@subsection slew option (-x)
+@cindex ntpd-slew
+
+This is the ``slew up to 600 seconds'' option.
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+This option can be used with the
+@code{-g}
+and
+@code{-q}
+options.
+See the
+@code{tinker}
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+@node ntpd usepcc
+@subsection usepcc option
+@cindex ntpd-usepcc
+
+This is the ``use cpu cycle counter (windows only)'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{SYS_WINNT} during the compilation.
+@end itemize
+
+Attempt to substitute the CPU counter for @code{QueryPerformanceCounter}.
+The CPU counter and @code{QueryPerformanceCounter} are compared, and if
+they have the same frequency, the CPU counter (RDTSC on x86) is
+used directly, saving the overhead of a system call.
+@node ntpd pccfreq
+@subsection pccfreq option
+@cindex ntpd-pccfreq
+
+This is the ``force cpu cycle counter use (windows only)'' option.
+This option takes a string argument.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{SYS_WINNT} during the compilation.
+@end itemize
+
+Force substitution the CPU counter for @code{QueryPerformanceCounter}.
+The CPU counter (RDTSC on x86) is used unconditionally with the
+given frequency (in Hz).
+@node ntpd mdns
+@subsection mdns option (-m)
+@cindex ntpd-mdns
+
+This is the ``register with mdns as a ntp server'' option.
+
+@noindent
+This option has some usage constraints. It:
+@itemize @bullet
+@item
+must be compiled in by defining @code{HAVE_DNSREGISTRATION} during the compilation.
+@end itemize
+
+Registers as an NTP server with the local mDNS server which allows
+the server to be discovered via mDNS client lookup.
+
+
+@node ntpd config
+@subsection presetting/configuring ntpd
+
+Any option that is not marked as @i{not presettable} may be preset by
+loading values from environment variables named @code{NTPD} and @code{NTPD_<OPTION_NAME>}. @code{<OPTION_NAME>} must be one of
+the options listed above in upper case and segmented with underscores.
+The @code{NTPD} variable will be tokenized and parsed like
+the command line. The remaining variables are tested for existence and their
+values are treated like option arguments.
+
+
+The command line options relating to configuration and/or usage help are:
+
+@subsubheading version (-)
+
+Print the program version to standard out, optionally with licensing
+information, then exit 0. The optional argument specifies how much licensing
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+Only the first letter of the argument is examined:
+
+@table @samp
+@item version
+Only print the version. This is the default.
+@item copyright
+Name the copyright usage licensing terms.
+@item verbose
+Print the full copyright usage licensing terms.
+@end table
+
+@node ntpd exit status
+@subsection ntpd exit status
+
+One of the following exit values will be returned:
+@table @samp
+@item 0 (EXIT_SUCCESS)
+Successful program execution.
+@item 1 (EXIT_FAILURE)
+The operation failed or the command syntax was not valid.
+@end table
+@node ntpd Usage
+@subsection ntpd Usage
+@node ntpd Files
+@subsection ntpd Files
+@node ntpd See Also
+@subsection ntpd See Also
+@node ntpd Bugs
+@subsection ntpd Bugs
+@node ntpd Notes
+@subsection ntpd Notes
diff --git a/contrib/ntp/ntpd/keyword-gen-utd b/contrib/ntp/ntpd/keyword-gen-utd
new file mode 100644
index 0000000..467351b
--- /dev/null
+++ b/contrib/ntp/ntpd/keyword-gen-utd
@@ -0,0 +1 @@
+ * Generated 2015-06-25 03:57:00 UTC diff_ignore_line
diff --git a/contrib/ntp/ntpd/keyword-gen.c b/contrib/ntp/ntpd/keyword-gen.c
new file mode 100644
index 0000000..42e9497
--- /dev/null
+++ b/contrib/ntp/ntpd/keyword-gen.c
@@ -0,0 +1,755 @@
+/*
+ * keyword-gen.c -- generate keyword scanner finite state machine and
+ * keyword_text array.
+ *
+ * This program is run to generate ntp_keyword.h
+ * After making a change here, two output files should be committed at
+ * the same time as keyword-gen.c:
+ * ntp_keyword.h
+ * keyword-gen-utd
+ *
+ * keyword-gen-utd is a sentinel used by Makefile.am to avoid compiling
+ * keyword_gen.c and generating ntp_keyword.h if the input keyword-gen.c
+ * has not changed. This is not solely an optimization, it also breaks
+ * a dependency chain that otherwise would cause programs to be compiled
+ * when running "make dist" or "make distdir". We want these to package
+ * the existing source without building anything but a tarball. See
+ * [Bug 1470].
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <ntp_stdlib.h>
+#include <ntp_config.h>
+#include <lib_strbuf.h>
+#include "ntp_scanner.h"
+#include "ntp_parser.h"
+
+
+/* Define a structure to hold a (keyword, token) pair */
+struct key_tok {
+ char * key; /* Keyword */
+ u_short token; /* Associated Token */
+ follby followedby; /* nonzero indicates the next token(s)
+ forced to be string(s) */
+};
+
+struct key_tok ntp_keywords[] = {
+{ "...", T_Ellipsis, FOLLBY_TOKEN },
+{ "allpeers", T_Allpeers, FOLLBY_TOKEN },
+{ "automax", T_Automax, FOLLBY_TOKEN },
+{ "broadcast", T_Broadcast, FOLLBY_STRING },
+{ "broadcastclient", T_Broadcastclient, FOLLBY_TOKEN },
+{ "broadcastdelay", T_Broadcastdelay, FOLLBY_TOKEN },
+{ "ctl", T_Ctl, FOLLBY_TOKEN },
+{ "disable", T_Disable, FOLLBY_TOKEN },
+{ "driftfile", T_Driftfile, FOLLBY_STRING },
+{ "dscp", T_Dscp, FOLLBY_TOKEN },
+{ "enable", T_Enable, FOLLBY_TOKEN },
+{ "end", T_End, FOLLBY_TOKEN },
+{ "filegen", T_Filegen, FOLLBY_TOKEN },
+{ "fudge", T_Fudge, FOLLBY_STRING },
+{ "io", T_Io, FOLLBY_TOKEN },
+{ "includefile", T_Includefile, FOLLBY_STRING },
+{ "leapfile", T_Leapfile, FOLLBY_STRING },
+{ "leapsmearinterval", T_Leapsmearinterval, FOLLBY_TOKEN },
+{ "logconfig", T_Logconfig, FOLLBY_STRINGS_TO_EOC },
+{ "logfile", T_Logfile, FOLLBY_STRING },
+{ "manycastclient", T_Manycastclient, FOLLBY_STRING },
+{ "manycastserver", T_Manycastserver, FOLLBY_STRINGS_TO_EOC },
+{ "mem", T_Mem, FOLLBY_TOKEN },
+{ "multicastclient", T_Multicastclient, FOLLBY_STRINGS_TO_EOC },
+{ "peer", T_Peer, FOLLBY_STRING },
+{ "phone", T_Phone, FOLLBY_STRINGS_TO_EOC },
+{ "pidfile", T_Pidfile, FOLLBY_STRING },
+{ "pool", T_Pool, FOLLBY_STRING },
+{ "discard", T_Discard, FOLLBY_TOKEN },
+{ "reset", T_Reset, FOLLBY_TOKEN },
+{ "restrict", T_Restrict, FOLLBY_TOKEN },
+{ "rlimit", T_Rlimit, FOLLBY_TOKEN },
+{ "server", T_Server, FOLLBY_STRING },
+{ "setvar", T_Setvar, FOLLBY_STRING },
+{ "statistics", T_Statistics, FOLLBY_TOKEN },
+{ "statsdir", T_Statsdir, FOLLBY_STRING },
+{ "sys", T_Sys, FOLLBY_TOKEN },
+{ "tick", T_Tick, FOLLBY_TOKEN },
+{ "timer", T_Timer, FOLLBY_TOKEN },
+{ "tinker", T_Tinker, FOLLBY_TOKEN },
+{ "tos", T_Tos, FOLLBY_TOKEN },
+{ "trap", T_Trap, FOLLBY_STRING },
+{ "unconfig", T_Unconfig, FOLLBY_STRING },
+{ "unpeer", T_Unpeer, FOLLBY_STRING },
+/* authentication_command */
+{ "controlkey", T_ControlKey, FOLLBY_TOKEN },
+{ "crypto", T_Crypto, FOLLBY_TOKEN },
+{ "keys", T_Keys, FOLLBY_STRING },
+{ "keysdir", T_Keysdir, FOLLBY_STRING },
+{ "ntpsigndsocket", T_NtpSignDsocket, FOLLBY_STRING },
+{ "requestkey", T_Requestkey, FOLLBY_TOKEN },
+{ "revoke", T_Revoke, FOLLBY_TOKEN },
+{ "trustedkey", T_Trustedkey, FOLLBY_TOKEN },
+/* IPv4/IPv6 protocol override flag */
+{ "-4", T_Ipv4_flag, FOLLBY_TOKEN },
+{ "-6", T_Ipv6_flag, FOLLBY_TOKEN },
+/* option */
+{ "autokey", T_Autokey, FOLLBY_TOKEN },
+{ "burst", T_Burst, FOLLBY_TOKEN },
+{ "iburst", T_Iburst, FOLLBY_TOKEN },
+{ "key", T_Key, FOLLBY_TOKEN },
+{ "maxpoll", T_Maxpoll, FOLLBY_TOKEN },
+{ "mdnstries", T_Mdnstries, FOLLBY_TOKEN },
+{ "minpoll", T_Minpoll, FOLLBY_TOKEN },
+{ "mode", T_Mode, FOLLBY_TOKEN },
+{ "noselect", T_Noselect, FOLLBY_TOKEN },
+{ "preempt", T_Preempt, FOLLBY_TOKEN },
+{ "true", T_True, FOLLBY_TOKEN },
+{ "prefer", T_Prefer, FOLLBY_TOKEN },
+{ "ttl", T_Ttl, FOLLBY_TOKEN },
+{ "version", T_Version, FOLLBY_TOKEN },
+{ "xleave", T_Xleave, FOLLBY_TOKEN },
+/* crypto_command */
+{ "host", T_Host, FOLLBY_STRING },
+{ "ident", T_Ident, FOLLBY_STRING },
+{ "pw", T_Pw, FOLLBY_STRING },
+{ "randfile", T_Randfile, FOLLBY_STRING },
+{ "digest", T_Digest, FOLLBY_STRING },
+/*** MONITORING COMMANDS ***/
+/* stat */
+{ "clockstats", T_Clockstats, FOLLBY_TOKEN },
+{ "cryptostats", T_Cryptostats, FOLLBY_TOKEN },
+{ "loopstats", T_Loopstats, FOLLBY_TOKEN },
+{ "peerstats", T_Peerstats, FOLLBY_TOKEN },
+{ "rawstats", T_Rawstats, FOLLBY_TOKEN },
+{ "sysstats", T_Sysstats, FOLLBY_TOKEN },
+{ "protostats", T_Protostats, FOLLBY_TOKEN },
+{ "timingstats", T_Timingstats, FOLLBY_TOKEN },
+/* filegen_option */
+{ "file", T_File, FOLLBY_STRING },
+{ "link", T_Link, FOLLBY_TOKEN },
+{ "nolink", T_Nolink, FOLLBY_TOKEN },
+{ "type", T_Type, FOLLBY_TOKEN },
+/* filegen_type */
+{ "age", T_Age, FOLLBY_TOKEN },
+{ "day", T_Day, FOLLBY_TOKEN },
+{ "month", T_Month, FOLLBY_TOKEN },
+{ "none", T_None, FOLLBY_TOKEN },
+{ "pid", T_Pid, FOLLBY_TOKEN },
+{ "week", T_Week, FOLLBY_TOKEN },
+{ "year", T_Year, FOLLBY_TOKEN },
+/*** ORPHAN MODE COMMANDS ***/
+/* tos_option */
+{ "minclock", T_Minclock, FOLLBY_TOKEN },
+{ "maxclock", T_Maxclock, FOLLBY_TOKEN },
+{ "minsane", T_Minsane, FOLLBY_TOKEN },
+{ "floor", T_Floor, FOLLBY_TOKEN },
+{ "ceiling", T_Ceiling, FOLLBY_TOKEN },
+{ "cohort", T_Cohort, FOLLBY_TOKEN },
+{ "mindist", T_Mindist, FOLLBY_TOKEN },
+{ "maxdist", T_Maxdist, FOLLBY_TOKEN },
+{ "beacon", T_Beacon, FOLLBY_TOKEN },
+{ "orphan", T_Orphan, FOLLBY_TOKEN },
+{ "orphanwait", T_Orphanwait, FOLLBY_TOKEN },
+{ "nonvolatile", T_Nonvolatile, FOLLBY_TOKEN },
+/* access_control_flag */
+{ "default", T_Default, FOLLBY_TOKEN },
+{ "source", T_Source, FOLLBY_TOKEN },
+{ "flake", T_Flake, FOLLBY_TOKEN },
+{ "ignore", T_Ignore, FOLLBY_TOKEN },
+{ "limited", T_Limited, FOLLBY_TOKEN },
+{ "mssntp", T_Mssntp, FOLLBY_TOKEN },
+{ "kod", T_Kod, FOLLBY_TOKEN },
+{ "lowpriotrap", T_Lowpriotrap, FOLLBY_TOKEN },
+{ "mask", T_Mask, FOLLBY_TOKEN },
+{ "nomodify", T_Nomodify, FOLLBY_TOKEN },
+{ "nomrulist", T_Nomrulist, FOLLBY_TOKEN },
+{ "nopeer", T_Nopeer, FOLLBY_TOKEN },
+{ "noquery", T_Noquery, FOLLBY_TOKEN },
+{ "noserve", T_Noserve, FOLLBY_TOKEN },
+{ "notrap", T_Notrap, FOLLBY_TOKEN },
+{ "notrust", T_Notrust, FOLLBY_TOKEN },
+{ "ntpport", T_Ntpport, FOLLBY_TOKEN },
+/* discard_option */
+{ "average", T_Average, FOLLBY_TOKEN },
+{ "minimum", T_Minimum, FOLLBY_TOKEN },
+{ "monitor", T_Monitor, FOLLBY_TOKEN },
+/* mru_option */
+{ "incalloc", T_Incalloc, FOLLBY_TOKEN },
+{ "incmem", T_Incmem, FOLLBY_TOKEN },
+{ "initalloc", T_Initalloc, FOLLBY_TOKEN },
+{ "initmem", T_Initmem, FOLLBY_TOKEN },
+{ "mindepth", T_Mindepth, FOLLBY_TOKEN },
+{ "maxage", T_Maxage, FOLLBY_TOKEN },
+{ "maxdepth", T_Maxdepth, FOLLBY_TOKEN },
+{ "maxmem", T_Maxmem, FOLLBY_TOKEN },
+{ "mru", T_Mru, FOLLBY_TOKEN },
+/* fudge_factor */
+{ "abbrev", T_Abbrev, FOLLBY_STRING },
+{ "flag1", T_Flag1, FOLLBY_TOKEN },
+{ "flag2", T_Flag2, FOLLBY_TOKEN },
+{ "flag3", T_Flag3, FOLLBY_TOKEN },
+{ "flag4", T_Flag4, FOLLBY_TOKEN },
+{ "refid", T_Refid, FOLLBY_STRING },
+{ "stratum", T_Stratum, FOLLBY_TOKEN },
+{ "time1", T_Time1, FOLLBY_TOKEN },
+{ "time2", T_Time2, FOLLBY_TOKEN },
+/* system_option */
+{ "auth", T_Auth, FOLLBY_TOKEN },
+{ "bclient", T_Bclient, FOLLBY_TOKEN },
+{ "calibrate", T_Calibrate, FOLLBY_TOKEN },
+{ "kernel", T_Kernel, FOLLBY_TOKEN },
+{ "ntp", T_Ntp, FOLLBY_TOKEN },
+{ "mode7", T_Mode7, FOLLBY_TOKEN },
+{ "stats", T_Stats, FOLLBY_TOKEN },
+/* rlimit_option */
+{ "memlock", T_Memlock, FOLLBY_TOKEN },
+{ "stacksize", T_Stacksize, FOLLBY_TOKEN },
+{ "filenum", T_Filenum, FOLLBY_TOKEN },
+/* tinker_option */
+{ "step", T_Step, FOLLBY_TOKEN },
+{ "stepback", T_Stepback, FOLLBY_TOKEN },
+{ "stepfwd", T_Stepfwd, FOLLBY_TOKEN },
+{ "panic", T_Panic, FOLLBY_TOKEN },
+{ "dispersion", T_Dispersion, FOLLBY_TOKEN },
+{ "stepout", T_Stepout, FOLLBY_TOKEN },
+{ "allan", T_Allan, FOLLBY_TOKEN },
+{ "huffpuff", T_Huffpuff, FOLLBY_TOKEN },
+{ "freq", T_Freq, FOLLBY_TOKEN },
+/* miscellaneous_command */
+{ "port", T_Port, FOLLBY_TOKEN },
+{ "interface", T_Interface, FOLLBY_TOKEN },
+{ "saveconfigdir", T_Saveconfigdir, FOLLBY_STRING },
+/* interface_command (ignore and interface already defined) */
+{ "nic", T_Nic, FOLLBY_TOKEN },
+{ "all", T_All, FOLLBY_TOKEN },
+{ "ipv4", T_Ipv4, FOLLBY_TOKEN },
+{ "ipv6", T_Ipv6, FOLLBY_TOKEN },
+{ "wildcard", T_Wildcard, FOLLBY_TOKEN },
+{ "listen", T_Listen, FOLLBY_TOKEN },
+{ "drop", T_Drop, FOLLBY_TOKEN },
+/* simulator commands */
+{ "simulate", T_Simulate, FOLLBY_TOKEN },
+{ "simulation_duration",T_Sim_Duration, FOLLBY_TOKEN },
+{ "beep_delay", T_Beep_Delay, FOLLBY_TOKEN },
+{ "duration", T_Duration, FOLLBY_TOKEN },
+{ "server_offset", T_Server_Offset, FOLLBY_TOKEN },
+{ "freq_offset", T_Freq_Offset, FOLLBY_TOKEN },
+{ "wander", T_Wander, FOLLBY_TOKEN },
+{ "jitter", T_Jitter, FOLLBY_TOKEN },
+{ "prop_delay", T_Prop_Delay, FOLLBY_TOKEN },
+{ "proc_delay", T_Proc_Delay, FOLLBY_TOKEN },
+};
+
+typedef struct big_scan_state_tag {
+ char ch; /* Character this state matches on */
+ char followedby; /* Forces next token(s) to T_String */
+ u_short finishes_token; /* nonzero ID if last keyword char */
+ u_short match_next_s; /* next state to check matching ch */
+ u_short other_next_s; /* next state to check if not ch */
+} big_scan_state;
+
+/*
+ * Note: to increase MAXSTATES beyond 2048, be aware it is currently
+ * crammed into 11 bits in scan_state form. Raising to 4096 would be
+ * relatively easy by storing the followedby value in a separate
+ * array with one entry per token, and shrinking the char value to
+ * 7 bits to free a bit for accepting/non-accepting. More than 4096
+ * states will require expanding scan_state beyond 32 bits each.
+ */
+#define MAXSTATES 2048
+#define MAX_TOK_LEN 63
+
+const char * current_keyword;/* for error reporting */
+big_scan_state sst[MAXSTATES]; /* scanner FSM state entries */
+u_short sst_highwater; /* next entry index to consider */
+char * symb[1024]; /* map token ID to symbolic name */
+
+/* for libntp */
+const char * progname = "keyword-gen";
+
+int main (int, char **);
+static void generate_preamble (void);
+static void generate_fsm (void);
+static void generate_token_text (void);
+static u_short create_keyword_scanner (void);
+static u_short create_scan_states (char *, u_short, follby, u_short);
+int compare_key_tok_id (const void *, const void *);
+int compare_key_tok_text (const void *, const void *);
+void populate_symb (char *);
+const char * symbname (u_short);
+
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage:\n%s t_header.h\n", argv[0]);
+ exit(1);
+ }
+ debug = 1;
+
+ populate_symb(argv[1]);
+
+ generate_preamble();
+ generate_token_text();
+ generate_fsm();
+
+ return 0;
+}
+
+
+static void
+generate_preamble(void)
+{
+ time_t now;
+ char timestamp[128];
+ char preamble[] =
+"/*\n"
+" * ntp_keyword.h\n"
+" * \n"
+" * NOTE: edit this file with caution, it is generated by keyword-gen.c\n"
+" *\t Generated %s UTC diff_ignore_line\n"
+" *\n"
+" */\n"
+"#include \"ntp_scanner.h\"\n"
+"#include \"ntp_parser.h\"\n"
+"\n";
+
+ time(&now);
+ if (!strftime(timestamp, sizeof(timestamp),
+ "%Y-%m-%d %H:%M:%S", gmtime(&now)))
+ timestamp[0] = '\0';
+
+ printf(preamble, timestamp);
+}
+
+
+static void
+generate_fsm(void)
+{
+ char rprefix[MAX_TOK_LEN + 1];
+ char prefix[MAX_TOK_LEN + 1];
+ char token_id_comment[16 + MAX_TOK_LEN + 1];
+ size_t prefix_len;
+ char *p;
+ char *r;
+ u_short initial_state;
+ u_short this_state;
+ u_short state;
+ u_short i;
+ u_short token;
+
+ /*
+ * Sort ntp_keywords in alphabetical keyword order. This is
+ * not necessary, but minimizes nonfunctional changes in the
+ * generated finite state machine when keywords are modified.
+ */
+ qsort(ntp_keywords, COUNTOF(ntp_keywords),
+ sizeof(ntp_keywords[0]), compare_key_tok_text);
+
+ /*
+ * To save space, reserve the state array entry matching each
+ * token number for its terminal state, so the token identifier
+ * does not need to be stored in each state, but can be
+ * recovered trivially. To mark the entry reserved,
+ * finishes_token is nonzero.
+ */
+
+ for (i = 0; i < COUNTOF(ntp_keywords); i++) {
+ token = ntp_keywords[i].token;
+ if (1 > token || token >= COUNTOF(sst)) {
+ fprintf(stderr,
+ "keyword-gen sst[%u] too small "
+ "for keyword '%s' id %d\n",
+ (int)COUNTOF(sst),
+ ntp_keywords[i].key,
+ token);
+ exit(4);
+ }
+ sst[token].finishes_token = token;
+ }
+
+ initial_state = create_keyword_scanner();
+
+ fprintf(stderr,
+ "%d keywords consumed %d states of %d max.\n",
+ (int)COUNTOF(ntp_keywords),
+ sst_highwater - 1,
+ (int)COUNTOF(sst) - 1);
+
+ printf("#define SCANNER_INIT_S %d\n\n", initial_state);
+
+ printf("const scan_state sst[%d] = {\n"
+ "/*SS_T( ch,\tf-by, match, other ),\t\t\t\t */\n"
+ " 0,\t\t\t\t /* %5d %-17s */\n",
+ sst_highwater,
+ 0, "");
+
+ for (i = 1; i < sst_highwater; i++) {
+
+ /* verify fields will fit */
+ if (sst[i].followedby & ~0x3) {
+ fprintf(stderr,
+ "keyword-gen internal error "
+ "sst[%d].followedby %d too big\n",
+ i, sst[i].followedby);
+ exit(7);
+ }
+
+ if (sst_highwater <= sst[i].match_next_s
+ || sst[i].match_next_s & ~0x7ff) {
+ fprintf(stderr,
+ "keyword-gen internal error "
+ "sst[%d].match_next_s %d too big\n",
+ i, sst[i].match_next_s);
+ exit(8);
+ }
+
+ if (sst_highwater <= sst[i].other_next_s
+ || sst[i].other_next_s & ~0x7ff) {
+ fprintf(stderr,
+ "keyword-gen internal error "
+ "sst[%d].other_next_s %d too big\n",
+ i, sst[i].other_next_s);
+ exit(9);
+ }
+
+ if (sst[i].finishes_token) {
+ snprintf(token_id_comment,
+ sizeof(token_id_comment), "%5d %-17s",
+ i, symbname(sst[i].finishes_token));
+ if (i != sst[i].finishes_token) {
+ fprintf(stderr,
+ "keyword-gen internal error "
+ "entry %d finishes token %d\n",
+ i, sst[i].finishes_token);
+ exit(5);
+ }
+ } else {
+ /*
+ * Determine the keyword prefix that leads to this
+ * state. This is expensive but keyword-gen is run
+ * only when it changes. Distributing keyword-gen-utd
+ * achieves that, which is why it must be committed
+ * at the same time as keyword-gen.c and ntp_keyword.h.
+ *
+ * Scan the state array iteratively looking for a state
+ * which leads to the current one, collecting matching
+ * characters along the way. There is only one such
+ * path back to the starting state given the way our
+ * scanner state machine is built and the practice of
+ * using the spelling of the keyword as its T_* token
+ * identifier, which results in never having two
+ * spellings result in the same T_* value.
+ */
+ prefix_len = 0;
+ this_state = i;
+ do {
+ for (state = 1; state < sst_highwater; state++)
+ if (sst[state].other_next_s == this_state) {
+ this_state = state;
+ break;
+ } else if (sst[state].match_next_s == this_state) {
+ this_state = state;
+ rprefix[prefix_len] = sst[state].ch;
+ prefix_len++;
+ break;
+ }
+ } while (this_state != initial_state);
+
+ if (prefix_len) {
+ /* reverse rprefix into prefix */
+ p = prefix + prefix_len;
+ r = rprefix;
+ while (r < rprefix + prefix_len)
+ *--p = *r++;
+ }
+ prefix[prefix_len] = '\0';
+
+ snprintf(token_id_comment,
+ sizeof(token_id_comment), "%5d %-17s",
+ i, (initial_state == i)
+ ? "[initial state]"
+ : prefix);
+ }
+
+ printf(" S_ST( '%c',\t%d, %5u, %5u )%s /* %s */\n",
+ sst[i].ch,
+ sst[i].followedby,
+ sst[i].match_next_s,
+ sst[i].other_next_s,
+ (i + 1 < sst_highwater)
+ ? ","
+ : " ",
+ token_id_comment);
+ }
+
+ printf("};\n\n");
+}
+
+
+/* Define a function to create the states of the scanner. This function
+ * is used by the create_keyword_scanner function below.
+ *
+ * This function takes a suffix of a keyword, the token to be returned on
+ * recognizing the complete keyword, and any pre-existing state that exists
+ * for some other keyword that has the same prefix as the current one.
+ */
+static u_short
+create_scan_states(
+ char * text,
+ u_short token,
+ follby followedby,
+ u_short prev_state
+ )
+{
+ u_short my_state;
+ u_short return_state;
+ u_short prev_char_s;
+ u_short curr_char_s;
+
+ return_state = prev_state;
+ curr_char_s = prev_state;
+ prev_char_s = 0;
+
+ /* Find the correct position to insert the state.
+ * All states should be in alphabetical order
+ */
+ while (curr_char_s && (text[0] < sst[curr_char_s].ch)) {
+ prev_char_s = curr_char_s;
+ curr_char_s = sst[curr_char_s].other_next_s;
+ }
+
+ /*
+ * Check if a previously seen keyword has the same prefix as
+ * the current keyword. If so, simply use the state for that
+ * keyword as my_state, otherwise, allocate a new state.
+ */
+ if (curr_char_s && (text[0] == sst[curr_char_s].ch)) {
+ my_state = curr_char_s;
+ if ('\0' == text[1]) {
+ fprintf(stderr,
+ "Duplicate entries for keyword '%s' in"
+ " keyword_gen.c ntp_keywords[].\n",
+ current_keyword);
+ exit(2);
+ }
+ } else {
+ do
+ my_state = sst_highwater++;
+ while (my_state < COUNTOF(sst)
+ && sst[my_state].finishes_token);
+ if (my_state >= COUNTOF(sst)) {
+ fprintf(stderr,
+ "fatal, keyword scanner state array "
+ "sst[%d] is too small, modify\n"
+ "keyword-gen.c to increase.\n",
+ (int)COUNTOF(sst));
+ exit(3);
+ }
+ /* Store the next character of the keyword */
+ sst[my_state].ch = text[0];
+ sst[my_state].other_next_s = curr_char_s;
+ sst[my_state].followedby = FOLLBY_NON_ACCEPTING;
+
+ if (prev_char_s)
+ sst[prev_char_s].other_next_s = my_state;
+ else
+ return_state = my_state;
+ }
+
+ /* Check if the next character is '\0'.
+ * If yes, we are done with the recognition and this is an accepting
+ * state.
+ * If not, we need to continue scanning
+ */
+ if ('\0' == text[1]) {
+ sst[my_state].finishes_token = (u_short)token;
+ sst[my_state].followedby = (char)followedby;
+
+ if (sst[token].finishes_token != (u_short)token) {
+ fprintf(stderr,
+ "fatal, sst[%d] not reserved for %s.\n",
+ token, symbname(token));
+ exit(6);
+ }
+ /* relocate so token id is sst[] index */
+ if (my_state != token) {
+ sst[token] = sst[my_state];
+ ZERO(sst[my_state]);
+ do
+ sst_highwater--;
+ while (sst[sst_highwater].finishes_token);
+ my_state = token;
+ if (prev_char_s)
+ sst[prev_char_s].other_next_s = my_state;
+ else
+ return_state = my_state;
+ }
+ } else
+ sst[my_state].match_next_s =
+ create_scan_states(
+ &text[1],
+ token,
+ followedby,
+ sst[my_state].match_next_s);
+
+ return return_state;
+}
+
+
+/* Define a function that takes a list of (keyword, token) values and
+ * creates a keywords scanner out of it.
+ */
+
+static u_short
+create_keyword_scanner(void)
+{
+ u_short scanner;
+ u_short i;
+
+ sst_highwater = 1; /* index 0 invalid, unused */
+ scanner = 0;
+
+ for (i = 0; i < COUNTOF(ntp_keywords); i++) {
+ current_keyword = ntp_keywords[i].key;
+ scanner =
+ create_scan_states(
+ ntp_keywords[i].key,
+ ntp_keywords[i].token,
+ ntp_keywords[i].followedby,
+ scanner);
+ }
+
+ return scanner;
+}
+
+
+static void
+generate_token_text(void)
+{
+ u_short lowest_id;
+ u_short highest_id;
+ u_short id_count;
+ u_short id;
+ u_short i;
+
+ /* sort ntp_keywords in token ID order */
+ qsort(ntp_keywords, COUNTOF(ntp_keywords),
+ sizeof(ntp_keywords[0]), compare_key_tok_id);
+
+ lowest_id = ntp_keywords[0].token;
+ highest_id = ntp_keywords[COUNTOF(ntp_keywords) - 1].token;
+ id_count = highest_id - lowest_id + 1;
+
+ printf("#define LOWEST_KEYWORD_ID %d\n\n", lowest_id);
+
+ printf("const char * const keyword_text[%d] = {", id_count);
+
+ id = lowest_id;
+ i = 0;
+ while (i < COUNTOF(ntp_keywords)) {
+ while (id < ntp_keywords[i].token) {
+ printf(",\n\t/* %-5d %5d %20s */\tNULL",
+ id - lowest_id, id, symbname(id));
+ id++;
+ }
+ if (i > 0)
+ printf(",");
+ printf("\n\t/* %-5d %5d %20s */\t\"%s\"",
+ id - lowest_id, id, symbname(id),
+ ntp_keywords[i].key);
+ i++;
+ id++;
+ }
+
+ printf("\n};\n\n");
+}
+
+
+int
+compare_key_tok_id(
+ const void *a1,
+ const void *a2
+ )
+{
+ const struct key_tok *p1 = a1;
+ const struct key_tok *p2 = a2;
+
+ if (p1->token == p2->token)
+ return 0;
+
+ if (p1->token < p2->token)
+ return -1;
+ else
+ return 1;
+}
+
+
+int
+compare_key_tok_text(
+ const void *a1,
+ const void *a2
+ )
+{
+ const struct key_tok *p1 = a1;
+ const struct key_tok *p2 = a2;
+
+ return strcmp(p1->key, p2->key);
+}
+
+
+/*
+ * populate_symb() - populate symb[] lookup array with symbolic token
+ * names such that symb[T_Age] == "T_Age", etc.
+ */
+void
+populate_symb(
+ char *header_file
+ )
+{
+ FILE * yh;
+ char line[2 * MAX_TOK_LEN];
+ char name[2 * MAX_TOK_LEN];
+ int token;
+
+ yh = fopen(header_file, "r");
+ if (NULL == yh) {
+ perror("unable to open yacc/bison header file");
+ exit(4);
+ }
+
+ while (NULL != fgets(line, sizeof(line), yh))
+ if (2 == sscanf(line, "#define %s %d", name, &token)
+ && 'T' == name[0] && '_' == name[1] && token >= 0
+ && token < COUNTOF(symb)) {
+
+ symb[token] = estrdup(name);
+ if (strlen(name) > MAX_TOK_LEN) {
+ fprintf(stderr,
+ "MAX_TOK_LEN %d too small for '%s'\n"
+ "Edit keyword-gen.c to raise.\n",
+ MAX_TOK_LEN, name);
+ exit(10);
+ }
+ }
+ fclose(yh);
+}
+
+
+const char *
+symbname(
+ u_short token
+ )
+{
+ char *name;
+
+ if (token < COUNTOF(symb) && symb[token] != NULL) {
+ name = symb[token];
+ } else {
+ LIB_GETBUF(name);
+ snprintf(name, LIB_BUFLENGTH, "%d", token);
+ }
+
+ return name;
+}
diff --git a/contrib/ntp/ntpd/ntp.conf.5man b/contrib/ntp/ntpd/ntp.conf.5man
new file mode 100644
index 0000000..14438bd
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.5man
@@ -0,0 +1,3052 @@
+.de1 NOP
+. it 1 an-trap
+. if \\n[.$] \,\\$*\/
+..
+.ie t \
+.ds B-Font [CB]
+.ds I-Font [CI]
+.ds R-Font [CR]
+.el \
+.ds B-Font B
+.ds I-Font I
+.ds R-Font R
+.TH ntp.conf 5man "29 Jun 2015" "4.2.8p3" "File Formats"
+.\"
+.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-R0aO7B/ag-30aG6B)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:16 PM by AutoGen 5.18.5
+.\" From the definitions ntp.conf.def
+.\" and the template file agman-cmd.tpl
+.SH NAME
+\f\*[B-Font]ntp.conf\fP
+\- Network Time Protocol (NTP) daemon configuration file format
+.SH SYNOPSIS
+\f\*[B-Font]ntp.conf\fP
+[\f\*[B-Font]\-\-option-name\f[]]
+[\f\*[B-Font]\-\-option-name\f[] \f\*[I-Font]value\f[]]
+.sp \n(Ppu
+.ne 2
+
+All arguments must be options.
+.sp \n(Ppu
+.ne 2
+
+.SH DESCRIPTION
+The
+\f\*[B-Font]ntp.conf\fP
+configuration file is read at initial startup by the
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+\fI/etc\f[]
+directory,
+but could be installed elsewhere
+(see the daemon's
+\f\*[B-Font]\-c\f[]
+command line option).
+.sp \n(Ppu
+.ne 2
+
+The file format is similar to other
+UNIX
+configuration files.
+Comments begin with a
+\[oq]#\[cq]
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+.sp \n(Ppu
+.ne 2
+
+The rest of this page describes the configuration and control options.
+The
+"Notes on Configuring NTP and Setting up an NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+contains an extended discussion of these options.
+In addition to the discussion of general
+\fIConfiguration\f[] \fIOptions\f[],
+there are sections describing the following supported functionality
+and the options used to control it:
+.IP \fB\(bu\fP 2
+\fIAuthentication\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIMonitoring\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIAccess\f[] \fIControl\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIAutomatic\f[] \fINTP\f[] \fIConfiguration\f[] \fIOptions\f[]
+.IP \fB\(bu\fP 2
+\fIReference\f[] \fIClock\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIMiscellaneous\f[] \fIOptions\f[]
+.PP
+.sp \n(Ppu
+.ne 2
+
+Following these is a section describing
+\fIMiscellaneous\f[] \fIOptions\f[].
+While there is a rich set of options available,
+the only required option is one or more
+\f\*[B-Font]pool\f[],
+\f\*[B-Font]server\f[],
+\f\*[B-Font]peer\f[],
+\f\*[B-Font]broadcast\f[]
+or
+\f\*[B-Font]manycastclient\f[]
+commands.
+.SH Configuration Support
+Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+.SS Configuration Commands
+The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+.sp \n(Ppu
+.ne 2
+
+If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+\*[Lq]\&:\*[Rq]
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+.sp \n(Ppu
+.ne 2
+
+Note that in contexts where a host name is expected, a
+\f\*[B-Font]\-4\f[]
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+\f\*[B-Font]\-6\f[]
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+.TP 7
+.NOP \f\*[B-Font]pool\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]burst\f[]] [\f\*[B-Font]iburst\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]]
+.TP 7
+.NOP \f\*[B-Font]server\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]burst\f[]] [\f\*[B-Font]iburst\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]]
+.TP 7
+.NOP \f\*[B-Font]peer\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]]
+.TP 7
+.NOP \f\*[B-Font]broadcast\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]ttl\f[] \f\*[I-Font]ttl\f[]]
+.TP 7
+.NOP \f\*[B-Font]manycastclient\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]] [\f\*[B-Font]ttl\f[] \f\*[I-Font]ttl\f[]]
+.PP
+.sp \n(Ppu
+.ne 2
+
+These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+\f\*[I-Font]address\f[]
+can be
+either a DNS name or an IP address in dotted-quad notation.
+Additional information on association behavior can be found in the
+"Association Management"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.TP 7
+.NOP \f\*[B-Font]pool\f[]
+For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+.TP 7
+.NOP \f\*[B-Font]server\f[]
+For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+\fInot\f[]
+be used for type
+b or m addresses.
+.TP 7
+.NOP \f\*[B-Font]peer\f[]
+For type s addresses (only), this command mobilizes a
+persistent symmetric-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+.TP 7
+.NOP \f\*[B-Font]broadcast\f[]
+For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+\f\*[I-Font]address\f[]
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+\f\*[B-Font]broadcastclient\f[]
+or
+\f\*[B-Font]multicastclient\f[]
+commands
+below.
+.TP 7
+.NOP \f\*[B-Font]manycastclient\f[]
+For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+\f\*[B-Font]manycastserver\f[]
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+\f\*[B-Font]manycastserver\f[]
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+\f\*[I-Font]address\f[]
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+\f\*[B-Font]server\f[]
+command.
+The remaining servers are discarded as if never
+heard.
+.PP
+.sp \n(Ppu
+.ne 2
+
+Options:
+.TP 7
+.NOP \f\*[B-Font]autokey\f[]
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]burst\f[]
+when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+\f\*[B-Font]server\f[]
+command and s addresses.
+.TP 7
+.NOP \f\*[B-Font]iburst\f[]
+When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+\f\*[B-Font]server\f[]
+command and s addresses and when
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+is started with the
+\f\*[B-Font]\-q\f[]
+option.
+.TP 7
+.NOP \f\*[B-Font]key\f[] \f\*[I-Font]key\f[]
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+\f\*[I-Font]key\f[]
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+.TP 7
+.NOP \f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]
+.TP 7
+.NOP \f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]
+These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+\f\*[B-Font]maxpoll\f[]
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+\f\*[B-Font]minpoll\f[]
+option to a lower limit of 4 (16 s).
+.TP 7
+.NOP \f\*[B-Font]noselect\f[]
+Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+.TP 7
+.NOP \f\*[B-Font]prefer\f[]
+Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+for further information.
+.TP 7
+.NOP \f\*[B-Font]ttl\f[] \f\*[I-Font]ttl\f[]
+This option is used only with broadcast server and manycast
+client modes.
+It specifies the time-to-live
+\f\*[I-Font]ttl\f[]
+to
+use on broadcast server and multicast server and the maximum
+\f\*[I-Font]ttl\f[]
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+.TP 7
+.NOP \f\*[B-Font]version\f[] \f\*[I-Font]version\f[]
+Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1-4 are the choices, with version 4 the
+default.
+.PP
+.SS Auxiliary Commands
+.TP 7
+.NOP \f\*[B-Font]broadcastclient\f[]
+This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric-key or public-key
+authentication as described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]manycastserver\f[] \f\*[I-Font]address\f[] \f\*[I-Font]...\f[]
+This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric-key or public-key
+authentication as described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]multicastclient\f[] \f\*[I-Font]address\f[] \f\*[I-Font]...\f[]
+This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric-key or
+public-key authentication as described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]mdnstries\f[] \f\*[I-Font]number\f[]
+If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+\f\*[B-Font]mdnstries\f[]
+times.
+After all,
+\f\*[B-Font]ntpd\f[]
+may be starting before mDNS.
+The default value for
+\f\*[B-Font]mdnstries\f[]
+is 5.
+.PP
+.SH Authentication Support
+Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed-MD5.
+Either algorithm computes a message digest, or one-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+.sp \n(Ppu
+.ne 2
+
+NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+.sp \n(Ppu
+.ne 2
+
+While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+.sp \n(Ppu
+.ne 2
+
+Authentication is configured separately for each association
+using the
+\f\*[B-Font]key\f[]
+or
+\f\*[B-Font]autokey\f[]
+subcommand on the
+\f\*[B-Font]peer\f[],
+\f\*[B-Font]server\f[],
+\f\*[B-Font]broadcast\f[]
+and
+\f\*[B-Font]manycastclient\f[]
+configuration commands as described in
+\fIConfiguration\f[] \fIOptions\f[]
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+.sp \n(Ppu
+.ne 2
+
+Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]auth\f[]
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+\f\*[B-Font]enable\f[]
+and
+\f\*[B-Font]disable\f[]
+commands and also by remote
+configuration commands sent by a
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+\f\*[B-Font]auth\f[]
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+.sp \n(Ppu
+.ne 2
+
+An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+\fIAutomatic\f[] \fINTP\f[] \fIConfiguration\f[] \fIOptions\f[]
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+.sp \n(Ppu
+.ne 2
+
+The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+\f[C]http://www.ntp.org/\f[].
+.SS Symmetric-Key Cryptography
+The original RFC-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+\fIntp.keys\f[],
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+utility programs.
+.sp \n(Ppu
+.ne 2
+
+When
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+is first started, it reads the key file specified in the
+\f\*[B-Font]keys\f[]
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+\f\*[B-Font]trusted\f[]
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[].
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+\f\*[B-Font]requestkey\f[]
+command selects the key used as the password for the
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+utility, while the
+\f\*[B-Font]controlkey\f[]
+command selects the key used as the password for the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+utility.
+.SS Public Key Cryptography
+NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+.\" .Pp
+.\" The cryptographic means necessary for all Autokey operations
+.\" is provided by the OpenSSL software library.
+.\" This library is available from http://www.openssl.org/
+.\" and can be installed using the procedures outlined
+.\" in the Building and Installing the Distribution page.
+.\" Once installed,
+.\" the configure and build
+.\" process automatically detects the library and links
+.\" the library routines required.
+.sp \n(Ppu
+.ne 2
+
+The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S-KEY scheme,
+in which a pseudo-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+\fIAutonomous\f[] \fIAuthentication\f[]
+page.
+.sp \n(Ppu
+.ne 2
+
+The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+\fCntp-keygen\f[]\fR(1ntpkeygenmdoc)\f[]
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+\f\*[B-Font]md5WithRSAEncryption\f[],
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+.sp \n(Ppu
+.ne 2
+
+NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+.SS Naming and Addressing
+It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+.sp \n(Ppu
+.ne 2
+
+By convention, the name of an Autokey host is the name returned
+by the Unix
+\fCgethostname\f[]\fR(2)\f[]
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+.sp \n(Ppu
+.ne 2
+
+It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+.SS Operation
+A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+.sp \n(Ppu
+.ne 2
+
+The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+\f\*[B-Font]server\f[]
+or
+\f\*[B-Font]peer\f[]
+configuration command and no
+\f\*[B-Font]key\f[]
+or
+\f\*[B-Font]autokey\f[]
+subcommands are present, the association is not
+authenticated; if the
+\f\*[B-Font]key\f[]
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+\f\*[B-Font]autokey\f[]
+subcommand is present, the association is authenticated
+using Autokey.
+.sp \n(Ppu
+.ne 2
+
+When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+.sp \n(Ppu
+.ne 2
+
+Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+.sp \n(Ppu
+.ne 2
+
+Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto-NAK, which tells her
+something broke.
+She can see the evidence using the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+program.
+.sp \n(Ppu
+.ne 2
+
+Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+.sp \n(Ppu
+.ne 2
+
+It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+.SS Key Management
+The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+\fCntp-keygen\f[]\fR(1ntpkeygenmdoc)\f[]
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+.sp \n(Ppu
+.ne 2
+
+Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+\f\*[B-Font]trustRoot\f[];.
+Other extension fields are ignored.
+.SS Authentication Commands
+.TP 7
+.NOP \f\*[B-Font]autokey\f[] [\f\*[I-Font]logsec\f[]]
+Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+.TP 7
+.NOP \f\*[B-Font]controlkey\f[] \f\*[I-Font]key\f[]
+Specifies the key identifier to use with the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+utility, which uses the standard
+protocol defined in RFC-1305.
+The
+\f\*[I-Font]key\f[]
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+.TP 7
+.NOP \f\*[B-Font]crypto\f[] [\f\*[B-Font]cert\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]leap\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]randfile\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]host\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]sign\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gq\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gqpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]iffpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]mvpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]pw\f[] \f\*[I-Font]password\f[]]
+This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+\f\*[B-Font]keysdir\f[]
+command or default
+\fI/usr/local/etc\f[].
+Following are the subcommands:
+.RS
+.TP 7
+.NOP \f\*[B-Font]cert\f[] \f\*[I-Font]file\f[]
+Specifies the location of the required host public certificate file.
+This overrides the link
+\fIntpkey_cert_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]gqpar\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+\fIntpkey_gq_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]host\f[] \f\*[I-Font]file\f[]
+Specifies the location of the required host key file.
+This overrides
+the link
+\fIntpkey_key_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]iffpar\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional IFF parameters file.This
+overrides the link
+\fIntpkey_iff_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]leap\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional leapsecond file.
+This overrides the link
+\fIntpkey_leap\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]mvpar\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional MV parameters file.
+This
+overrides the link
+\fIntpkey_mv_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]pw\f[] \f\*[I-Font]password\f[]
+Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+.TP 7
+.NOP \f\*[B-Font]randfile\f[] \f\*[I-Font]file\f[]
+Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+.TP 7
+.NOP \f\*[B-Font]sign\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional sign key file.
+This overrides
+the link
+\fIntpkey_sign_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+.RE
+.TP 7
+.NOP \f\*[B-Font]keys\f[] \f\*[I-Font]keyfile\f[]
+Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+\fCntpd\f[]\fR(1ntpdmdoc)\f[],
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+when operating with symmetric key cryptography.
+This is the same operation as the
+\f\*[B-Font]\-k\f[]
+command line option.
+.TP 7
+.NOP \f\*[B-Font]keysdir\f[] \f\*[I-Font]path\f[]
+This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+\fI/usr/local/etc/\f[].
+.TP 7
+.NOP \f\*[B-Font]requestkey\f[] \f\*[I-Font]key\f[]
+Specifies the key identifier to use with the
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+utility program, which uses a
+proprietary protocol specific to this implementation of
+\fCntpd\f[]\fR(1ntpdmdoc)\f[].
+The
+\f\*[I-Font]key\f[]
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+.TP 7
+.NOP \f\*[B-Font]revoke\f[] \f\*[I-Font]logsec\f[]
+Specifies the interval between re-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+.TP 7
+.NOP \f\*[B-Font]trustedkey\f[] \f\*[I-Font]key\f[] \f\*[I-Font]...\f[]
+Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+\f\*[I-Font]key\f[]
+arguments are 32-bit unsigned
+integers with values from 1 to 65,534.
+.PP
+.SS Error Codes
+The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+.TP 7
+.NOP 101
+(bad field format or length)
+The packet has invalid version, length or format.
+.TP 7
+.NOP 102
+(bad timestamp)
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+.TP 7
+.NOP 103
+(bad filestamp)
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+.TP 7
+.NOP 104
+(bad or missing public key)
+The public key is missing, has incorrect format or is an unsupported type.
+.TP 7
+.NOP 105
+(unsupported digest type)
+The server requires an unsupported digest/signature scheme.
+.TP 7
+.NOP 106
+(mismatched digest types)
+Not used.
+.TP 7
+.NOP 107
+(bad signature length)
+The signature length does not match the current public key.
+.TP 7
+.NOP 108
+(signature not verified)
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+.TP 7
+.NOP 109
+(certificate not verified)
+The certificate is invalid or signed with the wrong key.
+.TP 7
+.NOP 110
+(certificate not verified)
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+.TP 7
+.NOP 111
+(bad or missing cookie)
+The cookie is missing, corrupted or bogus.
+.TP 7
+.NOP 112
+(bad or missing leapseconds table)
+The leapseconds table is missing, corrupted or bogus.
+.TP 7
+.NOP 113
+(bad or missing certificate)
+The certificate is missing, corrupted or bogus.
+.TP 7
+.NOP 114
+(bad or missing identity)
+The identity key is missing, corrupt or bogus.
+.PP
+.SH Monitoring Support
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+\f\*[B-Font]statistics\f[]
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+\fI./scripts\f[]
+directory of this distribution.
+Using
+these facilities and
+UNIX
+\fCcron\f[]\fR(8)\f[]
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+.SS Monitoring Commands
+.TP 7
+.NOP \f\*[B-Font]statistics\f[] \f\*[I-Font]name\f[] \f\*[I-Font]...\f[]
+Enables writing of statistics records.
+Currently, eight kinds of
+\f\*[I-Font]name\f[]
+statistics are supported.
+.RS
+.TP 7
+.NOP \f\*[B-Font]clockstats\f[]
+Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+\f\*[B-Font]clockstats\f[]:
+.br
+.in +4
+.nf
+49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+.TP 7
+.NOP \f\*[B-Font]cryptostats\f[]
+This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+\f\*[B-Font]cryptostats\f[]:
+.br
+.in +4
+.nf
+49213 525.624 127.127.4.1 message
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+\fIAuthentication\f[] \fIOptions\f[]
+section for further information.
+.TP 7
+.NOP \f\*[B-Font]loopstats\f[]
+Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+\f\*[B-Font]loopstats\f[]:
+.br
+.in +4
+.nf
+50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million \-
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+.TP 7
+.NOP \f\*[B-Font]peerstats\f[]
+Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+\f\*[B-Font]peerstats\f[]:
+.br
+.in +4
+.nf
+48773 10847.650 127.127.4.1 9714 \-0.001605376 0.000000000 0.001424877 0.000958674
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+.TP 7
+.NOP \f\*[B-Font]rawstats\f[]
+Enables recording of raw-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+\f\*[B-Font]rawstats\f[]:
+.br
+.in +4
+.nf
+50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+.TP 7
+.NOP \f\*[B-Font]sysstats\f[]
+Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+\f\*[B-Font]sysstats\f[]:
+.br
+.in +4
+.nf
+50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+.RS
+.TP 7
+.NOP Time since restart \f\*[B-Font]36000\f[]
+Time in hours since the system was last rebooted.
+.TP 7
+.NOP Packets received \f\*[B-Font]81965\f[]
+Total number of packets received.
+.TP 7
+.NOP Packets processed \f\*[B-Font]0\f[]
+Number of packets received in response to previous packets sent
+.TP 7
+.NOP Current version \f\*[B-Font]9546\f[]
+Number of packets matching the current NTP version.
+.TP 7
+.NOP Previous version \f\*[B-Font]56\f[]
+Number of packets matching the previous NTP version.
+.TP 7
+.NOP Bad version \f\*[B-Font]71793\f[]
+Number of packets matching neither NTP version.
+.TP 7
+.NOP Access denied \f\*[B-Font]512\f[]
+Number of packets denied access for any reason.
+.TP 7
+.NOP Bad length or format \f\*[B-Font]540\f[]
+Number of packets with invalid length, format or port number.
+.TP 7
+.NOP Bad authentication \f\*[B-Font]10\f[]
+Number of packets not verified as authentic.
+.TP 7
+.NOP Rate exceeded \f\*[B-Font]147\f[]
+Number of packets discarded due to rate limitation.
+.RE
+.TP 7
+.NOP \f\*[B-Font]statsdir\f[] \f\*[I-Font]directory_path\f[]
+Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+\f\*[B-Font]filegen\f[]
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+.TP 7
+.NOP \f\*[B-Font]filegen\f[] \f\*[I-Font]name\f[] [\f\*[B-Font]file\f[] \f\*[I-Font]filename\f[]] [\f\*[B-Font]type\f[] \f\*[I-Font]typename\f[]] [\f\*[B-Font]link\f[] | \f\*[B-Font]nolink\f[]] [\f\*[B-Font]enable\f[] | \f\*[B-Font]disable\f[]]
+Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+.sp \n(Ppu
+.ne 2
+
+Note that this command can be sent from the
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+program running at a remote location.
+.RS
+.TP 7
+.NOP \f\*[B-Font]name\f[]
+This is the type of the statistics records, as shown in the
+\f\*[B-Font]statistics\f[]
+command.
+.TP 7
+.NOP \f\*[B-Font]file\f[] \f\*[I-Font]filename\f[]
+This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+\f\*[B-Font]prefix\f[],
+\f\*[B-Font]filename\f[]
+and
+\f\*[B-Font]suffix\f[]:
+.RS
+.TP 7
+.NOP \f\*[B-Font]prefix\f[]
+This is a constant filename path.
+It is not subject to
+modifications via the
+\f\*[I-Font]filegen\f[]
+option.
+It is defined by the
+server, usually specified as a compile-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+\f\*[I-Font]loopstats\f[]
+and
+\f\*[I-Font]peerstats\f[]
+generation can be configured using the
+\f\*[I-Font]statsdir\f[]
+option explained above.
+.TP 7
+.NOP \f\*[B-Font]filename\f[]
+This string is directly concatenated to the prefix mentioned
+above (no intervening
+\[oq]/\[cq]).
+This can be modified using
+the file argument to the
+\f\*[I-Font]filegen\f[]
+statement.
+No
+\fI..\f[]
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+\f\*[I-Font]prefix\f[].
+.TP 7
+.NOP \f\*[B-Font]suffix\f[]
+This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+.RE
+.TP 7
+.NOP \f\*[B-Font]type\f[] \f\*[I-Font]typename\f[]
+A file generation set is characterized by its type.
+The following
+types are supported:
+.RS
+.TP 7
+.NOP \f\*[B-Font]none\f[]
+The file set is actually a single plain file.
+.TP 7
+.NOP \f\*[B-Font]pid\f[]
+One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+server incarnations.
+The set member filename is built by appending a
+\[oq]\&.\[cq]
+to concatenated
+\f\*[I-Font]prefix\f[]
+and
+\f\*[I-Font]filename\f[]
+strings, and
+appending the decimal representation of the process ID of the
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+server process.
+.TP 7
+.NOP \f\*[B-Font]day\f[]
+One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+\[oq]\&.\[cq]
+and a day specification in
+the form
+\f\*[B-Font]YYYYMMdd\f[].
+\f\*[B-Font]YYYY\f[]
+is a 4-digit year number (e.g., 1992).
+\f\*[B-Font]MM\f[]
+is a two digit month number.
+\f\*[B-Font]dd\f[]
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+\f\*[I-Font]prefix\f[]
+\f\*[I-Font]filename\f[].19921210.
+.TP 7
+.NOP \f\*[B-Font]week\f[]
+Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day-of-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4-digit year number, the letter
+\f\*[B-Font]W\f[],
+and a 2-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.NOP. \f\*[I-Font]1992W1\f[].
+.TP 7
+.NOP \f\*[B-Font]month\f[]
+One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4-digit year number, and
+a 2-digit month.
+.TP 7
+.NOP \f\*[B-Font]year\f[]
+One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+.TP 7
+.NOP \f\*[B-Font]age\f[]
+This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+\f\*[B-Font]a\f[],
+and an 8-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24-hour period.
+Information is only written to a file generation by specifying
+\f\*[B-Font]enable\f[];
+output is prevented by specifying
+\f\*[B-Font]disable\f[].
+.RE
+.TP 7
+.NOP \f\*[B-Font]link\f[] | \f\*[B-Font]nolink\f[]
+It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+\f\*[B-Font]link\f[]
+and disabled using
+\f\*[B-Font]nolink\f[].
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+\f\*[B-Font]C\f[],
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+.TP 7
+.NOP \f\*[B-Font]enable\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]disable\f[]
+Enables or disables the recording function.
+.RE
+.RE
+.PP
+.SH Access Control Support
+The
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+"Notes on Configuring NTP and Setting up a NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.sp \n(Ppu
+.ne 2
+
+The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+.sp \n(Ppu
+.ne 2
+
+Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+.SS The Kiss-of-Death Packet
+Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss-of-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four-byte
+ASCII code.
+If the
+\f\*[B-Font]noserve\f[]
+or
+\f\*[B-Font]notrust\f[]
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+\f\*[B-Font]limited\f[]
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+.sp \n(Ppu
+.ne 2
+
+A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+.SS Access Control Commands
+.TP 7
+.NOP \f\*[B-Font]discard\f[] [\f\*[B-Font]average\f[] \f\*[I-Font]avg\f[]] [\f\*[B-Font]minimum\f[] \f\*[I-Font]min\f[]] [\f\*[B-Font]monitor\f[] \f\*[I-Font]prob\f[]]
+Set the parameters of the
+\f\*[B-Font]limited\f[]
+facility which protects the server from
+client abuse.
+The
+\f\*[B-Font]average\f[]
+subcommand specifies the minimum average packet
+spacing, while the
+\f\*[B-Font]minimum\f[]
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss-o'-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate-control window.
+.TP 7
+.NOP \f\*[B-Font]restrict\f[] \f\*[B-Font]address\f[] [\f\*[B-Font]mask\f[] \f\*[I-Font]mask\f[]] [\f\*[I-Font]flag\f[] \f\*[I-Font]...\f[]]
+The
+\f\*[I-Font]address\f[]
+argument expressed in
+dotted-quad form is the address of a host or network.
+Alternatively, the
+\f\*[I-Font]address\f[]
+argument can be a valid host DNS name.
+The
+\f\*[I-Font]mask\f[]
+argument expressed in dotted-quad form defaults to
+\f\*[B-Font]255.255.255.255\f[],
+meaning that the
+\f\*[I-Font]address\f[]
+is treated as the address of an individual host.
+A default entry (address
+\f\*[B-Font]0.0.0.0\f[],
+mask
+\f\*[B-Font]0.0.0.0\f[])
+is always included and is always the first entry in the list.
+Note that text string
+\f\*[B-Font]default\f[],
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+\f\*[B-Font]flag\f[]
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+.RS
+.TP 7
+.NOP \f\*[B-Font]ignore\f[]
+Deny packets of all kinds, including
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+queries.
+.TP 7
+.NOP \f\*[B-Font]kod\f[]
+If this flag is set when an access violation occurs, a kiss-o'-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+.TP 7
+.NOP \f\*[B-Font]limited\f[]
+Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+\fCntpd\f[]\fR(1ntpdmdoc)\f[].
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+\f\*[B-Font]limited\f[]
+flag.
+.TP 7
+.NOP \f\*[B-Font]lowpriotrap\f[]
+Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+.TP 7
+.NOP \f\*[B-Font]nomodify\f[]
+Deny
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+.TP 7
+.NOP \f\*[B-Font]noquery\f[]
+Deny
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+queries.
+Time service is not affected.
+.TP 7
+.NOP \f\*[B-Font]nopeer\f[]
+Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+\f\*[B-Font]pool\f[]
+associations, so if you want to use servers from a
+\f\*[B-Font]pool\f[]
+directive and also want to use
+\f\*[B-Font]nopeer\f[]
+by default, you'll want a
+\f\*[B-Font]restrict source ...\f[] \f\*[B-Font]line\f[] \f\*[B-Font]as\f[] \f\*[B-Font]well\f[] \f\*[B-Font]that\f[] \f\*[B-Font]does\f[]
+.TP 7
+.NOP not
+include the
+\f\*[B-Font]nopeer\f[]
+directive.
+.TP 7
+.NOP \f\*[B-Font]noserve\f[]
+Deny all packets except
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+queries.
+.TP 7
+.NOP \f\*[B-Font]notrap\f[]
+Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+.TP 7
+.NOP \f\*[B-Font]notrust\f[]
+Deny service unless the packet is cryptographically authenticated.
+.TP 7
+.NOP \f\*[B-Font]ntpport\f[]
+This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+\f\*[B-Font]ntpport\f[]
+and
+\f\*[B-Font]non-ntpport\f[]
+may
+be specified.
+The
+\f\*[B-Font]ntpport\f[]
+is considered more specific and
+is sorted later in the list.
+.TP 7
+.NOP \f\*[B-Font]version\f[]
+Deny packets that do not match the current NTP version.
+.RE
+.sp \n(Ppu
+.ne 2
+
+Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+.PP
+.SH Automatic NTP Configuration Options
+.SS Manycasting
+Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+.sp \n(Ppu
+.ne 2
+
+Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+.sp \n(Ppu
+.ne 2
+
+Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+\f[C]http://www.openssl.org/\f[].
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+.sp \n(Ppu
+.ne 2
+
+A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+\f\*[B-Font]D\f[]
+or IPv6 prefix
+\f\*[B-Font]FF\f[])
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time-to-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+.sp \n(Ppu
+.ne 2
+
+Manycast servers configured with the
+\f\*[B-Font]manycastserver\f[]
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+.sp \n(Ppu
+.ne 2
+
+The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+.sp \n(Ppu
+.ne 2
+
+The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+\f\*[B-Font]manycastclient\f[],
+\f\*[B-Font]tos\f[]
+and
+\f\*[B-Font]ttl\f[]
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+\f\*[B-Font]minpoll\f[]
+value specified in the
+\f\*[B-Font]manycastclient\f[],
+command and, under normal circumstances, increments to the
+\f\*[B-Font]maxpolll\f[]
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+.sp \n(Ppu
+.ne 2
+
+The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+\f\*[B-Font]minclock\f[]
+and
+\f\*[B-Font]minsane\f[]
+values specified in the
+\f\*[B-Font]tos\f[]
+configuration command.
+At least
+\f\*[B-Font]minsane\f[]
+candidate servers must be available and the mitigation
+algorithms produce at least
+\f\*[B-Font]minclock\f[]
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+\f\*[B-Font]minsane\f[]
+defaults to 1 and
+\f\*[B-Font]minclock\f[]
+defaults to 3.
+For manycast service
+\f\*[B-Font]minsane\f[]
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+.sp \n(Ppu
+.ne 2
+
+If at least
+\f\*[B-Font]minclock\f[]
+servers are found, the manycast poll interval is immediately
+set to eight times
+\f\*[B-Font]maxpoll\f[].
+If less than
+\f\*[B-Font]minclock\f[]
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+\f\*[B-Font]maxpoll\f[].
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+.sp \n(Ppu
+.ne 2
+
+Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+\f\*[B-Font]ttl\f[]
+configuration command can be
+used to modify the values to match the scope rules.
+.sp \n(Ppu
+.ne 2
+
+It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+\f\*[B-Font]tos\f[]
+command can be used to modify this behavior.
+Servers with stratum below
+\f\*[B-Font]floor\f[]
+or above
+\f\*[B-Font]ceiling\f[]
+specified in the
+\f\*[B-Font]tos\f[]
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+\f\*[B-Font]minclock\f[].
+.sp \n(Ppu
+.ne 2
+
+The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+\f\*[B-Font]minclock\f[],
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+\f\*[B-Font]maxpoll\f[]
+is 12 (4,096 s).
+.sp \n(Ppu
+.ne 2
+
+It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+\f\*[B-Font]multicastclient\f[]
+and
+\f\*[B-Font]multicastserver\f[]
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+.sp \n(Ppu
+.ne 2
+
+The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+\f\*[B-Font]tos\f[]
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+\f\*[B-Font]floor\f[]
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+.sp \n(Ppu
+.ne 2
+
+Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re-associate accordingly.
+.sp \n(Ppu
+.ne 2
+
+Some administrators prefer to avoid running
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+continuously and run either
+\fCntpdate\f[]\fR(8)\f[]
+or
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+\f\*[B-Font]\-q\f[]
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+\f\*[B-Font]\-q\f[].
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+.SS Manycast Interactions with Autokey
+Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+.sp \n(Ppu
+.ne 2
+
+About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+.SS Manycast Options
+.TP 7
+.NOP \f\*[B-Font]tos\f[] [\f\*[B-Font]ceiling\f[] \f\*[I-Font]ceiling\f[] | \f\*[B-Font]cohort\f[] { \f\*[B-Font]0\f[] | \f\*[B-Font]1\f[] } | \f\*[B-Font]floor\f[] \f\*[I-Font]floor\f[] | \f\*[B-Font]minclock\f[] \f\*[I-Font]minclock\f[] | \f\*[B-Font]minsane\f[] \f\*[I-Font]minsane\f[]]
+This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]ceiling\f[] \f\*[I-Font]ceiling\f[]
+Peers with strata above
+\f\*[B-Font]ceiling\f[]
+will be discarded if there are at least
+\f\*[B-Font]minclock\f[]
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+.TP 7
+.NOP \f\*[B-Font]cohort\f[] {0 | 1 }
+This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+.TP 7
+.NOP \f\*[B-Font]floor\f[] \f\*[I-Font]floor\f[]
+Peers with strata below
+\f\*[B-Font]floor\f[]
+will be discarded if there are at least
+\f\*[B-Font]minclock\f[]
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+.TP 7
+.NOP \f\*[B-Font]minclock\f[] \f\*[I-Font]minclock\f[]
+The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+\f\*[B-Font]minclock\f[]
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+.TP 7
+.NOP \f\*[B-Font]minsane\f[] \f\*[I-Font]minsane\f[]
+This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+\f\*[B-Font]minsane\f[]
+should be at least 4 in order to detect and discard
+a single falseticker.
+.RE
+.TP 7
+.NOP \f\*[B-Font]ttl\f[] \f\*[I-Font]hop\f[] \f\*[I-Font]...\f[]
+This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding-ring search.
+The default is eight
+multiples of 32 starting at 31.
+.PP
+.SH Reference Clock Support
+The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+Additional information can be found in the pages linked
+there, including the
+"Debugging Hints for Reference Clock Drivers"
+and
+"How To Write a Reference Clock Driver"
+pages
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+In addition, support for a PPS
+signal is available as described in the
+"Pulse-per-second (PPS) Signal Interfacing"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+"Line Disciplines and Streams Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.sp \n(Ppu
+.ne 2
+
+A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+.sp \n(Ppu
+.ne 2
+
+For the purposes of configuration,
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+\f[C]127.127.\f[]\f\*[I-Font]t\f[].\f\*[I-Font]u\f[],
+where
+\f\*[I-Font]t\f[]
+is an integer
+denoting the clock type and
+\f\*[I-Font]u\f[]
+indicates the unit
+number in the range 0-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]server\f[]
+command is used to configure a reference
+clock, where the
+\f\*[I-Font]address\f[]
+argument in that command
+is the clock address.
+The
+\f\*[B-Font]key\f[],
+\f\*[B-Font]version\f[]
+and
+\f\*[B-Font]ttl\f[]
+options are not used for reference clock support.
+The
+\f\*[B-Font]mode\f[]
+option is added for reference clock support, as
+described below.
+The
+\f\*[B-Font]prefer\f[]
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+"Mitigation Rules and the prefer Keyword"
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+page.
+The
+\f\*[B-Font]minpoll\f[]
+and
+\f\*[B-Font]maxpoll\f[]
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]fudge\f[]
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+\f\*[B-Font]server\f[]
+command.
+The
+\f\*[I-Font]address\f[]
+argument specifies the clock address.
+The
+\f\*[B-Font]refid\f[]
+and
+\f\*[B-Font]stratum\f[]
+options can be used to
+override the defaults for the device.
+There are two optional
+device-dependent time offsets and four flags that can be included
+in the
+\f\*[B-Font]fudge\f[]
+command as well.
+.sp \n(Ppu
+.ne 2
+
+The stratum number of a reference clock is by default zero.
+Since the
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+\f\*[B-Font]stratum\f[]
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse-per-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+\f\*[B-Font]refid\f[]
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+.SS Reference Clock Commands
+.TP 7
+.NOP \f\*[B-Font]server\f[] \f[C]127.127.\f[]\f\*[I-Font]t\f[].\f\*[I-Font]u\f[] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]int\f[]]
+This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]prefer\f[]
+Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+for further information.
+.TP 7
+.NOP \f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.TP 7
+.NOP \f\*[B-Font]minpoll\f[] \f\*[I-Font]int\f[]
+.TP 7
+.NOP \f\*[B-Font]maxpoll\f[] \f\*[I-Font]int\f[]
+These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+\f\*[B-Font]minpoll\f[]
+and
+\f\*[B-Font]maxpoll\f[]
+default to 6 (64 s).
+For modem reference clocks,
+\f\*[B-Font]minpoll\f[]
+defaults to 10 (17.1 m) and
+\f\*[B-Font]maxpoll\f[]
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+.RE
+.TP 7
+.NOP \f\*[B-Font]fudge\f[] \f[C]127.127.\f[]\f\*[I-Font]t\f[].\f\*[I-Font]u\f[] [\f\*[B-Font]time1\f[] \f\*[I-Font]sec\f[]] [\f\*[B-Font]time2\f[] \f\*[I-Font]sec\f[]] [\f\*[B-Font]stratum\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]refid\f[] \f\*[I-Font]string\f[]] [\f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]flag1\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]] [\f\*[B-Font]flag2\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]] [\f\*[B-Font]flag3\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]] [\f\*[B-Font]flag4\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]]
+This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+\f\*[B-Font]server\f[]
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+program.
+The options are interpreted as
+follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]time1\f[] \f\*[I-Font]sec\f[]
+Specifies a constant to be added to the time offset produced by
+the driver, a fixed-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+\f\*[B-Font]enable\f[]
+command described in
+\fIMiscellaneous\f[] \fIOptions\f[]
+page and operates as described in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.TP 7
+.NOP \f\*[B-Font]time2\f[] \f\*[I-Font]secs\f[]
+Specifies a fixed-point decimal number in seconds, which is
+interpreted in a driver-dependent way.
+See the descriptions of
+specific drivers in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.TP 7
+.NOP \f\*[B-Font]stratum\f[] \f\*[I-Font]int\f[]
+Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+.TP 7
+.NOP \f\*[B-Font]refid\f[] \f\*[I-Font]string\f[]
+Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+.TP 7
+.NOP \f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.TP 7
+.NOP \f\*[B-Font]flag1\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+.TP 7
+.NOP \f\*[B-Font]flag2\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+.TP 7
+.NOP \f\*[B-Font]flag3\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+.TP 7
+.NOP \f\*[B-Font]flag4\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+\f\*[B-Font]flag4\f[]
+is used to enable recording monitoring
+data to the
+\f\*[B-Font]clockstats\f[]
+file configured with the
+\f\*[B-Font]filegen\f[]
+command.
+Further information on the
+\f\*[B-Font]filegen\f[]
+command can be found in
+\fIMonitoring\f[] \fIOptions\f[].
+.RE
+.PP
+.SH Miscellaneous Options
+.TP 7
+.NOP \f\*[B-Font]broadcastdelay\f[] \f\*[I-Font]seconds\f[]
+The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+.TP 7
+.NOP \f\*[B-Font]calldelay\f[] \f\*[I-Font]delay\f[]
+This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+.TP 7
+.NOP \f\*[B-Font]driftfile\f[] \f\*[I-Font]driftfile\f[]
+This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+\f\*[B-Font]\-f\f[]
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+.sp \n(Ppu
+.ne 2
+
+The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts-per-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+.TP 7
+.NOP \f\*[B-Font]dscp\f[] \f\*[I-Font]value\f[]
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6-bit code. The default value is 46, signifying Expedited Forwarding.
+.TP 7
+.NOP \f\*[B-Font]enable\f[] [\f\*[B-Font]auth\f[] | \f\*[B-Font]bclient\f[] | \f\*[B-Font]calibrate\f[] | \f\*[B-Font]kernel\f[] | \f\*[B-Font]mode7\f[] | \f\*[B-Font]monitor\f[] | \f\*[B-Font]ntp\f[] | \f\*[B-Font]stats\f[]]
+.TP 7
+.NOP \f\*[B-Font]disable\f[] [\f\*[B-Font]auth\f[] | \f\*[B-Font]bclient\f[] | \f\*[B-Font]calibrate\f[] | \f\*[B-Font]kernel\f[] | \f\*[B-Font]mode7\f[] | \f\*[B-Font]monitor\f[] | \f\*[B-Font]ntp\f[] | \f\*[B-Font]stats\f[]]
+Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+utility program.
+.RS
+.TP 7
+.NOP \f\*[B-Font]auth\f[]
+Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+\f\*[B-Font]enable\f[].
+.TP 7
+.NOP \f\*[B-Font]bclient\f[]
+Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+\f\*[B-Font]multicastclient\f[]
+command with default
+address.
+The default for this flag is
+\f\*[B-Font]disable\f[].
+.TP 7
+.NOP \f\*[B-Font]calibrate\f[]
+Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+\f\*[B-Font]disable\f[].
+.TP 7
+.NOP \f\*[B-Font]kernel\f[]
+Enables the kernel time discipline, if available.
+The default for this
+flag is
+\f\*[B-Font]enable\f[]
+if support is available, otherwise
+\f\*[B-Font]disable\f[].
+.TP 7
+.NOP \f\*[B-Font]mode7\f[]
+Enables processing of NTP mode 7 implementation-specific requests
+which are used by the deprecated
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+\fCntpq\f[]\fR(1ntpqmdoc)\f[].
+The
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+program provides the same capabilities as
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+using standard mode 6 requests.
+.TP 7
+.NOP \f\*[B-Font]monitor\f[]
+Enables the monitoring facility.
+See the
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+program
+and the
+\f\*[B-Font]monlist\f[]
+command or further information.
+The
+default for this flag is
+\f\*[B-Font]enable\f[].
+.TP 7
+.NOP \f\*[B-Font]ntp\f[]
+Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+\f\*[B-Font]enable\f[].
+.TP 7
+.NOP \f\*[B-Font]stats\f[]
+Enables the statistics facility.
+See the
+\fIMonitoring\f[] \fIOptions\f[]
+section for further information.
+The default for this flag is
+\f\*[B-Font]disable\f[].
+.RE
+.TP 7
+.NOP \f\*[B-Font]includefile\f[] \f\*[I-Font]includefile\f[]
+This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+.TP 7
+.NOP \f\*[B-Font]leapsmearinterval\f[] \f\*[I-Font]seconds\f[]
+This EXPERIMENTAL option is only available if
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+was built with the
+\f\*[B-Font]\--enable-leap-smear\f[]
+option to the
+\f\*[B-Font]configure\f[]
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+.TP 7
+.NOP \f\*[B-Font]logconfig\f[] \f\*[I-Font]configkeyword\f[]
+This command controls the amount and type of output written to
+the system
+\fCsyslog\f[]\fR(3)\f[]
+facility or the alternate
+\f\*[B-Font]logfile\f[]
+log file.
+By default, all output is turned on.
+All
+\f\*[I-Font]configkeyword\f[]
+keywords can be prefixed with
+\[oq]=\[cq],
+\[oq]+\[cq]
+and
+\[oq]\-\[cq],
+where
+\[oq]=\[cq]
+sets the
+\fCsyslog\f[]\fR(3)\f[]
+priority mask,
+\[oq]+\[cq]
+adds and
+\[oq]\-\[cq]
+removes
+messages.
+\fCsyslog\f[]\fR(3)\f[]
+messages can be controlled in four
+classes
+(\f\*[B-Font]clock\f[], \f\*[B-Font]peer\f[], \f\*[B-Font]sys\f[] and \f\*[B-Font]sync\f[]).
+Within these classes four types of messages can be
+controlled: informational messages
+(\f\*[B-Font]info\f[]),
+event messages
+(\f\*[B-Font]events\f[]),
+statistics messages
+(\f\*[B-Font]statistics\f[])
+and
+status messages
+(\f\*[B-Font]status\f[]).
+.sp \n(Ppu
+.ne 2
+
+Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+\f\*[B-Font]all\f[]
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+\f\*[B-Font]all\f[]
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+.br
+.in +4
+.nf
+logconfig =syncstatus +sysevents
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+This would just list the synchronizations state of
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+.br
+.in +4
+.nf
+logconfig =syncall +clockall
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+.TP 7
+.NOP \f\*[B-Font]logfile\f[] \f\*[I-Font]logfile\f[]
+This command specifies the location of an alternate log file to
+be used instead of the default system
+\fCsyslog\f[]\fR(3)\f[]
+facility.
+This is the same operation as the \-l command line option.
+.TP 7
+.NOP \f\*[B-Font]setvar\f[] \f\*[I-Font]variable\f[] [\f\*[B-Font]default\f[]]
+This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+\fIname\f[]\fI=\f[]\f\*[I-Font]value\f[]
+is followed by the
+\f\*[B-Font]default\f[]
+keyword, the
+variable will be listed as part of the default system variables
+(\fCntpq\f[]\fR(1ntpqmdoc)\f[] \f\*[B-Font]rv\f[] command)).
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+\f\*[B-Font]setvar\f[]
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+\fIsys_var_list\f[]
+holds
+the names of all system variables.
+The
+\fIpeer_var_list\f[]
+holds
+the names of all peer variables and the
+\fIclock_var_list\f[]
+holds the names of the reference clock variables.
+.TP 7
+.NOP \f\*[B-Font]tinker\f[] [\f\*[B-Font]allan\f[] \f\*[I-Font]allan\f[] | \f\*[B-Font]dispersion\f[] \f\*[I-Font]dispersion\f[] | \f\*[B-Font]freq\f[] \f\*[I-Font]freq\f[] | \f\*[B-Font]huffpuff\f[] \f\*[I-Font]huffpuff\f[] | \f\*[B-Font]panic\f[] \f\*[I-Font]panic\f[] | \f\*[B-Font]step\f[] \f\*[I-Font]step\f[] | \f\*[B-Font]stepback\f[] \f\*[I-Font]stepback\f[] | \f\*[B-Font]stepfwd\f[] \f\*[I-Font]stepfwd\f[] | \f\*[B-Font]stepout\f[] \f\*[I-Font]stepout\f[]]
+This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+.sp \n(Ppu
+.ne 2
+
+The variables operate as follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]allan\f[] \f\*[I-Font]allan\f[]
+The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+.TP 7
+.NOP \f\*[B-Font]dispersion\f[] \f\*[I-Font]dispersion\f[]
+The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+.TP 7
+.NOP \f\*[B-Font]freq\f[] \f\*[I-Font]freq\f[]
+The argument becomes the initial value of the frequency offset in
+parts-per-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+.TP 7
+.NOP \f\*[B-Font]huffpuff\f[] \f\*[I-Font]huffpuff\f[]
+The argument becomes the new value for the experimental
+huff-n'-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+.TP 7
+.NOP \f\*[B-Font]panic\f[] \f\*[I-Font]panic\f[]
+The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+.TP 7
+.NOP \f\*[B-Font]step\f[] \f\*[I-Font]step\f[]
+The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+.TP 7
+.NOP \f\*[B-Font]stepback\f[] \f\*[I-Font]stepback\f[]
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+.TP 7
+.NOP \f\*[B-Font]stepfwd\f[] \f\*[I-Font]stepfwd\f[]
+As for stepback, but for the forward direction.
+.TP 7
+.NOP \f\*[B-Font]stepout\f[] \f\*[I-Font]stepout\f[]
+The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+.RE
+.TP 7
+.NOP \f\*[B-Font]rlimit\f[] [\f\*[B-Font]memlock\f[] \f\*[I-Font]Nmegabytes\f[] | \f\*[B-Font]stacksize\f[] \f\*[I-Font]N4kPages\f[] \f\*[B-Font]filenum\f[] \f\*[I-Font]Nfiledescriptors\f[]]
+.RS
+.TP 7
+.NOP \f\*[B-Font]memlock\f[] \f\*[I-Font]Nmegabytes\f[]
+Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+\f\*[B-Font]\-i\f[]
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+.TP 7
+.NOP \f\*[B-Font]stacksize\f[] \f\*[I-Font]N4kPages\f[]
+Specifies the maximum size of the process stack on systems with the
+\fBmlockall\f[]\fR()\f[]
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+.TP 7
+.NOP \f\*[B-Font]filenum\f[] \f\*[I-Font]Nfiledescriptors\f[]
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+.RE
+.TP 7
+.NOP \f\*[B-Font]trap\f[] \f\*[I-Font]host_address\f[] [\f\*[B-Font]port\f[] \f\*[I-Font]port_number\f[]] [\f\*[B-Font]interface\f[] \f\*[I-Font]interface_address\f[]]
+This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+.sp \n(Ppu
+.ne 2
+
+The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+.TP 7
+.NOP \f\*[B-Font]hop\f[] \f\*[I-Font]...\f[]
+This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding-ring search.
+The default is eight multiples of 32 starting at
+31.
+.PP
+.SH "OPTIONS"
+.TP
+.NOP \f\*[B-Font]\-\-help\f[]
+Display usage information and exit.
+.TP
+.NOP \f\*[B-Font]\-\-more-help\f[]
+Pass the extended usage information through a pager.
+.TP
+.NOP \f\*[B-Font]\-\-version\f[] [{\f\*[I-Font]v|c|n\f[]}]
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.PP
+.SH "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTP_CONF_<option-name>\fP or \fBNTP_CONF\fP
+.fi
+.ad
+.SH "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.SH FILES
+.TP 15
+.NOP \fI/etc/ntp.conf\f[]
+the default name of the configuration file
+.br
+.ns
+.TP 15
+.NOP \fIntp.keys\f[]
+private MD5 keys
+.br
+.ns
+.TP 15
+.NOP \fIntpkey\f[]
+RSA private key
+.br
+.ns
+.TP 15
+.NOP \fIntpkey_\f[]\f\*[I-Font]host\f[]
+RSA public key
+.br
+.ns
+.TP 15
+.NOP \fIntp_dh\f[]
+Diffie-Hellman agreement parameters
+.PP
+.SH "EXIT STATUS"
+One of the following exit values will be returned:
+.TP
+.NOP 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.TP
+.NOP 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.TP
+.NOP 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+.PP
+.SH "SEE ALSO"
+\fCntpd\f[]\fR(1ntpdmdoc)\f[],
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[],
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+.sp \n(Ppu
+.ne 2
+
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+\f[C]http://www.ntp.org/\f[].
+A snapshot of this documentation is available in HTML format in
+\fI/usr/share/doc/ntp\f[].
+David L. Mills,
+\fINetwork Time Protocol (Version 4)\fR,
+RFC5905
+.PP
+
+.SH "AUTHORS"
+The University of Delaware and Network Time Foundation
+.SH "COPYRIGHT"
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.SH BUGS
+The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+.sp \n(Ppu
+.ne 2
+
+The
+\fIntpkey_\f[]\f\*[I-Font]host\f[]
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+.sp \n(Ppu
+.ne 2
+
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.SH NOTES
+This document was derived from FreeBSD.
+.sp \n(Ppu
+.ne 2
+
+This manual page was \fIAutoGen\fP-erated from the \fBntp.conf\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.conf.5mdoc b/contrib/ntp/ntpd/ntp.conf.5mdoc
new file mode 100644
index 0000000..938acf6
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.5mdoc
@@ -0,0 +1,2853 @@
+.Dd June 29 2015
+.Dt NTP_CONF 5mdoc File Formats
+.Os
+.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:36 PM by AutoGen 5.18.5
+.\" From the definitions ntp.conf.def
+.\" and the template file agmdoc-cmd.tpl
+.Sh NAME
+.Nm ntp.conf
+.Nd Network Time Protocol (NTP) daemon configuration file format
+.Sh SYNOPSIS
+.Nm
+.Op Fl \-option\-name
+.Op Fl \-option\-name Ar value
+.Pp
+All arguments must be options.
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+configuration file is read at initial startup by the
+.Xr ntpd 1ntpdmdoc
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+.Pa /etc
+directory,
+but could be installed elsewhere
+(see the daemon's
+.Fl c
+command line option).
+.Pp
+The file format is similar to other
+.Ux
+configuration files.
+Comments begin with a
+.Ql #
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted\-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+.Pp
+The rest of this page describes the configuration and control options.
+The
+.Qq Notes on Configuring NTP and Setting up an NTP Subnet
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+contains an extended discussion of these options.
+In addition to the discussion of general
+.Sx Configuration Options ,
+there are sections describing the following supported functionality
+and the options used to control it:
+.Bl -bullet -offset indent
+.It
+.Sx Authentication Support
+.It
+.Sx Monitoring Support
+.It
+.Sx Access Control Support
+.It
+.Sx Automatic NTP Configuration Options
+.It
+.Sx Reference Clock Support
+.It
+.Sx Miscellaneous Options
+.El
+.Pp
+Following these is a section describing
+.Sx Miscellaneous Options .
+While there is a rich set of options available,
+the only required option is one or more
+.Ic pool ,
+.Ic server ,
+.Ic peer ,
+.Ic broadcast
+or
+.Ic manycastclient
+commands.
+.Sh Configuration Support
+Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+.Ss Configuration Commands
+The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+.Pp
+If the Basic Socket Interface Extensions for IPv6 (RFC\-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+.Dq \&:
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+.Pp
+Note that in contexts where a host name is expected, a
+.Fl 4
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+.Fl 6
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+.Bl -tag -width indent
+.It Xo Ic pool Ar address
+.Op Cm burst
+.Op Cm iburst
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic server Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm burst
+.Op Cm iburst
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic peer Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic broadcast Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm ttl Ar ttl
+.Xc
+.It Xo Ic manycastclient Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Op Cm ttl Ar ttl
+.Xc
+.El
+.Pp
+These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+.Ar address
+can be
+either a DNS name or an IP address in dotted\-quad notation.
+Additional information on association behavior can be found in the
+.Qq Association Management
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Bl -tag -width indent
+.It Ic pool
+For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+.It Ic server
+For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+.Em not
+be used for type
+b or m addresses.
+.It Ic peer
+For type s addresses (only), this command mobilizes a
+persistent symmetric\-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+.It Ic broadcast
+For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+.Ar address
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+.Ic broadcastclient
+or
+.Ic multicastclient
+commands
+below.
+.It Ic manycastclient
+For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+.Ic manycastserver
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+.Ic manycastserver
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+.Ar address
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+.Ic server
+command.
+The remaining servers are discarded as if never
+heard.
+.El
+.Pp
+Options:
+.Bl -tag -width indent
+.It Cm autokey
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+.Sx Authentication Options .
+.It Cm burst
+when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+.Ic server
+command and s addresses.
+.It Cm iburst
+When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+.Ic server
+command and s addresses and when
+.Xr ntpd 1ntpdmdoc
+is started with the
+.Fl q
+option.
+.It Cm key Ar key
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+.Ar key
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+.It Cm minpoll Ar minpoll
+.It Cm maxpoll Ar maxpoll
+These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+.Cm maxpoll
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+.Cm minpoll
+option to a lower limit of 4 (16 s).
+.It Cm noselect
+Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+.It Cm prefer
+Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+.Qq Mitigation Rules and the prefer Keyword
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+for further information.
+.It Cm ttl Ar ttl
+This option is used only with broadcast server and manycast
+client modes.
+It specifies the time\-to\-live
+.Ar ttl
+to
+use on broadcast server and multicast server and the maximum
+.Ar ttl
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+.It Cm version Ar version
+Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1\-4 are the choices, with version 4 the
+default.
+.El
+.Ss Auxiliary Commands
+.Bl -tag -width indent
+.It Ic broadcastclient
+This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric\-key or public\-key
+authentication as described in
+.Sx Authentication Options .
+.It Ic manycastserver Ar address ...
+This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric\-key or public\-key
+authentication as described in
+.Sx Authentication Options .
+.It Ic multicastclient Ar address ...
+This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric\-key or
+public\-key authentication as described in
+.Sx Authentication Options .
+.It Ic mdnstries Ar number
+If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+.Ic mdnstries
+times.
+After all,
+.Ic ntpd
+may be starting before mDNS.
+The default value for
+.Ic mdnstries
+is 5.
+.El
+.Sh Authentication Support
+Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC\-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES\-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed\-MD5.
+Either algorithm computes a message digest, or one\-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+.Pp
+NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+.Pp
+While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+.Pp
+Authentication is configured separately for each association
+using the
+.Cm key
+or
+.Cm autokey
+subcommand on the
+.Ic peer ,
+.Ic server ,
+.Ic broadcast
+and
+.Ic manycastclient
+configuration commands as described in
+.Sx Configuration Options
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+.Pp
+Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+.Pp
+The
+.Cm auth
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+.Ic enable
+and
+.Ic disable
+commands and also by remote
+configuration commands sent by a
+.Xr ntpdc 1ntpdcmdoc
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+.Ic auth
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+.Pp
+An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+.Sx Automatic NTP Configuration Options
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+.Pp
+The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+.Li http://www.ntp.org/ .
+.Ss Symmetric\-Key Cryptography
+The original RFC\-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32\-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+.Pa ntp.keys ,
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+utility programs.
+.Pp
+When
+.Xr ntpd 1ntpdmdoc
+is first started, it reads the key file specified in the
+.Ic keys
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+.Ic trusted
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+.Xr ntpdc 1ntpdcmdoc .
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+.Ic requestkey
+command selects the key used as the password for the
+.Xr ntpdc 1ntpdcmdoc
+utility, while the
+.Ic controlkey
+command selects the key used as the password for the
+.Xr ntpq 1ntpqmdoc
+utility.
+.Ss Public Key Cryptography
+NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC\-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+.\" .Pp
+.\" The cryptographic means necessary for all Autokey operations
+.\" is provided by the OpenSSL software library.
+.\" This library is available from http://www.openssl.org/
+.\" and can be installed using the procedures outlined
+.\" in the Building and Installing the Distribution page.
+.\" Once installed,
+.\" the configure and build
+.\" process automatically detects the library and links
+.\" the library routines required.
+.Pp
+The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S\-KEY scheme,
+in which a pseudo\-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+.Sx Autonomous Authentication
+page.
+.Pp
+The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+.Xr ntp\-keygen 1ntpkeygenmdoc
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+.Cm md5WithRSAEncryption ,
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+.Pp
+NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+.Ss Naming and Addressing
+It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+.Pp
+By convention, the name of an Autokey host is the name returned
+by the Unix
+.Xr gethostname 2
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+.Pp
+It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+.Ss Operation
+A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+.Pp
+The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+.Ic server
+or
+.Ic peer
+configuration command and no
+.Ic key
+or
+.Ic autokey
+subcommands are present, the association is not
+authenticated; if the
+.Ic key
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+.Ic autokey
+subcommand is present, the association is authenticated
+using Autokey.
+.Pp
+When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+.Pp
+Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+.Pp
+Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto\-NAK, which tells her
+something broke.
+She can see the evidence using the
+.Xr ntpq 1ntpqmdoc
+program.
+.Pp
+Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+.Pp
+It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+.Ss Key Management
+The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+.Xr ntp\-keygen 1ntpkeygenmdoc
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+.Pp
+Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+.Cm trustRoot ; .
+Other extension fields are ignored.
+.Ss Authentication Commands
+.Bl -tag -width indent
+.It Ic autokey Op Ar logsec
+Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+.It Ic controlkey Ar key
+Specifies the key identifier to use with the
+.Xr ntpq 1ntpqmdoc
+utility, which uses the standard
+protocol defined in RFC\-1305.
+The
+.Ar key
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+.It Xo Ic crypto
+.Op Cm cert Ar file
+.Op Cm leap Ar file
+.Op Cm randfile Ar file
+.Op Cm host Ar file
+.Op Cm sign Ar file
+.Op Cm gq Ar file
+.Op Cm gqpar Ar file
+.Op Cm iffpar Ar file
+.Op Cm mvpar Ar file
+.Op Cm pw Ar password
+.Xc
+This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+.Ic keysdir
+command or default
+.Pa /usr/local/etc .
+Following are the subcommands:
+.Bl -tag -width indent
+.It Cm cert Ar file
+Specifies the location of the required host public certificate file.
+This overrides the link
+.Pa ntpkey_cert_ Ns Ar hostname
+in the keys directory.
+.It Cm gqpar Ar file
+Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+.Pa ntpkey_gq_ Ns Ar hostname
+in the keys directory.
+.It Cm host Ar file
+Specifies the location of the required host key file.
+This overrides
+the link
+.Pa ntpkey_key_ Ns Ar hostname
+in the keys directory.
+.It Cm iffpar Ar file
+Specifies the location of the optional IFF parameters file.This
+overrides the link
+.Pa ntpkey_iff_ Ns Ar hostname
+in the keys directory.
+.It Cm leap Ar file
+Specifies the location of the optional leapsecond file.
+This overrides the link
+.Pa ntpkey_leap
+in the keys directory.
+.It Cm mvpar Ar file
+Specifies the location of the optional MV parameters file.
+This
+overrides the link
+.Pa ntpkey_mv_ Ns Ar hostname
+in the keys directory.
+.It Cm pw Ar password
+Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+.It Cm randfile Ar file
+Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+.It Cm sign Ar file
+Specifies the location of the optional sign key file.
+This overrides
+the link
+.Pa ntpkey_sign_ Ns Ar hostname
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+.El
+.It Ic keys Ar keyfile
+Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+.Xr ntpd 1ntpdmdoc ,
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+when operating with symmetric key cryptography.
+This is the same operation as the
+.Fl k
+command line option.
+.It Ic keysdir Ar path
+This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+.Pa /usr/local/etc/ .
+.It Ic requestkey Ar key
+Specifies the key identifier to use with the
+.Xr ntpdc 1ntpdcmdoc
+utility program, which uses a
+proprietary protocol specific to this implementation of
+.Xr ntpd 1ntpdmdoc .
+The
+.Ar key
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+.It Ic revoke Ar logsec
+Specifies the interval between re\-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute\-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+.It Ic trustedkey Ar key ...
+Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+.Ar key
+arguments are 32\-bit unsigned
+integers with values from 1 to 65,534.
+.El
+.Ss Error Codes
+The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+.Bl -tag -width indent
+.It 101
+.Pq bad field format or length
+The packet has invalid version, length or format.
+.It 102
+.Pq bad timestamp
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+.It 103
+.Pq bad filestamp
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+.It 104
+.Pq bad or missing public key
+The public key is missing, has incorrect format or is an unsupported type.
+.It 105
+.Pq unsupported digest type
+The server requires an unsupported digest/signature scheme.
+.It 106
+.Pq mismatched digest types
+Not used.
+.It 107
+.Pq bad signature length
+The signature length does not match the current public key.
+.It 108
+.Pq signature not verified
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+.It 109
+.Pq certificate not verified
+The certificate is invalid or signed with the wrong key.
+.It 110
+.Pq certificate not verified
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+.It 111
+.Pq bad or missing cookie
+The cookie is missing, corrupted or bogus.
+.It 112
+.Pq bad or missing leapseconds table
+The leapseconds table is missing, corrupted or bogus.
+.It 113
+.Pq bad or missing certificate
+The certificate is missing, corrupted or bogus.
+.It 114
+.Pq bad or missing identity
+The identity key is missing, corrupt or bogus.
+.El
+.Sh Monitoring Support
+.Xr ntpd 1ntpdmdoc
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+.Ic statistics
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+.Pa ./scripts
+directory of this distribution.
+Using
+these facilities and
+.Ux
+.Xr cron 8
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+.Ss Monitoring Commands
+.Bl -tag -width indent
+.It Ic statistics Ar name ...
+Enables writing of statistics records.
+Currently, eight kinds of
+.Ar name
+statistics are supported.
+.Bl -tag -width indent
+.It Cm clockstats
+Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+.Cm clockstats :
+.Bd -literal
+49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted\-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+.It Cm cryptostats
+This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+.Cm cryptostats :
+.Bd -literal
+49213 525.624 127.127.4.1 message
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted\-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+.Sx Authentication Options
+section for further information.
+.It Cm loopstats
+Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+.Cm loopstats :
+.Bd -literal
+50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million \-
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+.It Cm peerstats
+Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+.Cm peerstats :
+.Bd -literal
+48773 10847.650 127.127.4.1 9714 \-0.001605376 0.000000000 0.001424877 0.000958674
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted\-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+.It Cm rawstats
+Enables recording of raw\-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+.Cm rawstats :
+.Bd -literal
+50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted\-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+.It Cm sysstats
+Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+.Cm sysstats :
+.Bd -literal
+50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+.Bl -tag -width indent
+.It Time since restart Cm 36000
+Time in hours since the system was last rebooted.
+.It Packets received Cm 81965
+Total number of packets received.
+.It Packets processed Cm 0
+Number of packets received in response to previous packets sent
+.It Current version Cm 9546
+Number of packets matching the current NTP version.
+.It Previous version Cm 56
+Number of packets matching the previous NTP version.
+.It Bad version Cm 71793
+Number of packets matching neither NTP version.
+.It Access denied Cm 512
+Number of packets denied access for any reason.
+.It Bad length or format Cm 540
+Number of packets with invalid length, format or port number.
+.It Bad authentication Cm 10
+Number of packets not verified as authentic.
+.It Rate exceeded Cm 147
+Number of packets discarded due to rate limitation.
+.El
+.It Cm statsdir Ar directory_path
+Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+.Cm filegen
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+.It Cm filegen Ar name Xo
+.Op Cm file Ar filename
+.Op Cm type Ar typename
+.Op Cm link | nolink
+.Op Cm enable | disable
+.Xc
+Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+.Pp
+Note that this command can be sent from the
+.Xr ntpdc 1ntpdcmdoc
+program running at a remote location.
+.Bl -tag -width indent
+.It Cm name
+This is the type of the statistics records, as shown in the
+.Cm statistics
+command.
+.It Cm file Ar filename
+This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+.Ar Cm prefix ,
+.Ar Cm filename
+and
+.Ar Cm suffix :
+.Bl -tag -width indent
+.It Cm prefix
+This is a constant filename path.
+It is not subject to
+modifications via the
+.Ar filegen
+option.
+It is defined by the
+server, usually specified as a compile\-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+.Ar loopstats
+and
+.Ar peerstats
+generation can be configured using the
+.Ar statsdir
+option explained above.
+.It Cm filename
+This string is directly concatenated to the prefix mentioned
+above (no intervening
+.Ql / ) .
+This can be modified using
+the file argument to the
+.Ar filegen
+statement.
+No
+.Pa ..
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+.Ar prefix .
+.It Cm suffix
+This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+.El
+.It Cm type Ar typename
+A file generation set is characterized by its type.
+The following
+types are supported:
+.Bl -tag -width indent
+.It Cm none
+The file set is actually a single plain file.
+.It Cm pid
+One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+.Xr ntpd 1ntpdmdoc
+server incarnations.
+The set member filename is built by appending a
+.Ql \&.
+to concatenated
+.Ar prefix
+and
+.Ar filename
+strings, and
+appending the decimal representation of the process ID of the
+.Xr ntpd 1ntpdmdoc
+server process.
+.It Cm day
+One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+.Ql \&.
+and a day specification in
+the form
+.Cm YYYYMMdd .
+.Cm YYYY
+is a 4\-digit year number (e.g., 1992).
+.Cm MM
+is a two digit month number.
+.Cm dd
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+.Ar prefix
+.Ar filename Ns .19921210 .
+.It Cm week
+Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day\-of\-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4\-digit year number, the letter
+.Cm W ,
+and a 2\-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.No . Ns Ar 1992W1 .
+.It Cm month
+One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4\-digit year number, and
+a 2\-digit month.
+.It Cm year
+One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+.It Cm age
+This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+.Cm a ,
+and an 8\-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24\-hour period.
+Information is only written to a file generation by specifying
+.Cm enable ;
+output is prevented by specifying
+.Cm disable .
+.El
+.It Cm link | nolink
+It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+.Cm link
+and disabled using
+.Cm nolink .
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+.Cm C ,
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+.It Cm enable \&| Cm disable
+Enables or disables the recording function.
+.El
+.El
+.El
+.Sh Access Control Support
+The
+.Xr ntpd 1ntpdmdoc
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+.Qq Notes on Configuring NTP and Setting up a NTP Subnet
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Pp
+The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+.Pp
+Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+.Ss The Kiss\-of\-Death Packet
+Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss\-of\-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four\-byte
+ASCII code.
+If the
+.Cm noserve
+or
+.Cm notrust
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+.Cm limited
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+.Pp
+A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+.Ss Access Control Commands
+.Bl -tag -width indent
+.It Xo Ic discard
+.Op Cm average Ar avg
+.Op Cm minimum Ar min
+.Op Cm monitor Ar prob
+.Xc
+Set the parameters of the
+.Cm limited
+facility which protects the server from
+client abuse.
+The
+.Cm average
+subcommand specifies the minimum average packet
+spacing, while the
+.Cm minimum
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss\-o'\-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate\-control window.
+.It Xo Ic restrict address
+.Op Cm mask Ar mask
+.Op Ar flag ...
+.Xc
+The
+.Ar address
+argument expressed in
+dotted\-quad form is the address of a host or network.
+Alternatively, the
+.Ar address
+argument can be a valid host DNS name.
+The
+.Ar mask
+argument expressed in dotted\-quad form defaults to
+.Cm 255.255.255.255 ,
+meaning that the
+.Ar address
+is treated as the address of an individual host.
+A default entry (address
+.Cm 0.0.0.0 ,
+mask
+.Cm 0.0.0.0 )
+is always included and is always the first entry in the list.
+Note that text string
+.Cm default ,
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+.Cm flag
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run\-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+.Bl -tag -width indent
+.It Cm ignore
+Deny packets of all kinds, including
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries.
+.It Cm kod
+If this flag is set when an access violation occurs, a kiss\-o'\-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+.It Cm limited
+Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+.Xr ntpd 1ntpdmdoc .
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+.Cm limited
+flag.
+.It Cm lowpriotrap
+Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+.It Cm nomodify
+Deny
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+.It Cm noquery
+Deny
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries.
+Time service is not affected.
+.It Cm nopeer
+Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+.Cm pool
+associations, so if you want to use servers from a
+.Cm pool
+directive and also want to use
+.Cm nopeer
+by default, you'll want a
+.Cm "restrict source ..." line as well that does
+.It not
+include the
+.Cm nopeer
+directive.
+.It Cm noserve
+Deny all packets except
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries.
+.It Cm notrap
+Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+.It Cm notrust
+Deny service unless the packet is cryptographically authenticated.
+.It Cm ntpport
+This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+.Cm ntpport
+and
+.Cm non\-ntpport
+may
+be specified.
+The
+.Cm ntpport
+is considered more specific and
+is sorted later in the list.
+.It Cm version
+Deny packets that do not match the current NTP version.
+.El
+.Pp
+Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+.El
+.Sh Automatic NTP Configuration Options
+.Ss Manycasting
+Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+.Pp
+Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC\-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+.Pp
+Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+.Li http://www.openssl.org/ .
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+.Pp
+A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+.Cm D
+or IPv6 prefix
+.Cm FF )
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time\-to\-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+.Pp
+Manycast servers configured with the
+.Ic manycastserver
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+.Pp
+The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2\-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+.Pp
+The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near\-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+.Ic manycastclient ,
+.Ic tos
+and
+.Ic ttl
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+.Cm minpoll
+value specified in the
+.Ic manycastclient ,
+command and, under normal circumstances, increments to the
+.Cm maxpolll
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+.Pp
+The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+.Cm minclock
+and
+.Cm minsane
+values specified in the
+.Ic tos
+configuration command.
+At least
+.Cm minsane
+candidate servers must be available and the mitigation
+algorithms produce at least
+.Cm minclock
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+.Cm minsane
+defaults to 1 and
+.Cm minclock
+defaults to 3.
+For manycast service
+.Cm minsane
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+.Pp
+If at least
+.Cm minclock
+servers are found, the manycast poll interval is immediately
+set to eight times
+.Cm maxpoll .
+If less than
+.Cm minclock
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+.Cm maxpoll .
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+.Pp
+Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+.Ic ttl
+configuration command can be
+used to modify the values to match the scope rules.
+.Pp
+It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+.Ic tos
+command can be used to modify this behavior.
+Servers with stratum below
+.Cm floor
+or above
+.Cm ceiling
+specified in the
+.Ic tos
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+.Cm minclock .
+.Pp
+The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+.Cm minclock ,
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+.Cm maxpoll
+is 12 (4,096 s).
+.Pp
+It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+.Ic multicastclient
+and
+.Ic multicastserver
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+.Pp
+The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+.Ic tos
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+.Cm floor
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+.Pp
+Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re\-associate accordingly.
+.Pp
+Some administrators prefer to avoid running
+.Xr ntpd 1ntpdmdoc
+continuously and run either
+.Xr ntpdate 8
+or
+.Xr ntpd 1ntpdmdoc
+.Fl q
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+.Xr ntpd 1ntpdmdoc
+.Fl q .
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+.Ss Manycast Interactions with Autokey
+Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+.Pp
+About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+.Ss Manycast Options
+.Bl -tag -width indent
+.It Xo Ic tos
+.Oo
+.Cm ceiling Ar ceiling |
+.Cm cohort { 0 | 1 } |
+.Cm floor Ar floor |
+.Cm minclock Ar minclock |
+.Cm minsane Ar minsane
+.Oc
+.Xc
+This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+.Bl -tag -width indent
+.It Cm ceiling Ar ceiling
+Peers with strata above
+.Cm ceiling
+will be discarded if there are at least
+.Cm minclock
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+.It Cm cohort Bro 0 | 1 Brc
+This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+.It Cm floor Ar floor
+Peers with strata below
+.Cm floor
+will be discarded if there are at least
+.Cm minclock
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+.It Cm minclock Ar minclock
+The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+.Cm minclock
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+.It Cm minsane Ar minsane
+This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+.Cm minsane
+should be at least 4 in order to detect and discard
+a single falseticker.
+.El
+.It Cm ttl Ar hop ...
+This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding\-ring search.
+The default is eight
+multiples of 32 starting at 31.
+.El
+.Sh Reference Clock Support
+The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo\-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+Additional information can be found in the pages linked
+there, including the
+.Qq Debugging Hints for Reference Clock Drivers
+and
+.Qq How To Write a Reference Clock Driver
+pages
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+In addition, support for a PPS
+signal is available as described in the
+.Qq Pulse\-per\-second (PPS) Signal Interfacing
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+.Qq Line Disciplines and Streams Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Pp
+A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+.Pp
+For the purposes of configuration,
+.Xr ntpd 1ntpdmdoc
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+.Sm off
+.Li 127.127. Ar t . Ar u ,
+.Sm on
+where
+.Ar t
+is an integer
+denoting the clock type and
+.Ar u
+indicates the unit
+number in the range 0\-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+.Pp
+The
+.Ic server
+command is used to configure a reference
+clock, where the
+.Ar address
+argument in that command
+is the clock address.
+The
+.Cm key ,
+.Cm version
+and
+.Cm ttl
+options are not used for reference clock support.
+The
+.Cm mode
+option is added for reference clock support, as
+described below.
+The
+.Cm prefer
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+.Qq Mitigation Rules and the prefer Keyword
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+page.
+The
+.Cm minpoll
+and
+.Cm maxpoll
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+.Pp
+The
+.Ic fudge
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+.Ic server
+command.
+The
+.Ar address
+argument specifies the clock address.
+The
+.Cm refid
+and
+.Cm stratum
+options can be used to
+override the defaults for the device.
+There are two optional
+device\-dependent time offsets and four flags that can be included
+in the
+.Ic fudge
+command as well.
+.Pp
+The stratum number of a reference clock is by default zero.
+Since the
+.Xr ntpd 1ntpdmdoc
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+.Cm stratum
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse\-per\-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+.Cm refid
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+.Ss Reference Clock Commands
+.Bl -tag -width indent
+.It Xo Ic server
+.Sm off
+.Li 127.127. Ar t . Ar u
+.Sm on
+.Op Cm prefer
+.Op Cm mode Ar int
+.Op Cm minpoll Ar int
+.Op Cm maxpoll Ar int
+.Xc
+This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+.Bl -tag -width indent
+.It Cm prefer
+Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+.Qq Mitigation Rules and the prefer Keyword
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+for further information.
+.It Cm mode Ar int
+Specifies a mode number which is interpreted in a
+device\-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.It Cm minpoll Ar int
+.It Cm maxpoll Ar int
+These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+.Cm minpoll
+and
+.Cm maxpoll
+default to 6 (64 s).
+For modem reference clocks,
+.Cm minpoll
+defaults to 10 (17.1 m) and
+.Cm maxpoll
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+.El
+.It Xo Ic fudge
+.Sm off
+.Li 127.127. Ar t . Ar u
+.Sm on
+.Op Cm time1 Ar sec
+.Op Cm time2 Ar sec
+.Op Cm stratum Ar int
+.Op Cm refid Ar string
+.Op Cm mode Ar int
+.Op Cm flag1 Cm 0 \&| Cm 1
+.Op Cm flag2 Cm 0 \&| Cm 1
+.Op Cm flag3 Cm 0 \&| Cm 1
+.Op Cm flag4 Cm 0 \&| Cm 1
+.Xc
+This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+.Ic server
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+.Xr ntpdc 1ntpdcmdoc
+program.
+The options are interpreted as
+follows:
+.Bl -tag -width indent
+.It Cm time1 Ar sec
+Specifies a constant to be added to the time offset produced by
+the driver, a fixed\-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+.Ic enable
+command described in
+.Sx Miscellaneous Options
+page and operates as described in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.It Cm time2 Ar secs
+Specifies a fixed\-point decimal number in seconds, which is
+interpreted in a driver\-dependent way.
+See the descriptions of
+specific drivers in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.It Cm stratum Ar int
+Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+.It Cm refid Ar string
+Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+.It Cm mode Ar int
+Specifies a mode number which is interpreted in a
+device\-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.It Cm flag1 Cm 0 \&| Cm 1
+.It Cm flag2 Cm 0 \&| Cm 1
+.It Cm flag3 Cm 0 \&| Cm 1
+.It Cm flag4 Cm 0 \&| Cm 1
+These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+.Cm flag4
+is used to enable recording monitoring
+data to the
+.Cm clockstats
+file configured with the
+.Ic filegen
+command.
+Further information on the
+.Ic filegen
+command can be found in
+.Sx Monitoring Options .
+.El
+.El
+.Sh Miscellaneous Options
+.Bl -tag -width indent
+.It Ic broadcastdelay Ar seconds
+The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+.It Ic calldelay Ar delay
+This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+.It Ic driftfile Ar driftfile
+This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+.Fl f
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+.Pp
+The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts\-per\-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+.Xr ntpd 1ntpdmdoc
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+.It Ic dscp Ar value
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6\-bit code. The default value is 46, signifying Expedited Forwarding.
+.It Xo Ic enable
+.Oo
+.Cm auth | Cm bclient |
+.Cm calibrate | Cm kernel |
+.Cm mode7 | monitor |
+.Cm ntp | Cm stats
+.Oc
+.Xc
+.It Xo Ic disable
+.Oo
+.Cm auth | Cm bclient |
+.Cm calibrate | Cm kernel |
+.Cm mode7 | monitor |
+.Cm ntp | Cm stats
+.Oc
+.Xc
+Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+.Xr ntpdc 1ntpdcmdoc
+utility program.
+.Bl -tag -width indent
+.It Cm auth
+Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+.Ic enable .
+.It Cm bclient
+Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+.Ic multicastclient
+command with default
+address.
+The default for this flag is
+.Ic disable .
+.It Cm calibrate
+Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+.Ic disable .
+.It Cm kernel
+Enables the kernel time discipline, if available.
+The default for this
+flag is
+.Ic enable
+if support is available, otherwise
+.Ic disable .
+.It Cm mode7
+Enables processing of NTP mode 7 implementation\-specific requests
+which are used by the deprecated
+.Xr ntpdc 1ntpdcmdoc
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+.Xr ntpq 1ntpqmdoc .
+The
+.Xr ntpq 1ntpqmdoc
+program provides the same capabilities as
+.Xr ntpdc 1ntpdcmdoc
+using standard mode 6 requests.
+.It Cm monitor
+Enables the monitoring facility.
+See the
+.Xr ntpdc 1ntpdcmdoc
+program
+and the
+.Ic monlist
+command or further information.
+The
+default for this flag is
+.Ic enable .
+.It Cm ntp
+Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+.Ic enable .
+.It Cm stats
+Enables the statistics facility.
+See the
+.Sx Monitoring Options
+section for further information.
+The default for this flag is
+.Ic disable .
+.El
+.It Ic includefile Ar includefile
+This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+.Xr ntpd 1ntpdmdoc
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+.It Ic leapsmearinterval Ar seconds
+This EXPERIMENTAL option is only available if
+.Xr ntpd 1ntpdmdoc
+was built with the
+.Cm \-\-enable\-leap\-smear
+option to the
+.Cm configure
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC\-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+.It Ic logconfig Ar configkeyword
+This command controls the amount and type of output written to
+the system
+.Xr syslog 3
+facility or the alternate
+.Ic logfile
+log file.
+By default, all output is turned on.
+All
+.Ar configkeyword
+keywords can be prefixed with
+.Ql = ,
+.Ql +
+and
+.Ql \- ,
+where
+.Ql =
+sets the
+.Xr syslog 3
+priority mask,
+.Ql +
+adds and
+.Ql \-
+removes
+messages.
+.Xr syslog 3
+messages can be controlled in four
+classes
+.Po
+.Cm clock ,
+.Cm peer ,
+.Cm sys
+and
+.Cm sync
+.Pc .
+Within these classes four types of messages can be
+controlled: informational messages
+.Po
+.Cm info
+.Pc ,
+event messages
+.Po
+.Cm events
+.Pc ,
+statistics messages
+.Po
+.Cm statistics
+.Pc
+and
+status messages
+.Po
+.Cm status
+.Pc .
+.Pp
+Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+.Cm all
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+.Cm all
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+.Bd -literal
+logconfig =syncstatus +sysevents
+.Ed
+.Pp
+This would just list the synchronizations state of
+.Xr ntpd 1ntpdmdoc
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+.Bd -literal
+logconfig =syncall +clockall
+.Ed
+.Pp
+This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+.It Ic logfile Ar logfile
+This command specifies the location of an alternate log file to
+be used instead of the default system
+.Xr syslog 3
+facility.
+This is the same operation as the \-l command line option.
+.It Ic setvar Ar variable Op Cm default
+This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+.Sm off
+.Va name = Ar value
+.Sm on
+is followed by the
+.Cm default
+keyword, the
+variable will be listed as part of the default system variables
+.Po
+.Xr ntpq 1ntpqmdoc
+.Ic rv
+command
+.Pc ) .
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+.Ic setvar
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+.Va sys_var_list
+holds
+the names of all system variables.
+The
+.Va peer_var_list
+holds
+the names of all peer variables and the
+.Va clock_var_list
+holds the names of the reference clock variables.
+.It Xo Ic tinker
+.Oo
+.Cm allan Ar allan |
+.Cm dispersion Ar dispersion |
+.Cm freq Ar freq |
+.Cm huffpuff Ar huffpuff |
+.Cm panic Ar panic |
+.Cm step Ar step |
+.Cm stepback Ar stepback |
+.Cm stepfwd Ar stepfwd |
+.Cm stepout Ar stepout
+.Oc
+.Xc
+This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+.Pp
+The variables operate as follows:
+.Bl -tag -width indent
+.It Cm allan Ar allan
+The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+.It Cm dispersion Ar dispersion
+The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+.It Cm freq Ar freq
+The argument becomes the initial value of the frequency offset in
+parts\-per\-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+.It Cm huffpuff Ar huffpuff
+The argument becomes the new value for the experimental
+huff\-n'\-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+.It Cm panic Ar panic
+The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+.It Cm step Ar step
+The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+.It Cm stepback Ar stepback
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+.It Cm stepfwd Ar stepfwd
+As for stepback, but for the forward direction.
+.It Cm stepout Ar stepout
+The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+.El
+.It Xo Ic rlimit
+.Oo
+.Cm memlock Ar Nmegabytes |
+.Cm stacksize Ar N4kPages
+.Cm filenum Ar Nfiledescriptors
+.Oc
+.Xc
+.Bl -tag -width indent
+.It Cm memlock Ar Nmegabytes
+Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+.Fl i
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+.It Cm stacksize Ar N4kPages
+Specifies the maximum size of the process stack on systems with the
+.Fn mlockall
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+.It Cm filenum Ar Nfiledescriptors
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+.El
+.It Xo Ic trap Ar host_address
+.Op Cm port Ar port_number
+.Op Cm interface Ar interface_address
+.Xc
+This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+.Pp
+The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+.It Cm hop Ar ...
+This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding\-ring search.
+The default is eight multiples of 32 starting at
+31.
+.El
+.Sh "OPTIONS"
+.Bl -tag
+.It Fl \-help
+Display usage information and exit.
+.It Fl \-more\-help
+Pass the extended usage information through a pager.
+.It Fl \-version Op Brq Ar v|c|n
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.El
+.Sh "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTP_CONF_<option\-name>\fP or \fBNTP_CONF\fP
+.fi
+.ad
+.Sh "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.Sh FILES
+.Bl -tag -width /etc/ntp.drift -compact
+.It Pa /etc/ntp.conf
+the default name of the configuration file
+.It Pa ntp.keys
+private MD5 keys
+.It Pa ntpkey
+RSA private key
+.It Pa ntpkey_ Ns Ar host
+RSA public key
+.It Pa ntp_dh
+Diffie\-Hellman agreement parameters
+.El
+.Sh "EXIT STATUS"
+One of the following exit values will be returned:
+.Bl -tag
+.It 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.It 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.It 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen\-users@lists.sourceforge.net. Thank you.
+.El
+.Sh "SEE ALSO"
+.Xr ntpd 1ntpdmdoc ,
+.Xr ntpdc 1ntpdcmdoc ,
+.Xr ntpq 1ntpqmdoc
+.Pp
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+.Li http://www.ntp.org/ .
+A snapshot of this documentation is available in HTML format in
+.Pa /usr/share/doc/ntp .
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 4)
+.%O RFC5905
+.Re
+.Sh "AUTHORS"
+The University of Delaware and Network Time Foundation
+.Sh "COPYRIGHT"
+Copyright (C) 1992\-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.Sh BUGS
+The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+.Pp
+The
+.Pa ntpkey_ Ns Ar host
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+.Pp
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.Sh NOTES
+This document was derived from FreeBSD.
+.Pp
+This manual page was \fIAutoGen\fP\-erated from the \fBntp.conf\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.conf.def b/contrib/ntp/ntpd/ntp.conf.def
new file mode 100644
index 0000000..7e09c03
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.def
@@ -0,0 +1,2840 @@
+/* -*- Mode: Text -*- */
+
+autogen definitions options;
+
+#include copyright.def
+
+// We want the synopsis to be "/etc/ntp.conf" but we need the prog-name
+// to be ntp.conf - the latter is also how autogen produces the output
+// file name.
+prog-name = "ntp.conf";
+file-path = "/etc/ntp.conf";
+prog-title = "Network Time Protocol (NTP) daemon configuration file format";
+
+/* explain: Additional information whenever the usage routine is invoked */
+explain = <<- _END_EXPLAIN
+ _END_EXPLAIN;
+
+doc-section = {
+ ds-type = 'DESCRIPTION';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_PROG_MDOC_DESCRIP
+The
+.Nm
+configuration file is read at initial startup by the
+.Xr ntpd 1ntpdmdoc
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+.Pa /etc
+directory,
+but could be installed elsewhere
+(see the daemon's
+.Fl c
+command line option).
+.Pp
+The file format is similar to other
+.Ux
+configuration files.
+Comments begin with a
+.Ql #
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+.Pp
+The rest of this page describes the configuration and control options.
+The
+.Qq Notes on Configuring NTP and Setting up an NTP Subnet
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+contains an extended discussion of these options.
+In addition to the discussion of general
+.Sx Configuration Options ,
+there are sections describing the following supported functionality
+and the options used to control it:
+.Bl -bullet -offset indent
+.It
+.Sx Authentication Support
+.It
+.Sx Monitoring Support
+.It
+.Sx Access Control Support
+.It
+.Sx Automatic NTP Configuration Options
+.It
+.Sx Reference Clock Support
+.It
+.Sx Miscellaneous Options
+.El
+.Pp
+Following these is a section describing
+.Sx Miscellaneous Options .
+While there is a rich set of options available,
+the only required option is one or more
+.Ic pool ,
+.Ic server ,
+.Ic peer ,
+.Ic broadcast
+or
+.Ic manycastclient
+commands.
+.Sh Configuration Support
+Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+.Ss Configuration Commands
+The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+.Pp
+If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+.Dq \&:
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+.Pp
+Note that in contexts where a host name is expected, a
+.Fl 4
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+.Fl 6
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+.Bl -tag -width indent
+.It Xo Ic pool Ar address
+.Op Cm burst
+.Op Cm iburst
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic server Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm burst
+.Op Cm iburst
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic peer Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic broadcast Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm ttl Ar ttl
+.Xc
+.It Xo Ic manycastclient Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Op Cm ttl Ar ttl
+.Xc
+.El
+.Pp
+These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+.Ar address
+can be
+either a DNS name or an IP address in dotted-quad notation.
+Additional information on association behavior can be found in the
+.Qq Association Management
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Bl -tag -width indent
+.It Ic pool
+For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+.It Ic server
+For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+.Em not
+be used for type
+b or m addresses.
+.It Ic peer
+For type s addresses (only), this command mobilizes a
+persistent symmetric-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+.It Ic broadcast
+For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+.Ar address
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+.Ic broadcastclient
+or
+.Ic multicastclient
+commands
+below.
+.It Ic manycastclient
+For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+.Ic manycastserver
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+.Ic manycastserver
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+.Ar address
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+.Ic server
+command.
+The remaining servers are discarded as if never
+heard.
+.El
+.Pp
+Options:
+.Bl -tag -width indent
+.It Cm autokey
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+.Sx Authentication Options .
+.It Cm burst
+when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+.Ic server
+command and s addresses.
+.It Cm iburst
+When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+.Ic server
+command and s addresses and when
+.Xr ntpd 1ntpdmdoc
+is started with the
+.Fl q
+option.
+.It Cm key Ar key
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+.Ar key
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+.It Cm minpoll Ar minpoll
+.It Cm maxpoll Ar maxpoll
+These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+.Cm maxpoll
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+.Cm minpoll
+option to a lower limit of 4 (16 s).
+.It Cm noselect
+Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+.It Cm prefer
+Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+.Qq Mitigation Rules and the prefer Keyword
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+for further information.
+.It Cm ttl Ar ttl
+This option is used only with broadcast server and manycast
+client modes.
+It specifies the time-to-live
+.Ar ttl
+to
+use on broadcast server and multicast server and the maximum
+.Ar ttl
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+.It Cm version Ar version
+Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1-4 are the choices, with version 4 the
+default.
+.El
+.Ss Auxiliary Commands
+.Bl -tag -width indent
+.It Ic broadcastclient
+This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric-key or public-key
+authentication as described in
+.Sx Authentication Options .
+.It Ic manycastserver Ar address ...
+This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric-key or public-key
+authentication as described in
+.Sx Authentication Options .
+.It Ic multicastclient Ar address ...
+This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric-key or
+public-key authentication as described in
+.Sx Authentication Options .
+.It Ic mdnstries Ar number
+If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+.Ic mdnstries
+times.
+After all,
+.Ic ntpd
+may be starting before mDNS.
+The default value for
+.Ic mdnstries
+is 5.
+.El
+.Sh Authentication Support
+Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed-MD5.
+Either algorithm computes a message digest, or one-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+.Pp
+NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+.Pp
+While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+.Pp
+Authentication is configured separately for each association
+using the
+.Cm key
+or
+.Cm autokey
+subcommand on the
+.Ic peer ,
+.Ic server ,
+.Ic broadcast
+and
+.Ic manycastclient
+configuration commands as described in
+.Sx Configuration Options
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+.Pp
+Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+.Pp
+The
+.Cm auth
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+.Ic enable
+and
+.Ic disable
+commands and also by remote
+configuration commands sent by a
+.Xr ntpdc 1ntpdcmdoc
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+.Ic auth
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+.Pp
+An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+.Sx Automatic NTP Configuration Options
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+.Pp
+The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+.Li http://www.ntp.org/ .
+.Ss Symmetric-Key Cryptography
+The original RFC-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+.Pa ntp.keys ,
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+utility programs.
+.Pp
+When
+.Xr ntpd 1ntpdmdoc
+is first started, it reads the key file specified in the
+.Ic keys
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+.Ic trusted
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+.Xr ntpdc 1ntpdcmdoc .
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+.Ic requestkey
+command selects the key used as the password for the
+.Xr ntpdc 1ntpdcmdoc
+utility, while the
+.Ic controlkey
+command selects the key used as the password for the
+.Xr ntpq 1ntpqmdoc
+utility.
+.Ss Public Key Cryptography
+NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+.\" .Pp
+.\" The cryptographic means necessary for all Autokey operations
+.\" is provided by the OpenSSL software library.
+.\" This library is available from http://www.openssl.org/
+.\" and can be installed using the procedures outlined
+.\" in the Building and Installing the Distribution page.
+.\" Once installed,
+.\" the configure and build
+.\" process automatically detects the library and links
+.\" the library routines required.
+.Pp
+The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S-KEY scheme,
+in which a pseudo-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+.Sx Autonomous Authentication
+page.
+.Pp
+The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+.Xr ntp-keygen 1ntpkeygenmdoc
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+.Cm md5WithRSAEncryption ,
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+.Pp
+NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+.Ss Naming and Addressing
+It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+.Pp
+By convention, the name of an Autokey host is the name returned
+by the Unix
+.Xr gethostname 2
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+.Pp
+It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+.Ss Operation
+A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+.Pp
+The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+.Ic server
+or
+.Ic peer
+configuration command and no
+.Ic key
+or
+.Ic autokey
+subcommands are present, the association is not
+authenticated; if the
+.Ic key
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+.Ic autokey
+subcommand is present, the association is authenticated
+using Autokey.
+.Pp
+When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+.Pp
+Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+.Pp
+Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto-NAK, which tells her
+something broke.
+She can see the evidence using the
+.Xr ntpq 1ntpqmdoc
+program.
+.Pp
+Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+.Pp
+It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+.Ss Key Management
+The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+.Xr ntp-keygen 1ntpkeygenmdoc
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+.Pp
+Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+.Cm trustRoot ; .
+Other extension fields are ignored.
+.Ss Authentication Commands
+.Bl -tag -width indent
+.It Ic autokey Op Ar logsec
+Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+.It Ic controlkey Ar key
+Specifies the key identifier to use with the
+.Xr ntpq 1ntpqmdoc
+utility, which uses the standard
+protocol defined in RFC-1305.
+The
+.Ar key
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+.It Xo Ic crypto
+.Op Cm cert Ar file
+.Op Cm leap Ar file
+.Op Cm randfile Ar file
+.Op Cm host Ar file
+.Op Cm sign Ar file
+.Op Cm gq Ar file
+.Op Cm gqpar Ar file
+.Op Cm iffpar Ar file
+.Op Cm mvpar Ar file
+.Op Cm pw Ar password
+.Xc
+This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+.Ic keysdir
+command or default
+.Pa /usr/local/etc .
+Following are the subcommands:
+.Bl -tag -width indent
+.It Cm cert Ar file
+Specifies the location of the required host public certificate file.
+This overrides the link
+.Pa ntpkey_cert_ Ns Ar hostname
+in the keys directory.
+.It Cm gqpar Ar file
+Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+.Pa ntpkey_gq_ Ns Ar hostname
+in the keys directory.
+.It Cm host Ar file
+Specifies the location of the required host key file.
+This overrides
+the link
+.Pa ntpkey_key_ Ns Ar hostname
+in the keys directory.
+.It Cm iffpar Ar file
+Specifies the location of the optional IFF parameters file.This
+overrides the link
+.Pa ntpkey_iff_ Ns Ar hostname
+in the keys directory.
+.It Cm leap Ar file
+Specifies the location of the optional leapsecond file.
+This overrides the link
+.Pa ntpkey_leap
+in the keys directory.
+.It Cm mvpar Ar file
+Specifies the location of the optional MV parameters file.
+This
+overrides the link
+.Pa ntpkey_mv_ Ns Ar hostname
+in the keys directory.
+.It Cm pw Ar password
+Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+.It Cm randfile Ar file
+Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+.It Cm sign Ar file
+Specifies the location of the optional sign key file.
+This overrides
+the link
+.Pa ntpkey_sign_ Ns Ar hostname
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+.El
+.It Ic keys Ar keyfile
+Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+.Xr ntpd 1ntpdmdoc ,
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+when operating with symmetric key cryptography.
+This is the same operation as the
+.Fl k
+command line option.
+.It Ic keysdir Ar path
+This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+.Pa /usr/local/etc/ .
+.It Ic requestkey Ar key
+Specifies the key identifier to use with the
+.Xr ntpdc 1ntpdcmdoc
+utility program, which uses a
+proprietary protocol specific to this implementation of
+.Xr ntpd 1ntpdmdoc .
+The
+.Ar key
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+.It Ic revoke Ar logsec
+Specifies the interval between re-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+.It Ic trustedkey Ar key ...
+Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+.Ar key
+arguments are 32-bit unsigned
+integers with values from 1 to 65,534.
+.El
+.Ss Error Codes
+The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+.Bl -tag -width indent
+.It 101
+.Pq bad field format or length
+The packet has invalid version, length or format.
+.It 102
+.Pq bad timestamp
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+.It 103
+.Pq bad filestamp
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+.It 104
+.Pq bad or missing public key
+The public key is missing, has incorrect format or is an unsupported type.
+.It 105
+.Pq unsupported digest type
+The server requires an unsupported digest/signature scheme.
+.It 106
+.Pq mismatched digest types
+Not used.
+.It 107
+.Pq bad signature length
+The signature length does not match the current public key.
+.It 108
+.Pq signature not verified
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+.It 109
+.Pq certificate not verified
+The certificate is invalid or signed with the wrong key.
+.It 110
+.Pq certificate not verified
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+.It 111
+.Pq bad or missing cookie
+The cookie is missing, corrupted or bogus.
+.It 112
+.Pq bad or missing leapseconds table
+The leapseconds table is missing, corrupted or bogus.
+.It 113
+.Pq bad or missing certificate
+The certificate is missing, corrupted or bogus.
+.It 114
+.Pq bad or missing identity
+The identity key is missing, corrupt or bogus.
+.El
+.Sh Monitoring Support
+.Xr ntpd 1ntpdmdoc
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+.Ic statistics
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+.Pa ./scripts
+directory of this distribution.
+Using
+these facilities and
+.Ux
+.Xr cron 8
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+.Ss Monitoring Commands
+.Bl -tag -width indent
+.It Ic statistics Ar name ...
+Enables writing of statistics records.
+Currently, eight kinds of
+.Ar name
+statistics are supported.
+.Bl -tag -width indent
+.It Cm clockstats
+Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+.Cm clockstats :
+.Bd -literal
+49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+.It Cm cryptostats
+This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+.Cm cryptostats :
+.Bd -literal
+49213 525.624 127.127.4.1 message
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+.Sx Authentication Options
+section for further information.
+.It Cm loopstats
+Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+.Cm loopstats :
+.Bd -literal
+50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million -
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+.It Cm peerstats
+Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+.Cm peerstats :
+.Bd -literal
+48773 10847.650 127.127.4.1 9714 -0.001605376 0.000000000 0.001424877 0.000958674
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+.It Cm rawstats
+Enables recording of raw-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+.Cm rawstats :
+.Bd -literal
+50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+.It Cm sysstats
+Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+.Cm sysstats :
+.Bd -literal
+50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+.Bl -tag -width indent
+.It Time since restart Cm 36000
+Time in hours since the system was last rebooted.
+.It Packets received Cm 81965
+Total number of packets received.
+.It Packets processed Cm 0
+Number of packets received in response to previous packets sent
+.It Current version Cm 9546
+Number of packets matching the current NTP version.
+.It Previous version Cm 56
+Number of packets matching the previous NTP version.
+.It Bad version Cm 71793
+Number of packets matching neither NTP version.
+.It Access denied Cm 512
+Number of packets denied access for any reason.
+.It Bad length or format Cm 540
+Number of packets with invalid length, format or port number.
+.It Bad authentication Cm 10
+Number of packets not verified as authentic.
+.It Rate exceeded Cm 147
+Number of packets discarded due to rate limitation.
+.El
+.It Cm statsdir Ar directory_path
+Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+.Cm filegen
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+.It Cm filegen Ar name Xo
+.Op Cm file Ar filename
+.Op Cm type Ar typename
+.Op Cm link | nolink
+.Op Cm enable | disable
+.Xc
+Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+.Pp
+Note that this command can be sent from the
+.Xr ntpdc 1ntpdcmdoc
+program running at a remote location.
+.Bl -tag -width indent
+.It Cm name
+This is the type of the statistics records, as shown in the
+.Cm statistics
+command.
+.It Cm file Ar filename
+This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+.Ar Cm prefix ,
+.Ar Cm filename
+and
+.Ar Cm suffix :
+.Bl -tag -width indent
+.It Cm prefix
+This is a constant filename path.
+It is not subject to
+modifications via the
+.Ar filegen
+option.
+It is defined by the
+server, usually specified as a compile-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+.Ar loopstats
+and
+.Ar peerstats
+generation can be configured using the
+.Ar statsdir
+option explained above.
+.It Cm filename
+This string is directly concatenated to the prefix mentioned
+above (no intervening
+.Ql / ) .
+This can be modified using
+the file argument to the
+.Ar filegen
+statement.
+No
+.Pa ..
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+.Ar prefix .
+.It Cm suffix
+This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+.El
+.It Cm type Ar typename
+A file generation set is characterized by its type.
+The following
+types are supported:
+.Bl -tag -width indent
+.It Cm none
+The file set is actually a single plain file.
+.It Cm pid
+One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+.Xr ntpd 1ntpdmdoc
+server incarnations.
+The set member filename is built by appending a
+.Ql \&.
+to concatenated
+.Ar prefix
+and
+.Ar filename
+strings, and
+appending the decimal representation of the process ID of the
+.Xr ntpd 1ntpdmdoc
+server process.
+.It Cm day
+One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+.Ql \&.
+and a day specification in
+the form
+.Cm YYYYMMdd .
+.Cm YYYY
+is a 4-digit year number (e.g., 1992).
+.Cm MM
+is a two digit month number.
+.Cm dd
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+.Ar prefix
+.Ar filename Ns .19921210 .
+.It Cm week
+Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day-of-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4-digit year number, the letter
+.Cm W ,
+and a 2-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.No . Ns Ar 1992W1 .
+.It Cm month
+One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4-digit year number, and
+a 2-digit month.
+.It Cm year
+One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+.It Cm age
+This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+.Cm a ,
+and an 8-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24-hour period.
+Information is only written to a file generation by specifying
+.Cm enable ;
+output is prevented by specifying
+.Cm disable .
+.El
+.It Cm link | nolink
+It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+.Cm link
+and disabled using
+.Cm nolink .
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+.Cm C ,
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+.It Cm enable \&| Cm disable
+Enables or disables the recording function.
+.El
+.El
+.El
+.Sh Access Control Support
+The
+.Xr ntpd 1ntpdmdoc
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+.Qq Notes on Configuring NTP and Setting up a NTP Subnet
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Pp
+The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+.Pp
+Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+.Ss The Kiss-of-Death Packet
+Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss-of-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four-byte
+ASCII code.
+If the
+.Cm noserve
+or
+.Cm notrust
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+.Cm limited
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+.Pp
+A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+.Ss Access Control Commands
+.Bl -tag -width indent
+.It Xo Ic discard
+.Op Cm average Ar avg
+.Op Cm minimum Ar min
+.Op Cm monitor Ar prob
+.Xc
+Set the parameters of the
+.Cm limited
+facility which protects the server from
+client abuse.
+The
+.Cm average
+subcommand specifies the minimum average packet
+spacing, while the
+.Cm minimum
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss-o'-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate-control window.
+.It Xo Ic restrict address
+.Op Cm mask Ar mask
+.Op Ar flag ...
+.Xc
+The
+.Ar address
+argument expressed in
+dotted-quad form is the address of a host or network.
+Alternatively, the
+.Ar address
+argument can be a valid host DNS name.
+The
+.Ar mask
+argument expressed in dotted-quad form defaults to
+.Cm 255.255.255.255 ,
+meaning that the
+.Ar address
+is treated as the address of an individual host.
+A default entry (address
+.Cm 0.0.0.0 ,
+mask
+.Cm 0.0.0.0 )
+is always included and is always the first entry in the list.
+Note that text string
+.Cm default ,
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+.Cm flag
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+.Bl -tag -width indent
+.It Cm ignore
+Deny packets of all kinds, including
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries.
+.It Cm kod
+If this flag is set when an access violation occurs, a kiss-o'-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+.It Cm limited
+Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+.Xr ntpd 1ntpdmdoc .
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+.Cm limited
+flag.
+.It Cm lowpriotrap
+Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+.It Cm nomodify
+Deny
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+.It Cm noquery
+Deny
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries.
+Time service is not affected.
+.It Cm nopeer
+Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+.Cm pool
+associations, so if you want to use servers from a
+.Cm pool
+directive and also want to use
+.Cm nopeer
+by default, you'll want a
+.Cm "restrict source ..." line as well that does
+.It not
+include the
+.Cm nopeer
+directive.
+.It Cm noserve
+Deny all packets except
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+queries.
+.It Cm notrap
+Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+.It Cm notrust
+Deny service unless the packet is cryptographically authenticated.
+.It Cm ntpport
+This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+.Cm ntpport
+and
+.Cm non-ntpport
+may
+be specified.
+The
+.Cm ntpport
+is considered more specific and
+is sorted later in the list.
+.It Cm version
+Deny packets that do not match the current NTP version.
+.El
+.Pp
+Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+.El
+.Sh Automatic NTP Configuration Options
+.Ss Manycasting
+Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+.Pp
+Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+.Pp
+Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+.Li http://www.openssl.org/ .
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+.Pp
+A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+.Cm D
+or IPv6 prefix
+.Cm FF )
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time-to-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+.Pp
+Manycast servers configured with the
+.Ic manycastserver
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+.Pp
+The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+.Pp
+The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+.Ic manycastclient ,
+.Ic tos
+and
+.Ic ttl
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+.Cm minpoll
+value specified in the
+.Ic manycastclient ,
+command and, under normal circumstances, increments to the
+.Cm maxpolll
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+.Pp
+The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+.Cm minclock
+and
+.Cm minsane
+values specified in the
+.Ic tos
+configuration command.
+At least
+.Cm minsane
+candidate servers must be available and the mitigation
+algorithms produce at least
+.Cm minclock
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+.Cm minsane
+defaults to 1 and
+.Cm minclock
+defaults to 3.
+For manycast service
+.Cm minsane
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+.Pp
+If at least
+.Cm minclock
+servers are found, the manycast poll interval is immediately
+set to eight times
+.Cm maxpoll .
+If less than
+.Cm minclock
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+.Cm maxpoll .
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+.Pp
+Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+.Ic ttl
+configuration command can be
+used to modify the values to match the scope rules.
+.Pp
+It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+.Ic tos
+command can be used to modify this behavior.
+Servers with stratum below
+.Cm floor
+or above
+.Cm ceiling
+specified in the
+.Ic tos
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+.Cm minclock .
+.Pp
+The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+.Cm minclock ,
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+.Cm maxpoll
+is 12 (4,096 s).
+.Pp
+It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+.Ic multicastclient
+and
+.Ic multicastserver
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+.Pp
+The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+.Ic tos
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+.Cm floor
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+.Pp
+Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re-associate accordingly.
+.Pp
+Some administrators prefer to avoid running
+.Xr ntpd 1ntpdmdoc
+continuously and run either
+.Xr ntpdate 8
+or
+.Xr ntpd 1ntpdmdoc
+.Fl q
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+.Xr ntpd 1ntpdmdoc
+.Fl q .
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+.Ss Manycast Interactions with Autokey
+Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+.Pp
+About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+.Ss Manycast Options
+.Bl -tag -width indent
+.It Xo Ic tos
+.Oo
+.Cm ceiling Ar ceiling |
+.Cm cohort { 0 | 1 } |
+.Cm floor Ar floor |
+.Cm minclock Ar minclock |
+.Cm minsane Ar minsane
+.Oc
+.Xc
+This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+.Bl -tag -width indent
+.It Cm ceiling Ar ceiling
+Peers with strata above
+.Cm ceiling
+will be discarded if there are at least
+.Cm minclock
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+.It Cm cohort Bro 0 | 1 Brc
+This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+.It Cm floor Ar floor
+Peers with strata below
+.Cm floor
+will be discarded if there are at least
+.Cm minclock
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+.It Cm minclock Ar minclock
+The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+.Cm minclock
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+.It Cm minsane Ar minsane
+This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+.Cm minsane
+should be at least 4 in order to detect and discard
+a single falseticker.
+.El
+.It Cm ttl Ar hop ...
+This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding-ring search.
+The default is eight
+multiples of 32 starting at 31.
+.El
+.Sh Reference Clock Support
+The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+Additional information can be found in the pages linked
+there, including the
+.Qq Debugging Hints for Reference Clock Drivers
+and
+.Qq How To Write a Reference Clock Driver
+pages
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+In addition, support for a PPS
+signal is available as described in the
+.Qq Pulse-per-second (PPS) Signal Interfacing
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+.Qq Line Disciplines and Streams Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Pp
+A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+.Pp
+For the purposes of configuration,
+.Xr ntpd 1ntpdmdoc
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+.Sm off
+.Li 127.127. Ar t . Ar u ,
+.Sm on
+where
+.Ar t
+is an integer
+denoting the clock type and
+.Ar u
+indicates the unit
+number in the range 0-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+.Pp
+The
+.Ic server
+command is used to configure a reference
+clock, where the
+.Ar address
+argument in that command
+is the clock address.
+The
+.Cm key ,
+.Cm version
+and
+.Cm ttl
+options are not used for reference clock support.
+The
+.Cm mode
+option is added for reference clock support, as
+described below.
+The
+.Cm prefer
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+.Qq Mitigation Rules and the prefer Keyword
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+page.
+The
+.Cm minpoll
+and
+.Cm maxpoll
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+.Pp
+The
+.Ic fudge
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+.Ic server
+command.
+The
+.Ar address
+argument specifies the clock address.
+The
+.Cm refid
+and
+.Cm stratum
+options can be used to
+override the defaults for the device.
+There are two optional
+device-dependent time offsets and four flags that can be included
+in the
+.Ic fudge
+command as well.
+.Pp
+The stratum number of a reference clock is by default zero.
+Since the
+.Xr ntpd 1ntpdmdoc
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+.Cm stratum
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse-per-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+.Cm refid
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+.Ss Reference Clock Commands
+.Bl -tag -width indent
+.It Xo Ic server
+.Sm off
+.Li 127.127. Ar t . Ar u
+.Sm on
+.Op Cm prefer
+.Op Cm mode Ar int
+.Op Cm minpoll Ar int
+.Op Cm maxpoll Ar int
+.Xc
+This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+.Bl -tag -width indent
+.It Cm prefer
+Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+.Qq Mitigation Rules and the prefer Keyword
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+for further information.
+.It Cm mode Ar int
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.It Cm minpoll Ar int
+.It Cm maxpoll Ar int
+These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+.Cm minpoll
+and
+.Cm maxpoll
+default to 6 (64 s).
+For modem reference clocks,
+.Cm minpoll
+defaults to 10 (17.1 m) and
+.Cm maxpoll
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+.El
+.It Xo Ic fudge
+.Sm off
+.Li 127.127. Ar t . Ar u
+.Sm on
+.Op Cm time1 Ar sec
+.Op Cm time2 Ar sec
+.Op Cm stratum Ar int
+.Op Cm refid Ar string
+.Op Cm mode Ar int
+.Op Cm flag1 Cm 0 \&| Cm 1
+.Op Cm flag2 Cm 0 \&| Cm 1
+.Op Cm flag3 Cm 0 \&| Cm 1
+.Op Cm flag4 Cm 0 \&| Cm 1
+.Xc
+This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+.Ic server
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+.Xr ntpdc 1ntpdcmdoc
+program.
+The options are interpreted as
+follows:
+.Bl -tag -width indent
+.It Cm time1 Ar sec
+Specifies a constant to be added to the time offset produced by
+the driver, a fixed-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+.Ic enable
+command described in
+.Sx Miscellaneous Options
+page and operates as described in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.It Cm time2 Ar secs
+Specifies a fixed-point decimal number in seconds, which is
+interpreted in a driver-dependent way.
+See the descriptions of
+specific drivers in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.It Cm stratum Ar int
+Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+.It Cm refid Ar string
+Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+.It Cm mode Ar int
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.It Cm flag1 Cm 0 \&| Cm 1
+.It Cm flag2 Cm 0 \&| Cm 1
+.It Cm flag3 Cm 0 \&| Cm 1
+.It Cm flag4 Cm 0 \&| Cm 1
+These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+.Cm flag4
+is used to enable recording monitoring
+data to the
+.Cm clockstats
+file configured with the
+.Ic filegen
+command.
+Further information on the
+.Ic filegen
+command can be found in
+.Sx Monitoring Options .
+.El
+.El
+.Sh Miscellaneous Options
+.Bl -tag -width indent
+.It Ic broadcastdelay Ar seconds
+The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+.It Ic calldelay Ar delay
+This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+.It Ic driftfile Ar driftfile
+This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+.Fl f
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+.Pp
+The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts-per-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+.Xr ntpd 1ntpdmdoc
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+.It Ic dscp Ar value
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6-bit code. The default value is 46, signifying Expedited Forwarding.
+.It Xo Ic enable
+.Oo
+.Cm auth | Cm bclient |
+.Cm calibrate | Cm kernel |
+.Cm mode7 | monitor |
+.Cm ntp | Cm stats
+.Oc
+.Xc
+.It Xo Ic disable
+.Oo
+.Cm auth | Cm bclient |
+.Cm calibrate | Cm kernel |
+.Cm mode7 | monitor |
+.Cm ntp | Cm stats
+.Oc
+.Xc
+Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+.Xr ntpdc 1ntpdcmdoc
+utility program.
+.Bl -tag -width indent
+.It Cm auth
+Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+.Ic enable .
+.It Cm bclient
+Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+.Ic multicastclient
+command with default
+address.
+The default for this flag is
+.Ic disable .
+.It Cm calibrate
+Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+.Ic disable .
+.It Cm kernel
+Enables the kernel time discipline, if available.
+The default for this
+flag is
+.Ic enable
+if support is available, otherwise
+.Ic disable .
+.It Cm mode7
+Enables processing of NTP mode 7 implementation-specific requests
+which are used by the deprecated
+.Xr ntpdc 1ntpdcmdoc
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+.Xr ntpq 1ntpqmdoc .
+The
+.Xr ntpq 1ntpqmdoc
+program provides the same capabilities as
+.Xr ntpdc 1ntpdcmdoc
+using standard mode 6 requests.
+.It Cm monitor
+Enables the monitoring facility.
+See the
+.Xr ntpdc 1ntpdcmdoc
+program
+and the
+.Ic monlist
+command or further information.
+The
+default for this flag is
+.Ic enable .
+.It Cm ntp
+Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+.Ic enable .
+.It Cm stats
+Enables the statistics facility.
+See the
+.Sx Monitoring Options
+section for further information.
+The default for this flag is
+.Ic disable .
+.El
+.It Ic includefile Ar includefile
+This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+.Xr ntpd 1ntpdmdoc
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+.It Ic leapsmearinterval Ar seconds
+This EXPERIMENTAL option is only available if
+.Xr ntpd 1ntpdmdoc
+was built with the
+.Cm --enable-leap-smear
+option to the
+.Cm configure
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+.It Ic logconfig Ar configkeyword
+This command controls the amount and type of output written to
+the system
+.Xr syslog 3
+facility or the alternate
+.Ic logfile
+log file.
+By default, all output is turned on.
+All
+.Ar configkeyword
+keywords can be prefixed with
+.Ql = ,
+.Ql +
+and
+.Ql - ,
+where
+.Ql =
+sets the
+.Xr syslog 3
+priority mask,
+.Ql +
+adds and
+.Ql -
+removes
+messages.
+.Xr syslog 3
+messages can be controlled in four
+classes
+.Po
+.Cm clock ,
+.Cm peer ,
+.Cm sys
+and
+.Cm sync
+.Pc .
+Within these classes four types of messages can be
+controlled: informational messages
+.Po
+.Cm info
+.Pc ,
+event messages
+.Po
+.Cm events
+.Pc ,
+statistics messages
+.Po
+.Cm statistics
+.Pc
+and
+status messages
+.Po
+.Cm status
+.Pc .
+.Pp
+Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+.Cm all
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+.Cm all
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+.Bd -literal
+logconfig =syncstatus +sysevents
+.Ed
+.Pp
+This would just list the synchronizations state of
+.Xr ntpd 1ntpdmdoc
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+.Bd -literal
+logconfig =syncall +clockall
+.Ed
+.Pp
+This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+.It Ic logfile Ar logfile
+This command specifies the location of an alternate log file to
+be used instead of the default system
+.Xr syslog 3
+facility.
+This is the same operation as the -l command line option.
+.It Ic setvar Ar variable Op Cm default
+This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+.Sm off
+.Va name = Ar value
+.Sm on
+is followed by the
+.Cm default
+keyword, the
+variable will be listed as part of the default system variables
+.Po
+.Xr ntpq 1ntpqmdoc
+.Ic rv
+command
+.Pc ) .
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+.Ic setvar
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+.Va sys_var_list
+holds
+the names of all system variables.
+The
+.Va peer_var_list
+holds
+the names of all peer variables and the
+.Va clock_var_list
+holds the names of the reference clock variables.
+.It Xo Ic tinker
+.Oo
+.Cm allan Ar allan |
+.Cm dispersion Ar dispersion |
+.Cm freq Ar freq |
+.Cm huffpuff Ar huffpuff |
+.Cm panic Ar panic |
+.Cm step Ar step |
+.Cm stepback Ar stepback |
+.Cm stepfwd Ar stepfwd |
+.Cm stepout Ar stepout
+.Oc
+.Xc
+This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+.Pp
+The variables operate as follows:
+.Bl -tag -width indent
+.It Cm allan Ar allan
+The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+.It Cm dispersion Ar dispersion
+The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+.It Cm freq Ar freq
+The argument becomes the initial value of the frequency offset in
+parts-per-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+.It Cm huffpuff Ar huffpuff
+The argument becomes the new value for the experimental
+huff-n'-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+.It Cm panic Ar panic
+The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+.It Cm step Ar step
+The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+.It Cm stepback Ar stepback
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+.It Cm stepfwd Ar stepfwd
+As for stepback, but for the forward direction.
+.It Cm stepout Ar stepout
+The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+.El
+.It Xo Ic rlimit
+.Oo
+.Cm memlock Ar Nmegabytes |
+.Cm stacksize Ar N4kPages
+.Cm filenum Ar Nfiledescriptors
+.Oc
+.Xc
+.Bl -tag -width indent
+.It Cm memlock Ar Nmegabytes
+Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+.Fl i
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+.It Cm stacksize Ar N4kPages
+Specifies the maximum size of the process stack on systems with the
+.Fn mlockall
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+.It Cm filenum Ar Nfiledescriptors
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+.El
+.It Xo Ic trap Ar host_address
+.Op Cm port Ar port_number
+.Op Cm interface Ar interface_address
+.Xc
+This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+.Pp
+The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+.It Cm hop Ar ...
+This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding-ring search.
+The default is eight multiples of 32 starting at
+31.
+.El
+ _END_PROG_MDOC_DESCRIP;
+};
+
+doc-section = {
+ ds-type = 'FILES';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_FILES
+.Bl -tag -width /etc/ntp.drift -compact
+.It Pa /etc/ntp.conf
+the default name of the configuration file
+.It Pa ntp.keys
+private MD5 keys
+.It Pa ntpkey
+RSA private key
+.It Pa ntpkey_ Ns Ar host
+RSA public key
+.It Pa ntp_dh
+Diffie-Hellman agreement parameters
+.El
+ _END_MDOC_FILES;
+};
+
+doc-section = {
+ ds-type = 'SEE ALSO';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_SEE_ALSO
+.Xr ntpd 1ntpdmdoc ,
+.Xr ntpdc 1ntpdcmdoc ,
+.Xr ntpq 1ntpqmdoc
+.Pp
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+.Li http://www.ntp.org/ .
+A snapshot of this documentation is available in HTML format in
+.Pa /usr/share/doc/ntp .
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 4)
+.%O RFC5905
+.Re
+ _END_MDOC_SEE_ALSO;
+};
+
+doc-section = {
+ ds-type = 'BUGS';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_BUGS
+The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+.Pp
+The
+.Pa ntpkey_ Ns Ar host
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+ _END_MDOC_BUGS;
+};
+
+doc-section = {
+ ds-type = 'NOTES';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_NOTES
+This document was derived from FreeBSD.
+ _END_MDOC_NOTES;
+};
diff --git a/contrib/ntp/ntpd/ntp.conf.html b/contrib/ntp/ntpd/ntp.conf.html
new file mode 100644
index 0000000..ad64355
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.html
@@ -0,0 +1,2663 @@
+<html lang="en">
+<head>
+<title>NTP Configuration File User's Manual</title>
+<meta http-equiv="Content-Type" content="text/html">
+<meta name="description" content="NTP Configuration File User's Manual">
+<meta name="generator" content="makeinfo 4.7">
+<link title="Top" rel="top" href="#Top">
+<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
+<meta http-equiv="Content-Style-Type" content="text/css">
+<style type="text/css"><!--
+ pre.display { font-family:inherit }
+ pre.format { font-family:inherit }
+ pre.smalldisplay { font-family:inherit; font-size:smaller }
+ pre.smallformat { font-family:inherit; font-size:smaller }
+ pre.smallexample { font-size:smaller }
+ pre.smalllisp { font-size:smaller }
+ span.sc { font-variant:small-caps }
+ span.roman { font-family: serif; font-weight: normal; }
+--></style>
+</head>
+<body>
+<h1 class="settitle">NTP Configuration File User's Manual</h1>
+<div class="node">
+<p><hr>
+<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002econf-Description">ntp.conf Description</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
+<br>
+</div>
+
+<h2 class="unnumbered">NTP's Configuration File User Manual</h2>
+
+<p>This document describes the configuration file for the NTP Project's
+<code>ntpd</code> program.
+
+ <p>This document applies to version 4.2.8p3 of <code>ntp.conf</code>.
+
+ <div class="shortcontents">
+<h2>Short Contents</h2>
+<ul>
+<a href="#Top">NTP's Configuration File User Manual</a>
+</ul>
+</div>
+
+<ul class="menu">
+<li><a accesskey="1" href="#ntp_002econf-Description">ntp.conf Description</a>
+<li><a accesskey="2" href="#ntp_002econf-Notes">ntp.conf Notes</a>
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="ntp_002econf-Description"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+<br>
+</div>
+
+<!-- node-name, next, previous, up -->
+<h3 class="section">Description</h3>
+
+<p>The behavior of <code>ntpd</code> can be changed by a configuration file,
+by default <code>ntp.conf</code>.
+
+<div class="node">
+<p><hr>
+<a name="ntp_002econf-Notes"></a>
+<br>
+</div>
+
+<h3 class="section">Notes about ntp.conf</h3>
+
+<p><a name="index-ntp_002econf-1"></a><a name="index-Network-Time-Protocol-_0028NTP_0029-daemon-configuration-file-format-2"></a>
+
+ <p>The
+<code>ntp.conf</code>
+configuration file is read at initial startup by the
+<code>ntpd(1ntpdmdoc)</code>
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+<span class="file">/etc</span>
+directory,
+but could be installed elsewhere
+(see the daemon's
+<code>-c</code>
+command line option).
+
+ <p>The file format is similar to other
+<span class="sc">unix</span>
+configuration files.
+Comments begin with a
+#
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+
+ <p>The rest of this page describes the configuration and control options.
+The
+"Notes on Configuring NTP and Setting up an NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>)
+contains an extended discussion of these options.
+In addition to the discussion of general
+<a href="#Configuration-Options">Configuration Options</a>,
+there are sections describing the following supported functionality
+and the options used to control it:
+ <ul>
+<li><a href="#Authentication-Support">Authentication Support</a>
+<li><a href="#Monitoring-Support">Monitoring Support</a>
+<li><a href="#Access-Control-Support">Access Control Support</a>
+<li><a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a>
+<li><a href="#Reference-Clock-Support">Reference Clock Support</a>
+<li><a href="#Miscellaneous-Options">Miscellaneous Options</a>
+</ul>
+
+ <p>Following these is a section describing
+<a href="#Miscellaneous-Options">Miscellaneous Options</a>.
+While there is a rich set of options available,
+the only required option is one or more
+<code>pool</code>,
+<code>server</code>,
+<code>peer</code>,
+<code>broadcast</code>
+or
+<code>manycastclient</code>
+commands.
+<div class="node">
+<p><hr>
+<a name="Configuration-Support"></a>
+<br>
+</div>
+
+<h4 class="subsection">Configuration Support</h4>
+
+<p>Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+
+<h5 class="subsubsection">Configuration Commands</h5>
+
+<p>The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+
+ <p>If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+:
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+
+ <p>Note that in contexts where a host name is expected, a
+<code>-4</code>
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+<code>-6</code>
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+ <dl>
+<dt><code>pool</code> <kbd>address</kbd> <code>[burst]</code> <code>[iburst]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code><br><dt><code>server</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[burst]</code> <code>[iburst]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code><br><dt><code>peer</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code><br><dt><code>broadcast</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[ttl </code><kbd>ttl</kbd><code>]</code><br><dt><code>manycastclient</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code> <code>[ttl </code><kbd>ttl</kbd><code>]</code><dd></dl>
+
+ <p>These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+<kbd>address</kbd>
+can be
+either a DNS name or an IP address in dotted-quad notation.
+Additional information on association behavior can be found in the
+"Association Management"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+ <dl>
+<dt><code>pool</code><dd>For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+<br><dt><code>server</code><dd>For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+<em>not</em>
+be used for type
+b or m addresses.
+<br><dt><code>peer</code><dd>For type s addresses (only), this command mobilizes a
+persistent symmetric-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+<br><dt><code>broadcast</code><dd>For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+<kbd>address</kbd>
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+<code>broadcastclient</code>
+or
+<code>multicastclient</code>
+commands
+below.
+<br><dt><code>manycastclient</code><dd>For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+<code>manycastserver</code>
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+<code>manycastserver</code>
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+<kbd>address</kbd>
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+<code>server</code>
+command.
+The remaining servers are discarded as if never
+heard.
+</dl>
+
+ <p>Options:
+ <dl>
+<dt><code>autokey</code><dd>All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+<a href="#Authentication-Options">Authentication Options</a>.
+<br><dt><code>burst</code><dd>when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+<code>server</code>
+command and s addresses.
+<br><dt><code>iburst</code><dd>When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+<code>server</code>
+command and s addresses and when
+<code>ntpd(1ntpdmdoc)</code>
+is started with the
+<code>-q</code>
+option.
+<br><dt><code>key</code> <kbd>key</kbd><dd>All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+<kbd>key</kbd>
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+<br><dt><code>minpoll</code> <kbd>minpoll</kbd><br><dt><code>maxpoll</code> <kbd>maxpoll</kbd><dd>These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+<code>maxpoll</code>
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+<code>minpoll</code>
+option to a lower limit of 4 (16 s).
+<br><dt><code>noselect</code><dd>Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+<br><dt><code>prefer</code><dd>Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>)
+for further information.
+<br><dt><code>ttl</code> <kbd>ttl</kbd><dd>This option is used only with broadcast server and manycast
+client modes.
+It specifies the time-to-live
+<kbd>ttl</kbd>
+to
+use on broadcast server and multicast server and the maximum
+<kbd>ttl</kbd>
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+<br><dt><code>version</code> <kbd>version</kbd><dd>Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1-4 are the choices, with version 4 the
+default.
+</dl>
+
+<h5 class="subsubsection">Auxiliary Commands</h5>
+
+ <dl>
+<dt><code>broadcastclient</code><dd>This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric-key or public-key
+authentication as described in
+<a href="#Authentication-Options">Authentication Options</a>.
+<br><dt><code>manycastserver</code> <kbd>address</kbd> <kbd>...</kbd><dd>This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric-key or public-key
+authentication as described in
+<a href="#Authentication-Options">Authentication Options</a>.
+<br><dt><code>multicastclient</code> <kbd>address</kbd> <kbd>...</kbd><dd>This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric-key or
+public-key authentication as described in
+<a href="#Authentication-Options">Authentication Options</a>.
+<br><dt><code>mdnstries</code> <kbd>number</kbd><dd>If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+<code>mdnstries</code>
+times.
+After all,
+<code>ntpd</code>
+may be starting before mDNS.
+The default value for
+<code>mdnstries</code>
+is 5.
+</dl>
+<div class="node">
+<p><hr>
+<a name="Authentication-Support"></a>
+<br>
+</div>
+
+<h4 class="subsection">Authentication Support</h4>
+
+<p>Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed-MD5.
+Either algorithm computes a message digest, or one-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+
+ <p>NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+
+ <p>While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+
+ <p>Authentication is configured separately for each association
+using the
+<code>key</code>
+or
+<code>autokey</code>
+subcommand on the
+<code>peer</code>,
+<code>server</code>,
+<code>broadcast</code>
+and
+<code>manycastclient</code>
+configuration commands as described in
+<a href="#Configuration-Options">Configuration Options</a>
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+
+ <p>Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+
+ <p>The
+<code>auth</code>
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+<code>enable</code>
+and
+<code>disable</code>
+commands and also by remote
+configuration commands sent by a
+<code>ntpdc(1ntpdcmdoc)</code>
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+<code>auth</code>
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+
+ <p>An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+<a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a>
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+
+ <p>The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+<code>http://www.ntp.org/</code>.
+
+<h5 class="subsubsection">Symmetric-Key Cryptography</h5>
+
+<p>The original RFC-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+<span class="file">ntp.keys</span>,
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+utility programs.
+
+ <p>When
+<code>ntpd(1ntpdmdoc)</code>
+is first started, it reads the key file specified in the
+<code>keys</code>
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+<code>trusted</code>
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+<code>ntpdc(1ntpdcmdoc)</code>.
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+<code>requestkey</code>
+command selects the key used as the password for the
+<code>ntpdc(1ntpdcmdoc)</code>
+utility, while the
+<code>controlkey</code>
+command selects the key used as the password for the
+<code>ntpq(1ntpqmdoc)</code>
+utility.
+
+<h5 class="subsubsection">Public Key Cryptography</h5>
+
+<p>NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+
+ <p>The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S-KEY scheme,
+in which a pseudo-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+<a href="#Autonomous-Authentication">Autonomous Authentication</a>
+page.
+
+ <p>The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+<code>ntp-keygen(1ntpkeygenmdoc)</code>
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+<code>md5WithRSAEncryption</code>,
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+
+ <p>NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+
+<h5 class="subsubsection">Naming and Addressing</h5>
+
+<p>It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+
+ <p>By convention, the name of an Autokey host is the name returned
+by the Unix
+<code>gethostname(2)</code>
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+
+ <p>It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+
+<h5 class="subsubsection">Operation</h5>
+
+<p>A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+
+ <p>The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+<code>server</code>
+or
+<code>peer</code>
+configuration command and no
+<code>key</code>
+or
+<code>autokey</code>
+subcommands are present, the association is not
+authenticated; if the
+<code>key</code>
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+<code>autokey</code>
+subcommand is present, the association is authenticated
+using Autokey.
+
+ <p>When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+
+ <p>Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+
+ <p>Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto-NAK, which tells her
+something broke.
+She can see the evidence using the
+<code>ntpq(1ntpqmdoc)</code>
+program.
+
+ <p>Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+
+ <p>It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+
+<h5 class="subsubsection">Key Management</h5>
+
+<p>The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+<code>ntp-keygen(1ntpkeygenmdoc)</code>
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+
+ <p>Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+<code>trustRoot</code>;.
+Other extension fields are ignored.
+
+<h5 class="subsubsection">Authentication Commands</h5>
+
+ <dl>
+<dt><code>autokey</code> <code>[</code><kbd>logsec</kbd><code>]</code><dd>Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+<br><dt><code>controlkey</code> <kbd>key</kbd><dd>Specifies the key identifier to use with the
+<code>ntpq(1ntpqmdoc)</code>
+utility, which uses the standard
+protocol defined in RFC-1305.
+The
+<kbd>key</kbd>
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+<br><dt><code>crypto</code> <code>[cert </code><kbd>file</kbd><code>]</code> <code>[leap </code><kbd>file</kbd><code>]</code> <code>[randfile </code><kbd>file</kbd><code>]</code> <code>[host </code><kbd>file</kbd><code>]</code> <code>[sign </code><kbd>file</kbd><code>]</code> <code>[gq </code><kbd>file</kbd><code>]</code> <code>[gqpar </code><kbd>file</kbd><code>]</code> <code>[iffpar </code><kbd>file</kbd><code>]</code> <code>[mvpar </code><kbd>file</kbd><code>]</code> <code>[pw </code><kbd>password</kbd><code>]</code><dd>This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+<code>keysdir</code>
+command or default
+<span class="file">/usr/local/etc</span>.
+Following are the subcommands:
+ <dl>
+<dt><code>cert</code> <kbd>file</kbd><dd>Specifies the location of the required host public certificate file.
+This overrides the link
+<span class="file">ntpkey_cert_</span><kbd>hostname</kbd>
+in the keys directory.
+<br><dt><code>gqpar</code> <kbd>file</kbd><dd>Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+<span class="file">ntpkey_gq_</span><kbd>hostname</kbd>
+in the keys directory.
+<br><dt><code>host</code> <kbd>file</kbd><dd>Specifies the location of the required host key file.
+This overrides
+the link
+<span class="file">ntpkey_key_</span><kbd>hostname</kbd>
+in the keys directory.
+<br><dt><code>iffpar</code> <kbd>file</kbd><dd>Specifies the location of the optional IFF parameters file.This
+overrides the link
+<span class="file">ntpkey_iff_</span><kbd>hostname</kbd>
+in the keys directory.
+<br><dt><code>leap</code> <kbd>file</kbd><dd>Specifies the location of the optional leapsecond file.
+This overrides the link
+<span class="file">ntpkey_leap</span>
+in the keys directory.
+<br><dt><code>mvpar</code> <kbd>file</kbd><dd>Specifies the location of the optional MV parameters file.
+This
+overrides the link
+<span class="file">ntpkey_mv_</span><kbd>hostname</kbd>
+in the keys directory.
+<br><dt><code>pw</code> <kbd>password</kbd><dd>Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+<br><dt><code>randfile</code> <kbd>file</kbd><dd>Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+<br><dt><code>sign</code> <kbd>file</kbd><dd>Specifies the location of the optional sign key file.
+This overrides
+the link
+<span class="file">ntpkey_sign_</span><kbd>hostname</kbd>
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+</dl>
+ <br><dt><code>keys</code> <kbd>keyfile</kbd><dd>Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+<code>ntpd(1ntpdmdoc)</code>,
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+when operating with symmetric key cryptography.
+This is the same operation as the
+<code>-k</code>
+command line option.
+<br><dt><code>keysdir</code> <kbd>path</kbd><dd>This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+<span class="file">/usr/local/etc/</span>.
+<br><dt><code>requestkey</code> <kbd>key</kbd><dd>Specifies the key identifier to use with the
+<code>ntpdc(1ntpdcmdoc)</code>
+utility program, which uses a
+proprietary protocol specific to this implementation of
+<code>ntpd(1ntpdmdoc)</code>.
+The
+<kbd>key</kbd>
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+<br><dt><code>revoke</code> <kbd>logsec</kbd><dd>Specifies the interval between re-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+<br><dt><code>trustedkey</code> <kbd>key</kbd> <kbd>...</kbd><dd>Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+<kbd>key</kbd>
+arguments are 32-bit unsigned
+integers with values from 1 to 65,534.
+</dl>
+
+<h5 class="subsubsection">Error Codes</h5>
+
+<p>The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+ <dl>
+<dt>101<dd>(bad field format or length)
+The packet has invalid version, length or format.
+<br><dt>102<dd>(bad timestamp)
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+<br><dt>103<dd>(bad filestamp)
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+<br><dt>104<dd>(bad or missing public key)
+The public key is missing, has incorrect format or is an unsupported type.
+<br><dt>105<dd>(unsupported digest type)
+The server requires an unsupported digest/signature scheme.
+<br><dt>106<dd>(mismatched digest types)
+Not used.
+<br><dt>107<dd>(bad signature length)
+The signature length does not match the current public key.
+<br><dt>108<dd>(signature not verified)
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+<br><dt>109<dd>(certificate not verified)
+The certificate is invalid or signed with the wrong key.
+<br><dt>110<dd>(certificate not verified)
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+<br><dt>111<dd>(bad or missing cookie)
+The cookie is missing, corrupted or bogus.
+<br><dt>112<dd>(bad or missing leapseconds table)
+The leapseconds table is missing, corrupted or bogus.
+<br><dt>113<dd>(bad or missing certificate)
+The certificate is missing, corrupted or bogus.
+<br><dt>114<dd>(bad or missing identity)
+The identity key is missing, corrupt or bogus.
+</dl>
+ <div class="node">
+<p><hr>
+<a name="Monitoring-Support"></a>
+<br>
+</div>
+
+<h4 class="subsection">Monitoring Support</h4>
+
+<p><code>ntpd(1ntpdmdoc)</code>
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+<code>statistics</code>
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+<span class="file">./scripts</span>
+directory of this distribution.
+Using
+these facilities and
+<span class="sc">unix</span>
+<code>cron(8)</code>
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+
+<h5 class="subsubsection">Monitoring Commands</h5>
+
+ <dl>
+<dt><code>statistics</code> <kbd>name</kbd> <kbd>...</kbd><dd>Enables writing of statistics records.
+Currently, eight kinds of
+<kbd>name</kbd>
+statistics are supported.
+ <dl>
+<dt><code>clockstats</code><dd>Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+<code>clockstats</code>:
+<pre class="verbatim">
+ 49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+ </pre>
+
+ <p>The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+<br><dt><code>cryptostats</code><dd>This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+<code>cryptostats</code>:
+<pre class="verbatim">
+ 49213 525.624 127.127.4.1 message
+ </pre>
+
+ <p>The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+<a href="#Authentication-Options">Authentication Options</a>
+section for further information.
+<br><dt><code>loopstats</code><dd>Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+<code>loopstats</code>:
+<pre class="verbatim">
+ 50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+ </pre>
+
+ <p>The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million -
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+<br><dt><code>peerstats</code><dd>Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+<code>peerstats</code>:
+<pre class="verbatim">
+ 48773 10847.650 127.127.4.1 9714 -0.001605376 0.000000000 0.001424877 0.000958674
+ </pre>
+
+ <p>The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+<br><dt><code>rawstats</code><dd>Enables recording of raw-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+<code>rawstats</code>:
+<pre class="verbatim">
+ 50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+ </pre>
+
+ <p>The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+<br><dt><code>sysstats</code><dd>Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+<code>sysstats</code>:
+<pre class="verbatim">
+ 50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+ </pre>
+
+ <p>The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+ <dl>
+<dt>Time since restart <code>36000</code><dd>Time in hours since the system was last rebooted.
+<br><dt>Packets received <code>81965</code><dd>Total number of packets received.
+<br><dt>Packets processed <code>0</code><dd>Number of packets received in response to previous packets sent
+<br><dt>Current version <code>9546</code><dd>Number of packets matching the current NTP version.
+<br><dt>Previous version <code>56</code><dd>Number of packets matching the previous NTP version.
+<br><dt>Bad version <code>71793</code><dd>Number of packets matching neither NTP version.
+<br><dt>Access denied <code>512</code><dd>Number of packets denied access for any reason.
+<br><dt>Bad length or format <code>540</code><dd>Number of packets with invalid length, format or port number.
+<br><dt>Bad authentication <code>10</code><dd>Number of packets not verified as authentic.
+<br><dt>Rate exceeded <code>147</code><dd>Number of packets discarded due to rate limitation.
+</dl>
+ <br><dt><code>statsdir</code> <kbd>directory_path</kbd><dd>Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+<code>filegen</code>
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+<br><dt><code>filegen</code> <kbd>name</kbd> <code>[file </code><kbd>filename</kbd><code>]</code> <code>[type </code><kbd>typename</kbd><code>]</code> <code>[link | nolink]</code> <code>[enable | disable]</code><dd>Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+
+ <p>Note that this command can be sent from the
+<code>ntpdc(1ntpdcmdoc)</code>
+program running at a remote location.
+ <dl>
+<dt><code>name</code><dd>This is the type of the statistics records, as shown in the
+<code>statistics</code>
+command.
+<br><dt><code>file</code> <kbd>filename</kbd><dd>This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+<code>prefix</code>,
+<code>filename</code>
+and
+<code>suffix</code>:
+ <dl>
+<dt><code>prefix</code><dd>This is a constant filename path.
+It is not subject to
+modifications via the
+<kbd>filegen</kbd>
+option.
+It is defined by the
+server, usually specified as a compile-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+<kbd>loopstats</kbd>
+and
+<kbd>peerstats</kbd>
+generation can be configured using the
+<kbd>statsdir</kbd>
+option explained above.
+<br><dt><code>filename</code><dd>This string is directly concatenated to the prefix mentioned
+above (no intervening
+/).
+This can be modified using
+the file argument to the
+<kbd>filegen</kbd>
+statement.
+No
+<span class="file">..</span>
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+<kbd>prefix</kbd>.
+<br><dt><code>suffix</code><dd>This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+</dl>
+ <br><dt><code>type</code> <kbd>typename</kbd><dd>A file generation set is characterized by its type.
+The following
+types are supported:
+ <dl>
+<dt><code>none</code><dd>The file set is actually a single plain file.
+<br><dt><code>pid</code><dd>One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+<code>ntpd(1ntpdmdoc)</code>
+server incarnations.
+The set member filename is built by appending a
+.
+to concatenated
+<kbd>prefix</kbd>
+and
+<kbd>filename</kbd>
+strings, and
+appending the decimal representation of the process ID of the
+<code>ntpd(1ntpdmdoc)</code>
+server process.
+<br><dt><code>day</code><dd>One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+.
+and a day specification in
+the form
+<code>YYYYMMdd</code>.
+<code>YYYY</code>
+is a 4-digit year number (e.g., 1992).
+<code>MM</code>
+is a two digit month number.
+<code>dd</code>
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+<kbd>prefix</kbd>
+<kbd>filename</kbd>.19921210.
+<br><dt><code>week</code><dd>Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day-of-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4-digit year number, the letter
+<code>W</code>,
+and a 2-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.No . Ns Ar 1992W1 .
+<br><dt><code>month</code><dd>One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4-digit year number, and
+a 2-digit month.
+<br><dt><code>year</code><dd>One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+<br><dt><code>age</code><dd>This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+<code>a</code>,
+and an 8-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24-hour period.
+Information is only written to a file generation by specifying
+<code>enable</code>;
+output is prevented by specifying
+<code>disable</code>.
+</dl>
+ <br><dt><code>link</code> | <code>nolink</code><dd>It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+<code>link</code>
+and disabled using
+<code>nolink</code>.
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+<code>C</code>,
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+<br><dt><code>enable</code> <code>|</code> <code>disable</code><dd>Enables or disables the recording function.
+</dl>
+ </dl>
+ </dl>
+<div class="node">
+<p><hr>
+<a name="Access-Control-Support"></a>
+<br>
+</div>
+
+<h4 class="subsection">Access Control Support</h4>
+
+<p>The
+<code>ntpd(1ntpdmdoc)</code>
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+"Notes on Configuring NTP and Setting up a NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+
+ <p>The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+
+ <p>Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+
+<h5 class="subsubsection">The Kiss-of-Death Packet</h5>
+
+<p>Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss-of-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four-byte
+ASCII code.
+If the
+<code>noserve</code>
+or
+<code>notrust</code>
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+<code>limited</code>
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+
+ <p>A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+
+<h5 class="subsubsection">Access Control Commands</h5>
+
+ <dl>
+<dt><code>discard</code> <code>[average </code><kbd>avg</kbd><code>]</code> <code>[minimum </code><kbd>min</kbd><code>]</code> <code>[monitor </code><kbd>prob</kbd><code>]</code><dd>Set the parameters of the
+<code>limited</code>
+facility which protects the server from
+client abuse.
+The
+<code>average</code>
+subcommand specifies the minimum average packet
+spacing, while the
+<code>minimum</code>
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss-o'-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate-control window.
+<br><dt><code>restrict</code> <code>address</code> <code>[mask </code><kbd>mask</kbd><code>]</code> <code>[</code><kbd>flag</kbd> <kbd>...</kbd><code>]</code><dd>The
+<kbd>address</kbd>
+argument expressed in
+dotted-quad form is the address of a host or network.
+Alternatively, the
+<kbd>address</kbd>
+argument can be a valid host DNS name.
+The
+<kbd>mask</kbd>
+argument expressed in dotted-quad form defaults to
+<code>255.255.255.255</code>,
+meaning that the
+<kbd>address</kbd>
+is treated as the address of an individual host.
+A default entry (address
+<code>0.0.0.0</code>,
+mask
+<code>0.0.0.0</code>)
+is always included and is always the first entry in the list.
+Note that text string
+<code>default</code>,
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+<code>flag</code>
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+ <dl>
+<dt><code>ignore</code><dd>Deny packets of all kinds, including
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+queries.
+<br><dt><code>kod</code><dd>If this flag is set when an access violation occurs, a kiss-o'-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+<br><dt><code>limited</code><dd>Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+<code>ntpd(1ntpdmdoc)</code>.
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+<code>limited</code>
+flag.
+<br><dt><code>lowpriotrap</code><dd>Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+<br><dt><code>nomodify</code><dd>Deny
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+<br><dt><code>noquery</code><dd>Deny
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+queries.
+Time service is not affected.
+<br><dt><code>nopeer</code><dd>Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+<code>pool</code>
+associations, so if you want to use servers from a
+<code>pool</code>
+directive and also want to use
+<code>nopeer</code>
+by default, you'll want a
+<code>restrict source ...</code> <code>line</code> <code>as</code> <code>well</code> <code>that</code> <code>does</code>
+<br><dt>not<dd>include the
+<code>nopeer</code>
+directive.
+<br><dt><code>noserve</code><dd>Deny all packets except
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+queries.
+<br><dt><code>notrap</code><dd>Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+<br><dt><code>notrust</code><dd>Deny service unless the packet is cryptographically authenticated.
+<br><dt><code>ntpport</code><dd>This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+<code>ntpport</code>
+and
+<code>non-ntpport</code>
+may
+be specified.
+The
+<code>ntpport</code>
+is considered more specific and
+is sorted later in the list.
+<br><dt><code>version</code><dd>Deny packets that do not match the current NTP version.
+</dl>
+
+ <p>Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+</dl>
+<div class="node">
+<p><hr>
+<a name="Automatic-NTP-Configuration-Options"></a>
+<br>
+</div>
+
+<h4 class="subsection">Automatic NTP Configuration Options</h4>
+
+<h5 class="subsubsection">Manycasting</h5>
+
+<p>Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+
+ <p>Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+
+ <p>Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+<code>http://www.openssl.org/</code>.
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+
+ <p>A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+<code>D</code>
+or IPv6 prefix
+<code>FF</code>)
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time-to-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+
+ <p>Manycast servers configured with the
+<code>manycastserver</code>
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+
+ <p>The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+
+ <p>The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+<code>manycastclient</code>,
+<code>tos</code>
+and
+<code>ttl</code>
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+<code>minpoll</code>
+value specified in the
+<code>manycastclient</code>,
+command and, under normal circumstances, increments to the
+<code>maxpolll</code>
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+
+ <p>The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+<code>minclock</code>
+and
+<code>minsane</code>
+values specified in the
+<code>tos</code>
+configuration command.
+At least
+<code>minsane</code>
+candidate servers must be available and the mitigation
+algorithms produce at least
+<code>minclock</code>
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+<code>minsane</code>
+defaults to 1 and
+<code>minclock</code>
+defaults to 3.
+For manycast service
+<code>minsane</code>
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+
+ <p>If at least
+<code>minclock</code>
+servers are found, the manycast poll interval is immediately
+set to eight times
+<code>maxpoll</code>.
+If less than
+<code>minclock</code>
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+<code>maxpoll</code>.
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+
+ <p>Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+<code>ttl</code>
+configuration command can be
+used to modify the values to match the scope rules.
+
+ <p>It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+<code>tos</code>
+command can be used to modify this behavior.
+Servers with stratum below
+<code>floor</code>
+or above
+<code>ceiling</code>
+specified in the
+<code>tos</code>
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+<code>minclock</code>.
+
+ <p>The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+<code>minclock</code>,
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+<code>maxpoll</code>
+is 12 (4,096 s).
+
+ <p>It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+<code>multicastclient</code>
+and
+<code>multicastserver</code>
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+
+ <p>The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+<code>tos</code>
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+<code>floor</code>
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+
+ <p>Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re-associate accordingly.
+
+ <p>Some administrators prefer to avoid running
+<code>ntpd(1ntpdmdoc)</code>
+continuously and run either
+<code>ntpdate(8)</code>
+or
+<code>ntpd(1ntpdmdoc)</code>
+<code>-q</code>
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+<code>ntpd(1ntpdmdoc)</code>
+<code>-q</code>.
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+
+<h5 class="subsubsection">Manycast Interactions with Autokey</h5>
+
+<p>Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+
+ <p>About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+
+<h5 class="subsubsection">Manycast Options</h5>
+
+ <dl>
+<dt><code>tos</code> <code>[ceiling </code><kbd>ceiling</kbd><code> | cohort { 0 | 1 } | floor </code><kbd>floor</kbd><code> | minclock </code><kbd>minclock</kbd><code> | minsane </code><kbd>minsane</kbd><code>]</code><dd>This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+ <dl>
+<dt><code>ceiling</code> <kbd>ceiling</kbd><dd>Peers with strata above
+<code>ceiling</code>
+will be discarded if there are at least
+<code>minclock</code>
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+<br><dt><code>cohort</code> <code>{0 | 1}</code><dd>This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+<br><dt><code>floor</code> <kbd>floor</kbd><dd>Peers with strata below
+<code>floor</code>
+will be discarded if there are at least
+<code>minclock</code>
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+<br><dt><code>minclock</code> <kbd>minclock</kbd><dd>The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+<code>minclock</code>
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+<br><dt><code>minsane</code> <kbd>minsane</kbd><dd>This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+<code>minsane</code>
+should be at least 4 in order to detect and discard
+a single falseticker.
+</dl>
+ <br><dt><code>ttl</code> <kbd>hop</kbd> <kbd>...</kbd><dd>This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding-ring search.
+The default is eight
+multiples of 32 starting at 31.
+</dl>
+<div class="node">
+<p><hr>
+<a name="Reference-Clock-Support"></a>
+<br>
+</div>
+
+<h4 class="subsection">Reference Clock Support</h4>
+
+<p>The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+Additional information can be found in the pages linked
+there, including the
+"Debugging Hints for Reference Clock Drivers"
+and
+"How To Write a Reference Clock Driver"
+pages
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+In addition, support for a PPS
+signal is available as described in the
+"Pulse-per-second (PPS) Signal Interfacing"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+"Line Disciplines and Streams Drivers"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+
+ <p>A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+
+ <p>For the purposes of configuration,
+<code>ntpd(1ntpdmdoc)</code>
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+<code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd>,
+where
+<kbd>t</kbd>
+is an integer
+denoting the clock type and
+<kbd>u</kbd>
+indicates the unit
+number in the range 0-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+
+ <p>The
+<code>server</code>
+command is used to configure a reference
+clock, where the
+<kbd>address</kbd>
+argument in that command
+is the clock address.
+The
+<code>key</code>,
+<code>version</code>
+and
+<code>ttl</code>
+options are not used for reference clock support.
+The
+<code>mode</code>
+option is added for reference clock support, as
+described below.
+The
+<code>prefer</code>
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+"Mitigation Rules and the prefer Keyword"
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>)
+page.
+The
+<code>minpoll</code>
+and
+<code>maxpoll</code>
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+
+ <p>The
+<code>fudge</code>
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+<code>server</code>
+command.
+The
+<kbd>address</kbd>
+argument specifies the clock address.
+The
+<code>refid</code>
+and
+<code>stratum</code>
+options can be used to
+override the defaults for the device.
+There are two optional
+device-dependent time offsets and four flags that can be included
+in the
+<code>fudge</code>
+command as well.
+
+ <p>The stratum number of a reference clock is by default zero.
+Since the
+<code>ntpd(1ntpdmdoc)</code>
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+<code>stratum</code>
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse-per-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+<code>refid</code>
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+
+<h5 class="subsubsection">Reference Clock Commands</h5>
+
+ <dl>
+<dt><code>server</code> <code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd> <code>[prefer]</code> <code>[mode </code><kbd>int</kbd><code>]</code> <code>[minpoll </code><kbd>int</kbd><code>]</code> <code>[maxpoll </code><kbd>int</kbd><code>]</code><dd>This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+ <dl>
+<dt><code>prefer</code><dd>Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>)
+for further information.
+<br><dt><code>mode</code> <kbd>int</kbd><dd>Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+<br><dt><code>minpoll</code> <kbd>int</kbd><br><dt><code>maxpoll</code> <kbd>int</kbd><dd>These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+<code>minpoll</code>
+and
+<code>maxpoll</code>
+default to 6 (64 s).
+For modem reference clocks,
+<code>minpoll</code>
+defaults to 10 (17.1 m) and
+<code>maxpoll</code>
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+</dl>
+ <br><dt><code>fudge</code> <code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd> <code>[time1 </code><kbd>sec</kbd><code>]</code> <code>[time2 </code><kbd>sec</kbd><code>]</code> <code>[stratum </code><kbd>int</kbd><code>]</code> <code>[refid </code><kbd>string</kbd><code>]</code> <code>[mode </code><kbd>int</kbd><code>]</code> <code>[flag1 0 | 1]</code> <code>[flag2 0 | 1]</code> <code>[flag3 0 | 1]</code> <code>[flag4 0 | 1]</code><dd>This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+<code>server</code>
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+<code>ntpdc(1ntpdcmdoc)</code>
+program.
+The options are interpreted as
+follows:
+ <dl>
+<dt><code>time1</code> <kbd>sec</kbd><dd>Specifies a constant to be added to the time offset produced by
+the driver, a fixed-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+<code>enable</code>
+command described in
+<a href="#Miscellaneous-Options">Miscellaneous Options</a>
+page and operates as described in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+<br><dt><code>time2</code> <kbd>secs</kbd><dd>Specifies a fixed-point decimal number in seconds, which is
+interpreted in a driver-dependent way.
+See the descriptions of
+specific drivers in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+<span class="file">/usr/share/doc/ntp</span>).
+<br><dt><code>stratum</code> <kbd>int</kbd><dd>Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+<br><dt><code>refid</code> <kbd>string</kbd><dd>Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+<br><dt><code>mode</code> <kbd>int</kbd><dd>Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+<br><dt><code>flag1</code> <code>0</code> <code>|</code> <code>1</code><br><dt><code>flag2</code> <code>0</code> <code>|</code> <code>1</code><br><dt><code>flag3</code> <code>0</code> <code>|</code> <code>1</code><br><dt><code>flag4</code> <code>0</code> <code>|</code> <code>1</code><dd>These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+<code>flag4</code>
+is used to enable recording monitoring
+data to the
+<code>clockstats</code>
+file configured with the
+<code>filegen</code>
+command.
+Further information on the
+<code>filegen</code>
+command can be found in
+<a href="#Monitoring-Options">Monitoring Options</a>.
+</dl>
+ </dl>
+<div class="node">
+<p><hr>
+<a name="Miscellaneous-Options"></a>
+<br>
+</div>
+
+<h4 class="subsection">Miscellaneous Options</h4>
+
+ <dl>
+<dt><code>broadcastdelay</code> <kbd>seconds</kbd><dd>The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+<br><dt><code>calldelay</code> <kbd>delay</kbd><dd>This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+<br><dt><code>driftfile</code> <kbd>driftfile</kbd><dd>This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+<code>-f</code>
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+
+ <p>The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts-per-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+<code>ntpd(1ntpdmdoc)</code>
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+<br><dt><code>dscp</code> <kbd>value</kbd><dd>This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6-bit code. The default value is 46, signifying Expedited Forwarding.
+<br><dt><code>enable</code> <code>[auth | bclient | calibrate | kernel | mode7 | monitor | ntp | stats]</code><br><dt><code>disable</code> <code>[auth | bclient | calibrate | kernel | mode7 | monitor | ntp | stats]</code><dd>Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+<code>ntpdc(1ntpdcmdoc)</code>
+utility program.
+ <dl>
+<dt><code>auth</code><dd>Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+<code>enable</code>.
+<br><dt><code>bclient</code><dd>Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+<code>multicastclient</code>
+command with default
+address.
+The default for this flag is
+<code>disable</code>.
+<br><dt><code>calibrate</code><dd>Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+<code>disable</code>.
+<br><dt><code>kernel</code><dd>Enables the kernel time discipline, if available.
+The default for this
+flag is
+<code>enable</code>
+if support is available, otherwise
+<code>disable</code>.
+<br><dt><code>mode7</code><dd>Enables processing of NTP mode 7 implementation-specific requests
+which are used by the deprecated
+<code>ntpdc(1ntpdcmdoc)</code>
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+<code>ntpq(1ntpqmdoc)</code>.
+The
+<code>ntpq(1ntpqmdoc)</code>
+program provides the same capabilities as
+<code>ntpdc(1ntpdcmdoc)</code>
+using standard mode 6 requests.
+<br><dt><code>monitor</code><dd>Enables the monitoring facility.
+See the
+<code>ntpdc(1ntpdcmdoc)</code>
+program
+and the
+<code>monlist</code>
+command or further information.
+The
+default for this flag is
+<code>enable</code>.
+<br><dt><code>ntp</code><dd>Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+<code>enable</code>.
+<br><dt><code>stats</code><dd>Enables the statistics facility.
+See the
+<a href="#Monitoring-Options">Monitoring Options</a>
+section for further information.
+The default for this flag is
+<code>disable</code>.
+</dl>
+ <br><dt><code>includefile</code> <kbd>includefile</kbd><dd>This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+<code>ntpd(1ntpdmdoc)</code>
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+<br><dt><code>leapsmearinterval</code> <kbd>seconds</kbd><dd>This EXPERIMENTAL option is only available if
+<code>ntpd(1ntpdmdoc)</code>
+was built with the
+<code>--enable-leap-smear</code>
+option to the
+<code>configure</code>
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+<br><dt><code>logconfig</code> <kbd>configkeyword</kbd><dd>This command controls the amount and type of output written to
+the system
+<code>syslog(3)</code>
+facility or the alternate
+<code>logfile</code>
+log file.
+By default, all output is turned on.
+All
+<kbd>configkeyword</kbd>
+keywords can be prefixed with
+=,
++
+and
+-,
+where
+=
+sets the
+<code>syslog(3)</code>
+priority mask,
++
+adds and
+-
+removes
+messages.
+<code>syslog(3)</code>
+messages can be controlled in four
+classes
+(<code>clock</code>, <code>peer</code>, <code>sys</code> and <code>sync</code>).
+Within these classes four types of messages can be
+controlled: informational messages
+(<code>info</code>),
+event messages
+(<code>events</code>),
+statistics messages
+(<code>statistics</code>)
+and
+status messages
+(<code>status</code>).
+
+ <p>Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+<code>all</code>
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+<code>all</code>
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+<pre class="verbatim">
+ logconfig =syncstatus +sysevents
+</pre>
+
+ <p>This would just list the synchronizations state of
+<code>ntpd(1ntpdmdoc)</code>
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+<pre class="verbatim">
+ logconfig =syncall +clockall
+</pre>
+
+ <p>This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+<br><dt><code>logfile</code> <kbd>logfile</kbd><dd>This command specifies the location of an alternate log file to
+be used instead of the default system
+<code>syslog(3)</code>
+facility.
+This is the same operation as the -l command line option.
+<br><dt><code>setvar</code> <kbd>variable</kbd> <code>[default]</code><dd>This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+<code>name</code><code>=</code><kbd>value</kbd>
+is followed by the
+<code>default</code>
+keyword, the
+variable will be listed as part of the default system variables
+(<code>rv</code> command)).
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+<code>setvar</code>
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+<code>sys_var_list</code>
+holds
+the names of all system variables.
+The
+<code>peer_var_list</code>
+holds
+the names of all peer variables and the
+<code>clock_var_list</code>
+holds the names of the reference clock variables.
+<br><dt><code>tinker</code> <code>[allan </code><kbd>allan</kbd><code> | dispersion </code><kbd>dispersion</kbd><code> | freq </code><kbd>freq</kbd><code> | huffpuff </code><kbd>huffpuff</kbd><code> | panic </code><kbd>panic</kbd><code> | step </code><kbd>step</kbd><code> | stepback </code><kbd>stepback</kbd><code> | stepfwd </code><kbd>stepfwd</kbd><code> | stepout </code><kbd>stepout</kbd><code>]</code><dd>This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+
+ <p>The variables operate as follows:
+ <dl>
+<dt><code>allan</code> <kbd>allan</kbd><dd>The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+<br><dt><code>dispersion</code> <kbd>dispersion</kbd><dd>The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+<br><dt><code>freq</code> <kbd>freq</kbd><dd>The argument becomes the initial value of the frequency offset in
+parts-per-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+<br><dt><code>huffpuff</code> <kbd>huffpuff</kbd><dd>The argument becomes the new value for the experimental
+huff-n'-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+<br><dt><code>panic</code> <kbd>panic</kbd><dd>The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+<br><dt><code>step</code> <kbd>step</kbd><dd>The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+<br><dt><code>stepback</code> <kbd>stepback</kbd><dd>The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+<br><dt><code>stepfwd</code> <kbd>stepfwd</kbd><dd>As for stepback, but for the forward direction.
+<br><dt><code>stepout</code> <kbd>stepout</kbd><dd>The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+</dl>
+ <br><dt><code>rlimit</code> <code>[memlock </code><kbd>Nmegabytes</kbd><code> | stacksize </code><kbd>N4kPages</kbd><code> filenum </code><kbd>Nfiledescriptors</kbd><code>]</code><dd>
+ <dl>
+<dt><code>memlock</code> <kbd>Nmegabytes</kbd><dd>Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+<code>-i</code>
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+<br><dt><code>stacksize</code> <kbd>N4kPages</kbd><dd>Specifies the maximum size of the process stack on systems with the
+<code>mlockall()</code>
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+<br><dt><code>filenum</code> <kbd>Nfiledescriptors</kbd><dd>Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+</dl>
+ <br><dt><code>trap</code> <kbd>host_address</kbd> <code>[port </code><kbd>port_number</kbd><code>]</code> <code>[interface </code><kbd>interface_address</kbd><code>]</code><dd>This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+
+ <p>The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+<br><dt><code>hop</code> <kbd>...</kbd><dd>This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding-ring search.
+The default is eight multiples of 32 starting at
+31.
+</dl>
+
+ <p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp.conf</code> program.
+This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
+
+<ul class="menu">
+<li><a accesskey="1" href="#ntp_002econf-Files">ntp.conf Files</a>: Files
+<li><a accesskey="2" href="#ntp_002econf-See-Also">ntp.conf See Also</a>: See Also
+<li><a accesskey="3" href="#ntp_002econf-Bugs">ntp.conf Bugs</a>: Bugs
+<li><a accesskey="4" href="#ntp_002econf-Notes">ntp.conf Notes</a>: Notes
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="ntp_002econf-Files"></a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.conf Files</h4>
+
+ <dl>
+<dt><span class="file">/etc/ntp.conf</span><dd>the default name of the configuration file
+<br><dt><span class="file">ntp.keys</span><dd>private MD5 keys
+<br><dt><span class="file">ntpkey</span><dd>RSA private key
+<br><dt><span class="file">ntpkey_</span><kbd>host</kbd><dd>RSA public key
+<br><dt><span class="file">ntp_dh</span><dd>Diffie-Hellman agreement parameters
+</dl>
+<div class="node">
+<p><hr>
+<a name="ntp_002econf-See-Also"></a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.conf See Also</h4>
+
+<p><code>ntpd(1ntpdmdoc)</code>,
+<code>ntpdc(1ntpdcmdoc)</code>,
+<code>ntpq(1ntpqmdoc)</code>
+
+ <p>In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+<code>http://www.ntp.org/</code>.
+A snapshot of this documentation is available in HTML format in
+<span class="file">/usr/share/doc/ntp</span>.
+<br>
+
+ <p><br>
+David L. Mills, <em>Network Time Protocol (Version 4)</em>, RFC5905
+<div class="node">
+<p><hr>
+<a name="ntp_002econf-Bugs"></a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.conf Bugs</h4>
+
+<p>The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+
+ <p>The
+<span class="file">ntpkey_</span><kbd>host</kbd>
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+<div class="node">
+<p><hr>
+<a name="ntp_002econf-Notes"></a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.conf Notes</h4>
+
+<p>This document was derived from FreeBSD.
+
+</body></html>
+
diff --git a/contrib/ntp/ntpd/ntp.conf.man.in b/contrib/ntp/ntpd/ntp.conf.man.in
new file mode 100644
index 0000000..ef9e14d
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.man.in
@@ -0,0 +1,3052 @@
+.de1 NOP
+. it 1 an-trap
+. if \\n[.$] \,\\$*\/
+..
+.ie t \
+.ds B-Font [CB]
+.ds I-Font [CI]
+.ds R-Font [CR]
+.el \
+.ds B-Font B
+.ds I-Font I
+.ds R-Font R
+.TH ntp.conf 5 "29 Jun 2015" "4.2.8p3" "File Formats"
+.\"
+.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-R0aO7B/ag-30aG6B)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:16 PM by AutoGen 5.18.5
+.\" From the definitions ntp.conf.def
+.\" and the template file agman-cmd.tpl
+.SH NAME
+\f\*[B-Font]ntp.conf\fP
+\- Network Time Protocol (NTP) daemon configuration file format
+.SH SYNOPSIS
+\f\*[B-Font]ntp.conf\fP
+[\f\*[B-Font]\-\-option-name\f[]]
+[\f\*[B-Font]\-\-option-name\f[] \f\*[I-Font]value\f[]]
+.sp \n(Ppu
+.ne 2
+
+All arguments must be options.
+.sp \n(Ppu
+.ne 2
+
+.SH DESCRIPTION
+The
+\f\*[B-Font]ntp.conf\fP
+configuration file is read at initial startup by the
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+\fI/etc\f[]
+directory,
+but could be installed elsewhere
+(see the daemon's
+\f\*[B-Font]\-c\f[]
+command line option).
+.sp \n(Ppu
+.ne 2
+
+The file format is similar to other
+UNIX
+configuration files.
+Comments begin with a
+\[oq]#\[cq]
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+.sp \n(Ppu
+.ne 2
+
+The rest of this page describes the configuration and control options.
+The
+"Notes on Configuring NTP and Setting up an NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+contains an extended discussion of these options.
+In addition to the discussion of general
+\fIConfiguration\f[] \fIOptions\f[],
+there are sections describing the following supported functionality
+and the options used to control it:
+.IP \fB\(bu\fP 2
+\fIAuthentication\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIMonitoring\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIAccess\f[] \fIControl\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIAutomatic\f[] \fINTP\f[] \fIConfiguration\f[] \fIOptions\f[]
+.IP \fB\(bu\fP 2
+\fIReference\f[] \fIClock\f[] \fISupport\f[]
+.IP \fB\(bu\fP 2
+\fIMiscellaneous\f[] \fIOptions\f[]
+.PP
+.sp \n(Ppu
+.ne 2
+
+Following these is a section describing
+\fIMiscellaneous\f[] \fIOptions\f[].
+While there is a rich set of options available,
+the only required option is one or more
+\f\*[B-Font]pool\f[],
+\f\*[B-Font]server\f[],
+\f\*[B-Font]peer\f[],
+\f\*[B-Font]broadcast\f[]
+or
+\f\*[B-Font]manycastclient\f[]
+commands.
+.SH Configuration Support
+Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+.SS Configuration Commands
+The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+.sp \n(Ppu
+.ne 2
+
+If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+\*[Lq]\&:\*[Rq]
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+.sp \n(Ppu
+.ne 2
+
+Note that in contexts where a host name is expected, a
+\f\*[B-Font]\-4\f[]
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+\f\*[B-Font]\-6\f[]
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+.TP 7
+.NOP \f\*[B-Font]pool\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]burst\f[]] [\f\*[B-Font]iburst\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]]
+.TP 7
+.NOP \f\*[B-Font]server\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]burst\f[]] [\f\*[B-Font]iburst\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]]
+.TP 7
+.NOP \f\*[B-Font]peer\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]]
+.TP 7
+.NOP \f\*[B-Font]broadcast\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]ttl\f[] \f\*[I-Font]ttl\f[]]
+.TP 7
+.NOP \f\*[B-Font]manycastclient\f[] \f\*[I-Font]address\f[] [\f\*[B-Font]key\f[] \f\*[I-Font]key\f[] \f\*[I-Font]\&|\f[] \f\*[B-Font]autokey\f[]] [\f\*[B-Font]version\f[] \f\*[I-Font]version\f[]] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]] [\f\*[B-Font]ttl\f[] \f\*[I-Font]ttl\f[]]
+.PP
+.sp \n(Ppu
+.ne 2
+
+These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+\f\*[I-Font]address\f[]
+can be
+either a DNS name or an IP address in dotted-quad notation.
+Additional information on association behavior can be found in the
+"Association Management"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.TP 7
+.NOP \f\*[B-Font]pool\f[]
+For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+.TP 7
+.NOP \f\*[B-Font]server\f[]
+For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+\fInot\f[]
+be used for type
+b or m addresses.
+.TP 7
+.NOP \f\*[B-Font]peer\f[]
+For type s addresses (only), this command mobilizes a
+persistent symmetric-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+.TP 7
+.NOP \f\*[B-Font]broadcast\f[]
+For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+\f\*[I-Font]address\f[]
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+\f\*[B-Font]broadcastclient\f[]
+or
+\f\*[B-Font]multicastclient\f[]
+commands
+below.
+.TP 7
+.NOP \f\*[B-Font]manycastclient\f[]
+For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+\f\*[B-Font]manycastserver\f[]
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+\f\*[B-Font]manycastserver\f[]
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+\f\*[I-Font]address\f[]
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+\f\*[B-Font]server\f[]
+command.
+The remaining servers are discarded as if never
+heard.
+.PP
+.sp \n(Ppu
+.ne 2
+
+Options:
+.TP 7
+.NOP \f\*[B-Font]autokey\f[]
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]burst\f[]
+when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+\f\*[B-Font]server\f[]
+command and s addresses.
+.TP 7
+.NOP \f\*[B-Font]iburst\f[]
+When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+\f\*[B-Font]server\f[]
+command and s addresses and when
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+is started with the
+\f\*[B-Font]\-q\f[]
+option.
+.TP 7
+.NOP \f\*[B-Font]key\f[] \f\*[I-Font]key\f[]
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+\f\*[I-Font]key\f[]
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+.TP 7
+.NOP \f\*[B-Font]minpoll\f[] \f\*[I-Font]minpoll\f[]
+.TP 7
+.NOP \f\*[B-Font]maxpoll\f[] \f\*[I-Font]maxpoll\f[]
+These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+\f\*[B-Font]maxpoll\f[]
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+\f\*[B-Font]minpoll\f[]
+option to a lower limit of 4 (16 s).
+.TP 7
+.NOP \f\*[B-Font]noselect\f[]
+Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+.TP 7
+.NOP \f\*[B-Font]prefer\f[]
+Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+for further information.
+.TP 7
+.NOP \f\*[B-Font]ttl\f[] \f\*[I-Font]ttl\f[]
+This option is used only with broadcast server and manycast
+client modes.
+It specifies the time-to-live
+\f\*[I-Font]ttl\f[]
+to
+use on broadcast server and multicast server and the maximum
+\f\*[I-Font]ttl\f[]
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+.TP 7
+.NOP \f\*[B-Font]version\f[] \f\*[I-Font]version\f[]
+Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1-4 are the choices, with version 4 the
+default.
+.PP
+.SS Auxiliary Commands
+.TP 7
+.NOP \f\*[B-Font]broadcastclient\f[]
+This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric-key or public-key
+authentication as described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]manycastserver\f[] \f\*[I-Font]address\f[] \f\*[I-Font]...\f[]
+This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric-key or public-key
+authentication as described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]multicastclient\f[] \f\*[I-Font]address\f[] \f\*[I-Font]...\f[]
+This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric-key or
+public-key authentication as described in
+\fIAuthentication\f[] \fIOptions\f[].
+.TP 7
+.NOP \f\*[B-Font]mdnstries\f[] \f\*[I-Font]number\f[]
+If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+\f\*[B-Font]mdnstries\f[]
+times.
+After all,
+\f\*[B-Font]ntpd\f[]
+may be starting before mDNS.
+The default value for
+\f\*[B-Font]mdnstries\f[]
+is 5.
+.PP
+.SH Authentication Support
+Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed-MD5.
+Either algorithm computes a message digest, or one-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+.sp \n(Ppu
+.ne 2
+
+NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+.sp \n(Ppu
+.ne 2
+
+While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+.sp \n(Ppu
+.ne 2
+
+Authentication is configured separately for each association
+using the
+\f\*[B-Font]key\f[]
+or
+\f\*[B-Font]autokey\f[]
+subcommand on the
+\f\*[B-Font]peer\f[],
+\f\*[B-Font]server\f[],
+\f\*[B-Font]broadcast\f[]
+and
+\f\*[B-Font]manycastclient\f[]
+configuration commands as described in
+\fIConfiguration\f[] \fIOptions\f[]
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+.sp \n(Ppu
+.ne 2
+
+Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]auth\f[]
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+\f\*[B-Font]enable\f[]
+and
+\f\*[B-Font]disable\f[]
+commands and also by remote
+configuration commands sent by a
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+\f\*[B-Font]auth\f[]
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+.sp \n(Ppu
+.ne 2
+
+An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+\fIAutomatic\f[] \fINTP\f[] \fIConfiguration\f[] \fIOptions\f[]
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+.sp \n(Ppu
+.ne 2
+
+The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+\f[C]http://www.ntp.org/\f[].
+.SS Symmetric-Key Cryptography
+The original RFC-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+\fIntp.keys\f[],
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+utility programs.
+.sp \n(Ppu
+.ne 2
+
+When
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+is first started, it reads the key file specified in the
+\f\*[B-Font]keys\f[]
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+\f\*[B-Font]trusted\f[]
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[].
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+\f\*[B-Font]requestkey\f[]
+command selects the key used as the password for the
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+utility, while the
+\f\*[B-Font]controlkey\f[]
+command selects the key used as the password for the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+utility.
+.SS Public Key Cryptography
+NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+.\" .Pp
+.\" The cryptographic means necessary for all Autokey operations
+.\" is provided by the OpenSSL software library.
+.\" This library is available from http://www.openssl.org/
+.\" and can be installed using the procedures outlined
+.\" in the Building and Installing the Distribution page.
+.\" Once installed,
+.\" the configure and build
+.\" process automatically detects the library and links
+.\" the library routines required.
+.sp \n(Ppu
+.ne 2
+
+The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S-KEY scheme,
+in which a pseudo-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+\fIAutonomous\f[] \fIAuthentication\f[]
+page.
+.sp \n(Ppu
+.ne 2
+
+The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+\fCntp-keygen\f[]\fR(1ntpkeygenmdoc)\f[]
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+\f\*[B-Font]md5WithRSAEncryption\f[],
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+.sp \n(Ppu
+.ne 2
+
+NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+.SS Naming and Addressing
+It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+.sp \n(Ppu
+.ne 2
+
+By convention, the name of an Autokey host is the name returned
+by the Unix
+\fCgethostname\f[]\fR(2)\f[]
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+.sp \n(Ppu
+.ne 2
+
+It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+.SS Operation
+A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+.sp \n(Ppu
+.ne 2
+
+The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+\f\*[B-Font]server\f[]
+or
+\f\*[B-Font]peer\f[]
+configuration command and no
+\f\*[B-Font]key\f[]
+or
+\f\*[B-Font]autokey\f[]
+subcommands are present, the association is not
+authenticated; if the
+\f\*[B-Font]key\f[]
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+\f\*[B-Font]autokey\f[]
+subcommand is present, the association is authenticated
+using Autokey.
+.sp \n(Ppu
+.ne 2
+
+When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+.sp \n(Ppu
+.ne 2
+
+Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+.sp \n(Ppu
+.ne 2
+
+Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto-NAK, which tells her
+something broke.
+She can see the evidence using the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+program.
+.sp \n(Ppu
+.ne 2
+
+Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+.sp \n(Ppu
+.ne 2
+
+It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+.SS Key Management
+The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+\fCntp-keygen\f[]\fR(1ntpkeygenmdoc)\f[]
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+.sp \n(Ppu
+.ne 2
+
+Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+\f\*[B-Font]trustRoot\f[];.
+Other extension fields are ignored.
+.SS Authentication Commands
+.TP 7
+.NOP \f\*[B-Font]autokey\f[] [\f\*[I-Font]logsec\f[]]
+Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+.TP 7
+.NOP \f\*[B-Font]controlkey\f[] \f\*[I-Font]key\f[]
+Specifies the key identifier to use with the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+utility, which uses the standard
+protocol defined in RFC-1305.
+The
+\f\*[I-Font]key\f[]
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+.TP 7
+.NOP \f\*[B-Font]crypto\f[] [\f\*[B-Font]cert\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]leap\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]randfile\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]host\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]sign\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gq\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gqpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]iffpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]mvpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]pw\f[] \f\*[I-Font]password\f[]]
+This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+\f\*[B-Font]keysdir\f[]
+command or default
+\fI/usr/local/etc\f[].
+Following are the subcommands:
+.RS
+.TP 7
+.NOP \f\*[B-Font]cert\f[] \f\*[I-Font]file\f[]
+Specifies the location of the required host public certificate file.
+This overrides the link
+\fIntpkey_cert_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]gqpar\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+\fIntpkey_gq_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]host\f[] \f\*[I-Font]file\f[]
+Specifies the location of the required host key file.
+This overrides
+the link
+\fIntpkey_key_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]iffpar\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional IFF parameters file.This
+overrides the link
+\fIntpkey_iff_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]leap\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional leapsecond file.
+This overrides the link
+\fIntpkey_leap\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]mvpar\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional MV parameters file.
+This
+overrides the link
+\fIntpkey_mv_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+.TP 7
+.NOP \f\*[B-Font]pw\f[] \f\*[I-Font]password\f[]
+Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+.TP 7
+.NOP \f\*[B-Font]randfile\f[] \f\*[I-Font]file\f[]
+Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+.TP 7
+.NOP \f\*[B-Font]sign\f[] \f\*[I-Font]file\f[]
+Specifies the location of the optional sign key file.
+This overrides
+the link
+\fIntpkey_sign_\f[]\f\*[I-Font]hostname\f[]
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+.RE
+.TP 7
+.NOP \f\*[B-Font]keys\f[] \f\*[I-Font]keyfile\f[]
+Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+\fCntpd\f[]\fR(@NTPD_MS@)\f[],
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+when operating with symmetric key cryptography.
+This is the same operation as the
+\f\*[B-Font]\-k\f[]
+command line option.
+.TP 7
+.NOP \f\*[B-Font]keysdir\f[] \f\*[I-Font]path\f[]
+This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+\fI/usr/local/etc/\f[].
+.TP 7
+.NOP \f\*[B-Font]requestkey\f[] \f\*[I-Font]key\f[]
+Specifies the key identifier to use with the
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+utility program, which uses a
+proprietary protocol specific to this implementation of
+\fCntpd\f[]\fR(@NTPD_MS@)\f[].
+The
+\f\*[I-Font]key\f[]
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+.TP 7
+.NOP \f\*[B-Font]revoke\f[] \f\*[I-Font]logsec\f[]
+Specifies the interval between re-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+.TP 7
+.NOP \f\*[B-Font]trustedkey\f[] \f\*[I-Font]key\f[] \f\*[I-Font]...\f[]
+Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+\f\*[I-Font]key\f[]
+arguments are 32-bit unsigned
+integers with values from 1 to 65,534.
+.PP
+.SS Error Codes
+The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+.TP 7
+.NOP 101
+(bad field format or length)
+The packet has invalid version, length or format.
+.TP 7
+.NOP 102
+(bad timestamp)
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+.TP 7
+.NOP 103
+(bad filestamp)
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+.TP 7
+.NOP 104
+(bad or missing public key)
+The public key is missing, has incorrect format or is an unsupported type.
+.TP 7
+.NOP 105
+(unsupported digest type)
+The server requires an unsupported digest/signature scheme.
+.TP 7
+.NOP 106
+(mismatched digest types)
+Not used.
+.TP 7
+.NOP 107
+(bad signature length)
+The signature length does not match the current public key.
+.TP 7
+.NOP 108
+(signature not verified)
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+.TP 7
+.NOP 109
+(certificate not verified)
+The certificate is invalid or signed with the wrong key.
+.TP 7
+.NOP 110
+(certificate not verified)
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+.TP 7
+.NOP 111
+(bad or missing cookie)
+The cookie is missing, corrupted or bogus.
+.TP 7
+.NOP 112
+(bad or missing leapseconds table)
+The leapseconds table is missing, corrupted or bogus.
+.TP 7
+.NOP 113
+(bad or missing certificate)
+The certificate is missing, corrupted or bogus.
+.TP 7
+.NOP 114
+(bad or missing identity)
+The identity key is missing, corrupt or bogus.
+.PP
+.SH Monitoring Support
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+\f\*[B-Font]statistics\f[]
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+\fI./scripts\f[]
+directory of this distribution.
+Using
+these facilities and
+UNIX
+\fCcron\f[]\fR(8)\f[]
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+.SS Monitoring Commands
+.TP 7
+.NOP \f\*[B-Font]statistics\f[] \f\*[I-Font]name\f[] \f\*[I-Font]...\f[]
+Enables writing of statistics records.
+Currently, eight kinds of
+\f\*[I-Font]name\f[]
+statistics are supported.
+.RS
+.TP 7
+.NOP \f\*[B-Font]clockstats\f[]
+Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+\f\*[B-Font]clockstats\f[]:
+.br
+.in +4
+.nf
+49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+.TP 7
+.NOP \f\*[B-Font]cryptostats\f[]
+This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+\f\*[B-Font]cryptostats\f[]:
+.br
+.in +4
+.nf
+49213 525.624 127.127.4.1 message
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+\fIAuthentication\f[] \fIOptions\f[]
+section for further information.
+.TP 7
+.NOP \f\*[B-Font]loopstats\f[]
+Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+\f\*[B-Font]loopstats\f[]:
+.br
+.in +4
+.nf
+50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million \-
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+.TP 7
+.NOP \f\*[B-Font]peerstats\f[]
+Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+\f\*[B-Font]peerstats\f[]:
+.br
+.in +4
+.nf
+48773 10847.650 127.127.4.1 9714 \-0.001605376 0.000000000 0.001424877 0.000958674
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+.TP 7
+.NOP \f\*[B-Font]rawstats\f[]
+Enables recording of raw-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+\f\*[B-Font]rawstats\f[]:
+.br
+.in +4
+.nf
+50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+.TP 7
+.NOP \f\*[B-Font]sysstats\f[]
+Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+\f\*[B-Font]sysstats\f[]:
+.br
+.in +4
+.nf
+50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+.RS
+.TP 7
+.NOP Time since restart \f\*[B-Font]36000\f[]
+Time in hours since the system was last rebooted.
+.TP 7
+.NOP Packets received \f\*[B-Font]81965\f[]
+Total number of packets received.
+.TP 7
+.NOP Packets processed \f\*[B-Font]0\f[]
+Number of packets received in response to previous packets sent
+.TP 7
+.NOP Current version \f\*[B-Font]9546\f[]
+Number of packets matching the current NTP version.
+.TP 7
+.NOP Previous version \f\*[B-Font]56\f[]
+Number of packets matching the previous NTP version.
+.TP 7
+.NOP Bad version \f\*[B-Font]71793\f[]
+Number of packets matching neither NTP version.
+.TP 7
+.NOP Access denied \f\*[B-Font]512\f[]
+Number of packets denied access for any reason.
+.TP 7
+.NOP Bad length or format \f\*[B-Font]540\f[]
+Number of packets with invalid length, format or port number.
+.TP 7
+.NOP Bad authentication \f\*[B-Font]10\f[]
+Number of packets not verified as authentic.
+.TP 7
+.NOP Rate exceeded \f\*[B-Font]147\f[]
+Number of packets discarded due to rate limitation.
+.RE
+.TP 7
+.NOP \f\*[B-Font]statsdir\f[] \f\*[I-Font]directory_path\f[]
+Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+\f\*[B-Font]filegen\f[]
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+.TP 7
+.NOP \f\*[B-Font]filegen\f[] \f\*[I-Font]name\f[] [\f\*[B-Font]file\f[] \f\*[I-Font]filename\f[]] [\f\*[B-Font]type\f[] \f\*[I-Font]typename\f[]] [\f\*[B-Font]link\f[] | \f\*[B-Font]nolink\f[]] [\f\*[B-Font]enable\f[] | \f\*[B-Font]disable\f[]]
+Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+.sp \n(Ppu
+.ne 2
+
+Note that this command can be sent from the
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+program running at a remote location.
+.RS
+.TP 7
+.NOP \f\*[B-Font]name\f[]
+This is the type of the statistics records, as shown in the
+\f\*[B-Font]statistics\f[]
+command.
+.TP 7
+.NOP \f\*[B-Font]file\f[] \f\*[I-Font]filename\f[]
+This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+\f\*[B-Font]prefix\f[],
+\f\*[B-Font]filename\f[]
+and
+\f\*[B-Font]suffix\f[]:
+.RS
+.TP 7
+.NOP \f\*[B-Font]prefix\f[]
+This is a constant filename path.
+It is not subject to
+modifications via the
+\f\*[I-Font]filegen\f[]
+option.
+It is defined by the
+server, usually specified as a compile-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+\f\*[I-Font]loopstats\f[]
+and
+\f\*[I-Font]peerstats\f[]
+generation can be configured using the
+\f\*[I-Font]statsdir\f[]
+option explained above.
+.TP 7
+.NOP \f\*[B-Font]filename\f[]
+This string is directly concatenated to the prefix mentioned
+above (no intervening
+\[oq]/\[cq]).
+This can be modified using
+the file argument to the
+\f\*[I-Font]filegen\f[]
+statement.
+No
+\fI..\f[]
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+\f\*[I-Font]prefix\f[].
+.TP 7
+.NOP \f\*[B-Font]suffix\f[]
+This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+.RE
+.TP 7
+.NOP \f\*[B-Font]type\f[] \f\*[I-Font]typename\f[]
+A file generation set is characterized by its type.
+The following
+types are supported:
+.RS
+.TP 7
+.NOP \f\*[B-Font]none\f[]
+The file set is actually a single plain file.
+.TP 7
+.NOP \f\*[B-Font]pid\f[]
+One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+server incarnations.
+The set member filename is built by appending a
+\[oq]\&.\[cq]
+to concatenated
+\f\*[I-Font]prefix\f[]
+and
+\f\*[I-Font]filename\f[]
+strings, and
+appending the decimal representation of the process ID of the
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+server process.
+.TP 7
+.NOP \f\*[B-Font]day\f[]
+One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+\[oq]\&.\[cq]
+and a day specification in
+the form
+\f\*[B-Font]YYYYMMdd\f[].
+\f\*[B-Font]YYYY\f[]
+is a 4-digit year number (e.g., 1992).
+\f\*[B-Font]MM\f[]
+is a two digit month number.
+\f\*[B-Font]dd\f[]
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+\f\*[I-Font]prefix\f[]
+\f\*[I-Font]filename\f[].19921210.
+.TP 7
+.NOP \f\*[B-Font]week\f[]
+Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day-of-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4-digit year number, the letter
+\f\*[B-Font]W\f[],
+and a 2-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.NOP. \f\*[I-Font]1992W1\f[].
+.TP 7
+.NOP \f\*[B-Font]month\f[]
+One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4-digit year number, and
+a 2-digit month.
+.TP 7
+.NOP \f\*[B-Font]year\f[]
+One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+.TP 7
+.NOP \f\*[B-Font]age\f[]
+This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+\f\*[B-Font]a\f[],
+and an 8-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24-hour period.
+Information is only written to a file generation by specifying
+\f\*[B-Font]enable\f[];
+output is prevented by specifying
+\f\*[B-Font]disable\f[].
+.RE
+.TP 7
+.NOP \f\*[B-Font]link\f[] | \f\*[B-Font]nolink\f[]
+It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+\f\*[B-Font]link\f[]
+and disabled using
+\f\*[B-Font]nolink\f[].
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+\f\*[B-Font]C\f[],
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+.TP 7
+.NOP \f\*[B-Font]enable\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]disable\f[]
+Enables or disables the recording function.
+.RE
+.RE
+.PP
+.SH Access Control Support
+The
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+"Notes on Configuring NTP and Setting up a NTP Subnet"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.sp \n(Ppu
+.ne 2
+
+The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+.sp \n(Ppu
+.ne 2
+
+Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+.SS The Kiss-of-Death Packet
+Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss-of-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four-byte
+ASCII code.
+If the
+\f\*[B-Font]noserve\f[]
+or
+\f\*[B-Font]notrust\f[]
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+\f\*[B-Font]limited\f[]
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+.sp \n(Ppu
+.ne 2
+
+A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+.SS Access Control Commands
+.TP 7
+.NOP \f\*[B-Font]discard\f[] [\f\*[B-Font]average\f[] \f\*[I-Font]avg\f[]] [\f\*[B-Font]minimum\f[] \f\*[I-Font]min\f[]] [\f\*[B-Font]monitor\f[] \f\*[I-Font]prob\f[]]
+Set the parameters of the
+\f\*[B-Font]limited\f[]
+facility which protects the server from
+client abuse.
+The
+\f\*[B-Font]average\f[]
+subcommand specifies the minimum average packet
+spacing, while the
+\f\*[B-Font]minimum\f[]
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss-o'-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate-control window.
+.TP 7
+.NOP \f\*[B-Font]restrict\f[] \f\*[B-Font]address\f[] [\f\*[B-Font]mask\f[] \f\*[I-Font]mask\f[]] [\f\*[I-Font]flag\f[] \f\*[I-Font]...\f[]]
+The
+\f\*[I-Font]address\f[]
+argument expressed in
+dotted-quad form is the address of a host or network.
+Alternatively, the
+\f\*[I-Font]address\f[]
+argument can be a valid host DNS name.
+The
+\f\*[I-Font]mask\f[]
+argument expressed in dotted-quad form defaults to
+\f\*[B-Font]255.255.255.255\f[],
+meaning that the
+\f\*[I-Font]address\f[]
+is treated as the address of an individual host.
+A default entry (address
+\f\*[B-Font]0.0.0.0\f[],
+mask
+\f\*[B-Font]0.0.0.0\f[])
+is always included and is always the first entry in the list.
+Note that text string
+\f\*[B-Font]default\f[],
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+\f\*[B-Font]flag\f[]
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+.RS
+.TP 7
+.NOP \f\*[B-Font]ignore\f[]
+Deny packets of all kinds, including
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+queries.
+.TP 7
+.NOP \f\*[B-Font]kod\f[]
+If this flag is set when an access violation occurs, a kiss-o'-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+.TP 7
+.NOP \f\*[B-Font]limited\f[]
+Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+\fCntpd\f[]\fR(@NTPD_MS@)\f[].
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+\f\*[B-Font]limited\f[]
+flag.
+.TP 7
+.NOP \f\*[B-Font]lowpriotrap\f[]
+Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+.TP 7
+.NOP \f\*[B-Font]nomodify\f[]
+Deny
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+.TP 7
+.NOP \f\*[B-Font]noquery\f[]
+Deny
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+queries.
+Time service is not affected.
+.TP 7
+.NOP \f\*[B-Font]nopeer\f[]
+Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+\f\*[B-Font]pool\f[]
+associations, so if you want to use servers from a
+\f\*[B-Font]pool\f[]
+directive and also want to use
+\f\*[B-Font]nopeer\f[]
+by default, you'll want a
+\f\*[B-Font]restrict source ...\f[] \f\*[B-Font]line\f[] \f\*[B-Font]as\f[] \f\*[B-Font]well\f[] \f\*[B-Font]that\f[] \f\*[B-Font]does\f[]
+.TP 7
+.NOP not
+include the
+\f\*[B-Font]nopeer\f[]
+directive.
+.TP 7
+.NOP \f\*[B-Font]noserve\f[]
+Deny all packets except
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+queries.
+.TP 7
+.NOP \f\*[B-Font]notrap\f[]
+Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+.TP 7
+.NOP \f\*[B-Font]notrust\f[]
+Deny service unless the packet is cryptographically authenticated.
+.TP 7
+.NOP \f\*[B-Font]ntpport\f[]
+This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+\f\*[B-Font]ntpport\f[]
+and
+\f\*[B-Font]non-ntpport\f[]
+may
+be specified.
+The
+\f\*[B-Font]ntpport\f[]
+is considered more specific and
+is sorted later in the list.
+.TP 7
+.NOP \f\*[B-Font]version\f[]
+Deny packets that do not match the current NTP version.
+.RE
+.sp \n(Ppu
+.ne 2
+
+Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+.PP
+.SH Automatic NTP Configuration Options
+.SS Manycasting
+Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+.sp \n(Ppu
+.ne 2
+
+Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+.sp \n(Ppu
+.ne 2
+
+Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+\f[C]http://www.openssl.org/\f[].
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+.sp \n(Ppu
+.ne 2
+
+A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+\f\*[B-Font]D\f[]
+or IPv6 prefix
+\f\*[B-Font]FF\f[])
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time-to-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+.sp \n(Ppu
+.ne 2
+
+Manycast servers configured with the
+\f\*[B-Font]manycastserver\f[]
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+.sp \n(Ppu
+.ne 2
+
+The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+.sp \n(Ppu
+.ne 2
+
+The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+\f\*[B-Font]manycastclient\f[],
+\f\*[B-Font]tos\f[]
+and
+\f\*[B-Font]ttl\f[]
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+\f\*[B-Font]minpoll\f[]
+value specified in the
+\f\*[B-Font]manycastclient\f[],
+command and, under normal circumstances, increments to the
+\f\*[B-Font]maxpolll\f[]
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+.sp \n(Ppu
+.ne 2
+
+The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+\f\*[B-Font]minclock\f[]
+and
+\f\*[B-Font]minsane\f[]
+values specified in the
+\f\*[B-Font]tos\f[]
+configuration command.
+At least
+\f\*[B-Font]minsane\f[]
+candidate servers must be available and the mitigation
+algorithms produce at least
+\f\*[B-Font]minclock\f[]
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+\f\*[B-Font]minsane\f[]
+defaults to 1 and
+\f\*[B-Font]minclock\f[]
+defaults to 3.
+For manycast service
+\f\*[B-Font]minsane\f[]
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+.sp \n(Ppu
+.ne 2
+
+If at least
+\f\*[B-Font]minclock\f[]
+servers are found, the manycast poll interval is immediately
+set to eight times
+\f\*[B-Font]maxpoll\f[].
+If less than
+\f\*[B-Font]minclock\f[]
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+\f\*[B-Font]maxpoll\f[].
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+.sp \n(Ppu
+.ne 2
+
+Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+\f\*[B-Font]ttl\f[]
+configuration command can be
+used to modify the values to match the scope rules.
+.sp \n(Ppu
+.ne 2
+
+It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+\f\*[B-Font]tos\f[]
+command can be used to modify this behavior.
+Servers with stratum below
+\f\*[B-Font]floor\f[]
+or above
+\f\*[B-Font]ceiling\f[]
+specified in the
+\f\*[B-Font]tos\f[]
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+\f\*[B-Font]minclock\f[].
+.sp \n(Ppu
+.ne 2
+
+The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+\f\*[B-Font]minclock\f[],
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+\f\*[B-Font]maxpoll\f[]
+is 12 (4,096 s).
+.sp \n(Ppu
+.ne 2
+
+It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+\f\*[B-Font]multicastclient\f[]
+and
+\f\*[B-Font]multicastserver\f[]
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+.sp \n(Ppu
+.ne 2
+
+The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+\f\*[B-Font]tos\f[]
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+\f\*[B-Font]floor\f[]
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+.sp \n(Ppu
+.ne 2
+
+Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re-associate accordingly.
+.sp \n(Ppu
+.ne 2
+
+Some administrators prefer to avoid running
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+continuously and run either
+\fCntpdate\f[]\fR(8)\f[]
+or
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+\f\*[B-Font]\-q\f[]
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+\f\*[B-Font]\-q\f[].
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+.SS Manycast Interactions with Autokey
+Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+.sp \n(Ppu
+.ne 2
+
+About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+.SS Manycast Options
+.TP 7
+.NOP \f\*[B-Font]tos\f[] [\f\*[B-Font]ceiling\f[] \f\*[I-Font]ceiling\f[] | \f\*[B-Font]cohort\f[] { \f\*[B-Font]0\f[] | \f\*[B-Font]1\f[] } | \f\*[B-Font]floor\f[] \f\*[I-Font]floor\f[] | \f\*[B-Font]minclock\f[] \f\*[I-Font]minclock\f[] | \f\*[B-Font]minsane\f[] \f\*[I-Font]minsane\f[]]
+This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]ceiling\f[] \f\*[I-Font]ceiling\f[]
+Peers with strata above
+\f\*[B-Font]ceiling\f[]
+will be discarded if there are at least
+\f\*[B-Font]minclock\f[]
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+.TP 7
+.NOP \f\*[B-Font]cohort\f[] {0 | 1 }
+This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+.TP 7
+.NOP \f\*[B-Font]floor\f[] \f\*[I-Font]floor\f[]
+Peers with strata below
+\f\*[B-Font]floor\f[]
+will be discarded if there are at least
+\f\*[B-Font]minclock\f[]
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+.TP 7
+.NOP \f\*[B-Font]minclock\f[] \f\*[I-Font]minclock\f[]
+The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+\f\*[B-Font]minclock\f[]
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+.TP 7
+.NOP \f\*[B-Font]minsane\f[] \f\*[I-Font]minsane\f[]
+This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+\f\*[B-Font]minsane\f[]
+should be at least 4 in order to detect and discard
+a single falseticker.
+.RE
+.TP 7
+.NOP \f\*[B-Font]ttl\f[] \f\*[I-Font]hop\f[] \f\*[I-Font]...\f[]
+This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding-ring search.
+The default is eight
+multiples of 32 starting at 31.
+.PP
+.SH Reference Clock Support
+The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+Additional information can be found in the pages linked
+there, including the
+"Debugging Hints for Reference Clock Drivers"
+and
+"How To Write a Reference Clock Driver"
+pages
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+In addition, support for a PPS
+signal is available as described in the
+"Pulse-per-second (PPS) Signal Interfacing"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+"Line Disciplines and Streams Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.sp \n(Ppu
+.ne 2
+
+A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+.sp \n(Ppu
+.ne 2
+
+For the purposes of configuration,
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+\f[C]127.127.\f[]\f\*[I-Font]t\f[].\f\*[I-Font]u\f[],
+where
+\f\*[I-Font]t\f[]
+is an integer
+denoting the clock type and
+\f\*[I-Font]u\f[]
+indicates the unit
+number in the range 0-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]server\f[]
+command is used to configure a reference
+clock, where the
+\f\*[I-Font]address\f[]
+argument in that command
+is the clock address.
+The
+\f\*[B-Font]key\f[],
+\f\*[B-Font]version\f[]
+and
+\f\*[B-Font]ttl\f[]
+options are not used for reference clock support.
+The
+\f\*[B-Font]mode\f[]
+option is added for reference clock support, as
+described below.
+The
+\f\*[B-Font]prefer\f[]
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+"Mitigation Rules and the prefer Keyword"
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+page.
+The
+\f\*[B-Font]minpoll\f[]
+and
+\f\*[B-Font]maxpoll\f[]
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]fudge\f[]
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+\f\*[B-Font]server\f[]
+command.
+The
+\f\*[I-Font]address\f[]
+argument specifies the clock address.
+The
+\f\*[B-Font]refid\f[]
+and
+\f\*[B-Font]stratum\f[]
+options can be used to
+override the defaults for the device.
+There are two optional
+device-dependent time offsets and four flags that can be included
+in the
+\f\*[B-Font]fudge\f[]
+command as well.
+.sp \n(Ppu
+.ne 2
+
+The stratum number of a reference clock is by default zero.
+Since the
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+\f\*[B-Font]stratum\f[]
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse-per-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+\f\*[B-Font]refid\f[]
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+.SS Reference Clock Commands
+.TP 7
+.NOP \f\*[B-Font]server\f[] \f[C]127.127.\f[]\f\*[I-Font]t\f[].\f\*[I-Font]u\f[] [\f\*[B-Font]prefer\f[]] [\f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]minpoll\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]maxpoll\f[] \f\*[I-Font]int\f[]]
+This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]prefer\f[]
+Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+"Mitigation Rules and the prefer Keyword"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[])
+for further information.
+.TP 7
+.NOP \f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.TP 7
+.NOP \f\*[B-Font]minpoll\f[] \f\*[I-Font]int\f[]
+.TP 7
+.NOP \f\*[B-Font]maxpoll\f[] \f\*[I-Font]int\f[]
+These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+\f\*[B-Font]minpoll\f[]
+and
+\f\*[B-Font]maxpoll\f[]
+default to 6 (64 s).
+For modem reference clocks,
+\f\*[B-Font]minpoll\f[]
+defaults to 10 (17.1 m) and
+\f\*[B-Font]maxpoll\f[]
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+.RE
+.TP 7
+.NOP \f\*[B-Font]fudge\f[] \f[C]127.127.\f[]\f\*[I-Font]t\f[].\f\*[I-Font]u\f[] [\f\*[B-Font]time1\f[] \f\*[I-Font]sec\f[]] [\f\*[B-Font]time2\f[] \f\*[I-Font]sec\f[]] [\f\*[B-Font]stratum\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]refid\f[] \f\*[I-Font]string\f[]] [\f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]] [\f\*[B-Font]flag1\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]] [\f\*[B-Font]flag2\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]] [\f\*[B-Font]flag3\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]] [\f\*[B-Font]flag4\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]]
+This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+\f\*[B-Font]server\f[]
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+program.
+The options are interpreted as
+follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]time1\f[] \f\*[I-Font]sec\f[]
+Specifies a constant to be added to the time offset produced by
+the driver, a fixed-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+\f\*[B-Font]enable\f[]
+command described in
+\fIMiscellaneous\f[] \fIOptions\f[]
+page and operates as described in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.TP 7
+.NOP \f\*[B-Font]time2\f[] \f\*[I-Font]secs\f[]
+Specifies a fixed-point decimal number in seconds, which is
+interpreted in a driver-dependent way.
+See the descriptions of
+specific drivers in the
+"Reference Clock Drivers"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+.TP 7
+.NOP \f\*[B-Font]stratum\f[] \f\*[I-Font]int\f[]
+Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+.TP 7
+.NOP \f\*[B-Font]refid\f[] \f\*[I-Font]string\f[]
+Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+.TP 7
+.NOP \f\*[B-Font]mode\f[] \f\*[I-Font]int\f[]
+Specifies a mode number which is interpreted in a
+device-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.TP 7
+.NOP \f\*[B-Font]flag1\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+.TP 7
+.NOP \f\*[B-Font]flag2\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+.TP 7
+.NOP \f\*[B-Font]flag3\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+.TP 7
+.NOP \f\*[B-Font]flag4\f[] \f\*[B-Font]0\f[] \f\*[B-Font]\&|\f[] \f\*[B-Font]1\f[]
+These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+\f\*[B-Font]flag4\f[]
+is used to enable recording monitoring
+data to the
+\f\*[B-Font]clockstats\f[]
+file configured with the
+\f\*[B-Font]filegen\f[]
+command.
+Further information on the
+\f\*[B-Font]filegen\f[]
+command can be found in
+\fIMonitoring\f[] \fIOptions\f[].
+.RE
+.PP
+.SH Miscellaneous Options
+.TP 7
+.NOP \f\*[B-Font]broadcastdelay\f[] \f\*[I-Font]seconds\f[]
+The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+.TP 7
+.NOP \f\*[B-Font]calldelay\f[] \f\*[I-Font]delay\f[]
+This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+.TP 7
+.NOP \f\*[B-Font]driftfile\f[] \f\*[I-Font]driftfile\f[]
+This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+\f\*[B-Font]\-f\f[]
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+.sp \n(Ppu
+.ne 2
+
+The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts-per-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+.TP 7
+.NOP \f\*[B-Font]dscp\f[] \f\*[I-Font]value\f[]
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6-bit code. The default value is 46, signifying Expedited Forwarding.
+.TP 7
+.NOP \f\*[B-Font]enable\f[] [\f\*[B-Font]auth\f[] | \f\*[B-Font]bclient\f[] | \f\*[B-Font]calibrate\f[] | \f\*[B-Font]kernel\f[] | \f\*[B-Font]mode7\f[] | \f\*[B-Font]monitor\f[] | \f\*[B-Font]ntp\f[] | \f\*[B-Font]stats\f[]]
+.TP 7
+.NOP \f\*[B-Font]disable\f[] [\f\*[B-Font]auth\f[] | \f\*[B-Font]bclient\f[] | \f\*[B-Font]calibrate\f[] | \f\*[B-Font]kernel\f[] | \f\*[B-Font]mode7\f[] | \f\*[B-Font]monitor\f[] | \f\*[B-Font]ntp\f[] | \f\*[B-Font]stats\f[]]
+Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+utility program.
+.RS
+.TP 7
+.NOP \f\*[B-Font]auth\f[]
+Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+\f\*[B-Font]enable\f[].
+.TP 7
+.NOP \f\*[B-Font]bclient\f[]
+Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+\f\*[B-Font]multicastclient\f[]
+command with default
+address.
+The default for this flag is
+\f\*[B-Font]disable\f[].
+.TP 7
+.NOP \f\*[B-Font]calibrate\f[]
+Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+\f\*[B-Font]disable\f[].
+.TP 7
+.NOP \f\*[B-Font]kernel\f[]
+Enables the kernel time discipline, if available.
+The default for this
+flag is
+\f\*[B-Font]enable\f[]
+if support is available, otherwise
+\f\*[B-Font]disable\f[].
+.TP 7
+.NOP \f\*[B-Font]mode7\f[]
+Enables processing of NTP mode 7 implementation-specific requests
+which are used by the deprecated
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[].
+The
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+program provides the same capabilities as
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+using standard mode 6 requests.
+.TP 7
+.NOP \f\*[B-Font]monitor\f[]
+Enables the monitoring facility.
+See the
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+program
+and the
+\f\*[B-Font]monlist\f[]
+command or further information.
+The
+default for this flag is
+\f\*[B-Font]enable\f[].
+.TP 7
+.NOP \f\*[B-Font]ntp\f[]
+Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+\f\*[B-Font]enable\f[].
+.TP 7
+.NOP \f\*[B-Font]stats\f[]
+Enables the statistics facility.
+See the
+\fIMonitoring\f[] \fIOptions\f[]
+section for further information.
+The default for this flag is
+\f\*[B-Font]disable\f[].
+.RE
+.TP 7
+.NOP \f\*[B-Font]includefile\f[] \f\*[I-Font]includefile\f[]
+This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+.TP 7
+.NOP \f\*[B-Font]leapsmearinterval\f[] \f\*[I-Font]seconds\f[]
+This EXPERIMENTAL option is only available if
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+was built with the
+\f\*[B-Font]\--enable-leap-smear\f[]
+option to the
+\f\*[B-Font]configure\f[]
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+.TP 7
+.NOP \f\*[B-Font]logconfig\f[] \f\*[I-Font]configkeyword\f[]
+This command controls the amount and type of output written to
+the system
+\fCsyslog\f[]\fR(3)\f[]
+facility or the alternate
+\f\*[B-Font]logfile\f[]
+log file.
+By default, all output is turned on.
+All
+\f\*[I-Font]configkeyword\f[]
+keywords can be prefixed with
+\[oq]=\[cq],
+\[oq]+\[cq]
+and
+\[oq]\-\[cq],
+where
+\[oq]=\[cq]
+sets the
+\fCsyslog\f[]\fR(3)\f[]
+priority mask,
+\[oq]+\[cq]
+adds and
+\[oq]\-\[cq]
+removes
+messages.
+\fCsyslog\f[]\fR(3)\f[]
+messages can be controlled in four
+classes
+(\f\*[B-Font]clock\f[], \f\*[B-Font]peer\f[], \f\*[B-Font]sys\f[] and \f\*[B-Font]sync\f[]).
+Within these classes four types of messages can be
+controlled: informational messages
+(\f\*[B-Font]info\f[]),
+event messages
+(\f\*[B-Font]events\f[]),
+statistics messages
+(\f\*[B-Font]statistics\f[])
+and
+status messages
+(\f\*[B-Font]status\f[]).
+.sp \n(Ppu
+.ne 2
+
+Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+\f\*[B-Font]all\f[]
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+\f\*[B-Font]all\f[]
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+.br
+.in +4
+.nf
+logconfig =syncstatus +sysevents
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+This would just list the synchronizations state of
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+.br
+.in +4
+.nf
+logconfig =syncall +clockall
+.in -4
+.fi
+.sp \n(Ppu
+.ne 2
+
+This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+.TP 7
+.NOP \f\*[B-Font]logfile\f[] \f\*[I-Font]logfile\f[]
+This command specifies the location of an alternate log file to
+be used instead of the default system
+\fCsyslog\f[]\fR(3)\f[]
+facility.
+This is the same operation as the \-l command line option.
+.TP 7
+.NOP \f\*[B-Font]setvar\f[] \f\*[I-Font]variable\f[] [\f\*[B-Font]default\f[]]
+This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+\fIname\f[]\fI=\f[]\f\*[I-Font]value\f[]
+is followed by the
+\f\*[B-Font]default\f[]
+keyword, the
+variable will be listed as part of the default system variables
+(\fCntpq\f[]\fR(@NTPQ_MS@)\f[] \f\*[B-Font]rv\f[] command)).
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+\f\*[B-Font]setvar\f[]
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+\fIsys_var_list\f[]
+holds
+the names of all system variables.
+The
+\fIpeer_var_list\f[]
+holds
+the names of all peer variables and the
+\fIclock_var_list\f[]
+holds the names of the reference clock variables.
+.TP 7
+.NOP \f\*[B-Font]tinker\f[] [\f\*[B-Font]allan\f[] \f\*[I-Font]allan\f[] | \f\*[B-Font]dispersion\f[] \f\*[I-Font]dispersion\f[] | \f\*[B-Font]freq\f[] \f\*[I-Font]freq\f[] | \f\*[B-Font]huffpuff\f[] \f\*[I-Font]huffpuff\f[] | \f\*[B-Font]panic\f[] \f\*[I-Font]panic\f[] | \f\*[B-Font]step\f[] \f\*[I-Font]step\f[] | \f\*[B-Font]stepback\f[] \f\*[I-Font]stepback\f[] | \f\*[B-Font]stepfwd\f[] \f\*[I-Font]stepfwd\f[] | \f\*[B-Font]stepout\f[] \f\*[I-Font]stepout\f[]]
+This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+.sp \n(Ppu
+.ne 2
+
+The variables operate as follows:
+.RS
+.TP 7
+.NOP \f\*[B-Font]allan\f[] \f\*[I-Font]allan\f[]
+The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+.TP 7
+.NOP \f\*[B-Font]dispersion\f[] \f\*[I-Font]dispersion\f[]
+The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+.TP 7
+.NOP \f\*[B-Font]freq\f[] \f\*[I-Font]freq\f[]
+The argument becomes the initial value of the frequency offset in
+parts-per-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+.TP 7
+.NOP \f\*[B-Font]huffpuff\f[] \f\*[I-Font]huffpuff\f[]
+The argument becomes the new value for the experimental
+huff-n'-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+.TP 7
+.NOP \f\*[B-Font]panic\f[] \f\*[I-Font]panic\f[]
+The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+.TP 7
+.NOP \f\*[B-Font]step\f[] \f\*[I-Font]step\f[]
+The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+.TP 7
+.NOP \f\*[B-Font]stepback\f[] \f\*[I-Font]stepback\f[]
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+.TP 7
+.NOP \f\*[B-Font]stepfwd\f[] \f\*[I-Font]stepfwd\f[]
+As for stepback, but for the forward direction.
+.TP 7
+.NOP \f\*[B-Font]stepout\f[] \f\*[I-Font]stepout\f[]
+The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+.RE
+.TP 7
+.NOP \f\*[B-Font]rlimit\f[] [\f\*[B-Font]memlock\f[] \f\*[I-Font]Nmegabytes\f[] | \f\*[B-Font]stacksize\f[] \f\*[I-Font]N4kPages\f[] \f\*[B-Font]filenum\f[] \f\*[I-Font]Nfiledescriptors\f[]]
+.RS
+.TP 7
+.NOP \f\*[B-Font]memlock\f[] \f\*[I-Font]Nmegabytes\f[]
+Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+\f\*[B-Font]\-i\f[]
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+.TP 7
+.NOP \f\*[B-Font]stacksize\f[] \f\*[I-Font]N4kPages\f[]
+Specifies the maximum size of the process stack on systems with the
+\fBmlockall\f[]\fR()\f[]
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+.TP 7
+.NOP \f\*[B-Font]filenum\f[] \f\*[I-Font]Nfiledescriptors\f[]
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+.RE
+.TP 7
+.NOP \f\*[B-Font]trap\f[] \f\*[I-Font]host_address\f[] [\f\*[B-Font]port\f[] \f\*[I-Font]port_number\f[]] [\f\*[B-Font]interface\f[] \f\*[I-Font]interface_address\f[]]
+This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+.sp \n(Ppu
+.ne 2
+
+The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+.TP 7
+.NOP \f\*[B-Font]hop\f[] \f\*[I-Font]...\f[]
+This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding-ring search.
+The default is eight multiples of 32 starting at
+31.
+.PP
+.SH "OPTIONS"
+.TP
+.NOP \f\*[B-Font]\-\-help\f[]
+Display usage information and exit.
+.TP
+.NOP \f\*[B-Font]\-\-more-help\f[]
+Pass the extended usage information through a pager.
+.TP
+.NOP \f\*[B-Font]\-\-version\f[] [{\f\*[I-Font]v|c|n\f[]}]
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.PP
+.SH "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTP_CONF_<option-name>\fP or \fBNTP_CONF\fP
+.fi
+.ad
+.SH "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.SH FILES
+.TP 15
+.NOP \fI/etc/ntp.conf\f[]
+the default name of the configuration file
+.br
+.ns
+.TP 15
+.NOP \fIntp.keys\f[]
+private MD5 keys
+.br
+.ns
+.TP 15
+.NOP \fIntpkey\f[]
+RSA private key
+.br
+.ns
+.TP 15
+.NOP \fIntpkey_\f[]\f\*[I-Font]host\f[]
+RSA public key
+.br
+.ns
+.TP 15
+.NOP \fIntp_dh\f[]
+Diffie-Hellman agreement parameters
+.PP
+.SH "EXIT STATUS"
+One of the following exit values will be returned:
+.TP
+.NOP 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.TP
+.NOP 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.TP
+.NOP 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+.PP
+.SH "SEE ALSO"
+\fCntpd\f[]\fR(@NTPD_MS@)\f[],
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[],
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+.sp \n(Ppu
+.ne 2
+
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+\f[C]http://www.ntp.org/\f[].
+A snapshot of this documentation is available in HTML format in
+\fI/usr/share/doc/ntp\f[].
+David L. Mills,
+\fINetwork Time Protocol (Version 4)\fR,
+RFC5905
+.PP
+
+.SH "AUTHORS"
+The University of Delaware and Network Time Foundation
+.SH "COPYRIGHT"
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.SH BUGS
+The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+.sp \n(Ppu
+.ne 2
+
+The
+\fIntpkey_\f[]\f\*[I-Font]host\f[]
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+.sp \n(Ppu
+.ne 2
+
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.SH NOTES
+This document was derived from FreeBSD.
+.sp \n(Ppu
+.ne 2
+
+This manual page was \fIAutoGen\fP-erated from the \fBntp.conf\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.conf.mdoc.in b/contrib/ntp/ntpd/ntp.conf.mdoc.in
new file mode 100644
index 0000000..93c638d
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.mdoc.in
@@ -0,0 +1,2853 @@
+.Dd June 29 2015
+.Dt NTP_CONF 5 File Formats
+.Os
+.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:36 PM by AutoGen 5.18.5
+.\" From the definitions ntp.conf.def
+.\" and the template file agmdoc-cmd.tpl
+.Sh NAME
+.Nm ntp.conf
+.Nd Network Time Protocol (NTP) daemon configuration file format
+.Sh SYNOPSIS
+.Nm
+.Op Fl \-option\-name
+.Op Fl \-option\-name Ar value
+.Pp
+All arguments must be options.
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+configuration file is read at initial startup by the
+.Xr ntpd @NTPD_MS@
+daemon in order to specify the synchronization sources,
+modes and other related information.
+Usually, it is installed in the
+.Pa /etc
+directory,
+but could be installed elsewhere
+(see the daemon's
+.Fl c
+command line option).
+.Pp
+The file format is similar to other
+.Ux
+configuration files.
+Comments begin with a
+.Ql #
+character and extend to the end of the line;
+blank lines are ignored.
+Configuration commands consist of an initial keyword
+followed by a list of arguments,
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
+Arguments may be host names,
+host addresses written in numeric, dotted\-quad form,
+integers, floating point numbers (when specifying times in seconds)
+and text strings.
+.Pp
+The rest of this page describes the configuration and control options.
+The
+.Qq Notes on Configuring NTP and Setting up an NTP Subnet
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+contains an extended discussion of these options.
+In addition to the discussion of general
+.Sx Configuration Options ,
+there are sections describing the following supported functionality
+and the options used to control it:
+.Bl -bullet -offset indent
+.It
+.Sx Authentication Support
+.It
+.Sx Monitoring Support
+.It
+.Sx Access Control Support
+.It
+.Sx Automatic NTP Configuration Options
+.It
+.Sx Reference Clock Support
+.It
+.Sx Miscellaneous Options
+.El
+.Pp
+Following these is a section describing
+.Sx Miscellaneous Options .
+While there is a rich set of options available,
+the only required option is one or more
+.Ic pool ,
+.Ic server ,
+.Ic peer ,
+.Ic broadcast
+or
+.Ic manycastclient
+commands.
+.Sh Configuration Support
+Following is a description of the configuration commands in
+NTPv4.
+These commands have the same basic functions as in NTPv3 and
+in some cases new functions and new arguments.
+There are two
+classes of commands, configuration commands that configure a
+persistent association with a remote server or peer or reference
+clock, and auxiliary commands that specify environmental variables
+that control various related operations.
+.Ss Configuration Commands
+The various modes are determined by the command keyword and the
+type of the required IP address.
+Addresses are classed by type as
+(s) a remote server or peer (IPv4 class A, B and C), (b) the
+broadcast address of a local interface, (m) a multicast address (IPv4
+class D), or (r) a reference clock address (127.127.x.x).
+Note that
+only those options applicable to each command are listed below.
+Use
+of options not listed may not be caught as an error, but may result
+in some weird and even destructive behavior.
+.Pp
+If the Basic Socket Interface Extensions for IPv6 (RFC\-2553)
+is detected, support for the IPv6 address family is generated
+in addition to the default support of the IPv4 address family.
+In a few cases, including the reslist billboard generated
+by ntpdc, IPv6 addresses are automatically generated.
+IPv6 addresses can be identified by the presence of colons
+.Dq \&:
+in the address field.
+IPv6 addresses can be used almost everywhere where
+IPv4 addresses can be used,
+with the exception of reference clock addresses,
+which are always IPv4.
+.Pp
+Note that in contexts where a host name is expected, a
+.Fl 4
+qualifier preceding
+the host name forces DNS resolution to the IPv4 namespace,
+while a
+.Fl 6
+qualifier forces DNS resolution to the IPv6 namespace.
+See IPv6 references for the
+equivalent classes for that address family.
+.Bl -tag -width indent
+.It Xo Ic pool Ar address
+.Op Cm burst
+.Op Cm iburst
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic server Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm burst
+.Op Cm iburst
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic peer Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Xc
+.It Xo Ic broadcast Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm ttl Ar ttl
+.Xc
+.It Xo Ic manycastclient Ar address
+.Op Cm key Ar key \&| Cm autokey
+.Op Cm version Ar version
+.Op Cm prefer
+.Op Cm minpoll Ar minpoll
+.Op Cm maxpoll Ar maxpoll
+.Op Cm ttl Ar ttl
+.Xc
+.El
+.Pp
+These five commands specify the time server name or address to
+be used and the mode in which to operate.
+The
+.Ar address
+can be
+either a DNS name or an IP address in dotted\-quad notation.
+Additional information on association behavior can be found in the
+.Qq Association Management
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Bl -tag -width indent
+.It Ic pool
+For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+.It Ic server
+For type s and r addresses, this command mobilizes a persistent
+client mode association with the specified remote server or local
+radio clock.
+In this mode the local clock can synchronized to the
+remote server, but the remote server can never be synchronized to
+the local clock.
+This command should
+.Em not
+be used for type
+b or m addresses.
+.It Ic peer
+For type s addresses (only), this command mobilizes a
+persistent symmetric\-active mode association with the specified
+remote peer.
+In this mode the local clock can be synchronized to
+the remote peer or the remote peer can be synchronized to the local
+clock.
+This is useful in a network of servers where, depending on
+various failure scenarios, either the local or remote peer may be
+the better source of time.
+This command should NOT be used for type
+b, m or r addresses.
+.It Ic broadcast
+For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
+Multiple
+commands can be used to specify multiple local broadcast interfaces
+(subnets) and/or multiple multicast groups.
+Note that local
+broadcast messages go only to the interface associated with the
+subnet specified, but multicast messages go to all interfaces.
+In broadcast mode the local server sends periodic broadcast
+messages to a client population at the
+.Ar address
+specified, which is usually the broadcast address on (one of) the
+local network(s) or a multicast address assigned to NTP.
+The IANA
+has assigned the multicast group address IPv4 224.0.1.1 and
+IPv6 ff05::101 (site local) exclusively to
+NTP, but other nonconflicting addresses can be used to contain the
+messages within administrative boundaries.
+Ordinarily, this
+specification applies only to the local server operating as a
+sender; for operation as a broadcast client, see the
+.Ic broadcastclient
+or
+.Ic multicastclient
+commands
+below.
+.It Ic manycastclient
+For type m addresses (only), this command mobilizes a
+manycast client mode association for the multicast address
+specified.
+In this case a specific address must be supplied which
+matches the address used on the
+.Ic manycastserver
+command for
+the designated manycast servers.
+The NTP multicast address
+224.0.1.1 assigned by the IANA should NOT be used, unless specific
+means are taken to avoid spraying large areas of the Internet with
+these messages and causing a possibly massive implosion of replies
+at the sender.
+The
+.Ic manycastserver
+command specifies that the local server
+is to operate in client mode with the remote servers that are
+discovered as the result of broadcast/multicast messages.
+The
+client broadcasts a request message to the group address associated
+with the specified
+.Ar address
+and specifically enabled
+servers respond to these messages.
+The client selects the servers
+providing the best time and continues as with the
+.Ic server
+command.
+The remaining servers are discarded as if never
+heard.
+.El
+.Pp
+Options:
+.Bl -tag -width indent
+.It Cm autokey
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the autokey scheme
+described in
+.Sx Authentication Options .
+.It Cm burst
+when the server is reachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first and second packets
+can be changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to improve timekeeping quality
+with the
+.Ic server
+command and s addresses.
+.It Cm iburst
+When the server is unreachable, send a burst of eight packets
+instead of the usual one.
+The packet spacing is normally 2 s;
+however, the spacing between the first two packets can be
+changed with the calldelay command to allow
+additional time for a modem or ISDN call to complete.
+This is designed to speed the initial synchronization
+acquisition with the
+.Ic server
+command and s addresses and when
+.Xr ntpd @NTPD_MS@
+is started with the
+.Fl q
+option.
+.It Cm key Ar key
+All packets sent to and received from the server or peer are to
+include authentication fields encrypted using the specified
+.Ar key
+identifier with values from 1 to 65534, inclusive.
+The
+default is to include no encryption field.
+.It Cm minpoll Ar minpoll
+.It Cm maxpoll Ar maxpoll
+These options specify the minimum and maximum poll intervals
+for NTP messages, as a power of 2 in seconds
+The maximum poll
+interval defaults to 10 (1,024 s), but can be increased by the
+.Cm maxpoll
+option to an upper limit of 17 (36.4 h).
+The
+minimum poll interval defaults to 6 (64 s), but can be decreased by
+the
+.Cm minpoll
+option to a lower limit of 4 (16 s).
+.It Cm noselect
+Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+.It Cm prefer
+Marks the server as preferred.
+All other things being equal,
+this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+.Qq Mitigation Rules and the prefer Keyword
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+for further information.
+.It Cm ttl Ar ttl
+This option is used only with broadcast server and manycast
+client modes.
+It specifies the time\-to\-live
+.Ar ttl
+to
+use on broadcast server and multicast server and the maximum
+.Ar ttl
+for the expanding ring search with manycast
+client packets.
+Selection of the proper value, which defaults to
+127, is something of a black art and should be coordinated with the
+network administrator.
+.It Cm version Ar version
+Specifies the version number to be used for outgoing NTP
+packets.
+Versions 1\-4 are the choices, with version 4 the
+default.
+.El
+.Ss Auxiliary Commands
+.Bl -tag -width indent
+.It Ic broadcastclient
+This command enables reception of broadcast server messages to
+any local interface (type b) address.
+Upon receiving a message for
+the first time, the broadcast client measures the nominal server
+propagation delay using a brief client/server exchange with the
+server, then enters the broadcast client mode, in which it
+synchronizes to succeeding broadcast messages.
+Note that, in order
+to avoid accidental or malicious disruption in this mode, both the
+server and client should operate using symmetric\-key or public\-key
+authentication as described in
+.Sx Authentication Options .
+.It Ic manycastserver Ar address ...
+This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
+At least one
+address is required, but the NTP multicast address 224.0.1.1
+assigned by the IANA should NOT be used, unless specific means are
+taken to limit the span of the reply and avoid a possibly massive
+implosion at the original sender.
+Note that, in order to avoid
+accidental or malicious disruption in this mode, both the server
+and client should operate using symmetric\-key or public\-key
+authentication as described in
+.Sx Authentication Options .
+.It Ic multicastclient Ar address ...
+This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
+Upon receiving
+a message for the first time, the multicast client measures the
+nominal server propagation delay using a brief client/server
+exchange with the server, then enters the broadcast client mode, in
+which it synchronizes to succeeding multicast messages.
+Note that,
+in order to avoid accidental or malicious disruption in this mode,
+both the server and client should operate using symmetric\-key or
+public\-key authentication as described in
+.Sx Authentication Options .
+.It Ic mdnstries Ar number
+If we are participating in mDNS,
+after we have synched for the first time
+we attempt to register with the mDNS system.
+If that registration attempt fails,
+we try again at one minute intervals for up to
+.Ic mdnstries
+times.
+After all,
+.Ic ntpd
+may be starting before mDNS.
+The default value for
+.Ic mdnstries
+is 5.
+.El
+.Sh Authentication Support
+Authentication support allows the NTP client to verify that the
+server is in fact known and trusted and not an intruder intending
+accidentally or on purpose to masquerade as that server.
+The NTPv3
+specification RFC\-1305 defines a scheme which provides
+cryptographic authentication of received NTP packets.
+Originally,
+this was done using the Data Encryption Standard (DES) algorithm
+operating in Cipher Block Chaining (CBC) mode, commonly called
+DES\-CBC.
+Subsequently, this was replaced by the RSA Message Digest
+5 (MD5) algorithm using a private key, commonly called keyed\-MD5.
+Either algorithm computes a message digest, or one\-way hash, which
+can be used to verify the server has the correct private key and
+key identifier.
+.Pp
+NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+cryptography and, in addition, provides a new Autokey scheme
+based on public key cryptography.
+Public key cryptography is generally considered more secure
+than symmetric key cryptography, since the security is based
+on a private value which is generated by each server and
+never revealed.
+With Autokey all key distribution and
+management functions involve only public values, which
+considerably simplifies key distribution and storage.
+Public key management is based on X.509 certificates,
+which can be provided by commercial services or
+produced by utility programs in the OpenSSL software library
+or the NTPv4 distribution.
+.Pp
+While the algorithms for symmetric key cryptography are
+included in the NTPv4 distribution, public key cryptography
+requires the OpenSSL software library to be installed
+before building the NTP distribution.
+Directions for doing that
+are on the Building and Installing the Distribution page.
+.Pp
+Authentication is configured separately for each association
+using the
+.Cm key
+or
+.Cm autokey
+subcommand on the
+.Ic peer ,
+.Ic server ,
+.Ic broadcast
+and
+.Ic manycastclient
+configuration commands as described in
+.Sx Configuration Options
+page.
+The authentication
+options described below specify the locations of the key files,
+if other than default, which symmetric keys are trusted
+and the interval between various operations, if other than default.
+.Pp
+Authentication is always enabled,
+although ineffective if not configured as
+described below.
+If a NTP packet arrives
+including a message authentication
+code (MAC), it is accepted only if it
+passes all cryptographic checks.
+The
+checks require correct key ID, key value
+and message digest.
+If the packet has
+been modified in any way or replayed
+by an intruder, it will fail one or more
+of these checks and be discarded.
+Furthermore, the Autokey scheme requires a
+preliminary protocol exchange to obtain
+the server certificate, verify its
+credentials and initialize the protocol
+.Pp
+The
+.Cm auth
+flag controls whether new associations or
+remote configuration commands require cryptographic authentication.
+This flag can be set or reset by the
+.Ic enable
+and
+.Ic disable
+commands and also by remote
+configuration commands sent by a
+.Xr ntpdc @NTPDC_MS@
+program running in
+another machine.
+If this flag is enabled, which is the default
+case, new broadcast client and symmetric passive associations and
+remote configuration commands must be cryptographically
+authenticated using either symmetric key or public key cryptography.
+If this
+flag is disabled, these operations are effective
+even if not cryptographic
+authenticated.
+It should be understood
+that operating with the
+.Ic auth
+flag disabled invites a significant vulnerability
+where a rogue hacker can
+masquerade as a falseticker and seriously
+disrupt system timekeeping.
+It is
+important to note that this flag has no purpose
+other than to allow or disallow
+a new association in response to new broadcast
+and symmetric active messages
+and remote configuration commands and, in particular,
+the flag has no effect on
+the authentication process itself.
+.Pp
+An attractive alternative where multicast support is available
+is manycast mode, in which clients periodically troll
+for servers as described in the
+.Sx Automatic NTP Configuration Options
+page.
+Either symmetric key or public key
+cryptographic authentication can be used in this mode.
+The principle advantage
+of manycast mode is that potential servers need not be
+configured in advance,
+since the client finds them during regular operation,
+and the configuration
+files for all clients can be identical.
+.Pp
+The security model and protocol schemes for
+both symmetric key and public key
+cryptography are summarized below;
+further details are in the briefings, papers
+and reports at the NTP project page linked from
+.Li http://www.ntp.org/ .
+.Ss Symmetric\-Key Cryptography
+The original RFC\-1305 specification allows any one of possibly
+65,534 keys, each distinguished by a 32\-bit key identifier, to
+authenticate an association.
+The servers and clients involved must
+agree on the key and key identifier to
+authenticate NTP packets.
+Keys and
+related information are specified in a key
+file, usually called
+.Pa ntp.keys ,
+which must be distributed and stored using
+secure means beyond the scope of the NTP protocol itself.
+Besides the keys used
+for ordinary NTP associations,
+additional keys can be used as passwords for the
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+utility programs.
+.Pp
+When
+.Xr ntpd @NTPD_MS@
+is first started, it reads the key file specified in the
+.Ic keys
+configuration command and installs the keys
+in the key cache.
+However,
+individual keys must be activated with the
+.Ic trusted
+command before use.
+This
+allows, for instance, the installation of possibly
+several batches of keys and
+then activating or deactivating each batch
+remotely using
+.Xr ntpdc @NTPDC_MS@ .
+This also provides a revocation capability that can be used
+if a key becomes compromised.
+The
+.Ic requestkey
+command selects the key used as the password for the
+.Xr ntpdc @NTPDC_MS@
+utility, while the
+.Ic controlkey
+command selects the key used as the password for the
+.Xr ntpq @NTPQ_MS@
+utility.
+.Ss Public Key Cryptography
+NTPv4 supports the original NTPv3 symmetric key scheme
+described in RFC\-1305 and in addition the Autokey protocol,
+which is based on public key cryptography.
+The Autokey Version 2 protocol described on the Autokey Protocol
+page verifies packet integrity using MD5 message digests
+and verifies the source with digital signatures and any of several
+digest/signature schemes.
+Optional identity schemes described on the Identity Schemes
+page and based on cryptographic challenge/response algorithms
+are also available.
+Using all of these schemes provides strong security against
+replay with or without modification, spoofing, masquerade
+and most forms of clogging attacks.
+.\" .Pp
+.\" The cryptographic means necessary for all Autokey operations
+.\" is provided by the OpenSSL software library.
+.\" This library is available from http://www.openssl.org/
+.\" and can be installed using the procedures outlined
+.\" in the Building and Installing the Distribution page.
+.\" Once installed,
+.\" the configure and build
+.\" process automatically detects the library and links
+.\" the library routines required.
+.Pp
+The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
+Most modes use a special cookie which can be
+computed independently by the client and server,
+but encrypted in transmission.
+All modes use in addition a variant of the S\-KEY scheme,
+in which a pseudo\-random key list is generated and used
+in reverse order.
+These schemes are described along with an executive summary,
+current status, briefing slides and reading list on the
+.Sx Autonomous Authentication
+page.
+.Pp
+The specific cryptographic environment used by Autokey servers
+and clients is determined by a set of files
+and soft links generated by the
+.Xr ntp\-keygen 1ntpkeygenmdoc
+program.
+This includes a required host key file,
+required certificate file and optional sign key file,
+leapsecond file and identity scheme files.
+The
+digest/signature scheme is specified in the X.509 certificate
+along with the matching sign key.
+There are several schemes
+available in the OpenSSL software library, each identified
+by a specific string such as
+.Cm md5WithRSAEncryption ,
+which stands for the MD5 message digest with RSA
+encryption scheme.
+The current NTP distribution supports
+all the schemes in the OpenSSL library, including
+those based on RSA and DSA digital signatures.
+.Pp
+NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
+It is important that every host
+in the group be able to construct a certificate trail to one
+or more trusted hosts in the same group.
+Each group
+host runs the Autokey protocol to obtain the certificates
+for all hosts along the trail to one or more trusted hosts.
+This requires the configuration file in all hosts to be
+engineered so that, even under anticipated failure conditions,
+the NTP subnet will form such that every group host can find
+a trail to at least one trusted host.
+.Ss Naming and Addressing
+It is important to note that Autokey does not use DNS to
+resolve addresses, since DNS can't be completely trusted
+until the name servers have synchronized clocks.
+The cryptographic name used by Autokey to bind the host identity
+credentials and cryptographic values must be independent
+of interface, network and any other naming convention.
+The name appears in the host certificate in either or both
+the subject and issuer fields, so protection against
+DNS compromise is essential.
+.Pp
+By convention, the name of an Autokey host is the name returned
+by the Unix
+.Xr gethostname 2
+system call or equivalent in other systems.
+By the system design
+model, there are no provisions to allow alternate names or aliases.
+However, this is not to say that DNS aliases, different names
+for each interface, etc., are constrained in any way.
+.Pp
+It is also important to note that Autokey verifies authenticity
+using the host name, network address and public keys,
+all of which are bound together by the protocol specifically
+to deflect masquerade attacks.
+For this reason Autokey
+includes the source and destinatino IP addresses in message digest
+computations and so the same addresses must be available
+at both the server and client.
+For this reason operation
+with network address translation schemes is not possible.
+This reflects the intended robust security model where government
+and corporate NTP servers are operated outside firewall perimeters.
+.Ss Operation
+A specific combination of authentication scheme (none,
+symmetric key, public key) and identity scheme is called
+a cryptotype, although not all combinations are compatible.
+There may be management configurations where the clients,
+servers and peers may not all support the same cryptotypes.
+A secure NTPv4 subnet can be configured in many ways while
+keeping in mind the principles explained above and
+in this section.
+Note however that some cryptotype
+combinations may successfully interoperate with each other,
+but may not represent good security practice.
+.Pp
+The cryptotype of an association is determined at the time
+of mobilization, either at configuration time or some time
+later when a message of appropriate cryptotype arrives.
+When mobilized by a
+.Ic server
+or
+.Ic peer
+configuration command and no
+.Ic key
+or
+.Ic autokey
+subcommands are present, the association is not
+authenticated; if the
+.Ic key
+subcommand is present, the association is authenticated
+using the symmetric key ID specified; if the
+.Ic autokey
+subcommand is present, the association is authenticated
+using Autokey.
+.Pp
+When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
+The client request message contains bits corresponding
+to which schemes it has available.
+The server response message
+contains bits corresponding to which schemes it has available.
+Both server and client match the received bits with their own
+and select a common scheme.
+.Pp
+Following the principle that time is a public value,
+a server responds to any client packet that matches
+its cryptotype capabilities.
+Thus, a server receiving
+an unauthenticated packet will respond with an unauthenticated
+packet, while the same server receiving a packet of a cryptotype
+it supports will respond with packets of that cryptotype.
+However, unconfigured broadcast or manycast client
+associations or symmetric passive associations will not be
+mobilized unless the server supports a cryptotype compatible
+with the first packet received.
+By default, unauthenticated associations will not be mobilized
+unless overridden in a decidedly dangerous way.
+.Pp
+Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice's unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob's symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it's the
+same key and the message is verified, Bob sends Cathy a reply
+authenticated with that key.
+If verification fails,
+Bob sends Cathy a thing called a crypto\-NAK, which tells her
+something broke.
+She can see the evidence using the
+.Xr ntpq @NTPQ_MS@
+program.
+.Pp
+Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
+She sends the first Autokey message to Bob and they
+both dance the protocol authentication and identity steps.
+If all comes out okay, Denise and Bob continue as described above.
+.Pp
+It should be clear from the above that Bob can support
+all the girls at the same time, as long as he has compatible
+authentication and identity credentials.
+Now, Bob can act just like the girls in his own choice of servers;
+he can run multiple configured associations with multiple different
+servers (or the same server, although that might not be useful).
+But, wise security policy might preclude some cryptotype
+combinations; for instance, running an identity scheme
+with one server and no authentication with another might not be wise.
+.Ss Key Management
+The cryptographic values used by the Autokey protocol are
+incorporated as a set of files generated by the
+.Xr ntp\-keygen 1ntpkeygenmdoc
+utility program, including symmetric key, host key and
+public certificate files, as well as sign key, identity parameters
+and leapseconds files.
+Alternatively, host and sign keys and
+certificate files can be generated by the OpenSSL utilities
+and certificates can be imported from public certificate
+authorities.
+Note that symmetric keys are necessary for the
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+utility programs.
+The remaining files are necessary only for the
+Autokey protocol.
+.Pp
+Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
+The certificate should be in ASN.1 syntax, X.509 Version 3
+format and encoded in PEM, which is the same format
+used by OpenSSL.
+The overall length of the certificate encoded
+in ASN.1 must not exceed 1024 bytes.
+The subject distinguished
+name field (CN) is the fully qualified name of the host
+on which it is used; the remaining subject fields are ignored.
+The certificate extension fields must not contain either
+a subject key identifier or a issuer key identifier field;
+however, an extended key usage field for a trusted host must
+contain the value
+.Cm trustRoot ; .
+Other extension fields are ignored.
+.Ss Authentication Commands
+.Bl -tag -width indent
+.It Ic autokey Op Ar logsec
+Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
+Note that the size of the key
+list for each association depends on this interval and the current
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
+For poll intervals above the specified interval, a session key list
+with a single entry will be regenerated for every message
+sent.
+.It Ic controlkey Ar key
+Specifies the key identifier to use with the
+.Xr ntpq @NTPQ_MS@
+utility, which uses the standard
+protocol defined in RFC\-1305.
+The
+.Ar key
+argument is
+the key identifier for a trusted key, where the value can be in the
+range 1 to 65,534, inclusive.
+.It Xo Ic crypto
+.Op Cm cert Ar file
+.Op Cm leap Ar file
+.Op Cm randfile Ar file
+.Op Cm host Ar file
+.Op Cm sign Ar file
+.Op Cm gq Ar file
+.Op Cm gqpar Ar file
+.Op Cm iffpar Ar file
+.Op Cm mvpar Ar file
+.Op Cm pw Ar password
+.Xc
+This command requires the OpenSSL library.
+It activates public key
+cryptography, selects the message digest and signature
+encryption scheme and loads the required private and public
+values described above.
+If one or more files are left unspecified,
+the default names are used as described above.
+Unless the complete path and name of the file are specified, the
+location of a file is relative to the keys directory specified
+in the
+.Ic keysdir
+command or default
+.Pa /usr/local/etc .
+Following are the subcommands:
+.Bl -tag -width indent
+.It Cm cert Ar file
+Specifies the location of the required host public certificate file.
+This overrides the link
+.Pa ntpkey_cert_ Ns Ar hostname
+in the keys directory.
+.It Cm gqpar Ar file
+Specifies the location of the optional GQ parameters file.
+This
+overrides the link
+.Pa ntpkey_gq_ Ns Ar hostname
+in the keys directory.
+.It Cm host Ar file
+Specifies the location of the required host key file.
+This overrides
+the link
+.Pa ntpkey_key_ Ns Ar hostname
+in the keys directory.
+.It Cm iffpar Ar file
+Specifies the location of the optional IFF parameters file.This
+overrides the link
+.Pa ntpkey_iff_ Ns Ar hostname
+in the keys directory.
+.It Cm leap Ar file
+Specifies the location of the optional leapsecond file.
+This overrides the link
+.Pa ntpkey_leap
+in the keys directory.
+.It Cm mvpar Ar file
+Specifies the location of the optional MV parameters file.
+This
+overrides the link
+.Pa ntpkey_mv_ Ns Ar hostname
+in the keys directory.
+.It Cm pw Ar password
+Specifies the password to decrypt files containing private keys and
+identity parameters.
+This is required only if these files have been
+encrypted.
+.It Cm randfile Ar file
+Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+.It Cm sign Ar file
+Specifies the location of the optional sign key file.
+This overrides
+the link
+.Pa ntpkey_sign_ Ns Ar hostname
+in the keys directory.
+If this file is
+not found, the host key is also the sign key.
+.El
+.It Ic keys Ar keyfile
+Specifies the complete path and location of the MD5 key file
+containing the keys and key identifiers used by
+.Xr ntpd @NTPD_MS@ ,
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+when operating with symmetric key cryptography.
+This is the same operation as the
+.Fl k
+command line option.
+.It Ic keysdir Ar path
+This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
+The default is
+.Pa /usr/local/etc/ .
+.It Ic requestkey Ar key
+Specifies the key identifier to use with the
+.Xr ntpdc @NTPDC_MS@
+utility program, which uses a
+proprietary protocol specific to this implementation of
+.Xr ntpd @NTPD_MS@ .
+The
+.Ar key
+argument is a key identifier
+for the trusted key, where the value can be in the range 1 to
+65,534, inclusive.
+.It Ic revoke Ar logsec
+Specifies the interval between re\-randomization of certain
+cryptographic values used by the Autokey scheme, as a power of 2 in
+seconds.
+These values need to be updated frequently in order to
+deflect brute\-force attacks on the algorithms of the scheme;
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
+For poll
+intervals above the specified interval, the values will be updated
+for every message sent.
+.It Ic trustedkey Ar key ...
+Specifies the key identifiers which are trusted for the
+purposes of authenticating peers with symmetric key cryptography,
+as well as keys used by the
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+programs.
+The authentication procedures require that both the local
+and remote servers share the same key and key identifier for this
+purpose, although different keys can be used with different
+servers.
+The
+.Ar key
+arguments are 32\-bit unsigned
+integers with values from 1 to 65,534.
+.El
+.Ss Error Codes
+The following error codes are reported via the NTP control
+and monitoring protocol trap mechanism.
+.Bl -tag -width indent
+.It 101
+.Pq bad field format or length
+The packet has invalid version, length or format.
+.It 102
+.Pq bad timestamp
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+.It 103
+.Pq bad filestamp
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+.It 104
+.Pq bad or missing public key
+The public key is missing, has incorrect format or is an unsupported type.
+.It 105
+.Pq unsupported digest type
+The server requires an unsupported digest/signature scheme.
+.It 106
+.Pq mismatched digest types
+Not used.
+.It 107
+.Pq bad signature length
+The signature length does not match the current public key.
+.It 108
+.Pq signature not verified
+The message fails the signature check.
+It could be bogus or signed by a
+different private key.
+.It 109
+.Pq certificate not verified
+The certificate is invalid or signed with the wrong key.
+.It 110
+.Pq certificate not verified
+The certificate is not yet valid or has expired or the signature could not
+be verified.
+.It 111
+.Pq bad or missing cookie
+The cookie is missing, corrupted or bogus.
+.It 112
+.Pq bad or missing leapseconds table
+The leapseconds table is missing, corrupted or bogus.
+.It 113
+.Pq bad or missing certificate
+The certificate is missing, corrupted or bogus.
+.It 114
+.Pq bad or missing identity
+The identity key is missing, corrupt or bogus.
+.El
+.Sh Monitoring Support
+.Xr ntpd @NTPD_MS@
+includes a comprehensive monitoring facility suitable
+for continuous, long term recording of server and client
+timekeeping performance.
+See the
+.Ic statistics
+command below
+for a listing and example of each type of statistics currently
+supported.
+Statistic files are managed using file generation sets
+and scripts in the
+.Pa ./scripts
+directory of this distribution.
+Using
+these facilities and
+.Ux
+.Xr cron 8
+jobs, the data can be
+automatically summarized and archived for retrospective analysis.
+.Ss Monitoring Commands
+.Bl -tag -width indent
+.It Ic statistics Ar name ...
+Enables writing of statistics records.
+Currently, eight kinds of
+.Ar name
+statistics are supported.
+.Bl -tag -width indent
+.It Cm clockstats
+Enables recording of clock driver statistics information.
+Each update
+received from a clock driver appends a line of the following form to
+the file generation set named
+.Cm clockstats :
+.Bd -literal
+49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the
+clock address in dotted\-quad notation.
+The final field shows the last
+timecode received from the clock in decoded ASCII format, where
+meaningful.
+In some clock drivers a good deal of additional information
+can be gathered and displayed as well.
+See information specific to each
+clock for further details.
+.It Cm cryptostats
+This option requires the OpenSSL cryptographic software library.
+It
+enables recording of cryptographic public key protocol information.
+Each message received by the protocol module appends a line of the
+following form to the file generation set named
+.Cm cryptostats :
+.Bd -literal
+49213 525.624 127.127.4.1 message
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The next field shows the peer
+address in dotted\-quad notation, The final message field includes the
+message type and certain ancillary information.
+See the
+.Sx Authentication Options
+section for further information.
+.It Cm loopstats
+Enables recording of loop filter statistics information.
+Each
+update of the local clock outputs a line of the following form to
+the file generation set named
+.Cm loopstats :
+.Bd -literal
+50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next five fields
+show time offset (seconds), frequency offset (parts per million \-
+PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
+discipline time constant.
+.It Cm peerstats
+Enables recording of peer statistics information.
+This includes
+statistics records of all peers of a NTP server and of special
+signals, where present and configured.
+Each valid update appends a
+line of the following form to the current element of a file
+generation set named
+.Cm peerstats :
+.Bd -literal
+48773 10847.650 127.127.4.1 9714 \-0.001605376 0.000000000 0.001424877 0.000958674
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the peer address in dotted\-quad notation and status,
+respectively.
+The status field is encoded in hex in the format
+described in Appendix A of the NTP specification RFC 1305.
+The final four fields show the offset,
+delay, dispersion and RMS jitter, all in seconds.
+.It Cm rawstats
+Enables recording of raw\-timestamp statistics information.
+This
+includes statistics records of all peers of a NTP server and of
+special signals, where present and configured.
+Each NTP message
+received from a peer or clock driver appends a line of the
+following form to the file generation set named
+.Cm rawstats :
+.Bd -literal
+50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
+The next two fields
+show the remote peer or clock address followed by the local address
+in dotted\-quad notation.
+The final four fields show the originate,
+receive, transmit and final NTP timestamps in order.
+The timestamp
+values are as received and before processing by the various data
+smoothing and mitigation algorithms.
+.It Cm sysstats
+Enables recording of ntpd statistics counters on a periodic basis.
+Each
+hour a line of the following form is appended to the file generation
+set named
+.Cm sysstats :
+.Bd -literal
+50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+.Ed
+.Pp
+The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
+The remaining ten fields show
+the statistics counter values accumulated since the last generated
+line.
+.Bl -tag -width indent
+.It Time since restart Cm 36000
+Time in hours since the system was last rebooted.
+.It Packets received Cm 81965
+Total number of packets received.
+.It Packets processed Cm 0
+Number of packets received in response to previous packets sent
+.It Current version Cm 9546
+Number of packets matching the current NTP version.
+.It Previous version Cm 56
+Number of packets matching the previous NTP version.
+.It Bad version Cm 71793
+Number of packets matching neither NTP version.
+.It Access denied Cm 512
+Number of packets denied access for any reason.
+.It Bad length or format Cm 540
+Number of packets with invalid length, format or port number.
+.It Bad authentication Cm 10
+Number of packets not verified as authentic.
+.It Rate exceeded Cm 147
+Number of packets discarded due to rate limitation.
+.El
+.It Cm statsdir Ar directory_path
+Indicates the full path of a directory where statistics files
+should be created (see below).
+This keyword allows
+the (otherwise constant)
+.Cm filegen
+filename prefix to be modified for file generation sets, which
+is useful for handling statistics logs.
+.It Cm filegen Ar name Xo
+.Op Cm file Ar filename
+.Op Cm type Ar typename
+.Op Cm link | nolink
+.Op Cm enable | disable
+.Xc
+Configures setting of generation file set name.
+Generation
+file sets provide a means for handling files that are
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
+Generation file sets provide access to a set of files used
+to store the actual data.
+At any time at most one element
+of the set is being written to.
+The type given specifies
+when and how data will be directed to a new element of the set.
+This way, information stored in elements of a file set
+that are currently unused are available for administrational
+operations without the risk of disturbing the operation of ntpd.
+(Most important: they can be removed to free space for new data
+produced.)
+.Pp
+Note that this command can be sent from the
+.Xr ntpdc @NTPDC_MS@
+program running at a remote location.
+.Bl -tag -width indent
+.It Cm name
+This is the type of the statistics records, as shown in the
+.Cm statistics
+command.
+.It Cm file Ar filename
+This is the file name for the statistics records.
+Filenames of set
+members are built from three concatenated elements
+.Ar Cm prefix ,
+.Ar Cm filename
+and
+.Ar Cm suffix :
+.Bl -tag -width indent
+.It Cm prefix
+This is a constant filename path.
+It is not subject to
+modifications via the
+.Ar filegen
+option.
+It is defined by the
+server, usually specified as a compile\-time constant.
+It may,
+however, be configurable for individual file generation sets
+via other commands.
+For example, the prefix used with
+.Ar loopstats
+and
+.Ar peerstats
+generation can be configured using the
+.Ar statsdir
+option explained above.
+.It Cm filename
+This string is directly concatenated to the prefix mentioned
+above (no intervening
+.Ql / ) .
+This can be modified using
+the file argument to the
+.Ar filegen
+statement.
+No
+.Pa ..
+elements are
+allowed in this component to prevent filenames referring to
+parts outside the filesystem hierarchy denoted by
+.Ar prefix .
+.It Cm suffix
+This part is reflects individual elements of a file set.
+It is
+generated according to the type of a file set.
+.El
+.It Cm type Ar typename
+A file generation set is characterized by its type.
+The following
+types are supported:
+.Bl -tag -width indent
+.It Cm none
+The file set is actually a single plain file.
+.It Cm pid
+One element of file set is used per incarnation of a ntpd
+server.
+This type does not perform any changes to file set
+members during runtime, however it provides an easy way of
+separating files belonging to different
+.Xr ntpd @NTPD_MS@
+server incarnations.
+The set member filename is built by appending a
+.Ql \&.
+to concatenated
+.Ar prefix
+and
+.Ar filename
+strings, and
+appending the decimal representation of the process ID of the
+.Xr ntpd @NTPD_MS@
+server process.
+.It Cm day
+One file generation set element is created per day.
+A day is
+defined as the period between 00:00 and 24:00 UTC.
+The file set
+member suffix consists of a
+.Ql \&.
+and a day specification in
+the form
+.Cm YYYYMMdd .
+.Cm YYYY
+is a 4\-digit year number (e.g., 1992).
+.Cm MM
+is a two digit month number.
+.Cm dd
+is a two digit day number.
+Thus, all information written at 10 December 1992 would end up
+in a file named
+.Ar prefix
+.Ar filename Ns .19921210 .
+.It Cm week
+Any file set member contains data related to a certain week of
+a year.
+The term week is defined by computing day\-of\-year
+modulo 7.
+Elements of such a file generation set are
+distinguished by appending the following suffix to the file set
+filename base: A dot, a 4\-digit year number, the letter
+.Cm W ,
+and a 2\-digit week number.
+For example, information from January,
+10th 1992 would end up in a file with suffix
+.No . Ns Ar 1992W1 .
+.It Cm month
+One generation file set element is generated per month.
+The
+file name suffix consists of a dot, a 4\-digit year number, and
+a 2\-digit month.
+.It Cm year
+One generation file element is generated per year.
+The filename
+suffix consists of a dot and a 4 digit year number.
+.It Cm age
+This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
+The filename
+suffix consists of a dot, the letter
+.Cm a ,
+and an 8\-digit number.
+This number is taken to be the number of seconds the server is
+running at the start of the corresponding 24\-hour period.
+Information is only written to a file generation by specifying
+.Cm enable ;
+output is prevented by specifying
+.Cm disable .
+.El
+.It Cm link | nolink
+It is convenient to be able to access the current element of a file
+generation set by a fixed name.
+This feature is enabled by
+specifying
+.Cm link
+and disabled using
+.Cm nolink .
+If link is specified, a
+hard link from the current file set element to a file without
+suffix is created.
+When there is already a file with this name and
+the number of links of this file is one, it is renamed appending a
+dot, the letter
+.Cm C ,
+and the pid of the ntpd server process.
+When the
+number of links is greater than one, the file is unlinked.
+This
+allows the current file to be accessed by a constant name.
+.It Cm enable \&| Cm disable
+Enables or disables the recording function.
+.El
+.El
+.El
+.Sh Access Control Support
+The
+.Xr ntpd @NTPD_MS@
+daemon implements a general purpose address/mask based restriction
+list.
+The list contains address/match entries sorted first
+by increasing address values and and then by increasing mask values.
+A match occurs when the bitwise AND of the mask and the packet
+source address is equal to the bitwise AND of the mask and
+address in the list.
+The list is searched in order with the
+last match found defining the restriction flags associated
+with the entry.
+Additional information and examples can be found in the
+.Qq Notes on Configuring NTP and Setting up a NTP Subnet
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Pp
+The restriction facility was implemented in conformance
+with the access policies for the original NSFnet backbone
+time servers.
+Later the facility was expanded to deflect
+cryptographic and clogging attacks.
+While this facility may
+be useful for keeping unwanted or broken or malicious clients
+from congesting innocent servers, it should not be considered
+an alternative to the NTP authentication facilities.
+Source address based restrictions are easily circumvented
+by a determined cracker.
+.Pp
+Clients can be denied service because they are explicitly
+included in the restrict list created by the restrict command
+or implicitly as the result of cryptographic or rate limit
+violations.
+Cryptographic violations include certificate
+or identity verification failure; rate limit violations generally
+result from defective NTP implementations that send packets
+at abusive rates.
+Some violations cause denied service
+only for the offending packet, others cause denied service
+for a timed period and others cause the denied service for
+an indefinate period.
+When a client or network is denied access
+for an indefinate period, the only way at present to remove
+the restrictions is by restarting the server.
+.Ss The Kiss\-of\-Death Packet
+Ordinarily, packets denied service are simply dropped with no
+further action except incrementing statistics counters.
+Sometimes a
+more proactive response is needed, such as a server message that
+explicitly requests the client to stop sending and leave a message
+for the system operator.
+A special packet format has been created
+for this purpose called the "kiss\-of\-death" (KoD) packet.
+KoD packets have the leap bits set unsynchronized and stratum set
+to zero and the reference identifier field set to a four\-byte
+ASCII code.
+If the
+.Cm noserve
+or
+.Cm notrust
+flag of the matching restrict list entry is set,
+the code is "DENY"; if the
+.Cm limited
+flag is set and the rate limit
+is exceeded, the code is "RATE".
+Finally, if a cryptographic violation occurs, the code is "CRYP".
+.Pp
+A client receiving a KoD performs a set of sanity checks to
+minimize security exposure, then updates the stratum and
+reference identifier peer variables, sets the access
+denied (TEST4) bit in the peer flash variable and sends
+a message to the log.
+As long as the TEST4 bit is set,
+the client will send no further packets to the server.
+The only way at present to recover from this condition is
+to restart the protocol at both the client and server.
+This
+happens automatically at the client when the association times out.
+It will happen at the server only if the server operator cooperates.
+.Ss Access Control Commands
+.Bl -tag -width indent
+.It Xo Ic discard
+.Op Cm average Ar avg
+.Op Cm minimum Ar min
+.Op Cm monitor Ar prob
+.Xc
+Set the parameters of the
+.Cm limited
+facility which protects the server from
+client abuse.
+The
+.Cm average
+subcommand specifies the minimum average packet
+spacing, while the
+.Cm minimum
+subcommand specifies the minimum packet spacing.
+Packets that violate these minima are discarded
+and a kiss\-o'\-death packet returned if enabled.
+The default
+minimum average and minimum are 5 and 2, respectively.
+The monitor subcommand specifies the probability of discard
+for packets that overflow the rate\-control window.
+.It Xo Ic restrict address
+.Op Cm mask Ar mask
+.Op Ar flag ...
+.Xc
+The
+.Ar address
+argument expressed in
+dotted\-quad form is the address of a host or network.
+Alternatively, the
+.Ar address
+argument can be a valid host DNS name.
+The
+.Ar mask
+argument expressed in dotted\-quad form defaults to
+.Cm 255.255.255.255 ,
+meaning that the
+.Ar address
+is treated as the address of an individual host.
+A default entry (address
+.Cm 0.0.0.0 ,
+mask
+.Cm 0.0.0.0 )
+is always included and is always the first entry in the list.
+Note that text string
+.Cm default ,
+with no mask option, may
+be used to indicate the default entry.
+In the current implementation,
+.Cm flag
+always
+restricts access, i.e., an entry with no flags indicates that free
+access to the server is to be given.
+The flags are not orthogonal,
+in that more restrictive flags will often make less restrictive
+ones redundant.
+The flags can generally be classed into two
+categories, those which restrict time service and those which
+restrict informational queries and attempts to do run\-time
+reconfiguration of the server.
+One or more of the following flags
+may be specified:
+.Bl -tag -width indent
+.It Cm ignore
+Deny packets of all kinds, including
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+queries.
+.It Cm kod
+If this flag is set when an access violation occurs, a kiss\-o'\-death
+(KoD) packet is sent.
+KoD packets are rate limited to no more than one
+per second.
+If another KoD packet occurs within one second after the
+last one, the packet is dropped.
+.It Cm limited
+Deny service if the packet spacing violates the lower limits specified
+in the discard command.
+A history of clients is kept using the
+monitoring capability of
+.Xr ntpd @NTPD_MS@ .
+Thus, monitoring is always active as
+long as there is a restriction entry with the
+.Cm limited
+flag.
+.It Cm lowpriotrap
+Declare traps set by matching hosts to be low priority.
+The
+number of traps a server can maintain is limited (the current limit
+is 3).
+Traps are usually assigned on a first come, first served
+basis, with later trap requestors being denied service.
+This flag
+modifies the assignment algorithm by allowing low priority traps to
+be overridden by later requests for normal priority traps.
+.It Cm nomodify
+Deny
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+queries which attempt to modify the state of the
+server (i.e., run time reconfiguration).
+Queries which return
+information are permitted.
+.It Cm noquery
+Deny
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+queries.
+Time service is not affected.
+.It Cm nopeer
+Deny packets which would result in mobilizing a new association.
+This
+includes broadcast and symmetric active packets when a configured
+association does not exist.
+It also includes
+.Cm pool
+associations, so if you want to use servers from a
+.Cm pool
+directive and also want to use
+.Cm nopeer
+by default, you'll want a
+.Cm "restrict source ..." line as well that does
+.It not
+include the
+.Cm nopeer
+directive.
+.It Cm noserve
+Deny all packets except
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+queries.
+.It Cm notrap
+Decline to provide mode 6 control message trap service to matching
+hosts.
+The trap service is a subsystem of the ntpdq control message
+protocol which is intended for use by remote event logging programs.
+.It Cm notrust
+Deny service unless the packet is cryptographically authenticated.
+.It Cm ntpport
+This is actually a match algorithm modifier, rather than a
+restriction flag.
+Its presence causes the restriction entry to be
+matched only if the source port in the packet is the standard NTP
+UDP port (123).
+Both
+.Cm ntpport
+and
+.Cm non\-ntpport
+may
+be specified.
+The
+.Cm ntpport
+is considered more specific and
+is sorted later in the list.
+.It Cm version
+Deny packets that do not match the current NTP version.
+.El
+.Pp
+Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host's interface addresses are
+inserted into the table at startup to prevent the server
+from attempting to synchronize to its own time.
+A default entry is also always present, though if it is
+otherwise unconfigured; no flags are associated
+with the default entry (i.e., everything besides your own
+NTP server is unrestricted).
+.El
+.Sh Automatic NTP Configuration Options
+.Ss Manycasting
+Manycasting is a automatic discovery and configuration paradigm
+new to NTPv4.
+It is intended as a means for a multicast client
+to troll the nearby network neighborhood to find cooperating
+manycast servers, validate them using cryptographic means
+and evaluate their time values with respect to other servers
+that might be lurking in the vicinity.
+The intended result is that each manycast client mobilizes
+client associations with some number of the "best"
+of the nearby manycast servers, yet automatically reconfigures
+to sustain this number of servers should one or another fail.
+.Pp
+Note that the manycasting paradigm does not coincide
+with the anycast paradigm described in RFC\-1546,
+which is designed to find a single server from a clique
+of servers providing the same service.
+The manycast paradigm is designed to find a plurality
+of redundant servers satisfying defined optimality criteria.
+.Pp
+Manycasting can be used with either symmetric key
+or public key cryptography.
+The public key infrastructure (PKI)
+offers the best protection against compromised keys
+and is generally considered stronger, at least with relatively
+large key sizes.
+It is implemented using the Autokey protocol and
+the OpenSSL cryptographic library available from
+.Li http://www.openssl.org/ .
+The library can also be used with other NTPv4 modes
+as well and is highly recommended, especially for broadcast modes.
+.Pp
+A persistent manycast client association is configured
+using the manycastclient command, which is similar to the
+server command but with a multicast (IPv4 class
+.Cm D
+or IPv6 prefix
+.Cm FF )
+group address.
+The IANA has designated IPv4 address 224.1.1.1
+and IPv6 address FF05::101 (site local) for NTP.
+When more servers are needed, it broadcasts manycast
+client messages to this address at the minimum feasible rate
+and minimum feasible time\-to\-live (TTL) hops, depending
+on how many servers have already been found.
+There can be as many manycast client associations
+as different group address, each one serving as a template
+for a future ephemeral unicast client/server association.
+.Pp
+Manycast servers configured with the
+.Ic manycastserver
+command listen on the specified group address for manycast
+client messages.
+Note the distinction between manycast client,
+which actively broadcasts messages, and manycast server,
+which passively responds to them.
+If a manycast server is
+in scope of the current TTL and is itself synchronized
+to a valid source and operating at a stratum level equal
+to or lower than the manycast client, it replies to the
+manycast client message with an ordinary unicast server message.
+.Pp
+The manycast client receiving this message mobilizes
+an ephemeral client/server association according to the
+matching manycast client template, but only if cryptographically
+authenticated and the server stratum is less than or equal
+to the client stratum.
+Authentication is explicitly required
+and either symmetric key or public key (Autokey) can be used.
+Then, the client polls the server at its unicast address
+in burst mode in order to reliably set the host clock
+and validate the source.
+This normally results
+in a volley of eight client/server at 2\-s intervals
+during which both the synchronization and cryptographic
+protocols run concurrently.
+Following the volley,
+the client runs the NTP intersection and clustering
+algorithms, which act to discard all but the "best"
+associations according to stratum and synchronization
+distance.
+The surviving associations then continue
+in ordinary client/server mode.
+.Pp
+The manycast client polling strategy is designed to reduce
+as much as possible the volume of manycast client messages
+and the effects of implosion due to near\-simultaneous
+arrival of manycast server messages.
+The strategy is determined by the
+.Ic manycastclient ,
+.Ic tos
+and
+.Ic ttl
+configuration commands.
+The manycast poll interval is
+normally eight times the system poll interval,
+which starts out at the
+.Cm minpoll
+value specified in the
+.Ic manycastclient ,
+command and, under normal circumstances, increments to the
+.Cm maxpolll
+value specified in this command.
+Initially, the TTL is
+set at the minimum hops specified by the ttl command.
+At each retransmission the TTL is increased until reaching
+the maximum hops specified by this command or a sufficient
+number client associations have been found.
+Further retransmissions use the same TTL.
+.Pp
+The quality and reliability of the suite of associations
+discovered by the manycast client is determined by the NTP
+mitigation algorithms and the
+.Cm minclock
+and
+.Cm minsane
+values specified in the
+.Ic tos
+configuration command.
+At least
+.Cm minsane
+candidate servers must be available and the mitigation
+algorithms produce at least
+.Cm minclock
+survivors in order to synchronize the clock.
+Byzantine agreement principles require at least four
+candidates in order to correctly discard a single falseticker.
+For legacy purposes,
+.Cm minsane
+defaults to 1 and
+.Cm minclock
+defaults to 3.
+For manycast service
+.Cm minsane
+should be explicitly set to 4, assuming at least that
+number of servers are available.
+.Pp
+If at least
+.Cm minclock
+servers are found, the manycast poll interval is immediately
+set to eight times
+.Cm maxpoll .
+If less than
+.Cm minclock
+servers are found when the TTL has reached the maximum hops,
+the manycast poll interval is doubled.
+For each transmission
+after that, the poll interval is doubled again until
+reaching the maximum of eight times
+.Cm maxpoll .
+Further transmissions use the same poll interval and
+TTL values.
+Note that while all this is going on,
+each client/server association found is operating normally
+it the system poll interval.
+.Pp
+Administratively scoped multicast boundaries are normally
+specified by the network router configuration and,
+in the case of IPv6, the link/site scope prefix.
+By default, the increment for TTL hops is 32 starting
+from 31; however, the
+.Ic ttl
+configuration command can be
+used to modify the values to match the scope rules.
+.Pp
+It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
+Because manycast servers respond only when the client
+stratum is equal to or greater than the server stratum,
+primary (stratum 1) servers fill find only primary servers
+in TTL range, which is probably the most common objective.
+However, unless configured otherwise, all manycast clients
+in TTL range will eventually find all primary servers
+in TTL range, which is probably not the most common
+objective in large networks.
+The
+.Ic tos
+command can be used to modify this behavior.
+Servers with stratum below
+.Cm floor
+or above
+.Cm ceiling
+specified in the
+.Ic tos
+command are strongly discouraged during the selection
+process; however, these servers may be temporally
+accepted if the number of servers within TTL range is
+less than
+.Cm minclock .
+.Pp
+The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
+However, once the ephemeral client association is mobilized,
+subsequent manycast server replies are discarded,
+since that would result in a duplicate association.
+If during a poll interval the number of client associations
+falls below
+.Cm minclock ,
+all manycast client prototype associations are reset
+to the initial poll interval and TTL hops and operation
+resumes from the beginning.
+It is important to avoid
+frequent manycast client messages, since each one requires
+all manycast servers in TTL range to respond.
+The result could well be an implosion, either minor or major,
+depending on the number of servers in range.
+The recommended value for
+.Cm maxpoll
+is 12 (4,096 s).
+.Pp
+It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
+A number of hosts configured this way and sharing a common
+group address will automatically organize themselves
+in an optimum configuration based on stratum and
+synchronization distance.
+For example, consider an NTP
+subnet of two primary servers and a hundred or more
+dependent clients.
+With two exceptions, all servers
+and clients have identical configuration files including both
+.Ic multicastclient
+and
+.Ic multicastserver
+commands using, for instance, multicast group address
+239.1.1.1.
+The only exception is that each primary server
+configuration file must include commands for the primary
+reference source such as a GPS receiver.
+.Pp
+The remaining configuration files for all secondary
+servers and clients have the same contents, except for the
+.Ic tos
+command, which is specific for each stratum level.
+For stratum 1 and stratum 2 servers, that command is
+not necessary.
+For stratum 3 and above servers the
+.Cm floor
+value is set to the intended stratum number.
+Thus, all stratum 3 configuration files are identical,
+all stratum 4 files are identical and so forth.
+.Pp
+Once operations have stabilized in this scenario,
+the primary servers will find the primary reference source
+and each other, since they both operate at the same
+stratum (1), but not with any secondary server or client,
+since these operate at a higher stratum.
+The secondary
+servers will find the servers at the same stratum level.
+If one of the primary servers loses its GPS receiver,
+it will continue to operate as a client and other clients
+will time out the corresponding association and
+re\-associate accordingly.
+.Pp
+Some administrators prefer to avoid running
+.Xr ntpd @NTPD_MS@
+continuously and run either
+.Xr ntpdate 8
+or
+.Xr ntpd @NTPD_MS@
+.Fl q
+as a cron job.
+In either case the servers must be
+configured in advance and the program fails if none are
+available when the cron job runs.
+A really slick
+application of manycast is with
+.Xr ntpd @NTPD_MS@
+.Fl q .
+The program wakes up, scans the local landscape looking
+for the usual suspects, selects the best from among
+the rascals, sets the clock and then departs.
+Servers do not have to be configured in advance and
+all clients throughout the network can have the same
+configuration file.
+.Ss Manycast Interactions with Autokey
+Each time a manycast client sends a client mode packet
+to a multicast group address, all manycast servers
+in scope generate a reply including the host name
+and status word.
+The manycast clients then run
+the Autokey protocol, which collects and verifies
+all certificates involved.
+Following the burst interval
+all but three survivors are cast off,
+but the certificates remain in the local cache.
+It often happens that several complete signing trails
+from the client to the primary servers are collected in this way.
+.Pp
+About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
+However, about once per day the server private value
+used to generate cookies is refreshed along with all
+manycast client associations.
+In this case all
+cryptographic values including certificates is refreshed.
+If a new certificate has been generated since
+the last refresh epoch, it will automatically revoke
+all prior certificates that happen to be in the
+certificate cache.
+At the same time, the manycast
+scheme starts all over from the beginning and
+the expanding ring shrinks to the minimum and increments
+from there while collecting all servers in scope.
+.Ss Manycast Options
+.Bl -tag -width indent
+.It Xo Ic tos
+.Oo
+.Cm ceiling Ar ceiling |
+.Cm cohort { 0 | 1 } |
+.Cm floor Ar floor |
+.Cm minclock Ar minclock |
+.Cm minsane Ar minsane
+.Oc
+.Xc
+This command affects the clock selection and clustering
+algorithms.
+It can be used to select the quality and
+quantity of peers used to synchronize the system clock
+and is most useful in manycast mode.
+The variables operate
+as follows:
+.Bl -tag -width indent
+.It Cm ceiling Ar ceiling
+Peers with strata above
+.Cm ceiling
+will be discarded if there are at least
+.Cm minclock
+peers remaining.
+This value defaults to 15, but can be changed
+to any number from 1 to 15.
+.It Cm cohort Bro 0 | 1 Brc
+This is a binary flag which enables (0) or disables (1)
+manycast server replies to manycast clients with the same
+stratum level.
+This is useful to reduce implosions where
+large numbers of clients with the same stratum level
+are present.
+The default is to enable these replies.
+.It Cm floor Ar floor
+Peers with strata below
+.Cm floor
+will be discarded if there are at least
+.Cm minclock
+peers remaining.
+This value defaults to 1, but can be changed
+to any number from 1 to 15.
+.It Cm minclock Ar minclock
+The clustering algorithm repeatedly casts out outlyer
+associations until no more than
+.Cm minclock
+associations remain.
+This value defaults to 3,
+but can be changed to any number from 1 to the number of
+configured sources.
+.It Cm minsane Ar minsane
+This is the minimum number of candidates available
+to the clock selection algorithm in order to produce
+one or more truechimers for the clustering algorithm.
+If fewer than this number are available, the clock is
+undisciplined and allowed to run free.
+The default is 1
+for legacy purposes.
+However, according to principles of
+Byzantine agreement,
+.Cm minsane
+should be at least 4 in order to detect and discard
+a single falseticker.
+.El
+.It Cm ttl Ar hop ...
+This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
+In manycast mode these values are used in turn
+in an expanding\-ring search.
+The default is eight
+multiples of 32 starting at 31.
+.El
+.Sh Reference Clock Support
+The NTP Version 4 daemon supports some three dozen different radio,
+satellite and modem reference clocks plus a special pseudo\-clock
+used for backup or when no other clock source is available.
+Detailed descriptions of individual device drivers and options can
+be found in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+Additional information can be found in the pages linked
+there, including the
+.Qq Debugging Hints for Reference Clock Drivers
+and
+.Qq How To Write a Reference Clock Driver
+pages
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+In addition, support for a PPS
+signal is available as described in the
+.Qq Pulse\-per\-second (PPS) Signal Interfacing
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+Many
+drivers support special line discipline/streams modules which can
+significantly improve the accuracy using the driver.
+These are
+described in the
+.Qq Line Disciplines and Streams Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.Pp
+A reference clock will generally (though not always) be a radio
+timecode receiver which is synchronized to a source of standard
+time such as the services offered by the NRC in Canada and NIST and
+USNO in the US.
+The interface between the computer and the timecode
+receiver is device dependent, but is usually a serial port.
+A
+device driver specific to each reference clock must be selected and
+compiled in the distribution; however, most common radio, satellite
+and modem clocks are included by default.
+Note that an attempt to
+configure a reference clock when the driver has not been compiled
+or the hardware port has not been appropriately configured results
+in a scalding remark to the system log file, but is otherwise non
+hazardous.
+.Pp
+For the purposes of configuration,
+.Xr ntpd @NTPD_MS@
+treats
+reference clocks in a manner analogous to normal NTP peers as much
+as possible.
+Reference clocks are identified by a syntactically
+correct but invalid IP address, in order to distinguish them from
+normal NTP peers.
+Reference clock addresses are of the form
+.Sm off
+.Li 127.127. Ar t . Ar u ,
+.Sm on
+where
+.Ar t
+is an integer
+denoting the clock type and
+.Ar u
+indicates the unit
+number in the range 0\-3.
+While it may seem overkill, it is in fact
+sometimes useful to configure multiple reference clocks of the same
+type, in which case the unit numbers must be unique.
+.Pp
+The
+.Ic server
+command is used to configure a reference
+clock, where the
+.Ar address
+argument in that command
+is the clock address.
+The
+.Cm key ,
+.Cm version
+and
+.Cm ttl
+options are not used for reference clock support.
+The
+.Cm mode
+option is added for reference clock support, as
+described below.
+The
+.Cm prefer
+option can be useful to
+persuade the server to cherish a reference clock with somewhat more
+enthusiasm than other reference clocks or peers.
+Further
+information on this option can be found in the
+.Qq Mitigation Rules and the prefer Keyword
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+page.
+The
+.Cm minpoll
+and
+.Cm maxpoll
+options have
+meaning only for selected clock drivers.
+See the individual clock
+driver document pages for additional information.
+.Pp
+The
+.Ic fudge
+command is used to provide additional
+information for individual clock drivers and normally follows
+immediately after the
+.Ic server
+command.
+The
+.Ar address
+argument specifies the clock address.
+The
+.Cm refid
+and
+.Cm stratum
+options can be used to
+override the defaults for the device.
+There are two optional
+device\-dependent time offsets and four flags that can be included
+in the
+.Ic fudge
+command as well.
+.Pp
+The stratum number of a reference clock is by default zero.
+Since the
+.Xr ntpd @NTPD_MS@
+daemon adds one to the stratum of each
+peer, a primary server ordinarily displays an external stratum of
+one.
+In order to provide engineered backups, it is often useful to
+specify the reference clock stratum as greater than zero.
+The
+.Cm stratum
+option is used for this purpose.
+Also, in cases
+involving both a reference clock and a pulse\-per\-second (PPS)
+discipline signal, it is useful to specify the reference clock
+identifier as other than the default, depending on the driver.
+The
+.Cm refid
+option is used for this purpose.
+Except where noted,
+these options apply to all clock drivers.
+.Ss Reference Clock Commands
+.Bl -tag -width indent
+.It Xo Ic server
+.Sm off
+.Li 127.127. Ar t . Ar u
+.Sm on
+.Op Cm prefer
+.Op Cm mode Ar int
+.Op Cm minpoll Ar int
+.Op Cm maxpoll Ar int
+.Xc
+This command can be used to configure reference clocks in
+special ways.
+The options are interpreted as follows:
+.Bl -tag -width indent
+.It Cm prefer
+Marks the reference clock as preferred.
+All other things being
+equal, this host will be chosen for synchronization among a set of
+correctly operating hosts.
+See the
+.Qq Mitigation Rules and the prefer Keyword
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp )
+for further information.
+.It Cm mode Ar int
+Specifies a mode number which is interpreted in a
+device\-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.It Cm minpoll Ar int
+.It Cm maxpoll Ar int
+These options specify the minimum and maximum polling interval
+for reference clock messages, as a power of 2 in seconds
+For
+most directly connected reference clocks, both
+.Cm minpoll
+and
+.Cm maxpoll
+default to 6 (64 s).
+For modem reference clocks,
+.Cm minpoll
+defaults to 10 (17.1 m) and
+.Cm maxpoll
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+.El
+.It Xo Ic fudge
+.Sm off
+.Li 127.127. Ar t . Ar u
+.Sm on
+.Op Cm time1 Ar sec
+.Op Cm time2 Ar sec
+.Op Cm stratum Ar int
+.Op Cm refid Ar string
+.Op Cm mode Ar int
+.Op Cm flag1 Cm 0 \&| Cm 1
+.Op Cm flag2 Cm 0 \&| Cm 1
+.Op Cm flag3 Cm 0 \&| Cm 1
+.Op Cm flag4 Cm 0 \&| Cm 1
+.Xc
+This command can be used to configure reference clocks in
+special ways.
+It must immediately follow the
+.Ic server
+command which configures the driver.
+Note that the same capability
+is possible at run time using the
+.Xr ntpdc @NTPDC_MS@
+program.
+The options are interpreted as
+follows:
+.Bl -tag -width indent
+.It Cm time1 Ar sec
+Specifies a constant to be added to the time offset produced by
+the driver, a fixed\-point decimal number in seconds.
+This is used
+as a calibration constant to adjust the nominal time offset of a
+particular clock to agree with an external standard, such as a
+precision PPS signal.
+It also provides a way to correct a
+systematic error or bias due to serial port or operating system
+latencies, different cable lengths or receiver internal delay.
+The
+specified offset is in addition to the propagation delay provided
+by other means, such as internal DIPswitches.
+Where a calibration
+for an individual system and driver is available, an approximate
+correction is noted in the driver documentation pages.
+Note: in order to facilitate calibration when more than one
+radio clock or PPS signal is supported, a special calibration
+feature is available.
+It takes the form of an argument to the
+.Ic enable
+command described in
+.Sx Miscellaneous Options
+page and operates as described in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.It Cm time2 Ar secs
+Specifies a fixed\-point decimal number in seconds, which is
+interpreted in a driver\-dependent way.
+See the descriptions of
+specific drivers in the
+.Qq Reference Clock Drivers
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+.It Cm stratum Ar int
+Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
+This number overrides the default stratum number
+ordinarily assigned by the driver itself, usually zero.
+.It Cm refid Ar string
+Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
+This string
+overrides the default identifier ordinarily assigned by the driver
+itself.
+.It Cm mode Ar int
+Specifies a mode number which is interpreted in a
+device\-specific fashion.
+For instance, it selects a dialing
+protocol in the ACTS driver and a device subtype in the
+parse
+drivers.
+.It Cm flag1 Cm 0 \&| Cm 1
+.It Cm flag2 Cm 0 \&| Cm 1
+.It Cm flag3 Cm 0 \&| Cm 1
+.It Cm flag4 Cm 0 \&| Cm 1
+These four flags are used for customizing the clock driver.
+The
+interpretation of these values, and whether they are used at all,
+is a function of the particular clock driver.
+However, by
+convention
+.Cm flag4
+is used to enable recording monitoring
+data to the
+.Cm clockstats
+file configured with the
+.Ic filegen
+command.
+Further information on the
+.Ic filegen
+command can be found in
+.Sx Monitoring Options .
+.El
+.El
+.Sh Miscellaneous Options
+.Bl -tag -width indent
+.It Ic broadcastdelay Ar seconds
+The broadcast and multicast modes require a special calibration
+to determine the network delay between the local and remote
+servers.
+Ordinarily, this is done automatically by the initial
+protocol exchanges between the client and server.
+In some cases,
+the calibration procedure may fail due to network or server access
+controls, for example.
+This command specifies the default delay to
+be used under these circumstances.
+Typically (for Ethernet), a
+number between 0.003 and 0.007 seconds is appropriate.
+The default
+when this command is not used is 0.004 seconds.
+.It Ic calldelay Ar delay
+This option controls the delay in seconds between the first and second
+packets sent in burst or iburst mode to allow additional time for a modem
+or ISDN call to complete.
+.It Ic driftfile Ar driftfile
+This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
+This is the same
+operation as the
+.Fl f
+command line option.
+If the file exists, it is read at
+startup in order to set the initial frequency and then updated once per
+hour with the current frequency computed by the daemon.
+If the file name is
+specified, but the file itself does not exist, the starts with an initial
+frequency of zero and creates the file when writing it for the first time.
+If this command is not given, the daemon will always start with an initial
+frequency of zero.
+.Pp
+The file format consists of a single line containing a single
+floating point number, which records the frequency offset measured
+in parts\-per\-million (PPM).
+The file is updated by first writing
+the current drift value into a temporary file and then renaming
+this file to replace the old version.
+This implies that
+.Xr ntpd @NTPD_MS@
+must have write permission for the directory the
+drift file is located in, and that file system links, symbolic or
+otherwise, should be avoided.
+.It Ic dscp Ar value
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6\-bit code. The default value is 46, signifying Expedited Forwarding.
+.It Xo Ic enable
+.Oo
+.Cm auth | Cm bclient |
+.Cm calibrate | Cm kernel |
+.Cm mode7 | monitor |
+.Cm ntp | Cm stats
+.Oc
+.Xc
+.It Xo Ic disable
+.Oo
+.Cm auth | Cm bclient |
+.Cm calibrate | Cm kernel |
+.Cm mode7 | monitor |
+.Cm ntp | Cm stats
+.Oc
+.Xc
+Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
+Note that all of these flags
+can be controlled remotely using the
+.Xr ntpdc @NTPDC_MS@
+utility program.
+.Bl -tag -width indent
+.It Cm auth
+Enables the server to synchronize with unconfigured peers only if the
+peer has been correctly authenticated using either public key or
+private key cryptography.
+The default for this flag is
+.Ic enable .
+.It Cm bclient
+Enables the server to listen for a message from a broadcast or
+multicast server, as in the
+.Ic multicastclient
+command with default
+address.
+The default for this flag is
+.Ic disable .
+.It Cm calibrate
+Enables the calibrate feature for reference clocks.
+The default for
+this flag is
+.Ic disable .
+.It Cm kernel
+Enables the kernel time discipline, if available.
+The default for this
+flag is
+.Ic enable
+if support is available, otherwise
+.Ic disable .
+.It Cm mode7
+Enables processing of NTP mode 7 implementation\-specific requests
+which are used by the deprecated
+.Xr ntpdc @NTPDC_MS@
+program.
+The default for this flag is disable.
+This flag is excluded from runtime configuration using
+.Xr ntpq @NTPQ_MS@ .
+The
+.Xr ntpq @NTPQ_MS@
+program provides the same capabilities as
+.Xr ntpdc @NTPDC_MS@
+using standard mode 6 requests.
+.It Cm monitor
+Enables the monitoring facility.
+See the
+.Xr ntpdc @NTPDC_MS@
+program
+and the
+.Ic monlist
+command or further information.
+The
+default for this flag is
+.Ic enable .
+.It Cm ntp
+Enables time and frequency discipline.
+In effect, this switch opens and
+closes the feedback loop, which is useful for testing.
+The default for
+this flag is
+.Ic enable .
+.It Cm stats
+Enables the statistics facility.
+See the
+.Sx Monitoring Options
+section for further information.
+The default for this flag is
+.Ic disable .
+.El
+.It Ic includefile Ar includefile
+This command allows additional configuration commands
+to be included from a separate file.
+Include files may
+be nested to a depth of five; upon reaching the end of any
+include file, command processing resumes in the previous
+configuration file.
+This option is useful for sites that run
+.Xr ntpd @NTPD_MS@
+on multiple hosts, with (mostly) common options (e.g., a
+restriction list).
+.It Ic leapsmearinterval Ar seconds
+This EXPERIMENTAL option is only available if
+.Xr ntpd @NTPD_MS@
+was built with the
+.Cm \-\-enable\-leap\-smear
+option to the
+.Cm configure
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC\-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+.It Ic logconfig Ar configkeyword
+This command controls the amount and type of output written to
+the system
+.Xr syslog 3
+facility or the alternate
+.Ic logfile
+log file.
+By default, all output is turned on.
+All
+.Ar configkeyword
+keywords can be prefixed with
+.Ql = ,
+.Ql +
+and
+.Ql \- ,
+where
+.Ql =
+sets the
+.Xr syslog 3
+priority mask,
+.Ql +
+adds and
+.Ql \-
+removes
+messages.
+.Xr syslog 3
+messages can be controlled in four
+classes
+.Po
+.Cm clock ,
+.Cm peer ,
+.Cm sys
+and
+.Cm sync
+.Pc .
+Within these classes four types of messages can be
+controlled: informational messages
+.Po
+.Cm info
+.Pc ,
+event messages
+.Po
+.Cm events
+.Pc ,
+statistics messages
+.Po
+.Cm statistics
+.Pc
+and
+status messages
+.Po
+.Cm status
+.Pc .
+.Pp
+Configuration keywords are formed by concatenating the message class with
+the event class.
+The
+.Cm all
+prefix can be used instead of a message class.
+A
+message class may also be followed by the
+.Cm all
+keyword to enable/disable all
+messages of the respective message class.Thus, a minimal log configuration
+could look like this:
+.Bd -literal
+logconfig =syncstatus +sysevents
+.Ed
+.Pp
+This would just list the synchronizations state of
+.Xr ntpd @NTPD_MS@
+and the major system events.
+For a simple reference server, the
+following minimum message configuration could be useful:
+.Bd -literal
+logconfig =syncall +clockall
+.Ed
+.Pp
+This configuration will list all clock information and
+synchronization information.
+All other events and messages about
+peers, system events and so on is suppressed.
+.It Ic logfile Ar logfile
+This command specifies the location of an alternate log file to
+be used instead of the default system
+.Xr syslog 3
+facility.
+This is the same operation as the \-l command line option.
+.It Ic setvar Ar variable Op Cm default
+This command adds an additional system variable.
+These
+variables can be used to distribute additional information such as
+the access policy.
+If the variable of the form
+.Sm off
+.Va name = Ar value
+.Sm on
+is followed by the
+.Cm default
+keyword, the
+variable will be listed as part of the default system variables
+.Po
+.Xr ntpq @NTPQ_MS@
+.Ic rv
+command
+.Pc ) .
+These additional variables serve
+informational purposes only.
+They are not related to the protocol
+other that they can be listed.
+The known protocol variables will
+always override any variables defined via the
+.Ic setvar
+mechanism.
+There are three special variables that contain the names
+of all variable of the same group.
+The
+.Va sys_var_list
+holds
+the names of all system variables.
+The
+.Va peer_var_list
+holds
+the names of all peer variables and the
+.Va clock_var_list
+holds the names of the reference clock variables.
+.It Xo Ic tinker
+.Oo
+.Cm allan Ar allan |
+.Cm dispersion Ar dispersion |
+.Cm freq Ar freq |
+.Cm huffpuff Ar huffpuff |
+.Cm panic Ar panic |
+.Cm step Ar step |
+.Cm stepback Ar stepback |
+.Cm stepfwd Ar stepfwd |
+.Cm stepout Ar stepout
+.Oc
+.Xc
+This command can be used to alter several system variables in
+very exceptional circumstances.
+It should occur in the
+configuration file before any other configuration options.
+The
+default values of these variables have been carefully optimized for
+a wide range of network speeds and reliability expectations.
+In
+general, they interact in intricate ways that are hard to predict
+and some combinations can result in some very nasty behavior.
+Very
+rarely is it necessary to change the default values; but, some
+folks cannot resist twisting the knobs anyway and this command is
+for them.
+Emphasis added: twisters are on their own and can expect
+no help from the support group.
+.Pp
+The variables operate as follows:
+.Bl -tag -width indent
+.It Cm allan Ar allan
+The argument becomes the new value for the minimum Allan
+intercept, which is a parameter of the PLL/FLL clock discipline
+algorithm.
+The value in log2 seconds defaults to 7 (1024 s), which is also the lower
+limit.
+.It Cm dispersion Ar dispersion
+The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+.It Cm freq Ar freq
+The argument becomes the initial value of the frequency offset in
+parts\-per\-million.
+This overrides the value in the frequency file, if
+present, and avoids the initial training state if it is not.
+.It Cm huffpuff Ar huffpuff
+The argument becomes the new value for the experimental
+huff\-n'\-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
+The lower limit is
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
+There
+is no default, since the filter is not enabled unless this command
+is given.
+.It Cm panic Ar panic
+The argument is the panic threshold, normally 1000 s.
+If set to zero,
+the panic sanity check is disabled and a clock offset of any value will
+be accepted.
+.It Cm step Ar step
+The argument is the step threshold, which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if the step threshold is set to zero or greater than the
+default.
+.It Cm stepback Ar stepback
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+.It Cm stepfwd Ar stepfwd
+As for stepback, but for the forward direction.
+.It Cm stepout Ar stepout
+The argument is the stepout timeout, which by default is 900 s.
+It can
+be set to any positive number in seconds.
+If set to zero, the stepout
+pulses will not be suppressed.
+.El
+.It Xo Ic rlimit
+.Oo
+.Cm memlock Ar Nmegabytes |
+.Cm stacksize Ar N4kPages
+.Cm filenum Ar Nfiledescriptors
+.Oc
+.Xc
+.Bl -tag -width indent
+.It Cm memlock Ar Nmegabytes
+Specify the number of megabytes of memory that can be allocated.
+Probably only available under Linux, this option is useful
+when dropping root (the
+.Fl i
+option).
+The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+.It Cm stacksize Ar N4kPages
+Specifies the maximum size of the process stack on systems with the
+.Fn mlockall
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+.It Cm filenum Ar Nfiledescriptors
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
+.El
+.It Xo Ic trap Ar host_address
+.Op Cm port Ar port_number
+.Op Cm interface Ar interface_address
+.Xc
+This command configures a trap receiver at the given host
+address and port number for sending messages with the specified
+local interface address.
+If the port number is unspecified, a value
+of 18447 is used.
+If the interface address is not specified, the
+message is sent with a source address of the local interface the
+message is sent through.
+Note that on a multihomed host the
+interface used may vary from time to time with routing changes.
+.Pp
+The trap receiver will generally log event messages and other
+information from the server in a log file.
+While such monitor
+programs may also request their own trap dynamically, configuring a
+trap receiver will ensure that no messages are lost when the server
+is started.
+.It Cm hop Ar ...
+This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
+In manycast mode these values are used in turn in
+an expanding\-ring search.
+The default is eight multiples of 32 starting at
+31.
+.El
+.Sh "OPTIONS"
+.Bl -tag
+.It Fl \-help
+Display usage information and exit.
+.It Fl \-more\-help
+Pass the extended usage information through a pager.
+.It Fl \-version Op Brq Ar v|c|n
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.El
+.Sh "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTP_CONF_<option\-name>\fP or \fBNTP_CONF\fP
+.fi
+.ad
+.Sh "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.Sh FILES
+.Bl -tag -width /etc/ntp.drift -compact
+.It Pa /etc/ntp.conf
+the default name of the configuration file
+.It Pa ntp.keys
+private MD5 keys
+.It Pa ntpkey
+RSA private key
+.It Pa ntpkey_ Ns Ar host
+RSA public key
+.It Pa ntp_dh
+Diffie\-Hellman agreement parameters
+.El
+.Sh "EXIT STATUS"
+One of the following exit values will be returned:
+.Bl -tag
+.It 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.It 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.It 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen\-users@lists.sourceforge.net. Thank you.
+.El
+.Sh "SEE ALSO"
+.Xr ntpd @NTPD_MS@ ,
+.Xr ntpdc @NTPDC_MS@ ,
+.Xr ntpq @NTPQ_MS@
+.Pp
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+.Li http://www.ntp.org/ .
+A snapshot of this documentation is available in HTML format in
+.Pa /usr/share/doc/ntp .
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 4)
+.%O RFC5905
+.Re
+.Sh "AUTHORS"
+The University of Delaware and Network Time Foundation
+.Sh "COPYRIGHT"
+Copyright (C) 1992\-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.Sh BUGS
+The syntax checking is not picky; some combinations of
+ridiculous and even hilarious options and modes may not be
+detected.
+.Pp
+The
+.Pa ntpkey_ Ns Ar host
+files are really digital
+certificates.
+These should be obtained via secure directory
+services when they become universally available.
+.Pp
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.Sh NOTES
+This document was derived from FreeBSD.
+.Pp
+This manual page was \fIAutoGen\fP\-erated from the \fBntp.conf\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.conf.texi b/contrib/ntp/ntpd/ntp.conf.texi
new file mode 100644
index 0000000..fb1a7ab
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.conf.texi
@@ -0,0 +1,49 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ntp.conf.info
+@settitle NTP Configuration File User's Manual
+@include ../sntp/include/version.texi
+@paragraphindent 2
+@c %**end of header
+
+@ifinfo
+This file documents the use of the NTP Project's NTP configuration file,
+version @value{VERSION}, @value{UPDATED}.
+@end ifinfo
+
+@direntry
+* ntp.conf: (ntp.conf). NTP's configuration file
+@end direntry
+
+@titlepage
+@title NTP's Configuration File User's Manual
+@subtitle ntp.conf, version @value{VERSION}, @value{UPDATED}
+@c @author Max @email{foo@ntp.org}
+@end titlepage
+
+@c @page
+@c @vskip 0pt plus 1filll
+
+@node Top, ntp.conf Description, (dir), (dir)
+@top NTP's Configuration File User Manual
+
+This document describes the configuration file for the NTP Project's
+@code{ntpd} program.
+
+This document applies to version @value{VERSION} of @code{ntp.conf}.
+
+@shortcontents
+
+@menu
+* ntp.conf Description::
+* ntp.conf Notes::
+@end menu
+
+@node ntp.conf Description, , Top, Top
+@comment node-name, next, previous, up
+@section Description
+
+The behavior of @code{ntpd} can be changed by a configuration file,
+by default @code{ntp.conf}.
+
+@include invoke-ntp.conf.texi
diff --git a/contrib/ntp/ntpd/ntp.keys.5man b/contrib/ntp/ntpd/ntp.keys.5man
new file mode 100644
index 0000000..63d4553
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.5man
@@ -0,0 +1,173 @@
+.TH ntp.keys 5man "29 Jun 2015" "4.2.8p3" "File Formats"
+.\"
+.\" EDIT THIS FILE WITH CAUTION (ntp.man)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:21 PM by AutoGen 5.18.5
+.\" From the definitions ntp.keys.def
+.\" and the template file agman-file.tpl
+.Sh NAME
+.Nm ntp.keys
+.Nd NTP symmetric key file format
+
+.\"
+.SH NAME
+ntp.keys \- NTP symmetric key file format configuration file
+.de1 NOP
+. it 1 an-trap
+. if \\n[.$] \,\\$*\/
+..
+.ie t \
+.ds B-Font [CB]
+.ds I-Font [CI]
+.ds R-Font [CR]
+.el \
+.ds B-Font B
+.ds I-Font I
+.ds R-Font R
+.SH SYNOPSIS
+\f\*[B-Font]\fP
+[\f\*[B-Font]\-\-option-name\f[]]
+[\f\*[B-Font]\-\-option-name\f[] \f\*[I-Font]value\f[]]
+.sp \n(Ppu
+.ne 2
+
+All arguments must be options.
+.sp \n(Ppu
+.ne 2
+
+.SH DESCRIPTION
+This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+"Authentication Support"
+section of the
+\fCntp.conf\f[]\fR(5)\f[]
+page.
+.sp \n(Ppu
+.ne 2
+
+\fCntpd\f[]\fR(8)\f[]
+reads its keys from a file specified using the
+\f\*[B-Font]\-k\f[]
+command line option or the
+\f\*[B-Font]keys\f[]
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+.sp \n(Ppu
+.ne 2
+
+The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+.sp \n(Ppu
+.ne 2
+
+.in +4
+\f\*[I-Font]keyno\f[] \f\*[I-Font]type\f[] \f\*[I-Font]key\f[]
+.in -4
+.sp \n(Ppu
+.ne 2
+
+where
+\f\*[I-Font]keyno\f[]
+is a positive integer (between 1 and 65534),
+\f\*[I-Font]type\f[]
+is the message digest algorithm,
+and
+\f\*[I-Font]key\f[]
+is the key itself.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[I-Font]key\f[]
+may be given in a format
+controlled by the
+\f\*[I-Font]type\f[]
+field.
+The
+\f\*[I-Font]type\f[]
+\f[C]MD5\f[]
+is always supported.
+If
+\f[C]ntpd\f[]
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140-2 is required the
+\f\*[I-Font]type\f[]
+must be either
+\f[C]SHA\f[]
+or
+\f[C]SHA1\f[].
+.sp \n(Ppu
+.ne 2
+
+What follows are some key types, and corresponding formats:
+.sp \n(Ppu
+.ne 2
+
+.TP 7
+.NOP \f[C]MD5\f[]
+The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+\f[C]#\f[]
+(which is the "start of comment" character).
+.sp \n(Ppu
+.ne 2
+
+.br
+.ns
+.TP 7
+.NOP \f[C]SHA\f[]
+.br
+.ns
+.TP 7
+.NOP \f[C]SHA1\f[]
+.br
+.ns
+.TP 7
+.NOP \f[C]RMD160\f[]
+The key is a hex-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+.PP
+.sp \n(Ppu
+.ne 2
+
+Note that the keys used by the
+\fCntpq\f[]\fR(8)\f[]
+and
+\fCntpdc\f[]\fR(8)\f[]
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+.SH FILES
+.TP 14
+.NOP \fI/etc/ntp.keys\f[]
+the default name of the configuration file
+.PP
+.SH "SEE ALSO"
+\fCntp.conf\f[]\fR(5)\f[],
+\fCntpd\f[]\fR(1ntpdmdoc)\f[],
+\fCntpdate\f[]\fR(1ntpdatemdoc)\f[],
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[],
+\fCsntp\f[]\fR(1sntpmdoc)\f[]
+.SH "AUTHORS"
+The University of Delaware and Network Time Foundation
+.SH "COPYRIGHT"
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.SH "BUGS"
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.SH NOTES
+This document was derived from FreeBSD.
+.sp \n(Ppu
+.ne 2
+
+This manual page was \fIAutoGen\fP-erated from the \fBntp.keys\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.keys.5mdoc b/contrib/ntp/ntpd/ntp.keys.5mdoc
new file mode 100644
index 0000000..47e5f81
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.5mdoc
@@ -0,0 +1,158 @@
+.Dd June 29 2015
+.Dt NTP_KEYS 5mdoc File Formats
+.Os SunOS 5.10
+.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:39 PM by AutoGen 5.18.5
+.\" From the definitions ntp.keys.def
+.\" and the template file agmdoc-file.tpl
+.Sh NAME
+.Nm ntp.keys
+.Nd NTP symmetric key file format
+
+.Sh NAME
+.Nm ntp.keys
+.Nd NTP symmetric key file format
+.Sh SYNOPSIS
+.Nm
+.Op Fl \-option\-name
+.Op Fl \-option\-name Ar value
+.Pp
+All arguments must be options.
+.Pp
+.Sh DESCRIPTION
+This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+.Qq Authentication Support
+section of the
+.Xr ntp.conf 5
+page.
+.Pp
+.Xr ntpd 8
+reads its keys from a file specified using the
+.Fl k
+command line option or the
+.Ic keys
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+.Pp
+The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+.Pp
+.D1 Ar keyno type key
+.Pp
+where
+.Ar keyno
+is a positive integer (between 1 and 65534),
+.Ar type
+is the message digest algorithm,
+and
+.Ar key
+is the key itself.
+.Pp
+The
+.Ar key
+may be given in a format
+controlled by the
+.Ar type
+field.
+The
+.Ar type
+.Li MD5
+is always supported.
+If
+.Li ntpd
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140\-2 is required the
+.Ar type
+must be either
+.Li SHA
+or
+.Li SHA1 .
+.Pp
+What follows are some key types, and corresponding formats:
+.Pp
+.Bl -tag -width RMD160 -compact
+.It Li MD5
+The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+.Li #
+(which is the "start of comment" character).
+.Pp
+.It Li SHA
+.It Li SHA1
+.It Li RMD160
+The key is a hex\-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+.El
+.Pp
+Note that the keys used by the
+.Xr ntpq 8
+and
+.Xr ntpdc 8
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+.Sh "OPTIONS"
+.Bl -tag
+.It Fl \-help
+Display usage information and exit.
+.It Fl \-more\-help
+Pass the extended usage information through a pager.
+.It Fl \-version Op Brq Ar v|c|n
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.El
+.Sh "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTP_KEYS_<option\-name>\fP or \fBNTP_KEYS\fP
+.fi
+.ad
+.Sh "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.Sh FILES
+.Bl -tag -width /etc/ntp.keys -compact
+.It Pa /etc/ntp.keys
+the default name of the configuration file
+.El
+.Sh "EXIT STATUS"
+One of the following exit values will be returned:
+.Bl -tag
+.It 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.It 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.It 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen\-users@lists.sourceforge.net. Thank you.
+.El
+.Sh "SEE ALSO"
+.Xr ntp.conf 5 ,
+.Xr ntpd 1ntpdmdoc ,
+.Xr ntpdate 1ntpdatemdoc ,
+.Xr ntpdc 1ntpdcmdoc ,
+.Xr sntp 1sntpmdoc
+.Sh "AUTHORS"
+The University of Delaware and Network Time Foundation
+.Sh "COPYRIGHT"
+Copyright (C) 1992\-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.Sh "BUGS"
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.Sh NOTES
+This document was derived from FreeBSD.
+.Pp
+This manual page was \fIAutoGen\fP\-erated from the \fBntp.keys\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.keys.def b/contrib/ntp/ntpd/ntp.keys.def
new file mode 100644
index 0000000..dcb3d55
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.def
@@ -0,0 +1,152 @@
+/* -*- Mode: Text -*- */
+
+autogen definitions options;
+
+#include copyright.def
+#include version.def
+
+// We want the synopsis to be "/etc/ntp.keys" but we need the prog-name
+// to be ntp.keys - the latter is also how autogen produces the output
+// file name.
+prog-name = "ntp.keys";
+file-path = "/etc/ntp.keys";
+prog-title = "NTP symmetric key file format";
+
+/* explain: Additional information whenever the usage routine is invoked */
+explain = <<- _END_EXPLAIN
+ _END_EXPLAIN;
+
+doc-section = {
+ ds-type = 'DESCRIPTION';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_PROG_MDOC_DESCRIP
+This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+.Qq Authentication Support
+section of the
+.Xr ntp.conf 5
+page.
+.Pp
+.Xr ntpd 8
+reads its keys from a file specified using the
+.Fl k
+command line option or the
+.Ic keys
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+.Pp
+The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+.Pp
+.D1 Ar keyno type key
+.Pp
+where
+.Ar keyno
+is a positive integer (between 1 and 65534),
+.Ar type
+is the message digest algorithm,
+and
+.Ar key
+is the key itself.
+.Pp
+The
+.Ar key
+may be given in a format
+controlled by the
+.Ar type
+field.
+The
+.Ar type
+.Li MD5
+is always supported.
+If
+.Li ntpd
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140-2 is required the
+.Ar type
+must be either
+.Li SHA
+or
+.Li SHA1 .
+.Pp
+What follows are some key types, and corresponding formats:
+.Pp
+.Bl -tag -width RMD160 -compact
+.It Li MD5
+The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+.Li #
+(which is the "start of comment" character).
+.Pp
+.It Li SHA
+.It Li SHA1
+.It Li RMD160
+The key is a hex-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+.El
+.Pp
+Note that the keys used by the
+.Xr ntpq 8
+and
+.Xr ntpdc 8
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+ _END_PROG_MDOC_DESCRIP;
+};
+
+doc-section = {
+ ds-type = 'FILES';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_FILES
+.Bl -tag -width /etc/ntp.keys -compact
+.It Pa /etc/ntp.keys
+the default name of the configuration file
+.El
+ _END_MDOC_FILES;
+};
+
+doc-section = {
+ ds-type = 'SEE ALSO';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_SEE_ALSO
+.Xr ntp.conf 5 ,
+.Xr ntpd 1ntpdmdoc ,
+.Xr ntpdate 1ntpdatemdoc ,
+.Xr ntpdc 1ntpdcmdoc ,
+.Xr sntp 1sntpmdoc
+ _END_MDOC_SEE_ALSO;
+};
+
+/*
+doc-section = {
+ ds-type = 'BUGS';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_BUGS
+.Xr ntpd 8
+has gotten rather fat.
+While not huge, it has gotten larger than might
+be desirable for an elevated-priority daemon running on a workstation,
+particularly since many of the fancy features which consume the space
+were designed more with a busy primary server, rather than a high
+stratum workstation, in mind.
+ _END_MDOC_BUGS;
+};
+*/
+
+doc-section = {
+ ds-type = 'NOTES';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_NOTES
+This document was derived from FreeBSD.
+ _END_MDOC_NOTES;
+};
diff --git a/contrib/ntp/ntpd/ntp.keys.html b/contrib/ntp/ntpd/ntp.keys.html
new file mode 100644
index 0000000..f096f63
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.html
@@ -0,0 +1,200 @@
+<html lang="en">
+<head>
+<title>NTP Symmetric Key</title>
+<meta http-equiv="Content-Type" content="text/html">
+<meta name="description" content="NTP Symmetric Key">
+<meta name="generator" content="makeinfo 4.7">
+<link title="Top" rel="top" href="#Top">
+<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
+<meta http-equiv="Content-Style-Type" content="text/css">
+<style type="text/css"><!--
+ pre.display { font-family:inherit }
+ pre.format { font-family:inherit }
+ pre.smalldisplay { font-family:inherit; font-size:smaller }
+ pre.smallformat { font-family:inherit; font-size:smaller }
+ pre.smallexample { font-size:smaller }
+ pre.smalllisp { font-size:smaller }
+ span.sc { font-variant:small-caps }
+ span.roman { font-family: serif; font-weight: normal; }
+--></style>
+</head>
+<body>
+<h1 class="settitle">NTP Symmetric Key</h1>
+<div class="node">
+<p><hr>
+<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002ekeys-Description">ntp.keys Description</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
+<br>
+</div>
+
+<h2 class="unnumbered">NTP's Symmetric Key File User Manual</h2>
+
+<p>This document describes the symmetric key file for the NTP Project's
+<code>ntpd</code> program.
+
+ <p>This document applies to version 4.2.8p3 of <code>ntp.keys</code>.
+
+ <div class="shortcontents">
+<h2>Short Contents</h2>
+<ul>
+<a href="#Top">NTP's Symmetric Key File User Manual</a>
+</ul>
+</div>
+
+<ul class="menu">
+<li><a accesskey="1" href="#ntp_002ekeys-Description">ntp.keys Description</a>
+<li><a accesskey="2" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="ntp_002ekeys-Description"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+<br>
+</div>
+
+<!-- node-name, next, previous, up -->
+<h3 class="section">Description</h3>
+
+<p>The name and location of the symmetric key file for <code>ntpd</code> can
+be specified in a configuration file, by default <code>/etc/ntp.keys</code>.
+
+<div class="node">
+<p><hr>
+<a name="ntp_002ekeys-Notes"></a>
+<br>
+</div>
+
+<h3 class="section">Notes about ntp.keys</h3>
+
+<p><a name="index-ntp_002ekeys-1"></a><a name="index-NTP-symmetric-key-file-format-2"></a>
+
+ <p>This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+"Authentication Support"
+section of the
+<code>ntp.conf(5)</code>
+page.
+
+ <p><code>ntpd(8)</code>
+reads its keys from a file specified using the
+<code>-k</code>
+command line option or the
+<code>keys</code>
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+
+ <p>The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+
+<pre class="example"> <kbd>keyno</kbd> <kbd>type</kbd> <kbd>key</kbd>
+</pre>
+ <p>where
+<kbd>keyno</kbd>
+is a positive integer (between 1 and 65534),
+<kbd>type</kbd>
+is the message digest algorithm,
+and
+<kbd>key</kbd>
+is the key itself.
+
+ <p>The
+<kbd>key</kbd>
+may be given in a format
+controlled by the
+<kbd>type</kbd>
+field.
+The
+<kbd>type</kbd>
+<code>MD5</code>
+is always supported.
+If
+<code>ntpd</code>
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140-2 is required the
+<kbd>type</kbd>
+must be either
+<code>SHA</code>
+or
+<code>SHA1</code>.
+
+ <p>What follows are some key types, and corresponding formats:
+
+ <dl>
+<dt><code>MD5</code><dd>The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+<code>#</code>
+(which is the "start of comment" character).
+
+ <br><dt><code>SHA</code><br><dt><code>SHA1</code><br><dt><code>RMD160</code><dd>The key is a hex-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+</dl>
+
+ <p>Note that the keys used by the
+<code>ntpq(8)</code>
+and
+<code>ntpdc(8)</code>
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+
+ <p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp.keys</code> program.
+This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
+
+<ul class="menu">
+<li><a accesskey="1" href="#ntp_002ekeys-Files">ntp.keys Files</a>: Files
+<li><a accesskey="2" href="#ntp_002ekeys-See-Also">ntp.keys See Also</a>: See Also
+<li><a accesskey="3" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>: Notes
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="ntp_002ekeys-Files"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002ekeys-See-Also">ntp.keys See Also</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.keys Files</h4>
+
+ <dl>
+<dt><span class="file">/etc/ntp.keys</span><dd>the default name of the configuration file
+</dl>
+<div class="node">
+<p><hr>
+<a name="ntp_002ekeys-See-Also"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002ekeys-Files">ntp.keys Files</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.keys See Also</h4>
+
+<p><code>ntp.conf(5)</code>,
+<code>ntpd(1ntpdmdoc)</code>,
+<code>ntpdate(1ntpdatemdoc)</code>,
+<code>ntpdc(1ntpdcmdoc)</code>,
+<code>sntp(1sntpmdoc)</code>
+<div class="node">
+<p><hr>
+<a name="ntp_002ekeys-Notes"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002ekeys-See-Also">ntp.keys See Also</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
+<br>
+</div>
+
+<h4 class="subsection">ntp.keys Notes</h4>
+
+<p>This document was derived from FreeBSD.
+
+</body></html>
+
diff --git a/contrib/ntp/ntpd/ntp.keys.man.in b/contrib/ntp/ntpd/ntp.keys.man.in
new file mode 100644
index 0000000..1080b91
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.man.in
@@ -0,0 +1,173 @@
+.TH ntp.keys 5 "29 Jun 2015" "4.2.8p3" "File Formats"
+.\"
+.\" EDIT THIS FILE WITH CAUTION (ntp.man)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:21 PM by AutoGen 5.18.5
+.\" From the definitions ntp.keys.def
+.\" and the template file agman-file.tpl
+.Sh NAME
+.Nm ntp.keys
+.Nd NTP symmetric key file format
+
+.\"
+.SH NAME
+ntp.keys \- NTP symmetric key file format configuration file
+.de1 NOP
+. it 1 an-trap
+. if \\n[.$] \,\\$*\/
+..
+.ie t \
+.ds B-Font [CB]
+.ds I-Font [CI]
+.ds R-Font [CR]
+.el \
+.ds B-Font B
+.ds I-Font I
+.ds R-Font R
+.SH SYNOPSIS
+\f\*[B-Font]\fP
+[\f\*[B-Font]\-\-option-name\f[]]
+[\f\*[B-Font]\-\-option-name\f[] \f\*[I-Font]value\f[]]
+.sp \n(Ppu
+.ne 2
+
+All arguments must be options.
+.sp \n(Ppu
+.ne 2
+
+.SH DESCRIPTION
+This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+"Authentication Support"
+section of the
+\fCntp.conf\f[]\fR(5)\f[]
+page.
+.sp \n(Ppu
+.ne 2
+
+\fCntpd\f[]\fR(8)\f[]
+reads its keys from a file specified using the
+\f\*[B-Font]\-k\f[]
+command line option or the
+\f\*[B-Font]keys\f[]
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+.sp \n(Ppu
+.ne 2
+
+The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+.sp \n(Ppu
+.ne 2
+
+.in +4
+\f\*[I-Font]keyno\f[] \f\*[I-Font]type\f[] \f\*[I-Font]key\f[]
+.in -4
+.sp \n(Ppu
+.ne 2
+
+where
+\f\*[I-Font]keyno\f[]
+is a positive integer (between 1 and 65534),
+\f\*[I-Font]type\f[]
+is the message digest algorithm,
+and
+\f\*[I-Font]key\f[]
+is the key itself.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[I-Font]key\f[]
+may be given in a format
+controlled by the
+\f\*[I-Font]type\f[]
+field.
+The
+\f\*[I-Font]type\f[]
+\f[C]MD5\f[]
+is always supported.
+If
+\f[C]ntpd\f[]
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140-2 is required the
+\f\*[I-Font]type\f[]
+must be either
+\f[C]SHA\f[]
+or
+\f[C]SHA1\f[].
+.sp \n(Ppu
+.ne 2
+
+What follows are some key types, and corresponding formats:
+.sp \n(Ppu
+.ne 2
+
+.TP 7
+.NOP \f[C]MD5\f[]
+The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+\f[C]#\f[]
+(which is the "start of comment" character).
+.sp \n(Ppu
+.ne 2
+
+.br
+.ns
+.TP 7
+.NOP \f[C]SHA\f[]
+.br
+.ns
+.TP 7
+.NOP \f[C]SHA1\f[]
+.br
+.ns
+.TP 7
+.NOP \f[C]RMD160\f[]
+The key is a hex-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+.PP
+.sp \n(Ppu
+.ne 2
+
+Note that the keys used by the
+\fCntpq\f[]\fR(8)\f[]
+and
+\fCntpdc\f[]\fR(8)\f[]
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+.SH FILES
+.TP 14
+.NOP \fI/etc/ntp.keys\f[]
+the default name of the configuration file
+.PP
+.SH "SEE ALSO"
+\fCntp.conf\f[]\fR(5)\f[],
+\fCntpd\f[]\fR(@NTPD_MS@)\f[],
+\fCntpdate\f[]\fR(@NTPDATE_MS@)\f[],
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[],
+\fCsntp\f[]\fR(@SNTP_MS@)\f[]
+.SH "AUTHORS"
+The University of Delaware and Network Time Foundation
+.SH "COPYRIGHT"
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.SH "BUGS"
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.SH NOTES
+This document was derived from FreeBSD.
+.sp \n(Ppu
+.ne 2
+
+This manual page was \fIAutoGen\fP-erated from the \fBntp.keys\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.keys.mdoc.in b/contrib/ntp/ntpd/ntp.keys.mdoc.in
new file mode 100644
index 0000000..6bd1c09
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.mdoc.in
@@ -0,0 +1,158 @@
+.Dd June 29 2015
+.Dt NTP_KEYS 5 File Formats
+.Os SunOS 5.10
+.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:39 PM by AutoGen 5.18.5
+.\" From the definitions ntp.keys.def
+.\" and the template file agmdoc-file.tpl
+.Sh NAME
+.Nm ntp.keys
+.Nd NTP symmetric key file format
+
+.Sh NAME
+.Nm ntp.keys
+.Nd NTP symmetric key file format
+.Sh SYNOPSIS
+.Nm
+.Op Fl \-option\-name
+.Op Fl \-option\-name Ar value
+.Pp
+All arguments must be options.
+.Pp
+.Sh DESCRIPTION
+This document describes the format of an NTP symmetric key file.
+For a description of the use of this type of file, see the
+.Qq Authentication Support
+section of the
+.Xr ntp.conf 5
+page.
+.Pp
+.Xr ntpd 8
+reads its keys from a file specified using the
+.Fl k
+command line option or the
+.Ic keys
+statement in the configuration file.
+While key number 0 is fixed by the NTP standard
+(as 56 zero bits)
+and may not be changed,
+one or more keys numbered between 1 and 65534
+may be arbitrarily set in the keys file.
+.Pp
+The key file uses the same comment conventions
+as the configuration file.
+Key entries use a fixed format of the form
+.Pp
+.D1 Ar keyno type key
+.Pp
+where
+.Ar keyno
+is a positive integer (between 1 and 65534),
+.Ar type
+is the message digest algorithm,
+and
+.Ar key
+is the key itself.
+.Pp
+The
+.Ar key
+may be given in a format
+controlled by the
+.Ar type
+field.
+The
+.Ar type
+.Li MD5
+is always supported.
+If
+.Li ntpd
+was built with the OpenSSL library
+then any digest library supported by that library may be specified.
+However, if compliance with FIPS 140\-2 is required the
+.Ar type
+must be either
+.Li SHA
+or
+.Li SHA1 .
+.Pp
+What follows are some key types, and corresponding formats:
+.Pp
+.Bl -tag -width RMD160 -compact
+.It Li MD5
+The key is 1 to 16 printable characters terminated by
+an EOL,
+whitespace,
+or
+a
+.Li #
+(which is the "start of comment" character).
+.Pp
+.It Li SHA
+.It Li SHA1
+.It Li RMD160
+The key is a hex\-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+.El
+.Pp
+Note that the keys used by the
+.Xr ntpq 8
+and
+.Xr ntpdc 8
+programs are checked against passwords
+requested by the programs and entered by hand,
+so it is generally appropriate to specify these keys in ASCII format.
+.Sh "OPTIONS"
+.Bl -tag
+.It Fl \-help
+Display usage information and exit.
+.It Fl \-more\-help
+Pass the extended usage information through a pager.
+.It Fl \-version Op Brq Ar v|c|n
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.El
+.Sh "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTP_KEYS_<option\-name>\fP or \fBNTP_KEYS\fP
+.fi
+.ad
+.Sh "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.Sh FILES
+.Bl -tag -width /etc/ntp.keys -compact
+.It Pa /etc/ntp.keys
+the default name of the configuration file
+.El
+.Sh "EXIT STATUS"
+One of the following exit values will be returned:
+.Bl -tag
+.It 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.It 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.It 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen\-users@lists.sourceforge.net. Thank you.
+.El
+.Sh "SEE ALSO"
+.Xr ntp.conf 5 ,
+.Xr ntpd @NTPD_MS@ ,
+.Xr ntpdate @NTPDATE_MS@ ,
+.Xr ntpdc @NTPDC_MS@ ,
+.Xr sntp @SNTP_MS@
+.Sh "AUTHORS"
+The University of Delaware and Network Time Foundation
+.Sh "COPYRIGHT"
+Copyright (C) 1992\-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.Sh "BUGS"
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.Sh NOTES
+This document was derived from FreeBSD.
+.Pp
+This manual page was \fIAutoGen\fP\-erated from the \fBntp.keys\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntp.keys.texi b/contrib/ntp/ntpd/ntp.keys.texi
new file mode 100644
index 0000000..1fc7b5c
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp.keys.texi
@@ -0,0 +1,49 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ntp.keys.info
+@settitle NTP Symmetric Key
+@include ../sntp/include/version.texi
+@paragraphindent 2
+@c %**end of header
+
+@ifinfo
+This file documents the NTP Project's NTP Symmetric Key file,
+version @value{VERSION}, @value{UPDATED}.
+@end ifinfo
+
+@direntry
+* ntp.keys: (ntp.keys). NTP's Symmetric Key file
+@end direntry
+
+@titlepage
+@title NTP's Symmetric Key File User's Manual
+@subtitle ntp.keys, version @value{VERSION}, @value{UPDATED}
+@c @author Max @email{foo@ntp.org}
+@end titlepage
+
+@c @page
+@c @vskip 0pt plus 1filll
+
+@node Top, ntp.keys Description, (dir), (dir)
+@top NTP's Symmetric Key File User Manual
+
+This document describes the symmetric key file for the NTP Project's
+@code{ntpd} program.
+
+This document applies to version @value{VERSION} of @code{ntp.keys}.
+
+@shortcontents
+
+@menu
+* ntp.keys Description::
+* ntp.keys Notes::
+@end menu
+
+@node ntp.keys Description, , Top, Top
+@comment node-name, next, previous, up
+@section Description
+
+The name and location of the symmetric key file for @code{ntpd} can
+be specified in a configuration file, by default @code{/etc/ntp.keys}.
+
+@include invoke-ntp.keys.texi
diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c
index e038f20..3007732 100644
--- a/contrib/ntp/ntpd/ntp_config.c
+++ b/contrib/ntp/ntpd/ntp_config.c
@@ -1,6 +1,14 @@
-/*
- * ntp_config.c - read and apply configuration information
+/* ntp_config.c
+ *
+ * This file contains the ntpd configuration code.
+ *
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
+ * Some parts borrowed from the older ntp_config.c
+ * Copyright (c) 2006
*/
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@@ -9,375 +17,148 @@
# include <netinfo/ni.h>
#endif
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_unixtime.h"
-#include "ntp_refclock.h"
-#include "ntp_filegen.h"
-#include "ntp_stdlib.h"
-#include <ntp_random.h>
-#include <isc/net.h>
-#include <isc/result.h>
-
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
+# include <sys/param.h>
#endif
#include <signal.h>
#ifndef SIGCHLD
# define SIGCHLD SIGCLD
#endif
-#if !defined(VMS)
-# ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-# endif
-#endif /* VMS */
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
-#ifdef SYS_WINNT
-# include <io.h>
-static HANDLE ResolverThreadHandle = NULL;
-HANDLE ResolverEventHandle;
-#else
-int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */
-#endif /* SYS_WINNT */
+#include <isc/net.h>
+#include <isc/result.h>
+#include "ntp.h"
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_refclock.h"
+#include "ntp_filegen.h"
+#include "ntp_stdlib.h"
+#include "lib_strbuf.h"
+#include "ntp_assert.h"
+#include "ntp_random.h"
/*
* [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
* so #include these later.
*/
-
#include "ntp_config.h"
#include "ntp_cmdargs.h"
+#include "ntp_scanner.h"
+#include "ntp_parser.h"
+#include "ntpd-opts.h"
-extern int priority_done;
-
-/*
- * These routines are used to read the configuration file at
- * startup time. An entry in the file must fit on a single line.
- * Entries are processed as multiple tokens separated by white space
- * Lines are considered terminated when a '#' is encountered. Blank
- * lines are ignored.
- */
-/*
- * Translation table - keywords to function index
- */
-struct keyword {
- const char *text;
- int keytype;
-};
-
-/*
- * Command keywords
- */
-static struct keyword keywords[] = {
- { "automax", CONFIG_AUTOMAX },
- { "broadcast", CONFIG_BROADCAST },
- { "broadcastclient", CONFIG_BROADCASTCLIENT },
- { "broadcastdelay", CONFIG_BDELAY },
- { "calldelay", CONFIG_CDELAY},
-#ifdef OPENSSL
- { "crypto", CONFIG_CRYPTO },
-#endif /* OPENSSL */
- { "controlkey", CONFIG_CONTROLKEY },
- { "disable", CONFIG_DISABLE },
- { "driftfile", CONFIG_DRIFTFILE },
- { "enable", CONFIG_ENABLE },
- { "end", CONFIG_END },
- { "filegen", CONFIG_FILEGEN },
- { "fudge", CONFIG_FUDGE },
- { "includefile", CONFIG_INCLUDEFILE },
- { "keys", CONFIG_KEYS },
- { "keysdir", CONFIG_KEYSDIR },
- { "logconfig", CONFIG_LOGCONFIG },
- { "logfile", CONFIG_LOGFILE },
- { "manycastclient", CONFIG_MANYCASTCLIENT },
- { "manycastserver", CONFIG_MANYCASTSERVER },
- { "multicastclient", CONFIG_MULTICASTCLIENT },
- { "peer", CONFIG_PEER },
- { "phone", CONFIG_PHONE },
- { "pidfile", CONFIG_PIDFILE },
- { "discard", CONFIG_DISCARD },
- { "requestkey", CONFIG_REQUESTKEY },
- { "restrict", CONFIG_RESTRICT },
- { "revoke", CONFIG_REVOKE },
- { "server", CONFIG_SERVER },
- { "setvar", CONFIG_SETVAR },
- { "statistics", CONFIG_STATISTICS },
- { "statsdir", CONFIG_STATSDIR },
- { "tick", CONFIG_ADJ },
- { "tinker", CONFIG_TINKER },
- { "tos", CONFIG_TOS },
- { "trap", CONFIG_TRAP },
- { "trustedkey", CONFIG_TRUSTEDKEY },
- { "ttl", CONFIG_TTL },
- { "", CONFIG_UNKNOWN }
-};
-/*
- * "peer", "server", "broadcast" modifier keywords
- */
-static struct keyword mod_keywords[] = {
- { "autokey", CONF_MOD_SKEY },
- { "burst", CONF_MOD_BURST },
- { "iburst", CONF_MOD_IBURST },
- { "key", CONF_MOD_KEY },
- { "maxpoll", CONF_MOD_MAXPOLL },
- { "minpoll", CONF_MOD_MINPOLL },
- { "mode", CONF_MOD_MODE }, /* refclocks */
- { "noselect", CONF_MOD_NOSELECT },
- { "preempt", CONF_MOD_PREEMPT },
- { "true", CONF_MOD_TRUE },
- { "prefer", CONF_MOD_PREFER },
- { "ttl", CONF_MOD_TTL }, /* NTP peers */
- { "version", CONF_MOD_VERSION },
- { "dynamic", CONF_MOD_DYNAMIC },
- { "", CONFIG_UNKNOWN }
-};
+/* list of servers from command line for config_peers() */
+int cmdline_server_count;
+char ** cmdline_servers;
-/*
- * "restrict" modifier keywords
- */
-static struct keyword res_keywords[] = {
- { "ignore", CONF_RES_IGNORE },
- { "limited", CONF_RES_LIMITED },
- { "kod", CONF_RES_DEMOBILIZE },
- { "lowpriotrap", CONF_RES_LPTRAP },
- { "mask", CONF_RES_MASK },
- { "nomodify", CONF_RES_NOMODIFY },
- { "nopeer", CONF_RES_NOPEER },
- { "noquery", CONF_RES_NOQUERY },
- { "noserve", CONF_RES_NOSERVE },
- { "notrap", CONF_RES_NOTRAP },
- { "notrust", CONF_RES_NOTRUST },
- { "ntpport", CONF_RES_NTPPORT },
- { "version", CONF_RES_VERSION },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "trap" modifier keywords
- */
-static struct keyword trap_keywords[] = {
- { "port", CONF_TRAP_PORT },
- { "interface", CONF_TRAP_INTERFACE },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "fudge" modifier keywords
- */
-static struct keyword fudge_keywords[] = {
- { "flag1", CONF_FDG_FLAG1 },
- { "flag2", CONF_FDG_FLAG2 },
- { "flag3", CONF_FDG_FLAG3 },
- { "flag4", CONF_FDG_FLAG4 },
- { "refid", CONF_FDG_REFID }, /* this mapping should be cleaned up (endianness, \0) - kd 20041031 */
- { "stratum", CONF_FDG_STRATUM },
- { "time1", CONF_FDG_TIME1 },
- { "time2", CONF_FDG_TIME2 },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "filegen" modifier keywords
- */
-static struct keyword filegen_keywords[] = {
- { "disable", CONF_FGEN_FLAG_DISABLE },
- { "enable", CONF_FGEN_FLAG_ENABLE },
- { "file", CONF_FGEN_FILE },
- { "link", CONF_FGEN_FLAG_LINK },
- { "nolink", CONF_FGEN_FLAG_NOLINK },
- { "type", CONF_FGEN_TYPE },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "type" modifier keywords
- */
-static struct keyword fgen_types[] = {
- { "age", FILEGEN_AGE },
- { "day", FILEGEN_DAY },
- { "month", FILEGEN_MONTH },
- { "none", FILEGEN_NONE },
- { "pid", FILEGEN_PID },
- { "week", FILEGEN_WEEK },
- { "year", FILEGEN_YEAR },
- { "", CONFIG_UNKNOWN}
-};
-
-/*
- * "enable", "disable" modifier keywords
- */
-static struct keyword flags_keywords[] = {
- { "auth", PROTO_AUTHENTICATE },
- { "bclient", PROTO_BROADCLIENT },
- { "calibrate", PROTO_CAL },
- { "kernel", PROTO_KERNEL },
- { "monitor", PROTO_MONITOR },
- { "ntp", PROTO_NTP },
- { "stats", PROTO_FILEGEN },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "discard" modifier keywords
- */
-static struct keyword discard_keywords[] = {
- { "average", CONF_DISCARD_AVERAGE },
- { "minimum", CONF_DISCARD_MINIMUM },
- { "monitor", CONF_DISCARD_MONITOR },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "tinker" modifier keywords
- */
-static struct keyword tinker_keywords[] = {
- { "step", CONF_CLOCK_MAX },
- { "panic", CONF_CLOCK_PANIC },
- { "dispersion", CONF_CLOCK_PHI },
- { "stepout", CONF_CLOCK_MINSTEP },
- { "allan", CONF_CLOCK_ALLAN },
- { "huffpuff", CONF_CLOCK_HUFFPUFF },
- { "freq", CONF_CLOCK_FREQ },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * "tos" modifier keywords
- */
-static struct keyword tos_keywords[] = {
- { "minclock", CONF_TOS_MINCLOCK },
- { "maxclock", CONF_TOS_MAXCLOCK },
- { "minsane", CONF_TOS_MINSANE },
- { "floor", CONF_TOS_FLOOR },
- { "ceiling", CONF_TOS_CEILING },
- { "cohort", CONF_TOS_COHORT },
- { "mindist", CONF_TOS_MINDISP },
- { "maxdist", CONF_TOS_MAXDIST },
- { "maxhop", CONF_TOS_MAXHOP },
- { "beacon", CONF_TOS_BEACON },
- { "orphan", CONF_TOS_ORPHAN },
- { "", CONFIG_UNKNOWN }
-};
-
-#ifdef OPENSSL
-/*
- * "crypto" modifier keywords
- */
-static struct keyword crypto_keywords[] = {
- { "cert", CONF_CRYPTO_CERT },
- { "gqpar", CONF_CRYPTO_GQPAR },
- { "host", CONF_CRYPTO_RSA },
- { "ident", CONF_CRYPTO_IDENT },
- { "iffpar", CONF_CRYPTO_IFFPAR },
- { "leap", CONF_CRYPTO_LEAP },
- { "mvpar", CONF_CRYPTO_MVPAR },
- { "pw", CONF_CRYPTO_PW },
- { "randfile", CONF_CRYPTO_RAND },
- { "sign", CONF_CRYPTO_SIGN },
- { "", CONFIG_UNKNOWN }
-};
-#endif /* OPENSSL */
-
-/*
- * Address type selection, IPv4 or IPv4.
- * Used on various lines.
- */
-static struct keyword addr_type[] = {
- { "-4", CONF_ADDR_IPV4 },
- { "-6", CONF_ADDR_IPV6 },
- { "", CONFIG_UNKNOWN }
-};
+/* set to zero if admin doesn't want memory locked */
+int do_memlock = 1;
/*
* "logconfig" building blocks
*/
struct masks {
- const char *name;
- unsigned long mask;
+ const char * const name;
+ const u_int32 mask;
};
static struct masks logcfg_class[] = {
- { "clock", NLOG_OCLOCK },
- { "peer", NLOG_OPEER },
- { "sync", NLOG_OSYNC },
- { "sys", NLOG_OSYS },
- { (char *)0, 0 }
+ { "clock", NLOG_OCLOCK },
+ { "peer", NLOG_OPEER },
+ { "sync", NLOG_OSYNC },
+ { "sys", NLOG_OSYS },
+ { NULL, 0 }
};
-static struct masks logcfg_item[] = {
+/* logcfg_noclass_items[] masks are complete and must not be shifted */
+static struct masks logcfg_noclass_items[] = {
+ { "allall", NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK },
+ { "allinfo", NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO },
+ { "allevents", NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT },
+ { "allstatus", NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS },
+ { "allstatistics", NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST },
+ /* the remainder are misspellings of clockall, peerall, sysall, and syncall. */
+ { "allclock", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK },
+ { "allpeer", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER },
+ { "allsys", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS },
+ { "allsync", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC },
+ { NULL, 0 }
+};
+
+/* logcfg_class_items[] masks are shiftable by NLOG_O* counts */
+static struct masks logcfg_class_items[] = {
+ { "all", NLOG_INFO | NLOG_EVENT | NLOG_STATUS | NLOG_STATIST },
{ "info", NLOG_INFO },
- { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO },
{ "events", NLOG_EVENT },
- { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT },
{ "status", NLOG_STATUS },
- { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS },
{ "statistics", NLOG_STATIST },
- { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST },
- { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK },
- { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER },
- { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
- { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
- { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
- { (char *)0, 0 }
+ { NULL, 0 }
};
-/*
- * Limits on things
- */
-#define MAXTOKENS 20 /* 20 tokens on line */
-#define MAXLINE 1024 /* maximum length of line */
+typedef struct peer_resolved_ctx_tag {
+ int flags;
+ int host_mode; /* T_* token identifier */
+ u_short family;
+ keyid_t keyid;
+ u_char hmode; /* MODE_* */
+ u_char version;
+ u_char minpoll;
+ u_char maxpoll;
+ u_int32 ttl;
+ const char * group;
+} peer_resolved_ctx;
+
+/* Limits */
#define MAXPHONE 10 /* maximum number of phone strings */
#define MAXPPS 20 /* maximum length of PPS device string */
-#define MAXINCLUDELEVEL 5 /* maximum include file levels */
/*
* Miscellaneous macros
*/
-#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
#define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
#define ISSPACE(c) ((c) == ' ' || (c) == '\t')
-#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
-#define KEY_TYPE_MD5 4
-
-/*
- * File descriptor used by the resolver save routines, and temporary file
- * name.
- */
-int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */
-static FILE *res_fp;
-#ifndef SYS_WINNT
-static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */
-#define RES_TEMPFILE "/tmp/ntpXXXXXX"
-#else
-static char res_file[MAX_PATH];
-#endif /* SYS_WINNT */
+#define _UC(str) ((char *)(intptr_t)(str))
/*
* Definitions of things either imported from or exported to outside
*/
-
-short default_ai_family = AF_UNSPEC; /* Default either IPv4 or IPv6 */
-char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */
-char *keysdir = NTP_KEYSDIR; /* crypto keys directory */
+extern int yydebug; /* ntp_parser.c (.y) */
+config_tree cfgt; /* Parser output stored here */
+struct config_tree_tag *cfg_tree_history; /* History of configs */
+char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */
+char default_keysdir[] = NTP_KEYSDIR;
+char *keysdir = default_keysdir; /* crypto keys directory */
+char * saveconfigdir;
#if defined(HAVE_SCHED_SETSCHEDULER)
int config_priority_override = 0;
int config_priority;
#endif
const char *config_file;
+static char default_ntp_signd_socket[] =
+#ifdef NTP_SIGND_PATH
+ NTP_SIGND_PATH;
+#else
+ "";
+#endif
+char *ntp_signd_socket = default_ntp_signd_socket;
#ifdef HAVE_NETINFO
- struct netinfo_config_state *config_netinfo = NULL;
- int check_netinfo = 1;
+struct netinfo_config_state *config_netinfo = NULL;
+int check_netinfo = 1;
#endif /* HAVE_NETINFO */
#ifdef SYS_WINNT
- char *alt_config_file;
- LPTSTR temp;
- char config_file_storage[MAX_PATH];
- char alt_config_file_storage[MAX_PATH];
+char *alt_config_file;
+LPTSTR temp;
+char config_file_storage[MAX_PATH];
+char alt_config_file_storage[MAX_PATH];
#endif /* SYS_WINNT */
#ifdef HAVE_NETINFO
@@ -389,1544 +170,4537 @@ struct netinfo_config_state {
ni_id config_dir; /* ID config dir */
int prop_index; /* current property */
int val_index; /* current value */
- char **val_list; /* value list */
+ char **val_list; /* value list */
};
#endif
+struct REMOTE_CONFIG_INFO remote_config; /* Remote configuration buffer and
+ pointer info */
+int old_config_style = 1; /* A boolean flag, which when set,
+ * indicates that the old configuration
+ * format with a newline at the end of
+ * every command is being used
+ */
+int cryptosw; /* crypto command called */
+
+extern char *stats_drift_file; /* name of the driftfile */
+
+#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
/*
- * Function prototypes
+ * backwards compatibility flags
*/
-static unsigned long get_pfxmatch P((char **, struct masks *));
-static unsigned long get_match P((char *, struct masks *));
-static unsigned long get_logmask P((char *));
-#ifdef HAVE_NETINFO
-static struct netinfo_config_state *get_netinfo_config P((void));
-static void free_netinfo_config P((struct netinfo_config_state *));
-static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
+bc_entry bc_list[] = {
+ { T_Bc_bugXXXX, 1 } /* default enabled */
+};
+
+/*
+ * declare an int pointer for each flag for quick testing without
+ * walking bc_list. If the pointer is consumed by libntp rather
+ * than ntpd, declare it in a libntp source file pointing to storage
+ * initialized with the appropriate value for other libntp clients, and
+ * redirect it to point into bc_list during ntpd startup.
+ */
+int *p_bcXXXX_enabled = &bc_list[0].enabled;
+#endif
+
+/* FUNCTION PROTOTYPES */
+
+static void init_syntax_tree(config_tree *);
+static void apply_enable_disable(attr_val_fifo *q, int enable);
+
+#ifdef FREE_CFG_T
+static void free_auth_node(config_tree *);
+static void free_all_config_trees(void);
+
+static void free_config_access(config_tree *);
+static void free_config_auth(config_tree *);
+static void free_config_fudge(config_tree *);
+static void free_config_logconfig(config_tree *);
+static void free_config_monitor(config_tree *);
+static void free_config_nic_rules(config_tree *);
+static void free_config_other_modes(config_tree *);
+static void free_config_peers(config_tree *);
+static void free_config_phone(config_tree *);
+static void free_config_reset_counters(config_tree *);
+static void free_config_rlimit(config_tree *);
+static void free_config_setvar(config_tree *);
+static void free_config_system_opts(config_tree *);
+static void free_config_tinker(config_tree *);
+static void free_config_tos(config_tree *);
+static void free_config_trap(config_tree *);
+static void free_config_ttl(config_tree *);
+static void free_config_unpeers(config_tree *);
+static void free_config_vars(config_tree *);
+
+#ifdef SIM
+static void free_config_sim(config_tree *);
#endif
-static int gettokens P((FILE *, char *, char **, int *));
-static int matchkey P((char *, struct keyword *, int));
+static void destroy_address_fifo(address_fifo *);
+#define FREE_ADDRESS_FIFO(pf) \
+ do { \
+ destroy_address_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+ void free_all_config_trees(void); /* atexit() */
+static void free_config_tree(config_tree *ptree);
+#endif /* FREE_CFG_T */
+
+static void destroy_restrict_node(restrict_node *my_node);
+static int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
+static void save_and_apply_config_tree(int/*BOOL*/ from_file);
+static void destroy_int_fifo(int_fifo *);
+#define FREE_INT_FIFO(pf) \
+ do { \
+ destroy_int_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+static void destroy_string_fifo(string_fifo *);
+#define FREE_STRING_FIFO(pf) \
+ do { \
+ destroy_string_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+static void destroy_attr_val_fifo(attr_val_fifo *);
+#define FREE_ATTR_VAL_FIFO(pf) \
+ do { \
+ destroy_attr_val_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+static void destroy_filegen_fifo(filegen_fifo *);
+#define FREE_FILEGEN_FIFO(pf) \
+ do { \
+ destroy_filegen_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+static void destroy_restrict_fifo(restrict_fifo *);
+#define FREE_RESTRICT_FIFO(pf) \
+ do { \
+ destroy_restrict_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+static void destroy_setvar_fifo(setvar_fifo *);
+#define FREE_SETVAR_FIFO(pf) \
+ do { \
+ destroy_setvar_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+static void destroy_addr_opts_fifo(addr_opts_fifo *);
+#define FREE_ADDR_OPTS_FIFO(pf) \
+ do { \
+ destroy_addr_opts_fifo(pf); \
+ (pf) = NULL; \
+ } while (0)
+
+static void config_logconfig(config_tree *);
+static void config_monitor(config_tree *);
+static void config_rlimit(config_tree *);
+static void config_system_opts(config_tree *);
+static void config_tinker(config_tree *);
+static void config_tos(config_tree *);
+static void config_vars(config_tree *);
+
+#ifdef SIM
+static sockaddr_u *get_next_address(address_node *addr);
+static void config_sim(config_tree *);
+static void config_ntpdsim(config_tree *);
+#else /* !SIM follows */
+static void config_ntpd(config_tree *, int/*BOOL*/ input_from_file);
+static void config_other_modes(config_tree *);
+static void config_auth(config_tree *);
+static void config_access(config_tree *);
+static void config_mdnstries(config_tree *);
+static void config_phone(config_tree *);
+static void config_setvar(config_tree *);
+static void config_ttl(config_tree *);
+static void config_trap(config_tree *);
+static void config_fudge(config_tree *);
+static void config_peers(config_tree *);
+static void config_unpeers(config_tree *);
+static void config_nic_rules(config_tree *, int/*BOOL*/ input_from_file);
+static void config_reset_counters(config_tree *);
+static u_char get_correct_host_mode(int token);
+static int peerflag_bits(peer_node *);
+#endif /* !SIM */
+
+#ifdef WORKER
+static void peer_name_resolved(int, int, void *, const char *, const char *,
+ const struct addrinfo *,
+ const struct addrinfo *);
+static void unpeer_name_resolved(int, int, void *, const char *, const char *,
+ const struct addrinfo *,
+ const struct addrinfo *);
+static void trap_name_resolved(int, int, void *, const char *, const char *,
+ const struct addrinfo *,
+ const struct addrinfo *);
+#endif
+
enum gnn_type {
t_UNK, /* Unknown */
t_REF, /* Refclock */
t_MSK /* Network Mask */
- };
-static int getnetnum P((const char *, struct sockaddr_storage *, int,
- enum gnn_type));
-static void save_resolve P((char *, int, int, int, int, u_int, int,
- keyid_t, u_char *, u_char));
-static void do_resolve_internal P((void));
-static void abort_resolve P((void));
-#if !defined(VMS) && !defined(SYS_WINNT)
-static RETSIGTYPE catchchild P((int));
-#endif /* VMS */
+};
-/*
- * get_pfxmatch - find value for prefixmatch
- * and update char * accordingly
+static void ntpd_set_tod_using(const char *);
+static char * normal_dtoa(double);
+static u_int32 get_pfxmatch(const char **, struct masks *);
+static u_int32 get_match(const char *, struct masks *);
+static u_int32 get_logmask(const char *);
+#ifndef SIM
+static int getnetnum(const char *num, sockaddr_u *addr, int complain,
+ enum gnn_type a_type);
+
+#endif
+
+
+/* FUNCTIONS FOR INITIALIZATION
+ * ----------------------------
*/
-static unsigned long
-get_pfxmatch(
- char ** s,
- struct masks *m
+
+#ifdef FREE_CFG_T
+static void
+free_auth_node(
+ config_tree *ptree
)
{
- while (m->name) {
- if (strncmp(*s, m->name, strlen(m->name)) == 0) {
- *s += strlen(m->name);
- return m->mask;
- } else {
- m++;
- }
+ if (ptree->auth.keys) {
+ free(ptree->auth.keys);
+ ptree->auth.keys = NULL;
+ }
+
+ if (ptree->auth.keysdir) {
+ free(ptree->auth.keysdir);
+ ptree->auth.keysdir = NULL;
+ }
+
+ if (ptree->auth.ntp_signd_socket) {
+ free(ptree->auth.ntp_signd_socket);
+ ptree->auth.ntp_signd_socket = NULL;
}
- return 0;
}
+#endif /* DEBUG */
-/*
- * get_match - find logmask value
- */
-static unsigned long
-get_match(
- char *s,
- struct masks *m
+
+static void
+init_syntax_tree(
+ config_tree *ptree
)
{
- while (m->name) {
- if (strcmp(s, m->name) == 0) {
- return m->mask;
- } else {
- m++;
- }
+ ZERO(*ptree);
+ ptree->mdnstries = 5;
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_all_config_trees(void)
+{
+ config_tree *ptree;
+ config_tree *pnext;
+
+ ptree = cfg_tree_history;
+
+ while (ptree != NULL) {
+ pnext = ptree->link;
+ free_config_tree(ptree);
+ ptree = pnext;
}
- return 0;
}
-/*
- * get_logmask - build bitmask for ntp_syslogmask
- */
-static unsigned long
-get_logmask(
- char *s
+
+static void
+free_config_tree(
+ config_tree *ptree
)
{
- char *t;
- unsigned long offset;
- unsigned long mask;
+#if defined(_MSC_VER) && defined (_DEBUG)
+ _CrtCheckMemory();
+#endif
- t = s;
- offset = get_pfxmatch(&t, logcfg_class);
- mask = get_match(t, logcfg_item);
+ if (ptree->source.value.s != NULL)
+ free(ptree->source.value.s);
+
+ free_config_other_modes(ptree);
+ free_config_auth(ptree);
+ free_config_tos(ptree);
+ free_config_monitor(ptree);
+ free_config_access(ptree);
+ free_config_tinker(ptree);
+ free_config_rlimit(ptree);
+ free_config_system_opts(ptree);
+ free_config_logconfig(ptree);
+ free_config_phone(ptree);
+ free_config_setvar(ptree);
+ free_config_ttl(ptree);
+ free_config_trap(ptree);
+ free_config_fudge(ptree);
+ free_config_vars(ptree);
+ free_config_peers(ptree);
+ free_config_unpeers(ptree);
+ free_config_nic_rules(ptree);
+ free_config_reset_counters(ptree);
+#ifdef SIM
+ free_config_sim(ptree);
+#endif
+ free_auth_node(ptree);
- if (mask)
- return mask << offset;
- else
- msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s);
+ free(ptree);
- return 0;
+#if defined(_MSC_VER) && defined (_DEBUG)
+ _CrtCheckMemory();
+#endif
}
+#endif /* FREE_CFG_T */
-/*
- * getconfig - get command line options and read the configuration file
- */
-void
-getconfig(
- int argc,
- char *argv[]
- )
-{
- register int i;
- int c;
- int errflg;
- int status;
- int istart;
- int peerversion;
- int minpoll;
- int maxpoll;
- int ttl;
- long stratum;
- unsigned long ul;
- keyid_t peerkey;
- u_char *peerkeystr;
- u_long fudgeflag;
- u_int peerflags;
- int hmode;
- struct sockaddr_storage peeraddr;
- struct sockaddr_storage maskaddr;
- FILE *fp[MAXINCLUDELEVEL+1];
- FILE *includefile;
- int includelevel = 0;
- char line[MAXLINE];
- char *(tokens[MAXTOKENS]);
- int ntokens = 0;
- int tok = CONFIG_UNKNOWN;
- struct interface *localaddr;
- struct refclockstat clock_stat;
- FILEGEN *filegen;
+#ifdef SAVECONFIG
+/* Dump all trees */
+int
+dump_all_config_trees(
+ FILE *df,
+ int comment
+ )
+{
+ config_tree * cfg_ptr;
+ int return_value;
- /*
- * Initialize, initialize
- */
- errflg = 0;
-
-#ifndef SYS_WINNT
- config_file = CONFIG_FILE;
-#else
- temp = CONFIG_FILE;
- if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
- msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
- exit(1);
- }
- config_file = config_file_storage;
+ return_value = 0;
+ for (cfg_ptr = cfg_tree_history;
+ cfg_ptr != NULL;
+ cfg_ptr = cfg_ptr->link)
+ return_value |= dump_config_tree(cfg_ptr, df, comment);
- temp = ALT_CONFIG_FILE;
- if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
- msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
- exit(1);
+ return return_value;
+}
+
+
+/* The config dumper */
+int
+dump_config_tree(
+ config_tree *ptree,
+ FILE *df,
+ int comment
+ )
+{
+ peer_node *peern;
+ unpeer_node *unpeern;
+ attr_val *atrv;
+ address_node *addr;
+ address_node *peer_addr;
+ address_node *fudge_addr;
+ filegen_node *fgen_node;
+ restrict_node *rest_node;
+ addr_opts_node *addr_opts;
+ setvar_node *setv_node;
+ nic_rule_node *rule_node;
+ int_node *i_n;
+ int_node *flags;
+ int_node *counter_set;
+ string_node *str_node;
+
+ const char *s = NULL;
+ char *s1;
+ char *s2;
+ char timestamp[80];
+ int enable;
+
+ DPRINTF(1, ("dump_config_tree(%p)\n", ptree));
+
+ if (comment) {
+ if (!strftime(timestamp, sizeof(timestamp),
+ "%Y-%m-%d %H:%M:%S",
+ localtime(&ptree->timestamp)))
+ timestamp[0] = '\0';
+
+ fprintf(df, "# %s %s %s\n",
+ timestamp,
+ (CONF_SOURCE_NTPQ == ptree->source.attr)
+ ? "ntpq remote config from"
+ : "startup configuration file",
+ ptree->source.value.s);
}
- alt_config_file = alt_config_file_storage;
-#endif /* SYS_WINNT */
- res_fp = NULL;
- ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
+ /* For options I didn't find documentation I'll just output its name and the cor. value */
+ atrv = HEAD_PFIFO(ptree->vars);
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ switch (atrv->type) {
+#ifdef DEBUG
+ default:
+ fprintf(df, "\n# dump error:\n"
+ "# unknown vars type %d (%s) for %s\n",
+ atrv->type, token_name(atrv->type),
+ token_name(atrv->attr));
+ break;
+#endif
+ case T_Double:
+ fprintf(df, "%s %s\n", keyword(atrv->attr),
+ normal_dtoa(atrv->value.d));
+ break;
- /*
- * install a non default variable with this daemon version
- */
- (void) sprintf(line, "daemon_version=\"%s\"", Version);
- set_sys_var(line, strlen(line)+1, RO);
+ case T_Integer:
+ fprintf(df, "%s %d\n", keyword(atrv->attr),
+ atrv->value.i);
+ break;
- /*
- * Say how we're setting the time of day
- */
- (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using);
- set_sys_var(line, strlen(line)+1, RO);
+ case T_String:
+ fprintf(df, "%s \"%s\"", keyword(atrv->attr),
+ atrv->value.s);
+ if (T_Driftfile == atrv->attr &&
+ atrv->link != NULL &&
+ T_WanderThreshold == atrv->link->attr) {
+ atrv = atrv->link;
+ fprintf(df, " %s\n",
+ normal_dtoa(atrv->value.d));
+ } else {
+ fprintf(df, "\n");
+ }
+ break;
+ }
+ }
- /*
- * Initialize the loop.
- */
- loop_config(LOOP_DRIFTINIT, 0.);
+ atrv = HEAD_PFIFO(ptree->logconfig);
+ if (atrv != NULL) {
+ fprintf(df, "logconfig");
+ for ( ; atrv != NULL; atrv = atrv->link)
+ fprintf(df, " %c%s", atrv->attr, atrv->value.s);
+ fprintf(df, "\n");
+ }
- getCmdOpts(argc, argv);
+ if (ptree->stats_dir)
+ fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir);
- if (
- (fp[0] = fopen(FindConfig(config_file), "r")) == NULL
-#ifdef HAVE_NETINFO
- /* If there is no config_file, try NetInfo. */
- && check_netinfo && !(config_netinfo = get_netinfo_config())
-#endif /* HAVE_NETINFO */
- ) {
- fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
- msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
-#ifdef SYS_WINNT
- /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
+ i_n = HEAD_PFIFO(ptree->stats_list);
+ if (i_n != NULL) {
+ fprintf(df, "statistics");
+ for ( ; i_n != NULL; i_n = i_n->link)
+ fprintf(df, " %s", keyword(i_n->i));
+ fprintf(df, "\n");
+ }
- if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) {
+ fgen_node = HEAD_PFIFO(ptree->filegen_opts);
+ for ( ; fgen_node != NULL; fgen_node = fgen_node->link) {
+ atrv = HEAD_PFIFO(fgen_node->options);
+ if (atrv != NULL) {
+ fprintf(df, "filegen %s",
+ keyword(fgen_node->filegen_token));
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ switch (atrv->attr) {
+#ifdef DEBUG
+ default:
+ fprintf(df, "\n# dump error:\n"
+ "# unknown filegen option token %s\n"
+ "filegen %s",
+ token_name(atrv->attr),
+ keyword(fgen_node->filegen_token));
+ break;
+#endif
+ case T_File:
+ fprintf(df, " file %s",
+ atrv->value.s);
+ break;
- /*
- * Broadcast clients can sometimes run without
- * a configuration file.
- */
+ case T_Type:
+ fprintf(df, " type %s",
+ keyword(atrv->value.i));
+ break;
- fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
- msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
- return;
+ case T_Flag:
+ fprintf(df, " %s",
+ keyword(atrv->value.i));
+ break;
+ }
+ }
+ fprintf(df, "\n");
}
-#else /* not SYS_WINNT */
- return;
-#endif /* not SYS_WINNT */
}
- proto_config(PROTO_MONITOR, 0, 0., NULL);
-
- for (;;) {
- if (tok == CONFIG_END)
- break;
- if (fp[includelevel])
- tok = gettokens(fp[includelevel], line, tokens, &ntokens);
-#ifdef HAVE_NETINFO
- else
- tok = gettokens_netinfo(config_netinfo, tokens, &ntokens);
-#endif /* HAVE_NETINFO */
+ atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
+ if (atrv != NULL) {
+ fprintf(df, "crypto");
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ fprintf(df, " %s %s", keyword(atrv->attr),
+ atrv->value.s);
+ }
+ fprintf(df, "\n");
+ }
- if (tok == CONFIG_UNKNOWN) {
- if (includelevel > 0) {
- fclose(fp[includelevel--]);
- continue;
- } else {
- break;
- }
- }
-
- switch(tok) {
- case CONFIG_PEER:
- case CONFIG_SERVER:
- case CONFIG_MANYCASTCLIENT:
- case CONFIG_BROADCAST:
- if (tok == CONFIG_PEER)
- hmode = MODE_ACTIVE;
- else if (tok == CONFIG_SERVER)
- hmode = MODE_CLIENT;
- else if (tok == CONFIG_MANYCASTCLIENT)
- hmode = MODE_CLIENT;
+ if (ptree->auth.revoke != 0)
+ fprintf(df, "revoke %d\n", ptree->auth.revoke);
+
+ if (ptree->auth.keysdir != NULL)
+ fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir);
+
+ if (ptree->auth.keys != NULL)
+ fprintf(df, "keys \"%s\"\n", ptree->auth.keys);
+
+ atrv = HEAD_PFIFO(ptree->auth.trusted_key_list);
+ if (atrv != NULL) {
+ fprintf(df, "trustedkey");
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ if (T_Integer == atrv->type)
+ fprintf(df, " %d", atrv->value.i);
+ else if (T_Intrange == atrv->type)
+ fprintf(df, " (%d ... %d)",
+ atrv->value.r.first,
+ atrv->value.r.last);
+#ifdef DEBUG
else
- hmode = MODE_BROADCAST;
+ fprintf(df, "\n# dump error:\n"
+ "# unknown trustedkey attr type %d\n"
+ "trustedkey", atrv->type);
+#endif
+ }
+ fprintf(df, "\n");
+ }
- if (ntokens < 2) {
- msyslog(LOG_ERR,
- "No address for %s, line ignored",
- tokens[0]);
- break;
- }
+ if (ptree->auth.control_key)
+ fprintf(df, "controlkey %d\n", ptree->auth.control_key);
+
+ if (ptree->auth.request_key)
+ fprintf(df, "requestkey %d\n", ptree->auth.request_key);
+
+ /* dump enable list, then disable list */
+ for (enable = 1; enable >= 0; enable--) {
+ atrv = (enable)
+ ? HEAD_PFIFO(ptree->enable_opts)
+ : HEAD_PFIFO(ptree->disable_opts);
+ if (atrv != NULL) {
+ fprintf(df, "%s", (enable)
+ ? "enable"
+ : "disable");
+ for ( ; atrv != NULL; atrv = atrv->link)
+ fprintf(df, " %s",
+ keyword(atrv->value.i));
+ fprintf(df, "\n");
+ }
+ }
- istart = 1;
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- peeraddr.ss_family = default_ai_family;
- switch (matchkey(tokens[istart], addr_type, 0)) {
- case CONF_ADDR_IPV4:
- peeraddr.ss_family = AF_INET;
- istart++;
+ atrv = HEAD_PFIFO(ptree->orphan_cmds);
+ if (atrv != NULL) {
+ fprintf(df, "tos");
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ switch (atrv->type) {
+#ifdef DEBUG
+ default:
+ fprintf(df, "\n# dump error:\n"
+ "# unknown tos attr type %d %s\n"
+ "tos", atrv->type,
+ token_name(atrv->type));
break;
- case CONF_ADDR_IPV6:
- peeraddr.ss_family = AF_INET6;
- istart++;
+#endif
+ case T_Double:
+ fprintf(df, " %s %s",
+ keyword(atrv->attr),
+ normal_dtoa(atrv->value.d));
break;
}
+ }
+ fprintf(df, "\n");
+ }
- status = getnetnum(tokens[istart], &peeraddr, 0, t_UNK);
- if (status == -1)
- break; /* Found IPv6 address */
- if(status != 1) {
- errflg = -1;
- } else {
- errflg = 0;
-
- if (
-#ifdef REFCLOCK
- !ISREFCLOCKADR(&peeraddr) &&
-#endif
- ISBADADR(&peeraddr)) {
- msyslog(LOG_ERR,
- "attempt to configure invalid address %s",
- stoa(&peeraddr));
- break;
- }
- /*
- * Shouldn't be able to specify multicast
- * address for server/peer!
- * and unicast address for manycastclient!
- */
- if (peeraddr.ss_family == AF_INET) {
- if (((tok == CONFIG_SERVER) ||
- (tok == CONFIG_PEER)) &&
-#ifdef REFCLOCK
- !ISREFCLOCKADR(&peeraddr) &&
-#endif
- IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
- msyslog(LOG_ERR,
- "attempt to configure invalid address %s",
- stoa(&peeraddr));
- break;
- }
- if ((tok == CONFIG_MANYCASTCLIENT) &&
- !IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
- msyslog(LOG_ERR,
- "attempt to configure invalid address %s",
- stoa(&peeraddr));
- break;
- }
- }
- else if(peeraddr.ss_family == AF_INET6) {
- if (((tok == CONFIG_SERVER) ||
- (tok == CONFIG_PEER)) &&
-#ifdef REFCLOCK
- !ISREFCLOCKADR(&peeraddr) &&
-#endif
- IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
- msyslog(LOG_ERR,
- "attempt to configure in valid address %s",
- stoa(&peeraddr));
- break;
- }
- if ((tok == CONFIG_MANYCASTCLIENT) &&
- !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
- msyslog(LOG_ERR,
- "attempt to configure in valid address %s",
- stoa(&peeraddr));
- break;
- }
- }
- }
- if (peeraddr.ss_family == AF_INET6 &&
- isc_net_probeipv6() != ISC_R_SUCCESS)
- break;
+ atrv = HEAD_PFIFO(ptree->rlimit);
+ if (atrv != NULL) {
+ fprintf(df, "rlimit");
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ INSIST(T_Integer == atrv->type);
+ fprintf(df, " %s %d", keyword(atrv->attr),
+ atrv->value.i);
+ }
+ fprintf(df, "\n");
+ }
- peerversion = NTP_VERSION;
- minpoll = NTP_MINDPOLL;
- maxpoll = NTP_MAXDPOLL;
- peerkey = 0;
- peerkeystr = (u_char *)"*";
- peerflags = 0;
- ttl = 0;
- istart++;
- for (i = istart; i < ntokens; i++)
- switch (matchkey(tokens[i], mod_keywords, 1)) {
- case CONF_MOD_VERSION:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "peer/server version requires an argument");
- errflg = 1;
- break;
- }
- peerversion = atoi(tokens[++i]);
- if ((u_char)peerversion > NTP_VERSION
- || (u_char)peerversion < NTP_OLDVERSION) {
- msyslog(LOG_ERR,
- "inappropriate version number %s, line ignored",
- tokens[i]);
- errflg = 1;
- }
- break;
-
- case CONF_MOD_KEY:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "key: argument required");
- errflg = 1;
- break;
- }
- peerkey = (int)atol(tokens[++i]);
- peerflags |= FLAG_AUTHENABLE;
- break;
-
- case CONF_MOD_MINPOLL:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "minpoll: argument required");
- errflg = 1;
- break;
- }
- minpoll = atoi(tokens[++i]);
- if (minpoll < NTP_MINPOLL) {
- msyslog(LOG_INFO,
- "minpoll: provided value (%d) is below minimum (%d)",
- minpoll, NTP_MINPOLL);
- minpoll = NTP_MINPOLL;
- }
- break;
-
- case CONF_MOD_MAXPOLL:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "maxpoll: argument required"
- );
- errflg = 1;
- break;
- }
- maxpoll = atoi(tokens[++i]);
- if (maxpoll > NTP_MAXPOLL) {
- msyslog(LOG_INFO,
- "maxpoll: provided value (%d) is above maximum (%d)",
- maxpoll, NTP_MAXPOLL);
- maxpoll = NTP_MAXPOLL;
- }
- break;
-
- case CONF_MOD_PREFER:
- peerflags |= FLAG_PREFER;
- break;
-
- case CONF_MOD_PREEMPT:
- peerflags |= FLAG_PREEMPT;
- break;
-
- case CONF_MOD_NOSELECT:
- peerflags |= FLAG_NOSELECT;
- break;
-
- case CONF_MOD_TRUE:
- peerflags |= FLAG_TRUE;
-
- case CONF_MOD_BURST:
- peerflags |= FLAG_BURST;
- break;
-
- case CONF_MOD_IBURST:
- peerflags |= FLAG_IBURST;
- break;
-
- case CONF_MOD_DYNAMIC:
- msyslog(LOG_WARNING,
- "Warning: the \"dynamic\" keyword has been obsoleted"
- " and will be removed in the next release\n");
- break;
-
-#ifdef OPENSSL
- case CONF_MOD_SKEY:
- peerflags |= FLAG_SKEY |
- FLAG_AUTHENABLE;
- break;
-#endif /* OPENSSL */
-
- case CONF_MOD_TTL:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "ttl: argument required");
- errflg = 1;
- break;
- }
- ttl = atoi(tokens[++i]);
- if (ttl >= MAX_TTL) {
- msyslog(LOG_ERR,
- "ttl: invalid argument");
- errflg = 1;
- }
- break;
+ atrv = HEAD_PFIFO(ptree->tinker);
+ if (atrv != NULL) {
+ fprintf(df, "tinker");
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ INSIST(T_Double == atrv->type);
+ fprintf(df, " %s %s", keyword(atrv->attr),
+ normal_dtoa(atrv->value.d));
+ }
+ fprintf(df, "\n");
+ }
- case CONF_MOD_MODE:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "mode: argument required");
- errflg = 1;
- break;
- }
- ttl = atoi(tokens[++i]);
- break;
-
- case CONFIG_UNKNOWN:
- errflg = 1;
- break;
- }
- if (minpoll > maxpoll) {
- msyslog(LOG_ERR,
- "config error: minpoll > maxpoll");
- errflg = 1;
- }
- if (errflg == 0) {
- if (peer_config(&peeraddr,
- ANY_INTERFACE_CHOOSE(&peeraddr), hmode,
- peerversion, minpoll, maxpoll, peerflags,
- ttl, peerkey, peerkeystr) == 0) {
- msyslog(LOG_ERR,
- "configuration of %s failed",
- stoa(&peeraddr));
- }
- } else if (errflg == -1) {
- save_resolve(tokens[istart - 1], hmode, peerversion,
- minpoll, maxpoll, peerflags, ttl,
- peerkey, peerkeystr, peeraddr.ss_family);
- }
- break;
+ if (ptree->broadcastclient)
+ fprintf(df, "broadcastclient\n");
- case CONFIG_DRIFTFILE:
- if (ntokens >= 2)
- stats_config(STATS_FREQ_FILE, tokens[1]);
- else
- stats_config(STATS_FREQ_FILE, (char *)0);
- stats_write_period = stats_write_tolerance = 0;
- if (ntokens >= 3)
- stats_write_period = 60 * atol(tokens[2]);
- if (stats_write_period <= 0)
- stats_write_period = 3600;
- if (ntokens >= 4) {
- double ftemp;
- sscanf(tokens[3], "%lf", &ftemp);
- stats_write_tolerance = ftemp / 100;
- }
+ peern = HEAD_PFIFO(ptree->peers);
+ for ( ; peern != NULL; peern = peern->link) {
+ addr = peern->addr;
+ fprintf(df, "%s", keyword(peern->host_mode));
+ switch (addr->type) {
+#ifdef DEBUG
+ default:
+ fprintf(df, "# dump error:\n"
+ "# unknown peer family %d for:\n"
+ "%s", addr->type,
+ keyword(peern->host_mode));
break;
-
- case CONFIG_PIDFILE:
- if (ntokens >= 2)
- stats_config(STATS_PID_FILE, tokens[1]);
- else
- stats_config(STATS_PID_FILE, (char *)0);
+#endif
+ case AF_UNSPEC:
break;
- case CONFIG_END:
- for ( i = 0; i <= includelevel; i++ ) {
- fclose(fp[i]);
- }
+ case AF_INET:
+ fprintf(df, " -4");
break;
-
- case CONFIG_INCLUDEFILE:
- if (ntokens < 2) {
- msyslog(LOG_ERR, "includefile needs one argument");
- break;
- }
- if (includelevel >= MAXINCLUDELEVEL) {
- fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
- msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded.");
- break;
- }
- includefile = fopen(FindConfig(tokens[1]), "r");
- if (includefile == NULL) {
- fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1]));
- msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1]));
- break;
- }
- fp[++includelevel] = includefile;
+
+ case AF_INET6:
+ fprintf(df, " -6");
break;
+ }
+ fprintf(df, " %s", addr->address);
- case CONFIG_LOGFILE:
- if (ntokens >= 2) {
- FILE *new_file;
+ if (peern->minpoll != 0)
+ fprintf(df, " minpoll %u", peern->minpoll);
- new_file = fopen(tokens[1], "a");
- if (new_file != NULL) {
- NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
- msyslog(LOG_NOTICE, "logging to file %s", tokens[1]);
- if (syslog_file != NULL &&
- fileno(syslog_file) != fileno(new_file))
- (void)fclose(syslog_file);
+ if (peern->maxpoll != 0)
+ fprintf(df, " maxpoll %u", peern->maxpoll);
- syslog_file = new_file;
- syslogit = 0;
- }
- else
- msyslog(LOG_ERR,
- "Cannot open log file %s",
- tokens[1]);
- }
+ if (peern->ttl != 0) {
+ if (strlen(addr->address) > 8
+ && !memcmp(addr->address, "127.127.", 8))
+ fprintf(df, " mode %u", peern->ttl);
else
- msyslog(LOG_ERR, "logfile needs one argument");
- break;
-
- case CONFIG_LOGCONFIG:
- for (i = 1; i < ntokens; i++)
- {
- int add = 1;
- int equals = 0;
- char * s = &tokens[i][0];
-
- switch (*s) {
- case '+':
- case '-':
- case '=':
- add = *s == '+';
- equals = *s == '=';
- s++;
+ fprintf(df, " ttl %u", peern->ttl);
+ }
+
+ if (peern->peerversion != NTP_VERSION)
+ fprintf(df, " version %u", peern->peerversion);
+
+ if (peern->peerkey != 0)
+ fprintf(df, " key %u", peern->peerkey);
+
+ if (peern->group != NULL)
+ fprintf(df, " ident \"%s\"", peern->group);
+
+ atrv = HEAD_PFIFO(peern->peerflags);
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ INSIST(T_Flag == atrv->attr);
+ INSIST(T_Integer == atrv->type);
+ fprintf(df, " %s", keyword(atrv->value.i));
+ }
+
+ fprintf(df, "\n");
+
+ addr_opts = HEAD_PFIFO(ptree->fudge);
+ for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
+ peer_addr = peern->addr;
+ fudge_addr = addr_opts->addr;
+
+ s1 = peer_addr->address;
+ s2 = fudge_addr->address;
+
+ if (strcmp(s1, s2))
+ continue;
+
+ fprintf(df, "fudge %s", s1);
+
+ for (atrv = HEAD_PFIFO(addr_opts->options);
+ atrv != NULL;
+ atrv = atrv->link) {
+
+ switch (atrv->type) {
+#ifdef DEBUG
+ default:
+ fprintf(df, "\n# dump error:\n"
+ "# unknown fudge atrv->type %d\n"
+ "fudge %s", atrv->type,
+ s1);
+ break;
+#endif
+ case T_Double:
+ fprintf(df, " %s %s",
+ keyword(atrv->attr),
+ normal_dtoa(atrv->value.d));
+ break;
+
+ case T_Integer:
+ fprintf(df, " %s %d",
+ keyword(atrv->attr),
+ atrv->value.i);
break;
- default:
+ case T_String:
+ fprintf(df, " %s %s",
+ keyword(atrv->attr),
+ atrv->value.s);
break;
}
- if (equals) {
- ntp_syslogmask = get_logmask(s);
- } else {
- if (add) {
- ntp_syslogmask |= get_logmask(s);
- } else {
- ntp_syslogmask &= ~get_logmask(s);
- }
+ }
+ fprintf(df, "\n");
+ }
+ }
+
+ addr = HEAD_PFIFO(ptree->manycastserver);
+ if (addr != NULL) {
+ fprintf(df, "manycastserver");
+ for ( ; addr != NULL; addr = addr->link)
+ fprintf(df, " %s", addr->address);
+ fprintf(df, "\n");
+ }
+
+ addr = HEAD_PFIFO(ptree->multicastclient);
+ if (addr != NULL) {
+ fprintf(df, "multicastclient");
+ for ( ; addr != NULL; addr = addr->link)
+ fprintf(df, " %s", addr->address);
+ fprintf(df, "\n");
+ }
+
+
+ for (unpeern = HEAD_PFIFO(ptree->unpeers);
+ unpeern != NULL;
+ unpeern = unpeern->link)
+ fprintf(df, "unpeer %s\n", unpeern->addr->address);
+
+ atrv = HEAD_PFIFO(ptree->mru_opts);
+ if (atrv != NULL) {
+ fprintf(df, "mru");
+ for ( ; atrv != NULL; atrv = atrv->link)
+ fprintf(df, " %s %d", keyword(atrv->attr),
+ atrv->value.i);
+ fprintf(df, "\n");
+ }
+
+ atrv = HEAD_PFIFO(ptree->discard_opts);
+ if (atrv != NULL) {
+ fprintf(df, "discard");
+ for ( ; atrv != NULL; atrv = atrv->link)
+ fprintf(df, " %s %d", keyword(atrv->attr),
+ atrv->value.i);
+ fprintf(df, "\n");
+ }
+
+
+ for (rest_node = HEAD_PFIFO(ptree->restrict_opts);
+ rest_node != NULL;
+ rest_node = rest_node->link) {
+
+ if (NULL == rest_node->addr) {
+ s = "default";
+ flags = HEAD_PFIFO(rest_node->flags);
+ for ( ; flags != NULL; flags = flags->link)
+ if (T_Source == flags->i) {
+ s = "source";
+ break;
}
+ } else {
+ s = rest_node->addr->address;
+ }
+ fprintf(df, "restrict %s", s);
+ if (rest_node->mask != NULL)
+ fprintf(df, " mask %s",
+ rest_node->mask->address);
+ flags = HEAD_PFIFO(rest_node->flags);
+ for ( ; flags != NULL; flags = flags->link)
+ if (T_Source != flags->i)
+ fprintf(df, " %s", keyword(flags->i));
+ fprintf(df, "\n");
+ }
+
+ rule_node = HEAD_PFIFO(ptree->nic_rules);
+ for ( ; rule_node != NULL; rule_node = rule_node->link) {
+ fprintf(df, "interface %s %s\n",
+ keyword(rule_node->action),
+ (rule_node->match_class)
+ ? keyword(rule_node->match_class)
+ : rule_node->if_name);
+ }
+
+ str_node = HEAD_PFIFO(ptree->phone);
+ if (str_node != NULL) {
+ fprintf(df, "phone");
+ for ( ; str_node != NULL; str_node = str_node->link)
+ fprintf(df, " \"%s\"", str_node->s);
+ fprintf(df, "\n");
+ }
+
+ setv_node = HEAD_PFIFO(ptree->setvar);
+ for ( ; setv_node != NULL; setv_node = setv_node->link) {
+ s1 = quote_if_needed(setv_node->var);
+ s2 = quote_if_needed(setv_node->val);
+ fprintf(df, "setvar %s = %s", s1, s2);
+ free(s1);
+ free(s2);
+ if (setv_node->isdefault)
+ fprintf(df, " default");
+ fprintf(df, "\n");
+ }
+
+ i_n = HEAD_PFIFO(ptree->ttl);
+ if (i_n != NULL) {
+ fprintf(df, "ttl");
+ for( ; i_n != NULL; i_n = i_n->link)
+ fprintf(df, " %d", i_n->i);
+ fprintf(df, "\n");
+ }
+
+ addr_opts = HEAD_PFIFO(ptree->trap);
+ for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
+ addr = addr_opts->addr;
+ fprintf(df, "trap %s", addr->address);
+ atrv = HEAD_PFIFO(addr_opts->options);
+ for ( ; atrv != NULL; atrv = atrv->link) {
+ switch (atrv->attr) {
#ifdef DEBUG
- if (debug)
- printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]);
+ default:
+ fprintf(df, "\n# dump error:\n"
+ "# unknown trap token %d\n"
+ "trap %s", atrv->attr,
+ addr->address);
+ break;
#endif
+ case T_Port:
+ fprintf(df, " port %d", atrv->value.i);
+ break;
+
+ case T_Interface:
+ fprintf(df, " interface %s",
+ atrv->value.s);
+ break;
+ }
+ }
+ fprintf(df, "\n");
+ }
+
+ counter_set = HEAD_PFIFO(ptree->reset_counters);
+ if (counter_set != NULL) {
+ fprintf(df, "reset");
+ for ( ; counter_set != NULL;
+ counter_set = counter_set->link)
+ fprintf(df, " %s", keyword(counter_set->i));
+ fprintf(df, "\n");
+ }
+
+ return 0;
+}
+#endif /* SAVECONFIG */
+
+
+
+/* generic fifo routines for structs linked by 1st member */
+void *
+append_gen_fifo(
+ void *fifo,
+ void *entry
+ )
+{
+ gen_fifo *pf;
+ gen_node *pe;
+
+ pf = fifo;
+ pe = entry;
+ if (NULL == pf)
+ pf = emalloc_zero(sizeof(*pf));
+ else
+ CHECK_FIFO_CONSISTENCY(*pf);
+ if (pe != NULL)
+ LINK_FIFO(*pf, pe, link);
+ CHECK_FIFO_CONSISTENCY(*pf);
+
+ return pf;
+}
+
+
+void *
+concat_gen_fifos(
+ void *first,
+ void *second
+ )
+{
+ gen_fifo *pf1;
+ gen_fifo *pf2;
+
+ pf1 = first;
+ pf2 = second;
+ if (NULL == pf1)
+ return pf2;
+ if (NULL == pf2)
+ return pf1;
+
+ CONCAT_FIFO(*pf1, *pf2, link);
+ free(pf2);
+
+ return pf1;
+}
+
+
+/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
+ * -----------------------------------------------
+ */
+
+attr_val *
+create_attr_dval(
+ int attr,
+ double value
+ )
+{
+ attr_val *my_val;
+
+ my_val = emalloc_zero(sizeof(*my_val));
+ my_val->attr = attr;
+ my_val->value.d = value;
+ my_val->type = T_Double;
+
+ return my_val;
+}
+
+
+attr_val *
+create_attr_ival(
+ int attr,
+ int value
+ )
+{
+ attr_val *my_val;
+
+ my_val = emalloc_zero(sizeof(*my_val));
+ my_val->attr = attr;
+ my_val->value.i = value;
+ my_val->type = T_Integer;
+
+ return my_val;
+}
+
+
+attr_val *
+create_attr_uval(
+ int attr,
+ u_int value
+ )
+{
+ attr_val *my_val;
+
+ my_val = emalloc_zero(sizeof(*my_val));
+ my_val->attr = attr;
+ my_val->value.u = value;
+ my_val->type = T_U_int;
+
+ return my_val;
+}
+
+
+attr_val *
+create_attr_rangeval(
+ int attr,
+ int first,
+ int last
+ )
+{
+ attr_val *my_val;
+
+ my_val = emalloc_zero(sizeof(*my_val));
+ my_val->attr = attr;
+ my_val->value.r.first = first;
+ my_val->value.r.last = last;
+ my_val->type = T_Intrange;
+
+ return my_val;
+}
+
+
+attr_val *
+create_attr_sval(
+ int attr,
+ const char *s
+ )
+{
+ attr_val *my_val;
+
+ my_val = emalloc_zero(sizeof(*my_val));
+ my_val->attr = attr;
+ if (NULL == s) /* free() hates NULL */
+ s = estrdup("");
+ my_val->value.s = _UC(s);
+ my_val->type = T_String;
+
+ return my_val;
+}
+
+
+int_node *
+create_int_node(
+ int val
+ )
+{
+ int_node *i_n;
+
+ i_n = emalloc_zero(sizeof(*i_n));
+ i_n->i = val;
+
+ return i_n;
+}
+
+
+string_node *
+create_string_node(
+ char *str
+ )
+{
+ string_node *sn;
+
+ sn = emalloc_zero(sizeof(*sn));
+ sn->s = str;
+
+ return sn;
+}
+
+
+address_node *
+create_address_node(
+ char * addr,
+ int type
+ )
+{
+ address_node *my_node;
+
+ NTP_REQUIRE(NULL != addr);
+ NTP_REQUIRE(AF_INET == type ||
+ AF_INET6 == type || AF_UNSPEC == type);
+ my_node = emalloc_zero(sizeof(*my_node));
+ my_node->address = addr;
+ my_node->type = (u_short)type;
+
+ return my_node;
+}
+
+
+void
+destroy_address_node(
+ address_node *my_node
+ )
+{
+ if (NULL == my_node)
+ return;
+ NTP_REQUIRE(NULL != my_node->address);
+
+ free(my_node->address);
+ free(my_node);
+}
+
+
+peer_node *
+create_peer_node(
+ int hmode,
+ address_node * addr,
+ attr_val_fifo * options
+ )
+{
+ peer_node *my_node;
+ attr_val *option;
+ int freenode;
+ int errflag = 0;
+
+ my_node = emalloc_zero(sizeof(*my_node));
+
+ /* Initialize node values to default */
+ my_node->peerversion = NTP_VERSION;
+
+ /* Now set the node to the read values */
+ my_node->host_mode = hmode;
+ my_node->addr = addr;
+
+ /*
+ * the options FIFO mixes items that will be saved in the
+ * peer_node as explicit members, such as minpoll, and
+ * those that are moved intact to the peer_node's peerflags
+ * FIFO. The options FIFO is consumed and reclaimed here.
+ */
+
+ if (options != NULL)
+ CHECK_FIFO_CONSISTENCY(*options);
+ while (options != NULL) {
+ UNLINK_FIFO(option, *options, link);
+ if (NULL == option) {
+ free(options);
+ break;
+ }
+
+ freenode = 1;
+ /* Check the kind of option being set */
+ switch (option->attr) {
+
+ case T_Flag:
+ APPEND_G_FIFO(my_node->peerflags, option);
+ freenode = 0;
+ break;
+
+ case T_Minpoll:
+ if (option->value.i < NTP_MINPOLL ||
+ option->value.i > UCHAR_MAX) {
+ msyslog(LOG_INFO,
+ "minpoll: provided value (%d) is out of range [%d-%d])",
+ option->value.i, NTP_MINPOLL,
+ UCHAR_MAX);
+ my_node->minpoll = NTP_MINPOLL;
+ } else {
+ my_node->minpoll =
+ (u_char)option->value.u;
}
break;
- case CONFIG_BROADCASTCLIENT:
- if (ntokens == 1) {
- proto_config(PROTO_BROADCLIENT, 1, 0., NULL);
+ case T_Maxpoll:
+ if (option->value.i < 0 ||
+ option->value.i > NTP_MAXPOLL) {
+ msyslog(LOG_INFO,
+ "maxpoll: provided value (%d) is out of range [0-%d])",
+ option->value.i, NTP_MAXPOLL);
+ my_node->maxpoll = NTP_MAXPOLL;
} else {
- proto_config(PROTO_BROADCLIENT, 2, 0., NULL);
+ my_node->maxpoll =
+ (u_char)option->value.u;
}
break;
- case CONFIG_MULTICASTCLIENT:
- case CONFIG_MANYCASTSERVER:
- if (ntokens > 1) {
- istart = 1;
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- peeraddr.ss_family = default_ai_family;
- switch (matchkey(tokens[istart],
- addr_type, 0)) {
- case CONF_ADDR_IPV4:
- peeraddr.ss_family = AF_INET;
- istart++;
- break;
- case CONF_ADDR_IPV6:
- peeraddr.ss_family = AF_INET6;
- istart++;
- break;
- }
- /*
- * Abuse maskaddr to store the prefered ip
- * version.
- */
- memset((char *)&maskaddr, 0, sizeof(maskaddr));
- maskaddr.ss_family = peeraddr.ss_family;
-
- for (i = istart; i < ntokens; i++) {
- memset((char *)&peeraddr, 0,
- sizeof(peeraddr));
- peeraddr.ss_family = maskaddr.ss_family;
- if (getnetnum(tokens[i], &peeraddr, 1,
- t_UNK) == 1)
- proto_config(PROTO_MULTICAST_ADD,
- 0, 0., &peeraddr);
- }
- } else
- proto_config(PROTO_MULTICAST_ADD,
- 0, 0., NULL);
- if (tok == CONFIG_MULTICASTCLIENT)
- proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
- else if (tok == CONFIG_MANYCASTSERVER)
- sys_manycastserver = 1;
+ case T_Ttl:
+ if (option->value.u >= MAX_TTL) {
+ msyslog(LOG_ERR, "ttl: invalid argument");
+ errflag = 1;
+ } else {
+ my_node->ttl = (u_char)option->value.u;
+ }
break;
- case CONFIG_KEYS:
- if (ntokens >= 2) {
- getauthkeys(tokens[1]);
+ case T_Mode:
+ my_node->ttl = option->value.u;
+ break;
+
+ case T_Key:
+ if (option->value.u >= KEYID_T_MAX) {
+ msyslog(LOG_ERR, "key: invalid argument");
+ errflag = 1;
+ } else {
+ my_node->peerkey =
+ (keyid_t)option->value.u;
}
break;
- case CONFIG_KEYSDIR:
- if (ntokens < 2) {
- msyslog(LOG_ERR,
- "Keys directory name required");
- break;
+ case T_Version:
+ if (option->value.u >= UCHAR_MAX) {
+ msyslog(LOG_ERR, "version: invalid argument");
+ errflag = 1;
+ } else {
+ my_node->peerversion =
+ (u_char)option->value.u;
}
- keysdir = (char *)emalloc(strlen(tokens[1]) + 1);
- strcpy(keysdir, tokens[1]);
break;
- case CONFIG_TINKER:
- for (i = 1; i < ntokens; i++) {
- int temp;
- double ftemp;
+ case T_Ident:
+ my_node->group = option->value.s;
+ break;
- temp = matchkey(tokens[i++], tinker_keywords, 1);
- if (i > ntokens - 1) {
- msyslog(LOG_ERR,
- "tinker: missing argument");
- errflg++;
+ default:
+ msyslog(LOG_ERR,
+ "Unknown peer/server option token %s",
+ token_name(option->attr));
+ errflag = 1;
+ }
+ if (freenode)
+ free(option);
+ }
+
+ /* Check if errors were reported. If yes, ignore the node */
+ if (errflag) {
+ free(my_node);
+ my_node = NULL;
+ }
+
+ return my_node;
+}
+
+
+unpeer_node *
+create_unpeer_node(
+ address_node *addr
+ )
+{
+ unpeer_node * my_node;
+ u_int u;
+ char * pch;
+
+ my_node = emalloc_zero(sizeof(*my_node));
+
+ /*
+ * From the parser's perspective an association ID fits into
+ * its generic T_String definition of a name/address "address".
+ * We treat all valid 16-bit numbers as association IDs.
+ */
+ pch = addr->address;
+ while (*pch && isdigit((unsigned char)*pch))
+ pch++;
+
+ if (!*pch
+ && 1 == sscanf(addr->address, "%u", &u)
+ && u <= ASSOCID_MAX) {
+ my_node->assocID = (associd_t)u;
+ destroy_address_node(addr);
+ my_node->addr = NULL;
+ } else {
+ my_node->assocID = 0;
+ my_node->addr = addr;
+ }
+
+ return my_node;
+}
+
+filegen_node *
+create_filegen_node(
+ int filegen_token,
+ attr_val_fifo * options
+ )
+{
+ filegen_node *my_node;
+
+ my_node = emalloc_zero(sizeof(*my_node));
+ my_node->filegen_token = filegen_token;
+ my_node->options = options;
+
+ return my_node;
+}
+
+
+restrict_node *
+create_restrict_node(
+ address_node * addr,
+ address_node * mask,
+ int_fifo * flags,
+ int line_no
+ )
+{
+ restrict_node *my_node;
+
+ my_node = emalloc_zero(sizeof(*my_node));
+ my_node->addr = addr;
+ my_node->mask = mask;
+ my_node->flags = flags;
+ my_node->line_no = line_no;
+
+ return my_node;
+}
+
+
+static void
+destroy_restrict_node(
+ restrict_node *my_node
+ )
+{
+ /* With great care, free all the memory occupied by
+ * the restrict node
+ */
+ destroy_address_node(my_node->addr);
+ destroy_address_node(my_node->mask);
+ destroy_int_fifo(my_node->flags);
+ free(my_node);
+}
+
+
+static void
+destroy_int_fifo(
+ int_fifo * fifo
+ )
+{
+ int_node * i_n;
+
+ if (fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(i_n, *fifo, link);
+ if (i_n == NULL)
break;
- }
- sscanf(tokens[i], "%lf", &ftemp);
- switch(temp) {
+ free(i_n);
+ }
+ free(fifo);
+ }
+}
- case CONF_CLOCK_MAX:
- loop_config(LOOP_MAX, ftemp);
+
+static void
+destroy_string_fifo(
+ string_fifo * fifo
+ )
+{
+ string_node * sn;
+
+ if (fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(sn, *fifo, link);
+ if (sn == NULL)
break;
+ free(sn->s);
+ free(sn);
+ }
+ free(fifo);
+ }
+}
+
+
+static void
+destroy_attr_val_fifo(
+ attr_val_fifo * av_fifo
+ )
+{
+ attr_val * av;
- case CONF_CLOCK_PANIC:
- loop_config(LOOP_PANIC, ftemp);
+ if (av_fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(av, *av_fifo, link);
+ if (av == NULL)
break;
+ if (T_String == av->type)
+ free(av->value.s);
+ free(av);
+ }
+ free(av_fifo);
+ }
+}
+
- case CONF_CLOCK_PHI:
- loop_config(LOOP_PHI, ftemp);
+static void
+destroy_filegen_fifo(
+ filegen_fifo * fifo
+ )
+{
+ filegen_node * fg;
+
+ if (fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(fg, *fifo, link);
+ if (fg == NULL)
break;
+ destroy_attr_val_fifo(fg->options);
+ free(fg);
+ }
+ free(fifo);
+ }
+}
+
+
+static void
+destroy_restrict_fifo(
+ restrict_fifo * fifo
+ )
+{
+ restrict_node * rn;
- case CONF_CLOCK_MINSTEP:
- loop_config(LOOP_MINSTEP, ftemp);
+ if (fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(rn, *fifo, link);
+ if (rn == NULL)
break;
+ destroy_restrict_node(rn);
+ }
+ free(fifo);
+ }
+}
+
- case CONF_CLOCK_ALLAN:
- loop_config(LOOP_ALLAN, ftemp);
+static void
+destroy_setvar_fifo(
+ setvar_fifo * fifo
+ )
+{
+ setvar_node * sv;
+
+ if (fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(sv, *fifo, link);
+ if (sv == NULL)
break;
+ free(sv->var);
+ free(sv->val);
+ free(sv);
+ }
+ free(fifo);
+ }
+}
+
+
+static void
+destroy_addr_opts_fifo(
+ addr_opts_fifo * fifo
+ )
+{
+ addr_opts_node * aon;
- case CONF_CLOCK_HUFFPUFF:
- loop_config(LOOP_HUFFPUFF, ftemp);
+ if (fifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(aon, *fifo, link);
+ if (aon == NULL)
break;
+ destroy_address_node(aon->addr);
+ destroy_attr_val_fifo(aon->options);
+ free(aon);
+ }
+ free(fifo);
+ }
+}
- case CONF_CLOCK_FREQ:
- loop_config(LOOP_FREQ, ftemp);
- break;
- }
- }
+
+setvar_node *
+create_setvar_node(
+ char * var,
+ char * val,
+ int isdefault
+ )
+{
+ setvar_node * my_node;
+ char * pch;
+
+ /* do not allow = in the variable name */
+ pch = strchr(var, '=');
+ if (NULL != pch)
+ *pch = '\0';
+
+ /* Now store the string into a setvar_node */
+ my_node = emalloc_zero(sizeof(*my_node));
+ my_node->var = var;
+ my_node->val = val;
+ my_node->isdefault = isdefault;
+
+ return my_node;
+}
+
+
+nic_rule_node *
+create_nic_rule_node(
+ int match_class,
+ char *if_name, /* interface name or numeric address */
+ int action
+ )
+{
+ nic_rule_node *my_node;
+
+ NTP_REQUIRE(match_class != 0 || if_name != NULL);
+
+ my_node = emalloc_zero(sizeof(*my_node));
+ my_node->match_class = match_class;
+ my_node->if_name = if_name;
+ my_node->action = action;
+
+ return my_node;
+}
+
+
+addr_opts_node *
+create_addr_opts_node(
+ address_node * addr,
+ attr_val_fifo * options
+ )
+{
+ addr_opts_node *my_node;
+
+ my_node = emalloc_zero(sizeof(*my_node));
+ my_node->addr = addr;
+ my_node->options = options;
+
+ return my_node;
+}
+
+
+#ifdef SIM
+script_info *
+create_sim_script_info(
+ double duration,
+ attr_val_fifo * script_queue
+ )
+{
+ script_info *my_info;
+ attr_val *my_attr_val;
+
+ my_info = emalloc_zero(sizeof(*my_info));
+
+ /* Initialize Script Info with default values*/
+ my_info->duration = duration;
+ my_info->prop_delay = NET_DLY;
+ my_info->proc_delay = PROC_DLY;
+
+ /* Traverse the script_queue and fill out non-default values */
+
+ for (my_attr_val = HEAD_PFIFO(script_queue);
+ my_attr_val != NULL;
+ my_attr_val = my_attr_val->link) {
+
+ /* Set the desired value */
+ switch (my_attr_val->attr) {
+
+ case T_Freq_Offset:
+ my_info->freq_offset = my_attr_val->value.d;
break;
- case CONFIG_TOS:
- for (i = 1; i < ntokens; i++) {
- int temp;
- double ftemp;
+ case T_Wander:
+ my_info->wander = my_attr_val->value.d;
+ break;
- temp = matchkey(tokens[i++], tos_keywords, 1);
- if (i > ntokens - 1) {
- msyslog(LOG_ERR,
- "tos: missing argument");
- errflg++;
- break;
- }
- sscanf(tokens[i], "%lf", &ftemp);
- switch(temp) {
+ case T_Jitter:
+ my_info->jitter = my_attr_val->value.d;
+ break;
- case CONF_TOS_MINCLOCK:
- proto_config(PROTO_MINCLOCK, 0, ftemp, NULL);
- break;
+ case T_Prop_Delay:
+ my_info->prop_delay = my_attr_val->value.d;
+ break;
- case CONF_TOS_MAXCLOCK:
- proto_config(PROTO_MAXCLOCK, 0, ftemp, NULL);
- break;
+ case T_Proc_Delay:
+ my_info->proc_delay = my_attr_val->value.d;
+ break;
- case CONF_TOS_MINSANE:
- proto_config(PROTO_MINSANE, 0, ftemp, NULL);
- break;
+ default:
+ msyslog(LOG_ERR, "Unknown script token %d",
+ my_attr_val->attr);
+ }
+ }
- case CONF_TOS_FLOOR:
- proto_config(PROTO_FLOOR, 0, ftemp, NULL);
- break;
+ return my_info;
+}
+#endif /* SIM */
- case CONF_TOS_CEILING:
- proto_config(PROTO_CEILING, 0, ftemp, NULL);
- break;
- case CONF_TOS_COHORT:
- proto_config(PROTO_COHORT, 0, ftemp, NULL);
- break;
+#ifdef SIM
+static sockaddr_u *
+get_next_address(
+ address_node *addr
+ )
+{
+ const char addr_prefix[] = "192.168.0.";
+ static int curr_addr_num = 1;
+#define ADDR_LENGTH 16 + 1 /* room for 192.168.1.255 */
+ char addr_string[ADDR_LENGTH];
+ sockaddr_u *final_addr;
+ struct addrinfo *ptr;
+ int gai_err;
- case CONF_TOS_MINDISP:
- proto_config(PROTO_MINDISP, 0, ftemp, NULL);
- break;
+ final_addr = emalloc(sizeof(*final_addr));
- case CONF_TOS_MAXDIST:
- proto_config(PROTO_MAXDIST, 0, ftemp, NULL);
- break;
+ if (addr->type == T_String) {
+ snprintf(addr_string, sizeof(addr_string), "%s%d",
+ addr_prefix, curr_addr_num++);
+ printf("Selecting ip address %s for hostname %s\n",
+ addr_string, addr->address);
+ gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr);
+ } else {
+ gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr);
+ }
- case CONF_TOS_MAXHOP:
- proto_config(PROTO_MAXHOP, 0, ftemp, NULL);
- break;
+ if (gai_err) {
+ fprintf(stderr, "ERROR!! Could not get a new address\n");
+ exit(1);
+ }
+ memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
+ fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n",
+ stoa(final_addr));
+ freeaddrinfo(ptr);
+
+ return final_addr;
+}
+#endif /* SIM */
+
+
+#ifdef SIM
+server_info *
+create_sim_server(
+ address_node * addr,
+ double server_offset,
+ script_info_fifo * script
+ )
+{
+ server_info *my_info;
+
+ my_info = emalloc_zero(sizeof(*my_info));
+ my_info->server_time = server_offset;
+ my_info->addr = get_next_address(addr);
+ my_info->script = script;
+ UNLINK_FIFO(my_info->curr_script, *my_info->script, link);
+
+ return my_info;
+}
+#endif /* SIM */
+
+sim_node *
+create_sim_node(
+ attr_val_fifo * init_opts,
+ server_info_fifo * servers
+ )
+{
+ sim_node *my_node;
+
+ my_node = emalloc(sizeof(*my_node));
+ my_node->init_opts = init_opts;
+ my_node->servers = servers;
+
+ return my_node;
+}
- case CONF_TOS_ORPHAN:
- proto_config(PROTO_ORPHAN, 0, ftemp, NULL);
- break;
- case CONF_TOS_BEACON:
- proto_config(PROTO_BEACON, 0, ftemp, NULL);
+
+
+/* FUNCTIONS FOR PERFORMING THE CONFIGURATION
+ * ------------------------------------------
+ */
+
+#ifndef SIM
+static void
+config_other_modes(
+ config_tree * ptree
+ )
+{
+ sockaddr_u addr_sock;
+ address_node * addr_node;
+
+ if (ptree->broadcastclient)
+ proto_config(PROTO_BROADCLIENT, ptree->broadcastclient,
+ 0., NULL);
+
+ addr_node = HEAD_PFIFO(ptree->manycastserver);
+ while (addr_node != NULL) {
+ ZERO_SOCK(&addr_sock);
+ AF(&addr_sock) = addr_node->type;
+ if (1 == getnetnum(addr_node->address, &addr_sock, 1,
+ t_UNK)) {
+ proto_config(PROTO_MULTICAST_ADD,
+ 0, 0., &addr_sock);
+ sys_manycastserver = 1;
+ }
+ addr_node = addr_node->link;
+ }
+
+ /* Configure the multicast clients */
+ addr_node = HEAD_PFIFO(ptree->multicastclient);
+ if (addr_node != NULL) {
+ do {
+ ZERO_SOCK(&addr_sock);
+ AF(&addr_sock) = addr_node->type;
+ if (1 == getnetnum(addr_node->address,
+ &addr_sock, 1, t_UNK)) {
+ proto_config(PROTO_MULTICAST_ADD, 0, 0.,
+ &addr_sock);
+ }
+ addr_node = addr_node->link;
+ } while (addr_node != NULL);
+ proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
+ }
+}
+#endif /* !SIM */
+
+
+#ifdef FREE_CFG_T
+static void
+destroy_address_fifo(
+ address_fifo * pfifo
+ )
+{
+ address_node * addr_node;
+
+ if (pfifo != NULL) {
+ for (;;) {
+ UNLINK_FIFO(addr_node, *pfifo, link);
+ if (addr_node == NULL)
break;
- }
+ destroy_address_node(addr_node);
+ }
+ free(pfifo);
+ }
+}
+
+
+static void
+free_config_other_modes(
+ config_tree *ptree
+ )
+{
+ FREE_ADDRESS_FIFO(ptree->manycastserver);
+ FREE_ADDRESS_FIFO(ptree->multicastclient);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_auth(
+ config_tree *ptree
+ )
+{
+ attr_val * my_val;
+ int first;
+ int last;
+ int i;
+ int count;
+#ifdef AUTOKEY
+ int item;
+#endif
+
+ /* Crypto Command */
+#ifdef AUTOKEY
+ item = -1; /* quiet warning */
+ my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
+ for (; my_val != NULL; my_val = my_val->link) {
+ switch (my_val->attr) {
+
+ default:
+ INSIST(0);
+ break;
+
+ case T_Host:
+ item = CRYPTO_CONF_PRIV;
+ break;
+
+ case T_Ident:
+ item = CRYPTO_CONF_IDENT;
+ break;
+
+ case T_Pw:
+ item = CRYPTO_CONF_PW;
+ break;
+
+ case T_Randfile:
+ item = CRYPTO_CONF_RAND;
+ break;
+
+ case T_Digest:
+ item = CRYPTO_CONF_NID;
+ break;
+ }
+ crypto_config(item, my_val->value.s);
+ }
+#endif /* AUTOKEY */
+
+ /* Keysdir Command */
+ if (ptree->auth.keysdir) {
+ if (keysdir != default_keysdir)
+ free(keysdir);
+ keysdir = estrdup(ptree->auth.keysdir);
+ }
+
+
+ /* ntp_signd_socket Command */
+ if (ptree->auth.ntp_signd_socket) {
+ if (ntp_signd_socket != default_ntp_signd_socket)
+ free(ntp_signd_socket);
+ ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket);
+ }
+
+#ifdef AUTOKEY
+ if (ptree->auth.cryptosw && !cryptosw) {
+ crypto_setup();
+ cryptosw = 1;
+ }
+#endif /* AUTOKEY */
+
+ /*
+ * Count the number of trusted keys to preallocate storage and
+ * size the hash table.
+ */
+ count = 0;
+ my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
+ for (; my_val != NULL; my_val = my_val->link) {
+ if (T_Integer == my_val->type) {
+ first = my_val->value.i;
+ if (first > 1 && first <= NTP_MAXKEY)
+ count++;
+ } else {
+ REQUIRE(T_Intrange == my_val->type);
+ first = my_val->value.r.first;
+ last = my_val->value.r.last;
+ if (!(first > last || first < 1 ||
+ last > NTP_MAXKEY)) {
+ count += 1 + last - first;
}
+ }
+ }
+ auth_prealloc_symkeys(count);
+
+ /* Keys Command */
+ if (ptree->auth.keys)
+ getauthkeys(ptree->auth.keys);
+
+ /* Control Key Command */
+ if (ptree->auth.control_key)
+ ctl_auth_keyid = (keyid_t)ptree->auth.control_key;
+
+ /* Requested Key Command */
+ if (ptree->auth.request_key) {
+ DPRINTF(4, ("set info_auth_keyid to %08lx\n",
+ (u_long) ptree->auth.request_key));
+ info_auth_keyid = (keyid_t)ptree->auth.request_key;
+ }
+
+ /* Trusted Key Command */
+ my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
+ for (; my_val != NULL; my_val = my_val->link) {
+ if (T_Integer == my_val->type) {
+ first = my_val->value.i;
+ if (first >= 1 && first <= NTP_MAXKEY) {
+ authtrust(first, TRUE);
+ } else {
+ msyslog(LOG_NOTICE,
+ "Ignoring invalid trustedkey %d, min 1 max %d.",
+ first, NTP_MAXKEY);
+ }
+ } else {
+ first = my_val->value.r.first;
+ last = my_val->value.r.last;
+ if (first > last || first < 1 ||
+ last > NTP_MAXKEY) {
+ msyslog(LOG_NOTICE,
+ "Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
+ first, last, NTP_MAXKEY);
+ } else {
+ for (i = first; i <= last; i++) {
+ authtrust(i, TRUE);
+ }
+ }
+ }
+ }
+
+#ifdef AUTOKEY
+ /* crypto revoke command */
+ if (ptree->auth.revoke)
+ sys_revoke = 1UL << ptree->auth.revoke;
+#endif /* AUTOKEY */
+}
+#endif /* !SIM */
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_auth(
+ config_tree *ptree
+ )
+{
+ destroy_attr_val_fifo(ptree->auth.crypto_cmd_list);
+ ptree->auth.crypto_cmd_list = NULL;
+ destroy_attr_val_fifo(ptree->auth.trusted_key_list);
+ ptree->auth.trusted_key_list = NULL;
+}
+#endif /* FREE_CFG_T */
+
+
+static void
+config_tos(
+ config_tree *ptree
+ )
+{
+ attr_val * tos;
+ int item;
+ double val;
+
+ item = -1; /* quiet warning */
+ tos = HEAD_PFIFO(ptree->orphan_cmds);
+ for (; tos != NULL; tos = tos->link) {
+ val = tos->value.d;
+ switch(tos->attr) {
+
+ default:
+ INSIST(0);
break;
- case CONFIG_TTL:
- for (i = 1; i < ntokens && i < MAX_TTL; i++) {
- sys_ttl[i - 1] = (u_char) atoi(tokens[i]);
- sys_ttlmax = i - 1;
+ case T_Ceiling:
+ if (val > STRATUM_UNSPEC - 1) {
+ msyslog(LOG_WARNING,
+ "Using maximum tos ceiling %d, %g requested",
+ STRATUM_UNSPEC - 1, val);
+ val = STRATUM_UNSPEC - 1;
}
+ item = PROTO_CEILING;
break;
- case CONFIG_DISCARD:
- for (i = 1; i < ntokens; i++) {
- int temp;
+ case T_Floor:
+ item = PROTO_FLOOR;
+ break;
- temp = matchkey(tokens[i++],
- discard_keywords, 1);
- if (i > ntokens - 1) {
- msyslog(LOG_ERR,
- "discard: missing argument");
- errflg++;
- break;
- }
- switch(temp) {
- case CONF_DISCARD_AVERAGE:
- res_avg_interval = atoi(tokens[i]);
+ case T_Cohort:
+ item = PROTO_COHORT;
+ break;
+
+ case T_Orphan:
+ item = PROTO_ORPHAN;
+ break;
+
+ case T_Orphanwait:
+ item = PROTO_ORPHWAIT;
+ break;
+
+ case T_Mindist:
+ item = PROTO_MINDISP;
+ break;
+
+ case T_Maxdist:
+ item = PROTO_MAXDIST;
+ break;
+
+ case T_Minclock:
+ item = PROTO_MINCLOCK;
+ break;
+
+ case T_Maxclock:
+ item = PROTO_MAXCLOCK;
+ break;
+
+ case T_Minsane:
+ item = PROTO_MINSANE;
+ break;
+
+ case T_Beacon:
+ item = PROTO_BEACON;
+ break;
+ }
+ proto_config(item, 0, val, NULL);
+ }
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_tos(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
+}
+#endif /* FREE_CFG_T */
+
+
+static void
+config_monitor(
+ config_tree *ptree
+ )
+{
+ int_node *pfilegen_token;
+ const char *filegen_string;
+ const char *filegen_file;
+ FILEGEN *filegen;
+ filegen_node *my_node;
+ attr_val *my_opts;
+ int filegen_type;
+ int filegen_flag;
+
+ /* Set the statistics directory */
+ if (ptree->stats_dir)
+ stats_config(STATS_STATSDIR, ptree->stats_dir);
+
+ /* NOTE:
+ * Calling filegen_get is brain dead. Doing a string
+ * comparison to find the relavant filegen structure is
+ * expensive.
+ *
+ * Through the parser, we already know which filegen is
+ * being specified. Hence, we should either store a
+ * pointer to the specified structure in the syntax tree
+ * or an index into a filegen array.
+ *
+ * Need to change the filegen code to reflect the above.
+ */
+
+ /* Turn on the specified statistics */
+ pfilegen_token = HEAD_PFIFO(ptree->stats_list);
+ for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) {
+ filegen_string = keyword(pfilegen_token->i);
+ filegen = filegen_get(filegen_string);
+ if (NULL == filegen) {
+ msyslog(LOG_ERR,
+ "stats %s unrecognized",
+ filegen_string);
+ continue;
+ }
+ DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n",
+ filegen_string, filegen->dir,
+ filegen->fname));
+ filegen_flag = filegen->flag;
+ filegen_flag |= FGEN_FLAG_ENABLED;
+ filegen_config(filegen, statsdir, filegen_string,
+ filegen->type, filegen_flag);
+ }
+
+ /* Configure the statistics with the options */
+ my_node = HEAD_PFIFO(ptree->filegen_opts);
+ for (; my_node != NULL; my_node = my_node->link) {
+ filegen_string = keyword(my_node->filegen_token);
+ filegen = filegen_get(filegen_string);
+ if (NULL == filegen) {
+ msyslog(LOG_ERR,
+ "filegen category '%s' unrecognized",
+ filegen_string);
+ continue;
+ }
+ filegen_file = filegen_string;
+
+ /* Initialize the filegen variables to their pre-configuration states */
+ filegen_flag = filegen->flag;
+ filegen_type = filegen->type;
+
+ /* "filegen ... enabled" is the default (when filegen is used) */
+ filegen_flag |= FGEN_FLAG_ENABLED;
+
+ my_opts = HEAD_PFIFO(my_node->options);
+ for (; my_opts != NULL; my_opts = my_opts->link) {
+ switch (my_opts->attr) {
+
+ case T_File:
+ filegen_file = my_opts->value.s;
break;
- case CONF_DISCARD_MINIMUM:
- res_min_interval = atoi(tokens[i]);
+ case T_Type:
+ switch (my_opts->value.i) {
+
+ default:
+ INSIST(0);
+ break;
+
+ case T_None:
+ filegen_type = FILEGEN_NONE;
+ break;
+
+ case T_Pid:
+ filegen_type = FILEGEN_PID;
+ break;
+
+ case T_Day:
+ filegen_type = FILEGEN_DAY;
+ break;
+
+ case T_Week:
+ filegen_type = FILEGEN_WEEK;
+ break;
+
+ case T_Month:
+ filegen_type = FILEGEN_MONTH;
+ break;
+
+ case T_Year:
+ filegen_type = FILEGEN_YEAR;
+ break;
+
+ case T_Age:
+ filegen_type = FILEGEN_AGE;
+ break;
+ }
break;
- case CONF_DISCARD_MONITOR:
- mon_age = atoi(tokens[i]);
+ case T_Flag:
+ switch (my_opts->value.i) {
+
+ case T_Link:
+ filegen_flag |= FGEN_FLAG_LINK;
+ break;
+
+ case T_Nolink:
+ filegen_flag &= ~FGEN_FLAG_LINK;
+ break;
+
+ case T_Enable:
+ filegen_flag |= FGEN_FLAG_ENABLED;
+ break;
+
+ case T_Disable:
+ filegen_flag &= ~FGEN_FLAG_ENABLED;
+ break;
+
+ default:
+ msyslog(LOG_ERR,
+ "Unknown filegen flag token %d",
+ my_opts->value.i);
+ exit(1);
+ }
break;
- default:
+ default:
msyslog(LOG_ERR,
- "discard: unknown keyword");
- break;
- }
+ "Unknown filegen option token %d",
+ my_opts->attr);
+ exit(1);
}
+ }
+ filegen_config(filegen, statsdir, filegen_file,
+ filegen_type, filegen_flag);
+ }
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_monitor(
+ config_tree *ptree
+ )
+{
+ if (ptree->stats_dir) {
+ free(ptree->stats_dir);
+ ptree->stats_dir = NULL;
+ }
+
+ FREE_INT_FIFO(ptree->stats_list);
+ FREE_FILEGEN_FIFO(ptree->filegen_opts);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_access(
+ config_tree *ptree
+ )
+{
+ static int warned_signd;
+ attr_val * my_opt;
+ restrict_node * my_node;
+ int_node * curr_flag;
+ sockaddr_u addr;
+ sockaddr_u mask;
+ struct addrinfo hints;
+ struct addrinfo * ai_list;
+ struct addrinfo * pai;
+ int rc;
+ int restrict_default;
+ u_short flags;
+ u_short mflags;
+ int range_err;
+ const char * signd_warning =
+#ifdef HAVE_NTP_SIGND
+ "MS-SNTP signd operations currently block ntpd degrading service to all clients.";
+#else
+ "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd.";
+#endif
+
+ /* Configure the mru options */
+ my_opt = HEAD_PFIFO(ptree->mru_opts);
+ for (; my_opt != NULL; my_opt = my_opt->link) {
+
+ range_err = FALSE;
+
+ switch (my_opt->attr) {
+
+ case T_Incalloc:
+ if (0 <= my_opt->value.i)
+ mru_incalloc = my_opt->value.u;
+ else
+ range_err = TRUE;
break;
-#ifdef OPENSSL
- case CONFIG_REVOKE:
- if (ntokens >= 2)
- sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE);
+ case T_Incmem:
+ if (0 <= my_opt->value.i)
+ mru_incalloc = (my_opt->value.u * 1024U)
+ / sizeof(mon_entry);
+ else
+ range_err = TRUE;
break;
- case CONFIG_AUTOMAX:
- if (ntokens >= 2)
- sys_automax = 1 << max(atoi(tokens[1]), 10);
+ case T_Initalloc:
+ if (0 <= my_opt->value.i)
+ mru_initalloc = my_opt->value.u;
+ else
+ range_err = TRUE;
break;
- case CONFIG_CRYPTO:
- if (ntokens == 1) {
- crypto_config(CRYPTO_CONF_NONE, NULL);
- break;
- }
- for (i = 1; i < ntokens; i++) {
- int temp;
+ case T_Initmem:
+ if (0 <= my_opt->value.i)
+ mru_initalloc = (my_opt->value.u * 1024U)
+ / sizeof(mon_entry);
+ else
+ range_err = TRUE;
+ break;
+
+ case T_Mindepth:
+ if (0 <= my_opt->value.i)
+ mru_mindepth = my_opt->value.u;
+ else
+ range_err = TRUE;
+ break;
+
+ case T_Maxage:
+ mru_maxage = my_opt->value.i;
+ break;
+
+ case T_Maxdepth:
+ if (0 <= my_opt->value.i)
+ mru_maxdepth = my_opt->value.u;
+ else
+ mru_maxdepth = UINT_MAX;
+ break;
+
+ case T_Maxmem:
+ if (0 <= my_opt->value.i)
+ mru_maxdepth = (my_opt->value.u * 1024U) /
+ sizeof(mon_entry);
+ else
+ mru_maxdepth = UINT_MAX;
+ break;
- temp = matchkey(tokens[i++],
- crypto_keywords, 1);
- if (i > ntokens - 1) {
+ default:
+ msyslog(LOG_ERR,
+ "Unknown mru option %s (%d)",
+ keyword(my_opt->attr), my_opt->attr);
+ exit(1);
+ }
+ if (range_err)
+ msyslog(LOG_ERR,
+ "mru %s %d out of range, ignored.",
+ keyword(my_opt->attr), my_opt->value.i);
+ }
+
+ /* Configure the discard options */
+ my_opt = HEAD_PFIFO(ptree->discard_opts);
+ for (; my_opt != NULL; my_opt = my_opt->link) {
+
+ switch (my_opt->attr) {
+
+ case T_Average:
+ if (0 <= my_opt->value.i &&
+ my_opt->value.i <= UCHAR_MAX)
+ ntp_minpoll = (u_char)my_opt->value.u;
+ else
msyslog(LOG_ERR,
- "crypto: missing argument");
- errflg++;
+ "discard average %d out of range, ignored.",
+ my_opt->value.i);
+ break;
+
+ case T_Minimum:
+ ntp_minpkt = my_opt->value.i;
+ break;
+
+ case T_Monitor:
+ mon_age = my_opt->value.i;
+ break;
+
+ default:
+ msyslog(LOG_ERR,
+ "Unknown discard option %s (%d)",
+ keyword(my_opt->attr), my_opt->attr);
+ exit(1);
+ }
+ }
+
+ /* Configure the restrict options */
+ my_node = HEAD_PFIFO(ptree->restrict_opts);
+ for (; my_node != NULL; my_node = my_node->link) {
+ /* Parse the flags */
+ flags = 0;
+ mflags = 0;
+
+ curr_flag = HEAD_PFIFO(my_node->flags);
+ for (; curr_flag != NULL; curr_flag = curr_flag->link) {
+ switch (curr_flag->i) {
+
+ default:
+ INSIST(0);
break;
- }
- switch(temp) {
- case CONF_CRYPTO_CERT:
- crypto_config(CRYPTO_CONF_CERT,
- tokens[i]);
+ case T_Ntpport:
+ mflags |= RESM_NTPONLY;
break;
- case CONF_CRYPTO_RSA:
- crypto_config(CRYPTO_CONF_PRIV,
- tokens[i]);
+ case T_Source:
+ mflags |= RESM_SOURCE;
break;
- case CONF_CRYPTO_IDENT:
- crypto_config(CRYPTO_CONF_IDENT,
- tokens[i]);
+ case T_Flake:
+ flags |= RES_FLAKE;
break;
- case CONF_CRYPTO_IFFPAR:
- crypto_config(CRYPTO_CONF_IFFPAR,
- tokens[i]);
+ case T_Ignore:
+ flags |= RES_IGNORE;
break;
- case CONF_CRYPTO_GQPAR:
- crypto_config(CRYPTO_CONF_GQPAR,
- tokens[i]);
+ case T_Kod:
+ flags |= RES_KOD;
break;
- case CONF_CRYPTO_MVPAR:
- crypto_config(CRYPTO_CONF_MVPAR,
- tokens[i]);
+ case T_Mssntp:
+ flags |= RES_MSSNTP;
break;
- case CONF_CRYPTO_LEAP:
- crypto_config(CRYPTO_CONF_LEAP,
- tokens[i]);
+ case T_Limited:
+ flags |= RES_LIMITED;
break;
- case CONF_CRYPTO_PW:
- crypto_config(CRYPTO_CONF_PW,
- tokens[i]);
+ case T_Lowpriotrap:
+ flags |= RES_LPTRAP;
break;
- case CONF_CRYPTO_RAND:
- crypto_config(CRYPTO_CONF_RAND,
- tokens[i]);
+ case T_Nomodify:
+ flags |= RES_NOMODIFY;
break;
- case CONF_CRYPTO_SIGN:
- crypto_config(CRYPTO_CONF_SIGN,
- tokens[i]);
+ case T_Nomrulist:
+ flags |= RES_NOMRULIST;
break;
- default:
- msyslog(LOG_ERR,
- "crypto: unknown keyword");
+ case T_Nopeer:
+ flags |= RES_NOPEER;
break;
- }
- }
- break;
-#endif /* OPENSSL */
- case CONFIG_RESTRICT:
- if (ntokens < 2) {
- msyslog(LOG_ERR, "restrict requires an address");
+ case T_Noquery:
+ flags |= RES_NOQUERY;
break;
- }
- istart = 1;
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- peeraddr.ss_family = default_ai_family;
- switch (matchkey(tokens[istart], addr_type, 0)) {
- case CONF_ADDR_IPV4:
- peeraddr.ss_family = AF_INET;
- istart++;
+
+ case T_Noserve:
+ flags |= RES_DONTSERVE;
+ break;
+
+ case T_Notrap:
+ flags |= RES_NOTRAP;
+ break;
+
+ case T_Notrust:
+ flags |= RES_DONTTRUST;
break;
- case CONF_ADDR_IPV6:
- peeraddr.ss_family = AF_INET6;
- istart++;
+
+ case T_Version:
+ flags |= RES_VERSION;
break;
}
+ }
+
+ if ((RES_MSSNTP & flags) && !warned_signd) {
+ warned_signd = 1;
+ fprintf(stderr, "%s\n", signd_warning);
+ msyslog(LOG_WARNING, "%s", signd_warning);
+ }
+
+ /* It would be swell if we could identify the line number */
+ if ((RES_KOD & flags) && !(RES_LIMITED & flags)) {
+ const char *kod_where = (my_node->addr)
+ ? my_node->addr->address
+ : (mflags & RESM_SOURCE)
+ ? "source"
+ : "default";
+ const char *kod_warn = "KOD does nothing without LIMITED.";
+
+ fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn);
+ msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn);
+ }
+
+ ZERO_SOCK(&addr);
+ ai_list = NULL;
+ pai = NULL;
+ restrict_default = 0;
+
+ if (NULL == my_node->addr) {
+ ZERO_SOCK(&mask);
+ if (!(RESM_SOURCE & mflags)) {
+ /*
+ * The user specified a default rule
+ * without a -4 / -6 qualifier, add to
+ * both lists
+ */
+ restrict_default = 1;
+ } else {
+ /* apply "restrict source ..." */
+ DPRINTF(1, ("restrict source template mflags %x flags %x\n",
+ mflags, flags));
+ hack_restrict(RESTRICT_FLAGS, NULL,
+ NULL, mflags, flags, 0);
+ continue;
+ }
+ } else {
+ /* Resolve the specified address */
+ AF(&addr) = (u_short)my_node->addr->type;
+
+ if (getnetnum(my_node->addr->address,
+ &addr, 1, t_UNK) != 1) {
+ /*
+ * Attempt a blocking lookup. This
+ * is in violation of the nonblocking
+ * design of ntpd's mainline code. The
+ * alternative of running without the
+ * restriction until the name resolved
+ * seems worse.
+ * Ideally some scheme could be used for
+ * restrict directives in the startup
+ * ntp.conf to delay starting up the
+ * protocol machinery until after all
+ * restrict hosts have been resolved.
+ */
+ ai_list = NULL;
+ ZERO(hints);
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_family = my_node->addr->type;
+ rc = getaddrinfo(my_node->addr->address,
+ "ntp", &hints,
+ &ai_list);
+ if (rc) {
+ msyslog(LOG_ERR,
+ "restrict: ignoring line %d, address/host '%s' unusable.",
+ my_node->line_no,
+ my_node->addr->address);
+ continue;
+ }
+ INSIST(ai_list != NULL);
+ pai = ai_list;
+ INSIST(pai->ai_addr != NULL);
+ INSIST(sizeof(addr) >=
+ pai->ai_addrlen);
+ memcpy(&addr, pai->ai_addr,
+ pai->ai_addrlen);
+ INSIST(AF_INET == AF(&addr) ||
+ AF_INET6 == AF(&addr));
+ }
+
+ SET_HOSTMASK(&mask, AF(&addr));
+
+ /* Resolve the mask */
+ if (my_node->mask) {
+ ZERO_SOCK(&mask);
+ AF(&mask) = my_node->mask->type;
+ if (getnetnum(my_node->mask->address,
+ &mask, 1, t_MSK) != 1) {
+ msyslog(LOG_ERR,
+ "restrict: ignoring line %d, mask '%s' unusable.",
+ my_node->line_no,
+ my_node->mask->address);
+ continue;
+ }
+ }
+ }
+
+ /* Set the flags */
+ if (restrict_default) {
+ AF(&addr) = AF_INET;
+ AF(&mask) = AF_INET;
+ hack_restrict(RESTRICT_FLAGS, &addr,
+ &mask, mflags, flags, 0);
+ AF(&addr) = AF_INET6;
+ AF(&mask) = AF_INET6;
+ }
+
+ do {
+ hack_restrict(RESTRICT_FLAGS, &addr,
+ &mask, mflags, flags, 0);
+ if (pai != NULL &&
+ NULL != (pai = pai->ai_next)) {
+ INSIST(pai->ai_addr != NULL);
+ INSIST(sizeof(addr) >=
+ pai->ai_addrlen);
+ ZERO_SOCK(&addr);
+ memcpy(&addr, pai->ai_addr,
+ pai->ai_addrlen);
+ INSIST(AF_INET == AF(&addr) ||
+ AF_INET6 == AF(&addr));
+ SET_HOSTMASK(&mask, AF(&addr));
+ }
+ } while (pai != NULL);
+
+ if (ai_list != NULL)
+ freeaddrinfo(ai_list);
+ }
+}
+#endif /* !SIM */
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_access(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->mru_opts);
+ FREE_ATTR_VAL_FIFO(ptree->discard_opts);
+ FREE_RESTRICT_FIFO(ptree->restrict_opts);
+}
+#endif /* FREE_CFG_T */
+
+
+static void
+config_rlimit(
+ config_tree *ptree
+ )
+{
+ attr_val * rlimit_av;
+
+ rlimit_av = HEAD_PFIFO(ptree->rlimit);
+ for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) {
+ switch (rlimit_av->attr) {
+
+ default:
+ INSIST(0);
+ break;
+
+ case T_Memlock:
+ if (rlimit_av->value.i != 0) {
+#if defined(RLIMIT_MEMLOCK)
+ ntp_rlimit(RLIMIT_MEMLOCK,
+ (rlim_t)(rlimit_av->value.i * 1024 * 1024),
+ 1024 * 1024,
+ "MB");
+#else
+ /* STDERR as well would be fine... */
+ msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system.");
+#endif /* RLIMIT_MEMLOCK */
+ } else {
+ do_memlock = 0;
+ }
+ break;
+
+ case T_Stacksize:
+#if defined(RLIMIT_STACK)
+ ntp_rlimit(RLIMIT_STACK,
+ (rlim_t)(rlimit_av->value.i * 4096),
+ 4096,
+ "4k");
+#else
+ /* STDERR as well would be fine... */
+ msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system.");
+#endif /* RLIMIT_STACK */
+ break;
+
+ case T_Filenum:
+#if defined(RLIMIT_NOFILE)
+ ntp_rlimit(RLIMIT_NOFILE,
+ (rlim_t)(rlimit_av->value.i),
+ 1,
+ "");
+#else
+ /* STDERR as well would be fine... */
+ msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system.");
+#endif /* RLIMIT_NOFILE */
+ break;
+
+ }
+ }
+}
+
+
+static void
+config_tinker(
+ config_tree *ptree
+ )
+{
+ attr_val * tinker;
+ int item;
+
+ item = -1; /* quiet warning */
+ tinker = HEAD_PFIFO(ptree->tinker);
+ for (; tinker != NULL; tinker = tinker->link) {
+ switch (tinker->attr) {
+
+ default:
+ INSIST(0);
+ break;
+
+ case T_Allan:
+ item = LOOP_ALLAN;
+ break;
+
+ case T_Dispersion:
+ item = LOOP_PHI;
+ break;
+
+ case T_Freq:
+ item = LOOP_FREQ;
+ break;
+
+ case T_Huffpuff:
+ item = LOOP_HUFFPUFF;
+ break;
+
+ case T_Panic:
+ item = LOOP_PANIC;
+ break;
+ case T_Step:
+ item = LOOP_MAX;
+ break;
+
+ case T_Stepback:
+ item = LOOP_MAX_BACK;
+ break;
+
+ case T_Stepfwd:
+ item = LOOP_MAX_FWD;
+ break;
+
+ case T_Stepout:
+ item = LOOP_MINSTEP;
+ break;
+
+ case T_Tick:
+ item = LOOP_TICK;
+ break;
+ }
+ loop_config(item, tinker->value.d);
+ }
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_rlimit(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->rlimit);
+}
+
+static void
+free_config_tinker(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->tinker);
+}
+#endif /* FREE_CFG_T */
+
+
+/*
+ * config_nic_rules - apply interface listen/ignore/drop items
+ */
+#ifndef SIM
+static void
+config_nic_rules(
+ config_tree *ptree,
+ int/*BOOL*/ input_from_file
+ )
+{
+ nic_rule_node * curr_node;
+ sockaddr_u addr;
+ nic_rule_match match_type;
+ nic_rule_action action;
+ char * if_name;
+ char * pchSlash;
+ int prefixlen;
+ int addrbits;
+
+ curr_node = HEAD_PFIFO(ptree->nic_rules);
+
+ if (curr_node != NULL
+ && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) {
+ msyslog(LOG_ERR,
+ "interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s",
+ (input_from_file) ? ", exiting" : "");
+ if (input_from_file)
+ exit(1);
+ else
+ return;
+ }
+
+ for (; curr_node != NULL; curr_node = curr_node->link) {
+ prefixlen = -1;
+ if_name = curr_node->if_name;
+ if (if_name != NULL)
+ if_name = estrdup(if_name);
+
+ switch (curr_node->match_class) {
+
+ default:
/*
- * Assume default means an IPv4 address, except
- * if forced by a -4 or -6.
+ * this assignment quiets a gcc "may be used
+ * uninitialized" warning and is here for no
+ * other reason.
*/
- if (STREQ(tokens[istart], "default")) {
- if (peeraddr.ss_family == 0)
- peeraddr.ss_family = AF_INET;
- } else if (getnetnum(tokens[istart], &peeraddr, 1,
- t_UNK) != 1)
- break;
+ match_type = MATCH_ALL;
+ INSIST(FALSE);
+ break;
+ case 0:
/*
- * Use peerversion as flags, peerkey as mflags. Ick.
+ * 0 is out of range for valid token T_...
+ * and in a nic_rules_node indicates the
+ * interface descriptor is either a name or
+ * address, stored in if_name in either case.
*/
- peerversion = 0;
- peerkey = 0;
- errflg = 0;
- SET_HOSTMASK(&maskaddr, peeraddr.ss_family);
- istart++;
- for (i = istart; i < ntokens; i++) {
- switch (matchkey(tokens[i], res_keywords, 1)) {
- case CONF_RES_MASK:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "mask keyword needs argument");
- errflg++;
- break;
- }
- i++;
- if (getnetnum(tokens[i], &maskaddr, 1,
- t_MSK) != 1)
- errflg++;
- break;
+ INSIST(if_name != NULL);
+ pchSlash = strchr(if_name, '/');
+ if (pchSlash != NULL)
+ *pchSlash = '\0';
+ if (is_ip_address(if_name, AF_UNSPEC, &addr)) {
+ match_type = MATCH_IFADDR;
+ if (pchSlash != NULL
+ && 1 == sscanf(pchSlash + 1, "%d",
+ &prefixlen)) {
+ addrbits = 8 *
+ SIZEOF_INADDR(AF(&addr));
+ prefixlen = max(-1, prefixlen);
+ prefixlen = min(prefixlen,
+ addrbits);
+ }
+ } else {
+ match_type = MATCH_IFNAME;
+ if (pchSlash != NULL)
+ *pchSlash = '/';
+ }
+ break;
- case CONF_RES_IGNORE:
- peerversion |= RES_IGNORE;
- break;
+ case T_All:
+ match_type = MATCH_ALL;
+ break;
- case CONF_RES_NOSERVE:
- peerversion |= RES_DONTSERVE;
- break;
+ case T_Ipv4:
+ match_type = MATCH_IPV4;
+ break;
- case CONF_RES_NOTRUST:
- peerversion |= RES_DONTTRUST;
- break;
+ case T_Ipv6:
+ match_type = MATCH_IPV6;
+ break;
- case CONF_RES_NOQUERY:
- peerversion |= RES_NOQUERY;
- break;
+ case T_Wildcard:
+ match_type = MATCH_WILDCARD;
+ break;
+ }
- case CONF_RES_NOMODIFY:
- peerversion |= RES_NOMODIFY;
- break;
+ switch (curr_node->action) {
- case CONF_RES_NOPEER:
- peerversion |= RES_NOPEER;
- break;
+ default:
+ /*
+ * this assignment quiets a gcc "may be used
+ * uninitialized" warning and is here for no
+ * other reason.
+ */
+ action = ACTION_LISTEN;
+ INSIST(FALSE);
+ break;
- case CONF_RES_NOTRAP:
- peerversion |= RES_NOTRAP;
- break;
+ case T_Listen:
+ action = ACTION_LISTEN;
+ break;
- case CONF_RES_LPTRAP:
- peerversion |= RES_LPTRAP;
- break;
+ case T_Ignore:
+ action = ACTION_IGNORE;
+ break;
- case CONF_RES_NTPPORT:
- peerkey |= RESM_NTPONLY;
- break;
+ case T_Drop:
+ action = ACTION_DROP;
+ break;
+ }
- case CONF_RES_VERSION:
- peerversion |= RES_VERSION;
- break;
+ add_nic_rule(match_type, if_name, prefixlen,
+ action);
+ timer_interfacetimeout(current_time + 2);
+ if (if_name != NULL)
+ free(if_name);
+ }
+}
+#endif /* !SIM */
- case CONF_RES_DEMOBILIZE:
- peerversion |= RES_DEMOBILIZE;
- break;
- case CONF_RES_LIMITED:
- peerversion |= RES_LIMITED;
- break;
+#ifdef FREE_CFG_T
+static void
+free_config_nic_rules(
+ config_tree *ptree
+ )
+{
+ nic_rule_node *curr_node;
+
+ if (ptree->nic_rules != NULL) {
+ for (;;) {
+ UNLINK_FIFO(curr_node, *ptree->nic_rules, link);
+ if (NULL == curr_node)
+ break;
+ free(curr_node->if_name);
+ free(curr_node);
+ }
+ free(ptree->nic_rules);
+ ptree->nic_rules = NULL;
+ }
+}
+#endif /* FREE_CFG_T */
+
+
+static void
+apply_enable_disable(
+ attr_val_fifo * fifo,
+ int enable
+ )
+{
+ attr_val *curr_flag;
+ int option;
+#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
+ bc_entry *pentry;
+#endif
+
+ for (curr_flag = HEAD_PFIFO(fifo);
+ curr_flag != NULL;
+ curr_flag = curr_flag->link) {
+
+ option = curr_flag->value.i;
+ switch (option) {
- case CONFIG_UNKNOWN:
- errflg++;
+ default:
+ msyslog(LOG_ERR,
+ "can not apply enable/disable token %d, unknown",
+ option);
+ break;
+
+ case T_Auth:
+ proto_config(PROTO_AUTHENTICATE, enable, 0., NULL);
+ break;
+
+ case T_Bclient:
+ proto_config(PROTO_BROADCLIENT, enable, 0., NULL);
+ break;
+
+ case T_Calibrate:
+ proto_config(PROTO_CAL, enable, 0., NULL);
+ break;
+
+ case T_Kernel:
+ proto_config(PROTO_KERNEL, enable, 0., NULL);
+ break;
+
+ case T_Monitor:
+ proto_config(PROTO_MONITOR, enable, 0., NULL);
+ break;
+
+ case T_Ntp:
+ proto_config(PROTO_NTP, enable, 0., NULL);
+ break;
+
+ case T_Mode7:
+ proto_config(PROTO_MODE7, enable, 0., NULL);
+ break;
+
+ case T_Stats:
+ proto_config(PROTO_FILEGEN, enable, 0., NULL);
+ break;
+
+#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
+ case T_Bc_bugXXXX:
+ pentry = bc_list;
+ while (pentry->token) {
+ if (pentry->token == option)
break;
- }
+ pentry++;
+ }
+ if (!pentry->token) {
+ msyslog(LOG_ERR,
+ "compat token %d not in bc_list[]",
+ option);
+ continue;
}
- if (SOCKNUL(&peeraddr))
- ANYSOCK(&maskaddr);
- if (!errflg)
- hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
- (int)peerkey, peerversion);
+ pentry->enabled = enable;
break;
+#endif
+ }
+ }
+}
- case CONFIG_BDELAY:
- if (ntokens >= 2) {
- double tmp;
- if (sscanf(tokens[1], "%lf", &tmp) != 1) {
- msyslog(LOG_ERR,
- "broadcastdelay value %s undecodable",
- tokens[1]);
- } else {
- proto_config(PROTO_BROADDELAY, 0, tmp, NULL);
- }
- }
+static void
+config_system_opts(
+ config_tree *ptree
+ )
+{
+ apply_enable_disable(ptree->enable_opts, 1);
+ apply_enable_disable(ptree->disable_opts, 0);
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_system_opts(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->enable_opts);
+ FREE_ATTR_VAL_FIFO(ptree->disable_opts);
+}
+#endif /* FREE_CFG_T */
+
+
+static void
+config_logconfig(
+ config_tree *ptree
+ )
+{
+ attr_val * my_lc;
+
+ my_lc = HEAD_PFIFO(ptree->logconfig);
+ for (; my_lc != NULL; my_lc = my_lc->link) {
+ switch (my_lc->attr) {
+
+ case '+':
+ ntp_syslogmask |= get_logmask(my_lc->value.s);
break;
- case CONFIG_CDELAY:
- if (ntokens >= 2) {
- u_long ui;
+ case '-':
+ ntp_syslogmask &= ~get_logmask(my_lc->value.s);
+ break;
- if (sscanf(tokens[1], "%ld", &ui) != 1)
- msyslog(LOG_ERR,
- "illegal value - line ignored");
- else
- proto_config(PROTO_CALLDELAY, ui, 0, NULL);
- }
+ case '=':
+ ntp_syslogmask = get_logmask(my_lc->value.s);
+ break;
+ default:
+ INSIST(0);
break;
+ }
+ }
+}
- case CONFIG_TRUSTEDKEY:
- for (i = 1; i < ntokens; i++) {
- keyid_t tkey;
- tkey = atol(tokens[i]);
- if (tkey == 0) {
+#ifdef FREE_CFG_T
+static void
+free_config_logconfig(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->logconfig);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_phone(
+ config_tree *ptree
+ )
+{
+ size_t i;
+ string_node * sn;
+
+ i = 0;
+ sn = HEAD_PFIFO(ptree->phone);
+ for (; sn != NULL; sn = sn->link) {
+ /* need to leave array entry for NULL terminator */
+ if (i < COUNTOF(sys_phone) - 1) {
+ sys_phone[i++] = estrdup(sn->s);
+ sys_phone[i] = NULL;
+ } else {
+ msyslog(LOG_INFO,
+ "phone: Number of phone entries exceeds %zu. Ignoring phone %s...",
+ (COUNTOF(sys_phone) - 1), sn->s);
+ }
+ }
+}
+#endif /* !SIM */
+
+static void
+config_mdnstries(
+ config_tree *ptree
+ )
+{
+#ifdef HAVE_DNSREGISTRATION
+ extern int mdnstries;
+ mdnstries = ptree->mdnstries;
+#endif /* HAVE_DNSREGISTRATION */
+}
+
+#ifdef FREE_CFG_T
+static void
+free_config_phone(
+ config_tree *ptree
+ )
+{
+ FREE_STRING_FIFO(ptree->phone);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_setvar(
+ config_tree *ptree
+ )
+{
+ setvar_node *my_node;
+ size_t varlen, vallen, octets;
+ char * str;
+
+ str = NULL;
+ my_node = HEAD_PFIFO(ptree->setvar);
+ for (; my_node != NULL; my_node = my_node->link) {
+ varlen = strlen(my_node->var);
+ vallen = strlen(my_node->val);
+ octets = varlen + vallen + 1 + 1;
+ str = erealloc(str, octets);
+ snprintf(str, octets, "%s=%s", my_node->var,
+ my_node->val);
+ set_sys_var(str, octets, (my_node->isdefault)
+ ? DEF
+ : 0);
+ }
+ if (str != NULL)
+ free(str);
+}
+#endif /* !SIM */
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_setvar(
+ config_tree *ptree
+ )
+{
+ FREE_SETVAR_FIFO(ptree->setvar);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_ttl(
+ config_tree *ptree
+ )
+{
+ size_t i = 0;
+ int_node *curr_ttl;
+
+ curr_ttl = HEAD_PFIFO(ptree->ttl);
+ for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
+ if (i < COUNTOF(sys_ttl))
+ sys_ttl[i++] = (u_char)curr_ttl->i;
+ else
+ msyslog(LOG_INFO,
+ "ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
+ COUNTOF(sys_ttl), curr_ttl->i);
+ }
+ sys_ttlmax = i - 1;
+}
+#endif /* !SIM */
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_ttl(
+ config_tree *ptree
+ )
+{
+ FREE_INT_FIFO(ptree->ttl);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_trap(
+ config_tree *ptree
+ )
+{
+ addr_opts_node *curr_trap;
+ attr_val *curr_opt;
+ sockaddr_u addr_sock;
+ sockaddr_u peeraddr;
+ struct interface *localaddr;
+ struct addrinfo hints;
+ char port_text[8];
+ settrap_parms *pstp;
+ u_short port;
+ int err_flag;
+ int rc;
+
+ /* silence warning about addr_sock potentially uninitialized */
+ AF(&addr_sock) = AF_UNSPEC;
+
+ curr_trap = HEAD_PFIFO(ptree->trap);
+ for (; curr_trap != NULL; curr_trap = curr_trap->link) {
+ err_flag = 0;
+ port = 0;
+ localaddr = NULL;
+
+ curr_opt = HEAD_PFIFO(curr_trap->options);
+ for (; curr_opt != NULL; curr_opt = curr_opt->link) {
+ if (T_Port == curr_opt->attr) {
+ if (curr_opt->value.i < 1
+ || curr_opt->value.i > USHRT_MAX) {
msyslog(LOG_ERR,
- "trusted key %s unlikely",
- tokens[i]);
- } else {
- authtrust(tkey, 1);
+ "invalid port number "
+ "%d, trap ignored",
+ curr_opt->value.i);
+ err_flag = 1;
}
+ port = (u_short)curr_opt->value.i;
}
- break;
+ else if (T_Interface == curr_opt->attr) {
+ /* Resolve the interface address */
+ ZERO_SOCK(&addr_sock);
+ if (getnetnum(curr_opt->value.s,
+ &addr_sock, 1, t_UNK) != 1) {
+ err_flag = 1;
+ break;
+ }
- case CONFIG_REQUESTKEY:
- if (ntokens >= 2) {
- if (!atouint(tokens[1], &ul)) {
- msyslog(LOG_ERR,
- "%s is undecodable as request key",
- tokens[1]);
- } else if (ul == 0) {
+ localaddr = findinterface(&addr_sock);
+
+ if (NULL == localaddr) {
msyslog(LOG_ERR,
- "%s makes a poor request keyid",
- tokens[1]);
- } else {
-#ifdef DEBUG
- if (debug > 3)
- printf(
- "set info_auth_key to %08lx\n", ul);
-#endif
- info_auth_keyid = (keyid_t)ul;
+ "can't find interface with address %s",
+ stoa(&addr_sock));
+ err_flag = 1;
}
}
- break;
-
- case CONFIG_CONTROLKEY:
- if (ntokens >= 2) {
- keyid_t ckey;
+ }
- ckey = atol(tokens[1]);
- if (ckey == 0) {
- msyslog(LOG_ERR,
- "%s makes a poor control keyid",
- tokens[1]);
- } else {
- ctl_auth_keyid = ckey;
+ /* Now process the trap for the specified interface
+ * and port number
+ */
+ if (!err_flag) {
+ if (!port)
+ port = TRAPPORT;
+ ZERO_SOCK(&peeraddr);
+ rc = getnetnum(curr_trap->addr->address,
+ &peeraddr, 1, t_UNK);
+ if (1 != rc) {
+#ifndef WORKER
+ msyslog(LOG_ERR,
+ "trap: unable to use IP address %s.",
+ curr_trap->addr->address);
+#else /* WORKER follows */
+ /*
+ * save context and hand it off
+ * for name resolution.
+ */
+ ZERO(hints);
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_socktype = SOCK_DGRAM;
+ snprintf(port_text, sizeof(port_text),
+ "%u", port);
+ hints.ai_flags = Z_AI_NUMERICSERV;
+ pstp = emalloc_zero(sizeof(*pstp));
+ if (localaddr != NULL) {
+ hints.ai_family = localaddr->family;
+ pstp->ifaddr_nonnull = 1;
+ memcpy(&pstp->ifaddr,
+ &localaddr->sin,
+ sizeof(pstp->ifaddr));
}
+ rc = getaddrinfo_sometime(
+ curr_trap->addr->address,
+ port_text, &hints,
+ INITIAL_DNS_RETRY,
+ &trap_name_resolved,
+ pstp);
+ if (!rc)
+ msyslog(LOG_ERR,
+ "config_trap: getaddrinfo_sometime(%s,%s): %m",
+ curr_trap->addr->address,
+ port_text);
+#endif /* WORKER */
+ continue;
}
- break;
+ /* port is at same location for v4 and v6 */
+ SET_PORT(&peeraddr, port);
- case CONFIG_TRAP:
- if (ntokens < 2) {
+ if (NULL == localaddr)
+ localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
+ else
+ AF(&peeraddr) = AF(&addr_sock);
+
+ if (!ctlsettrap(&peeraddr, localaddr, 0,
+ NTP_VERSION))
msyslog(LOG_ERR,
- "no address for trap command, line ignored");
+ "set trap %s -> %s failed.",
+ latoa(localaddr),
+ stoa(&peeraddr));
+ }
+ }
+}
+
+
+/*
+ * trap_name_resolved()
+ *
+ * Callback invoked when config_trap()'s DNS lookup completes.
+ */
+# ifdef WORKER
+static void
+trap_name_resolved(
+ int rescode,
+ int gai_errno,
+ void * context,
+ const char * name,
+ const char * service,
+ const struct addrinfo * hints,
+ const struct addrinfo * res
+ )
+{
+ settrap_parms *pstp;
+ struct interface *localaddr;
+ sockaddr_u peeraddr;
+
+ (void)gai_errno;
+ (void)service;
+ (void)hints;
+ pstp = context;
+ if (rescode) {
+ msyslog(LOG_ERR,
+ "giving up resolving trap host %s: %s (%d)",
+ name, gai_strerror(rescode), rescode);
+ free(pstp);
+ return;
+ }
+ INSIST(sizeof(peeraddr) >= res->ai_addrlen);
+ ZERO(peeraddr);
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ localaddr = NULL;
+ if (pstp->ifaddr_nonnull)
+ localaddr = findinterface(&pstp->ifaddr);
+ if (NULL == localaddr)
+ localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
+ if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION))
+ msyslog(LOG_ERR, "set trap %s -> %s failed.",
+ latoa(localaddr), stoa(&peeraddr));
+ free(pstp);
+}
+# endif /* WORKER */
+#endif /* !SIM */
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_trap(
+ config_tree *ptree
+ )
+{
+ FREE_ADDR_OPTS_FIFO(ptree->trap);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_fudge(
+ config_tree *ptree
+ )
+{
+ addr_opts_node *curr_fudge;
+ attr_val *curr_opt;
+ sockaddr_u addr_sock;
+ address_node *addr_node;
+ struct refclockstat clock_stat;
+ int err_flag;
+
+ curr_fudge = HEAD_PFIFO(ptree->fudge);
+ for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) {
+ err_flag = 0;
+
+ /* Get the reference clock address and
+ * ensure that it is sane
+ */
+ addr_node = curr_fudge->addr;
+ ZERO_SOCK(&addr_sock);
+ if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
+ != 1) {
+ err_flag = 1;
+ msyslog(LOG_ERR,
+ "unrecognized fudge reference clock address %s, line ignored",
+ stoa(&addr_sock));
+ }
+
+ if (!ISREFCLOCKADR(&addr_sock)) {
+ err_flag = 1;
+ msyslog(LOG_ERR,
+ "inappropriate address %s for the fudge command, line ignored",
+ stoa(&addr_sock));
+ }
+
+ /* Parse all the options to the fudge command */
+ ZERO(clock_stat);
+ curr_opt = HEAD_PFIFO(curr_fudge->options);
+ for (; curr_opt != NULL; curr_opt = curr_opt->link) {
+ switch (curr_opt->attr) {
+
+ case T_Time1:
+ clock_stat.haveflags |= CLK_HAVETIME1;
+ clock_stat.fudgetime1 = curr_opt->value.d;
break;
- }
- istart = 1;
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- peeraddr.ss_family = default_ai_family;
- switch (matchkey(tokens[istart], addr_type, 0)) {
- case CONF_ADDR_IPV4:
- peeraddr.ss_family = AF_INET;
- istart++;
+
+ case T_Time2:
+ clock_stat.haveflags |= CLK_HAVETIME2;
+ clock_stat.fudgetime2 = curr_opt->value.d;
break;
- case CONF_ADDR_IPV6:
- peeraddr.ss_family = AF_INET6;
- istart++;
+
+ case T_Stratum:
+ clock_stat.haveflags |= CLK_HAVEVAL1;
+ clock_stat.fudgeval1 = curr_opt->value.i;
break;
- }
- if (getnetnum(tokens[istart], &peeraddr, 1, t_UNK) != 1)
- break;
+ case T_Refid:
+ clock_stat.haveflags |= CLK_HAVEVAL2;
+ clock_stat.fudgeval2 = 0;
+ memcpy(&clock_stat.fudgeval2,
+ curr_opt->value.s,
+ min(strlen(curr_opt->value.s), 4));
+ break;
- /*
- * Use peerversion for port number. Barf.
- */
- errflg = 0;
- peerversion = 0;
- localaddr = 0;
- istart++;
- for (i = istart; i < ntokens-1; i++)
- switch (matchkey(tokens[i], trap_keywords, 1)) {
- case CONF_TRAP_PORT:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "trap port requires an argument");
- errflg = 1;
- break;
- }
- peerversion = atoi(tokens[++i]);
- if (peerversion <= 0
- || peerversion > 32767) {
- msyslog(LOG_ERR,
- "invalid port number %s, trap ignored",
- tokens[i]);
- errflg = 1;
- }
- break;
-
- case CONF_TRAP_INTERFACE:
- if (i >= ntokens-1) {
- msyslog(LOG_ERR,
- "trap interface requires an argument");
- errflg = 1;
- break;
- }
-
- memset((char *)&maskaddr, 0,
- sizeof(maskaddr));
- maskaddr.ss_family = peeraddr.ss_family;
- if (getnetnum(tokens[++i],
- &maskaddr, 1, t_UNK) != 1) {
- errflg = 1;
- break;
- }
-
- localaddr = findinterface(&maskaddr);
- if (localaddr == NULL) {
- msyslog(LOG_ERR,
- "can't find interface with address %s",
- stoa(&maskaddr));
- errflg = 1;
- }
- break;
-
- case CONFIG_UNKNOWN:
- errflg++;
- break;
- }
-
- if (!errflg) {
- if (peerversion != 0)
- ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion);
+ case T_Flag1:
+ clock_stat.haveflags |= CLK_HAVEFLAG1;
+ if (curr_opt->value.i)
+ clock_stat.flags |= CLK_FLAG1;
else
- ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT);
- if (localaddr == NULL)
- localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
- if (!ctlsettrap(&peeraddr, localaddr, 0,
- NTP_VERSION))
- msyslog(LOG_ERR,
- "can't set trap for %s, no resources",
- stoa(&peeraddr));
- }
- break;
+ clock_stat.flags &= ~CLK_FLAG1;
+ break;
- case CONFIG_FUDGE:
- if (ntokens < 2) {
- msyslog(LOG_ERR,
- "no address for fudge command, line ignored");
+ case T_Flag2:
+ clock_stat.haveflags |= CLK_HAVEFLAG2;
+ if (curr_opt->value.i)
+ clock_stat.flags |= CLK_FLAG2;
+ else
+ clock_stat.flags &= ~CLK_FLAG2;
break;
- }
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- if (getnetnum(tokens[1], &peeraddr, 1, t_REF) != 1)
- break;
- if (!ISREFCLOCKADR(&peeraddr)) {
- msyslog(LOG_ERR,
- "%s is inappropriate address for the fudge command, line ignored",
- stoa(&peeraddr));
+ case T_Flag3:
+ clock_stat.haveflags |= CLK_HAVEFLAG3;
+ if (curr_opt->value.i)
+ clock_stat.flags |= CLK_FLAG3;
+ else
+ clock_stat.flags &= ~CLK_FLAG3;
break;
+
+ case T_Flag4:
+ clock_stat.haveflags |= CLK_HAVEFLAG4;
+ if (curr_opt->value.i)
+ clock_stat.flags |= CLK_FLAG4;
+ else
+ clock_stat.flags &= ~CLK_FLAG4;
+ break;
+
+ default:
+ msyslog(LOG_ERR,
+ "Unexpected fudge flag %s (%d) for %s",
+ token_name(curr_opt->attr),
+ curr_opt->attr, stoa(&addr_sock));
+ exit(curr_opt->attr ? curr_opt->attr : 1);
}
+ }
+# ifdef REFCLOCK
+ if (!err_flag)
+ refclock_control(&addr_sock, &clock_stat, NULL);
+# endif
+ }
+}
+#endif /* !SIM */
- memset((void *)&clock_stat, 0, sizeof clock_stat);
- fudgeflag = 0;
- errflg = 0;
- for (i = 2; i < ntokens-1; i++) {
- switch (c = matchkey(tokens[i],
- fudge_keywords, 1)) {
- case CONF_FDG_TIME1:
- if (sscanf(tokens[++i], "%lf",
- &clock_stat.fudgetime1) != 1) {
- msyslog(LOG_ERR,
- "fudge %s time1 value in error",
- stoa(&peeraddr));
- errflg = i;
- break;
- }
- clock_stat.haveflags |= CLK_HAVETIME1;
- break;
- case CONF_FDG_TIME2:
- if (sscanf(tokens[++i], "%lf",
- &clock_stat.fudgetime2) != 1) {
- msyslog(LOG_ERR,
- "fudge %s time2 value in error",
- stoa(&peeraddr));
- errflg = i;
- break;
- }
- clock_stat.haveflags |= CLK_HAVETIME2;
- break;
+#ifdef FREE_CFG_T
+static void
+free_config_fudge(
+ config_tree *ptree
+ )
+{
+ FREE_ADDR_OPTS_FIFO(ptree->fudge);
+}
+#endif /* FREE_CFG_T */
- case CONF_FDG_STRATUM:
- if (!atoint(tokens[++i], &stratum))
- {
- msyslog(LOG_ERR,
- "fudge %s stratum value in error",
- stoa(&peeraddr));
- errflg = i;
- break;
- }
- clock_stat.fudgeval1 = stratum;
- clock_stat.haveflags |= CLK_HAVEVAL1;
- break;
+static void
+config_vars(
+ config_tree *ptree
+ )
+{
+ attr_val *curr_var;
+ int len;
- case CONF_FDG_REFID:
- i++;
- memcpy(&clock_stat.fudgeval2,
- tokens[i], min(strlen(tokens[i]),
- 4));
- clock_stat.haveflags |= CLK_HAVEVAL2;
- break;
+ curr_var = HEAD_PFIFO(ptree->vars);
+ for (; curr_var != NULL; curr_var = curr_var->link) {
+ /* Determine which variable to set and set it */
+ switch (curr_var->attr) {
- case CONF_FDG_FLAG1:
- case CONF_FDG_FLAG2:
- case CONF_FDG_FLAG3:
- case CONF_FDG_FLAG4:
- if (!atouint(tokens[++i], &fudgeflag)
- || fudgeflag > 1) {
- msyslog(LOG_ERR,
- "fudge %s flag value in error",
- stoa(&peeraddr));
- errflg = i;
- break;
- }
- switch(c) {
- case CONF_FDG_FLAG1:
- c = CLK_FLAG1;
- clock_stat.haveflags|=CLK_HAVEFLAG1;
- break;
- case CONF_FDG_FLAG2:
- c = CLK_FLAG2;
- clock_stat.haveflags|=CLK_HAVEFLAG2;
- break;
- case CONF_FDG_FLAG3:
- c = CLK_FLAG3;
- clock_stat.haveflags|=CLK_HAVEFLAG3;
- break;
- case CONF_FDG_FLAG4:
- c = CLK_FLAG4;
- clock_stat.haveflags|=CLK_HAVEFLAG4;
- break;
- }
- if (fudgeflag == 0)
- clock_stat.flags &= ~c;
- else
- clock_stat.flags |= c;
- break;
+ case T_Broadcastdelay:
+ proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
+ break;
- case CONFIG_UNKNOWN:
- errflg = -1;
- break;
- }
- }
+ case T_Tick:
+ loop_config(LOOP_TICK, curr_var->value.d);
+ break;
-#ifdef REFCLOCK
- /*
- * If reference clock support isn't defined the
- * fudge line will still be accepted and syntax
- * checked, but will essentially do nothing.
- */
- if (!errflg) {
- refclock_control(&peeraddr, &clock_stat,
- (struct refclockstat *)0);
+ case T_Driftfile:
+ if ('\0' == curr_var->value.s[0]) {
+ stats_drift_file = 0;
+ msyslog(LOG_INFO, "config: driftfile disabled");
+ } else
+ stats_config(STATS_FREQ_FILE, curr_var->value.s);
+ break;
+
+ case T_Dscp:
+ /* DSCP is in the upper 6 bits of the IP TOS/DS field */
+ qos = curr_var->value.i << 2;
+ break;
+
+ case T_Ident:
+ sys_ident = curr_var->value.s;
+ break;
+
+ case T_WanderThreshold: /* FALLTHROUGH */
+ case T_Nonvolatile:
+ wander_threshold = curr_var->value.d;
+ break;
+
+ case T_Leapfile:
+ stats_config(STATS_LEAP_FILE, curr_var->value.s);
+ break;
+
+#ifdef LEAP_SMEAR
+ case T_Leapsmearinterval:
+ leap_smear_intv = curr_var->value.i;
+ msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
+ break;
+#endif
+
+ case T_Pidfile:
+ stats_config(STATS_PID_FILE, curr_var->value.s);
+ break;
+
+ case T_Logfile:
+ if (-1 == change_logfile(curr_var->value.s, TRUE))
+ msyslog(LOG_ERR,
+ "Cannot open logfile %s: %m",
+ curr_var->value.s);
+ break;
+
+ case T_Saveconfigdir:
+ if (saveconfigdir != NULL)
+ free(saveconfigdir);
+ len = strlen(curr_var->value.s);
+ if (0 == len) {
+ saveconfigdir = NULL;
+ } else if (DIR_SEP != curr_var->value.s[len - 1]
+#ifdef SYS_WINNT /* slash is also a dir. sep. on Windows */
+ && '/' != curr_var->value.s[len - 1]
+#endif
+ ) {
+ len++;
+ saveconfigdir = emalloc(len + 1);
+ snprintf(saveconfigdir, len + 1,
+ "%s%c",
+ curr_var->value.s,
+ DIR_SEP);
+ } else {
+ saveconfigdir = estrdup(
+ curr_var->value.s);
}
+ break;
+
+ case T_Automax:
+#ifdef AUTOKEY
+ sys_automax = curr_var->value.i;
#endif
break;
- case CONFIG_STATSDIR:
- if (ntokens >= 2)
- stats_config(STATS_STATSDIR,tokens[1]);
+ default:
+ msyslog(LOG_ERR,
+ "config_vars(): unexpected token %d",
+ curr_var->attr);
+ }
+ }
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_vars(
+ config_tree *ptree
+ )
+{
+ FREE_ATTR_VAL_FIFO(ptree->vars);
+}
+#endif /* FREE_CFG_T */
+
+
+/* Define a function to check if a resolved address is sane.
+ * If yes, return 1, else return 0;
+ */
+static int
+is_sane_resolved_address(
+ sockaddr_u * peeraddr,
+ int hmode
+ )
+{
+ if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) {
+ msyslog(LOG_ERR,
+ "attempt to configure invalid address %s",
+ stoa(peeraddr));
+ return 0;
+ }
+ /*
+ * Shouldn't be able to specify multicast
+ * address for server/peer!
+ * and unicast address for manycastclient!
+ */
+ if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode)
+ && IS_MCAST(peeraddr)) {
+ msyslog(LOG_ERR,
+ "attempt to configure invalid address %s",
+ stoa(peeraddr));
+ return 0;
+ }
+ if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) {
+ msyslog(LOG_ERR,
+ "attempt to configure invalid address %s",
+ stoa(peeraddr));
+ return 0;
+ }
+
+ if (IS_IPV6(peeraddr) && !ipv6_works)
+ return 0;
+
+ /* Ok, all tests succeeded, now we can return 1 */
+ return 1;
+}
+
+
+#ifndef SIM
+static u_char
+get_correct_host_mode(
+ int token
+ )
+{
+ switch (token) {
+
+ case T_Server:
+ case T_Pool:
+ case T_Manycastclient:
+ return MODE_CLIENT;
+
+ case T_Peer:
+ return MODE_ACTIVE;
+
+ case T_Broadcast:
+ return MODE_BROADCAST;
+
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ * peerflag_bits() get config_peers() peerflags value from a
+ * peer_node's queue of flag attr_val entries.
+ */
+static int
+peerflag_bits(
+ peer_node *pn
+ )
+{
+ int peerflags;
+ attr_val *option;
+
+ /* translate peerflags options to bits */
+ peerflags = 0;
+ option = HEAD_PFIFO(pn->peerflags);
+ for (; option != NULL; option = option->link) {
+ switch (option->value.i) {
+
+ default:
+ INSIST(0);
break;
- case CONFIG_STATISTICS:
- for (i = 1; i < ntokens; i++) {
- filegen = filegen_get(tokens[i]);
+ case T_Autokey:
+ peerflags |= FLAG_SKEY;
+ break;
- if (filegen == NULL) {
- msyslog(LOG_ERR,
- "no statistics named %s available",
- tokens[i]);
- continue;
- }
-#ifdef DEBUG
- if (debug > 3)
- printf("enabling filegen for %s statistics \"%s%s\"\n",
- tokens[i], filegen->prefix, filegen->basename);
+ case T_Burst:
+ peerflags |= FLAG_BURST;
+ break;
+
+ case T_Iburst:
+ peerflags |= FLAG_IBURST;
+ break;
+
+ case T_Noselect:
+ peerflags |= FLAG_NOSELECT;
+ break;
+
+ case T_Preempt:
+ peerflags |= FLAG_PREEMPT;
+ break;
+
+ case T_Prefer:
+ peerflags |= FLAG_PREFER;
+ break;
+
+ case T_True:
+ peerflags |= FLAG_TRUE;
+ break;
+
+ case T_Xleave:
+ peerflags |= FLAG_XLEAVE;
+ break;
+ }
+ }
+
+ return peerflags;
+}
+
+
+static void
+config_peers(
+ config_tree *ptree
+ )
+{
+ sockaddr_u peeraddr;
+ struct addrinfo hints;
+ peer_node * curr_peer;
+ peer_resolved_ctx * ctx;
+ u_char hmode;
+
+ /* add servers named on the command line with iburst implied */
+ for (;
+ cmdline_server_count > 0;
+ cmdline_server_count--, cmdline_servers++) {
+
+ ZERO_SOCK(&peeraddr);
+ /*
+ * If we have a numeric address, we can safely
+ * proceed in the mainline with it. Otherwise, hand
+ * the hostname off to the blocking child.
+ */
+ if (is_ip_address(*cmdline_servers, AF_UNSPEC,
+ &peeraddr)) {
+
+ SET_PORT(&peeraddr, NTP_PORT);
+ if (is_sane_resolved_address(&peeraddr,
+ T_Server))
+ peer_config(
+ &peeraddr,
+ NULL,
+ NULL,
+ MODE_CLIENT,
+ NTP_VERSION,
+ 0,
+ 0,
+ FLAG_IBURST,
+ 0,
+ 0,
+ NULL);
+ } else {
+ /* we have a hostname to resolve */
+# ifdef WORKER
+ ctx = emalloc_zero(sizeof(*ctx));
+ ctx->family = AF_UNSPEC;
+ ctx->host_mode = T_Server;
+ ctx->hmode = MODE_CLIENT;
+ ctx->version = NTP_VERSION;
+ ctx->flags = FLAG_IBURST;
+
+ ZERO(hints);
+ hints.ai_family = (u_short)ctx->family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ getaddrinfo_sometime(*cmdline_servers,
+ "ntp", &hints,
+ INITIAL_DNS_RETRY,
+ &peer_name_resolved,
+ (void *)ctx);
+# else /* !WORKER follows */
+ msyslog(LOG_ERR,
+ "hostname %s can not be used, please use IP address instead.",
+ curr_peer->addr->address);
+# endif
+ }
+ }
+
+ /* add associations from the configuration file */
+ curr_peer = HEAD_PFIFO(ptree->peers);
+ for (; curr_peer != NULL; curr_peer = curr_peer->link) {
+ ZERO_SOCK(&peeraddr);
+ /* Find the correct host-mode */
+ hmode = get_correct_host_mode(curr_peer->host_mode);
+ INSIST(hmode != 0);
+
+ if (T_Pool == curr_peer->host_mode) {
+ AF(&peeraddr) = curr_peer->addr->type;
+ peer_config(
+ &peeraddr,
+ curr_peer->addr->address,
+ NULL,
+ hmode,
+ curr_peer->peerversion,
+ curr_peer->minpoll,
+ curr_peer->maxpoll,
+ peerflag_bits(curr_peer),
+ curr_peer->ttl,
+ curr_peer->peerkey,
+ curr_peer->group);
+ /*
+ * If we have a numeric address, we can safely
+ * proceed in the mainline with it. Otherwise, hand
+ * the hostname off to the blocking child.
+ */
+ } else if (is_ip_address(curr_peer->addr->address,
+ curr_peer->addr->type, &peeraddr)) {
+
+ SET_PORT(&peeraddr, NTP_PORT);
+ if (is_sane_resolved_address(&peeraddr,
+ curr_peer->host_mode))
+ peer_config(
+ &peeraddr,
+ NULL,
+ NULL,
+ hmode,
+ curr_peer->peerversion,
+ curr_peer->minpoll,
+ curr_peer->maxpoll,
+ peerflag_bits(curr_peer),
+ curr_peer->ttl,
+ curr_peer->peerkey,
+ curr_peer->group);
+ } else {
+ /* we have a hostname to resolve */
+# ifdef WORKER
+ ctx = emalloc_zero(sizeof(*ctx));
+ ctx->family = curr_peer->addr->type;
+ ctx->host_mode = curr_peer->host_mode;
+ ctx->hmode = hmode;
+ ctx->version = curr_peer->peerversion;
+ ctx->minpoll = curr_peer->minpoll;
+ ctx->maxpoll = curr_peer->maxpoll;
+ ctx->flags = peerflag_bits(curr_peer);
+ ctx->ttl = curr_peer->ttl;
+ ctx->keyid = curr_peer->peerkey;
+ ctx->group = curr_peer->group;
+
+ ZERO(hints);
+ hints.ai_family = ctx->family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ getaddrinfo_sometime(curr_peer->addr->address,
+ "ntp", &hints,
+ INITIAL_DNS_RETRY,
+ &peer_name_resolved, ctx);
+# else /* !WORKER follows */
+ msyslog(LOG_ERR,
+ "hostname %s can not be used, please use IP address instead.",
+ curr_peer->addr->address);
+# endif
+ }
+ }
+}
+#endif /* !SIM */
+
+/*
+ * peer_name_resolved()
+ *
+ * Callback invoked when config_peers()'s DNS lookup completes.
+ */
+#ifdef WORKER
+static void
+peer_name_resolved(
+ int rescode,
+ int gai_errno,
+ void * context,
+ const char * name,
+ const char * service,
+ const struct addrinfo * hints,
+ const struct addrinfo * res
+ )
+{
+ sockaddr_u peeraddr;
+ peer_resolved_ctx * ctx;
+ u_short af;
+ const char * fam_spec;
+
+ (void)gai_errno;
+ (void)service;
+ (void)hints;
+ ctx = context;
+
+ DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
+
+ if (rescode) {
+#ifndef IGNORE_DNS_ERRORS
+ free(ctx);
+ msyslog(LOG_ERR,
+ "giving up resolving host %s: %s (%d)",
+ name, gai_strerror(rescode), rescode);
+#else /* IGNORE_DNS_ERRORS follows */
+ getaddrinfo_sometime(name, service, hints,
+ INITIAL_DNS_RETRY,
+ &peer_name_resolved, context);
#endif
- filegen->flag |= FGEN_FLAG_ENABLED;
+ return;
+ }
+
+ /* Loop to configure a single association */
+ for (; res != NULL; res = res->ai_next) {
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ if (is_sane_resolved_address(&peeraddr,
+ ctx->host_mode)) {
+ NLOG(NLOG_SYSINFO) {
+ af = ctx->family;
+ fam_spec = (AF_INET6 == af)
+ ? "(AAAA) "
+ : (AF_INET == af)
+ ? "(A) "
+ : "";
+ msyslog(LOG_INFO, "DNS %s %s-> %s",
+ name, fam_spec,
+ stoa(&peeraddr));
}
+ peer_config(
+ &peeraddr,
+ NULL,
+ NULL,
+ ctx->hmode,
+ ctx->version,
+ ctx->minpoll,
+ ctx->maxpoll,
+ ctx->flags,
+ ctx->ttl,
+ ctx->keyid,
+ ctx->group);
break;
+ }
+ }
+ free(ctx);
+}
+#endif /* WORKER */
- case CONFIG_FILEGEN:
- if (ntokens < 2) {
- msyslog(LOG_ERR,
- "no id for filegen command, line ignored");
+
+#ifdef FREE_CFG_T
+static void
+free_config_peers(
+ config_tree *ptree
+ )
+{
+ peer_node *curr_peer;
+
+ if (ptree->peers != NULL) {
+ for (;;) {
+ UNLINK_FIFO(curr_peer, *ptree->peers, link);
+ if (NULL == curr_peer)
break;
+ destroy_address_node(curr_peer->addr);
+ destroy_attr_val_fifo(curr_peer->peerflags);
+ free(curr_peer);
+ }
+ free(ptree->peers);
+ ptree->peers = NULL;
+ }
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_unpeers(
+ config_tree *ptree
+ )
+{
+ sockaddr_u peeraddr;
+ struct addrinfo hints;
+ unpeer_node * curr_unpeer;
+ struct peer * p;
+ const char * name;
+ int rc;
+
+ curr_unpeer = HEAD_PFIFO(ptree->unpeers);
+ for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) {
+ /*
+ * Either AssocID will be zero, and we unpeer by name/
+ * address addr, or it is nonzero and addr NULL.
+ */
+ if (curr_unpeer->assocID) {
+ p = findpeerbyassoc(curr_unpeer->assocID);
+ if (p != NULL) {
+ msyslog(LOG_NOTICE, "unpeered %s",
+ stoa(&p->srcadr));
+ peer_clear(p, "GONE");
+ unpeer(p);
}
- filegen = filegen_get(tokens[1]);
- if (filegen == NULL) {
- msyslog(LOG_ERR,
- "unknown filegen \"%s\" ignored",
- tokens[1]);
- break;
+ continue;
+ }
+
+ ZERO(peeraddr);
+ AF(&peeraddr) = curr_unpeer->addr->type;
+ name = curr_unpeer->addr->address;
+ rc = getnetnum(name, &peeraddr, 0, t_UNK);
+ /* Do we have a numeric address? */
+ if (rc > 0) {
+ DPRINTF(1, ("unpeer: searching for %s\n",
+ stoa(&peeraddr)));
+ p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
+ if (p != NULL) {
+ msyslog(LOG_NOTICE, "unpeered %s",
+ stoa(&peeraddr));
+ peer_clear(p, "GONE");
+ unpeer(p);
}
- /*
- * peerversion is (ab)used for filegen file (index)
- * peerkey is (ab)used for filegen type
- * peerflags is (ab)used for filegen flags
- */
- peerversion = 0;
- peerkey = filegen->type;
- peerflags = filegen->flag;
- errflg = 0;
-
- for (i = 2; i < ntokens; i++) {
- switch (matchkey(tokens[i],
- filegen_keywords, 1)) {
- case CONF_FGEN_FILE:
- if (i >= ntokens - 1) {
- msyslog(LOG_ERR,
- "filegen %s file requires argument",
- tokens[1]);
- errflg = i;
- break;
- }
- peerversion = ++i;
- break;
- case CONF_FGEN_TYPE:
- if (i >= ntokens -1) {
- msyslog(LOG_ERR,
- "filegen %s type requires argument",
- tokens[1]);
- errflg = i;
- break;
- }
- peerkey = matchkey(tokens[++i],
- fgen_types, 1);
- if (peerkey == CONFIG_UNKNOWN) {
- msyslog(LOG_ERR,
- "filegen %s unknown type \"%s\"",
- tokens[1], tokens[i]);
- errflg = i;
- break;
- }
- break;
- case CONF_FGEN_FLAG_LINK:
- peerflags |= FGEN_FLAG_LINK;
+ continue;
+ }
+ /*
+ * It's not a numeric IP address, it's a hostname.
+ * Check for associations with a matching hostname.
+ */
+ for (p = peer_list; p != NULL; p = p->p_link)
+ if (p->hostname != NULL)
+ if (!strcasecmp(p->hostname, name))
break;
+ if (p != NULL) {
+ msyslog(LOG_NOTICE, "unpeered %s", name);
+ peer_clear(p, "GONE");
+ unpeer(p);
+ }
+ /* Resolve the hostname to address(es). */
+# ifdef WORKER
+ ZERO(hints);
+ hints.ai_family = curr_unpeer->addr->type;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ getaddrinfo_sometime(name, "ntp", &hints,
+ INITIAL_DNS_RETRY,
+ &unpeer_name_resolved, NULL);
+# else /* !WORKER follows */
+ msyslog(LOG_ERR,
+ "hostname %s can not be used, please use IP address instead.",
+ name);
+# endif
+ }
+}
+#endif /* !SIM */
- case CONF_FGEN_FLAG_NOLINK:
- peerflags &= ~FGEN_FLAG_LINK;
- break;
- case CONF_FGEN_FLAG_ENABLE:
- peerflags |= FGEN_FLAG_ENABLED;
- break;
+/*
+ * unpeer_name_resolved()
+ *
+ * Callback invoked when config_unpeers()'s DNS lookup completes.
+ */
+#ifdef WORKER
+static void
+unpeer_name_resolved(
+ int rescode,
+ int gai_errno,
+ void * context,
+ const char * name,
+ const char * service,
+ const struct addrinfo * hints,
+ const struct addrinfo * res
+ )
+{
+ sockaddr_u peeraddr;
+ struct peer * peer;
+ u_short af;
+ const char * fam_spec;
+
+ (void)context;
+ (void)hints;
+ DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
+
+ if (rescode) {
+ msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
+ name, gai_strerror(rescode), rescode);
+ return;
+ }
+ /*
+ * Loop through the addresses found
+ */
+ for (; res != NULL; res = res->ai_next) {
+ INSIST(res->ai_addrlen <= sizeof(peeraddr));
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ DPRINTF(1, ("unpeer: searching for peer %s\n",
+ stoa(&peeraddr)));
+ peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
+ if (peer != NULL) {
+ af = AF(&peeraddr);
+ fam_spec = (AF_INET6 == af)
+ ? "(AAAA) "
+ : (AF_INET == af)
+ ? "(A) "
+ : "";
+ msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
+ fam_spec, stoa(&peeraddr));
+ peer_clear(peer, "GONE");
+ unpeer(peer);
+ }
+ }
+}
+#endif /* WORKER */
- case CONF_FGEN_FLAG_DISABLE:
- peerflags &= ~FGEN_FLAG_ENABLED;
- break;
- }
- }
- if (!errflg)
- filegen_config(filegen, tokens[peerversion],
- (u_char)peerkey, (u_char)peerflags);
+
+#ifdef FREE_CFG_T
+static void
+free_config_unpeers(
+ config_tree *ptree
+ )
+{
+ unpeer_node *curr_unpeer;
+
+ if (ptree->unpeers != NULL) {
+ for (;;) {
+ UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link);
+ if (NULL == curr_unpeer)
+ break;
+ destroy_address_node(curr_unpeer->addr);
+ free(curr_unpeer);
+ }
+ free(ptree->unpeers);
+ }
+}
+#endif /* FREE_CFG_T */
+
+
+#ifndef SIM
+static void
+config_reset_counters(
+ config_tree *ptree
+ )
+{
+ int_node *counter_set;
+
+ for (counter_set = HEAD_PFIFO(ptree->reset_counters);
+ counter_set != NULL;
+ counter_set = counter_set->link) {
+ switch (counter_set->i) {
+ default:
+ DPRINTF(1, ("config_reset_counters %s (%d) invalid\n",
+ keyword(counter_set->i), counter_set->i));
break;
- case CONFIG_SETVAR:
- if (ntokens < 2) {
- msyslog(LOG_ERR,
- "no value for setvar command - line ignored");
- } else {
- set_sys_var(tokens[1], strlen(tokens[1])+1,
- (u_short) (RW |
- ((((ntokens > 2)
- && !strcmp(tokens[2],
- "default")))
- ? DEF
- : 0)));
- }
+ case T_Allpeers:
+ peer_all_reset();
break;
- case CONFIG_ENABLE:
- for (i = 1; i < ntokens; i++) {
- int flag;
+ case T_Auth:
+ reset_auth_stats();
+ break;
- flag = matchkey(tokens[i], flags_keywords, 1);
- if (flag == CONFIG_UNKNOWN) {
- msyslog(LOG_ERR,
- "enable unknown flag %s",
- tokens[i]);
- errflg = 1;
- break;
- }
- proto_config(flag, 1, 0., NULL);
- }
+ case T_Ctl:
+ ctl_clr_stats();
break;
- case CONFIG_DISABLE:
- for (i = 1; i < ntokens; i++) {
- int flag;
+ case T_Io:
+ io_clr_stats();
+ break;
- flag = matchkey(tokens[i], flags_keywords, 1);
- if (flag == CONFIG_UNKNOWN) {
- msyslog(LOG_ERR,
- "disable unknown flag %s",
- tokens[i]);
- errflg = 1;
- break;
- }
- proto_config(flag, 0, 0., NULL);
- }
+ case T_Mem:
+ peer_clr_stats();
break;
- case CONFIG_PHONE:
- for (i = 1; i < ntokens && i < MAXPHONE - 1; i++) {
- sys_phone[i - 1] =
- emalloc(strlen(tokens[i]) + 1);
- strcpy(sys_phone[i - 1], tokens[i]);
- }
- sys_phone[i] = NULL;
+ case T_Sys:
+ proto_clr_stats();
break;
- case CONFIG_ADJ: {
- double ftemp;
+ case T_Timer:
+ timer_clr_stats();
+ break;
+ }
+ }
+}
+#endif /* !SIM */
- sscanf(tokens[1], "%lf", &ftemp);
- proto_config(PROTO_ADJ, 0, ftemp, NULL);
- }
+
+#ifdef FREE_CFG_T
+static void
+free_config_reset_counters(
+ config_tree *ptree
+ )
+{
+ FREE_INT_FIFO(ptree->reset_counters);
+}
+#endif /* FREE_CFG_T */
+
+
+#ifdef SIM
+static void
+config_sim(
+ config_tree *ptree
+ )
+{
+ int i;
+ server_info *serv_info;
+ attr_val *init_stmt;
+ sim_node *sim_n;
+
+ /* Check if a simulate block was found in the configuration code.
+ * If not, return an error and exit
+ */
+ sim_n = HEAD_PFIFO(ptree->sim_details);
+ if (NULL == sim_n) {
+ fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
+ fprintf(stderr, "\tCheck your configuration file.\n");
+ exit(1);
+ }
+
+ /* Process the initialization statements
+ * -------------------------------------
+ */
+ init_stmt = HEAD_PFIFO(sim_n->init_opts);
+ for (; init_stmt != NULL; init_stmt = init_stmt->link) {
+ switch(init_stmt->attr) {
+
+ case T_Beep_Delay:
+ simulation.beep_delay = init_stmt->value.d;
+ break;
+
+ case T_Sim_Duration:
+ simulation.end_time = init_stmt->value.d;
break;
+ default:
+ fprintf(stderr,
+ "Unknown simulator init token %d\n",
+ init_stmt->attr);
+ exit(1);
+ }
+ }
+
+ /* Process the server list
+ * -----------------------
+ */
+ simulation.num_of_servers = 0;
+ serv_info = HEAD_PFIFO(sim_n->servers);
+ for (; serv_info != NULL; serv_info = serv_info->link)
+ simulation.num_of_servers++;
+ simulation.servers = eallocarray(simulation.num_of_servers,
+ sizeof(simulation.servers[0]));
+
+ i = 0;
+ serv_info = HEAD_PFIFO(sim_n->servers);
+ for (; serv_info != NULL; serv_info = serv_info->link) {
+ if (NULL == serv_info) {
+ fprintf(stderr, "Simulator server list is corrupt\n");
+ exit(1);
+ } else {
+ simulation.servers[i] = *serv_info;
+ simulation.servers[i].link = NULL;
+ i++;
+ }
+ }
+
+ printf("Creating server associations\n");
+ create_server_associations();
+ fprintf(stderr,"\tServer associations successfully created!!\n");
+}
+
+
+#ifdef FREE_CFG_T
+static void
+free_config_sim(
+ config_tree *ptree
+ )
+{
+ sim_node *sim_n;
+ server_info *serv_n;
+ script_info *script_n;
+
+ if (NULL == ptree->sim_details)
+ return;
+ sim_n = HEAD_PFIFO(ptree->sim_details);
+ free(ptree->sim_details);
+ ptree->sim_details = NULL;
+ if (NULL == sim_n)
+ return;
+
+ FREE_ATTR_VAL_FIFO(sim_n->init_opts);
+ for (;;) {
+ UNLINK_FIFO(serv_n, *sim_n->servers, link);
+ if (NULL == serv_n)
+ break;
+ free(serv_n->curr_script);
+ if (serv_n->script != NULL) {
+ for (;;) {
+ UNLINK_FIFO(script_n, *serv_n->script,
+ link);
+ if (script_n == NULL)
+ break;
+ free(script_n);
+ }
+ free(serv_n->script);
}
+ free(serv_n);
+ }
+ free(sim_n);
+}
+#endif /* FREE_CFG_T */
+#endif /* SIM */
+
+
+/* Define two different config functions. One for the daemon and the other for
+ * the simulator. The simulator ignores a lot of the standard ntpd configuration
+ * options
+ */
+#ifndef SIM
+static void
+config_ntpd(
+ config_tree *ptree,
+ int/*BOOL*/ input_from_files
+ )
+{
+ config_nic_rules(ptree, input_from_files);
+ config_monitor(ptree);
+ config_auth(ptree);
+ config_tos(ptree);
+ config_access(ptree);
+ config_tinker(ptree);
+ config_rlimit(ptree);
+ config_system_opts(ptree);
+ config_logconfig(ptree);
+ config_phone(ptree);
+ config_mdnstries(ptree);
+ config_setvar(ptree);
+ config_ttl(ptree);
+ config_trap(ptree);
+ config_vars(ptree);
+
+ io_open_sockets();
+
+ config_other_modes(ptree);
+ config_peers(ptree);
+ config_unpeers(ptree);
+ config_fudge(ptree);
+ config_reset_counters(ptree);
+
+#ifdef TEST_BLOCKING_WORKER
+ {
+ struct addrinfo hints;
+
+ ZERO(hints);
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ getaddrinfo_sometime("www.cnn.com", "ntp", &hints,
+ INITIAL_DNS_RETRY,
+ gai_test_callback, (void *)1);
+ hints.ai_family = AF_INET6;
+ getaddrinfo_sometime("ipv6.google.com", "ntp", &hints,
+ INITIAL_DNS_RETRY,
+ gai_test_callback, (void *)0x600);
}
- if (fp[0])
- (void)fclose(fp[0]);
+#endif
+}
+#endif /* !SIM */
+
+
+#ifdef SIM
+static void
+config_ntpdsim(
+ config_tree *ptree
+ )
+{
+ printf("Configuring Simulator...\n");
+ printf("Some ntpd-specific commands in the configuration file will be ignored.\n");
+
+ config_tos(ptree);
+ config_monitor(ptree);
+ config_tinker(ptree);
+ if (0)
+ config_rlimit(ptree); /* not needed for the simulator */
+ config_system_opts(ptree);
+ config_logconfig(ptree);
+ config_vars(ptree);
+ config_sim(ptree);
+}
+#endif /* SIM */
+
+
+/*
+ * config_remotely() - implements ntpd side of ntpq :config
+ */
+void
+config_remotely(
+ sockaddr_u * remote_addr
+ )
+{
+ char origin[128];
+
+ snprintf(origin, sizeof(origin), "remote config from %s",
+ stoa(remote_addr));
+ lex_init_stack(origin, NULL); /* no checking needed... */
+ init_syntax_tree(&cfgt);
+ yyparse();
+ lex_drop_stack();
+
+ cfgt.source.attr = CONF_SOURCE_NTPQ;
+ cfgt.timestamp = time(NULL);
+ cfgt.source.value.s = estrdup(stoa(remote_addr));
+
+ DPRINTF(1, ("Finished Parsing!!\n"));
+
+ save_and_apply_config_tree(FALSE);
+}
+
+
+/*
+ * getconfig() - process startup configuration file e.g /etc/ntp.conf
+ */
+void
+getconfig(
+ int argc,
+ char ** argv
+ )
+{
+ char line[256];
+
+#ifdef DEBUG
+ atexit(free_all_config_trees);
+#endif
+#ifndef SYS_WINNT
+ config_file = CONFIG_FILE;
+#else
+ temp = CONFIG_FILE;
+ if (!ExpandEnvironmentStringsA(temp, config_file_storage,
+ sizeof(config_file_storage))) {
+ msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m");
+ exit(1);
+ }
+ config_file = config_file_storage;
+
+ temp = ALT_CONFIG_FILE;
+ if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage,
+ sizeof(alt_config_file_storage))) {
+ msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m");
+ exit(1);
+ }
+ alt_config_file = alt_config_file_storage;
+#endif /* SYS_WINNT */
+
+ /*
+ * install a non default variable with this daemon version
+ */
+ snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version);
+ set_sys_var(line, strlen(line) + 1, RO);
+
+ /*
+ * Set up for the first time step to install a variable showing
+ * which syscall is being used to step.
+ */
+ set_tod_using = &ntpd_set_tod_using;
+
+ getCmdOpts(argc, argv);
+ init_syntax_tree(&cfgt);
+ if (
+ !lex_init_stack(FindConfig(config_file), "r")
+#ifdef HAVE_NETINFO
+ /* If there is no config_file, try NetInfo. */
+ && check_netinfo && !(config_netinfo = get_netinfo_config())
+#endif /* HAVE_NETINFO */
+ ) {
+ msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(config_file));
+#ifndef SYS_WINNT
+ io_open_sockets();
+
+ return;
+#else
+ /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
+
+ if (!lex_init_stack(FindConfig(alt_config_file), "r")) {
+ /*
+ * Broadcast clients can sometimes run without
+ * a configuration file.
+ */
+ msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(alt_config_file));
+ io_open_sockets();
+
+ return;
+ }
+ cfgt.source.value.s = estrdup(alt_config_file);
+#endif /* SYS_WINNT */
+ } else
+ cfgt.source.value.s = estrdup(config_file);
+
+
+ /*** BULK OF THE PARSER ***/
+#ifdef DEBUG
+ yydebug = !!(debug >= 5);
+#endif
+ yyparse();
+ lex_drop_stack();
+
+ DPRINTF(1, ("Finished Parsing!!\n"));
+
+ cfgt.source.attr = CONF_SOURCE_FILE;
+ cfgt.timestamp = time(NULL);
+
+ save_and_apply_config_tree(TRUE);
#ifdef HAVE_NETINFO
if (config_netinfo)
free_netinfo_config(config_netinfo);
#endif /* HAVE_NETINFO */
+}
-#if !defined(VMS) && !defined(SYS_VXWORKS)
- /* find a keyid */
- if (info_auth_keyid == 0)
- req_keyid = 65535;
- else
- req_keyid = info_auth_keyid;
- /* if doesn't exist, make up one at random */
- if (!authhavekey(req_keyid)) {
- char rankey[9];
- int j;
+void
+save_and_apply_config_tree(int/*BOOL*/ input_from_file)
+{
+ config_tree *ptree;
+#ifndef SAVECONFIG
+ config_tree *punlinked;
+#endif
- for (i = 0; i < 8; i++)
- for (j = 1; j < 100; ++j) {
- rankey[i] = (char) (arc4random() & 0xff);
- if (rankey[i] != 0) break;
- }
- rankey[8] = 0;
- authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
- authtrust(req_keyid, 1);
- if (!authhavekey(req_keyid)) {
- msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
- /* HMS: Should this be fatal? */
+ /*
+ * Keep all the configuration trees applied since startup in
+ * a list that can be used to dump the configuration back to
+ * a text file.
+ */
+ ptree = emalloc(sizeof(*ptree));
+ memcpy(ptree, &cfgt, sizeof(*ptree));
+ ZERO(cfgt);
+
+ LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree);
+
+#ifdef SAVECONFIG
+ if (HAVE_OPT( SAVECONFIGQUIT )) {
+ FILE *dumpfile;
+ int err;
+ int dumpfailed;
+
+ dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w");
+ if (NULL == dumpfile) {
+ err = errno;
+ mfprintf(stderr,
+ "can not create save file %s, error %d %m\n",
+ OPT_ARG(SAVECONFIGQUIT), err);
+ exit(err);
}
+
+ dumpfailed = dump_all_config_trees(dumpfile, 0);
+ if (dumpfailed)
+ fprintf(stderr,
+ "--saveconfigquit %s error %d\n",
+ OPT_ARG( SAVECONFIGQUIT ),
+ dumpfailed);
+ else
+ fprintf(stderr,
+ "configuration saved to %s\n",
+ OPT_ARG( SAVECONFIGQUIT ));
+
+ exit(dumpfailed);
}
+#endif /* SAVECONFIG */
- /* save keyid so we will accept config requests with it */
- info_auth_keyid = req_keyid;
-#endif /* !defined(VMS) && !defined(SYS_VXWORKS) */
+ /* The actual configuration done depends on whether we are configuring the
+ * simulator or the daemon. Perform a check and call the appropriate
+ * function as needed.
+ */
- if (res_fp != NULL) {
- if (call_resolver) {
- /*
- * Need name resolution
- */
- do_resolve_internal();
+#ifndef SIM
+ config_ntpd(ptree, input_from_file);
+#else
+ config_ntpdsim(ptree);
+#endif
+
+ /*
+ * With configure --disable-saveconfig, there's no use keeping
+ * the config tree around after application, so free it.
+ */
+#ifndef SAVECONFIG
+ UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link,
+ config_tree);
+ INSIST(punlinked == ptree);
+ free_config_tree(ptree);
+#endif
+}
+
+
+static void
+ntpd_set_tod_using(
+ const char *which
+ )
+{
+ char line[128];
+
+ snprintf(line, sizeof(line), "settimeofday=\"%s\"", which);
+ set_sys_var(line, strlen(line) + 1, RO);
+}
+
+
+static char *
+normal_dtoa(
+ double d
+ )
+{
+ char * buf;
+ char * pch_e;
+ char * pch_nz;
+
+ LIB_GETBUF(buf);
+ snprintf(buf, LIB_BUFLENGTH, "%g", d);
+
+ /* use lowercase 'e', strip any leading zeroes in exponent */
+ pch_e = strchr(buf, 'e');
+ if (NULL == pch_e) {
+ pch_e = strchr(buf, 'E');
+ if (NULL == pch_e)
+ return buf;
+ *pch_e = 'e';
+ }
+ pch_e++;
+ if ('-' == *pch_e)
+ pch_e++;
+ pch_nz = pch_e;
+ while ('0' == *pch_nz)
+ pch_nz++;
+ if (pch_nz == pch_e)
+ return buf;
+ strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf));
+
+ return buf;
+}
+
+
+/* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
+ * --------------------------------------------
+ */
+
+
+/*
+ * get_pfxmatch - find value for prefixmatch
+ * and update char * accordingly
+ */
+static u_int32
+get_pfxmatch(
+ const char ** pstr,
+ struct masks * m
+ )
+{
+ while (m->name != NULL) {
+ if (strncmp(*pstr, m->name, strlen(m->name)) == 0) {
+ *pstr += strlen(m->name);
+ return m->mask;
+ } else {
+ m++;
}
}
+ return 0;
+}
+
+/*
+ * get_match - find logmask value
+ */
+static u_int32
+get_match(
+ const char * str,
+ struct masks * m
+ )
+{
+ while (m->name != NULL) {
+ if (strcmp(str, m->name) == 0)
+ return m->mask;
+ else
+ m++;
+ }
+ return 0;
+}
+
+/*
+ * get_logmask - build bitmask for ntp_syslogmask
+ */
+static u_int32
+get_logmask(
+ const char * str
+ )
+{
+ const char * t;
+ u_int32 offset;
+ u_int32 mask;
+
+ mask = get_match(str, logcfg_noclass_items);
+ if (mask != 0)
+ return mask;
+
+ t = str;
+ offset = get_pfxmatch(&t, logcfg_class);
+ mask = get_match(t, logcfg_class_items);
+
+ if (mask)
+ return mask << offset;
+ else
+ msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
+ str);
+
+ return 0;
}
#ifdef HAVE_NETINFO
-/*
+/*
* get_netinfo_config - find the nearest NetInfo domain with an ntp
* configuration and initialize the configuration state.
*/
static struct netinfo_config_state *
-get_netinfo_config()
+get_netinfo_config(void)
{
ni_status status;
void *domain;
ni_id config_dir;
- struct netinfo_config_state *config;
+ struct netinfo_config_state *config;
if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
@@ -1944,30 +4718,30 @@ get_netinfo_config()
return NULL;
}
- config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
- config->domain = domain;
- config->config_dir = config_dir;
- config->prop_index = 0;
- config->val_index = 0;
- config->val_list = NULL;
+ config = emalloc(sizeof(*config));
+ config->domain = domain;
+ config->config_dir = config_dir;
+ config->prop_index = 0;
+ config->val_index = 0;
+ config->val_list = NULL;
return config;
}
-
/*
* free_netinfo_config - release NetInfo configuration state
*/
static void
-free_netinfo_config(struct netinfo_config_state *config)
+free_netinfo_config(
+ struct netinfo_config_state *config
+ )
{
ni_free(config->domain);
free(config);
}
-
/*
* gettokens_netinfo - return tokens from NetInfo
*/
@@ -1985,35 +4759,40 @@ gettokens_netinfo (
/*
* Iterate through each keyword and look for a property that matches it.
*/
- again:
+ again:
if (!val_list) {
- for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
- {
- ni_namelist namelist;
+ for (; prop_index < COUNTOF(keywords); prop_index++)
+ {
+ ni_namelist namelist;
struct keyword current_prop = keywords[prop_index];
+ ni_index index;
/*
* For each value associated in the property, we're going to return
* a separate line. We squirrel away the values in the config state
* so the next time through, we don't need to do this lookup.
*/
- NI_INIT(&namelist);
- if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
- ni_index index;
+ NI_INIT(&namelist);
+ if (NI_OK == ni_lookupprop(config->domain,
+ &config->config_dir, current_prop.text,
+ &namelist)) {
/* Found the property, but it has no values */
if (namelist.ni_namelist_len == 0) continue;
- if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
- { msyslog(LOG_ERR, "out of memory while configuring"); break; }
-
- for (index = 0; index < namelist.ni_namelist_len; index++) {
- char *value = namelist.ni_namelist_val[index];
+ config->val_list =
+ eallocarray(
+ (namelist.ni_namelist_len + 1),
+ sizeof(char*));
+ val_list = config->val_list;
- if (! (val_list[index] = (char*)malloc(strlen(value)+1)))
- { msyslog(LOG_ERR, "out of memory while configuring"); break; }
+ for (index = 0;
+ index < namelist.ni_namelist_len;
+ index++) {
+ char *value;
- strcpy(val_list[index], value);
+ value = namelist.ni_namelist_val[index];
+ val_list[index] = estrdup(value);
}
val_list[index] = NULL;
@@ -2025,14 +4804,14 @@ gettokens_netinfo (
}
/* No list; we're done here. */
- if (!val_list) return CONFIG_UNKNOWN;
+ if (!val_list)
+ return CONFIG_UNKNOWN;
/*
* We have a list of values for the current property.
* Iterate through them and return each in order.
*/
- if (val_list[val_index])
- {
+ if (val_list[val_index]) {
int ntok = 1;
int quoted = 0;
char *tokens = val_list[val_index];
@@ -2050,16 +4829,18 @@ gettokens_netinfo (
break;
} else { /* must be space */
*tokens++ = '\0';
- while (ISSPACE(*tokens)) tokens++;
- if (ISEOL(*tokens)) break;
+ while (ISSPACE(*tokens))
+ tokens++;
+ if (ISEOL(*tokens))
+ break;
}
}
if (ntok == MAXTOKENS) {
/* HMS: chomp it to lose the EOL? */
msyslog(LOG_ERR,
- "gettokens_netinfo: too many tokens. Ignoring: %s",
- tokens);
+ "gettokens_netinfo: too many tokens. Ignoring: %s",
+ tokens);
} else {
*ntokens = ntok + 1;
}
@@ -2075,508 +4856,124 @@ gettokens_netinfo (
/* Free val_list and reset counters. */
for (val_index = 0; val_list[val_index]; val_index++)
free(val_list[val_index]);
- free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0;
+ free(val_list);
+ val_list = config->val_list = NULL;
+ val_index = config->val_index = 0;
goto again;
}
-
#endif /* HAVE_NETINFO */
/*
- * gettokens - read a line and return tokens
- */
-static int
-gettokens (
- FILE *fp,
- char *line,
- char **tokenlist,
- int *ntokens
- )
-{
- register char *cp;
- register int ntok;
- register int quoted = 0;
-
- /*
- * Find start of first token
- */
- again:
- while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
- cp = line;
- while (ISSPACE(*cp))
- cp++;
- if (!ISEOL(*cp))
- break;
- }
- if (cp == NULL) {
- *ntokens = 0;
- return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
- }
-
- /*
- * Now separate out the tokens
- */
- for (ntok = 0; ntok < MAXTOKENS; ntok++) {
- tokenlist[ntok] = cp;
- while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
- quoted ^= (*cp++ == '"');
-
- if (ISEOL(*cp)) {
- *cp = '\0';
- break;
- } else { /* must be space */
- *cp++ = '\0';
- while (ISSPACE(*cp))
- cp++;
- if (ISEOL(*cp))
- break;
- }
- }
-
- /* Heiko: Remove leading and trailing quotes around tokens */
- {
- int i,j = 0;
-
-
- for (i = 0; i < ntok; i++) {
- /* Now check if the first char is a quote and remove that */
- if ( tokenlist[ntok][0] == '"' )
- tokenlist[ntok]++;
-
- /* Now check the last char ... */
- j = strlen(tokenlist[ntok])-1;
- if ( tokenlist[ntok][j] == '"' )
- tokenlist[ntok][j] = '\0';
- }
-
- }
-
- if (ntok == MAXTOKENS) {
- --ntok;
- /* HMS: chomp it to lose the EOL? */
- msyslog(LOG_ERR,
- "gettokens: too many tokens on the line. Ignoring %s",
- cp);
- } else {
- /*
- * Return the match
- */
- *ntokens = ntok + 1;
- ntok = matchkey(tokenlist[0], keywords, 1);
- if (ntok == CONFIG_UNKNOWN)
- goto again;
- }
-
- return ntok;
-}
-
-
-
-/*
- * matchkey - match a keyword to a list
- */
-static int
-matchkey(
- register char *word,
- register struct keyword *keys,
- int complain
- )
-{
- for (;;) {
- if (keys->keytype == CONFIG_UNKNOWN) {
- if (complain)
- msyslog(LOG_ERR,
- "configure: keyword \"%s\" unknown, line ignored",
- word);
- return CONFIG_UNKNOWN;
- }
- if (STRSAME(word, keys->text))
- return keys->keytype;
- keys++;
- }
-}
-
-
-/*
* getnetnum - return a net number (this is crude, but careful)
+ *
+ * returns 1 for success, and mysteriously, 0 for most failures, and
+ * -1 if the address found is IPv6 and we believe IPv6 isn't working.
*/
+#ifndef SIM
static int
getnetnum(
const char *num,
- struct sockaddr_storage *addr,
+ sockaddr_u *addr,
int complain,
- enum gnn_type a_type
+ enum gnn_type a_type /* ignored */
)
{
- struct addrinfo hints;
- struct addrinfo *ptr;
- int retval;
-
-#if 0
- printf("getnetnum: <%s> is a %s (%d)\n",
- num,
- (a_type == t_UNK)
- ? "t_UNK"
- : (a_type == t_REF)
- ? "t_REF"
- : (a_type == t_MSK)
- ? "t_MSK"
- : "???",
- a_type);
-#endif
+ NTP_REQUIRE(AF_UNSPEC == AF(addr) ||
+ AF_INET == AF(addr) ||
+ AF_INET6 == AF(addr));
- /* Get host address. Looking for UDP datagram connection */
- memset(&hints, 0, sizeof (hints));
- if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
- hints.ai_family = addr->ss_family;
- else
- hints.ai_family = AF_UNSPEC;
- /*
- * If we don't have an IPv6 stack, just look up IPv4 addresses
- */
- if (isc_net_probeipv6() != ISC_R_SUCCESS)
- hints.ai_family = AF_INET;
+ if (!is_ip_address(num, AF(addr), addr))
+ return 0;
- hints.ai_socktype = SOCK_DGRAM;
+ if (IS_IPV6(addr) && !ipv6_works)
+ return -1;
- if (a_type != t_UNK) {
- hints.ai_flags = AI_NUMERICHOST;
- }
+# ifdef ISC_PLATFORM_HAVESALEN
+ addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr));
+# endif
+ SET_PORT(addr, NTP_PORT);
-#ifdef DEBUG
- if (debug > 3)
- printf("getnetnum: calling getaddrinfo(%s,...)\n", num);
-#endif
- retval = getaddrinfo(num, "ntp", &hints, &ptr);
- if (retval != 0 ||
- (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) {
- if (complain)
- msyslog(LOG_ERR,
- "getaddrinfo: \"%s\" invalid host address, ignored",
- num);
-#ifdef DEBUG
- if (debug > 0)
- printf(
- "getaddrinfo: \"%s\" invalid host address%s.\n",
- num, (complain)
- ? ", ignored"
- : "");
-#endif
- if (retval == 0 &&
- ptr->ai_family == AF_INET6 &&
- isc_net_probeipv6() != ISC_R_SUCCESS)
- {
- return -1;
- }
- else {
- return 0;
- }
- }
+ DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr)));
- memcpy(addr, ptr->ai_addr, ptr->ai_addrlen);
-#ifdef DEBUG
- if (debug > 1)
- printf("getnetnum given %s, got %s (%s/%d)\n",
- num, stoa(addr),
- (a_type == t_UNK)
- ? "t_UNK"
- : (a_type == t_REF)
- ? "t_REF"
- : (a_type == t_MSK)
- ? "t_MSK"
- : "???",
- a_type);
-#endif
- freeaddrinfo(ptr);
return 1;
}
+#endif /* !SIM */
-
-#if !defined(VMS) && !defined(SYS_WINNT)
-/*
- * catchchild - receive the resolver's exit status
- */
-static RETSIGTYPE
-catchchild(
- int sig
+#if defined(HAVE_SETRLIMIT)
+void
+ntp_rlimit(
+ int rl_what,
+ rlim_t rl_value,
+ int rl_scale,
+ const char * rl_sstr
)
{
- /*
- * We only start up one child, and if we're here
- * it should have already exited. Hence the following
- * shouldn't hang. If it does, please tell me.
- */
-#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
- (void) wait(0);
-#endif /* SYS_WINNT && VXWORKS*/
-}
-#endif /* VMS */
-
-
-/*
- * save_resolve - save configuration info into a file for later name resolution
- */
-static void
-save_resolve(
- char *name,
- int mode,
- int version,
- int minpoll,
- int maxpoll,
- u_int flags,
- int ttl,
- keyid_t keyid,
- u_char *keystr,
- u_char peeraf
- )
-{
-#ifndef SYS_VXWORKS
- if (res_fp == NULL) {
-#ifndef SYS_WINNT
- (void) strcpy(res_file, RES_TEMPFILE);
-#else
- /* no /tmp directory under NT */
- {
- if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
- msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
- return;
- }
- (void) strcat(res_file, "ntpdXXXXXX");
- }
-#endif /* SYS_WINNT */
-#ifdef HAVE_MKSTEMP
- {
- int fd;
+ struct rlimit rl;
- res_fp = NULL;
- if ((fd = mkstemp(res_file)) != -1)
- res_fp = fdopen(fd, "r+");
- }
-#else
- (void) mktemp(res_file);
- res_fp = fopen(res_file, "w");
-#endif
- if (res_fp == NULL) {
- msyslog(LOG_ERR, "open failed for %s: %m", res_file);
- return;
- }
- }
-#ifdef DEBUG
- if (debug) {
- printf("resolving %s\n", name);
- }
-#endif
-
- (void)fprintf(res_fp, "%s %u %d %d %d %d %d %d %u %s\n", name, peeraf,
- mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
-#ifdef DEBUG
- if (debug > 1)
- printf("config: %s %u %d %d %d %d %x %d %u %s\n", name, peeraf, mode,
- version, minpoll, maxpoll, flags, ttl, keyid, keystr);
-#endif
-
-#else /* SYS_VXWORKS */
- /* save resolve info to a struct */
-#endif /* SYS_VXWORKS */
-}
-
-
-/*
- * abort_resolve - terminate the resolver stuff and delete the file
- */
-static void
-abort_resolve(void)
-{
- /*
- * In an ideal world we would might reread the file and
- * log the hosts which aren't getting configured. Since
- * this is too much work, however, just close and delete
- * the temp file.
- */
- if (res_fp != NULL)
- (void) fclose(res_fp);
- res_fp = NULL;
-
-#ifndef SYS_VXWORKS /* we don't open the file to begin with */
-#if !defined(VMS)
- (void) unlink(res_file);
-#else
- (void) delete(res_file);
-#endif /* VMS */
-#endif /* SYS_VXWORKS */
-}
-
-
-/*
- * do_resolve_internal - start up the resolver function (not program)
- */
-/*
- * On VMS, this routine will simply refuse to resolve anything.
- *
- * Possible implementation: keep `res_file' in memory, do async
- * name resolution via QIO, update from within completion AST.
- * I'm unlikely to find the time for doing this, though. -wjm
- */
-static void
-do_resolve_internal(void)
-{
- int i;
-
- if (res_fp == NULL) {
- /* belch */
- msyslog(LOG_ERR,
- "do_resolve_internal: Fatal: res_fp == NULL");
- exit(1);
- }
-
- /* we are done with this now */
- (void) fclose(res_fp);
- res_fp = NULL;
-
-#if !defined(VMS) && !defined (SYS_VXWORKS)
- req_file = res_file; /* set up pointer to res file */
-#ifndef SYS_WINNT
- (void) signal_no_reset(SIGCHLD, catchchild);
-
-#ifndef SYS_VXWORKS
- /* the parent process will write to the pipe
- * in order to wake up to child process
- * which may be waiting in a select() call
- * on the read fd */
- if (pipe(resolver_pipe_fd) < 0) {
- msyslog(LOG_ERR,
- "unable to open resolver pipe");
- exit(1);
- }
-
- i = fork();
- /* Shouldn't the code below be re-ordered?
- * I.e. first check if the fork() returned an error, then
- * check whether we're parent or child.
- * Martin Burnicki
- */
- if (i == 0) {
+ switch (rl_what) {
+# ifdef RLIMIT_MEMLOCK
+ case RLIMIT_MEMLOCK:
/*
- * this used to close everything
- * I don't think this is necessary
+ * The default RLIMIT_MEMLOCK is very low on Linux systems.
+ * Unless we increase this limit malloc calls are likely to
+ * fail if we drop root privilege. To be useful the value
+ * has to be larger than the largest ntpd resident set size.
*/
+ DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n",
+ (int)(rl_value / rl_scale), rl_sstr));
+ rl.rlim_cur = rl.rlim_max = rl_value;
+ if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
+ msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
+ break;
+# endif /* RLIMIT_MEMLOCK */
+
+# ifdef RLIMIT_NOFILE
+ case RLIMIT_NOFILE:
/*
- * To the unknown commenter above:
- * Well, I think it's better to clean up
- * after oneself. I have had problems with
- * refclock-io when intres was running - things
- * where fine again when ntpintres was gone.
- * So some systems react erratic at least.
- *
- * Frank Kardel
- *
- * 94-11-16:
- * Further debugging has proven that the above is
- * absolutely harmful. The internal resolver
- * is still in the SIGIO process group and the lingering
- * async io information causes it to process requests from
- * all file decriptor causing a race between the NTP daemon
- * and the resolver. which then eats data when it wins 8-(.
- * It is absolutly necessary to kill any IO associations
- * shared with the NTP daemon.
- *
- * We also block SIGIO (currently no ports means to
- * disable the signal handle for IO).
- *
- * Thanks to wgstuken@informatik.uni-erlangen.de to notice
- * that it is the ntp-resolver child running into trouble.
- *
- * THUS:
+ * For large systems the default file descriptor limit may
+ * not be enough.
*/
-
- /* This is the child process who will read the pipe,
- * so we close the write fd */
- close(resolver_pipe_fd[1]);
- closelog();
- kill_asyncio(0);
-
- (void) signal_no_reset(SIGCHLD, SIG_DFL);
-
-#ifdef DEBUG
- if (0)
- debug = 2;
-#endif
-
-# ifndef LOG_DAEMON
- openlog("ntpd_initres", LOG_PID);
-# else /* LOG_DAEMON */
-
-# ifndef LOG_NTP
-# define LOG_NTP LOG_DAEMON
-# endif
- openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
-#ifndef SYS_CYGWIN32
-# ifdef DEBUG
- if (debug)
- setlogmask(LOG_UPTO(LOG_DEBUG));
- else
-# endif /* DEBUG */
- setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
-# endif /* LOG_DAEMON */
-#endif
-
- ntp_intres();
-
+ DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n",
+ (int)(rl_value / rl_scale), rl_sstr));
+ rl.rlim_cur = rl.rlim_max = rl_value;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
+ msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m");
+ break;
+# endif /* RLIMIT_NOFILE */
+
+# ifdef RLIMIT_STACK
+ case RLIMIT_STACK:
/*
- * If we got here, the intres code screwed up.
- * Print something so we don't die without complaint
+ * Provide a way to set the stack limit to something
+ * smaller, so that we don't lock a lot of unused
+ * stack memory.
*/
- msyslog(LOG_ERR, "call to ntp_intres lost");
- abort_resolve();
- exit(1);
- }
-#else
- /* vxWorks spawns a thread... -casey */
- i = sp (ntp_intres);
- /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
-#endif
- if (i == -1) {
- msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
- (void) signal_no_reset(SIGCHLD, SIG_DFL);
- abort_resolve();
- }
- else {
- /* This is the parent process who will write to the pipe,
- * so we close the read fd */
- close(resolver_pipe_fd[0]);
- }
-#else /* SYS_WINNT */
- {
- /* NT's equivalent of fork() is _spawn(), but the start point
- * of the new process is an executable filename rather than
- * a function name as desired here.
- */
- DWORD dwThreadId;
- fflush(stdout);
- ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (ResolverEventHandle == NULL) {
- msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
- abort_resolve();
- }
- ResolverThreadHandle = CreateThread(
- NULL, /* no security attributes */
- 0, /* use default stack size */
- (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */
- NULL, /* argument to thread function */
- 0, /* use default creation flags */
- &dwThreadId); /* returns the thread identifier */
- if (ResolverThreadHandle == NULL) {
- msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
- CloseHandle(ResolverEventHandle);
- ResolverEventHandle = NULL;
- abort_resolve();
+ DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n",
+ (int)(rl_value / rl_scale), rl_sstr));
+ if (-1 == getrlimit(RLIMIT_STACK, &rl)) {
+ msyslog(LOG_ERR, "getrlimit(RLIMIT_STACK) failed: %m");
+ } else {
+ if (rl_value > rl.rlim_max) {
+ msyslog(LOG_WARNING,
+ "ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.",
+ (u_long)rl.rlim_max,
+ (u_long)rl_value);
+ rl_value = rl.rlim_max;
+ }
+ rl.rlim_cur = rl_value;
+ if (-1 == setrlimit(RLIMIT_STACK, &rl)) {
+ msyslog(LOG_ERR,
+ "ntp_rlimit: Cannot set RLIMIT_STACK: %m");
+ }
}
+ break;
+# endif /* RLIMIT_STACK */
+
+ default:
+ INSIST(!"Unexpected setrlimit() case!");
+ break;
}
-#endif /* SYS_WINNT */
-#else /* VMS VX_WORKS */
- msyslog(LOG_ERR,
- "Name resolution not implemented for VMS - use numeric addresses");
- abort_resolve();
-#endif /* VMS VX_WORKS */
}
+#endif /* HAVE_SETRLIMIT */
diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c
index dbee89a..8ad1faf 100644
--- a/contrib/ntp/ntpd/ntp_control.c
+++ b/contrib/ntp/ntpd/ntp_control.c
@@ -1,28 +1,42 @@
/*
- * ntp_control.c - respond to control messages and send async traps
+ * ntp_control.c - respond to mode 6 control messages and send async
+ * traps. Provides service to ntpq and others.
*/
/*
- * $FreeBSD$
+ * $FreeBSD: stable/10/contrib/ntp/ntpd/ntp_control.c 276072 2014-12-22 19:07:16Z delphij $
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+# include <config.h>
#endif
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/stat.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#include <arpa/inet.h>
+
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_control.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
+#include "ntp_config.h"
+#include "ntp_crypto.h"
+#include "ntp_assert.h"
+#include "ntp_leapsec.h"
+#include "ntp_md5.h" /* provides OpenSSL digest API */
+#include "lib_strbuf.h"
+#ifdef KERNEL_PLL
+# include "ntp_syscall.h"
+#endif
-#include <stdio.h>
-#include <ctype.h>
-#include <signal.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
+extern size_t remoteconfig_cmdlength( const char *src_buf, const char *src_end );
#ifndef MIN
#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
@@ -31,123 +45,413 @@
/*
* Structure to hold request procedure information
*/
-#define NOAUTH 0
-#define AUTH 1
-
-#define NO_REQUEST (-1)
struct ctl_proc {
short control_code; /* defined request code */
+#define NO_REQUEST (-1)
u_short flags; /* flags word */
- void (*handler) P((struct recvbuf *, int)); /* handle request */
-};
-
-/*
- * Only one flag. Authentication required or not.
- */
+ /* Only one flag. Authentication required or not. */
#define NOAUTH 0
#define AUTH 1
+ void (*handler) (struct recvbuf *, int); /* handle request */
+};
+
/*
* Request processing routines
*/
-static void ctl_error P((int));
+static void ctl_error (u_char);
#ifdef REFCLOCK
-static u_short ctlclkstatus P((struct refclockstat *));
-#endif
-static void ctl_flushpkt P((int));
-static void ctl_putdata P((const char *, unsigned int, int));
-static void ctl_putstr P((const char *, const char *,
- unsigned int));
-static void ctl_putdbl P((const char *, double));
-static void ctl_putuint P((const char *, u_long));
-static void ctl_puthex P((const char *, u_long));
-static void ctl_putint P((const char *, long));
-static void ctl_putts P((const char *, l_fp *));
-static void ctl_putadr P((const char *, u_int32, struct sockaddr_storage*));
-static void ctl_putid P((const char *, char *));
-static void ctl_putarray P((const char *, double *, int));
-static void ctl_putsys P((int));
-static void ctl_putpeer P((int, struct peer *));
-#ifdef OPENSSL
-static void ctl_putfs P((const char *, tstamp_t));
+static u_short ctlclkstatus (struct refclockstat *);
#endif
+static void ctl_flushpkt (u_char);
+static void ctl_putdata (const char *, unsigned int, int);
+static void ctl_putstr (const char *, const char *, size_t);
+static void ctl_putdblf (const char *, int, int, double);
+#define ctl_putdbl(tag, d) ctl_putdblf(tag, 1, 3, d)
+#define ctl_putdbl6(tag, d) ctl_putdblf(tag, 1, 6, d)
+#define ctl_putsfp(tag, sfp) ctl_putdblf(tag, 0, -1, \
+ FPTOD(sfp))
+static void ctl_putuint (const char *, u_long);
+static void ctl_puthex (const char *, u_long);
+static void ctl_putint (const char *, long);
+static void ctl_putts (const char *, l_fp *);
+static void ctl_putadr (const char *, u_int32,
+ sockaddr_u *);
+static void ctl_putrefid (const char *, u_int32);
+static void ctl_putarray (const char *, double *, int);
+static void ctl_putsys (int);
+static void ctl_putpeer (int, struct peer *);
+static void ctl_putfs (const char *, tstamp_t);
#ifdef REFCLOCK
-static void ctl_putclock P((int, struct refclockstat *, int));
+static void ctl_putclock (int, struct refclockstat *, int);
#endif /* REFCLOCK */
-static struct ctl_var *ctl_getitem P((struct ctl_var *, char **));
-static u_long count_var P((struct ctl_var *));
-static void control_unspec P((struct recvbuf *, int));
-static void read_status P((struct recvbuf *, int));
-static void read_variables P((struct recvbuf *, int));
-static void write_variables P((struct recvbuf *, int));
-static void read_clock_status P((struct recvbuf *, int));
-static void write_clock_status P((struct recvbuf *, int));
-static void set_trap P((struct recvbuf *, int));
-static void unset_trap P((struct recvbuf *, int));
-static struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *,
- struct interface *));
-
-static struct ctl_proc control_codes[] = {
- { CTL_OP_UNSPEC, NOAUTH, control_unspec },
- { CTL_OP_READSTAT, NOAUTH, read_status },
- { CTL_OP_READVAR, NOAUTH, read_variables },
- { CTL_OP_WRITEVAR, AUTH, write_variables },
- { CTL_OP_READCLOCK, NOAUTH, read_clock_status },
- { CTL_OP_WRITECLOCK, NOAUTH, write_clock_status },
- { CTL_OP_SETTRAP, NOAUTH, set_trap },
- { CTL_OP_UNSETTRAP, NOAUTH, unset_trap },
- { NO_REQUEST, 0 }
+static const struct ctl_var *ctl_getitem(const struct ctl_var *,
+ char **);
+static u_short count_var (const struct ctl_var *);
+static void control_unspec (struct recvbuf *, int);
+static void read_status (struct recvbuf *, int);
+static void read_sysvars (void);
+static void read_peervars (void);
+static void read_variables (struct recvbuf *, int);
+static void write_variables (struct recvbuf *, int);
+static void read_clockstatus(struct recvbuf *, int);
+static void write_clockstatus(struct recvbuf *, int);
+static void set_trap (struct recvbuf *, int);
+static void save_config (struct recvbuf *, int);
+static void configure (struct recvbuf *, int);
+static void send_mru_entry (mon_entry *, int);
+static void send_random_tag_value(int);
+static void read_mru_list (struct recvbuf *, int);
+static void send_ifstats_entry(endpt *, u_int);
+static void read_ifstats (struct recvbuf *);
+static void sockaddrs_from_restrict_u(sockaddr_u *, sockaddr_u *,
+ restrict_u *, int);
+static void send_restrict_entry(restrict_u *, int, u_int);
+static void send_restrict_list(restrict_u *, int, u_int *);
+static void read_addr_restrictions(struct recvbuf *);
+static void read_ordlist (struct recvbuf *, int);
+static u_int32 derive_nonce (sockaddr_u *, u_int32, u_int32);
+static void generate_nonce (struct recvbuf *, char *, size_t);
+static int validate_nonce (const char *, struct recvbuf *);
+static void req_nonce (struct recvbuf *, int);
+static void unset_trap (struct recvbuf *, int);
+static struct ctl_trap *ctlfindtrap(sockaddr_u *,
+ struct interface *);
+
+static const struct ctl_proc control_codes[] = {
+ { CTL_OP_UNSPEC, NOAUTH, control_unspec },
+ { CTL_OP_READSTAT, NOAUTH, read_status },
+ { CTL_OP_READVAR, NOAUTH, read_variables },
+ { CTL_OP_WRITEVAR, AUTH, write_variables },
+ { CTL_OP_READCLOCK, NOAUTH, read_clockstatus },
+ { CTL_OP_WRITECLOCK, NOAUTH, write_clockstatus },
+ { CTL_OP_SETTRAP, NOAUTH, set_trap },
+ { CTL_OP_CONFIGURE, AUTH, configure },
+ { CTL_OP_SAVECONFIG, AUTH, save_config },
+ { CTL_OP_READ_MRU, NOAUTH, read_mru_list },
+ { CTL_OP_READ_ORDLIST_A, AUTH, read_ordlist },
+ { CTL_OP_REQ_NONCE, NOAUTH, req_nonce },
+ { CTL_OP_UNSETTRAP, NOAUTH, unset_trap },
+ { NO_REQUEST, 0, NULL }
};
/*
+ * System variables we understand
+ */
+#define CS_LEAP 1
+#define CS_STRATUM 2
+#define CS_PRECISION 3
+#define CS_ROOTDELAY 4
+#define CS_ROOTDISPERSION 5
+#define CS_REFID 6
+#define CS_REFTIME 7
+#define CS_POLL 8
+#define CS_PEERID 9
+#define CS_OFFSET 10
+#define CS_DRIFT 11
+#define CS_JITTER 12
+#define CS_ERROR 13
+#define CS_CLOCK 14
+#define CS_PROCESSOR 15
+#define CS_SYSTEM 16
+#define CS_VERSION 17
+#define CS_STABIL 18
+#define CS_VARLIST 19
+#define CS_TAI 20
+#define CS_LEAPTAB 21
+#define CS_LEAPEND 22
+#define CS_RATE 23
+#define CS_MRU_ENABLED 24
+#define CS_MRU_DEPTH 25
+#define CS_MRU_DEEPEST 26
+#define CS_MRU_MINDEPTH 27
+#define CS_MRU_MAXAGE 28
+#define CS_MRU_MAXDEPTH 29
+#define CS_MRU_MEM 30
+#define CS_MRU_MAXMEM 31
+#define CS_SS_UPTIME 32
+#define CS_SS_RESET 33
+#define CS_SS_RECEIVED 34
+#define CS_SS_THISVER 35
+#define CS_SS_OLDVER 36
+#define CS_SS_BADFORMAT 37
+#define CS_SS_BADAUTH 38
+#define CS_SS_DECLINED 39
+#define CS_SS_RESTRICTED 40
+#define CS_SS_LIMITED 41
+#define CS_SS_KODSENT 42
+#define CS_SS_PROCESSED 43
+#define CS_PEERADR 44
+#define CS_PEERMODE 45
+#define CS_BCASTDELAY 46
+#define CS_AUTHDELAY 47
+#define CS_AUTHKEYS 48
+#define CS_AUTHFREEK 49
+#define CS_AUTHKLOOKUPS 50
+#define CS_AUTHKNOTFOUND 51
+#define CS_AUTHKUNCACHED 52
+#define CS_AUTHKEXPIRED 53
+#define CS_AUTHENCRYPTS 54
+#define CS_AUTHDECRYPTS 55
+#define CS_AUTHRESET 56
+#define CS_K_OFFSET 57
+#define CS_K_FREQ 58
+#define CS_K_MAXERR 59
+#define CS_K_ESTERR 60
+#define CS_K_STFLAGS 61
+#define CS_K_TIMECONST 62
+#define CS_K_PRECISION 63
+#define CS_K_FREQTOL 64
+#define CS_K_PPS_FREQ 65
+#define CS_K_PPS_STABIL 66
+#define CS_K_PPS_JITTER 67
+#define CS_K_PPS_CALIBDUR 68
+#define CS_K_PPS_CALIBS 69
+#define CS_K_PPS_CALIBERRS 70
+#define CS_K_PPS_JITEXC 71
+#define CS_K_PPS_STBEXC 72
+#define CS_KERN_FIRST CS_K_OFFSET
+#define CS_KERN_LAST CS_K_PPS_STBEXC
+#define CS_IOSTATS_RESET 73
+#define CS_TOTAL_RBUF 74
+#define CS_FREE_RBUF 75
+#define CS_USED_RBUF 76
+#define CS_RBUF_LOWATER 77
+#define CS_IO_DROPPED 78
+#define CS_IO_IGNORED 79
+#define CS_IO_RECEIVED 80
+#define CS_IO_SENT 81
+#define CS_IO_SENDFAILED 82
+#define CS_IO_WAKEUPS 83
+#define CS_IO_GOODWAKEUPS 84
+#define CS_TIMERSTATS_RESET 85
+#define CS_TIMER_OVERRUNS 86
+#define CS_TIMER_XMTS 87
+#define CS_FUZZ 88
+#define CS_WANDER_THRESH 89
+#define CS_LEAPSMEARINTV 90
+#define CS_LEAPSMEAROFFS 91
+#define CS_MAX_NOAUTOKEY CS_LEAPSMEAROFFS
+#ifdef AUTOKEY
+#define CS_FLAGS (1 + CS_MAX_NOAUTOKEY)
+#define CS_HOST (2 + CS_MAX_NOAUTOKEY)
+#define CS_PUBLIC (3 + CS_MAX_NOAUTOKEY)
+#define CS_CERTIF (4 + CS_MAX_NOAUTOKEY)
+#define CS_SIGNATURE (5 + CS_MAX_NOAUTOKEY)
+#define CS_REVTIME (6 + CS_MAX_NOAUTOKEY)
+#define CS_IDENT (7 + CS_MAX_NOAUTOKEY)
+#define CS_DIGEST (8 + CS_MAX_NOAUTOKEY)
+#define CS_MAXCODE CS_DIGEST
+#else /* !AUTOKEY follows */
+#define CS_MAXCODE CS_MAX_NOAUTOKEY
+#endif /* !AUTOKEY */
+
+/*
+ * Peer variables we understand
+ */
+#define CP_CONFIG 1
+#define CP_AUTHENABLE 2
+#define CP_AUTHENTIC 3
+#define CP_SRCADR 4
+#define CP_SRCPORT 5
+#define CP_DSTADR 6
+#define CP_DSTPORT 7
+#define CP_LEAP 8
+#define CP_HMODE 9
+#define CP_STRATUM 10
+#define CP_PPOLL 11
+#define CP_HPOLL 12
+#define CP_PRECISION 13
+#define CP_ROOTDELAY 14
+#define CP_ROOTDISPERSION 15
+#define CP_REFID 16
+#define CP_REFTIME 17
+#define CP_ORG 18
+#define CP_REC 19
+#define CP_XMT 20
+#define CP_REACH 21
+#define CP_UNREACH 22
+#define CP_TIMER 23
+#define CP_DELAY 24
+#define CP_OFFSET 25
+#define CP_JITTER 26
+#define CP_DISPERSION 27
+#define CP_KEYID 28
+#define CP_FILTDELAY 29
+#define CP_FILTOFFSET 30
+#define CP_PMODE 31
+#define CP_RECEIVED 32
+#define CP_SENT 33
+#define CP_FILTERROR 34
+#define CP_FLASH 35
+#define CP_TTL 36
+#define CP_VARLIST 37
+#define CP_IN 38
+#define CP_OUT 39
+#define CP_RATE 40
+#define CP_BIAS 41
+#define CP_SRCHOST 42
+#define CP_TIMEREC 43
+#define CP_TIMEREACH 44
+#define CP_BADAUTH 45
+#define CP_BOGUSORG 46
+#define CP_OLDPKT 47
+#define CP_SELDISP 48
+#define CP_SELBROKEN 49
+#define CP_CANDIDATE 50
+#define CP_MAX_NOAUTOKEY CP_CANDIDATE
+#ifdef AUTOKEY
+#define CP_FLAGS (1 + CP_MAX_NOAUTOKEY)
+#define CP_HOST (2 + CP_MAX_NOAUTOKEY)
+#define CP_VALID (3 + CP_MAX_NOAUTOKEY)
+#define CP_INITSEQ (4 + CP_MAX_NOAUTOKEY)
+#define CP_INITKEY (5 + CP_MAX_NOAUTOKEY)
+#define CP_INITTSP (6 + CP_MAX_NOAUTOKEY)
+#define CP_SIGNATURE (7 + CP_MAX_NOAUTOKEY)
+#define CP_IDENT (8 + CP_MAX_NOAUTOKEY)
+#define CP_MAXCODE CP_IDENT
+#else /* !AUTOKEY follows */
+#define CP_MAXCODE CP_MAX_NOAUTOKEY
+#endif /* !AUTOKEY */
+
+/*
+ * Clock variables we understand
+ */
+#define CC_TYPE 1
+#define CC_TIMECODE 2
+#define CC_POLL 3
+#define CC_NOREPLY 4
+#define CC_BADFORMAT 5
+#define CC_BADDATA 6
+#define CC_FUDGETIME1 7
+#define CC_FUDGETIME2 8
+#define CC_FUDGEVAL1 9
+#define CC_FUDGEVAL2 10
+#define CC_FLAGS 11
+#define CC_DEVICE 12
+#define CC_VARLIST 13
+#define CC_MAXCODE CC_VARLIST
+
+/*
* System variable values. The array can be indexed by the variable
* index to find the textual name.
*/
-static struct ctl_var sys_var[] = {
+static const struct ctl_var sys_var[] = {
{ 0, PADDING, "" }, /* 0 */
{ CS_LEAP, RW, "leap" }, /* 1 */
{ CS_STRATUM, RO, "stratum" }, /* 2 */
{ CS_PRECISION, RO, "precision" }, /* 3 */
{ CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */
- { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */
+ { CS_ROOTDISPERSION, RO, "rootdisp" }, /* 5 */
{ CS_REFID, RO, "refid" }, /* 6 */
{ CS_REFTIME, RO, "reftime" }, /* 7 */
- { CS_POLL, RO, "poll" }, /* 8 */
+ { CS_POLL, RO, "tc" }, /* 8 */
{ CS_PEERID, RO, "peer" }, /* 9 */
- { CS_STATE, RO, "state" }, /* 10 */
- { CS_OFFSET, RO, "offset" }, /* 11 */
- { CS_DRIFT, RO, "frequency" }, /* 12 */
- { CS_JITTER, RO, "jitter" }, /* 13 */
- { CS_ERROR, RO, "noise" }, /* 14 */
- { CS_CLOCK, RO, "clock" }, /* 15 */
- { CS_PROCESSOR, RO, "processor" }, /* 16 */
- { CS_SYSTEM, RO, "system" }, /* 17 */
- { CS_VERSION, RO, "version" }, /* 18 */
- { CS_STABIL, RO, "stability" }, /* 19 */
- { CS_VARLIST, RO, "sys_var_list" }, /* 20 */
-#ifdef OPENSSL
- { CS_FLAGS, RO, "flags" }, /* 21 */
- { CS_HOST, RO, "hostname" }, /* 22 */
- { CS_PUBLIC, RO, "update" }, /* 23 */
- { CS_CERTIF, RO, "cert" }, /* 24 */
- { CS_REVTIME, RO, "expire" }, /* 25 */
- { CS_LEAPTAB, RO, "leapsec" }, /* 26 */
- { CS_TAI, RO, "tai" }, /* 27 */
- { CS_DIGEST, RO, "signature" }, /* 28 */
- { CS_IDENT, RO, "ident" }, /* 29 */
- { CS_REVOKE, RO, "expire" }, /* 30 */
-#endif /* OPENSSL */
- { 0, EOV, "" } /* 21/31 */
+ { CS_OFFSET, RO, "offset" }, /* 10 */
+ { CS_DRIFT, RO, "frequency" }, /* 11 */
+ { CS_JITTER, RO, "sys_jitter" }, /* 12 */
+ { CS_ERROR, RO, "clk_jitter" }, /* 13 */
+ { CS_CLOCK, RO, "clock" }, /* 14 */
+ { CS_PROCESSOR, RO, "processor" }, /* 15 */
+ { CS_SYSTEM, RO, "system" }, /* 16 */
+ { CS_VERSION, RO, "version" }, /* 17 */
+ { CS_STABIL, RO, "clk_wander" }, /* 18 */
+ { CS_VARLIST, RO, "sys_var_list" }, /* 19 */
+ { CS_TAI, RO, "tai" }, /* 20 */
+ { CS_LEAPTAB, RO, "leapsec" }, /* 21 */
+ { CS_LEAPEND, RO, "expire" }, /* 22 */
+ { CS_RATE, RO, "mintc" }, /* 23 */
+ { CS_MRU_ENABLED, RO, "mru_enabled" }, /* 24 */
+ { CS_MRU_DEPTH, RO, "mru_depth" }, /* 25 */
+ { CS_MRU_DEEPEST, RO, "mru_deepest" }, /* 26 */
+ { CS_MRU_MINDEPTH, RO, "mru_mindepth" }, /* 27 */
+ { CS_MRU_MAXAGE, RO, "mru_maxage" }, /* 28 */
+ { CS_MRU_MAXDEPTH, RO, "mru_maxdepth" }, /* 29 */
+ { CS_MRU_MEM, RO, "mru_mem" }, /* 30 */
+ { CS_MRU_MAXMEM, RO, "mru_maxmem" }, /* 31 */
+ { CS_SS_UPTIME, RO, "ss_uptime" }, /* 32 */
+ { CS_SS_RESET, RO, "ss_reset" }, /* 33 */
+ { CS_SS_RECEIVED, RO, "ss_received" }, /* 34 */
+ { CS_SS_THISVER, RO, "ss_thisver" }, /* 35 */
+ { CS_SS_OLDVER, RO, "ss_oldver" }, /* 36 */
+ { CS_SS_BADFORMAT, RO, "ss_badformat" }, /* 37 */
+ { CS_SS_BADAUTH, RO, "ss_badauth" }, /* 38 */
+ { CS_SS_DECLINED, RO, "ss_declined" }, /* 39 */
+ { CS_SS_RESTRICTED, RO, "ss_restricted" }, /* 40 */
+ { CS_SS_LIMITED, RO, "ss_limited" }, /* 41 */
+ { CS_SS_KODSENT, RO, "ss_kodsent" }, /* 42 */
+ { CS_SS_PROCESSED, RO, "ss_processed" }, /* 43 */
+ { CS_PEERADR, RO, "peeradr" }, /* 44 */
+ { CS_PEERMODE, RO, "peermode" }, /* 45 */
+ { CS_BCASTDELAY, RO, "bcastdelay" }, /* 46 */
+ { CS_AUTHDELAY, RO, "authdelay" }, /* 47 */
+ { CS_AUTHKEYS, RO, "authkeys" }, /* 48 */
+ { CS_AUTHFREEK, RO, "authfreek" }, /* 49 */
+ { CS_AUTHKLOOKUPS, RO, "authklookups" }, /* 50 */
+ { CS_AUTHKNOTFOUND, RO, "authknotfound" }, /* 51 */
+ { CS_AUTHKUNCACHED, RO, "authkuncached" }, /* 52 */
+ { CS_AUTHKEXPIRED, RO, "authkexpired" }, /* 53 */
+ { CS_AUTHENCRYPTS, RO, "authencrypts" }, /* 54 */
+ { CS_AUTHDECRYPTS, RO, "authdecrypts" }, /* 55 */
+ { CS_AUTHRESET, RO, "authreset" }, /* 56 */
+ { CS_K_OFFSET, RO, "koffset" }, /* 57 */
+ { CS_K_FREQ, RO, "kfreq" }, /* 58 */
+ { CS_K_MAXERR, RO, "kmaxerr" }, /* 59 */
+ { CS_K_ESTERR, RO, "kesterr" }, /* 60 */
+ { CS_K_STFLAGS, RO, "kstflags" }, /* 61 */
+ { CS_K_TIMECONST, RO, "ktimeconst" }, /* 62 */
+ { CS_K_PRECISION, RO, "kprecis" }, /* 63 */
+ { CS_K_FREQTOL, RO, "kfreqtol" }, /* 64 */
+ { CS_K_PPS_FREQ, RO, "kppsfreq" }, /* 65 */
+ { CS_K_PPS_STABIL, RO, "kppsstab" }, /* 66 */
+ { CS_K_PPS_JITTER, RO, "kppsjitter" }, /* 67 */
+ { CS_K_PPS_CALIBDUR, RO, "kppscalibdur" }, /* 68 */
+ { CS_K_PPS_CALIBS, RO, "kppscalibs" }, /* 69 */
+ { CS_K_PPS_CALIBERRS, RO, "kppscaliberrs" }, /* 70 */
+ { CS_K_PPS_JITEXC, RO, "kppsjitexc" }, /* 71 */
+ { CS_K_PPS_STBEXC, RO, "kppsstbexc" }, /* 72 */
+ { CS_IOSTATS_RESET, RO, "iostats_reset" }, /* 73 */
+ { CS_TOTAL_RBUF, RO, "total_rbuf" }, /* 74 */
+ { CS_FREE_RBUF, RO, "free_rbuf" }, /* 75 */
+ { CS_USED_RBUF, RO, "used_rbuf" }, /* 76 */
+ { CS_RBUF_LOWATER, RO, "rbuf_lowater" }, /* 77 */
+ { CS_IO_DROPPED, RO, "io_dropped" }, /* 78 */
+ { CS_IO_IGNORED, RO, "io_ignored" }, /* 79 */
+ { CS_IO_RECEIVED, RO, "io_received" }, /* 80 */
+ { CS_IO_SENT, RO, "io_sent" }, /* 81 */
+ { CS_IO_SENDFAILED, RO, "io_sendfailed" }, /* 82 */
+ { CS_IO_WAKEUPS, RO, "io_wakeups" }, /* 83 */
+ { CS_IO_GOODWAKEUPS, RO, "io_goodwakeups" }, /* 84 */
+ { CS_TIMERSTATS_RESET, RO, "timerstats_reset" },/* 85 */
+ { CS_TIMER_OVERRUNS, RO, "timer_overruns" }, /* 86 */
+ { CS_TIMER_XMTS, RO, "timer_xmts" }, /* 87 */
+ { CS_FUZZ, RO, "fuzz" }, /* 88 */
+ { CS_WANDER_THRESH, RO, "clk_wander_threshold" }, /* 89 */
+#ifdef LEAP_SMEAR
+ { CS_LEAPSMEARINTV, RO, "leapsmearinterval" }, /* 90 */
+ { CS_LEAPSMEAROFFS, RO, "leapsmearoffset" }, /* 91 */
+#endif /* LEAP_SMEAR */
+#ifdef AUTOKEY
+ { CS_FLAGS, RO, "flags" }, /* 1 + CS_MAX_NOAUTOKEY */
+ { CS_HOST, RO, "host" }, /* 2 + CS_MAX_NOAUTOKEY */
+ { CS_PUBLIC, RO, "update" }, /* 3 + CS_MAX_NOAUTOKEY */
+ { CS_CERTIF, RO, "cert" }, /* 4 + CS_MAX_NOAUTOKEY */
+ { CS_SIGNATURE, RO, "signature" }, /* 5 + CS_MAX_NOAUTOKEY */
+ { CS_REVTIME, RO, "until" }, /* 6 + CS_MAX_NOAUTOKEY */
+ { CS_IDENT, RO, "ident" }, /* 7 + CS_MAX_NOAUTOKEY */
+ { CS_DIGEST, RO, "digest" }, /* 8 + CS_MAX_NOAUTOKEY */
+#endif /* AUTOKEY */
+ { 0, EOV, "" } /* 87/95 */
};
-static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
+static struct ctl_var *ext_sys_var = NULL;
/*
* System variables we print by default (in fuzzball order,
* more-or-less)
*/
-static u_char def_sys_var[] = {
+static const u_char def_sys_var[] = {
CS_VERSION,
CS_PROCESSOR,
CS_SYSTEM,
@@ -156,27 +460,31 @@ static u_char def_sys_var[] = {
CS_PRECISION,
CS_ROOTDELAY,
CS_ROOTDISPERSION,
- CS_PEERID,
CS_REFID,
CS_REFTIME,
- CS_POLL,
CS_CLOCK,
- CS_STATE,
+ CS_PEERID,
+ CS_POLL,
+ CS_RATE,
CS_OFFSET,
CS_DRIFT,
CS_JITTER,
CS_ERROR,
CS_STABIL,
-#ifdef OPENSSL
+ CS_TAI,
+ CS_LEAPTAB,
+ CS_LEAPEND,
+ CS_LEAPSMEARINTV,
+ CS_LEAPSMEAROFFS,
+#ifdef AUTOKEY
CS_HOST,
- CS_DIGEST,
+ CS_IDENT,
CS_FLAGS,
+ CS_DIGEST,
+ CS_SIGNATURE,
CS_PUBLIC,
- CS_IDENT,
- CS_LEAPTAB,
- CS_TAI,
CS_CERTIF,
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
0
};
@@ -184,11 +492,11 @@ static u_char def_sys_var[] = {
/*
* Peer variable list
*/
-static struct ctl_var peer_var[] = {
+static const struct ctl_var peer_var[] = {
{ 0, PADDING, "" }, /* 0 */
{ CP_CONFIG, RO, "config" }, /* 1 */
{ CP_AUTHENABLE, RO, "authenable" }, /* 2 */
- { CP_AUTHENTIC, RO, "authentic" }, /* 3 */
+ { CP_AUTHENTIC, RO, "authentic" }, /* 3 */
{ CP_SRCADR, RO, "srcadr" }, /* 4 */
{ CP_SRCPORT, RO, "srcport" }, /* 5 */
{ CP_DSTADR, RO, "dstadr" }, /* 6 */
@@ -200,12 +508,12 @@ static struct ctl_var peer_var[] = {
{ CP_HPOLL, RO, "hpoll" }, /* 12 */
{ CP_PRECISION, RO, "precision" }, /* 13 */
{ CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */
- { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */
+ { CP_ROOTDISPERSION, RO, "rootdisp" }, /* 15 */
{ CP_REFID, RO, "refid" }, /* 16 */
{ CP_REFTIME, RO, "reftime" }, /* 17 */
{ CP_ORG, RO, "org" }, /* 18 */
{ CP_REC, RO, "rec" }, /* 19 */
- { CP_XMT, RO, "xmt" }, /* 20 */
+ { CP_XMT, RO, "xleave" }, /* 20 */
{ CP_REACH, RO, "reach" }, /* 21 */
{ CP_UNREACH, RO, "unreach" }, /* 22 */
{ CP_TIMER, RO, "timer" }, /* 23 */
@@ -214,49 +522,68 @@ static struct ctl_var peer_var[] = {
{ CP_JITTER, RO, "jitter" }, /* 26 */
{ CP_DISPERSION, RO, "dispersion" }, /* 27 */
{ CP_KEYID, RO, "keyid" }, /* 28 */
- { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */
- { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */
+ { CP_FILTDELAY, RO, "filtdelay" }, /* 29 */
+ { CP_FILTOFFSET, RO, "filtoffset" }, /* 30 */
{ CP_PMODE, RO, "pmode" }, /* 31 */
{ CP_RECEIVED, RO, "received"}, /* 32 */
{ CP_SENT, RO, "sent" }, /* 33 */
- { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */
+ { CP_FILTERROR, RO, "filtdisp" }, /* 34 */
{ CP_FLASH, RO, "flash" }, /* 35 */
{ CP_TTL, RO, "ttl" }, /* 36 */
{ CP_VARLIST, RO, "peer_var_list" }, /* 37 */
-#ifdef OPENSSL
- { CP_FLAGS, RO, "flags" }, /* 38 */
- { CP_HOST, RO, "hostname" }, /* 39 */
- { CP_VALID, RO, "valid" }, /* 40 */
- { CP_INITSEQ, RO, "initsequence" }, /* 41 */
- { CP_INITKEY, RO, "initkey" }, /* 42 */
- { CP_INITTSP, RO, "timestamp" }, /* 43 */
- { CP_DIGEST, RO, "signature" }, /* 44 */
- { CP_IDENT, RO, "trust" }, /* 45 */
-#endif /* OPENSSL */
- { 0, EOV, "" } /* 38/46 */
+ { CP_IN, RO, "in" }, /* 38 */
+ { CP_OUT, RO, "out" }, /* 39 */
+ { CP_RATE, RO, "headway" }, /* 40 */
+ { CP_BIAS, RO, "bias" }, /* 41 */
+ { CP_SRCHOST, RO, "srchost" }, /* 42 */
+ { CP_TIMEREC, RO, "timerec" }, /* 43 */
+ { CP_TIMEREACH, RO, "timereach" }, /* 44 */
+ { CP_BADAUTH, RO, "badauth" }, /* 45 */
+ { CP_BOGUSORG, RO, "bogusorg" }, /* 46 */
+ { CP_OLDPKT, RO, "oldpkt" }, /* 47 */
+ { CP_SELDISP, RO, "seldisp" }, /* 48 */
+ { CP_SELBROKEN, RO, "selbroken" }, /* 49 */
+ { CP_CANDIDATE, RO, "candidate" }, /* 50 */
+#ifdef AUTOKEY
+ { CP_FLAGS, RO, "flags" }, /* 1 + CP_MAX_NOAUTOKEY */
+ { CP_HOST, RO, "host" }, /* 2 + CP_MAX_NOAUTOKEY */
+ { CP_VALID, RO, "valid" }, /* 3 + CP_MAX_NOAUTOKEY */
+ { CP_INITSEQ, RO, "initsequence" }, /* 4 + CP_MAX_NOAUTOKEY */
+ { CP_INITKEY, RO, "initkey" }, /* 5 + CP_MAX_NOAUTOKEY */
+ { CP_INITTSP, RO, "timestamp" }, /* 6 + CP_MAX_NOAUTOKEY */
+ { CP_SIGNATURE, RO, "signature" }, /* 7 + CP_MAX_NOAUTOKEY */
+ { CP_IDENT, RO, "ident" }, /* 8 + CP_MAX_NOAUTOKEY */
+#endif /* AUTOKEY */
+ { 0, EOV, "" } /* 50/58 */
};
/*
* Peer variables we print by default
*/
-static u_char def_peer_var[] = {
+static const u_char def_peer_var[] = {
CP_SRCADR,
CP_SRCPORT,
+ CP_SRCHOST,
CP_DSTADR,
CP_DSTPORT,
+ CP_OUT,
+ CP_IN,
CP_LEAP,
CP_STRATUM,
CP_PRECISION,
CP_ROOTDELAY,
CP_ROOTDISPERSION,
CP_REFID,
+ CP_REFTIME,
+ CP_REC,
CP_REACH,
CP_UNREACH,
CP_HMODE,
CP_PMODE,
CP_HPOLL,
CP_PPOLL,
+ CP_RATE,
CP_FLASH,
CP_KEYID,
CP_TTL,
@@ -264,21 +591,19 @@ static u_char def_peer_var[] = {
CP_DELAY,
CP_DISPERSION,
CP_JITTER,
- CP_REFTIME,
- CP_ORG,
- CP_REC,
CP_XMT,
+ CP_BIAS,
CP_FILTDELAY,
CP_FILTOFFSET,
CP_FILTERROR,
-#ifdef OPENSSL
+#ifdef AUTOKEY
CP_HOST,
- CP_DIGEST,
- CP_VALID,
CP_FLAGS,
- CP_IDENT,
+ CP_SIGNATURE,
+ CP_VALID,
CP_INITSEQ,
-#endif /* OPENSSL */
+ CP_IDENT,
+#endif /* AUTOKEY */
0
};
@@ -287,7 +612,7 @@ static u_char def_peer_var[] = {
/*
* Clock variable list
*/
-static struct ctl_var clock_var[] = {
+static const struct ctl_var clock_var[] = {
{ 0, PADDING, "" }, /* 0 */
{ CC_TYPE, RO, "type" }, /* 1 */
{ CC_TIMECODE, RO, "timecode" }, /* 2 */
@@ -309,7 +634,7 @@ static struct ctl_var clock_var[] = {
/*
* Clock variables printed by default
*/
-static u_char def_clock_var[] = {
+static const u_char def_clock_var[] = {
CC_DEVICE,
CC_TYPE, /* won't be output if device = known */
CC_TIMECODE,
@@ -326,6 +651,11 @@ static u_char def_clock_var[] = {
};
#endif
+/*
+ * MRU string constants shared by send_mru_entry() and read_mru_list().
+ */
+static const char addr_fmt[] = "addr.%d";
+static const char last_fmt[] = "last.%d";
/*
* System and processor definitions.
@@ -335,11 +665,11 @@ static u_char def_clock_var[] = {
# define STR_SYSTEM "UNIX"
# endif
# ifndef STR_PROCESSOR
-# define STR_PROCESSOR "unknown"
+# define STR_PROCESSOR "unknown"
# endif
-static char str_system[] = STR_SYSTEM;
-static char str_processor[] = STR_PROCESSOR;
+static const char str_system[] = STR_SYSTEM;
+static const char str_processor[] = STR_PROCESSOR;
#else
# include <sys/utsname.h>
static struct utsname utsnamebuf;
@@ -352,7 +682,7 @@ static struct utsname utsnamebuf;
* timed out.
*/
/* ntp_request.c */
-struct ctl_trap ctl_trap[CTL_MAXTRAPS];
+struct ctl_trap ctl_traps[CTL_MAXTRAPS];
int num_ctl_traps;
/*
@@ -369,53 +699,57 @@ int num_ctl_traps;
* the reference clock driver doesn't set peer->sstclktype to something
* different than CTL_SST_TS_UNSPEC.
*/
-static u_char clocktypes[] = {
- CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
+#ifdef REFCLOCK
+static const u_char clocktypes[] = {
+ CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */
- CTL_SST_TS_UHF, /* deprecated REFCLK_GPS_TRAK (2) */
+ CTL_SST_TS_UHF, /* deprecated REFCLK_GPS_TRAK (2) */
CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */
CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */
- CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */
- CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) IRIG_AUDIO? */
+ CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */
+ CTL_SST_TS_UHF, /* REFCLK_IRIG_AUDIO (6) */
CTL_SST_TS_HF, /* REFCLK_CHU (7) */
CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */
CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */
- CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */
+ CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */
CTL_SST_TS_LF, /* deprecated REFCLK_MSF_EES (14) */
- CTL_SST_TS_NTP, /* not used (15) */
- CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
+ CTL_SST_TS_NTP, /* not used (15) */
+ CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */
CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */
CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */
CTL_SST_TS_NTP, /* not used (23) */
CTL_SST_TS_NTP, /* not used (24) */
- CTL_SST_TS_NTP, /* not used (25) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */
- CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */
- CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */
- CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */
- CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */
+ CTL_SST_TS_NTP, /* not used (25) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */
+ CTL_SST_TS_LF, /* REFCLK_ARCRON_MSF (27) */
+ CTL_SST_TS_UHF, /* REFCLK_SHM (28) */
+ CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */
+ CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */
CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */
CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */
CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (33) */
CTL_SST_TS_LF, /* REFCLK_ULINK (34) */
CTL_SST_TS_LF, /* REFCLK_PCF (35) */
- CTL_SST_TS_LF, /* REFCLK_WWV (36) */
+ CTL_SST_TS_HF, /* REFCLK_WWV (36) */
CTL_SST_TS_LF, /* REFCLK_FG (37) */
- CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */
+ CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */
CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */
CTL_SST_TS_LF, /* REFCLK_JJY (40) */
CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */
CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */
CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */
CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */
+ CTL_SST_TS_UHF, /* REFCLK_TSYNCPCI (45) */
+ CTL_SST_TS_UHF /* REFCLK_GPSDJSON (46) */
};
+#endif /* REFCLOCK */
/*
@@ -436,17 +770,17 @@ static u_char ctl_sys_num_events;
u_long ctltimereset; /* time stats reset */
u_long numctlreq; /* number of requests we've received */
u_long numctlbadpkts; /* number of bad control packets */
-u_long numctlresponses; /* number of resp packets sent with data */
-u_long numctlfrags; /* number of fragments sent */
+u_long numctlresponses; /* number of resp packets sent with data */
+u_long numctlfrags; /* number of fragments sent */
u_long numctlerrors; /* number of error responses sent */
u_long numctltooshort; /* number of too short input packets */
-u_long numctlinputresp; /* number of responses on input */
-u_long numctlinputfrag; /* number of fragments on input */
+u_long numctlinputresp; /* number of responses on input */
+u_long numctlinputfrag; /* number of fragments on input */
u_long numctlinputerr; /* number of input pkts with err bit set */
-u_long numctlbadoffset; /* number of input pkts with nonzero offset */
+u_long numctlbadoffset; /* number of input pkts with nonzero offset */
u_long numctlbadversion; /* number of input pkts with unknown version */
u_long numctldatatooshort; /* data too short for count */
-u_long numctlbadop; /* bad op code found in packet */
+u_long numctlbadop; /* bad op code found in packet */
u_long numasyncmsgs; /* number of async messages we've sent */
/*
@@ -460,12 +794,14 @@ static struct ntp_control rpkt;
static u_char res_version;
static u_char res_opcode;
static associd_t res_associd;
-static int res_offset;
+static u_short res_frags; /* datagrams in this response */
+static int res_offset; /* offset of payload in response */
static u_char * datapt;
static u_char * dataend;
static int datalinelen;
+static int datasent; /* flag to avoid initial ", " */
static int datanotbinflag;
-static struct sockaddr_storage *rmt_addr;
+static sockaddr_u *rmt_addr;
static struct interface *lcl_inter;
static u_char res_authenticate;
@@ -474,7 +810,7 @@ static keyid_t res_keyid;
#define MAXDATALINELEN (72)
-static u_char res_async; /* set to 1 if this is async trap response */
+static u_char res_async; /* sending async trap response? */
/*
* Pointers for saving state when decoding request packets
@@ -482,13 +818,17 @@ static u_char res_async; /* set to 1 if this is async trap response */
static char *reqpt;
static char *reqend;
+#ifndef MIN
+#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
+#endif
+
/*
* init_control - initialize request data
*/
void
init_control(void)
{
- int i;
+ size_t i;
#ifdef HAVE_UNAME
uname(&utsnamebuf);
@@ -501,8 +841,8 @@ init_control(void)
ctl_sys_num_events = 0;
num_ctl_traps = 0;
- for (i = 0; i < CTL_MAXTRAPS; i++)
- ctl_trap[i].tr_flags = 0;
+ for (i = 0; i < COUNTOF(ctl_traps); i++)
+ ctl_traps[i].tr_flags = 0;
}
@@ -511,39 +851,162 @@ init_control(void)
*/
static void
ctl_error(
- int errcode
+ u_char errcode
)
{
-#ifdef DEBUG
- if (debug >= 4)
- printf("sending control error %d\n", errcode);
-#endif
+ int maclen;
+
+ numctlerrors++;
+ DPRINTF(3, ("sending control error %u\n", errcode));
+
/*
* Fill in the fields. We assume rpkt.sequence and rpkt.associd
* have already been filled in.
*/
- rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode &
- CTL_OP_MASK));
- rpkt.status = htons((u_short) ((errcode<<8) & 0xff00));
+ rpkt.r_m_e_op = (u_char)CTL_RESPONSE | CTL_ERROR |
+ (res_opcode & CTL_OP_MASK);
+ rpkt.status = htons((u_short)(errcode << 8) & 0xff00);
rpkt.count = 0;
/*
* send packet and bump counters
*/
if (res_authenticate && sys_authenticate) {
- int maclen;
-
- *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) =
- htonl(res_keyid);
maclen = authencrypt(res_keyid, (u_int32 *)&rpkt,
- CTL_HEADER_LEN);
- sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
- CTL_HEADER_LEN + maclen);
+ CTL_HEADER_LEN);
+ sendpkt(rmt_addr, lcl_inter, -2, (void *)&rpkt,
+ CTL_HEADER_LEN + maclen);
+ } else
+ sendpkt(rmt_addr, lcl_inter, -3, (void *)&rpkt,
+ CTL_HEADER_LEN);
+}
+
+/*
+ * save_config - Implements ntpq -c "saveconfig <filename>"
+ * Writes current configuration including any runtime
+ * changes by ntpq's :config or config-from-file
+ */
+void
+save_config(
+ struct recvbuf *rbufp,
+ int restrict_mask
+ )
+{
+ char reply[128];
+#ifdef SAVECONFIG
+ char filespec[128];
+ char filename[128];
+ char fullpath[512];
+ const char savedconfig_eq[] = "savedconfig=";
+ char savedconfig[sizeof(savedconfig_eq) + sizeof(filename)];
+ time_t now;
+ int fd;
+ FILE *fptr;
+#endif
+
+ if (RES_NOMODIFY & restrict_mask) {
+ snprintf(reply, sizeof(reply),
+ "saveconfig prohibited by restrict ... nomodify");
+ ctl_putdata(reply, strlen(reply), 0);
+ ctl_flushpkt(0);
+ NLOG(NLOG_SYSINFO)
+ msyslog(LOG_NOTICE,
+ "saveconfig from %s rejected due to nomodify restriction",
+ stoa(&rbufp->recv_srcadr));
+ sys_restricted++;
+ return;
+ }
+
+#ifdef SAVECONFIG
+ if (NULL == saveconfigdir) {
+ snprintf(reply, sizeof(reply),
+ "saveconfig prohibited, no saveconfigdir configured");
+ ctl_putdata(reply, strlen(reply), 0);
+ ctl_flushpkt(0);
+ NLOG(NLOG_SYSINFO)
+ msyslog(LOG_NOTICE,
+ "saveconfig from %s rejected, no saveconfigdir",
+ stoa(&rbufp->recv_srcadr));
+ return;
+ }
+
+ if (0 == reqend - reqpt)
+ return;
+
+ strlcpy(filespec, reqpt, sizeof(filespec));
+ time(&now);
+
+ /*
+ * allow timestamping of the saved config filename with
+ * strftime() format such as:
+ * ntpq -c "saveconfig ntp-%Y%m%d-%H%M%S.conf"
+ * XXX: Nice feature, but not too safe.
+ */
+ if (0 == strftime(filename, sizeof(filename), filespec,
+ localtime(&now)))
+ strlcpy(filename, filespec, sizeof(filename));
+
+ /*
+ * Conceptually we should be searching for DIRSEP in filename,
+ * however Windows actually recognizes both forward and
+ * backslashes as equivalent directory separators at the API
+ * level. On POSIX systems we could allow '\\' but such
+ * filenames are tricky to manipulate from a shell, so just
+ * reject both types of slashes on all platforms.
+ */
+ if (strchr(filename, '\\') || strchr(filename, '/')) {
+ snprintf(reply, sizeof(reply),
+ "saveconfig does not allow directory in filename");
+ ctl_putdata(reply, strlen(reply), 0);
+ ctl_flushpkt(0);
+ msyslog(LOG_NOTICE,
+ "saveconfig with path from %s rejected",
+ stoa(&rbufp->recv_srcadr));
+ return;
+ }
+
+ snprintf(fullpath, sizeof(fullpath), "%s%s",
+ saveconfigdir, filename);
+
+ fd = open(fullpath, O_CREAT | O_TRUNC | O_WRONLY,
+ S_IRUSR | S_IWUSR);
+ if (-1 == fd)
+ fptr = NULL;
+ else
+ fptr = fdopen(fd, "w");
+
+ if (NULL == fptr || -1 == dump_all_config_trees(fptr, 1)) {
+ snprintf(reply, sizeof(reply),
+ "Unable to save configuration to file %s",
+ filename);
+ msyslog(LOG_ERR,
+ "saveconfig %s from %s failed", filename,
+ stoa(&rbufp->recv_srcadr));
} else {
- sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
- CTL_HEADER_LEN);
+ snprintf(reply, sizeof(reply),
+ "Configuration saved to %s", filename);
+ msyslog(LOG_NOTICE,
+ "Configuration saved to %s (requested by %s)",
+ fullpath, stoa(&rbufp->recv_srcadr));
+ /*
+ * save the output filename in system variable
+ * savedconfig, retrieved with:
+ * ntpq -c "rv 0 savedconfig"
+ */
+ snprintf(savedconfig, sizeof(savedconfig), "%s%s",
+ savedconfig_eq, filename);
+ set_sys_var(savedconfig, strlen(savedconfig) + 1, RO);
}
- numctlerrors++;
+
+ if (NULL != fptr)
+ fclose(fptr);
+#else /* !SAVECONFIG follows */
+ snprintf(reply, sizeof(reply),
+ "saveconfig unavailable, configured with --disable-saveconfig");
+#endif
+
+ ctl_putdata(reply, strlen(reply), 0);
+ ctl_flushpkt(0);
}
@@ -556,17 +1019,15 @@ process_control(
int restrict_mask
)
{
- register struct ntp_control *pkt;
- register int req_count;
- register int req_data;
- register struct ctl_proc *cc;
+ struct ntp_control *pkt;
+ int req_count;
+ int req_data;
+ const struct ctl_proc *cc;
+ keyid_t *pkid;
int properlen;
- int maclen;
+ size_t maclen;
-#ifdef DEBUG
- if (debug > 2)
- printf("in process_control()\n");
-#endif
+ DPRINTF(3, ("in process_control()\n"));
/*
* Save the addresses for error responses
@@ -580,20 +1041,17 @@ process_control(
* If the length is less than required for the header, or
* it is a response or a fragment, ignore this.
*/
- if (rbufp->recv_length < CTL_HEADER_LEN
- || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR)
+ if (rbufp->recv_length < (int)CTL_HEADER_LEN
+ || (CTL_RESPONSE | CTL_MORE | CTL_ERROR) & pkt->r_m_e_op
|| pkt->offset != 0) {
-#ifdef DEBUG
- if (debug)
- printf("invalid format in control packet\n");
-#endif
- if (rbufp->recv_length < CTL_HEADER_LEN)
+ DPRINTF(1, ("invalid format in control packet\n"));
+ if (rbufp->recv_length < (int)CTL_HEADER_LEN)
numctltooshort++;
- if (pkt->r_m_e_op & CTL_RESPONSE)
+ if (CTL_RESPONSE & pkt->r_m_e_op)
numctlinputresp++;
- if (pkt->r_m_e_op & CTL_MORE)
+ if (CTL_MORE & pkt->r_m_e_op)
numctlinputfrag++;
- if (pkt->r_m_e_op & CTL_ERROR)
+ if (CTL_ERROR & pkt->r_m_e_op)
numctlinputerr++;
if (pkt->offset != 0)
numctlbadoffset++;
@@ -601,11 +1059,8 @@ process_control(
}
res_version = PKT_VERSION(pkt->li_vn_mode);
if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {
-#ifdef DEBUG
- if (debug)
- printf("unknown version %d in control packet\n",
- res_version);
-#endif
+ DPRINTF(1, ("unknown version %d in control packet\n",
+ res_version));
numctlbadversion++;
return;
}
@@ -615,22 +1070,28 @@ process_control(
* responses
*/
rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version,
- MODE_CONTROL);
+ MODE_CONTROL);
res_opcode = pkt->r_m_e_op;
rpkt.sequence = pkt->sequence;
rpkt.associd = pkt->associd;
rpkt.status = 0;
+ res_frags = 1;
res_offset = 0;
res_associd = htons(pkt->associd);
- res_async = 0;
- res_authenticate = 0;
+ res_async = FALSE;
+ res_authenticate = FALSE;
res_keyid = 0;
- res_authokay = 0;
- req_count = (int)htons(pkt->count);
- datanotbinflag = 0;
+ res_authokay = FALSE;
+ req_count = (int)ntohs(pkt->count);
+ datanotbinflag = FALSE;
datalinelen = 0;
- datapt = rpkt.data;
- dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
+ datasent = 0;
+ datapt = rpkt.u.data;
+ dataend = &rpkt.u.data[CTL_MAX_DATA_LEN];
+
+ if ((rbufp->recv_length & 0x3) != 0)
+ DPRINTF(3, ("Control packet length %d unrounded\n",
+ rbufp->recv_length));
/*
* We're set up now. Make sure we've got at least enough
@@ -644,54 +1105,37 @@ process_control(
}
properlen = req_count + CTL_HEADER_LEN;
-#ifdef DEBUG
- if (debug > 2 && (rbufp->recv_length & 0x3) != 0)
- printf("Packet length %d unrounded\n",
- rbufp->recv_length);
-#endif
/* round up proper len to a 8 octet boundary */
properlen = (properlen + 7) & ~7;
maclen = rbufp->recv_length - properlen;
- if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 &&
+ if ((rbufp->recv_length & 3) == 0 &&
maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN &&
sys_authenticate) {
- res_authenticate = 1;
- res_keyid = ntohl(*(u_int32 *)((u_char *)pkt +
- properlen));
-
-#ifdef DEBUG
- if (debug > 2)
- printf(
- "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
- rbufp->recv_length, properlen, res_keyid, maclen);
-#endif
- if (!authistrusted(res_keyid)) {
-#ifdef DEBUG
- if (debug > 2)
- printf("invalid keyid %08x\n",
- res_keyid);
-#endif
- } else if (authdecrypt(res_keyid, (u_int32 *)pkt,
- rbufp->recv_length - maclen, maclen)) {
-#ifdef DEBUG
- if (debug > 2)
- printf("authenticated okay\n");
-#endif
- res_authokay = 1;
+ res_authenticate = TRUE;
+ pkid = (void *)((char *)pkt + properlen);
+ res_keyid = ntohl(*pkid);
+ DPRINTF(3, ("recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%zu\n",
+ rbufp->recv_length, properlen, res_keyid,
+ maclen));
+
+ if (!authistrusted(res_keyid))
+ DPRINTF(3, ("invalid keyid %08x\n", res_keyid));
+ else if (authdecrypt(res_keyid, (u_int32 *)pkt,
+ rbufp->recv_length - maclen,
+ maclen)) {
+ res_authokay = TRUE;
+ DPRINTF(3, ("authenticated okay\n"));
} else {
-#ifdef DEBUG
- if (debug > 2)
- printf("authentication failed\n");
-#endif
res_keyid = 0;
+ DPRINTF(3, ("authentication failed\n"));
}
}
/*
* Set up translate pointers
*/
- reqpt = (char *)pkt->data;
+ reqpt = (char *)pkt->u.data;
reqend = reqpt + req_count;
/*
@@ -699,13 +1143,11 @@ process_control(
*/
for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) {
if (cc->control_code == res_opcode) {
-#ifdef DEBUG
- if (debug > 2)
- printf("opcode %d, found command handler\n",
- res_opcode);
-#endif
- if (cc->flags == AUTH && (!res_authokay ||
- res_keyid != ctl_auth_keyid)) {
+ DPRINTF(3, ("opcode %d, found command handler\n",
+ res_opcode));
+ if (cc->flags == AUTH
+ && (!res_authokay
+ || res_keyid != ctl_auth_keyid)) {
ctl_error(CERR_PERMISSION);
return;
}
@@ -728,22 +1170,24 @@ process_control(
*/
u_short
ctlpeerstatus(
- register struct peer *peer
+ register struct peer *p
)
{
- register u_short status;
+ u_short status;
- status = peer->status;
- if (peer->flags & FLAG_CONFIG)
+ status = p->status;
+ if (FLAG_CONFIG & p->flags)
status |= CTL_PST_CONFIG;
- if (peer->flags & FLAG_AUTHENABLE)
+ if (p->keyid)
status |= CTL_PST_AUTHENABLE;
- if (peer->flags & FLAG_AUTHENTIC)
+ if (FLAG_AUTHENTIC & p->flags)
status |= CTL_PST_AUTHENTIC;
- if (peer->reach != 0)
+ if (p->reach)
status |= CTL_PST_REACH;
- return (u_short)CTL_PEER_STATUS(status, peer->num_events,
- peer->last_event);
+ if (MDF_TXONLY_MASK & p->cast_flags)
+ status |= CTL_PST_BCAST;
+
+ return CTL_PEER_STATUS(status, p->num_events, p->last_event);
}
@@ -753,11 +1197,10 @@ ctlpeerstatus(
#ifdef REFCLOCK
static u_short
ctlclkstatus(
- struct refclockstat *this_clock
+ struct refclockstat *pcs
)
{
- return ((u_short)(((this_clock->currentstatus) << 8) |
- (this_clock->lastevent)));
+ return CTL_PEER_STATUS(0, pcs->lastevent, pcs->currentstatus);
}
#endif
@@ -772,22 +1215,18 @@ ctlsysstatus(void)
this_clock = CTL_SST_TS_UNSPEC;
#ifdef REFCLOCK
- if (sys_peer != 0) {
- if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
+ if (sys_peer != NULL) {
+ if (CTL_SST_TS_UNSPEC != sys_peer->sstclktype)
this_clock = sys_peer->sstclktype;
- if (pps_control)
- this_clock |= CTL_SST_TS_PPS;
- } else {
- if (sys_peer->refclktype < sizeof(clocktypes))
- this_clock =
- clocktypes[sys_peer->refclktype];
- if (pps_control)
- this_clock |= CTL_SST_TS_PPS;
- }
+ else if (sys_peer->refclktype < COUNTOF(clocktypes))
+ this_clock = clocktypes[sys_peer->refclktype];
}
+#else /* REFCLOCK */
+ if (sys_peer != 0)
+ this_clock = CTL_SST_TS_NTP;
#endif /* REFCLOCK */
- return (u_short)CTL_SYS_STATUS(sys_leap, this_clock,
- ctl_sys_num_events, ctl_sys_last_event);
+ return CTL_SYS_STATUS(sys_leap, this_clock, ctl_sys_num_events,
+ ctl_sys_last_event);
}
@@ -797,20 +1236,25 @@ ctlsysstatus(void)
*/
static void
ctl_flushpkt(
- int more
+ u_char more
)
{
+ size_t i;
int dlen;
int sendlen;
+ int maclen;
+ int totlen;
+ keyid_t keyid;
- if (!more && datanotbinflag) {
+ dlen = datapt - rpkt.u.data;
+ if (!more && datanotbinflag && dlen + 2 < CTL_MAX_DATA_LEN) {
/*
* Big hack, output a trailing \r\n
*/
*datapt++ = '\r';
*datapt++ = '\n';
+ dlen += 2;
}
- dlen = datapt - (u_char *)rpkt.data;
sendlen = dlen + CTL_HEADER_LEN;
/*
@@ -824,35 +1268,31 @@ ctl_flushpkt(
/*
* Fill in the packet with the current info
*/
- rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode &
- CTL_OP_MASK));
- rpkt.count = htons((u_short) dlen);
- rpkt.offset = htons( (u_short) res_offset);
+ rpkt.r_m_e_op = CTL_RESPONSE | more |
+ (res_opcode & CTL_OP_MASK);
+ rpkt.count = htons((u_short)dlen);
+ rpkt.offset = htons((u_short)res_offset);
if (res_async) {
- register int i;
-
- for (i = 0; i < CTL_MAXTRAPS; i++) {
- if (ctl_trap[i].tr_flags & TRAP_INUSE) {
+ for (i = 0; i < COUNTOF(ctl_traps); i++) {
+ if (TRAP_INUSE & ctl_traps[i].tr_flags) {
rpkt.li_vn_mode =
- PKT_LI_VN_MODE(sys_leap,
- ctl_trap[i].tr_version,
- MODE_CONTROL);
+ PKT_LI_VN_MODE(
+ sys_leap,
+ ctl_traps[i].tr_version,
+ MODE_CONTROL);
rpkt.sequence =
- htons(ctl_trap[i].tr_sequence);
- sendpkt(&ctl_trap[i].tr_addr,
- ctl_trap[i].tr_localaddr, -4,
+ htons(ctl_traps[i].tr_sequence);
+ sendpkt(&ctl_traps[i].tr_addr,
+ ctl_traps[i].tr_localaddr, -4,
(struct pkt *)&rpkt, sendlen);
if (!more)
- ctl_trap[i].tr_sequence++;
+ ctl_traps[i].tr_sequence++;
numasyncmsgs++;
}
}
} else {
if (res_authenticate && sys_authenticate) {
- int maclen;
- int totlen = sendlen;
- keyid_t keyid = htonl(res_keyid);
-
+ totlen = sendlen;
/*
* If we are going to authenticate, then there
* is an additional requirement that the MAC
@@ -862,14 +1302,15 @@ ctl_flushpkt(
*datapt++ = '\0';
totlen++;
}
- memcpy(datapt, &keyid, sizeof keyid);
+ keyid = htonl(res_keyid);
+ memcpy(datapt, &keyid, sizeof(keyid));
maclen = authencrypt(res_keyid,
- (u_int32 *)&rpkt, totlen);
+ (u_int32 *)&rpkt, totlen);
sendpkt(rmt_addr, lcl_inter, -5,
- (struct pkt *)&rpkt, totlen + maclen);
+ (struct pkt *)&rpkt, totlen + maclen);
} else {
sendpkt(rmt_addr, lcl_inter, -6,
- (struct pkt *)&rpkt, sendlen);
+ (struct pkt *)&rpkt, sendlen);
}
if (more)
numctlfrags++;
@@ -880,8 +1321,9 @@ ctl_flushpkt(
/*
* Set us up for another go around.
*/
+ res_frags++;
res_offset += dlen;
- datapt = (u_char *)rpkt.data;
+ datapt = rpkt.u.data;
}
@@ -893,7 +1335,7 @@ static void
ctl_putdata(
const char *dp,
unsigned int dlen,
- int bin /* set to 1 when data is binary */
+ int bin /* set to 1 when data is binary */
)
{
int overhead;
@@ -901,13 +1343,12 @@ ctl_putdata(
overhead = 0;
if (!bin) {
- datanotbinflag = 1;
+ datanotbinflag = TRUE;
overhead = 3;
- if (datapt != rpkt.data) {
+ if (datasent) {
*datapt++ = ',';
datalinelen++;
- if ((dlen + datalinelen + 1) >= MAXDATALINELEN)
- {
+ if ((dlen + datalinelen + 1) >= MAXDATALINELEN) {
*datapt++ = '\r';
*datapt++ = '\n';
datalinelen = 0;
@@ -925,7 +1366,7 @@ ctl_putdata(
/*
* Not enough room in this one, flush it out.
*/
- currentlen = MIN(dlen, dataend - datapt);
+ currentlen = MIN(dlen, (unsigned int)(dataend - datapt));
memcpy(datapt, dp, currentlen);
@@ -937,54 +1378,94 @@ ctl_putdata(
ctl_flushpkt(CTL_MORE);
}
- memmove((char *)datapt, dp, (unsigned)dlen);
+ memcpy(datapt, dp, dlen);
datapt += dlen;
datalinelen += dlen;
+ datasent = TRUE;
}
/*
* ctl_putstr - write a tagged string into the response packet
+ * in the form:
+ *
+ * tag="data"
+ *
+ * len is the data length excluding the NUL terminator,
+ * as in ctl_putstr("var", "value", strlen("value"));
*/
static void
ctl_putstr(
- const char *tag,
- const char *data,
- unsigned int len
+ const char * tag,
+ const char * data,
+ size_t len
)
{
- register char *cp;
- register const char *cq;
- char buffer[400];
+ char buffer[512];
+ char *cp;
+ size_t tl;
- cp = buffer;
- cq = tag;
- while (*cq != '\0')
- *cp++ = *cq++;
+ tl = strlen(tag);
+ memcpy(buffer, tag, tl);
+ cp = buffer + tl;
if (len > 0) {
+ NTP_INSIST(tl + 3 + len <= sizeof(buffer));
*cp++ = '=';
*cp++ = '"';
- if (len > (int) (sizeof(buffer) - (cp - buffer) - 1))
- len = sizeof(buffer) - (cp - buffer) - 1;
- memmove(cp, data, (unsigned)len);
+ memcpy(cp, data, len);
cp += len;
*cp++ = '"';
}
- ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+ ctl_putdata(buffer, (u_int)(cp - buffer), 0);
}
/*
- * ctl_putdbl - write a tagged, signed double into the response packet
+ * ctl_putunqstr - write a tagged string into the response packet
+ * in the form:
+ *
+ * tag=data
+ *
+ * len is the data length excluding the NUL terminator.
+ * data must not contain a comma or whitespace.
*/
static void
-ctl_putdbl(
- const char *tag,
- double ts
+ctl_putunqstr(
+ const char * tag,
+ const char * data,
+ size_t len
)
{
- register char *cp;
- register const char *cq;
+ char buffer[512];
+ char *cp;
+ size_t tl;
+
+ tl = strlen(tag);
+ memcpy(buffer, tag, tl);
+ cp = buffer + tl;
+ if (len > 0) {
+ NTP_INSIST(tl + 1 + len <= sizeof(buffer));
+ *cp++ = '=';
+ memcpy(cp, data, len);
+ cp += len;
+ }
+ ctl_putdata(buffer, (u_int)(cp - buffer), 0);
+}
+
+
+/*
+ * ctl_putdblf - write a tagged, signed double into the response packet
+ */
+static void
+ctl_putdblf(
+ const char * tag,
+ int use_f,
+ int precision,
+ double d
+ )
+{
+ char *cp;
+ const char *cq;
char buffer[200];
cp = buffer;
@@ -992,10 +1473,11 @@ ctl_putdbl(
while (*cq != '\0')
*cp++ = *cq++;
*cp++ = '=';
- (void)sprintf(cp, "%.3f", ts);
- while (*cp != '\0')
- cp++;
- ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+ NTP_INSIST((size_t)(cp - buffer) < sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer), use_f ? "%.*f" : "%.*g",
+ precision, d);
+ cp += strlen(cp);
+ ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
}
/*
@@ -1017,16 +1499,42 @@ ctl_putuint(
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "%lu", uval);
- while (*cp != '\0')
- cp++;
+ NTP_INSIST((cp - buffer) < (int)sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer), "%lu", uval);
+ cp += strlen(cp);
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
}
/*
+ * ctl_putcal - write a decoded calendar data into the response
+ */
+static void
+ctl_putcal(
+ const char *tag,
+ const struct calendar *pcal
+ )
+{
+ char buffer[100];
+ unsigned numch;
+
+ numch = snprintf(buffer, sizeof(buffer),
+ "%s=%04d%02d%02d%02d%02d",
+ tag,
+ pcal->year,
+ pcal->month,
+ pcal->monthday,
+ pcal->hour,
+ pcal->minute
+ );
+ NTP_INSIST(numch < sizeof(buffer));
+ ctl_putdata(buffer, numch, 0);
+
+ return;
+}
+
+/*
* ctl_putfs - write a decoded filestamp into the response
*/
-#ifdef OPENSSL
static void
ctl_putfs(
const char *tag,
@@ -1047,20 +1555,20 @@ ctl_putfs(
*cp++ = '=';
fstamp = uval - JAN_1970;
tm = gmtime(&fstamp);
- if (tm == NULL)
+ if (NULL == tm)
return;
-
- sprintf(cp, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
- tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
- while (*cp != '\0')
- cp++;
+ NTP_INSIST((cp - buffer) < (int)sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer),
+ "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
+ tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+ cp += strlen(cp);
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
}
-#endif
/*
- * ctl_puthex - write a tagged unsigned integer, in hex, into the response
+ * ctl_puthex - write a tagged unsigned integer, in hex, into the
+ * response
*/
static void
ctl_puthex(
@@ -1078,9 +1586,9 @@ ctl_puthex(
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "0x%lx", uval);
- while (*cp != '\0')
- cp++;
+ NTP_INSIST((cp - buffer) < (int)sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer), "0x%lx", uval);
+ cp += strlen(cp);
ctl_putdata(buffer,(unsigned)( cp - buffer ), 0);
}
@@ -1104,9 +1612,9 @@ ctl_putint(
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "%ld", ival);
- while (*cp != '\0')
- cp++;
+ NTP_INSIST((cp - buffer) < (int)sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer), "%ld", ival);
+ cp += strlen(cp);
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
}
@@ -1130,11 +1638,10 @@ ctl_putts(
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "0x%08lx.%08lx",
- ts->l_ui & ULONG_CONST(0xffffffff),
- ts->l_uf & ULONG_CONST(0xffffffff));
- while (*cp != '\0')
- cp++;
+ NTP_INSIST((size_t)(cp - buffer) < sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer), "0x%08x.%08x",
+ (u_int)ts->l_ui, (u_int)ts->l_uf);
+ cp += strlen(cp);
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
}
@@ -1146,7 +1653,7 @@ static void
ctl_putadr(
const char *tag,
u_int32 addr32,
- struct sockaddr_storage* addr
+ sockaddr_u *addr
)
{
register char *cp;
@@ -1159,38 +1666,54 @@ ctl_putadr(
*cp++ = *cq++;
*cp++ = '=';
- if (addr == NULL)
+ if (NULL == addr)
cq = numtoa(addr32);
else
cq = stoa(addr);
- while (*cq != '\0')
- *cp++ = *cq++;
- ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+ NTP_INSIST((cp - buffer) < (int)sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer), "%s", cq);
+ cp += strlen(cp);
+ ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
}
+
/*
- * ctl_putid - write a tagged clock ID into the response
+ * ctl_putrefid - send a u_int32 refid as printable text
*/
static void
-ctl_putid(
- const char *tag,
- char *id
+ctl_putrefid(
+ const char * tag,
+ u_int32 refid
)
{
- register char *cp;
- register const char *cq;
- char buffer[200];
-
- cp = buffer;
- cq = tag;
- while (*cq != '\0')
- *cp++ = *cq++;
-
- *cp++ = '=';
- cq = id;
- while (*cq != '\0' && (cq - id) < 4)
- *cp++ = *cq++;
- ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+ char output[16];
+ char * optr;
+ char * oplim;
+ char * iptr;
+ char * iplim;
+ char * past_eq;
+
+ optr = output;
+ oplim = output + sizeof(output);
+ while (optr < oplim && '\0' != *tag)
+ *optr++ = *tag++;
+ if (optr < oplim) {
+ *optr++ = '=';
+ past_eq = optr;
+ }
+ if (!(optr < oplim))
+ return;
+ iptr = (char *)&refid;
+ iplim = iptr + sizeof(refid);
+ for ( ; optr < oplim && iptr < iplim && '\0' != *iptr;
+ iptr++, optr++)
+ if (isprint((int)*iptr))
+ *optr = *iptr;
+ else
+ *optr = '.';
+ if (!(optr <= oplim))
+ optr = past_eq;
+ ctl_putdata(output, (u_int)(optr - output), FALSE);
}
@@ -1212,15 +1735,17 @@ ctl_putarray(
cq = tag;
while (*cq != '\0')
*cp++ = *cq++;
+ *cp++ = '=';
i = start;
do {
if (i == 0)
i = NTP_SHIFT;
i--;
- (void)sprintf(cp, " %.2f", arr[i] * 1e3);
- while (*cp != '\0')
- cp++;
- } while(i != start);
+ NTP_INSIST((cp - buffer) < (int)sizeof(buffer));
+ snprintf(cp, sizeof(buffer) - (cp - buffer),
+ " %.2f", arr[i] * 1e3);
+ cp += strlen(cp);
+ } while (i != start);
ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
}
@@ -1235,10 +1760,36 @@ ctl_putsys(
{
l_fp tmp;
char str[256];
-#ifdef OPENSSL
+ u_int u;
+ double kb;
+ double dtemp;
+ const char *ss;
+#ifdef AUTOKEY
struct cert_info *cp;
- char cbuf[256];
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
+#ifdef KERNEL_PLL
+ static struct timex ntx;
+ static u_long ntp_adjtime_time;
+
+ static const double to_ms =
+# ifdef STA_NANO
+ 1.0e-6; /* nsec to msec */
+# else
+ 1.0e-3; /* usec to msec */
+# endif
+
+ /*
+ * CS_K_* variables depend on up-to-date output of ntp_adjtime()
+ */
+ if (CS_KERN_FIRST <= varid && varid <= CS_KERN_LAST &&
+ current_time != ntp_adjtime_time) {
+ ZERO(ntx);
+ if (ntp_adjtime(&ntx) < 0)
+ msyslog(LOG_ERR, "ntp_adjtime() for mode 6 query failed: %m");
+ else
+ ntp_adjtime_time = current_time;
+ }
+#endif /* KERNEL_PLL */
switch (varid) {
@@ -1256,20 +1807,19 @@ ctl_putsys(
case CS_ROOTDELAY:
ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay *
- 1e3);
+ 1e3);
break;
case CS_ROOTDISPERSION:
ctl_putdbl(sys_var[CS_ROOTDISPERSION].text,
- sys_rootdispersion * 1e3);
+ sys_rootdisp * 1e3);
break;
case CS_REFID:
if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC)
- ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL);
+ ctl_putadr(sys_var[varid].text, sys_refid, NULL);
else
- ctl_putid(sys_var[CS_REFID].text,
- (char *)&sys_refid);
+ ctl_putrefid(sys_var[varid].text, sys_refid);
break;
case CS_REFTIME:
@@ -1285,15 +1835,26 @@ ctl_putsys(
ctl_putuint(sys_var[CS_PEERID].text, 0);
else
ctl_putuint(sys_var[CS_PEERID].text,
- sys_peer->associd);
+ sys_peer->associd);
+ break;
+
+ case CS_PEERADR:
+ if (sys_peer != NULL && sys_peer->dstadr != NULL)
+ ss = sptoa(&sys_peer->srcadr);
+ else
+ ss = "0.0.0.0:0";
+ ctl_putunqstr(sys_var[CS_PEERADR].text, ss, strlen(ss));
break;
- case CS_STATE:
- ctl_putuint(sys_var[CS_STATE].text, (unsigned)state);
+ case CS_PEERMODE:
+ u = (sys_peer != NULL)
+ ? sys_peer->hmode
+ : MODE_UNSPEC;
+ ctl_putuint(sys_var[CS_PEERMODE].text, u);
break;
case CS_OFFSET:
- ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3);
+ ctl_putdbl6(sys_var[CS_OFFSET].text, last_offset * 1e3);
break;
case CS_DRIFT:
@@ -1301,7 +1862,7 @@ ctl_putsys(
break;
case CS_JITTER:
- ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3);
+ ctl_putdbl6(sys_var[CS_JITTER].text, sys_jitter * 1e3);
break;
case CS_ERROR:
@@ -1316,164 +1877,539 @@ ctl_putsys(
case CS_PROCESSOR:
#ifndef HAVE_UNAME
ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor,
- sizeof(str_processor) - 1);
+ sizeof(str_processor) - 1);
#else
ctl_putstr(sys_var[CS_PROCESSOR].text,
- utsnamebuf.machine, strlen(utsnamebuf.machine));
+ utsnamebuf.machine, strlen(utsnamebuf.machine));
#endif /* HAVE_UNAME */
break;
case CS_SYSTEM:
#ifndef HAVE_UNAME
ctl_putstr(sys_var[CS_SYSTEM].text, str_system,
- sizeof(str_system) - 1);
+ sizeof(str_system) - 1);
#else
- sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release);
+ snprintf(str, sizeof(str), "%s/%s", utsnamebuf.sysname,
+ utsnamebuf.release);
ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str));
#endif /* HAVE_UNAME */
break;
case CS_VERSION:
ctl_putstr(sys_var[CS_VERSION].text, Version,
- strlen(Version));
+ strlen(Version));
break;
case CS_STABIL:
ctl_putdbl(sys_var[CS_STABIL].text, clock_stability *
- 1e6);
+ 1e6);
break;
case CS_VARLIST:
- {
- char buf[CTL_MAX_DATA_LEN];
- register char *s, *t, *be;
- register const char *ss;
- register int i;
- register struct ctl_var *k;
-
- s = buf;
- be = buf + sizeof(buf) -
- strlen(sys_var[CS_VARLIST].text) - 4;
- if (s > be)
- break; /* really long var name */
-
- strcpy(s, sys_var[CS_VARLIST].text);
- strcat(s, "=\"");
- s += strlen(s);
- t = s;
- for (k = sys_var; !(k->flags &EOV); k++) {
- if (k->flags & PADDING)
- continue;
- i = strlen(k->text);
- if (s+i+1 >= be)
+ {
+ char buf[CTL_MAX_DATA_LEN];
+ //buffPointer, firstElementPointer, buffEndPointer
+ char *buffp, *buffend;
+ int firstVarName;
+ const char *ss1;
+ int len;
+ const struct ctl_var *k;
+
+ buffp = buf;
+ buffend = buf + sizeof(buf);
+ if (buffp + strlen(sys_var[CS_VARLIST].text) + 4 > buffend)
+ break; /* really long var name */
+
+ snprintf(buffp, sizeof(buf), "%s=\"",sys_var[CS_VARLIST].text);
+ buffp += strlen(buffp);
+ firstVarName = TRUE;
+ for (k = sys_var; !(k->flags & EOV); k++) {
+ if (k->flags & PADDING)
+ continue;
+ len = strlen(k->text);
+ if (buffp + len + 1 >= buffend)
break;
+ if (!firstVarName)
+ *buffp++ = ',';
+ else
+ firstVarName = FALSE;
+ memcpy(buffp, k->text, len);
+ buffp += len;
+ }
- if (s != t)
- *s++ = ',';
- strcpy(s, k->text);
- s += i;
+ for (k = ext_sys_var; k && !(k->flags & EOV); k++) {
+ if (k->flags & PADDING)
+ continue;
+ if (NULL == k->text)
+ continue;
+ ss1 = strchr(k->text, '=');
+ if (NULL == ss1)
+ len = strlen(k->text);
+ else
+ len = ss1 - k->text;
+ if (buffp + len + 1 >= buffend)
+ break;
+ if (firstVarName) {
+ *buffp++ = ',';
+ firstVarName = FALSE;
}
+ memcpy(buffp, k->text,(unsigned)len);
+ buffp += len;
+ }
+ if (buffp + 2 >= buffend)
+ break;
+
+ *buffp++ = '"';
+ *buffp = '\0';
- for (k = ext_sys_var; k && !(k->flags &EOV);
- k++) {
- if (k->flags & PADDING)
- continue;
+ ctl_putdata(buf, (unsigned)( buffp - buf ), 0);
+ break;
+ }
- ss = k->text;
- if (!ss)
- continue;
+ case CS_TAI:
+ if (sys_tai > 0)
+ ctl_putuint(sys_var[CS_TAI].text, sys_tai);
+ break;
- while (*ss && *ss != '=')
- ss++;
- i = ss - k->text;
- if (s + i + 1 >= be)
- break;
+ case CS_LEAPTAB:
+ {
+ leap_signature_t lsig;
+ leapsec_getsig(&lsig);
+ if (lsig.ttime > 0)
+ ctl_putfs(sys_var[CS_LEAPTAB].text, lsig.ttime);
+ break;
+ }
- if (s != t)
- *s++ = ',';
- strncpy(s, k->text,
- (unsigned)i);
- s += i;
- }
- if (s+2 >= be)
- break;
+ case CS_LEAPEND:
+ {
+ leap_signature_t lsig;
+ leapsec_getsig(&lsig);
+ if (lsig.etime > 0)
+ ctl_putfs(sys_var[CS_LEAPEND].text, lsig.etime);
+ break;
+ }
- *s++ = '"';
- *s = '\0';
+#ifdef LEAP_SMEAR
+ case CS_LEAPSMEARINTV:
+ if (leap_smear_intv > 0)
+ ctl_putuint(sys_var[CS_LEAPSMEARINTV].text, leap_smear_intv);
+ break;
- ctl_putdata(buf, (unsigned)( s - buf ),
- 0);
- }
+ case CS_LEAPSMEAROFFS:
+ if (leap_smear_intv > 0)
+ ctl_putdbl(sys_var[CS_LEAPSMEAROFFS].text,
+ leap_smear.doffset * 1e3);
+ break;
+#endif /* LEAP_SMEAR */
+
+ case CS_RATE:
+ ctl_putuint(sys_var[CS_RATE].text, ntp_minpoll);
+ break;
+
+ case CS_MRU_ENABLED:
+ ctl_puthex(sys_var[varid].text, mon_enabled);
+ break;
+
+ case CS_MRU_DEPTH:
+ ctl_putuint(sys_var[varid].text, mru_entries);
+ break;
+
+ case CS_MRU_MEM:
+ kb = mru_entries * (sizeof(mon_entry) / 1024.);
+ u = (u_int)kb;
+ if (kb - u >= 0.5)
+ u++;
+ ctl_putuint(sys_var[varid].text, u);
+ break;
+
+ case CS_MRU_DEEPEST:
+ ctl_putuint(sys_var[varid].text, mru_peakentries);
+ break;
+
+ case CS_MRU_MINDEPTH:
+ ctl_putuint(sys_var[varid].text, mru_mindepth);
+ break;
+
+ case CS_MRU_MAXAGE:
+ ctl_putint(sys_var[varid].text, mru_maxage);
break;
-#ifdef OPENSSL
+ case CS_MRU_MAXDEPTH:
+ ctl_putuint(sys_var[varid].text, mru_maxdepth);
+ break;
+
+ case CS_MRU_MAXMEM:
+ kb = mru_maxdepth * (sizeof(mon_entry) / 1024.);
+ u = (u_int)kb;
+ if (kb - u >= 0.5)
+ u++;
+ ctl_putuint(sys_var[varid].text, u);
+ break;
+
+ case CS_SS_UPTIME:
+ ctl_putuint(sys_var[varid].text, current_time);
+ break;
+
+ case CS_SS_RESET:
+ ctl_putuint(sys_var[varid].text,
+ current_time - sys_stattime);
+ break;
+
+ case CS_SS_RECEIVED:
+ ctl_putuint(sys_var[varid].text, sys_received);
+ break;
+
+ case CS_SS_THISVER:
+ ctl_putuint(sys_var[varid].text, sys_newversion);
+ break;
+
+ case CS_SS_OLDVER:
+ ctl_putuint(sys_var[varid].text, sys_oldversion);
+ break;
+
+ case CS_SS_BADFORMAT:
+ ctl_putuint(sys_var[varid].text, sys_badlength);
+ break;
+
+ case CS_SS_BADAUTH:
+ ctl_putuint(sys_var[varid].text, sys_badauth);
+ break;
+
+ case CS_SS_DECLINED:
+ ctl_putuint(sys_var[varid].text, sys_declined);
+ break;
+
+ case CS_SS_RESTRICTED:
+ ctl_putuint(sys_var[varid].text, sys_restricted);
+ break;
+
+ case CS_SS_LIMITED:
+ ctl_putuint(sys_var[varid].text, sys_limitrejected);
+ break;
+
+ case CS_SS_KODSENT:
+ ctl_putuint(sys_var[varid].text, sys_kodsent);
+ break;
+
+ case CS_SS_PROCESSED:
+ ctl_putuint(sys_var[varid].text, sys_processed);
+ break;
+
+ case CS_BCASTDELAY:
+ ctl_putdbl(sys_var[varid].text, sys_bdelay * 1e3);
+ break;
+
+ case CS_AUTHDELAY:
+ LFPTOD(&sys_authdelay, dtemp);
+ ctl_putdbl(sys_var[varid].text, dtemp * 1e3);
+ break;
+
+ case CS_AUTHKEYS:
+ ctl_putuint(sys_var[varid].text, authnumkeys);
+ break;
+
+ case CS_AUTHFREEK:
+ ctl_putuint(sys_var[varid].text, authnumfreekeys);
+ break;
+
+ case CS_AUTHKLOOKUPS:
+ ctl_putuint(sys_var[varid].text, authkeylookups);
+ break;
+
+ case CS_AUTHKNOTFOUND:
+ ctl_putuint(sys_var[varid].text, authkeynotfound);
+ break;
+
+ case CS_AUTHKUNCACHED:
+ ctl_putuint(sys_var[varid].text, authkeyuncached);
+ break;
+
+ case CS_AUTHKEXPIRED:
+ ctl_putuint(sys_var[varid].text, authkeyexpired);
+ break;
+
+ case CS_AUTHENCRYPTS:
+ ctl_putuint(sys_var[varid].text, authencryptions);
+ break;
+
+ case CS_AUTHDECRYPTS:
+ ctl_putuint(sys_var[varid].text, authdecryptions);
+ break;
+
+ case CS_AUTHRESET:
+ ctl_putuint(sys_var[varid].text,
+ current_time - auth_timereset);
+ break;
+
+ /*
+ * CTL_IF_KERNLOOP() puts a zero if the kernel loop is
+ * unavailable, otherwise calls putfunc with args.
+ */
+#ifndef KERNEL_PLL
+# define CTL_IF_KERNLOOP(putfunc, args) \
+ ctl_putint(sys_var[varid].text, 0)
+#else
+# define CTL_IF_KERNLOOP(putfunc, args) \
+ putfunc args
+#endif
+
+ /*
+ * CTL_IF_KERNPPS() puts a zero if either the kernel
+ * loop is unavailable, or kernel hard PPS is not
+ * active, otherwise calls putfunc with args.
+ */
+#ifndef KERNEL_PLL
+# define CTL_IF_KERNPPS(putfunc, args) \
+ ctl_putint(sys_var[varid].text, 0)
+#else
+# define CTL_IF_KERNPPS(putfunc, args) \
+ if (0 == ntx.shift) \
+ ctl_putint(sys_var[varid].text, 0); \
+ else \
+ putfunc args /* no trailing ; */
+#endif
+
+ case CS_K_OFFSET:
+ CTL_IF_KERNLOOP(
+ ctl_putdblf,
+ (sys_var[varid].text, 0, -1, to_ms * ntx.offset)
+ );
+ break;
+
+ case CS_K_FREQ:
+ CTL_IF_KERNLOOP(
+ ctl_putsfp,
+ (sys_var[varid].text, ntx.freq)
+ );
+ break;
+
+ case CS_K_MAXERR:
+ CTL_IF_KERNLOOP(
+ ctl_putdblf,
+ (sys_var[varid].text, 0, 6,
+ to_ms * ntx.maxerror)
+ );
+ break;
+
+ case CS_K_ESTERR:
+ CTL_IF_KERNLOOP(
+ ctl_putdblf,
+ (sys_var[varid].text, 0, 6,
+ to_ms * ntx.esterror)
+ );
+ break;
+
+ case CS_K_STFLAGS:
+#ifndef KERNEL_PLL
+ ss = "";
+#else
+ ss = k_st_flags(ntx.status);
+#endif
+ ctl_putstr(sys_var[varid].text, ss, strlen(ss));
+ break;
+
+ case CS_K_TIMECONST:
+ CTL_IF_KERNLOOP(
+ ctl_putint,
+ (sys_var[varid].text, ntx.constant)
+ );
+ break;
+
+ case CS_K_PRECISION:
+ CTL_IF_KERNLOOP(
+ ctl_putdblf,
+ (sys_var[varid].text, 0, 6,
+ to_ms * ntx.precision)
+ );
+ break;
+
+ case CS_K_FREQTOL:
+ CTL_IF_KERNLOOP(
+ ctl_putsfp,
+ (sys_var[varid].text, ntx.tolerance)
+ );
+ break;
+
+ case CS_K_PPS_FREQ:
+ CTL_IF_KERNPPS(
+ ctl_putsfp,
+ (sys_var[varid].text, ntx.ppsfreq)
+ );
+ break;
+
+ case CS_K_PPS_STABIL:
+ CTL_IF_KERNPPS(
+ ctl_putsfp,
+ (sys_var[varid].text, ntx.stabil)
+ );
+ break;
+
+ case CS_K_PPS_JITTER:
+ CTL_IF_KERNPPS(
+ ctl_putdbl,
+ (sys_var[varid].text, to_ms * ntx.jitter)
+ );
+ break;
+
+ case CS_K_PPS_CALIBDUR:
+ CTL_IF_KERNPPS(
+ ctl_putint,
+ (sys_var[varid].text, 1 << ntx.shift)
+ );
+ break;
+
+ case CS_K_PPS_CALIBS:
+ CTL_IF_KERNPPS(
+ ctl_putint,
+ (sys_var[varid].text, ntx.calcnt)
+ );
+ break;
+
+ case CS_K_PPS_CALIBERRS:
+ CTL_IF_KERNPPS(
+ ctl_putint,
+ (sys_var[varid].text, ntx.errcnt)
+ );
+ break;
+
+ case CS_K_PPS_JITEXC:
+ CTL_IF_KERNPPS(
+ ctl_putint,
+ (sys_var[varid].text, ntx.jitcnt)
+ );
+ break;
+
+ case CS_K_PPS_STBEXC:
+ CTL_IF_KERNPPS(
+ ctl_putint,
+ (sys_var[varid].text, ntx.stbcnt)
+ );
+ break;
+
+ case CS_IOSTATS_RESET:
+ ctl_putuint(sys_var[varid].text,
+ current_time - io_timereset);
+ break;
+
+ case CS_TOTAL_RBUF:
+ ctl_putuint(sys_var[varid].text, total_recvbuffs());
+ break;
+
+ case CS_FREE_RBUF:
+ ctl_putuint(sys_var[varid].text, free_recvbuffs());
+ break;
+
+ case CS_USED_RBUF:
+ ctl_putuint(sys_var[varid].text, full_recvbuffs());
+ break;
+
+ case CS_RBUF_LOWATER:
+ ctl_putuint(sys_var[varid].text, lowater_additions());
+ break;
+
+ case CS_IO_DROPPED:
+ ctl_putuint(sys_var[varid].text, packets_dropped);
+ break;
+
+ case CS_IO_IGNORED:
+ ctl_putuint(sys_var[varid].text, packets_ignored);
+ break;
+
+ case CS_IO_RECEIVED:
+ ctl_putuint(sys_var[varid].text, packets_received);
+ break;
+
+ case CS_IO_SENT:
+ ctl_putuint(sys_var[varid].text, packets_sent);
+ break;
+
+ case CS_IO_SENDFAILED:
+ ctl_putuint(sys_var[varid].text, packets_notsent);
+ break;
+
+ case CS_IO_WAKEUPS:
+ ctl_putuint(sys_var[varid].text, handler_calls);
+ break;
+
+ case CS_IO_GOODWAKEUPS:
+ ctl_putuint(sys_var[varid].text, handler_pkts);
+ break;
+
+ case CS_TIMERSTATS_RESET:
+ ctl_putuint(sys_var[varid].text,
+ current_time - timer_timereset);
+ break;
+
+ case CS_TIMER_OVERRUNS:
+ ctl_putuint(sys_var[varid].text, alarm_overflow);
+ break;
+
+ case CS_TIMER_XMTS:
+ ctl_putuint(sys_var[varid].text, timer_xmtcalls);
+ break;
+
+ case CS_FUZZ:
+ ctl_putdbl(sys_var[varid].text, sys_fuzz * 1e3);
+ break;
+ case CS_WANDER_THRESH:
+ ctl_putdbl(sys_var[varid].text, wander_threshold * 1e6);
+ break;
+#ifdef AUTOKEY
case CS_FLAGS:
+ if (crypto_flags)
+ ctl_puthex(sys_var[CS_FLAGS].text,
+ crypto_flags);
+ break;
+
+ case CS_DIGEST:
if (crypto_flags) {
- ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags);
+ strlcpy(str, OBJ_nid2ln(crypto_nid),
+ COUNTOF(str));
+ ctl_putstr(sys_var[CS_DIGEST].text, str,
+ strlen(str));
}
break;
- case CS_DIGEST:
+ case CS_SIGNATURE:
if (crypto_flags) {
const EVP_MD *dp;
dp = EVP_get_digestbynid(crypto_flags >> 16);
- strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
- ctl_putstr(sys_var[CS_DIGEST].text, str,
+ strlcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)),
+ COUNTOF(str));
+ ctl_putstr(sys_var[CS_SIGNATURE].text, str,
strlen(str));
}
break;
case CS_HOST:
- if (sys_hostname != NULL)
- ctl_putstr(sys_var[CS_HOST].text, sys_hostname,
- strlen(sys_hostname));
+ if (hostval.ptr != NULL)
+ ctl_putstr(sys_var[CS_HOST].text, hostval.ptr,
+ strlen(hostval.ptr));
+ break;
+
+ case CS_IDENT:
+ if (sys_ident != NULL)
+ ctl_putstr(sys_var[CS_IDENT].text, sys_ident,
+ strlen(sys_ident));
break;
case CS_CERTIF:
for (cp = cinfo; cp != NULL; cp = cp->link) {
- sprintf(cbuf, "%s %s 0x%x", cp->subject,
- cp->issuer, cp->flags);
- ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
- strlen(cbuf));
- ctl_putfs(sys_var[CS_REVOKE].text, cp->last);
+ snprintf(str, sizeof(str), "%s %s 0x%x",
+ cp->subject, cp->issuer, cp->flags);
+ ctl_putstr(sys_var[CS_CERTIF].text, str,
+ strlen(str));
+ ctl_putcal(sys_var[CS_REVTIME].text, &(cp->last));
}
break;
case CS_PUBLIC:
- if (hostval.fstamp != 0)
- ctl_putfs(sys_var[CS_PUBLIC].text,
- ntohl(hostval.tstamp));
- break;
-
- case CS_REVTIME:
if (hostval.tstamp != 0)
- ctl_putfs(sys_var[CS_REVTIME].text,
+ ctl_putfs(sys_var[CS_PUBLIC].text,
ntohl(hostval.tstamp));
break;
-
- case CS_IDENT:
- if (iffpar_pkey != NULL)
- ctl_putstr(sys_var[CS_IDENT].text,
- iffpar_file, strlen(iffpar_file));
- if (gqpar_pkey != NULL)
- ctl_putstr(sys_var[CS_IDENT].text,
- gqpar_file, strlen(gqpar_file));
- if (mvpar_pkey != NULL)
- ctl_putstr(sys_var[CS_IDENT].text,
- mvpar_file, strlen(mvpar_file));
- break;
-
- case CS_LEAPTAB:
- if (tai_leap.fstamp != 0)
- ctl_putfs(sys_var[CS_LEAPTAB].text,
- ntohl(tai_leap.fstamp));
- break;
-
- case CS_TAI:
- ctl_putuint(sys_var[CS_TAI].text, sys_tai);
- break;
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
}
}
@@ -1483,275 +2419,328 @@ ctl_putsys(
*/
static void
ctl_putpeer(
- int varid,
- struct peer *peer
+ int id,
+ struct peer *p
)
{
- int temp;
-#ifdef OPENSSL
- char str[256];
+ char buf[CTL_MAX_DATA_LEN];
+ char *s;
+ char *t;
+ char *be;
+ int i;
+ const struct ctl_var *k;
+#ifdef AUTOKEY
struct autokey *ap;
-#endif /* OPENSSL */
+ const EVP_MD *dp;
+ const char *str;
+#endif /* AUTOKEY */
- switch (varid) {
+ switch (id) {
case CP_CONFIG:
- ctl_putuint(peer_var[CP_CONFIG].text,
- (unsigned)((peer->flags & FLAG_CONFIG) != 0));
+ ctl_putuint(peer_var[id].text,
+ !(FLAG_PREEMPT & p->flags));
break;
case CP_AUTHENABLE:
- ctl_putuint(peer_var[CP_AUTHENABLE].text,
- (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0));
+ ctl_putuint(peer_var[id].text, !(p->keyid));
break;
case CP_AUTHENTIC:
- ctl_putuint(peer_var[CP_AUTHENTIC].text,
- (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0));
+ ctl_putuint(peer_var[id].text,
+ !!(FLAG_AUTHENTIC & p->flags));
break;
case CP_SRCADR:
- ctl_putadr(peer_var[CP_SRCADR].text, 0,
- &peer->srcadr);
+ ctl_putadr(peer_var[id].text, 0, &p->srcadr);
break;
case CP_SRCPORT:
- ctl_putuint(peer_var[CP_SRCPORT].text,
- ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port));
+ ctl_putuint(peer_var[id].text, SRCPORT(&p->srcadr));
+ break;
+
+ case CP_SRCHOST:
+ if (p->hostname != NULL)
+ ctl_putstr(peer_var[id].text, p->hostname,
+ strlen(p->hostname));
break;
case CP_DSTADR:
- if (peer->dstadr) {
- ctl_putadr(peer_var[CP_DSTADR].text, 0,
- &(peer->dstadr->sin));
- } else {
- ctl_putadr(peer_var[CP_DSTADR].text, 0,
- NULL);
- }
+ ctl_putadr(peer_var[id].text, 0,
+ (p->dstadr != NULL)
+ ? &p->dstadr->sin
+ : NULL);
break;
case CP_DSTPORT:
- ctl_putuint(peer_var[CP_DSTPORT].text,
- (u_long)(peer->dstadr ?
- ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0));
+ ctl_putuint(peer_var[id].text,
+ (p->dstadr != NULL)
+ ? SRCPORT(&p->dstadr->sin)
+ : 0);
+ break;
+
+ case CP_IN:
+ if (p->r21 > 0.)
+ ctl_putdbl(peer_var[id].text, p->r21 / 1e3);
+ break;
+
+ case CP_OUT:
+ if (p->r34 > 0.)
+ ctl_putdbl(peer_var[id].text, p->r34 / 1e3);
+ break;
+
+ case CP_RATE:
+ ctl_putuint(peer_var[id].text, p->throttle);
break;
case CP_LEAP:
- ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
+ ctl_putuint(peer_var[id].text, p->leap);
break;
case CP_HMODE:
- ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
+ ctl_putuint(peer_var[id].text, p->hmode);
break;
case CP_STRATUM:
- ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
+ ctl_putuint(peer_var[id].text, p->stratum);
break;
case CP_PPOLL:
- ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
+ ctl_putuint(peer_var[id].text, p->ppoll);
break;
case CP_HPOLL:
- ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
+ ctl_putuint(peer_var[id].text, p->hpoll);
break;
case CP_PRECISION:
- ctl_putint(peer_var[CP_PRECISION].text,
- peer->precision);
+ ctl_putint(peer_var[id].text, p->precision);
break;
case CP_ROOTDELAY:
- ctl_putdbl(peer_var[CP_ROOTDELAY].text,
- peer->rootdelay * 1e3);
+ ctl_putdbl(peer_var[id].text, p->rootdelay * 1e3);
break;
case CP_ROOTDISPERSION:
- ctl_putdbl(peer_var[CP_ROOTDISPERSION].text,
- peer->rootdispersion * 1e3);
+ ctl_putdbl(peer_var[id].text, p->rootdisp * 1e3);
break;
case CP_REFID:
- if (peer->flags & FLAG_REFCLOCK) {
- ctl_putid(peer_var[CP_REFID].text,
- (char *)&peer->refid);
- } else {
- if (peer->stratum > 1 && peer->stratum <
- STRATUM_UNSPEC)
- ctl_putadr(peer_var[CP_REFID].text,
- peer->refid, NULL);
- else
- ctl_putid(peer_var[CP_REFID].text,
- (char *)&peer->refid);
+#ifdef REFCLOCK
+ if (p->flags & FLAG_REFCLOCK) {
+ ctl_putrefid(peer_var[id].text, p->refid);
+ break;
}
+#endif
+ if (p->stratum > 1 && p->stratum < STRATUM_UNSPEC)
+ ctl_putadr(peer_var[id].text, p->refid,
+ NULL);
+ else
+ ctl_putrefid(peer_var[id].text, p->refid);
break;
case CP_REFTIME:
- ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime);
+ ctl_putts(peer_var[id].text, &p->reftime);
break;
case CP_ORG:
- ctl_putts(peer_var[CP_ORG].text, &peer->org);
+ ctl_putts(peer_var[id].text, &p->aorg);
break;
case CP_REC:
- ctl_putts(peer_var[CP_REC].text, &peer->rec);
+ ctl_putts(peer_var[id].text, &p->dst);
break;
case CP_XMT:
- ctl_putts(peer_var[CP_XMT].text, &peer->xmt);
+ if (p->xleave)
+ ctl_putdbl(peer_var[id].text, p->xleave * 1e3);
+ break;
+
+ case CP_BIAS:
+ if (p->bias != 0.)
+ ctl_putdbl(peer_var[id].text, p->bias * 1e3);
break;
case CP_REACH:
- ctl_puthex(peer_var[CP_REACH].text, peer->reach);
+ ctl_puthex(peer_var[id].text, p->reach);
break;
case CP_FLASH:
- temp = peer->flash;
- ctl_puthex(peer_var[CP_FLASH].text, temp);
+ ctl_puthex(peer_var[id].text, p->flash);
break;
case CP_TTL:
- ctl_putint(peer_var[CP_TTL].text, sys_ttl[peer->ttl]);
+#ifdef REFCLOCK
+ if (p->flags & FLAG_REFCLOCK) {
+ ctl_putuint(peer_var[id].text, p->ttl);
+ break;
+ }
+#endif
+ if (p->ttl > 0 && p->ttl < COUNTOF(sys_ttl))
+ ctl_putint(peer_var[id].text,
+ sys_ttl[p->ttl]);
break;
case CP_UNREACH:
- ctl_putuint(peer_var[CP_UNREACH].text, peer->unreach);
+ ctl_putuint(peer_var[id].text, p->unreach);
break;
case CP_TIMER:
- ctl_putuint(peer_var[CP_TIMER].text,
- peer->nextdate - current_time);
+ ctl_putuint(peer_var[id].text,
+ p->nextdate - current_time);
break;
case CP_DELAY:
- ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3);
+ ctl_putdbl(peer_var[id].text, p->delay * 1e3);
break;
case CP_OFFSET:
- ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset *
- 1e3);
+ ctl_putdbl(peer_var[id].text, p->offset * 1e3);
break;
case CP_JITTER:
- ctl_putdbl(peer_var[CP_JITTER].text, peer->jitter * 1e3);
+ ctl_putdbl(peer_var[id].text, p->jitter * 1e3);
break;
case CP_DISPERSION:
- ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp *
- 1e3);
+ ctl_putdbl(peer_var[id].text, p->disp * 1e3);
break;
case CP_KEYID:
- ctl_putuint(peer_var[CP_KEYID].text, peer->keyid);
+ if (p->keyid > NTP_MAXKEY)
+ ctl_puthex(peer_var[id].text, p->keyid);
+ else
+ ctl_putuint(peer_var[id].text, p->keyid);
break;
case CP_FILTDELAY:
- ctl_putarray(peer_var[CP_FILTDELAY].text,
- peer->filter_delay, (int)peer->filter_nextpt);
+ ctl_putarray(peer_var[id].text, p->filter_delay,
+ p->filter_nextpt);
break;
case CP_FILTOFFSET:
- ctl_putarray(peer_var[CP_FILTOFFSET].text,
- peer->filter_offset, (int)peer->filter_nextpt);
+ ctl_putarray(peer_var[id].text, p->filter_offset,
+ p->filter_nextpt);
break;
case CP_FILTERROR:
- ctl_putarray(peer_var[CP_FILTERROR].text,
- peer->filter_disp, (int)peer->filter_nextpt);
+ ctl_putarray(peer_var[id].text, p->filter_disp,
+ p->filter_nextpt);
break;
case CP_PMODE:
- ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
+ ctl_putuint(peer_var[id].text, p->pmode);
break;
case CP_RECEIVED:
- ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
+ ctl_putuint(peer_var[id].text, p->received);
break;
case CP_SENT:
- ctl_putuint(peer_var[CP_SENT].text, peer->sent);
+ ctl_putuint(peer_var[id].text, p->sent);
break;
case CP_VARLIST:
- {
- char buf[CTL_MAX_DATA_LEN];
- register char *s, *t, *be;
- register int i;
- register struct ctl_var *k;
-
- s = buf;
- be = buf + sizeof(buf) -
- strlen(peer_var[CP_VARLIST].text) - 4;
- if (s > be)
- break; /* really long var name */
-
- strcpy(s, peer_var[CP_VARLIST].text);
- strcat(s, "=\"");
- s += strlen(s);
- t = s;
- for (k = peer_var; !(k->flags &EOV); k++) {
- if (k->flags & PADDING)
- continue;
-
- i = strlen(k->text);
- if (s + i + 1 >= be)
- break;
-
- if (s != t)
- *s++ = ',';
- strcpy(s, k->text);
- s += i;
- }
- if (s+2 >= be)
+ s = buf;
+ be = buf + sizeof(buf);
+ if (strlen(peer_var[id].text) + 4 > sizeof(buf))
+ break; /* really long var name */
+
+ snprintf(s, sizeof(buf), "%s=\"", peer_var[id].text);
+ s += strlen(s);
+ t = s;
+ for (k = peer_var; !(EOV & k->flags); k++) {
+ if (PADDING & k->flags)
+ continue;
+ i = strlen(k->text);
+ if (s + i + 1 >= be)
break;
-
+ if (s != t)
+ *s++ = ',';
+ memcpy(s, k->text, i);
+ s += i;
+ }
+ if (s + 2 < be) {
*s++ = '"';
*s = '\0';
- ctl_putdata(buf, (unsigned)(s - buf), 0);
+ ctl_putdata(buf, (u_int)(s - buf), 0);
}
break;
-#ifdef OPENSSL
- case CP_FLAGS:
- if (peer->crypto)
- ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto);
+
+ case CP_TIMEREC:
+ ctl_putuint(peer_var[id].text,
+ current_time - p->timereceived);
break;
- case CP_DIGEST:
- if (peer->crypto) {
- const EVP_MD *dp;
+ case CP_TIMEREACH:
+ ctl_putuint(peer_var[id].text,
+ current_time - p->timereachable);
+ break;
+
+ case CP_BADAUTH:
+ ctl_putuint(peer_var[id].text, p->badauth);
+ break;
+
+ case CP_BOGUSORG:
+ ctl_putuint(peer_var[id].text, p->bogusorg);
+ break;
+
+ case CP_OLDPKT:
+ ctl_putuint(peer_var[id].text, p->oldpkt);
+ break;
+
+ case CP_SELDISP:
+ ctl_putuint(peer_var[id].text, p->seldisptoolarge);
+ break;
+
+ case CP_SELBROKEN:
+ ctl_putuint(peer_var[id].text, p->selbroken);
+ break;
- dp = EVP_get_digestbynid(peer->crypto >> 16);
- strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
- ctl_putstr(peer_var[CP_DIGEST].text, str,
- strlen(str));
+ case CP_CANDIDATE:
+ ctl_putuint(peer_var[id].text, p->status);
+ break;
+#ifdef AUTOKEY
+ case CP_FLAGS:
+ if (p->crypto)
+ ctl_puthex(peer_var[id].text, p->crypto);
+ break;
+
+ case CP_SIGNATURE:
+ if (p->crypto) {
+ dp = EVP_get_digestbynid(p->crypto >> 16);
+ str = OBJ_nid2ln(EVP_MD_pkey_type(dp));
+ ctl_putstr(peer_var[id].text, str, strlen(str));
}
break;
case CP_HOST:
- if (peer->subject != NULL)
- ctl_putstr(peer_var[CP_HOST].text,
- peer->subject, strlen(peer->subject));
+ if (p->subject != NULL)
+ ctl_putstr(peer_var[id].text, p->subject,
+ strlen(p->subject));
break;
case CP_VALID: /* not used */
break;
- case CP_IDENT:
- if (peer->issuer != NULL)
- ctl_putstr(peer_var[CP_IDENT].text,
- peer->issuer, strlen(peer->issuer));
- break;
-
case CP_INITSEQ:
- if ((ap = (struct autokey *)peer->recval.ptr) == NULL)
+ if (NULL == (ap = p->recval.ptr))
break;
+
ctl_putint(peer_var[CP_INITSEQ].text, ap->seq);
ctl_puthex(peer_var[CP_INITKEY].text, ap->key);
ctl_putfs(peer_var[CP_INITTSP].text,
- ntohl(peer->recval.tstamp));
+ ntohl(p->recval.tstamp));
+ break;
+
+ case CP_IDENT:
+ if (p->ident != NULL)
+ ctl_putstr(peer_var[id].text, p->ident,
+ strlen(p->ident));
break;
-#endif /* OPENSSL */
+
+
+#endif /* AUTOKEY */
}
}
@@ -1762,153 +2751,148 @@ ctl_putpeer(
*/
static void
ctl_putclock(
- int varid,
- struct refclockstat *clock_stat,
+ int id,
+ struct refclockstat *pcs,
int mustput
)
{
- switch(varid) {
+ char buf[CTL_MAX_DATA_LEN];
+ char *s, *t, *be;
+ const char *ss;
+ int i;
+ const struct ctl_var *k;
+
+ switch (id) {
case CC_TYPE:
- if (mustput || clock_stat->clockdesc == NULL
- || *(clock_stat->clockdesc) == '\0') {
- ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type);
+ if (mustput || pcs->clockdesc == NULL
+ || *(pcs->clockdesc) == '\0') {
+ ctl_putuint(clock_var[id].text, pcs->type);
}
break;
case CC_TIMECODE:
- ctl_putstr(clock_var[CC_TIMECODE].text,
- clock_stat->p_lastcode,
- (unsigned)clock_stat->lencode);
+ ctl_putstr(clock_var[id].text,
+ pcs->p_lastcode,
+ (unsigned)pcs->lencode);
break;
case CC_POLL:
- ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls);
+ ctl_putuint(clock_var[id].text, pcs->polls);
break;
case CC_NOREPLY:
- ctl_putuint(clock_var[CC_NOREPLY].text,
- clock_stat->noresponse);
+ ctl_putuint(clock_var[id].text,
+ pcs->noresponse);
break;
case CC_BADFORMAT:
- ctl_putuint(clock_var[CC_BADFORMAT].text,
- clock_stat->badformat);
+ ctl_putuint(clock_var[id].text,
+ pcs->badformat);
break;
case CC_BADDATA:
- ctl_putuint(clock_var[CC_BADDATA].text,
- clock_stat->baddata);
+ ctl_putuint(clock_var[id].text,
+ pcs->baddata);
break;
case CC_FUDGETIME1:
- if (mustput || (clock_stat->haveflags & CLK_HAVETIME1))
- ctl_putdbl(clock_var[CC_FUDGETIME1].text,
- clock_stat->fudgetime1 * 1e3);
+ if (mustput || (pcs->haveflags & CLK_HAVETIME1))
+ ctl_putdbl(clock_var[id].text,
+ pcs->fudgetime1 * 1e3);
break;
case CC_FUDGETIME2:
- if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) ctl_putdbl(clock_var[CC_FUDGETIME2].text,
- clock_stat->fudgetime2 * 1e3);
+ if (mustput || (pcs->haveflags & CLK_HAVETIME2))
+ ctl_putdbl(clock_var[id].text,
+ pcs->fudgetime2 * 1e3);
break;
case CC_FUDGEVAL1:
- if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1))
- ctl_putint(clock_var[CC_FUDGEVAL1].text,
- clock_stat->fudgeval1);
+ if (mustput || (pcs->haveflags & CLK_HAVEVAL1))
+ ctl_putint(clock_var[id].text,
+ pcs->fudgeval1);
break;
case CC_FUDGEVAL2:
- if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) {
- if (clock_stat->fudgeval1 > 1)
- ctl_putadr(clock_var[CC_FUDGEVAL2].text,
- (u_int32)clock_stat->fudgeval2, NULL);
+ if (mustput || (pcs->haveflags & CLK_HAVEVAL2)) {
+ if (pcs->fudgeval1 > 1)
+ ctl_putadr(clock_var[id].text,
+ pcs->fudgeval2, NULL);
else
- ctl_putid(clock_var[CC_FUDGEVAL2].text,
- (char *)&clock_stat->fudgeval2);
+ ctl_putrefid(clock_var[id].text,
+ pcs->fudgeval2);
}
break;
case CC_FLAGS:
- if (mustput || (clock_stat->haveflags & (CLK_HAVEFLAG1 |
- CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4)))
- ctl_putuint(clock_var[CC_FLAGS].text,
- clock_stat->flags);
+ ctl_putuint(clock_var[id].text, pcs->flags);
break;
case CC_DEVICE:
- if (clock_stat->clockdesc == NULL ||
- *(clock_stat->clockdesc) == '\0') {
+ if (pcs->clockdesc == NULL ||
+ *(pcs->clockdesc) == '\0') {
if (mustput)
- ctl_putstr(clock_var[CC_DEVICE].text,
- "", 0);
+ ctl_putstr(clock_var[id].text,
+ "", 0);
} else {
- ctl_putstr(clock_var[CC_DEVICE].text,
- clock_stat->clockdesc,
- strlen(clock_stat->clockdesc));
+ ctl_putstr(clock_var[id].text,
+ pcs->clockdesc,
+ strlen(pcs->clockdesc));
}
break;
case CC_VARLIST:
- {
- char buf[CTL_MAX_DATA_LEN];
- register char *s, *t, *be;
- register const char *ss;
- register int i;
- register struct ctl_var *k;
-
- s = buf;
- be = buf + sizeof(buf);
- if (s + strlen(clock_var[CC_VARLIST].text) + 4 >
- be)
- break; /* really long var name */
-
- strcpy(s, clock_var[CC_VARLIST].text);
- strcat(s, "=\"");
- s += strlen(s);
- t = s;
-
- for (k = clock_var; !(k->flags &EOV); k++) {
- if (k->flags & PADDING)
- continue;
-
- i = strlen(k->text);
- if (s + i + 1 >= be)
- break;
+ s = buf;
+ be = buf + sizeof(buf);
+ if (strlen(clock_var[CC_VARLIST].text) + 4 >
+ sizeof(buf))
+ break; /* really long var name */
+
+ snprintf(s, sizeof(buf), "%s=\"",
+ clock_var[CC_VARLIST].text);
+ s += strlen(s);
+ t = s;
+
+ for (k = clock_var; !(EOV & k->flags); k++) {
+ if (PADDING & k->flags)
+ continue;
- if (s != t)
- *s++ = ',';
- strcpy(s, k->text);
- s += i;
- }
+ i = strlen(k->text);
+ if (s + i + 1 >= be)
+ break;
- for (k = clock_stat->kv_list; k && !(k->flags &
- EOV); k++) {
- if (k->flags & PADDING)
- continue;
+ if (s != t)
+ *s++ = ',';
+ memcpy(s, k->text, i);
+ s += i;
+ }
- ss = k->text;
- if (!ss)
- continue;
+ for (k = pcs->kv_list; k && !(EOV & k->flags); k++) {
+ if (PADDING & k->flags)
+ continue;
- while (*ss && *ss != '=')
- ss++;
- i = ss - k->text;
- if (s+i+1 >= be)
- break;
+ ss = k->text;
+ if (NULL == ss)
+ continue;
- if (s != t)
- *s++ = ',';
- strncpy(s, k->text, (unsigned)i);
- s += i;
- *s = '\0';
- }
- if (s+2 >= be)
+ while (*ss && *ss != '=')
+ ss++;
+ i = ss - k->text;
+ if (s + i + 1 >= be)
break;
- *s++ = '"';
+ if (s != t)
+ *s++ = ',';
+ memcpy(s, k->text, (unsigned)i);
+ s += i;
*s = '\0';
- ctl_putdata(buf, (unsigned)( s - buf ), 0);
}
+ if (s + 2 >= be)
+ break;
+
+ *s++ = '"';
+ *s = '\0';
+ ctl_putdata(buf, (unsigned)(s - buf), 0);
break;
}
}
@@ -1919,29 +2903,31 @@ ctl_putclock(
/*
* ctl_getitem - get the next data item from the incoming packet
*/
-static struct ctl_var *
+static const struct ctl_var *
ctl_getitem(
- struct ctl_var *var_list,
+ const struct ctl_var *var_list,
char **data
)
{
- register struct ctl_var *v;
- register char *cp;
- register char *tp;
- static struct ctl_var eol = { 0, EOV, };
+ static const struct ctl_var eol = { 0, EOV, NULL };
static char buf[128];
+ static u_long quiet_until;
+ const struct ctl_var *v;
+ const char *pch;
+ char *cp;
+ char *tp;
/*
* Delete leading commas and white space
*/
while (reqpt < reqend && (*reqpt == ',' ||
- isspace((unsigned char)*reqpt)))
+ isspace((unsigned char)*reqpt)))
reqpt++;
if (reqpt >= reqend)
- return (0);
+ return NULL;
- if (var_list == (struct ctl_var *)0)
- return (&eol);
+ if (NULL == var_list)
+ return &eol;
/*
* Look for a first character match on the tag. If we find
@@ -1949,18 +2935,18 @@ ctl_getitem(
*/
v = var_list;
cp = reqpt;
- while (!(v->flags & EOV)) {
- if (!(v->flags & PADDING) && *cp == *(v->text)) {
- tp = v->text;
- while (*tp != '\0' && *tp != '=' && cp <
- reqend && *cp == *tp) {
+ for (v = var_list; !(EOV & v->flags); v++) {
+ if (!(PADDING & v->flags) && *cp == *(v->text)) {
+ pch = v->text;
+ while ('\0' != *pch && '=' != *pch && cp < reqend
+ && *cp == *pch) {
cp++;
- tp++;
+ pch++;
}
- if ((*tp == '\0') || (*tp == '=')) {
- while (cp < reqend && isspace((unsigned char)*cp))
+ if ('\0' == *pch || '=' == *pch) {
+ while (cp < reqend && isspace((u_char)*cp))
cp++;
- if (cp == reqend || *cp == ',') {
+ if (cp == reqend || ',' == *cp) {
buf[0] = '\0';
*data = buf;
if (cp < reqend)
@@ -1968,42 +2954,37 @@ ctl_getitem(
reqpt = cp;
return v;
}
- if (*cp == '=') {
+ if ('=' == *cp) {
cp++;
tp = buf;
- while (cp < reqend && isspace((unsigned char)*cp))
+ while (cp < reqend && isspace((u_char)*cp))
cp++;
while (cp < reqend && *cp != ',') {
*tp++ = *cp++;
- if (tp >= buf + sizeof(buf)) {
+ if ((size_t)(tp - buf) >= sizeof(buf)) {
ctl_error(CERR_BADFMT);
numctlbadpkts++;
-#if 0 /* Avoid possible DOS attack */
-/* If we get a smarter msyslog we can re-enable this */
- msyslog(LOG_WARNING,
- "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n",
- stoa(rmt_addr), SRCPORT(rmt_addr)
- );
-#endif
- return (0);
+ NLOG(NLOG_SYSEVENT)
+ if (quiet_until <= current_time) {
+ quiet_until = current_time + 300;
+ msyslog(LOG_WARNING,
+"Possible 'ntpdx' exploit from %s#%u (possibly spoofed)", stoa(rmt_addr), SRCPORT(rmt_addr));
+ }
+ return NULL;
}
}
if (cp < reqend)
cp++;
*tp-- = '\0';
- while (tp >= buf) {
- if (!isspace((unsigned int)(*tp)))
- break;
+ while (tp >= buf && isspace((u_char)*tp))
*tp-- = '\0';
- }
reqpt = cp;
*data = buf;
- return (v);
+ return v;
}
}
cp = reqpt;
}
- v++;
}
return v;
}
@@ -2026,15 +3007,15 @@ control_unspec(
* I return no errors and no data, unless a specified assocation
* doesn't exist.
*/
- if (res_associd != 0) {
- if ((peer = findpeerbyassoc(res_associd)) == 0) {
+ if (res_associd) {
+ peer = findpeerbyassoc(res_associd);
+ if (NULL == peer) {
ctl_error(CERR_BADASSOC);
return;
}
rpkt.status = htons(ctlpeerstatus(peer));
- } else {
+ } else
rpkt.status = htons(ctlsysstatus());
- }
ctl_flushpkt(0);
}
@@ -2050,9 +3031,11 @@ read_status(
int restrict_mask
)
{
- register int i;
- register struct peer *peer;
- u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)];
+ struct peer *peer;
+ const u_char *cp;
+ size_t n;
+ /* a_st holds association ID, status pairs alternating */
+ u_short a_st[CTL_MAX_DATA_LEN / sizeof(u_short)];
#ifdef DEBUG
if (debug > 2)
@@ -2063,167 +3046,175 @@ read_status(
* zero we return all known assocation ID's. Otherwise
* we return a bunch of stuff about the particular peer.
*/
- if (res_associd == 0) {
- register int n;
-
- n = 0;
- rpkt.status = htons(ctlsysstatus());
- for (i = 0; i < NTP_HASH_SIZE; i++) {
- for (peer = assoc_hash[i]; peer != 0;
- peer = peer->ass_next) {
- ass_stat[n++] = htons(peer->associd);
- ass_stat[n++] =
- htons(ctlpeerstatus(peer));
- if (n ==
- CTL_MAX_DATA_LEN/sizeof(u_short)) {
- ctl_putdata((char *)ass_stat,
- n * sizeof(u_short), 1);
- n = 0;
- }
- }
- }
-
- if (n != 0)
- ctl_putdata((char *)ass_stat, n *
- sizeof(u_short), 1);
- ctl_flushpkt(0);
- } else {
+ if (res_associd) {
peer = findpeerbyassoc(res_associd);
- if (peer == 0) {
+ if (NULL == peer) {
ctl_error(CERR_BADASSOC);
- } else {
- register u_char *cp;
+ return;
+ }
+ rpkt.status = htons(ctlpeerstatus(peer));
+ if (res_authokay)
+ peer->num_events = 0;
+ /*
+ * For now, output everything we know about the
+ * peer. May be more selective later.
+ */
+ for (cp = def_peer_var; *cp != 0; cp++)
+ ctl_putpeer((int)*cp, peer);
+ ctl_flushpkt(0);
+ return;
+ }
+ n = 0;
+ rpkt.status = htons(ctlsysstatus());
+ for (peer = peer_list; peer != NULL; peer = peer->p_link) {
+ a_st[n++] = htons(peer->associd);
+ a_st[n++] = htons(ctlpeerstatus(peer));
+ /* two entries each loop iteration, so n + 1 */
+ if (n + 1 >= COUNTOF(a_st)) {
+ ctl_putdata((void *)a_st, n * sizeof(a_st[0]),
+ 1);
+ n = 0;
+ }
+ }
+ if (n)
+ ctl_putdata((void *)a_st, n * sizeof(a_st[0]), 1);
+ ctl_flushpkt(0);
+}
- rpkt.status = htons(ctlpeerstatus(peer));
- if (res_authokay)
- peer->num_events = 0;
- /*
- * For now, output everything we know about the
- * peer. May be more selective later.
- */
- for (cp = def_peer_var; *cp != 0; cp++)
- ctl_putpeer((int)*cp, peer);
- ctl_flushpkt(0);
+
+/*
+ * read_peervars - half of read_variables() implementation
+ */
+static void
+read_peervars(void)
+{
+ const struct ctl_var *v;
+ struct peer *peer;
+ const u_char *cp;
+ size_t i;
+ char * valuep;
+ u_char wants[CP_MAXCODE + 1];
+ u_int gotvar;
+
+ /*
+ * Wants info for a particular peer. See if we know
+ * the guy.
+ */
+ peer = findpeerbyassoc(res_associd);
+ if (NULL == peer) {
+ ctl_error(CERR_BADASSOC);
+ return;
+ }
+ rpkt.status = htons(ctlpeerstatus(peer));
+ if (res_authokay)
+ peer->num_events = 0;
+ ZERO(wants);
+ gotvar = 0;
+ while (NULL != (v = ctl_getitem(peer_var, &valuep))) {
+ if (v->flags & EOV) {
+ ctl_error(CERR_UNKNOWNVAR);
+ return;
}
+ NTP_INSIST(v->code < COUNTOF(wants));
+ wants[v->code] = 1;
+ gotvar = 1;
}
+ if (gotvar) {
+ for (i = 1; i < COUNTOF(wants); i++)
+ if (wants[i])
+ ctl_putpeer(i, peer);
+ } else
+ for (cp = def_peer_var; *cp != 0; cp++)
+ ctl_putpeer((int)*cp, peer);
+ ctl_flushpkt(0);
}
/*
- * read_variables - return the variables the caller asks for
+ * read_sysvars - half of read_variables() implementation
*/
-/*ARGSUSED*/
static void
-read_variables(
- struct recvbuf *rbufp,
- int restrict_mask
- )
+read_sysvars(void)
{
- register struct ctl_var *v;
- register int i;
- char *valuep;
+ const struct ctl_var *v;
+ struct ctl_var *kv;
+ u_int n;
+ u_int gotvar;
+ const u_char *cs;
+ char * valuep;
+ const char * pch;
u_char *wants;
- unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE +
- 1) : (CP_MAXCODE + 1);
- if (res_associd == 0) {
- /*
- * Wants system variables. Figure out which he wants
- * and give them to him.
- */
- rpkt.status = htons(ctlsysstatus());
- if (res_authokay)
- ctl_sys_num_events = 0;
- gotvar += count_var(ext_sys_var);
- wants = (u_char *)emalloc(gotvar);
- memset((char *)wants, 0, gotvar);
- gotvar = 0;
- while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
- if (v->flags & EOV) {
- if ((v = ctl_getitem(ext_sys_var,
- &valuep)) != 0) {
- if (v->flags & EOV) {
- ctl_error(CERR_UNKNOWNVAR);
- free((char *)wants);
- return;
- }
- wants[CS_MAXCODE + 1 +
- v->code] = 1;
- gotvar = 1;
- continue;
- } else {
- break; /* shouldn't happen ! */
- }
- }
+ size_t wants_count;
+
+ /*
+ * Wants system variables. Figure out which he wants
+ * and give them to him.
+ */
+ rpkt.status = htons(ctlsysstatus());
+ if (res_authokay)
+ ctl_sys_num_events = 0;
+ wants_count = CS_MAXCODE + 1 + count_var(ext_sys_var);
+ wants = emalloc_zero(wants_count);
+ gotvar = 0;
+ while (NULL != (v = ctl_getitem(sys_var, &valuep))) {
+ if (!(EOV & v->flags)) {
+ NTP_INSIST(v->code < wants_count);
wants[v->code] = 1;
gotvar = 1;
- }
- if (gotvar) {
- for (i = 1; i <= CS_MAXCODE; i++)
- if (wants[i])
- ctl_putsys(i);
- for (i = 0; ext_sys_var &&
- !(ext_sys_var[i].flags & EOV); i++)
- if (wants[i + CS_MAXCODE + 1])
- ctl_putdata(ext_sys_var[i].text,
- strlen(ext_sys_var[i].text),
- 0);
} else {
- register u_char *cs;
- register struct ctl_var *kv;
-
- for (cs = def_sys_var; *cs != 0; cs++)
- ctl_putsys((int)*cs);
- for (kv = ext_sys_var; kv && !(kv->flags & EOV);
- kv++)
- if (kv->flags & DEF)
- ctl_putdata(kv->text,
- strlen(kv->text), 0);
- }
- free((char *)wants);
- } else {
- register struct peer *peer;
-
- /*
- * Wants info for a particular peer. See if we know
- * the guy.
- */
- peer = findpeerbyassoc(res_associd);
- if (peer == 0) {
- ctl_error(CERR_BADASSOC);
- return;
- }
- rpkt.status = htons(ctlpeerstatus(peer));
- if (res_authokay)
- peer->num_events = 0;
- wants = (u_char *)emalloc(gotvar);
- memset((char*)wants, 0, gotvar);
- gotvar = 0;
- while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
- if (v->flags & EOV) {
+ v = ctl_getitem(ext_sys_var, &valuep);
+ NTP_INSIST(v != NULL);
+ if (EOV & v->flags) {
ctl_error(CERR_UNKNOWNVAR);
- free((char *)wants);
+ free(wants);
return;
}
- wants[v->code] = 1;
+ n = v->code + CS_MAXCODE + 1;
+ NTP_INSIST(n < wants_count);
+ wants[n] = 1;
gotvar = 1;
}
- if (gotvar) {
- for (i = 1; i <= CP_MAXCODE; i++)
- if (wants[i])
- ctl_putpeer(i, peer);
- } else {
- register u_char *cp;
-
- for (cp = def_peer_var; *cp != 0; cp++)
- ctl_putpeer((int)*cp, peer);
- }
- free((char *)wants);
}
+ if (gotvar) {
+ for (n = 1; n <= CS_MAXCODE; n++)
+ if (wants[n])
+ ctl_putsys(n);
+ for (n = 0; n + CS_MAXCODE + 1 < wants_count; n++)
+ if (wants[n + CS_MAXCODE + 1]) {
+ pch = ext_sys_var[n].text;
+ ctl_putdata(pch, strlen(pch), 0);
+ }
+ } else {
+ for (cs = def_sys_var; *cs != 0; cs++)
+ ctl_putsys((int)*cs);
+ for (kv = ext_sys_var; kv && !(EOV & kv->flags); kv++)
+ if (DEF & kv->flags)
+ ctl_putdata(kv->text, strlen(kv->text),
+ 0);
+ }
+ free(wants);
ctl_flushpkt(0);
}
/*
+ * read_variables - return the variables the caller asks for
+ */
+/*ARGSUSED*/
+static void
+read_variables(
+ struct recvbuf *rbufp,
+ int restrict_mask
+ )
+{
+ if (res_associd)
+ read_peervars();
+ else
+ read_sysvars();
+}
+
+
+/*
* write_variables - write into variables. We only allow leap bit
* writing this way.
*/
@@ -2234,11 +3225,16 @@ write_variables(
int restrict_mask
)
{
- register struct ctl_var *v;
- register int ext_var;
+ const struct ctl_var *v;
+ int ext_var;
char *valuep;
- long val = 0;
+ long val;
+ size_t octets;
+ char *vareqv;
+ const char *t;
+ char *tt;
+ val = 0;
/*
* If he's trying to write into a peer tell him no way
*/
@@ -2275,7 +3271,7 @@ write_variables(
return;
}
if (!ext_var && (*valuep == '\0' || !atoint(valuep,
- &val))) {
+ &val))) {
ctl_error(CERR_BADFMT);
return;
}
@@ -2285,30 +3281,19 @@ write_variables(
}
if (ext_var) {
- char *s = (char *)emalloc(strlen(v->text) +
- strlen(valuep) + 2);
- const char *t;
- char *tt = s;
-
+ octets = strlen(v->text) + strlen(valuep) + 2;
+ vareqv = emalloc(octets);
+ tt = vareqv;
t = v->text;
while (*t && *t != '=')
*tt++ = *t++;
-
*tt++ = '=';
- strcat(tt, valuep);
- set_sys_var(s, strlen(s)+1, v->flags);
- free(s);
+ memcpy(tt, valuep, 1 + strlen(valuep));
+ set_sys_var(vareqv, 1 + strlen(vareqv), v->flags);
+ free(vareqv);
} else {
- /*
- * This one seems sane. Save it.
- */
- switch(v->code) {
-
- case CS_LEAP:
- default:
- ctl_error(CERR_UNSPEC); /* really */
- return;
- }
+ ctl_error(CERR_UNSPEC); /* really */
+ return;
}
}
@@ -2317,10 +3302,10 @@ write_variables(
*/
/*
if (leapind != ~0 || leapwarn != ~0) {
- if (!leap_setleap((int)leapind, (int)leapwarn)) {
- ctl_error(CERR_PERMISSION);
- return;
- }
+ if (!leap_setleap((int)leapind, (int)leapwarn)) {
+ ctl_error(CERR_PERMISSION);
+ return;
+ }
}
*/
ctl_flushpkt(0);
@@ -2328,11 +3313,1035 @@ write_variables(
/*
- * read_clock_status - return clock radio status
+ * configure() processes ntpq :config/config-from-file, allowing
+ * generic runtime reconfiguration.
+ */
+static void configure(
+ struct recvbuf *rbufp,
+ int restrict_mask
+ )
+{
+ size_t data_count;
+ int retval;
+
+ /* I haven't yet implemented changes to an existing association.
+ * Hence check if the association id is 0
+ */
+ if (res_associd != 0) {
+ ctl_error(CERR_BADVALUE);
+ return;
+ }
+
+ if (RES_NOMODIFY & restrict_mask) {
+ snprintf(remote_config.err_msg,
+ sizeof(remote_config.err_msg),
+ "runtime configuration prohibited by restrict ... nomodify");
+ ctl_putdata(remote_config.err_msg,
+ strlen(remote_config.err_msg), 0);
+ ctl_flushpkt(0);
+ NLOG(NLOG_SYSINFO)
+ msyslog(LOG_NOTICE,
+ "runtime config from %s rejected due to nomodify restriction",
+ stoa(&rbufp->recv_srcadr));
+ sys_restricted++;
+ return;
+ }
+
+ /* Initialize the remote config buffer */
+ data_count = remoteconfig_cmdlength(reqpt, reqend);
+
+ if (data_count > sizeof(remote_config.buffer) - 2) {
+ snprintf(remote_config.err_msg,
+ sizeof(remote_config.err_msg),
+ "runtime configuration failed: request too long");
+ ctl_putdata(remote_config.err_msg,
+ strlen(remote_config.err_msg), 0);
+ ctl_flushpkt(0);
+ msyslog(LOG_NOTICE,
+ "runtime config from %s rejected: request too long",
+ stoa(&rbufp->recv_srcadr));
+ return;
+ }
+ /* Bug 2853 -- check if all characters were acceptable */
+ if (data_count != (size_t)(reqend - reqpt)) {
+ snprintf(remote_config.err_msg,
+ sizeof(remote_config.err_msg),
+ "runtime configuration failed: request contains an unprintable character");
+ ctl_putdata(remote_config.err_msg,
+ strlen(remote_config.err_msg), 0);
+ ctl_flushpkt(0);
+ msyslog(LOG_NOTICE,
+ "runtime config from %s rejected: request contains an unprintable character: %0x",
+ stoa(&rbufp->recv_srcadr),
+ reqpt[data_count]);
+ return;
+ }
+
+ memcpy(remote_config.buffer, reqpt, data_count);
+ /* The buffer has no trailing linefeed or NUL right now. For
+ * logging, we do not want a newline, so we do that first after
+ * adding the necessary NUL byte.
+ */
+ remote_config.buffer[data_count] = '\0';
+ DPRINTF(1, ("Got Remote Configuration Command: %s\n",
+ remote_config.buffer));
+ msyslog(LOG_NOTICE, "%s config: %s",
+ stoa(&rbufp->recv_srcadr),
+ remote_config.buffer);
+
+ /* Now we have to make sure there is a NL/NUL sequence at the
+ * end of the buffer before we parse it.
+ */
+ remote_config.buffer[data_count++] = '\n';
+ remote_config.buffer[data_count] = '\0';
+ remote_config.pos = 0;
+ remote_config.err_pos = 0;
+ remote_config.no_errors = 0;
+ config_remotely(&rbufp->recv_srcadr);
+
+ /*
+ * Check if errors were reported. If not, output 'Config
+ * Succeeded'. Else output the error count. It would be nice
+ * to output any parser error messages.
+ */
+ if (0 == remote_config.no_errors) {
+ retval = snprintf(remote_config.err_msg,
+ sizeof(remote_config.err_msg),
+ "Config Succeeded");
+ if (retval > 0)
+ remote_config.err_pos += retval;
+ }
+
+ ctl_putdata(remote_config.err_msg, remote_config.err_pos, 0);
+ ctl_flushpkt(0);
+
+ DPRINTF(1, ("Reply: %s\n", remote_config.err_msg));
+
+ if (remote_config.no_errors > 0)
+ msyslog(LOG_NOTICE, "%d error in %s config",
+ remote_config.no_errors,
+ stoa(&rbufp->recv_srcadr));
+}
+
+
+/*
+ * derive_nonce - generate client-address-specific nonce value
+ * associated with a given timestamp.
+ */
+static u_int32 derive_nonce(
+ sockaddr_u * addr,
+ u_int32 ts_i,
+ u_int32 ts_f
+ )
+{
+ static u_int32 salt[4];
+ static u_long last_salt_update;
+ union d_tag {
+ u_char digest[EVP_MAX_MD_SIZE];
+ u_int32 extract;
+ } d;
+ EVP_MD_CTX ctx;
+ u_int len;
+
+ while (!salt[0] || current_time - last_salt_update >= 3600) {
+ salt[0] = ntp_random();
+ salt[1] = ntp_random();
+ salt[2] = ntp_random();
+ salt[3] = ntp_random();
+ last_salt_update = current_time;
+ }
+
+ EVP_DigestInit(&ctx, EVP_get_digestbynid(NID_md5));
+ EVP_DigestUpdate(&ctx, salt, sizeof(salt));
+ EVP_DigestUpdate(&ctx, &ts_i, sizeof(ts_i));
+ EVP_DigestUpdate(&ctx, &ts_f, sizeof(ts_f));
+ if (IS_IPV4(addr))
+ EVP_DigestUpdate(&ctx, &SOCK_ADDR4(addr),
+ sizeof(SOCK_ADDR4(addr)));
+ else
+ EVP_DigestUpdate(&ctx, &SOCK_ADDR6(addr),
+ sizeof(SOCK_ADDR6(addr)));
+ EVP_DigestUpdate(&ctx, &NSRCPORT(addr), sizeof(NSRCPORT(addr)));
+ EVP_DigestUpdate(&ctx, salt, sizeof(salt));
+ EVP_DigestFinal(&ctx, d.digest, &len);
+
+ return d.extract;
+}
+
+
+/*
+ * generate_nonce - generate client-address-specific nonce string.
+ */
+static void generate_nonce(
+ struct recvbuf * rbufp,
+ char * nonce,
+ size_t nonce_octets
+ )
+{
+ u_int32 derived;
+
+ derived = derive_nonce(&rbufp->recv_srcadr,
+ rbufp->recv_time.l_ui,
+ rbufp->recv_time.l_uf);
+ snprintf(nonce, nonce_octets, "%08x%08x%08x",
+ rbufp->recv_time.l_ui, rbufp->recv_time.l_uf, derived);
+}
+
+
+/*
+ * validate_nonce - validate client-address-specific nonce string.
+ *
+ * Returns TRUE if the local calculation of the nonce matches the
+ * client-provided value and the timestamp is recent enough.
+ */
+static int validate_nonce(
+ const char * pnonce,
+ struct recvbuf * rbufp
+ )
+{
+ u_int ts_i;
+ u_int ts_f;
+ l_fp ts;
+ l_fp now_delta;
+ u_int supposed;
+ u_int derived;
+
+ if (3 != sscanf(pnonce, "%08x%08x%08x", &ts_i, &ts_f, &supposed))
+ return FALSE;
+
+ ts.l_ui = (u_int32)ts_i;
+ ts.l_uf = (u_int32)ts_f;
+ derived = derive_nonce(&rbufp->recv_srcadr, ts.l_ui, ts.l_uf);
+ get_systime(&now_delta);
+ L_SUB(&now_delta, &ts);
+
+ return (supposed == derived && now_delta.l_ui < 16);
+}
+
+
+/*
+ * send_random_tag_value - send a randomly-generated three character
+ * tag prefix, a '.', an index, a '=' and a
+ * random integer value.
+ *
+ * To try to force clients to ignore unrecognized tags in mrulist,
+ * reslist, and ifstats responses, the first and last rows are spiced
+ * with randomly-generated tag names with correct .# index. Make it
+ * three characters knowing that none of the currently-used subscripted
+ * tags have that length, avoiding the need to test for
+ * tag collision.
+ */
+static void
+send_random_tag_value(
+ int indx
+ )
+{
+ int noise;
+ char buf[32];
+
+ noise = rand() ^ (rand() << 16);
+ buf[0] = 'a' + noise % 26;
+ noise >>= 5;
+ buf[1] = 'a' + noise % 26;
+ noise >>= 5;
+ buf[2] = 'a' + noise % 26;
+ noise >>= 5;
+ buf[3] = '.';
+ snprintf(&buf[4], sizeof(buf) - 4, "%d", indx);
+ ctl_putuint(buf, noise);
+}
+
+
+/*
+ * Send a MRU list entry in response to a "ntpq -c mrulist" operation.
+ *
+ * To keep clients honest about not depending on the order of values,
+ * and thereby avoid being locked into ugly workarounds to maintain
+ * backward compatibility later as new fields are added to the response,
+ * the order is random.
+ */
+static void
+send_mru_entry(
+ mon_entry * mon,
+ int count
+ )
+{
+ const char first_fmt[] = "first.%d";
+ const char ct_fmt[] = "ct.%d";
+ const char mv_fmt[] = "mv.%d";
+ const char rs_fmt[] = "rs.%d";
+ char tag[32];
+ u_char sent[6]; /* 6 tag=value pairs */
+ u_int32 noise;
+ u_int which;
+ u_int remaining;
+ const char * pch;
+
+ remaining = COUNTOF(sent);
+ ZERO(sent);
+ noise = (u_int32)(rand() ^ (rand() << 16));
+ while (remaining > 0) {
+ which = (noise & 7) % COUNTOF(sent);
+ noise >>= 3;
+ while (sent[which])
+ which = (which + 1) % COUNTOF(sent);
+
+ switch (which) {
+
+ case 0:
+ snprintf(tag, sizeof(tag), addr_fmt, count);
+ pch = sptoa(&mon->rmtadr);
+ ctl_putunqstr(tag, pch, strlen(pch));
+ break;
+
+ case 1:
+ snprintf(tag, sizeof(tag), last_fmt, count);
+ ctl_putts(tag, &mon->last);
+ break;
+
+ case 2:
+ snprintf(tag, sizeof(tag), first_fmt, count);
+ ctl_putts(tag, &mon->first);
+ break;
+
+ case 3:
+ snprintf(tag, sizeof(tag), ct_fmt, count);
+ ctl_putint(tag, mon->count);
+ break;
+
+ case 4:
+ snprintf(tag, sizeof(tag), mv_fmt, count);
+ ctl_putuint(tag, mon->vn_mode);
+ break;
+
+ case 5:
+ snprintf(tag, sizeof(tag), rs_fmt, count);
+ ctl_puthex(tag, mon->flags);
+ break;
+ }
+ sent[which] = TRUE;
+ remaining--;
+ }
+}
+
+
+/*
+ * read_mru_list - supports ntpq's mrulist command.
+ *
+ * The challenge here is to match ntpdc's monlist functionality without
+ * being limited to hundreds of entries returned total, and without
+ * requiring state on the server. If state were required, ntpq's
+ * mrulist command would require authentication.
+ *
+ * The approach was suggested by Ry Jones. A finite and variable number
+ * of entries are retrieved per request, to avoid having responses with
+ * such large numbers of packets that socket buffers are overflowed and
+ * packets lost. The entries are retrieved oldest-first, taking into
+ * account that the MRU list will be changing between each request. We
+ * can expect to see duplicate entries for addresses updated in the MRU
+ * list during the fetch operation. In the end, the client can assemble
+ * a close approximation of the MRU list at the point in time the last
+ * response was sent by ntpd. The only difference is it may be longer,
+ * containing some number of oldest entries which have since been
+ * reclaimed. If necessary, the protocol could be extended to zap those
+ * from the client snapshot at the end, but so far that doesn't seem
+ * useful.
+ *
+ * To accomodate the changing MRU list, the starting point for requests
+ * after the first request is supplied as a series of last seen
+ * timestamps and associated addresses, the newest ones the client has
+ * received. As long as at least one of those entries hasn't been
+ * bumped to the head of the MRU list, ntpd can pick up at that point.
+ * Otherwise, the request is failed and it is up to ntpq to back up and
+ * provide the next newest entry's timestamps and addresses, conceivably
+ * backing up all the way to the starting point.
+ *
+ * input parameters:
+ * nonce= Regurgitated nonce retrieved by the client
+ * previously using CTL_OP_REQ_NONCE, demonstrating
+ * ability to receive traffic sent to its address.
+ * frags= Limit on datagrams (fragments) in response. Used
+ * by newer ntpq versions instead of limit= when
+ * retrieving multiple entries.
+ * limit= Limit on MRU entries returned. One of frags= or
+ * limit= must be provided.
+ * limit=1 is a special case: Instead of fetching
+ * beginning with the supplied starting point's
+ * newer neighbor, fetch the supplied entry, and
+ * in that case the #.last timestamp can be zero.
+ * This enables fetching a single entry by IP
+ * address. When limit is not one and frags= is
+ * provided, the fragment limit controls.
+ * mincount= (decimal) Return entries with count >= mincount.
+ * laddr= Return entries associated with the server's IP
+ * address given. No port specification is needed,
+ * and any supplied is ignored.
+ * resall= 0x-prefixed hex restrict bits which must all be
+ * lit for an MRU entry to be included.
+ * Has precedence over any resany=.
+ * resany= 0x-prefixed hex restrict bits, at least one of
+ * which must be list for an MRU entry to be
+ * included.
+ * last.0= 0x-prefixed hex l_fp timestamp of newest entry
+ * which client previously received.
+ * addr.0= text of newest entry's IP address and port,
+ * IPv6 addresses in bracketed form: [::]:123
+ * last.1= timestamp of 2nd newest entry client has.
+ * addr.1= address of 2nd newest entry.
+ * [...]
+ *
+ * ntpq provides as many last/addr pairs as will fit in a single request
+ * packet, except for the first request in a MRU fetch operation.
+ *
+ * The response begins with a new nonce value to be used for any
+ * followup request. Following the nonce is the next newer entry than
+ * referred to by last.0 and addr.0, if the "0" entry has not been
+ * bumped to the front. If it has, the first entry returned will be the
+ * next entry newer than referred to by last.1 and addr.1, and so on.
+ * If none of the referenced entries remain unchanged, the request fails
+ * and ntpq backs up to the next earlier set of entries to resync.
+ *
+ * Except for the first response, the response begins with confirmation
+ * of the entry that precedes the first additional entry provided:
+ *
+ * last.older= hex l_fp timestamp matching one of the input
+ * .last timestamps, which entry now precedes the
+ * response 0. entry in the MRU list.
+ * addr.older= text of address corresponding to older.last.
+ *
+ * And in any case, a successful response contains sets of values
+ * comprising entries, with the oldest numbered 0 and incrementing from
+ * there:
+ *
+ * addr.# text of IPv4 or IPv6 address and port
+ * last.# hex l_fp timestamp of last receipt
+ * first.# hex l_fp timestamp of first receipt
+ * ct.# count of packets received
+ * mv.# mode and version
+ * rs.# restriction mask (RES_* bits)
+ *
+ * Note the code currently assumes there are no valid three letter
+ * tags sent with each row, and needs to be adjusted if that changes.
+ *
+ * The client should accept the values in any order, and ignore .#
+ * values which it does not understand, to allow a smooth path to
+ * future changes without requiring a new opcode. Clients can rely
+ * on all *.0 values preceding any *.1 values, that is all values for
+ * a given index number are together in the response.
+ *
+ * The end of the response list is noted with one or two tag=value
+ * pairs. Unconditionally:
+ *
+ * now= 0x-prefixed l_fp timestamp at the server marking
+ * the end of the operation.
+ *
+ * If any entries were returned, now= is followed by:
+ *
+ * last.newest= hex l_fp identical to last.# of the prior
+ * entry.
+ */
+static void read_mru_list(
+ struct recvbuf *rbufp,
+ int restrict_mask
+ )
+{
+ const char nonce_text[] = "nonce";
+ const char frags_text[] = "frags";
+ const char limit_text[] = "limit";
+ const char mincount_text[] = "mincount";
+ const char resall_text[] = "resall";
+ const char resany_text[] = "resany";
+ const char maxlstint_text[] = "maxlstint";
+ const char laddr_text[] = "laddr";
+ const char resaxx_fmt[] = "0x%hx";
+ u_int limit;
+ u_short frags;
+ u_short resall;
+ u_short resany;
+ int mincount;
+ u_int maxlstint;
+ sockaddr_u laddr;
+ struct interface * lcladr;
+ u_int count;
+ u_int ui;
+ u_int uf;
+ l_fp last[16];
+ sockaddr_u addr[COUNTOF(last)];
+ char buf[128];
+ struct ctl_var * in_parms;
+ const struct ctl_var * v;
+ char * val;
+ const char * pch;
+ char * pnonce;
+ int nonce_valid;
+ size_t i;
+ int priors;
+ u_short hash;
+ mon_entry * mon;
+ mon_entry * prior_mon;
+ l_fp now;
+
+ if (RES_NOMRULIST & restrict_mask) {
+ ctl_error(CERR_PERMISSION);
+ NLOG(NLOG_SYSINFO)
+ msyslog(LOG_NOTICE,
+ "mrulist from %s rejected due to nomrulist restriction",
+ stoa(&rbufp->recv_srcadr));
+ sys_restricted++;
+ return;
+ }
+ /*
+ * fill in_parms var list with all possible input parameters.
+ */
+ in_parms = NULL;
+ set_var(&in_parms, nonce_text, sizeof(nonce_text), 0);
+ set_var(&in_parms, frags_text, sizeof(frags_text), 0);
+ set_var(&in_parms, limit_text, sizeof(limit_text), 0);
+ set_var(&in_parms, mincount_text, sizeof(mincount_text), 0);
+ set_var(&in_parms, resall_text, sizeof(resall_text), 0);
+ set_var(&in_parms, resany_text, sizeof(resany_text), 0);
+ set_var(&in_parms, maxlstint_text, sizeof(maxlstint_text), 0);
+ set_var(&in_parms, laddr_text, sizeof(laddr_text), 0);
+ for (i = 0; i < COUNTOF(last); i++) {
+ snprintf(buf, sizeof(buf), last_fmt, (int)i);
+ set_var(&in_parms, buf, strlen(buf) + 1, 0);
+ snprintf(buf, sizeof(buf), addr_fmt, (int)i);
+ set_var(&in_parms, buf, strlen(buf) + 1, 0);
+ }
+
+ /* decode input parms */
+ pnonce = NULL;
+ frags = 0;
+ limit = 0;
+ mincount = 0;
+ resall = 0;
+ resany = 0;
+ maxlstint = 0;
+ lcladr = NULL;
+ priors = 0;
+ ZERO(last);
+ ZERO(addr);
+
+ while (NULL != (v = ctl_getitem(in_parms, &val)) &&
+ !(EOV & v->flags)) {
+ int si;
+
+ if (!strcmp(nonce_text, v->text)) {
+ if (NULL != pnonce)
+ free(pnonce);
+ pnonce = estrdup(val);
+ } else if (!strcmp(frags_text, v->text)) {
+ sscanf(val, "%hu", &frags);
+ } else if (!strcmp(limit_text, v->text)) {
+ sscanf(val, "%u", &limit);
+ } else if (!strcmp(mincount_text, v->text)) {
+ if (1 != sscanf(val, "%d", &mincount) ||
+ mincount < 0)
+ mincount = 0;
+ } else if (!strcmp(resall_text, v->text)) {
+ sscanf(val, resaxx_fmt, &resall);
+ } else if (!strcmp(resany_text, v->text)) {
+ sscanf(val, resaxx_fmt, &resany);
+ } else if (!strcmp(maxlstint_text, v->text)) {
+ sscanf(val, "%u", &maxlstint);
+ } else if (!strcmp(laddr_text, v->text)) {
+ if (decodenetnum(val, &laddr))
+ lcladr = getinterface(&laddr, 0);
+ } else if (1 == sscanf(v->text, last_fmt, &si) &&
+ (size_t)si < COUNTOF(last)) {
+ if (2 == sscanf(val, "0x%08x.%08x", &ui, &uf)) {
+ last[si].l_ui = ui;
+ last[si].l_uf = uf;
+ if (!SOCK_UNSPEC(&addr[si]) &&
+ si == priors)
+ priors++;
+ }
+ } else if (1 == sscanf(v->text, addr_fmt, &si) &&
+ (size_t)si < COUNTOF(addr)) {
+ if (decodenetnum(val, &addr[si])
+ && last[si].l_ui && last[si].l_uf &&
+ si == priors)
+ priors++;
+ }
+ }
+ free_varlist(in_parms);
+ in_parms = NULL;
+
+ /* return no responses until the nonce is validated */
+ if (NULL == pnonce)
+ return;
+
+ nonce_valid = validate_nonce(pnonce, rbufp);
+ free(pnonce);
+ if (!nonce_valid)
+ return;
+
+ if ((0 == frags && !(0 < limit && limit <= MRU_ROW_LIMIT)) ||
+ frags > MRU_FRAGS_LIMIT) {
+ ctl_error(CERR_BADVALUE);
+ return;
+ }
+
+ /*
+ * If either frags or limit is not given, use the max.
+ */
+ if (0 != frags && 0 == limit)
+ limit = UINT_MAX;
+ else if (0 != limit && 0 == frags)
+ frags = MRU_FRAGS_LIMIT;
+
+ /*
+ * Find the starting point if one was provided.
+ */
+ mon = NULL;
+ for (i = 0; i < (size_t)priors; i++) {
+ hash = MON_HASH(&addr[i]);
+ for (mon = mon_hash[hash];
+ mon != NULL;
+ mon = mon->hash_next)
+ if (ADDR_PORT_EQ(&mon->rmtadr, &addr[i]))
+ break;
+ if (mon != NULL) {
+ if (L_ISEQU(&mon->last, &last[i]))
+ break;
+ mon = NULL;
+ }
+ }
+
+ /* If a starting point was provided... */
+ if (priors) {
+ /* and none could be found unmodified... */
+ if (NULL == mon) {
+ /* tell ntpq to try again with older entries */
+ ctl_error(CERR_UNKNOWNVAR);
+ return;
+ }
+ /* confirm the prior entry used as starting point */
+ ctl_putts("last.older", &mon->last);
+ pch = sptoa(&mon->rmtadr);
+ ctl_putunqstr("addr.older", pch, strlen(pch));
+
+ /*
+ * Move on to the first entry the client doesn't have,
+ * except in the special case of a limit of one. In
+ * that case return the starting point entry.
+ */
+ if (limit > 1)
+ mon = PREV_DLIST(mon_mru_list, mon, mru);
+ } else { /* start with the oldest */
+ mon = TAIL_DLIST(mon_mru_list, mru);
+ }
+
+ /*
+ * send up to limit= entries in up to frags= datagrams
+ */
+ get_systime(&now);
+ generate_nonce(rbufp, buf, sizeof(buf));
+ ctl_putunqstr("nonce", buf, strlen(buf));
+ prior_mon = NULL;
+ for (count = 0;
+ mon != NULL && res_frags < frags && count < limit;
+ mon = PREV_DLIST(mon_mru_list, mon, mru)) {
+
+ if (mon->count < mincount)
+ continue;
+ if (resall && resall != (resall & mon->flags))
+ continue;
+ if (resany && !(resany & mon->flags))
+ continue;
+ if (maxlstint > 0 && now.l_ui - mon->last.l_ui >
+ maxlstint)
+ continue;
+ if (lcladr != NULL && mon->lcladr != lcladr)
+ continue;
+
+ send_mru_entry(mon, count);
+ if (!count)
+ send_random_tag_value(0);
+ count++;
+ prior_mon = mon;
+ }
+
+ /*
+ * If this batch completes the MRU list, say so explicitly with
+ * a now= l_fp timestamp.
+ */
+ if (NULL == mon) {
+ if (count > 1)
+ send_random_tag_value(count - 1);
+ ctl_putts("now", &now);
+ /* if any entries were returned confirm the last */
+ if (prior_mon != NULL)
+ ctl_putts("last.newest", &prior_mon->last);
+ }
+ ctl_flushpkt(0);
+}
+
+
+/*
+ * Send a ifstats entry in response to a "ntpq -c ifstats" request.
+ *
+ * To keep clients honest about not depending on the order of values,
+ * and thereby avoid being locked into ugly workarounds to maintain
+ * backward compatibility later as new fields are added to the response,
+ * the order is random.
+ */
+static void
+send_ifstats_entry(
+ endpt * la,
+ u_int ifnum
+ )
+{
+ const char addr_fmtu[] = "addr.%u";
+ const char bcast_fmt[] = "bcast.%u";
+ const char en_fmt[] = "en.%u"; /* enabled */
+ const char name_fmt[] = "name.%u";
+ const char flags_fmt[] = "flags.%u";
+ const char tl_fmt[] = "tl.%u"; /* ttl */
+ const char mc_fmt[] = "mc.%u"; /* mcast count */
+ const char rx_fmt[] = "rx.%u";
+ const char tx_fmt[] = "tx.%u";
+ const char txerr_fmt[] = "txerr.%u";
+ const char pc_fmt[] = "pc.%u"; /* peer count */
+ const char up_fmt[] = "up.%u"; /* uptime */
+ char tag[32];
+ u_char sent[IFSTATS_FIELDS]; /* 12 tag=value pairs */
+ int noisebits;
+ u_int32 noise;
+ u_int which;
+ u_int remaining;
+ const char *pch;
+
+ remaining = COUNTOF(sent);
+ ZERO(sent);
+ noise = 0;
+ noisebits = 0;
+ while (remaining > 0) {
+ if (noisebits < 4) {
+ noise = rand() ^ (rand() << 16);
+ noisebits = 31;
+ }
+ which = (noise & 0xf) % COUNTOF(sent);
+ noise >>= 4;
+ noisebits -= 4;
+
+ while (sent[which])
+ which = (which + 1) % COUNTOF(sent);
+
+ switch (which) {
+
+ case 0:
+ snprintf(tag, sizeof(tag), addr_fmtu, ifnum);
+ pch = sptoa(&la->sin);
+ ctl_putunqstr(tag, pch, strlen(pch));
+ break;
+
+ case 1:
+ snprintf(tag, sizeof(tag), bcast_fmt, ifnum);
+ if (INT_BCASTOPEN & la->flags)
+ pch = sptoa(&la->bcast);
+ else
+ pch = "";
+ ctl_putunqstr(tag, pch, strlen(pch));
+ break;
+
+ case 2:
+ snprintf(tag, sizeof(tag), en_fmt, ifnum);
+ ctl_putint(tag, !la->ignore_packets);
+ break;
+
+ case 3:
+ snprintf(tag, sizeof(tag), name_fmt, ifnum);
+ ctl_putstr(tag, la->name, strlen(la->name));
+ break;
+
+ case 4:
+ snprintf(tag, sizeof(tag), flags_fmt, ifnum);
+ ctl_puthex(tag, (u_int)la->flags);
+ break;
+
+ case 5:
+ snprintf(tag, sizeof(tag), tl_fmt, ifnum);
+ ctl_putint(tag, la->last_ttl);
+ break;
+
+ case 6:
+ snprintf(tag, sizeof(tag), mc_fmt, ifnum);
+ ctl_putint(tag, la->num_mcast);
+ break;
+
+ case 7:
+ snprintf(tag, sizeof(tag), rx_fmt, ifnum);
+ ctl_putint(tag, la->received);
+ break;
+
+ case 8:
+ snprintf(tag, sizeof(tag), tx_fmt, ifnum);
+ ctl_putint(tag, la->sent);
+ break;
+
+ case 9:
+ snprintf(tag, sizeof(tag), txerr_fmt, ifnum);
+ ctl_putint(tag, la->notsent);
+ break;
+
+ case 10:
+ snprintf(tag, sizeof(tag), pc_fmt, ifnum);
+ ctl_putuint(tag, la->peercnt);
+ break;
+
+ case 11:
+ snprintf(tag, sizeof(tag), up_fmt, ifnum);
+ ctl_putuint(tag, current_time - la->starttime);
+ break;
+ }
+ sent[which] = TRUE;
+ remaining--;
+ }
+ send_random_tag_value((int)ifnum);
+}
+
+
+/*
+ * read_ifstats - send statistics for each local address, exposed by
+ * ntpq -c ifstats
+ */
+static void
+read_ifstats(
+ struct recvbuf * rbufp
+ )
+{
+ u_int ifidx;
+ endpt * la;
+
+ /*
+ * loop over [0..sys_ifnum] searching ep_list for each
+ * ifnum in turn.
+ */
+ for (ifidx = 0; ifidx < sys_ifnum; ifidx++) {
+ for (la = ep_list; la != NULL; la = la->elink)
+ if (ifidx == la->ifnum)
+ break;
+ if (NULL == la)
+ continue;
+ /* return stats for one local address */
+ send_ifstats_entry(la, ifidx);
+ }
+ ctl_flushpkt(0);
+}
+
+static void
+sockaddrs_from_restrict_u(
+ sockaddr_u * psaA,
+ sockaddr_u * psaM,
+ restrict_u * pres,
+ int ipv6
+ )
+{
+ ZERO(*psaA);
+ ZERO(*psaM);
+ if (!ipv6) {
+ psaA->sa.sa_family = AF_INET;
+ psaA->sa4.sin_addr.s_addr = htonl(pres->u.v4.addr);
+ psaM->sa.sa_family = AF_INET;
+ psaM->sa4.sin_addr.s_addr = htonl(pres->u.v4.mask);
+ } else {
+ psaA->sa.sa_family = AF_INET6;
+ memcpy(&psaA->sa6.sin6_addr, &pres->u.v6.addr,
+ sizeof(psaA->sa6.sin6_addr));
+ psaM->sa.sa_family = AF_INET6;
+ memcpy(&psaM->sa6.sin6_addr, &pres->u.v6.mask,
+ sizeof(psaA->sa6.sin6_addr));
+ }
+}
+
+
+/*
+ * Send a restrict entry in response to a "ntpq -c reslist" request.
+ *
+ * To keep clients honest about not depending on the order of values,
+ * and thereby avoid being locked into ugly workarounds to maintain
+ * backward compatibility later as new fields are added to the response,
+ * the order is random.
+ */
+static void
+send_restrict_entry(
+ restrict_u * pres,
+ int ipv6,
+ u_int idx
+ )
+{
+ const char addr_fmtu[] = "addr.%u";
+ const char mask_fmtu[] = "mask.%u";
+ const char hits_fmt[] = "hits.%u";
+ const char flags_fmt[] = "flags.%u";
+ char tag[32];
+ u_char sent[RESLIST_FIELDS]; /* 4 tag=value pairs */
+ int noisebits;
+ u_int32 noise;
+ u_int which;
+ u_int remaining;
+ sockaddr_u addr;
+ sockaddr_u mask;
+ const char * pch;
+ char * buf;
+ const char * match_str;
+ const char * access_str;
+
+ sockaddrs_from_restrict_u(&addr, &mask, pres, ipv6);
+ remaining = COUNTOF(sent);
+ ZERO(sent);
+ noise = 0;
+ noisebits = 0;
+ while (remaining > 0) {
+ if (noisebits < 2) {
+ noise = rand() ^ (rand() << 16);
+ noisebits = 31;
+ }
+ which = (noise & 0x3) % COUNTOF(sent);
+ noise >>= 2;
+ noisebits -= 2;
+
+ while (sent[which])
+ which = (which + 1) % COUNTOF(sent);
+
+ switch (which) {
+
+ case 0:
+ snprintf(tag, sizeof(tag), addr_fmtu, idx);
+ pch = stoa(&addr);
+ ctl_putunqstr(tag, pch, strlen(pch));
+ break;
+
+ case 1:
+ snprintf(tag, sizeof(tag), mask_fmtu, idx);
+ pch = stoa(&mask);
+ ctl_putunqstr(tag, pch, strlen(pch));
+ break;
+
+ case 2:
+ snprintf(tag, sizeof(tag), hits_fmt, idx);
+ ctl_putuint(tag, pres->count);
+ break;
+
+ case 3:
+ snprintf(tag, sizeof(tag), flags_fmt, idx);
+ match_str = res_match_flags(pres->mflags);
+ access_str = res_access_flags(pres->flags);
+ if ('\0' == match_str[0]) {
+ pch = access_str;
+ } else {
+ LIB_GETBUF(buf);
+ snprintf(buf, LIB_BUFLENGTH, "%s %s",
+ match_str, access_str);
+ pch = buf;
+ }
+ ctl_putunqstr(tag, pch, strlen(pch));
+ break;
+ }
+ sent[which] = TRUE;
+ remaining--;
+ }
+ send_random_tag_value((int)idx);
+}
+
+
+static void
+send_restrict_list(
+ restrict_u * pres,
+ int ipv6,
+ u_int * pidx
+ )
+{
+ for ( ; pres != NULL; pres = pres->link) {
+ send_restrict_entry(pres, ipv6, *pidx);
+ (*pidx)++;
+ }
+}
+
+
+/*
+ * read_addr_restrictions - returns IPv4 and IPv6 access control lists
+ */
+static void
+read_addr_restrictions(
+ struct recvbuf * rbufp
+)
+{
+ u_int idx;
+
+ idx = 0;
+ send_restrict_list(restrictlist4, FALSE, &idx);
+ send_restrict_list(restrictlist6, TRUE, &idx);
+ ctl_flushpkt(0);
+}
+
+
+/*
+ * read_ordlist - CTL_OP_READ_ORDLIST_A for ntpq -c ifstats & reslist
+ */
+static void
+read_ordlist(
+ struct recvbuf * rbufp,
+ int restrict_mask
+ )
+{
+ const char ifstats_s[] = "ifstats";
+ const size_t ifstats_chars = COUNTOF(ifstats_s) - 1;
+ const char addr_rst_s[] = "addr_restrictions";
+ const size_t a_r_chars = COUNTOF(addr_rst_s) - 1;
+ struct ntp_control * cpkt;
+ u_short qdata_octets;
+
+ /*
+ * CTL_OP_READ_ORDLIST_A was first named CTL_OP_READ_IFSTATS and
+ * used only for ntpq -c ifstats. With the addition of reslist
+ * the same opcode was generalized to retrieve ordered lists
+ * which require authentication. The request data is empty or
+ * contains "ifstats" (not null terminated) to retrieve local
+ * addresses and associated stats. It is "addr_restrictions"
+ * to retrieve the IPv4 then IPv6 remote address restrictions,
+ * which are access control lists. Other request data return
+ * CERR_UNKNOWNVAR.
+ */
+ cpkt = (struct ntp_control *)&rbufp->recv_pkt;
+ qdata_octets = ntohs(cpkt->count);
+ if (0 == qdata_octets || (ifstats_chars == qdata_octets &&
+ !memcmp(ifstats_s, cpkt->u.data, ifstats_chars))) {
+ read_ifstats(rbufp);
+ return;
+ }
+ if (a_r_chars == qdata_octets &&
+ !memcmp(addr_rst_s, cpkt->u.data, a_r_chars)) {
+ read_addr_restrictions(rbufp);
+ return;
+ }
+ ctl_error(CERR_UNKNOWNVAR);
+}
+
+
+/*
+ * req_nonce - CTL_OP_REQ_NONCE for ntpq -c mrulist prerequisite.
+ */
+static void req_nonce(
+ struct recvbuf * rbufp,
+ int restrict_mask
+ )
+{
+ char buf[64];
+
+ generate_nonce(rbufp, buf, sizeof(buf));
+ ctl_putunqstr("nonce", buf, strlen(buf));
+ ctl_flushpkt(0);
+}
+
+
+/*
+ * read_clockstatus - return clock radio status
*/
/*ARGSUSED*/
static void
-read_clock_status(
+read_clockstatus(
struct recvbuf *rbufp,
int restrict_mask
)
@@ -2343,108 +4352,91 @@ read_clock_status(
*/
ctl_error(CERR_BADASSOC);
#else
- register struct ctl_var *v;
- register int i;
- register struct peer *peer;
- char *valuep;
- u_char *wants;
- unsigned int gotvar;
- struct refclockstat clock_stat;
-
- if (res_associd == 0) {
+ const struct ctl_var * v;
+ int i;
+ struct peer * peer;
+ char * valuep;
+ u_char * wants;
+ size_t wants_alloc;
+ int gotvar;
+ const u_char * cc;
+ struct ctl_var * kv;
+ struct refclockstat cs;
+ if (res_associd != 0) {
+ peer = findpeerbyassoc(res_associd);
+ } else {
/*
* Find a clock for this jerk. If the system peer
- * is a clock use it, else search the hash tables
- * for one.
+ * is a clock use it, else search peer_list for one.
*/
- if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK))
- {
+ if (sys_peer != NULL && (FLAG_REFCLOCK &
+ sys_peer->flags))
peer = sys_peer;
- } else {
- peer = 0;
- for (i = 0; peer == 0 && i < NTP_HASH_SIZE; i++) {
- for (peer = assoc_hash[i]; peer != 0;
- peer = peer->ass_next) {
- if (peer->flags & FLAG_REFCLOCK)
- break;
- }
- }
- if (peer == 0) {
- ctl_error(CERR_BADASSOC);
- return;
- }
- }
- } else {
- peer = findpeerbyassoc(res_associd);
- if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) {
- ctl_error(CERR_BADASSOC);
- return;
- }
+ else
+ for (peer = peer_list;
+ peer != NULL;
+ peer = peer->p_link)
+ if (FLAG_REFCLOCK & peer->flags)
+ break;
+ }
+ if (NULL == peer || !(FLAG_REFCLOCK & peer->flags)) {
+ ctl_error(CERR_BADASSOC);
+ return;
}
-
/*
* If we got here we have a peer which is a clock. Get his
* status.
*/
- clock_stat.kv_list = (struct ctl_var *)0;
- refclock_control(&peer->srcadr, (struct refclockstat *)0,
- &clock_stat);
-
+ cs.kv_list = NULL;
+ refclock_control(&peer->srcadr, NULL, &cs);
+ kv = cs.kv_list;
/*
* Look for variables in the packet.
*/
- rpkt.status = htons(ctlclkstatus(&clock_stat));
- gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list);
- wants = (u_char *)emalloc(gotvar);
- memset((char*)wants, 0, gotvar);
- gotvar = 0;
- while ((v = ctl_getitem(clock_var, &valuep)) != 0) {
- if (v->flags & EOV) {
- if ((v = ctl_getitem(clock_stat.kv_list,
- &valuep)) != 0) {
- if (v->flags & EOV) {
- ctl_error(CERR_UNKNOWNVAR);
- free((char*)wants);
- free_varlist(clock_stat.kv_list);
- return;
- }
- wants[CC_MAXCODE + 1 + v->code] = 1;
- gotvar = 1;
- continue;
- } else {
- break; /* shouldn't happen ! */
+ rpkt.status = htons(ctlclkstatus(&cs));
+ wants_alloc = CC_MAXCODE + 1 + count_var(kv);
+ wants = emalloc_zero(wants_alloc);
+ gotvar = FALSE;
+ while (NULL != (v = ctl_getitem(clock_var, &valuep))) {
+ if (!(EOV & v->flags)) {
+ wants[v->code] = TRUE;
+ gotvar = TRUE;
+ } else {
+ v = ctl_getitem(kv, &valuep);
+ NTP_INSIST(NULL != v);
+ if (EOV & v->flags) {
+ ctl_error(CERR_UNKNOWNVAR);
+ free(wants);
+ free_varlist(cs.kv_list);
+ return;
}
+ wants[CC_MAXCODE + 1 + v->code] = TRUE;
+ gotvar = TRUE;
}
- wants[v->code] = 1;
- gotvar = 1;
}
if (gotvar) {
for (i = 1; i <= CC_MAXCODE; i++)
if (wants[i])
- ctl_putclock(i, &clock_stat, 1);
- for (i = 0; clock_stat.kv_list &&
- !(clock_stat.kv_list[i].flags & EOV); i++)
- if (wants[i + CC_MAXCODE + 1])
- ctl_putdata(clock_stat.kv_list[i].text,
- strlen(clock_stat.kv_list[i].text),
- 0);
+ ctl_putclock(i, &cs, TRUE);
+ if (kv != NULL)
+ for (i = 0; !(EOV & kv[i].flags); i++)
+ if (wants[i + CC_MAXCODE + 1])
+ ctl_putdata(kv[i].text,
+ strlen(kv[i].text),
+ FALSE);
} else {
- register u_char *cc;
- register struct ctl_var *kv;
-
for (cc = def_clock_var; *cc != 0; cc++)
- ctl_putclock((int)*cc, &clock_stat, 0);
- for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV);
- kv++)
- if (kv->flags & DEF)
+ ctl_putclock((int)*cc, &cs, FALSE);
+ for ( ; kv != NULL && !(EOV & kv->flags); kv++)
+ if (DEF & kv->flags)
ctl_putdata(kv->text, strlen(kv->text),
- 0);
+ FALSE);
}
- free((char*)wants);
- free_varlist(clock_stat.kv_list);
+ free(wants);
+ free_varlist(cs.kv_list);
ctl_flushpkt(0);
#endif
@@ -2452,11 +4444,11 @@ read_clock_status(
/*
- * write_clock_status - we don't do this
+ * write_clockstatus - we don't do this
*/
/*ARGSUSED*/
static void
-write_clock_status(
+write_clockstatus(
struct recvbuf *rbufp,
int restrict_mask
)
@@ -2500,7 +4492,7 @@ set_trap(
* an error if it can't assign the trap.
*/
if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype,
- (int)res_version))
+ (int)res_version))
ctl_error(CERR_NORESOURCE);
ctl_flushpkt(0);
}
@@ -2541,14 +4533,15 @@ unset_trap(
*/
int
ctlsettrap(
- struct sockaddr_storage *raddr,
+ sockaddr_u *raddr,
struct interface *linter,
int traptype,
int version
)
{
- register struct ctl_trap *tp;
- register struct ctl_trap *tptouse;
+ size_t n;
+ struct ctl_trap *tp;
+ struct ctl_trap *tptouse;
/*
* See if we can find this trap. If so, we only need update
@@ -2584,16 +4577,17 @@ ctlsettrap(
* have to. Clear out anyone who's expired while we're at it.
*/
tptouse = NULL;
- for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
- if ((tp->tr_flags & TRAP_INUSE) &&
- !(tp->tr_flags & TRAP_CONFIGURED) &&
+ for (n = 0; n < COUNTOF(ctl_traps); n++) {
+ tp = &ctl_traps[n];
+ if ((TRAP_INUSE & tp->tr_flags) &&
+ !(TRAP_CONFIGURED & tp->tr_flags) &&
((tp->tr_settime + CTL_TRAPTIME) > current_time)) {
tp->tr_flags = 0;
num_ctl_traps--;
}
- if (!(tp->tr_flags & TRAP_INUSE)) {
+ if (!(TRAP_INUSE & tp->tr_flags)) {
tptouse = tp;
- } else if (!(tp->tr_flags & TRAP_CONFIGURED)) {
+ } else if (!(TRAP_CONFIGURED & tp->tr_flags)) {
switch (traptype) {
case TRAP_TYPE_CONFIG:
@@ -2601,12 +4595,12 @@ ctlsettrap(
tptouse = tp;
break;
}
- if (tptouse->tr_flags & TRAP_NONPRIO &&
- !(tp->tr_flags & TRAP_NONPRIO))
+ if ((TRAP_NONPRIO & tptouse->tr_flags) &&
+ !(TRAP_NONPRIO & tp->tr_flags))
break;
- if (!(tptouse->tr_flags & TRAP_NONPRIO)
- && tp->tr_flags & TRAP_NONPRIO) {
+ if (!(TRAP_NONPRIO & tptouse->tr_flags)
+ && (TRAP_NONPRIO & tp->tr_flags)) {
tptouse = tp;
break;
}
@@ -2616,12 +4610,12 @@ ctlsettrap(
break;
case TRAP_TYPE_PRIO:
- if (tp->tr_flags & TRAP_NONPRIO) {
+ if ( TRAP_NONPRIO & tp->tr_flags) {
if (tptouse == NULL ||
- (tptouse->tr_flags &
- TRAP_INUSE &&
- tptouse->tr_origtime <
- tp->tr_origtime))
+ ((TRAP_INUSE &
+ tptouse->tr_flags) &&
+ tptouse->tr_origtime <
+ tp->tr_origtime))
tptouse = tp;
}
break;
@@ -2662,7 +4656,7 @@ ctlsettrap(
*/
int
ctlclrtrap(
- struct sockaddr_storage *raddr,
+ sockaddr_u *raddr,
struct interface *linter,
int traptype
)
@@ -2673,7 +4667,7 @@ ctlclrtrap(
return (0);
if (tp->tr_flags & TRAP_CONFIGURED
- && traptype != TRAP_TYPE_CONFIG)
+ && traptype != TRAP_TYPE_CONFIG)
return (0);
tp->tr_flags = 0;
@@ -2687,20 +4681,19 @@ ctlclrtrap(
*/
static struct ctl_trap *
ctlfindtrap(
- struct sockaddr_storage *raddr,
+ sockaddr_u *raddr,
struct interface *linter
)
{
- register struct ctl_trap *tp;
+ size_t n;
- for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
- if ((tp->tr_flags & TRAP_INUSE)
- && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr))
- && SOCKCMP(raddr, &tp->tr_addr)
- && (linter == tp->tr_localaddr) )
- return (tp);
- }
- return (struct ctl_trap *)NULL;
+ for (n = 0; n < COUNTOF(ctl_traps); n++)
+ if ((ctl_traps[n].tr_flags & TRAP_INUSE)
+ && ADDR_PORT_EQ(raddr, &ctl_traps[n].tr_addr)
+ && (linter == ctl_traps[n].tr_localaddr))
+ return &ctl_traps[n];
+
+ return NULL;
}
@@ -2709,69 +4702,80 @@ ctlfindtrap(
*/
void
report_event(
- int err,
- struct peer *peer
+ int err, /* error code */
+ struct peer *peer, /* peer structure pointer */
+ const char *str /* protostats string */
)
{
- register int i;
+ char statstr[NTP_MAXSTRLEN];
+ int i;
+ size_t len;
/*
- * Record error code in proper spots, but have mercy on the
- * log file.
+ * Report the error to the protostats file, system log and
+ * trappers.
*/
- if (!(err & (PEER_EVENT | CRPT_EVENT))) {
- if (ctl_sys_num_events < CTL_SYS_MAXEVENTS)
- ctl_sys_num_events++;
- if (ctl_sys_last_event != (u_char)err) {
- NLOG(NLOG_SYSEVENT)
- msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)",
- eventstr(err), err,
- sysstatstr(ctlsysstatus()), ctlsysstatus());
-#ifdef DEBUG
- if (debug)
- printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n",
- eventstr(err), err,
- sysstatstr(ctlsysstatus()),
- ctlsysstatus());
-#endif
- ctl_sys_last_event = (u_char)err;
+ if (peer == NULL) {
+
+ /*
+ * Discard a system report if the number of reports of
+ * the same type exceeds the maximum.
+ */
+ if (ctl_sys_last_event != (u_char)err)
+ ctl_sys_num_events= 0;
+ if (ctl_sys_num_events >= CTL_SYS_MAXEVENTS)
+ return;
+
+ ctl_sys_last_event = (u_char)err;
+ ctl_sys_num_events++;
+ snprintf(statstr, sizeof(statstr),
+ "0.0.0.0 %04x %02x %s",
+ ctlsysstatus(), err, eventstr(err));
+ if (str != NULL) {
+ len = strlen(statstr);
+ snprintf(statstr + len, sizeof(statstr) - len,
+ " %s", str);
}
- } else if (peer != 0) {
- char *src;
+ NLOG(NLOG_SYSEVENT)
+ msyslog(LOG_INFO, "%s", statstr);
+ } else {
-#ifdef REFCLOCK
+ /*
+ * Discard a peer report if the number of reports of
+ * the same type exceeds the maximum for that peer.
+ */
+ const char * src;
+ u_char errlast;
+
+ errlast = (u_char)err & ~PEER_EVENT;
+ if (peer->last_event == errlast)
+ peer->num_events = 0;
+ if (peer->num_events >= CTL_PEER_MAXEVENTS)
+ return;
+
+ peer->last_event = errlast;
+ peer->num_events++;
if (ISREFCLOCKADR(&peer->srcadr))
src = refnumtoa(&peer->srcadr);
else
-#endif
src = stoa(&peer->srcadr);
- peer->last_event = (u_char)(err & ~PEER_EVENT);
- if (peer->num_events < CTL_PEER_MAXEVENTS)
- peer->num_events++;
+ snprintf(statstr, sizeof(statstr),
+ "%s %04x %02x %s", src,
+ ctlpeerstatus(peer), err, eventstr(err));
+ if (str != NULL) {
+ len = strlen(statstr);
+ snprintf(statstr + len, sizeof(statstr) - len,
+ " %s", str);
+ }
NLOG(NLOG_PEEREVENT)
- msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)",
- src, eventstr(err), err,
- peerstatstr(ctlpeerstatus(peer)),
- ctlpeerstatus(peer));
-#ifdef DEBUG
- if (debug)
- printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n",
- src, eventstr(err), err,
- peerstatstr(ctlpeerstatus(peer)),
- ctlpeerstatus(peer));
-#endif
- } else {
- msyslog(LOG_ERR,
- "report_event: err '%s' (0x%02x), no peer",
- eventstr(err), err);
-#ifdef DEBUG
- printf(
- "report_event: peer event '%s' (0x%02x), no peer\n",
- eventstr(err), err);
-#endif
- return;
+ msyslog(LOG_INFO, "%s", statstr);
}
+ record_proto_stats(statstr);
+#if DEBUG
+ if (debug)
+ printf("event at %lu %s\n", current_time, statstr);
+#endif
/*
* If no trappers, return.
@@ -2784,87 +4788,50 @@ report_event(
*/
res_opcode = CTL_OP_ASYNCMSG;
res_offset = 0;
- res_async = 1;
- res_authenticate = 0;
- datapt = rpkt.data;
- dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
+ res_async = TRUE;
+ res_authenticate = FALSE;
+ datapt = rpkt.u.data;
+ dataend = &rpkt.u.data[CTL_MAX_DATA_LEN];
if (!(err & PEER_EVENT)) {
rpkt.associd = 0;
rpkt.status = htons(ctlsysstatus());
- /*
- * For now, put everything we know about system
- * variables. Don't send crypto strings.
- */
- for (i = 1; i <= CS_MAXCODE; i++) {
-#ifdef OPENSSL
- if (i > CS_VARLIST)
- continue;
-#endif /* OPENSSL */
+ /* Include the core system variables and the list. */
+ for (i = 1; i <= CS_VARLIST; i++)
ctl_putsys(i);
- }
-#ifdef REFCLOCK
- /*
- * for clock exception events: add clock variables to
- * reflect info on exception
- */
- if (err == EVNT_CLOCKEXCPT) {
- struct refclockstat clock_stat;
- struct ctl_var *kv;
-
- clock_stat.kv_list = (struct ctl_var *)0;
- refclock_control(&peer->srcadr,
- (struct refclockstat *)0, &clock_stat);
- ctl_puthex("refclockstatus",
- ctlclkstatus(&clock_stat));
- for (i = 1; i <= CC_MAXCODE; i++)
- ctl_putclock(i, &clock_stat, 0);
- for (kv = clock_stat.kv_list; kv &&
- !(kv->flags & EOV); kv++)
- if (kv->flags & DEF)
- ctl_putdata(kv->text,
- strlen(kv->text), 0);
- free_varlist(clock_stat.kv_list);
- }
-#endif /* REFCLOCK */
} else {
+ NTP_INSIST(peer != NULL);
rpkt.associd = htons(peer->associd);
rpkt.status = htons(ctlpeerstatus(peer));
- /*
- * Dump it all. Later, maybe less.
- */
- for (i = 1; i <= CP_MAXCODE; i++) {
-#ifdef OPENSSL
- if (i > CP_VARLIST)
- continue;
-#endif /* OPENSSL */
+ /* Dump it all. Later, maybe less. */
+ for (i = 1; i <= CP_MAX_NOAUTOKEY; i++)
ctl_putpeer(i, peer);
- }
#ifdef REFCLOCK
/*
* for clock exception events: add clock variables to
* reflect info on exception
*/
- if (err == EVNT_PEERCLOCK) {
- struct refclockstat clock_stat;
+ if (err == PEVNT_CLOCK) {
+ struct refclockstat cs;
struct ctl_var *kv;
- clock_stat.kv_list = (struct ctl_var *)0;
- refclock_control(&peer->srcadr,
- (struct refclockstat *)0, &clock_stat);
+ cs.kv_list = NULL;
+ refclock_control(&peer->srcadr, NULL, &cs);
ctl_puthex("refclockstatus",
- ctlclkstatus(&clock_stat));
+ ctlclkstatus(&cs));
for (i = 1; i <= CC_MAXCODE; i++)
- ctl_putclock(i, &clock_stat, 0);
- for (kv = clock_stat.kv_list; kv &&
- !(kv->flags & EOV); kv++)
- if (kv->flags & DEF)
+ ctl_putclock(i, &cs, FALSE);
+ for (kv = cs.kv_list;
+ kv != NULL && !(EOV & kv->flags);
+ kv++)
+ if (DEF & kv->flags)
ctl_putdata(kv->text,
- strlen(kv->text), 0);
- free_varlist(clock_stat.kv_list);
+ strlen(kv->text),
+ FALSE);
+ free_varlist(cs.kv_list);
}
#endif /* REFCLOCK */
}
@@ -2877,6 +4844,30 @@ report_event(
/*
+ * mprintf_event - printf-style varargs variant of report_event()
+ */
+int
+mprintf_event(
+ int evcode, /* event code */
+ struct peer * p, /* may be NULL */
+ const char * fmt, /* msnprintf format */
+ ...
+ )
+{
+ va_list ap;
+ int rc;
+ char msg[512];
+
+ va_start(ap, fmt);
+ rc = mvsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ report_event(evcode, p, msg);
+
+ return rc;
+}
+
+
+/*
* ctl_clr_stats - clear stat counters
*/
void
@@ -2900,22 +4891,25 @@ ctl_clr_stats(void)
numasyncmsgs = 0;
}
-static u_long
+static u_short
count_var(
- struct ctl_var *k
+ const struct ctl_var *k
)
{
- register u_long c;
+ u_int c;
- if (!k)
- return (0);
+ if (NULL == k)
+ return 0;
c = 0;
- while (!(k++->flags & EOV))
+ while (!(EOV & (k++)->flags))
c++;
- return (c);
+
+ NTP_ENSURE(c <= USHRT_MAX);
+ return (u_short)c;
}
+
char *
add_var(
struct ctl_var **kv,
@@ -2923,27 +4917,25 @@ add_var(
u_short def
)
{
- register u_long c;
- register struct ctl_var *k;
+ u_short c;
+ struct ctl_var *k;
+ char * buf;
c = count_var(*kv);
-
+ *kv = erealloc(*kv, (c + 2) * sizeof(**kv));
k = *kv;
- *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var));
- if (k) {
- memmove((char *)*kv, (char *)k,
- sizeof(struct ctl_var)*c);
- free((char *)k);
- }
- (*kv)[c].code = (u_short) c;
- (*kv)[c].text = (char *)emalloc(size);
- (*kv)[c].flags = def;
- (*kv)[c+1].code = 0;
- (*kv)[c+1].text = (char *)0;
- (*kv)[c+1].flags = EOV;
- return (char *)(*kv)[c].text;
+ buf = emalloc(size);
+ k[c].code = c;
+ k[c].text = buf;
+ k[c].flags = def;
+ k[c + 1].code = 0;
+ k[c + 1].text = NULL;
+ k[c + 1].flags = EOV;
+
+ return buf;
}
+
void
set_var(
struct ctl_var **kv,
@@ -2952,46 +4944,46 @@ set_var(
u_short def
)
{
- register struct ctl_var *k;
- register const char *s;
- register const char *t;
+ struct ctl_var *k;
+ const char *s;
+ const char *t;
char *td;
- if (!data || !size)
+ if (NULL == data || !size)
return;
k = *kv;
if (k != NULL) {
- while (!(k->flags & EOV)) {
- s = data;
- t = k->text;
- if (t) {
- while (*t != '=' && *s - *t == 0) {
+ while (!(EOV & k->flags)) {
+ if (NULL == k->text) {
+ td = emalloc(size);
+ memcpy(td, data, size);
+ k->text = td;
+ k->flags = def;
+ return;
+ } else {
+ s = data;
+ t = k->text;
+ while (*t != '=' && *s == *t) {
s++;
t++;
}
if (*s == *t && ((*t == '=') || !*t)) {
- free((void *)k->text);
- td = (char *)emalloc(size);
- memmove(td, data, size);
- k->text =td;
+ td = erealloc((void *)(intptr_t)k->text, size);
+ memcpy(td, data, size);
+ k->text = td;
k->flags = def;
return;
}
- } else {
- td = (char *)emalloc(size);
- memmove(td, data, size);
- k->text = td;
- k->flags = def;
- return;
}
k++;
}
}
td = add_var(kv, size, def);
- memmove(td, data, size);
+ memcpy(td, data, size);
}
+
void
set_sys_var(
const char *data,
@@ -3002,6 +4994,36 @@ set_sys_var(
set_var(&ext_sys_var, data, size, def);
}
+
+/*
+ * get_ext_sys_var() retrieves the value of a user-defined variable or
+ * NULL if the variable has not been setvar'd.
+ */
+const char *
+get_ext_sys_var(const char *tag)
+{
+ struct ctl_var * v;
+ size_t c;
+ const char * val;
+
+ val = NULL;
+ c = strlen(tag);
+ for (v = ext_sys_var; !(EOV & v->flags); v++) {
+ if (NULL != v->text && !memcmp(tag, v->text, c)) {
+ if ('=' == v->text[c]) {
+ val = v->text + c + 1;
+ break;
+ } else if ('\0' == v->text[c]) {
+ val = "";
+ break;
+ }
+ }
+ }
+
+ return val;
+}
+
+
void
free_varlist(
struct ctl_var *kv
@@ -3010,7 +5032,7 @@ free_varlist(
struct ctl_var *k;
if (kv) {
for (k = kv; !(k->flags & EOV); k++)
- free((void *)k->text);
+ free((void *)(intptr_t)k->text);
free((void *)kv);
}
}
diff --git a/contrib/ntp/ntpd/ntp_crypto.c b/contrib/ntp/ntpd/ntp_crypto.c
index e3f7afd..2be501d 100644
--- a/contrib/ntp/ntpd/ntp_crypto.c
+++ b/contrib/ntp/ntpd/ntp_crypto.c
@@ -5,8 +5,9 @@
#include <config.h>
#endif
-#ifdef OPENSSL
+#ifdef AUTOKEY
#include <stdio.h>
+#include <stdlib.h> /* strtoul */
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
@@ -16,7 +17,10 @@
#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "ntp_string.h"
-#include <ntp_random.h>
+#include "ntp_random.h"
+#include "ntp_assert.h"
+#include "ntp_calendar.h"
+#include "ntp_leapsec.h"
#include "openssl/asn1_mac.h"
#include "openssl/bn.h"
@@ -31,6 +35,33 @@
#endif /* KERNEL_PLL */
/*
+ * calcomp - compare two calendar structures, ignoring yearday and weekday; like strcmp
+ * No, it's not a plotter. If you don't understand that, you're too young.
+ */
+static int calcomp(struct calendar *pjd1, struct calendar *pjd2)
+{
+ int32_t diff; /* large enough to hold the signed difference between two uint16_t values */
+
+ diff = pjd1->year - pjd2->year;
+ if (diff < 0) return -1; else if (diff > 0) return 1;
+ /* same year; compare months */
+ diff = pjd1->month - pjd2->month;
+ if (diff < 0) return -1; else if (diff > 0) return 1;
+ /* same year and month; compare monthday */
+ diff = pjd1->monthday - pjd2->monthday;
+ if (diff < 0) return -1; else if (diff > 0) return 1;
+ /* same year and month and monthday; compare time */
+ diff = pjd1->hour - pjd2->hour;
+ if (diff < 0) return -1; else if (diff > 0) return 1;
+ diff = pjd1->minute - pjd2->minute;
+ if (diff < 0) return -1; else if (diff > 0) return 1;
+ diff = pjd1->second - pjd2->second;
+ if (diff < 0) return -1; else if (diff > 0) return 1;
+ /* identical */
+ return 0;
+}
+
+/*
* Extension field message format
*
* These are always signed and saved before sending in network byte
@@ -40,7 +71,7 @@
* +-------+-------+
* | op | len | <- extension pointer
* +-------+-------+
- * | assocID |
+ * | associd |
* +---------------+
* | timestamp | <- value pointer
* +---------------+
@@ -79,13 +110,28 @@
* creator or signor is synchronized to an authoritative source and
* proventicated to a trusted authority.
*
- * Note there are four conditions required for server trust. First, the
- * public key on the certificate must be verified, which involves a
- * number of format, content and consistency checks. Next, the server
- * identity must be confirmed by one of four schemes: private
- * certificate, IFF scheme, GQ scheme or certificate trail hike to a
- * self signed trusted certificate. Finally, the server signature must
- * be verified.
+ * Note there are several conditions required for server trust. First,
+ * the public key on the server certificate must be verified, which can
+ * involve a hike along the certificate trail to a trusted host. Next,
+ * the server trust must be confirmed by one of several identity
+ * schemes. Valid cryptographic values are signed with attached
+ * timestamp and filestamp. Individual packet trust is confirmed
+ * relative to these values by a message digest with keys generated by a
+ * reverse-order pseudorandom hash.
+ *
+ * State decomposition. These flags are lit in the order given. They are
+ * dim only when the association is demobilized.
+ *
+ * CRYPTO_FLAG_ENAB Lit upon acceptance of a CRYPTO_ASSOC message
+ * CRYPTO_FLAG_CERT Lit when a self-digned trusted certificate is
+ * accepted.
+ * CRYPTO_FLAG_VRFY Lit when identity is confirmed.
+ * CRYPTO_FLAG_PROV Lit when the first signature is verified.
+ * CRYPTO_FLAG_COOK Lit when a valid cookie is accepted.
+ * CRYPTO_FLAG_AUTO Lit when valid autokey values are accepted.
+ * CRYPTO_FLAG_SIGN Lit when the server signed certificate is
+ * accepted.
+ * CRYPTO_FLAG_LEAP Lit when the leapsecond values are accepted.
*/
/*
* Cryptodefines
@@ -100,20 +146,24 @@
* Global cryptodata in host byte order
*/
u_int32 crypto_flags = 0x0; /* status word */
+int crypto_nid = KEY_TYPE_MD5; /* digest nid */
+char *sys_hostname = NULL;
+char *sys_groupname = NULL;
+static char *host_filename = NULL; /* host file name */
+static char *ident_filename = NULL; /* group file name */
/*
* Global cryptodata in network byte order
*/
-struct cert_info *cinfo = NULL; /* certificate info/value */
+struct cert_info *cinfo = NULL; /* certificate info/value cache */
+struct cert_info *cert_host = NULL; /* host certificate */
+struct pkey_info *pkinfo = NULL; /* key info/value cache */
struct value hostval; /* host value */
struct value pubkey; /* public key */
-struct value tai_leap; /* leapseconds table */
-EVP_PKEY *iffpar_pkey = NULL; /* IFF parameters */
-EVP_PKEY *gqpar_pkey = NULL; /* GQ parameters */
-EVP_PKEY *mvpar_pkey = NULL; /* MV parameters */
-char *iffpar_file = NULL; /* IFF parameters file */
-char *gqpar_file = NULL; /* GQ parameters file */
-char *mvpar_file = NULL; /* MV parameters file */
+struct value tai_leap; /* leapseconds values */
+struct pkey_info *iffkey_info = NULL; /* IFF keys */
+struct pkey_info *gqkey_info = NULL; /* GQ keys */
+struct pkey_info *mvkey_info = NULL; /* MV keys */
/*
* Private cryptodata in host byte order
@@ -124,43 +174,34 @@ static EVP_PKEY *sign_pkey = NULL; /* sign key */
static const EVP_MD *sign_digest = NULL; /* sign digest */
static u_int sign_siglen; /* sign key length */
static char *rand_file = NULL; /* random seed file */
-static char *host_file = NULL; /* host key file */
-static char *sign_file = NULL; /* sign key file */
-static char *cert_file = NULL; /* certificate file */
-static char *leap_file = NULL; /* leapseconds file */
-static tstamp_t if_fstamp = 0; /* IFF filestamp */
-static tstamp_t gq_fstamp = 0; /* GQ file stamp */
-static tstamp_t mv_fstamp = 0; /* MV filestamp */
-static u_int ident_scheme = 0; /* server identity scheme */
/*
* Cryptotypes
*/
-static int crypto_verify P((struct exten *, struct value *,
- struct peer *));
-static int crypto_encrypt P((const u_char *, u_int, keyid_t *,
- struct value *));
-static int crypto_alice P((struct peer *, struct value *));
-static int crypto_alice2 P((struct peer *, struct value *));
-static int crypto_alice3 P((struct peer *, struct value *));
-static int crypto_bob P((struct exten *, struct value *));
-static int crypto_bob2 P((struct exten *, struct value *));
-static int crypto_bob3 P((struct exten *, struct value *));
-static int crypto_iff P((struct exten *, struct peer *));
-static int crypto_gq P((struct exten *, struct peer *));
-static int crypto_mv P((struct exten *, struct peer *));
-static u_int crypto_send P((struct exten *, struct value *));
-static tstamp_t crypto_time P((void));
-static u_long asn2ntp P((ASN1_TIME *));
-static struct cert_info *cert_parse P((u_char *, u_int, tstamp_t));
-static int cert_sign P((struct exten *, struct value *));
-static int cert_valid P((struct cert_info *, EVP_PKEY *));
-static int cert_install P((struct exten *, struct peer *));
-static void cert_free P((struct cert_info *));
-static EVP_PKEY *crypto_key P((char *, tstamp_t *));
-static int bighash P((BIGNUM *, BIGNUM *));
-static struct cert_info *crypto_cert P((char *));
-static void crypto_tai P((char *));
+static int crypto_verify (struct exten *, struct value *,
+ struct peer *);
+static int crypto_encrypt (const u_char *, u_int, keyid_t *,
+ struct value *);
+static int crypto_alice (struct peer *, struct value *);
+static int crypto_alice2 (struct peer *, struct value *);
+static int crypto_alice3 (struct peer *, struct value *);
+static int crypto_bob (struct exten *, struct value *);
+static int crypto_bob2 (struct exten *, struct value *);
+static int crypto_bob3 (struct exten *, struct value *);
+static int crypto_iff (struct exten *, struct peer *);
+static int crypto_gq (struct exten *, struct peer *);
+static int crypto_mv (struct exten *, struct peer *);
+static int crypto_send (struct exten *, struct value *, int);
+static tstamp_t crypto_time (void);
+static void asn_to_calendar (ASN1_TIME *, struct calendar*);
+static struct cert_info *cert_parse (const u_char *, long, tstamp_t);
+static int cert_sign (struct exten *, struct value *);
+static struct cert_info *cert_install (struct exten *, struct peer *);
+static int cert_hike (struct peer *, struct cert_info *);
+static void cert_free (struct cert_info *);
+static struct pkey_info *crypto_key (char *, char *, sockaddr_u *);
+static void bighash (BIGNUM *, BIGNUM *);
+static struct cert_info *crypto_cert (char *);
#ifdef SYS_WINNT
int
@@ -177,12 +218,12 @@ readlink(char * link, char * file, int len) {
* session key is the MD5 hash of these values, while the next key ID is
* the first four octets of the hash.
*
- * Returns the next key ID
+ * Returns the next key ID or 0 if there is no destination address.
*/
keyid_t
session_key(
- struct sockaddr_storage *srcadr, /* source address */
- struct sockaddr_storage *dstadr, /* destination address */
+ sockaddr_u *srcadr, /* source address */
+ sockaddr_u *dstadr, /* destination address */
keyid_t keyno, /* key ID */
keyid_t private, /* private value */
u_long lifetime /* key lifetime */
@@ -202,41 +243,38 @@ session_key(
* greater than zero, install the key and call it trusted.
*/
hdlen = 0;
- switch(srcadr->ss_family) {
+ switch(AF(srcadr)) {
case AF_INET:
- header[0] = ((struct sockaddr_in *)srcadr)->sin_addr.s_addr;
- header[1] = ((struct sockaddr_in *)dstadr)->sin_addr.s_addr;
+ header[0] = NSRCADR(srcadr);
+ header[1] = NSRCADR(dstadr);
header[2] = htonl(keyno);
header[3] = htonl(private);
hdlen = 4 * sizeof(u_int32);
break;
case AF_INET6:
- memcpy(&header[0], &GET_INADDR6(*srcadr),
+ memcpy(&header[0], PSOCK_ADDR6(srcadr),
sizeof(struct in6_addr));
- memcpy(&header[4], &GET_INADDR6(*dstadr),
+ memcpy(&header[4], PSOCK_ADDR6(dstadr),
sizeof(struct in6_addr));
header[8] = htonl(keyno);
header[9] = htonl(private);
hdlen = 10 * sizeof(u_int32);
break;
}
- EVP_DigestInit(&ctx, EVP_md5());
+ EVP_DigestInit(&ctx, EVP_get_digestbynid(crypto_nid));
EVP_DigestUpdate(&ctx, (u_char *)header, hdlen);
EVP_DigestFinal(&ctx, dgst, &len);
memcpy(&keyid, dgst, 4);
keyid = ntohl(keyid);
if (lifetime != 0) {
- MD5auth_setkey(keyno, dgst, len);
+ MD5auth_setkey(keyno, crypto_nid, dgst, len);
authtrust(keyno, lifetime);
}
-#ifdef DEBUG
- if (debug > 1)
- printf(
- "session_key: %s > %s %08x %08x hash %08x life %lu\n",
+ DPRINTF(2, ("session_key: %s > %s %08x %08x hash %08x life %lu\n",
stoa(srcadr), stoa(dstadr), keyno,
- private, keyid, lifetime);
-#endif
+ private, keyid, lifetime));
+
return (keyid);
}
@@ -246,7 +284,7 @@ session_key(
*
* Returns
* XEVNT_OK success
- * XEVNT_PER host certificate expired
+ * XEVNT_ERR protocol error
*
* This routine constructs a pseudo-random sequence by repeatedly
* hashing the session key starting from a given source address,
@@ -266,28 +304,30 @@ make_keylist(
struct value *vp; /* value pointer */
keyid_t keyid = 0; /* next key ID */
keyid_t cookie; /* private value */
- u_long lifetime;
+ long lifetime;
u_int len, mpoll;
int i;
if (!dstadr)
- return XEVNT_OK;
+ return XEVNT_ERR;
/*
* Allocate the key list if necessary.
*/
tstamp = crypto_time();
if (peer->keylist == NULL)
- peer->keylist = emalloc(sizeof(keyid_t) *
- NTP_MAXSESSION);
+ peer->keylist = eallocarray(NTP_MAXSESSION,
+ sizeof(keyid_t));
/*
* Generate an initial key ID which is unique and greater than
* NTP_MAXKEY.
*/
while (1) {
- keyid = (ntp_random() + NTP_MAXKEY + 1) & ((1 <<
- sizeof(keyid_t)) - 1);
+ keyid = ntp_random() & 0xffffffff;
+ if (keyid <= NTP_MAXKEY)
+ continue;
+
if (authhavekey(keyid))
continue;
break;
@@ -301,7 +341,7 @@ make_keylist(
* cookie if client mode or the host cookie if symmetric modes.
*/
mpoll = 1 << min(peer->ppoll, peer->hpoll);
- lifetime = min(sys_automax, NTP_MAXSESSION * mpoll);
+ lifetime = min(1U << sys_automax, NTP_MAXSESSION * mpoll);
if (peer->hmode == MODE_BROADCAST)
cookie = 0;
else
@@ -310,10 +350,10 @@ make_keylist(
peer->keylist[i] = keyid;
peer->keynumber = i;
keyid = session_key(&dstadr->sin, &peer->srcadr, keyid,
- cookie, lifetime);
+ cookie, lifetime + mpoll);
lifetime -= mpoll;
if (auth_havekey(keyid) || keyid <= NTP_MAXKEY ||
- lifetime <= mpoll)
+ lifetime < 0 || tstamp == 0)
break;
}
@@ -334,27 +374,20 @@ make_keylist(
vp->vallen = htonl(sizeof(struct autokey));
vp->siglen = 0;
if (tstamp != 0) {
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
if (vp->sig == NULL)
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)vp, 12);
EVP_SignUpdate(&ctx, vp->ptr, sizeof(struct autokey));
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
vp->siglen = htonl(len);
- else
- msyslog(LOG_ERR, "make_keys %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- peer->flags |= FLAG_ASSOC;
+ peer->flags |= FLAG_ASSOC;
+ }
}
-#ifdef DEBUG
- if (debug)
- printf("make_keys: %d %08x %08x ts %u fs %u poll %d\n",
- ntohl(ap->seq), ntohl(ap->key), cookie,
- ntohl(vp->tstamp), ntohl(vp->fstamp), peer->hpoll);
-#endif
+ DPRINTF(1, ("make_keys: %d %08x %08x ts %u fs %u poll %d\n",
+ peer->keynumber, keyid, cookie, ntohl(vp->tstamp),
+ ntohl(vp->fstamp), peer->hpoll));
return (XEVNT_OK);
}
@@ -369,6 +402,11 @@ make_keylist(
* valid length and is verified. There are a few cases where some values
* are believed even if the signature fails, but only if the proventic
* bit is not set.
+ *
+ * Returns
+ * XEVNT_OK success
+ * XEVNT_ERR protocol error
+ * XEVNT_LEN bad field format or length
*/
int
crypto_recv(
@@ -380,10 +418,10 @@ crypto_recv(
u_int32 *pkt; /* receive packet pointer */
struct autokey *ap, *bp; /* autokey pointer */
struct exten *ep, *fp; /* extension pointers */
+ struct cert_info *xinfo; /* certificate info pointer */
int has_mac; /* length of MAC field */
int authlen; /* offset of MAC field */
associd_t associd; /* association ID */
- tstamp_t tstamp = 0; /* timestamp */
tstamp_t fstamp = 0; /* filestamp */
u_int len; /* extension field length */
u_int code; /* extension field opcode */
@@ -393,7 +431,7 @@ crypto_recv(
keyid_t cookie; /* crumbles */
int hismode; /* packet mode */
int rval = XEVNT_OK;
- u_char *ptr;
+ const u_char *puch;
u_int32 temp32;
/*
@@ -408,43 +446,28 @@ crypto_recv(
*/
authlen = LEN_PKT_NOMAC;
hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
- while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
+ while ((has_mac = rbufp->recv_length - authlen) > (int)MAX_MAC_LEN) {
pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
ep = (struct exten *)pkt;
code = ntohl(ep->opcode) & 0xffff0000;
len = ntohl(ep->opcode) & 0x0000ffff;
- associd = (associd_t) ntohl(pkt[1]);
+ // HMS: Why pkt[1] instead of ep->associd ?
+ associd = (associd_t)ntohl(pkt[1]);
rval = XEVNT_OK;
-#ifdef DEBUG
- if (debug)
- printf(
- "crypto_recv: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",
+ DPRINTF(1, ("crypto_recv: flags 0x%x ext offset %d len %u code 0x%x associd %d\n",
peer->crypto, authlen, len, code >> 16,
- associd);
-#endif
+ associd));
/*
* Check version number and field length. If bad,
* quietly ignore the packet.
*/
if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8) {
- sys_unknownversion++;
+ sys_badlength++;
code |= CRYPTO_ERROR;
}
- /*
- * Little vulnerability bandage here. If a perp tosses a
- * fake association ID over the fence, we better toss it
- * out. Only the first one counts.
- */
- if (code & CRYPTO_RESP) {
- if (peer->assoc == 0)
- peer->assoc = associd;
- else if (peer->assoc != associd)
- code |= CRYPTO_ERROR;
- }
if (len >= VALUE_LEN) {
- tstamp = ntohl(ep->tstamp);
fstamp = ntohl(ep->fstamp);
vallen = ntohl(ep->vallen);
/*
@@ -469,19 +492,26 @@ crypto_recv(
case CRYPTO_ASSOC:
/*
- * If the machine is running when this message
- * arrives, the other fellow has reset and so
- * must we. Otherwise, pass the extension field
- * to the transmit side.
+ * If our state machine is running when this
+ * message arrives, the other fellow might have
+ * restarted. However, this could be an
+ * intruder, so just clamp the poll interval and
+ * find out for ourselves. Otherwise, pass the
+ * extension field to the transmit side.
*/
- if (peer->crypto) {
+ if (peer->crypto & CRYPTO_FLAG_CERT) {
rval = XEVNT_ERR;
break;
}
+ if (peer->cmmd) {
+ if (peer->assoc != associd) {
+ rval = XEVNT_ERR;
+ break;
+ }
+ }
fp = emalloc(len);
memcpy(fp, ep, len);
- temp32 = CRYPTO_RESP;
- fp->opcode |= htonl(temp32);
+ fp->associd = htonl(peer->associd);
peer->cmmd = fp;
/* fall through */
@@ -491,67 +521,52 @@ crypto_recv(
* Discard the message if it has already been
* stored or the message has been amputated.
*/
- if (peer->crypto)
+ if (peer->crypto) {
+ if (peer->assoc != associd)
+ rval = XEVNT_ERR;
break;
-
+ }
+ INSIST(len >= VALUE_LEN);
if (vallen == 0 || vallen > MAXHOSTNAME ||
len - VALUE_LEN < vallen) {
rval = XEVNT_LEN;
break;
}
+ DPRINTF(1, ("crypto_recv: ident host 0x%x %d server 0x%x %d\n",
+ crypto_flags, peer->associd, fstamp,
+ peer->assoc));
+ temp32 = crypto_flags & CRYPTO_FLAG_MASK;
/*
- * Check the identity schemes are compatible. If
- * the client has PC, the server must have PC,
- * in which case the server public key and
- * identity are presumed valid, so we skip the
- * certificate and identity exchanges and move
- * immediately to the cookie exchange which
- * confirms the server signature.
+ * If the client scheme is PC, the server scheme
+ * must be PC. The public key and identity are
+ * presumed valid, so we skip the certificate
+ * and identity exchanges and move immediately
+ * to the cookie exchange which confirms the
+ * server signature.
*/
-#ifdef DEBUG
- if (debug)
- printf(
- "crypto_recv: ident host 0x%x server 0x%x\n",
- crypto_flags, fstamp);
-#endif
- temp32 = (crypto_flags | ident_scheme) &
- fstamp & CRYPTO_FLAG_MASK;
if (crypto_flags & CRYPTO_FLAG_PRIV) {
if (!(fstamp & CRYPTO_FLAG_PRIV)) {
rval = XEVNT_KEY;
break;
-
- } else {
- fstamp |= CRYPTO_FLAG_VALID |
- CRYPTO_FLAG_VRFY |
- CRYPTO_FLAG_SIGN;
}
- /*
- * In symmetric modes it is an error if either
- * peer requests identity and the other peer
- * does not support it.
- */
- } else if ((hismode == MODE_ACTIVE || hismode ==
- MODE_PASSIVE) && ((crypto_flags | fstamp) &
- CRYPTO_FLAG_MASK) && !temp32) {
- rval = XEVNT_KEY;
- break;
- /*
- * It is an error if the client requests
- * identity and the server does not support it.
- */
- } else if (hismode == MODE_CLIENT && (fstamp &
- CRYPTO_FLAG_MASK) && !temp32) {
- rval = XEVNT_KEY;
- break;
- }
+ fstamp |= CRYPTO_FLAG_CERT |
+ CRYPTO_FLAG_VRFY | CRYPTO_FLAG_SIGN;
/*
- * Otherwise, the identity scheme(s) are those
- * that both client and server support.
+ * It is an error if either peer supports
+ * identity, but the other does not.
*/
- fstamp = temp32 | (fstamp & ~CRYPTO_FLAG_MASK);
+ } else if (hismode == MODE_ACTIVE || hismode ==
+ MODE_PASSIVE) {
+ if ((temp32 && !(fstamp &
+ CRYPTO_FLAG_MASK)) ||
+ (!temp32 && (fstamp &
+ CRYPTO_FLAG_MASK))) {
+ rval = XEVNT_KEY;
+ break;
+ }
+ }
/*
* Discard the message if the signature digest
@@ -567,24 +582,32 @@ crypto_recv(
/*
* Save status word, host name and message
- * digest/signature type.
+ * digest/signature type. If this is from a
+ * broadcast and the association ID has changed,
+ * request the autokey values.
*/
+ peer->assoc = associd;
+ if (hismode == MODE_SERVER)
+ fstamp |= CRYPTO_FLAG_AUTO;
+ if (!(fstamp & CRYPTO_FLAG_TAI))
+ fstamp |= CRYPTO_FLAG_LEAP;
+ RAND_bytes((u_char *)&peer->hcookie, 4);
peer->crypto = fstamp;
peer->digest = dp;
+ if (peer->subject != NULL)
+ free(peer->subject);
peer->subject = emalloc(vallen + 1);
memcpy(peer->subject, ep->pkt, vallen);
peer->subject[vallen] = '\0';
- peer->issuer = emalloc(vallen + 1);
- strcpy(peer->issuer, peer->subject);
- temp32 = (fstamp >> 16) & 0xffff;
- snprintf(statstr, NTP_MAXSTRLEN,
- "flags 0x%x host %s signature %s", fstamp,
- peer->subject, OBJ_nid2ln(temp32));
+ if (peer->issuer != NULL)
+ free(peer->issuer);
+ peer->issuer = estrdup(peer->subject);
+ snprintf(statstr, sizeof(statstr),
+ "assoc %d %d host %s %s", peer->associd,
+ peer->assoc, peer->subject,
+ OBJ_nid2ln(temp32));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
@@ -597,8 +620,11 @@ crypto_recv(
case CRYPTO_CERT | CRYPTO_RESP:
/*
- * Discard the message if invalid.
+ * Discard the message if empty or invalid.
*/
+ if (len < VALUE_LEN)
+ break;
+
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -606,26 +632,16 @@ crypto_recv(
/*
* Scan the certificate list to delete old
* versions and link the newest version first on
- * the list.
+ * the list. Then, verify the signature. If the
+ * certificate is bad or missing, just ignore
+ * it.
*/
- if ((rval = cert_install(ep, peer)) != XEVNT_OK)
+ if ((xinfo = cert_install(ep, peer)) == NULL) {
+ rval = XEVNT_CRT;
+ break;
+ }
+ if ((rval = cert_hike(peer, xinfo)) != XEVNT_OK)
break;
-
- /*
- * If we snatch the certificate before the
- * server certificate has been signed by its
- * server, it will be self signed. When it is,
- * we chase the certificate issuer, which the
- * server has, and keep going until a self
- * signed trusted certificate is found. Be sure
- * to update the issuer field, since it may
- * change.
- */
- if (peer->issuer != NULL)
- free(peer->issuer);
- peer->issuer = emalloc(strlen(cinfo->issuer) +
- 1);
- strcpy(peer->issuer, cinfo->issuer);
/*
* We plug in the public key and lifetime from
@@ -635,71 +651,58 @@ crypto_recv(
* signature/digest NID.
*/
if (peer->pkey == NULL) {
- ptr = (u_char *)cinfo->cert.ptr;
- cert = d2i_X509(NULL, &ptr,
- ntohl(cinfo->cert.vallen));
+ puch = xinfo->cert.ptr;
+ cert = d2i_X509(NULL, &puch,
+ ntohl(xinfo->cert.vallen));
peer->pkey = X509_get_pubkey(cert);
X509_free(cert);
}
peer->flash &= ~TEST8;
- temp32 = cinfo->nid;
- snprintf(statstr, NTP_MAXSTRLEN,
- "cert %s 0x%x %s (%u) fs %u",
- cinfo->subject, cinfo->flags,
+ temp32 = xinfo->nid;
+ snprintf(statstr, sizeof(statstr),
+ "cert %s %s 0x%x %s (%u) fs %u",
+ xinfo->subject, xinfo->issuer, xinfo->flags,
OBJ_nid2ln(temp32), temp32,
ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
- * Schnorr (IFF)identity scheme. This scheme is designed
- * for use with shared secret group keys and where the
- * certificate may be generated by a third party. The
- * client sends a challenge to the server, which
- * performs a calculation and returns the result. A
- * positive result is possible only if both client and
+ * Schnorr (IFF) identity scheme. This scheme is
+ * designed for use with shared secret server group keys
+ * and where the certificate may be generated by a third
+ * party. The client sends a challenge to the server,
+ * which performs a calculation and returns the result.
+ * A positive result is possible only if both client and
* server contain the same secret group key.
*/
case CRYPTO_IFF | CRYPTO_RESP:
/*
- * Discard the message if invalid or certificate
- * trail not trusted.
+ * Discard the message if invalid.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
- rval = XEVNT_ERR;
- break;
- }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
/*
- * If the the challenge matches the response,
- * the certificate public key, as well as the
- * server public key, signatyre and identity are
+ * If the challenge matches the response, the
+ * server public key, signature and identity are
* all verified at the same time. The server is
* declared trusted, so we skip further
- * certificate stages and move immediately to
- * the cookie stage.
+ * certificate exchanges and move immediately to
+ * the cookie exchange.
*/
if ((rval = crypto_iff(ep, peer)) != XEVNT_OK)
break;
- peer->crypto |= CRYPTO_FLAG_VRFY |
- CRYPTO_FLAG_PROV;
+ peer->crypto |= CRYPTO_FLAG_VRFY;
peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN, "iff fs %u",
- ntohl(ep->fstamp));
+ snprintf(statstr, sizeof(statstr), "iff %s fs %u",
+ peer->issuer, ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
@@ -715,136 +718,68 @@ crypto_recv(
case CRYPTO_GQ | CRYPTO_RESP:
/*
- * Discard the message if invalid or certificate
- * trail not trusted.
+ * Discard the message if invalid
*/
- if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
- rval = XEVNT_ERR;
- break;
- }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
/*
- * If the the challenge matches the response,
- * the certificate public key, as well as the
- * server public key, signatyre and identity are
+ * If the challenge matches the response, the
+ * server public key, signature and identity are
* all verified at the same time. The server is
* declared trusted, so we skip further
- * certificate stages and move immediately to
- * the cookie stage.
+ * certificate exchanges and move immediately to
+ * the cookie exchange.
*/
if ((rval = crypto_gq(ep, peer)) != XEVNT_OK)
break;
- peer->crypto |= CRYPTO_FLAG_VRFY |
- CRYPTO_FLAG_PROV;
+ peer->crypto |= CRYPTO_FLAG_VRFY;
peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN, "gq fs %u",
- ntohl(ep->fstamp));
+ snprintf(statstr, sizeof(statstr), "gq %s fs %u",
+ peer->issuer, ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
- * MV
+ * Mu-Varadharajan (MV) identity scheme. This scheme is
+ * designed for use with three levels of trust, trusted
+ * host, server and client. The trusted host key is
+ * opaque to servers and clients; the server keys are
+ * opaque to clients and each client key is different.
+ * Client keys can be revoked without requiring new key
+ * generations.
*/
case CRYPTO_MV | CRYPTO_RESP:
/*
- * Discard the message if invalid or certificate
- * trail not trusted.
+ * Discard the message if invalid.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
- rval = XEVNT_ERR;
- break;
- }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
/*
- * If the the challenge matches the response,
- * the certificate public key, as well as the
- * server public key, signatyre and identity are
+ * If the challenge matches the response, the
+ * server public key, signature and identity are
* all verified at the same time. The server is
* declared trusted, so we skip further
- * certificate stages and move immediately to
- * the cookie stage.
+ * certificate exchanges and move immediately to
+ * the cookie exchange.
*/
if ((rval = crypto_mv(ep, peer)) != XEVNT_OK)
break;
- peer->crypto |= CRYPTO_FLAG_VRFY |
- CRYPTO_FLAG_PROV;
+ peer->crypto |= CRYPTO_FLAG_VRFY;
peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN, "mv fs %u",
- ntohl(ep->fstamp));
+ snprintf(statstr, sizeof(statstr), "mv %s fs %u",
+ peer->issuer, ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
- /*
- * Cookie request in symmetric modes. Roll a random
- * cookie and install in symmetric mode. Encrypt for the
- * response, which is transmitted later.
- */
- case CRYPTO_COOK:
-
- /*
- * Discard the message if invalid or certificate
- * trail not trusted.
- */
- if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
- rval = XEVNT_ERR;
- break;
- }
- if ((rval = crypto_verify(ep, NULL, peer)) !=
- XEVNT_OK)
- break;
-
- /*
- * Pass the extension field to the transmit
- * side. If already agreed, walk away.
- */
- fp = emalloc(len);
- memcpy(fp, ep, len);
- temp32 = CRYPTO_RESP;
- fp->opcode |= htonl(temp32);
- peer->cmmd = fp;
- if (peer->crypto & CRYPTO_FLAG_AGREE) {
- peer->flash &= ~TEST8;
- break;
- }
-
- /*
- * Install cookie values and light the cookie
- * bit. The transmit side will pick up and
- * encrypt it for the response.
- */
- key_expire(peer);
- peer->cookval.tstamp = ep->tstamp;
- peer->cookval.fstamp = ep->fstamp;
- RAND_bytes((u_char *)&peer->pcookie, 4);
- peer->crypto &= ~CRYPTO_FLAG_AUTO;
- peer->crypto |= CRYPTO_FLAG_AGREE;
- peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN, "cook %x ts %u fs %u",
- peer->pcookie, ntohl(ep->tstamp),
- ntohl(ep->fstamp));
- record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
- break;
/*
* Cookie response in client and symmetric modes. If the
@@ -854,14 +789,10 @@ crypto_recv(
case CRYPTO_COOK | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * not confirmed or signature not verified with
- * respect to the cookie values.
+ * Discard the message if invalid or signature
+ * not verified with respect to the cookie
+ * values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
- rval = XEVNT_ERR;
- break;
- }
if ((rval = crypto_verify(ep, &peer->cookval,
peer)) != XEVNT_OK)
break;
@@ -870,13 +801,14 @@ crypto_recv(
* Decrypt the cookie, hunting all the time for
* errors.
*/
- if (vallen == (u_int) EVP_PKEY_size(host_pkey)) {
+ if (vallen == (u_int)EVP_PKEY_size(host_pkey)) {
u_int32 *cookiebuf = malloc(
- RSA_size(host_pkey->pkey.rsa));
- if (cookiebuf == NULL) {
+ RSA_size(host_pkey->pkey.rsa));
+ if (!cookiebuf) {
rval = XEVNT_CKY;
break;
}
+
if (RSA_private_decrypt(vallen,
(u_char *)ep->pkt,
(u_char *)cookiebuf,
@@ -900,27 +832,18 @@ crypto_recv(
* are done here.
*/
key_expire(peer);
- peer->cookval.tstamp = ep->tstamp;
- peer->cookval.fstamp = ep->fstamp;
- if (peer->crypto & CRYPTO_FLAG_AGREE)
- peer->pcookie ^= cookie;
+ if (hismode == MODE_ACTIVE || hismode ==
+ MODE_PASSIVE)
+ peer->pcookie = peer->hcookie ^ cookie;
else
peer->pcookie = cookie;
- if (peer->hmode == MODE_CLIENT &&
- !(peer->cast_flags & MDF_BCLNT))
- peer->crypto |= CRYPTO_FLAG_AUTO;
- else
- peer->crypto &= ~CRYPTO_FLAG_AUTO;
- peer->crypto |= CRYPTO_FLAG_AGREE;
+ peer->crypto |= CRYPTO_FLAG_COOK;
peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN, "cook %x ts %u fs %u",
- peer->pcookie, ntohl(ep->tstamp),
- ntohl(ep->fstamp));
+ snprintf(statstr, sizeof(statstr),
+ "cook %x ts %u fs %u", peer->pcookie,
+ ntohl(ep->tstamp), ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
@@ -936,22 +859,32 @@ crypto_recv(
case CRYPTO_AUTO | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * not confirmed or signature not verified with
- * respect to the receive autokey values.
+ * Discard the message if invalid or signature
+ * not verified with respect to the receive
+ * autokey values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
- rval = XEVNT_ERR;
- break;
- }
if ((rval = crypto_verify(ep, &peer->recval,
- peer)) != XEVNT_OK)
+ peer)) != XEVNT_OK)
+ break;
+
+ /*
+ * Discard the message if a broadcast client and
+ * the association ID does not match. This might
+ * happen if a broacast server restarts the
+ * protocol. A protocol restart will occur at
+ * the next ASSOC message.
+ */
+ if ((peer->cast_flags & MDF_BCLNT) &&
+ peer->assoc != associd)
break;
/*
* Install autokey values and light the
* autokey bit. This is not hard.
*/
+ if (ep->tstamp == 0)
+ break;
+
if (peer->recval.ptr == NULL)
peer->recval.ptr =
emalloc(sizeof(struct autokey));
@@ -964,15 +897,12 @@ crypto_recv(
peer->pkeyid = bp->key;
peer->crypto |= CRYPTO_FLAG_AUTO;
peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN,
+ snprintf(statstr, sizeof(statstr),
"auto seq %d key %x ts %u fs %u", bp->seq,
bp->key, ntohl(ep->tstamp),
ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
@@ -985,13 +915,8 @@ crypto_recv(
case CRYPTO_SIGN | CRYPTO_RESP:
/*
- * Discard the message if invalid or not
- * proventic.
+ * Discard the message if invalid.
*/
- if (!(peer->crypto & CRYPTO_FLAG_PROV)) {
- rval = XEVNT_ERR;
- break;
- }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -1001,118 +926,74 @@ crypto_recv(
* versions and link the newest version first on
* the list.
*/
- if ((rval = cert_install(ep, peer)) != XEVNT_OK)
+ if ((xinfo = cert_install(ep, peer)) == NULL) {
+ rval = XEVNT_CRT;
break;
-
+ }
peer->crypto |= CRYPTO_FLAG_SIGN;
peer->flash &= ~TEST8;
- temp32 = cinfo->nid;
- snprintf(statstr, NTP_MAXSTRLEN,
- "sign %s 0x%x %s (%u) fs %u",
- cinfo->issuer, cinfo->flags,
+ temp32 = xinfo->nid;
+ snprintf(statstr, sizeof(statstr),
+ "sign %s %s 0x%x %s (%u) fs %u",
+ xinfo->subject, xinfo->issuer, xinfo->flags,
OBJ_nid2ln(temp32), temp32,
ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
- * Install leapseconds table in symmetric modes. This
- * table is proventicated to the NIST primary servers,
- * either by copying the file containing the table from
- * a NIST server to a trusted server or directly using
- * this protocol. While the entire table is installed at
- * the server, presently only the current TAI offset is
- * provided via the kernel to other applications.
+ * Install leapseconds values. While the leapsecond
+ * values epoch, TAI offset and values expiration epoch
+ * are retained, only the current TAI offset is provided
+ * via the kernel to other applications.
*/
- case CRYPTO_TAI:
-
+ case CRYPTO_LEAP | CRYPTO_RESP:
/*
- * Discard the message if invalid.
+ * Discard the message if invalid. We can't
+ * compare the value timestamps here, as they
+ * can be updated by different servers.
*/
- if ((rval = crypto_verify(ep, NULL, peer)) !=
- XEVNT_OK)
+ rval = crypto_verify(ep, NULL, peer);
+ if ((rval != XEVNT_OK ) ||
+ (vallen != 3*sizeof(uint32_t)) )
break;
- /*
- * Pass the extension field to the transmit
- * side. Continue below if a leapseconds table
- * accompanies the message.
- */
- fp = emalloc(len);
- memcpy(fp, ep, len);
- temp32 = CRYPTO_RESP;
- fp->opcode |= htonl(temp32);
- peer->cmmd = fp;
- if (len <= VALUE_LEN) {
- peer->flash &= ~TEST8;
- break;
- }
- /* fall through */
-
- case CRYPTO_TAI | CRYPTO_RESP:
-
- /*
- * If this is a response, discard the message if
- * signature not verified with respect to the
- * leapsecond table values.
+ /* Check if we can update the basic TAI offset
+ * for our current leap frame. This is a hack
+ * and ignores the time stamps in the autokey
+ * message.
*/
- if (peer->cmmd == NULL) {
- if ((rval = crypto_verify(ep,
- &peer->tai_leap, peer)) != XEVNT_OK)
- break;
- }
-
- /*
- * Initialize peer variables with latest update.
- */
- peer->tai_leap.tstamp = ep->tstamp;
- peer->tai_leap.fstamp = ep->fstamp;
- peer->tai_leap.vallen = ep->vallen;
-
- /*
- * Install the new table if there is no stored
- * table or the new table is more recent than
- * the stored table. Since a filestamp may have
- * changed, recompute the signatures.
- */
- if (ntohl(peer->tai_leap.fstamp) >
- ntohl(tai_leap.fstamp)) {
- tai_leap.fstamp = ep->fstamp;
- tai_leap.vallen = ep->vallen;
- if (tai_leap.ptr != NULL)
- free(tai_leap.ptr);
- tai_leap.ptr = emalloc(vallen);
- memcpy(tai_leap.ptr, ep->pkt, vallen);
- crypto_update();
- }
- crypto_flags |= CRYPTO_FLAG_TAI;
+ if (sys_leap != LEAP_NOTINSYNC)
+ leapsec_autokey_tai(ntohl(ep->pkt[0]),
+ rbufp->recv_time.l_ui, NULL);
+ tai_leap.tstamp = ep->tstamp;
+ tai_leap.fstamp = ep->fstamp;
+ crypto_update();
+ mprintf_event(EVNT_TAI, peer,
+ "%d seconds", ntohl(ep->pkt[0]));
peer->crypto |= CRYPTO_FLAG_LEAP;
peer->flash &= ~TEST8;
- snprintf(statstr, NTP_MAXSTRLEN,
- "leap %u ts %u fs %u", vallen,
- ntohl(ep->tstamp), ntohl(ep->fstamp));
+ snprintf(statstr, sizeof(statstr),
+ "leap TAI offset %d at %u expire %u fs %u",
+ ntohl(ep->pkt[0]), ntohl(ep->pkt[1]),
+ ntohl(ep->pkt[2]), ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
break;
/*
* We come here in symmetric modes for miscellaneous
* commands that have value fields but are processed on
* the transmit side. All we need do here is check for
- * valid field length. Remaining checks are below and on
- * the transmit side.
+ * valid field length. Note that ASSOC is handled
+ * separately.
*/
case CRYPTO_CERT:
case CRYPTO_IFF:
case CRYPTO_GQ:
case CRYPTO_MV:
+ case CRYPTO_COOK:
case CRYPTO_SIGN:
if (len < VALUE_LEN) {
rval = XEVNT_LEN;
@@ -1121,49 +1002,36 @@ crypto_recv(
/* fall through */
/*
- * We come here for miscellaneous requests and unknown
- * requests and responses. If an unknown response or
- * error, forget it. If a request, save the extension
- * field for later. Unknown requests will be caught on
- * the transmit side.
+ * We come here in symmetric modes for requests
+ * requiring a response (above plus AUTO and LEAP) and
+ * for responses. If a request, save the extension field
+ * for later; invalid requests will be caught on the
+ * transmit side. If an error or invalid response,
+ * declare a protocol error.
*/
default:
if (code & (CRYPTO_RESP | CRYPTO_ERROR)) {
rval = XEVNT_ERR;
- } else if ((rval = crypto_verify(ep, NULL,
- peer)) == XEVNT_OK) {
+ } else if (peer->cmmd == NULL) {
fp = emalloc(len);
memcpy(fp, ep, len);
- temp32 = CRYPTO_RESP;
- fp->opcode |= htonl(temp32);
peer->cmmd = fp;
}
}
/*
- * We don't log length/format/timestamp errors and
- * duplicates, which are log clogging vulnerabilities.
* The first error found terminates the extension field
- * scan and we return the laundry to the caller. A
- * length/format/timestamp error on transmit is
- * cheerfully ignored, as the message is not sent.
+ * scan and we return the laundry to the caller.
*/
- if (rval > XEVNT_TSP) {
- snprintf(statstr, NTP_MAXSTRLEN,
- "error %x opcode %x ts %u fs %u", rval,
- code, tstamp, fstamp);
+ if (rval != XEVNT_OK) {
+ snprintf(statstr, sizeof(statstr),
+ "%04x %d %02x %s", htonl(ep->opcode),
+ associd, rval, eventstr(rval));
record_crypto_stats(&peer->srcadr, statstr);
- report_event(rval, peer);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
- break;
-
- } else if (rval > XEVNT_OK && (code & CRYPTO_RESP)) {
- rval = XEVNT_OK;
+ DPRINTF(1, ("crypto_recv: %s\n", statstr));
+ return (rval);
}
- authlen += len;
+ authlen += (len + 3) / 4 * 4;
}
return (rval);
}
@@ -1177,30 +1045,39 @@ crypto_recv(
* autokey information, in which case the caller has to provide the
* association ID to match the association.
*
- * Returns length of extension field.
+ * Side effect: update the packet offset.
+ *
+ * Errors
+ * XEVNT_OK success
+ * XEVNT_CRT bad or missing certificate
+ * XEVNT_ERR protocol error
+ * XEVNT_LEN bad field format or length
+ * XEVNT_PER host certificate expired
*/
int
crypto_xmit(
+ struct peer *peer, /* peer structure pointer */
struct pkt *xpkt, /* transmit packet pointer */
- struct sockaddr_storage *srcadr_sin, /* active runway */
+ struct recvbuf *rbufp, /* receive buffer pointer */
int start, /* offset to extension field */
struct exten *ep, /* extension pointer */
keyid_t cookie /* session cookie */
)
{
+ struct exten *fp; /* extension pointers */
+ struct cert_info *cp, *xp, *yp; /* cert info/value pointer */
+ sockaddr_u *srcadr_sin; /* source address */
u_int32 *pkt; /* packet pointer */
- struct peer *peer; /* peer structure pointer */
u_int opcode; /* extension field opcode */
- struct exten *fp; /* extension pointers */
- struct cert_info *cp, *xp; /* certificate info/value pointer */
char certname[MAXHOSTNAME + 1]; /* subject name buffer */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
tstamp_t tstamp;
+ struct calendar tscal;
u_int vallen;
- u_int len;
struct value vtemp;
associd_t associd;
int rval;
+ int len;
keyid_t tcookie;
/*
@@ -1211,9 +1088,17 @@ crypto_xmit(
pkt = (u_int32 *)xpkt + start / 4;
fp = (struct exten *)pkt;
opcode = ntohl(ep->opcode);
+ if (peer != NULL) {
+ srcadr_sin = &peer->srcadr;
+ if (!(opcode & CRYPTO_RESP))
+ peer->opcode = ep->opcode;
+ } else {
+ srcadr_sin = &rbufp->recv_srcadr;
+ }
associd = (associd_t) ntohl(ep->associd);
- fp->associd = htonl(associd);
len = 8;
+ fp->opcode = htonl((opcode & 0xffff0000) | len);
+ fp->associd = ep->associd;
rval = XEVNT_OK;
tstamp = crypto_time();
switch (opcode & 0xffff0000) {
@@ -1223,16 +1108,12 @@ crypto_xmit(
* host name. Note, this message is not signed and the filestamp
* contains only the status word.
*/
+ case CRYPTO_ASSOC:
case CRYPTO_ASSOC | CRYPTO_RESP:
- len += crypto_send(fp, &hostval);
+ len = crypto_send(fp, &hostval, start);
fp->fstamp = htonl(crypto_flags);
break;
- case CRYPTO_ASSOC:
- len += crypto_send(fp, &hostval);
- fp->fstamp = htonl(crypto_flags | ident_scheme);
- break;
-
/*
* Send certificate request. Use the values from the extension
* field.
@@ -1243,89 +1124,99 @@ crypto_xmit(
vtemp.fstamp = ep->fstamp;
vtemp.vallen = ep->vallen;
vtemp.ptr = (u_char *)ep->pkt;
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
break;
/*
- * Send certificate response or sign request. Use the values
- * from the certificate cache. If the request contains no
- * subject name, assume the name of this host. This is for
- * backwards compatibility. Private certificates are never sent.
+ * Send sign request. Use the host certificate, which is self-
+ * signed and may or may not be trusted.
*/
case CRYPTO_SIGN:
+ (void)ntpcal_ntp_to_date(&tscal, tstamp, NULL);
+ if ((calcomp(&tscal, &(cert_host->first)) < 0)
+ || (calcomp(&tscal, &(cert_host->last)) > 0))
+ rval = XEVNT_PER;
+ else
+ len = crypto_send(fp, &cert_host->cert, start);
+ break;
+
+ /*
+ * Send certificate response. Use the name in the extension
+ * field to find the certificate in the cache. If the request
+ * contains no subject name, assume the name of this host. This
+ * is for backwards compatibility. Private certificates are
+ * never sent.
+ *
+ * There may be several certificates matching the request. First
+ * choice is a self-signed trusted certificate; second choice is
+ * any certificate signed by another host. There is no third
+ * choice.
+ */
case CRYPTO_CERT | CRYPTO_RESP:
- vallen = ntohl(ep->vallen);
- if (vallen == 8) {
- strcpy(certname, sys_hostname);
- } else if (vallen == 0 || vallen > MAXHOSTNAME ||
+ vallen = ntohl(ep->vallen); /* Must be <64k */
+ if (vallen == 0 || vallen > MAXHOSTNAME ||
len - VALUE_LEN < vallen) {
rval = XEVNT_LEN;
break;
-
- } else {
- memcpy(certname, ep->pkt, vallen);
- certname[vallen] = '\0';
}
/*
- * Find all certificates with matching subject. If a
- * self-signed, trusted certificate is found, use that.
- * If not, use the first one with matching subject. A
- * private certificate is never divulged or signed.
+ * Find all public valid certificates with matching
+ * subject. If a self-signed, trusted certificate is
+ * found, use that certificate. If not, use the last non
+ * self-signed certificate.
*/
- xp = NULL;
+ memcpy(certname, ep->pkt, vallen);
+ certname[vallen] = '\0';
+ xp = yp = NULL;
for (cp = cinfo; cp != NULL; cp = cp->link) {
- if (cp->flags & CERT_PRIV)
+ if (cp->flags & (CERT_PRIV | CERT_ERROR))
continue;
- if (strcmp(certname, cp->subject) == 0) {
- if (xp == NULL)
- xp = cp;
- if (strcmp(certname, cp->issuer) ==
- 0 && cp->flags & CERT_TRUST) {
- xp = cp;
- break;
- }
- }
+ if (strcmp(certname, cp->subject) != 0)
+ continue;
+
+ if (strcmp(certname, cp->issuer) != 0)
+ yp = cp;
+ else if (cp ->flags & CERT_TRUST)
+ xp = cp;
+ continue;
}
/*
- * Be careful who you trust. If not yet synchronized,
- * give back an empty response. If certificate not found
- * or beyond the lifetime, return an error. This is to
- * avoid a bad dude trying to get an expired certificate
- * re-signed. Otherwise, send it.
+ * Be careful who you trust. If the certificate is not
+ * found, return an empty response. Note that we dont
+ * enforce lifetimes here.
*
- * Note the timestamp and filestamp are taken from the
+ * The timestamp and filestamp are taken from the
* certificate value structure. For all certificates the
* timestamp is the latest signature update time. For
* host and imported certificates the filestamp is the
* creation epoch. For signed certificates the filestamp
* is the creation epoch of the trusted certificate at
- * the base of the certificate trail. In principle, this
+ * the root of the certificate trail. In principle, this
* allows strong checking for signature masquerade.
*/
+ if (xp == NULL)
+ xp = yp;
+ if (xp == NULL)
+ break;
+
if (tstamp == 0)
break;
- if (xp == NULL)
- rval = XEVNT_CRT;
- else if (tstamp < xp->first || tstamp > xp->last)
- rval = XEVNT_SRV;
- else
- len += crypto_send(fp, &xp->cert);
+ len = crypto_send(fp, &xp->cert, start);
break;
/*
* Send challenge in Schnorr (IFF) identity scheme.
*/
case CRYPTO_IFF:
- if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) {
- rval = XEVNT_ERR;
- break;
- }
+ if (peer == NULL)
+ break; /* hack attack */
+
if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1335,7 +1226,7 @@ crypto_xmit(
*/
case CRYPTO_IFF | CRYPTO_RESP:
if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1344,12 +1235,11 @@ crypto_xmit(
* Send challenge in Guillou-Quisquater (GQ) identity scheme.
*/
case CRYPTO_GQ:
- if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) {
- rval = XEVNT_ERR;
- break;
- }
+ if (peer == NULL)
+ break; /* hack attack */
+
if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1359,7 +1249,7 @@ crypto_xmit(
*/
case CRYPTO_GQ | CRYPTO_RESP:
if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1368,12 +1258,11 @@ crypto_xmit(
* Send challenge in MV identity scheme.
*/
case CRYPTO_MV:
- if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) {
- rval = XEVNT_ERR;
- break;
- }
+ if (peer == NULL)
+ break; /* hack attack */
+
if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1383,7 +1272,7 @@ crypto_xmit(
*/
case CRYPTO_MV | CRYPTO_RESP:
if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1397,9 +1286,10 @@ crypto_xmit(
* invalid or contains an unverified signature.
*/
case CRYPTO_SIGN | CRYPTO_RESP:
- if ((rval = cert_sign(ep, &vtemp)) == XEVNT_OK)
- len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ if ((rval = cert_sign(ep, &vtemp)) == XEVNT_OK) {
+ len = crypto_send(fp, &vtemp, start);
+ value_free(&vtemp);
+ }
break;
/*
@@ -1407,7 +1297,7 @@ crypto_xmit(
* key.
*/
case CRYPTO_COOK:
- len += crypto_send(fp, &pubkey);
+ len = crypto_send(fp, &pubkey, start);
break;
/*
@@ -1422,18 +1312,13 @@ crypto_xmit(
rval = XEVNT_LEN;
break;
}
- if (PKT_MODE(xpkt->li_vn_mode) == MODE_SERVER) {
+ if (peer == NULL)
tcookie = cookie;
- } else {
- if ((peer = findpeerbyassoc(associd)) == NULL) {
- rval = XEVNT_ERR;
- break;
- }
- tcookie = peer->pcookie;
- }
+ else
+ tcookie = peer->hcookie;
if ((rval = crypto_encrypt((const u_char *)ep->pkt, vallen, &tcookie, &vtemp))
== XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
break;
@@ -1446,28 +1331,28 @@ crypto_xmit(
* old message, in which case light the error bit.
*/
case CRYPTO_AUTO | CRYPTO_RESP:
- if ((peer = findpeerbyassoc(associd)) == NULL) {
- rval = XEVNT_ERR;
- break;
+ if (peer == NULL) {
+ if ((peer = findpeerbyassoc(associd)) == NULL) {
+ rval = XEVNT_ERR;
+ break;
+ }
}
peer->flags &= ~FLAG_ASSOC;
- len += crypto_send(fp, &peer->sndval);
+ len = crypto_send(fp, &peer->sndval, start);
break;
/*
- * Send leapseconds table and signature. Use the values from the
- * tai structure. If no table has been loaded, just send an
+ * Send leapseconds values and signature. Use the values from
+ * the tai structure. If no table has been loaded, just send an
* empty request.
*/
- case CRYPTO_TAI:
- case CRYPTO_TAI | CRYPTO_RESP:
- if (crypto_flags & CRYPTO_FLAG_TAI)
- len += crypto_send(fp, &tai_leap);
+ case CRYPTO_LEAP | CRYPTO_RESP:
+ len = crypto_send(fp, &tai_leap, start);
break;
/*
- * Default - Fall through for requests; for unknown responses,
- * flag as error.
+ * Default - Send a valid command for unknown requests; send
+ * an error response for unknown resonses.
*/
default:
if (opcode & CRYPTO_RESP)
@@ -1479,47 +1364,37 @@ crypto_xmit(
* puppy; if a response, return so the sender can flame, too.
*/
if (rval != XEVNT_OK) {
- opcode |= CRYPTO_ERROR;
- snprintf(statstr, NTP_MAXSTRLEN,
- "error %x opcode %x", rval, opcode);
+ u_int32 uint32;
+
+ uint32 = CRYPTO_ERROR;
+ opcode |= uint32;
+ fp->opcode |= htonl(uint32);
+ snprintf(statstr, sizeof(statstr),
+ "%04x %d %02x %s", opcode, associd, rval,
+ eventstr(rval));
record_crypto_stats(srcadr_sin, statstr);
- report_event(rval, NULL);
-#ifdef DEBUG
- if (debug)
- printf("crypto_xmit: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_xmit: %s\n", statstr));
if (!(opcode & CRYPTO_RESP))
return (0);
}
-
- /*
- * Round up the field length to a multiple of 8 bytes and save
- * the request code and length.
- */
- len = ((len + 7) / 8) * 8;
- fp->opcode = htonl((opcode & 0xffff0000) | len);
-#ifdef DEBUG
- if (debug)
- printf(
- "crypto_xmit: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",
- crypto_flags, start, len, opcode >> 16, associd);
-#endif
+ DPRINTF(1, ("crypto_xmit: flags 0x%x offset %d len %d code 0x%x associd %d\n",
+ crypto_flags, start, len, opcode >> 16, associd));
return (len);
}
/*
- * crypto_verify - parse and verify the extension field and value
+ * crypto_verify - verify the extension field value and signature
*
* Returns
* XEVNT_OK success
- * XEVNT_LEN bad field format or length
- * XEVNT_TSP bad timestamp
+ * XEVNT_ERR protocol error
* XEVNT_FSP bad filestamp
+ * XEVNT_LEN bad field format or length
* XEVNT_PUB bad or missing public key
* XEVNT_SGL bad signature length
* XEVNT_SIG signature not verified
- * XEVNT_ERR protocol error
+ * XEVNT_TSP bad timestamp
*/
static int
crypto_verify(
@@ -1538,41 +1413,47 @@ crypto_verify(
int i;
/*
- * We require valid opcode and field lengths, timestamp,
- * filestamp, public key, digest, signature length and
- * signature, where relevant. Note that preliminary length
- * checks are done in the main loop.
+ * We are extremely parannoyed. We require valid opcode, length,
+ * association ID, timestamp, filestamp, public key, digest,
+ * signature length and signature, where relevant. Note that
+ * preliminary length checks are done in the main loop.
*/
len = ntohl(ep->opcode) & 0x0000ffff;
opcode = ntohl(ep->opcode) & 0xffff0000;
/*
- * Check for valid operation code and protocol. The opcode must
- * not have the error bit set. If a response, it must have a
- * value header. If a request and does not contain a value
- * header, no need for further checking.
+ * Check for valid value header, association ID and extension
+ * field length. Remember, it is not an error to receive an
+ * unsolicited response; however, the response ID must match
+ * the association ID.
*/
if (opcode & CRYPTO_ERROR)
return (XEVNT_ERR);
- if (opcode & CRYPTO_RESP) {
- if (len < VALUE_LEN)
- return (XEVNT_LEN);
+ if (len < VALUE_LEN)
+ return (XEVNT_LEN);
+
+ if (opcode == (CRYPTO_AUTO | CRYPTO_RESP) && (peer->pmode ==
+ MODE_BROADCAST || (peer->cast_flags & MDF_BCLNT))) {
+ if (ntohl(ep->associd) != peer->assoc)
+ return (XEVNT_ERR);
} else {
- if (len < VALUE_LEN)
- return (XEVNT_OK);
+ if (ntohl(ep->associd) != peer->associd)
+ return (XEVNT_ERR);
}
/*
- * We have a value header. Check for valid field lengths. The
- * field length must be long enough to contain the value header,
- * value and signature. Note both the value and signature fields
- * are rounded up to the next word.
+ * We have a valid value header. Check for valid value and
+ * signature field lengths. The extension field length must be
+ * long enough to contain the value header, value and signature.
+ * Note both the value and signature field lengths are rounded
+ * up to the next word (4 octets).
*/
vallen = ntohl(ep->vallen);
if ( vallen == 0
|| vallen > MAX_VALLEN)
return (XEVNT_LEN);
+
i = (vallen + 3) / 4;
siglen = ntohl(ep->pkt[i++]);
if ( siglen > MAX_VALLEN
@@ -1582,32 +1463,16 @@ crypto_verify(
return (XEVNT_LEN);
/*
- * Punt if this is a response with no data. Punt if this is a
- * request and a previous response is pending.
- */
- if (opcode & CRYPTO_RESP) {
- if (vallen == 0)
- return (XEVNT_LEN);
- } else {
- if (peer->cmmd != NULL)
- return (XEVNT_LEN);
- }
-
- /*
* Check for valid timestamp and filestamp. If the timestamp is
* zero, the sender is not synchronized and signatures are
- * disregarded. If not, the timestamp must not precede the
+ * not possible. If nonzero the timestamp must not precede the
* filestamp. The timestamp and filestamp must not precede the
- * corresponding values in the value structure, if present. Once
- * the autokey values have been installed, the timestamp must
- * always be later than the corresponding value in the value
- * structure. Duplicate timestamps are illegal once the cookie
- * has been validated.
- */
+ * corresponding values in the value structure, if present.
+ */
tstamp = ntohl(ep->tstamp);
fstamp = ntohl(ep->fstamp);
if (tstamp == 0)
- return (XEVNT_OK);
+ return (XEVNT_TSP);
if (tstamp < fstamp)
return (XEVNT_TSP);
@@ -1615,15 +1480,24 @@ crypto_verify(
if (vp != NULL) {
tstamp1 = ntohl(vp->tstamp);
fstamp1 = ntohl(vp->fstamp);
- if ((tstamp < tstamp1 || (tstamp == tstamp1 &&
- (peer->crypto & CRYPTO_FLAG_AUTO))))
- return (XEVNT_TSP);
+ if (tstamp1 != 0 && fstamp1 != 0) {
+ if (tstamp < tstamp1)
+ return (XEVNT_TSP);
- if ((tstamp < fstamp1 || fstamp < fstamp1))
- return (XEVNT_FSP);
+ if ((tstamp < fstamp1 || fstamp < fstamp1))
+ return (XEVNT_FSP);
+ }
}
/*
+ * At the time the certificate message is validated, the public
+ * key in the message is not available. Thus, don't try to
+ * verify the signature.
+ */
+ if (opcode == (CRYPTO_CERT | CRYPTO_RESP))
+ return (XEVNT_OK);
+
+ /*
* Check for valid signature length, public key and digest
* algorithm.
*/
@@ -1632,7 +1506,7 @@ crypto_verify(
else
pkey = peer->pkey;
if (siglen == 0 || pkey == NULL || peer->digest == NULL)
- return (XEVNT_OK);
+ return (XEVNT_ERR);
if (siglen != (u_int)EVP_PKEY_size(pkey))
return (XEVNT_SGL);
@@ -1640,20 +1514,17 @@ crypto_verify(
/*
* Darn, I thought we would never get here. Verify the
* signature. If the identity exchange is verified, light the
- * proventic bit. If no client identity scheme is specified,
- * avoid doing the sign exchange.
+ * proventic bit. What a relief.
*/
EVP_VerifyInit(&ctx, peer->digest);
/* XXX: the "+ 12" needs to be at least documented... */
EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + 12);
- if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen, pkey) <= 0)
+ if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen,
+ pkey) <= 0)
return (XEVNT_SIG);
- if (peer->crypto & CRYPTO_FLAG_VRFY) {
+ if (peer->crypto & CRYPTO_FLAG_VRFY)
peer->crypto |= CRYPTO_FLAG_PROV;
- if (!(crypto_flags & CRYPTO_FLAG_MASK))
- peer->crypto |= CRYPTO_FLAG_SIGN;
- }
return (XEVNT_OK);
}
@@ -1664,9 +1535,8 @@ crypto_verify(
*
* Returns:
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
* XEVNT_CKY bad or missing cookie
- * XEVNT_PER host certificate expired
+ * XEVNT_PUB bad or missing public key
*/
static int
crypto_encrypt(
@@ -1680,13 +1550,14 @@ crypto_encrypt(
EVP_MD_CTX ctx; /* signature context */
tstamp_t tstamp; /* NTP timestamp */
u_int32 temp32;
+ u_char *puch;
/*
* Extract the public key from the request.
*/
pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, vallen);
if (pkey == NULL) {
- msyslog(LOG_ERR, "crypto_encrypt %s\n",
+ msyslog(LOG_ERR, "crypto_encrypt: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_PUB);
}
@@ -1694,35 +1565,35 @@ crypto_encrypt(
/*
* Encrypt the cookie, encode in ASN.1 and sign.
*/
- tstamp = crypto_time();
memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
vp->fstamp = hostval.tstamp;
vallen = EVP_PKEY_size(pkey);
vp->vallen = htonl(vallen);
vp->ptr = emalloc(vallen);
+ puch = vp->ptr;
temp32 = htonl(*cookie);
- if (!RSA_public_encrypt(4, (u_char *)&temp32, vp->ptr,
- pkey->pkey.rsa, RSA_PKCS1_OAEP_PADDING)) {
- msyslog(LOG_ERR, "crypto_encrypt %s\n",
+ if (RSA_public_encrypt(4, (u_char *)&temp32, puch,
+ pkey->pkey.rsa, RSA_PKCS1_OAEP_PADDING) <= 0) {
+ msyslog(LOG_ERR, "crypto_encrypt: %s",
ERR_error_string(ERR_get_error(), NULL));
+ free(vp->ptr);
EVP_PKEY_free(pkey);
return (XEVNT_CKY);
}
EVP_PKEY_free(pkey);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, vallen);
- if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
- vp->siglen = htonl(sign_siglen);
+ if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey)) {
+ NTP_INSIST(vallen <= sign_siglen);
+ vp->siglen = htonl(vallen);
+ }
return (XEVNT_OK);
}
@@ -1732,71 +1603,54 @@ crypto_encrypt(
*
* This routine determines which identity scheme is in use and
* constructs an extension field for that scheme.
+ *
+ * Returns
+ * CRYTPO_IFF IFF scheme
+ * CRYPTO_GQ GQ scheme
+ * CRYPTO_MV MV scheme
+ * CRYPTO_NULL no available scheme
*/
u_int
crypto_ident(
struct peer *peer /* peer structure pointer */
)
{
- char filename[MAXFILENAME + 1];
+ char filename[MAXFILENAME];
+ const char * scheme_name;
+ u_int scheme_id;
/*
- * If the server identity has already been verified, no further
- * action is necessary. Otherwise, try to load the identity file
- * of the certificate issuer. If the issuer file is not found,
- * try the host file. If nothing found, declare a cryptobust.
- * Note we can't get here unless the trusted certificate has
- * been found and the CRYPTO_FLAG_VALID bit is set, so the
- * certificate issuer is valid.
+ * We come here after the group trusted host has been found; its
+ * name defines the group name. Search the key cache for all
+ * keys matching the same group name in order IFF, GQ and MV.
+ * Use the first one available.
*/
- if (peer->ident_pkey != NULL)
- EVP_PKEY_free(peer->ident_pkey);
- if (peer->crypto & CRYPTO_FLAG_GQ) {
- snprintf(filename, MAXFILENAME, "ntpkey_gq_%s",
- peer->issuer);
- peer->ident_pkey = crypto_key(filename, &peer->fstamp);
- if (peer->ident_pkey != NULL)
- return (CRYPTO_GQ);
-
- snprintf(filename, MAXFILENAME, "ntpkey_gq_%s",
- sys_hostname);
- peer->ident_pkey = crypto_key(filename, &peer->fstamp);
- if (peer->ident_pkey != NULL)
- return (CRYPTO_GQ);
- }
+ scheme_name = NULL;
if (peer->crypto & CRYPTO_FLAG_IFF) {
- snprintf(filename, MAXFILENAME, "ntpkey_iff_%s",
- peer->issuer);
- peer->ident_pkey = crypto_key(filename, &peer->fstamp);
+ scheme_name = "iff";
+ scheme_id = CRYPTO_IFF;
+ } else if (peer->crypto & CRYPTO_FLAG_GQ) {
+ scheme_name = "gq";
+ scheme_id = CRYPTO_GQ;
+ } else if (peer->crypto & CRYPTO_FLAG_MV) {
+ scheme_name = "mv";
+ scheme_id = CRYPTO_MV;
+ }
+
+ if (scheme_name != NULL) {
+ snprintf(filename, sizeof(filename), "ntpkey_%spar_%s",
+ scheme_name, peer->ident);
+ peer->ident_pkey = crypto_key(filename, NULL,
+ &peer->srcadr);
if (peer->ident_pkey != NULL)
- return (CRYPTO_IFF);
-
- snprintf(filename, MAXFILENAME, "ntpkey_iff_%s",
- sys_hostname);
- peer->ident_pkey = crypto_key(filename, &peer->fstamp);
- if (peer->ident_pkey != NULL)
- return (CRYPTO_IFF);
+ return scheme_id;
}
- if (peer->crypto & CRYPTO_FLAG_MV) {
- snprintf(filename, MAXFILENAME, "ntpkey_mv_%s",
- peer->issuer);
- peer->ident_pkey = crypto_key(filename, &peer->fstamp);
- if (peer->ident_pkey != NULL)
- return (CRYPTO_MV);
- snprintf(filename, MAXFILENAME, "ntpkey_mv_%s",
- sys_hostname);
- peer->ident_pkey = crypto_key(filename, &peer->fstamp);
- if (peer->ident_pkey != NULL)
- return (CRYPTO_MV);
- }
+ msyslog(LOG_NOTICE,
+ "crypto_ident: no identity parameters found for group %s",
+ peer->ident);
- /*
- * No compatible identity scheme is available. Life is hard.
- */
- msyslog(LOG_INFO,
- "crypto_ident: no compatible identity scheme found");
- return (0);
+ return CRYPTO_NULL;
}
@@ -1808,7 +1662,7 @@ crypto_ident(
* extension field is created here, but freed after the crypto_xmit()
* call in the protocol module.
*
- * Returns extension field pointer (no errors).
+ * Returns extension field pointer (no errors)
*
* XXX: opcode and len should really be 32-bit quantities and
* we should make sure that str is not too big.
@@ -1817,43 +1671,37 @@ struct exten *
crypto_args(
struct peer *peer, /* peer structure pointer */
u_int opcode, /* operation code */
+ associd_t associd, /* association ID */
char *str /* argument string */
)
{
tstamp_t tstamp; /* NTP timestamp */
struct exten *ep; /* extension field pointer */
u_int len; /* extension field length */
- size_t slen;
+ size_t slen = 0;
tstamp = crypto_time();
len = sizeof(struct exten);
if (str != NULL) {
slen = strlen(str);
+ INSIST(slen < MAX_VALLEN);
len += slen;
}
- ep = emalloc(len);
- memset(ep, 0, len);
+ ep = emalloc_zero(len);
if (opcode == 0)
return (ep);
- ep->opcode = htonl(opcode + len);
+ REQUIRE(0 == (len & ~0x0000ffff));
+ REQUIRE(0 == (opcode & ~0xffff0000));
- /*
- * If a response, send our ID; if a request, send the
- * responder's ID.
- */
- if (opcode & CRYPTO_RESP)
- ep->associd = htonl(peer->associd);
- else
- ep->associd = htonl(peer->assoc);
+ ep->opcode = htonl(opcode + len);
+ ep->associd = htonl(associd);
ep->tstamp = htonl(tstamp);
ep->fstamp = hostval.tstamp;
ep->vallen = 0;
if (str != NULL) {
ep->vallen = htonl(slen);
memcpy((char *)ep->pkt, str, slen);
- } else {
- ep->pkt[0] = peer->associd;
}
return (ep);
}
@@ -1862,44 +1710,71 @@ crypto_args(
/*
* crypto_send - construct extension field from value components
*
- * Returns extension field length. Note: it is not polite to send a
- * nonempty signature with zero timestamp or a nonzero timestamp with
- * empty signature, but these rules are not enforced here.
+ * The value and signature fields are zero-padded to a word boundary.
+ * Note: it is not polite to send a nonempty signature with zero
+ * timestamp or a nonzero timestamp with an empty signature, but those
+ * rules are not enforced here.
*
* XXX This code won't work on a box with 16-bit ints.
*/
-u_int
+int
crypto_send(
struct exten *ep, /* extension field pointer */
- struct value *vp /* value pointer */
+ struct value *vp, /* value pointer */
+ int start /* buffer offset */
)
{
- u_int len, temp32;
- int i;
+ u_int len, vallen, siglen, opcode;
+ u_int i, j;
/*
- * Copy data. If the data field is empty or zero length, encode
- * an empty value with length zero.
+ * Calculate extension field length and check for buffer
+ * overflow. Leave room for the MAC.
+ */
+ len = 16; /* XXX Document! */
+ vallen = ntohl(vp->vallen);
+ INSIST(vallen <= MAX_VALLEN);
+ len += ((vallen + 3) / 4 + 1) * 4;
+ siglen = ntohl(vp->siglen);
+ len += ((siglen + 3) / 4 + 1) * 4;
+ if (start + len > sizeof(struct pkt) - MAX_MAC_LEN)
+ return (0);
+
+ /*
+ * Copy timestamps.
*/
ep->tstamp = vp->tstamp;
ep->fstamp = vp->fstamp;
ep->vallen = vp->vallen;
- len = 12;
- temp32 = ntohl(vp->vallen);
- if (temp32 > 0 && vp->ptr != NULL)
- memcpy(ep->pkt, vp->ptr, temp32);
+
+ /*
+ * Copy value. If the data field is empty or zero length,
+ * encode an empty value with length zero.
+ */
+ i = 0;
+ if (vallen > 0 && vp->ptr != NULL) {
+ j = vallen / 4;
+ if (j * 4 < vallen)
+ ep->pkt[i + j++] = 0;
+ memcpy(&ep->pkt[i], vp->ptr, vallen);
+ i += j;
+ }
/*
* Copy signature. If the signature field is empty or zero
* length, encode an empty signature with length zero.
*/
- i = (temp32 + 3) / 4;
- len += i * 4 + 4;
ep->pkt[i++] = vp->siglen;
- temp32 = ntohl(vp->siglen);
- if (temp32 > 0 && vp->sig != NULL)
- memcpy(&ep->pkt[i], vp->sig, temp32);
- len += temp32;
+ if (siglen > 0 && vp->sig != NULL) {
+ j = siglen / 4;
+ if (j * 4 < siglen)
+ ep->pkt[i + j++] = 0;
+ memcpy(&ep->pkt[i], vp->sig, siglen);
+ i += j;
+ }
+ opcode = ntohl(ep->opcode);
+ ep->opcode = htonl((opcode & 0xffff0000) | len);
+ ENSURE(len <= MAX_VALLEN);
return (len);
}
@@ -1914,12 +1789,11 @@ crypto_send(
* hostval host name (not signed)
* pubkey public key
* cinfo certificate info/value list
- * tai_leap leapseconds file
+ * tai_leap leap values
*
- * Filestamps are proventicated data, so this routine is run only when
- * the host has been synchronized to a proventicated source. Thus, the
- * timestamp is proventicated, too, and can be used to deflect
- * clogging attacks and even cook breakfast.
+ * Filestamps are proventic data, so this routine runs only when the
+ * host is synchronized to a proventicated source. Thus, the timestamp
+ * is proventic and can be used to deflect clogging attacks.
*
* Returns void (no errors)
*/
@@ -1927,16 +1801,16 @@ void
crypto_update(void)
{
EVP_MD_CTX ctx; /* message digest context */
- struct cert_info *cp, *cpn; /* certificate info/value */
+ struct cert_info *cp; /* certificate info/value */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
- tstamp_t tstamp; /* NTP timestamp */
+ u_int32 *ptr;
u_int len;
+ leap_result_t leap_data;
- if ((tstamp = crypto_time()) == 0)
+ hostval.tstamp = htonl(crypto_time());
+ if (hostval.tstamp == 0)
return;
- hostval.tstamp = htonl(tstamp);
-
/*
* Sign public key and timestamps. The filestamp is derived from
* the host key file extension from wherever the file was
@@ -1950,8 +1824,10 @@ crypto_update(void)
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&pubkey, 12);
EVP_SignUpdate(&ctx, pubkey.ptr, ntohl(pubkey.vallen));
- if (EVP_SignFinal(&ctx, pubkey.sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, pubkey.sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
pubkey.siglen = htonl(len);
+ }
}
/*
@@ -1960,8 +1836,7 @@ crypto_update(void)
* was generated. Note we do not throw expired certificates
* away; they may have signed younger ones.
*/
- for (cp = cinfo; cp != NULL; cp = cpn) {
- cpn = cp->link;
+ for (cp = cinfo; cp != NULL; cp = cp->link) {
cp->cert.tstamp = hostval.tstamp;
cp->cert.siglen = 0;
if (cp->cert.sig == NULL)
@@ -1970,36 +1845,98 @@ crypto_update(void)
EVP_SignUpdate(&ctx, (u_char *)&cp->cert, 12);
EVP_SignUpdate(&ctx, cp->cert.ptr,
ntohl(cp->cert.vallen));
- if (EVP_SignFinal(&ctx, cp->cert.sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, cp->cert.sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
cp->cert.siglen = htonl(len);
+ }
}
/*
- * Sign leapseconds table and timestamps. The filestamp is
- * derived from the leapsecond file extension from wherever the
- * file was generated.
+ * Sign leapseconds values and timestamps. Note it is not an
+ * error to return null values.
*/
- if (tai_leap.vallen != 0) {
- tai_leap.tstamp = hostval.tstamp;
- tai_leap.siglen = 0;
- if (tai_leap.sig == NULL)
- tai_leap.sig = emalloc(sign_siglen);
- EVP_SignInit(&ctx, sign_digest);
- EVP_SignUpdate(&ctx, (u_char *)&tai_leap, 12);
- EVP_SignUpdate(&ctx, tai_leap.ptr,
- ntohl(tai_leap.vallen));
- if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey))
- tai_leap.siglen = htonl(len);
+ tai_leap.tstamp = hostval.tstamp;
+ tai_leap.fstamp = hostval.fstamp;
+
+ /* Get the leap second era. We might need a full lookup early
+ * after start, when the cache is not yet loaded.
+ */
+ leapsec_frame(&leap_data);
+ if ( ! memcmp(&leap_data.ebase, &leap_data.ttime, sizeof(vint64))) {
+ time_t now = time(NULL);
+ uint32_t nowntp = (uint32_t)now + JAN_1970;
+ leapsec_query(&leap_data, nowntp, &now);
}
- snprintf(statstr, NTP_MAXSTRLEN,
- "update ts %u", ntohl(hostval.tstamp));
+
+ /* Create the data block. The protocol does not work without. */
+ len = 3 * sizeof(u_int32);
+ if (tai_leap.ptr == NULL || ntohl(tai_leap.vallen) != len) {
+ free(tai_leap.ptr);
+ tai_leap.ptr = emalloc(len);
+ tai_leap.vallen = htonl(len);
+ }
+ ptr = (u_int32 *)tai_leap.ptr;
+ if (leap_data.tai_offs > 10) {
+ /* create a TAI / leap era block. The end time is a
+ * fake -- maybe we can do better.
+ */
+ ptr[0] = htonl(leap_data.tai_offs);
+ ptr[1] = htonl(leap_data.ebase.d_s.lo);
+ if (leap_data.ttime.d_s.hi >= 0)
+ ptr[2] = htonl(leap_data.ttime.D_s.lo + 7*86400);
+ else
+ ptr[2] = htonl(leap_data.ebase.D_s.lo + 25*86400);
+ } else {
+ /* no leap era available */
+ memset(ptr, 0, len);
+ }
+ if (tai_leap.sig == NULL)
+ tai_leap.sig = emalloc(sign_siglen);
+ EVP_SignInit(&ctx, sign_digest);
+ EVP_SignUpdate(&ctx, (u_char *)&tai_leap, 12);
+ EVP_SignUpdate(&ctx, tai_leap.ptr, len);
+ if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
+ tai_leap.siglen = htonl(len);
+ }
+ crypto_flags |= CRYPTO_FLAG_TAI;
+
+ snprintf(statstr, sizeof(statstr), "signature update ts %u",
+ ntohl(hostval.tstamp));
record_crypto_stats(NULL, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_update: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_update: %s\n", statstr));
}
+/*
+ * crypto_update_taichange - eventually trigger crypto_update
+ *
+ * This is called when a change in 'sys_tai' is detected. This will
+ * happen shortly after a leap second is detected, but unhappily also
+ * early after system start; also, the crypto stuff might be unused and
+ * an unguarded call to crypto_update() causes a crash.
+ *
+ * This function makes sure that there already *is* a valid crypto block
+ * for the use with autokey, and only calls 'crypto_update()' if it can
+ * succeed.
+ *
+ * Returns void (no errors)
+ */
+void
+crypto_update_taichange(void)
+{
+ static const u_int len = 3 * sizeof(u_int32);
+
+ /* check if the signing digest algo is available */
+ if (sign_digest == NULL || sign_pkey == NULL)
+ return;
+
+ /* check size of TAI extension block */
+ if (tai_leap.ptr == NULL || ntohl(tai_leap.vallen) != len)
+ return;
+
+ /* crypto_update should at least not crash here! */
+ crypto_update();
+}
/*
* value_free - free value structure components.
@@ -2020,12 +1957,14 @@ value_free(
/*
- * crypto_time - returns current NTP time in seconds.
+ * crypto_time - returns current NTP time.
+ *
+ * Returns NTP seconds if in synch, 0 otherwise
*/
tstamp_t
crypto_time()
{
- l_fp tstamp; /* NTP time */ L_CLR(&tstamp);
+ l_fp tstamp; /* NTP time */
L_CLR(&tstamp);
if (sys_leap != LEAP_NOTINSYNC)
@@ -2035,46 +1974,71 @@ crypto_time()
/*
- * asn2ntp - convert ASN1_TIME time structure to NTP time in seconds.
+ * asn_to_calendar - convert ASN1_TIME time structure to struct calendar.
+ *
*/
-u_long
-asn2ntp (
- ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */
+static
+void
+asn_to_calendar (
+ ASN1_TIME *asn1time, /* pointer to ASN1_TIME structure */
+ struct calendar *pjd /* pointer to result */
)
{
- char *v; /* pointer to ASN1_TIME string */
- struct tm tm; /* used to convert to NTP time */
+ size_t len; /* length of ASN1_TIME string */
+ char v[24]; /* writable copy of ASN1_TIME string */
+ unsigned long temp; /* result from strtoul */
/*
* Extract time string YYMMDDHHMMSSZ from ASN1 time structure.
+ * Or YYYYMMDDHHMMSSZ.
* Note that the YY, MM, DD fields start with one, the HH, MM,
- * SS fiels start with zero and the Z character should be 'Z'
- * for UTC. Also note that years less than 50 map to years
- * greater than 100. Dontcha love ASN.1? Better than MIL-188.
- */
- if (asn1time->length > 13)
- return ((u_long)(~0)); /* We can't use -1 here. It's invalid */
-
- v = (char *)asn1time->data;
- tm.tm_year = (v[0] - '0') * 10 + v[1] - '0';
- if (tm.tm_year < 50)
- tm.tm_year += 100;
- tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1;
- tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0';
- tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0';
- tm.tm_min = (v[8] - '0') * 10 + v[9] - '0';
- tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0';
- tm.tm_wday = 0;
- tm.tm_yday = 0;
- tm.tm_isdst = 0;
- return (timegm(&tm) + JAN_1970);
+ * SS fields start with zero and the Z character is ignored.
+ * Also note that two-digit years less than 50 map to years greater than
+ * 100. Dontcha love ASN.1? Better than MIL-188.
+ */
+ len = asn1time->length;
+ NTP_REQUIRE(len < sizeof(v));
+ (void)strncpy(v, (char *)(asn1time->data), len);
+ NTP_REQUIRE(len >= 13);
+ temp = strtoul(v+len-3, NULL, 10);
+ pjd->second = temp;
+ v[len-3] = '\0';
+
+ temp = strtoul(v+len-5, NULL, 10);
+ pjd->minute = temp;
+ v[len-5] = '\0';
+
+ temp = strtoul(v+len-7, NULL, 10);
+ pjd->hour = temp;
+ v[len-7] = '\0';
+
+ temp = strtoul(v+len-9, NULL, 10);
+ pjd->monthday = temp;
+ v[len-9] = '\0';
+
+ temp = strtoul(v+len-11, NULL, 10);
+ pjd->month = temp;
+ v[len-11] = '\0';
+
+ temp = strtoul(v, NULL, 10);
+ /* handle two-digit years */
+ if (temp < 50UL)
+ temp += 100UL;
+ if (temp < 150UL)
+ temp += 1900UL;
+ pjd->year = temp;
+
+ pjd->yearday = pjd->weekday = 0;
+ return;
}
/*
* bigdig() - compute a BIGNUM MD5 hash of a BIGNUM number.
+ *
+ * Returns void (no errors)
*/
-static int
+static void
bighash(
BIGNUM *bn, /* BIGNUM * from */
BIGNUM *bk /* BIGNUM * to */
@@ -2092,10 +2056,7 @@ bighash(
EVP_DigestUpdate(&ctx, ptr, len);
EVP_DigestFinal(&ctx, dgst, &len);
BN_bin2bn(dgst, len, bk);
-
- /* XXX MEMLEAK? free ptr? */
-
- return (1);
+ free(ptr);
}
@@ -2107,35 +2068,38 @@ bighash(
***********************************************************************
*
* The Schnorr (IFF) identity scheme is intended for use when
- * the ntp-genkeys program does not generate the certificates used in
- * the protocol and the group key cannot be conveyed in the certificate
- * itself. For this purpose, new generations of IFF values must be
- * securely transmitted to all members of the group before use. The
- * scheme is self contained and independent of new generations of host
- * keys, sign keys and certificates.
- *
- * The IFF identity scheme is based on DSA cryptography and algorithms
- * described in Stinson p. 285. The IFF values hide in a DSA cuckoo
- * structure, but only the primes and generator are used. The p is a
- * 512-bit prime, q a 160-bit prime that divides p - 1 and is a qth root
- * of 1 mod p; that is, g^q = 1 mod p. The TA rolls primvate random
- * group key b disguised as a DSA structure member, then computes public
- * key g^(q - b). These values are shared only among group members and
- * never revealed in messages. Alice challenges Bob to confirm identity
- * using the protocol described below.
+ * certificates are generated by some other trusted certificate
+ * authority and the certificate cannot be used to convey public
+ * parameters. There are two kinds of files: encrypted server files that
+ * contain private and public values and nonencrypted client files that
+ * contain only public values. New generations of server files must be
+ * securely transmitted to all servers of the group; client files can be
+ * distributed by any means. The scheme is self contained and
+ * independent of new generations of host keys, sign keys and
+ * certificates.
+ *
+ * The IFF values hide in a DSA cuckoo structure which uses the same
+ * parameters. The values are used by an identity scheme based on DSA
+ * cryptography and described in Stimson p. 285. The p is a 512-bit
+ * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
+ * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
+ * private random group key b (0 < b < q) and public key v = g^b, then
+ * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients.
+ * Alice challenges Bob to confirm identity using the protocol described
+ * below.
*
* How it works
*
* The scheme goes like this. Both Alice and Bob have the public primes
* p, q and generator g. The TA gives private key b to Bob and public
- * key v = g^(q - a) mod p to Alice.
- *
- * Alice rolls new random challenge r and sends to Bob in the IFF
- * request message. Bob rolls new random k, then computes y = k + b r
- * mod q and x = g^k mod p and sends (y, hash(x)) to Alice in the
- * response message. Besides making the response shorter, the hash makes
- * it effectivey impossible for an intruder to solve for b by observing
- * a number of these messages.
+ * key v to Alice.
+ *
+ * Alice rolls new random challenge r (o < r < q) and sends to Bob in
+ * the IFF request message. Bob rolls new random k (0 < k < q), then
+ * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x))
+ * to Alice in the response message. Besides making the response
+ * shorter, the hash makes it effectivey impossible for an intruder to
+ * solve for b by observing a number of these messages.
*
* Alice receives the response and computes g^y v^r mod p. After a bit
* of algebra, this simplifies to g^k. If the hash of this result
@@ -2147,8 +2111,8 @@ bighash(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
* XEVNT_ID bad or missing group key
+ * XEVNT_PUB bad or missing public key
*/
static int
crypto_alice(
@@ -2165,50 +2129,49 @@ crypto_alice(
/*
* The identity parameters must have correct format and content.
*/
- if (peer->ident_pkey == NULL)
+ if (peer->ident_pkey == NULL) {
+ msyslog(LOG_NOTICE, "crypto_alice: scheme unavailable");
return (XEVNT_ID);
+ }
- if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_alice: defective key");
+ if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
+ msyslog(LOG_NOTICE, "crypto_alice: defective key");
return (XEVNT_PUB);
}
/*
- * Roll new random r (0 < r < q). The OpenSSL library has a bug
- * omitting BN_rand_range, so we have to do it the hard way.
+ * Roll new random r (0 < r < q).
*/
- bctx = BN_CTX_new();
- len = BN_num_bytes(dsa->q);
if (peer->iffval != NULL)
BN_free(peer->iffval);
peer->iffval = BN_new();
- BN_rand(peer->iffval, len * 8, -1, 1); /* r */
+ len = BN_num_bytes(dsa->q);
+ BN_rand(peer->iffval, len * 8, -1, 1); /* r mod q*/
+ bctx = BN_CTX_new();
BN_mod(peer->iffval, peer->iffval, dsa->q, bctx);
BN_CTX_free(bctx);
/*
* Sign and send to Bob. The filestamp is from the local file.
*/
- tstamp = crypto_time();
memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
- vp->fstamp = htonl(peer->fstamp);
+ vp->fstamp = htonl(peer->ident_pkey->fstamp);
vp->vallen = htonl(len);
vp->ptr = emalloc(len);
BN_bn2bin(peer->iffval, vp->ptr);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
vp->siglen = htonl(len);
+ }
return (XEVNT_OK);
}
@@ -2218,9 +2181,8 @@ crypto_alice(
*
* Returns
* XEVNT_OK success
- * XEVNT_ID bad or missing group key
* XEVNT_ERR protocol error
- * XEVNT_PER host expired certificate
+ * XEVNT_ID bad or missing group key
*/
static int
crypto_bob(
@@ -2242,11 +2204,11 @@ crypto_bob(
* If the IFF parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (iffpar_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_bob: scheme unavailable");
+ if (iffkey_info == NULL) {
+ msyslog(LOG_NOTICE, "crypto_bob: scheme unavailable");
return (XEVNT_ID);
}
- dsa = iffpar_pkey->pkey.dsa;
+ dsa = iffkey_info->pkey->pkey.dsa;
/*
* Extract r from the challenge.
@@ -2256,7 +2218,7 @@ crypto_bob(
if (vallen == 0 || len < VALUE_LEN || len - VALUE_LEN < vallen)
return XEVNT_LEN;
if ((r = BN_bin2bn((u_char *)ep->pkt, vallen, NULL)) == NULL) {
- msyslog(LOG_ERR, "crypto_bob %s\n",
+ msyslog(LOG_ERR, "crypto_bob: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
}
@@ -2277,13 +2239,18 @@ crypto_bob(
sdsa->s = BN_dup(bk);
BN_CTX_free(bctx);
BN_free(r); BN_free(bn); BN_free(bk);
+#ifdef DEBUG
+ if (debug > 1)
+ DSA_print_fp(stdout, dsa, 0);
+#endif
/*
- * Encode the values in ASN.1 and sign.
+ * Encode the values in ASN.1 and sign. The filestamp is from
+ * the local file.
*/
vallen = i2d_DSA_SIG(sdsa, NULL);
if (vallen == 0) {
- msyslog(LOG_ERR, "crypto_bob %s\n",
+ msyslog(LOG_ERR, "crypto_bob: %s",
ERR_error_string(ERR_get_error(), NULL));
DSA_SIG_free(sdsa);
return (XEVNT_ERR);
@@ -2297,26 +2264,24 @@ crypto_bob(
memset(vp, 0, sizeof(struct value));
tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
- vp->fstamp = htonl(if_fstamp);
+ vp->fstamp = htonl(iffkey_info->fstamp);
vp->vallen = htonl(vallen);
ptr = emalloc(vallen);
vp->ptr = ptr;
i2d_DSA_SIG(sdsa, &ptr);
DSA_SIG_free(sdsa);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
/* XXX: more validation to make sure the sign fits... */
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, vallen);
- if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
- vp->siglen = htonl(len);
+ if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey)) {
+ NTP_INSIST(vallen <= sign_siglen);
+ vp->siglen = htonl(vallen);
+ }
return (XEVNT_OK);
}
@@ -2326,9 +2291,9 @@ crypto_bob(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
- * XEVNT_ID bad or missing group key
* XEVNT_FSP bad filestamp
+ * XEVNT_ID bad or missing group key
+ * XEVNT_PUB bad or missing public key
*/
int
crypto_iff(
@@ -2341,7 +2306,7 @@ crypto_iff(
DSA_SIG *sdsa; /* DSA parameters */
BIGNUM *bn, *bk;
u_int len;
- const u_char *ptr;
+ const u_char *ptr;
int temp;
/*
@@ -2349,20 +2314,20 @@ crypto_iff(
* something awful happened or we are being tormented.
*/
if (peer->ident_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_iff: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_iff: scheme unavailable");
return (XEVNT_ID);
}
- if (ntohl(ep->fstamp) != peer->fstamp) {
- msyslog(LOG_INFO, "crypto_iff: invalid filestamp %u",
+ if (ntohl(ep->fstamp) != peer->ident_pkey->fstamp) {
+ msyslog(LOG_NOTICE, "crypto_iff: invalid filestamp %u",
ntohl(ep->fstamp));
return (XEVNT_FSP);
}
- if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_iff: defective key");
+ if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
+ msyslog(LOG_NOTICE, "crypto_iff: defective key");
return (XEVNT_PUB);
}
if (peer->iffval == NULL) {
- msyslog(LOG_INFO, "crypto_iff: missing challenge");
+ msyslog(LOG_NOTICE, "crypto_iff: missing challenge");
return (XEVNT_ID);
}
@@ -2371,9 +2336,10 @@ crypto_iff(
*/
bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new();
len = ntohl(ep->vallen);
- ptr = (const u_char *)ep->pkt;
+ ptr = (u_char *)ep->pkt;
if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) {
- msyslog(LOG_ERR, "crypto_iff %s\n",
+ BN_free(bn); BN_free(bk); BN_CTX_free(bctx);
+ msyslog(LOG_ERR, "crypto_iff: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
}
@@ -2397,8 +2363,8 @@ crypto_iff(
if (temp == 0)
return (XEVNT_OK);
- else
- return (XEVNT_ID);
+ msyslog(LOG_NOTICE, "crypto_iff: identity not verified");
+ return (XEVNT_ID);
}
@@ -2411,20 +2377,25 @@ crypto_iff(
***********************************************************************
*
* The Guillou-Quisquater (GQ) identity scheme is intended for use when
- * the ntp-genkeys program generates the certificates used in the
- * protocol and the group key can be conveyed in a certificate extension
- * field. The scheme is self contained and independent of new
- * generations of host keys, sign keys and certificates.
- *
- * The GQ identity scheme is based on RSA cryptography and algorithms
- * described in Stinson p. 300 (with errors). The GQ values hide in a
- * RSA cuckoo structure, but only the modulus is used. The 512-bit
- * public modulus is n = p q, where p and q are secret large primes. The
- * TA rolls random group key b disguised as a RSA structure member.
- * Except for the public key, these values are shared only among group
- * members and never revealed in messages.
- *
- * When rolling new certificates, Bob recomputes the private and
+ * the certificate can be used to convey public parameters. The scheme
+ * uses a X509v3 certificate extension field do convey the public key of
+ * a private key known only to servers. There are two kinds of files:
+ * encrypted server files that contain private and public values and
+ * nonencrypted client files that contain only public values. New
+ * generations of server files must be securely transmitted to all
+ * servers of the group; client files can be distributed by any means.
+ * The scheme is self contained and independent of new generations of
+ * host keys and sign keys. The scheme is self contained and independent
+ * of new generations of host keys and sign keys.
+ *
+ * The GQ parameters hide in a RSA cuckoo structure which uses the same
+ * parameters. The values are used by an identity scheme based on RSA
+ * cryptography and described in Stimson p. 300 (with errors). The 512-
+ * bit public modulus is n = p q, where p and q are secret large primes.
+ * The TA rolls private random group key b as RSA exponent. These values
+ * are known to all group members.
+ *
+ * When rolling new certificates, a server recomputes the private and
* public keys. The private key u is a random roll, while the public key
* is the inverse obscured by the group key v = (u^-1)^b. These values
* replace the private and public keys normally generated by the RSA
@@ -2459,9 +2430,8 @@ crypto_iff(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
* XEVNT_ID bad or missing group key
- * XEVNT_PER host certificate expired
+ * XEVNT_PUB bad or missing public key
*/
static int
crypto_alice2(
@@ -2481,47 +2451,44 @@ crypto_alice2(
if (peer->ident_pkey == NULL)
return (XEVNT_ID);
- if ((rsa = peer->ident_pkey->pkey.rsa) == NULL) {
- msyslog(LOG_INFO, "crypto_alice2: defective key");
+ if ((rsa = peer->ident_pkey->pkey->pkey.rsa) == NULL) {
+ msyslog(LOG_NOTICE, "crypto_alice2: defective key");
return (XEVNT_PUB);
}
/*
- * Roll new random r (0 < r < n). The OpenSSL library has a bug
- * omitting BN_rand_range, so we have to do it the hard way.
+ * Roll new random r (0 < r < n).
*/
- bctx = BN_CTX_new();
- len = BN_num_bytes(rsa->n);
if (peer->iffval != NULL)
BN_free(peer->iffval);
peer->iffval = BN_new();
+ len = BN_num_bytes(rsa->n);
BN_rand(peer->iffval, len * 8, -1, 1); /* r mod n */
+ bctx = BN_CTX_new();
BN_mod(peer->iffval, peer->iffval, rsa->n, bctx);
BN_CTX_free(bctx);
/*
* Sign and send to Bob. The filestamp is from the local file.
*/
- tstamp = crypto_time();
memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
- vp->fstamp = htonl(peer->fstamp);
+ vp->fstamp = htonl(peer->ident_pkey->fstamp);
vp->vallen = htonl(len);
vp->ptr = emalloc(len);
BN_bn2bin(peer->iffval, vp->ptr);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
vp->siglen = htonl(len);
+ }
return (XEVNT_OK);
}
@@ -2531,9 +2498,8 @@ crypto_alice2(
*
* Returns
* XEVNT_OK success
- * XEVNT_ID bad or missing group key
* XEVNT_ERR protocol error
- * XEVNT_PER host certificate expired
+ * XEVNT_ID bad or missing group key
*/
static int
crypto_bob2(
@@ -2549,23 +2515,24 @@ crypto_bob2(
BIGNUM *r, *k, *g, *y;
u_char *ptr;
u_int len;
+ int s_len;
/*
* If the GQ parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (gqpar_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_bob2: scheme unavailable");
+ if (gqkey_info == NULL) {
+ msyslog(LOG_NOTICE, "crypto_bob2: scheme unavailable");
return (XEVNT_ID);
}
- rsa = gqpar_pkey->pkey.rsa;
+ rsa = gqkey_info->pkey->pkey.rsa;
/*
* Extract r from the challenge.
*/
len = ntohl(ep->vallen);
if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
- msyslog(LOG_ERR, "crypto_bob2 %s\n",
+ msyslog(LOG_ERR, "crypto_bob2: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
}
@@ -2586,39 +2553,42 @@ crypto_bob2(
sdsa->s = BN_dup(g);
BN_CTX_free(bctx);
BN_free(r); BN_free(k); BN_free(g); BN_free(y);
+#ifdef DEBUG
+ if (debug > 1)
+ RSA_print_fp(stdout, rsa, 0);
+#endif
/*
- * Encode the values in ASN.1 and sign.
+ * Encode the values in ASN.1 and sign. The filestamp is from
+ * the local file.
*/
- tstamp = crypto_time();
- memset(vp, 0, sizeof(struct value));
- vp->tstamp = htonl(tstamp);
- vp->fstamp = htonl(gq_fstamp);
- len = i2d_DSA_SIG(sdsa, NULL);
- if (len <= 0) {
- msyslog(LOG_ERR, "crypto_bob2 %s\n",
+ len = s_len = i2d_DSA_SIG(sdsa, NULL);
+ if (s_len <= 0) {
+ msyslog(LOG_ERR, "crypto_bob2: %s",
ERR_error_string(ERR_get_error(), NULL));
DSA_SIG_free(sdsa);
return (XEVNT_ERR);
}
+ memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
+ vp->tstamp = htonl(tstamp);
+ vp->fstamp = htonl(gqkey_info->fstamp);
vp->vallen = htonl(len);
ptr = emalloc(len);
vp->ptr = ptr;
i2d_DSA_SIG(sdsa, &ptr);
DSA_SIG_free(sdsa);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
vp->siglen = htonl(len);
+ }
return (XEVNT_OK);
}
@@ -2628,10 +2598,10 @@ crypto_bob2(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
- * XEVNT_ID bad or missing group keys
* XEVNT_ERR protocol error
* XEVNT_FSP bad filestamp
+ * XEVNT_ID bad or missing group keys
+ * XEVNT_PUB bad or missing public key
*/
int
crypto_gq(
@@ -2643,29 +2613,31 @@ crypto_gq(
BN_CTX *bctx; /* BIGNUM context */
DSA_SIG *sdsa; /* RSA signature context fake */
BIGNUM *y, *v;
- const u_char *ptr;
- u_int len;
- int temp;
+ const u_char *ptr;
+ long len;
+ u_int temp;
/*
* If the GQ parameters are not valid or no challenge was sent,
- * something awful happened or we are being tormented.
+ * something awful happened or we are being tormented. Note that
+ * the filestamp on the local key file can be greater than on
+ * the remote parameter file if the keys have been refreshed.
*/
if (peer->ident_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_gq: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_gq: scheme unavailable");
return (XEVNT_ID);
}
- if (ntohl(ep->fstamp) != peer->fstamp) {
- msyslog(LOG_INFO, "crypto_gq: invalid filestamp %u",
+ if (ntohl(ep->fstamp) < peer->ident_pkey->fstamp) {
+ msyslog(LOG_NOTICE, "crypto_gq: invalid filestamp %u",
ntohl(ep->fstamp));
return (XEVNT_FSP);
}
- if ((rsa = peer->ident_pkey->pkey.rsa) == NULL) {
- msyslog(LOG_INFO, "crypto_gq: defective key");
+ if ((rsa = peer->ident_pkey->pkey->pkey.rsa) == NULL) {
+ msyslog(LOG_NOTICE, "crypto_gq: defective key");
return (XEVNT_PUB);
}
if (peer->iffval == NULL) {
- msyslog(LOG_INFO, "crypto_gq: missing challenge");
+ msyslog(LOG_NOTICE, "crypto_gq: missing challenge");
return (XEVNT_ID);
}
@@ -2675,9 +2647,10 @@ crypto_gq(
*/
bctx = BN_CTX_new(); y = BN_new(); v = BN_new();
len = ntohl(ep->vallen);
- ptr = (const u_char *)ep->pkt;
+ ptr = (u_char *)ep->pkt;
if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) {
- msyslog(LOG_ERR, "crypto_gq %s\n",
+ BN_CTX_free(bctx); BN_free(y); BN_free(v);
+ msyslog(LOG_ERR, "crypto_gq: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
}
@@ -2685,6 +2658,10 @@ crypto_gq(
/*
* Compute v^r y^b mod n.
*/
+ if (peer->grpkey == NULL) {
+ msyslog(LOG_NOTICE, "crypto_gq: missing group key");
+ return (XEVNT_ID);
+ }
BN_mod_exp(v, peer->grpkey, peer->iffval, rsa->n, bctx);
/* v^r mod n */
BN_mod_exp(y, sdsa->r, rsa->e, rsa->n, bctx); /* y^b mod n */
@@ -2702,8 +2679,8 @@ crypto_gq(
if (temp == 0)
return (XEVNT_OK);
- else
- return (XEVNT_ID);
+ msyslog(LOG_NOTICE, "crypto_gq: identity not verified");
+ return (XEVNT_ID);
}
@@ -2714,8 +2691,7 @@ crypto_gq(
* scheme *
* *
***********************************************************************
- */
-/*
+ *
* The Mu-Varadharajan (MV) cryptosystem was originally intended when
* servers broadcast messages to clients, but clients never send
* messages to servers. There is one encryption key for the server and a
@@ -2732,19 +2708,16 @@ crypto_gq(
* Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001,
* 223-231. The paper has significant errors and serious omissions.
*
- * Let q be the product of n distinct primes s'[j] (j = 1...n), where
- * each s'[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
- * that q and each s'[j] divide p - 1 and p has M = n * m + 1
- * significant bits. The elements x mod q of Zq with the elements 2 and
- * the primes removed form a field Zq* valid for polynomial arithetic.
- * Let g be a generator of Zp; that is, gcd(g, p - 1) = 1 and g^q = 1
- * mod p. We expect M to be in the 500-bit range and n relatively small,
- * like 25, so the likelihood of a randomly generated element of x mod q
- * of Zq colliding with a factor of p - 1 is very small and can be
- * avoided. Associated with each s'[j] is an element s[j] such that s[j]
- * s'[j] = s'[j] mod q. We find s[j] as the quotient (q + s'[j]) /
- * s'[j]. These are the parameters of the scheme and they are expensive
- * to compute.
+ * Let q be the product of n distinct primes s1[j] (j = 1...n), where
+ * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
+ * that q and each s1[j] divide p - 1 and p has M = n * m + 1
+ * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1)
+ * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then
+ * project into Zp* as exponents of g. Sometimes we have to compute an
+ * inverse b^-1 of random b in Zq, but for that purpose we require
+ * gcd(b, q) = 1. We expect M to be in the 500-bit range and n
+ * relatively small, like 30. These are the parameters of the scheme and
+ * they are expensive to compute.
*
* We set up an instance of the scheme as follows. A set of random
* values x[j] mod q (j = 1...n), are generated as the zeros of a
@@ -2755,39 +2728,41 @@ crypto_gq(
* pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used
* to construct the decryption keys. The devil is in the details.
*
+ * This routine generates a private server encryption file including the
+ * private encryption key E and partial decryption keys gbar and ghat.
+ * It then generates public client decryption files including the public
+ * keys xbar[j] and xhat[j] for each client j. The partial decryption
+ * files are used to compute the inverse of E. These values are suitably
+ * blinded so secrets are not revealed.
+ *
* The distinguishing characteristic of this scheme is the capability to
* revoke keys. Included in the calculation of E, gbar and ghat is the
- * product s = prod(s'[j]) (j = 1...n) above. If the factor s'[j] is
+ * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is
* subsequently removed from the product and E, gbar and ghat
* recomputed, the jth client will no longer be able to compute E^-1 and
- * thus unable to decrypt the block.
+ * thus unable to decrypt the messageblock.
*
* How it works
*
- * The scheme goes like this. Bob has the server values (p, A, q, gbar,
- * ghat) and Alice the client values (p, xbar, xhat).
+ * The scheme goes like this. Bob has the server values (p, E, q, gbar,
+ * ghat) and Alice has the client values (p, xbar, xhat).
*
- * Alice rolls new random challenge r (0 < r < p) and sends to Bob in
- * the MV request message. Bob rolls new random k (0 < k < q), encrypts
- * y = A^k mod p (a permutation) and sends (hash(y), gbar^k, ghat^k) to
- * Alice.
+ * Alice rolls new random nonce r mod p and sends to Bob in the MV
+ * request message. Bob rolls random nonce k mod q, encrypts y = r E^k
+ * mod p and sends (y, gbar^k, ghat^k) to Alice.
*
- * Alice receives the response and computes the decryption key (the
- * inverse permutation) from previously obtained (xbar, xhat) and
- * (gbar^k, ghat^k) in the message. She computes the inverse, which is
- * unique by reasons explained in the ntp-keygen.c program sources. If
- * the hash of this result matches hash(y), Alice knows that Bob has the
- * group key b. The signed response binds this knowledge to Bob's
- * private key and the public key previously received in his
- * certificate.
+ * Alice receives the response and computes the inverse (E^k)^-1 from
+ * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then
+ * decrypts y and verifies it matches the original r. The signed
+ * response binds this knowledge to Bob's private key and the public key
+ * previously received in his certificate.
*
* crypto_alice3 - construct Alice's challenge in MV scheme
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
* XEVNT_ID bad or missing group key
- * XEVNT_PER host certificate expired
+ * XEVNT_PUB bad or missing public key
*/
static int
crypto_alice3(
@@ -2807,47 +2782,44 @@ crypto_alice3(
if (peer->ident_pkey == NULL)
return (XEVNT_ID);
- if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_alice3: defective key");
+ if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
+ msyslog(LOG_NOTICE, "crypto_alice3: defective key");
return (XEVNT_PUB);
}
/*
- * Roll new random r (0 < r < q). The OpenSSL library has a bug
- * omitting BN_rand_range, so we have to do it the hard way.
+ * Roll new random r (0 < r < q).
*/
- bctx = BN_CTX_new();
- len = BN_num_bytes(dsa->p);
if (peer->iffval != NULL)
BN_free(peer->iffval);
peer->iffval = BN_new();
- BN_rand(peer->iffval, len * 8, -1, 1); /* r */
+ len = BN_num_bytes(dsa->p);
+ BN_rand(peer->iffval, len * 8, -1, 1); /* r mod p */
+ bctx = BN_CTX_new();
BN_mod(peer->iffval, peer->iffval, dsa->p, bctx);
BN_CTX_free(bctx);
/*
* Sign and send to Bob. The filestamp is from the local file.
*/
- tstamp = crypto_time();
memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
- vp->fstamp = htonl(peer->fstamp);
+ vp->fstamp = htonl(peer->ident_pkey->fstamp);
vp->vallen = htonl(len);
vp->ptr = emalloc(len);
BN_bn2bin(peer->iffval, vp->ptr);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
vp->siglen = htonl(len);
+ }
return (XEVNT_OK);
}
@@ -2858,7 +2830,6 @@ crypto_alice3(
* Returns
* XEVNT_OK success
* XEVNT_ERR protocol error
- * XEVNT_PER host certificate expired
*/
static int
crypto_bob3(
@@ -2879,26 +2850,26 @@ crypto_bob3(
* If the MV parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (mvpar_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_bob3: scheme unavailable");
+ if (mvkey_info == NULL) {
+ msyslog(LOG_NOTICE, "crypto_bob3: scheme unavailable");
return (XEVNT_ID);
}
- dsa = mvpar_pkey->pkey.dsa;
+ dsa = mvkey_info->pkey->pkey.dsa;
/*
* Extract r from the challenge.
*/
len = ntohl(ep->vallen);
if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
- msyslog(LOG_ERR, "crypto_bob3 %s\n",
+ msyslog(LOG_ERR, "crypto_bob3: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
}
/*
* Bob rolls random k (0 < k < q), making sure it is not a
- * factor of q. He then computes y = A^k r and sends (hash(y),
- * gbar^k, ghat^k) to Alice.
+ * factor of q. He then computes y = r A^k and sends (y, gbar^k,
+ * and ghat^k) to Alice.
*/
bctx = BN_CTX_new(); k = BN_new(); u = BN_new();
sdsa = DSA_new();
@@ -2910,23 +2881,27 @@ crypto_bob3(
if (BN_is_one(u))
break;
}
- BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A r */
- BN_mod_mul(u, u, r, dsa->p, bctx);
- bighash(u, sdsa->p);
+ BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A^k r */
+ BN_mod_mul(sdsa->p, u, r, dsa->p, bctx);
BN_mod_exp(sdsa->q, dsa->priv_key, k, dsa->p, bctx); /* gbar */
BN_mod_exp(sdsa->g, dsa->pub_key, k, dsa->p, bctx); /* ghat */
BN_CTX_free(bctx); BN_free(k); BN_free(r); BN_free(u);
+#ifdef DEBUG
+ if (debug > 1)
+ DSA_print_fp(stdout, sdsa, 0);
+#endif
/*
- * Encode the values in ASN.1 and sign.
+ * Encode the values in ASN.1 and sign. The filestamp is from
+ * the local file.
*/
- tstamp = crypto_time();
memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
- vp->fstamp = htonl(mv_fstamp);
+ vp->fstamp = htonl(mvkey_info->fstamp);
len = i2d_DSAparams(sdsa, NULL);
- if (len <= 0) {
- msyslog(LOG_ERR, "crypto_bob3 %s\n",
+ if (len == 0) {
+ msyslog(LOG_ERR, "crypto_bob3: %s",
ERR_error_string(ERR_get_error(), NULL));
DSA_free(sdsa);
return (XEVNT_ERR);
@@ -2936,19 +2911,17 @@ crypto_bob3(
vp->ptr = ptr;
i2d_DSAparams(sdsa, &ptr);
DSA_free(sdsa);
- vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
vp->siglen = htonl(len);
+ }
return (XEVNT_OK);
}
@@ -2958,10 +2931,10 @@ crypto_bob3(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
- * XEVNT_ID bad or missing group key
* XEVNT_ERR protocol error
* XEVNT_FSP bad filestamp
+ * XEVNT_ID bad or missing group key
+ * XEVNT_PUB bad or missing public key
*/
int
crypto_mv(
@@ -2974,7 +2947,7 @@ crypto_mv(
BN_CTX *bctx; /* BIGNUM context */
BIGNUM *k, *u, *v;
u_int len;
- const u_char *ptr;
+ const u_char *ptr;
int temp;
/*
@@ -2982,49 +2955,47 @@ crypto_mv(
* something awful happened or we are being tormented.
*/
if (peer->ident_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_mv: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_mv: scheme unavailable");
return (XEVNT_ID);
}
- if (ntohl(ep->fstamp) != peer->fstamp) {
- msyslog(LOG_INFO, "crypto_mv: invalid filestamp %u",
+ if (ntohl(ep->fstamp) != peer->ident_pkey->fstamp) {
+ msyslog(LOG_NOTICE, "crypto_mv: invalid filestamp %u",
ntohl(ep->fstamp));
return (XEVNT_FSP);
}
- if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_mv: defective key");
+ if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
+ msyslog(LOG_NOTICE, "crypto_mv: defective key");
return (XEVNT_PUB);
}
if (peer->iffval == NULL) {
- msyslog(LOG_INFO, "crypto_mv: missing challenge");
+ msyslog(LOG_NOTICE, "crypto_mv: missing challenge");
return (XEVNT_ID);
}
/*
- * Extract the (hash(y), gbar, ghat) values from the response.
+ * Extract the y, gbar and ghat values from the response.
*/
bctx = BN_CTX_new(); k = BN_new(); u = BN_new(); v = BN_new();
len = ntohl(ep->vallen);
- ptr = (const u_char *)ep->pkt;
+ ptr = (u_char *)ep->pkt;
if ((sdsa = d2i_DSAparams(NULL, &ptr, len)) == NULL) {
- msyslog(LOG_ERR, "crypto_mv %s\n",
+ msyslog(LOG_ERR, "crypto_mv: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
}
/*
- * Compute (gbar^xhat ghat^xbar)^-1 mod p.
+ * Compute (gbar^xhat ghat^xbar) mod p.
*/
BN_mod_exp(u, sdsa->q, dsa->pub_key, dsa->p, bctx);
BN_mod_exp(v, sdsa->g, dsa->priv_key, dsa->p, bctx);
BN_mod_mul(u, u, v, dsa->p, bctx);
- BN_mod_inverse(u, u, dsa->p, bctx);
- BN_mod_mul(v, u, peer->iffval, dsa->p, bctx);
+ BN_mod_mul(u, u, sdsa->p, dsa->p, bctx);
/*
- * The result should match the hash of r mod p.
+ * The result should match r.
*/
- bighash(v, v);
- temp = BN_cmp(v, sdsa->p);
+ temp = BN_cmp(u, peer->iffval);
BN_CTX_free(bctx); BN_free(k); BN_free(u); BN_free(v);
BN_free(peer->iffval);
peer->iffval = NULL;
@@ -3032,8 +3003,8 @@ crypto_mv(
if (temp == 0)
return (XEVNT_OK);
- else
- return (XEVNT_ID);
+ msyslog(LOG_NOTICE, "crypto_mv: identity not verified");
+ return (XEVNT_ID);
}
@@ -3045,187 +3016,6 @@ crypto_mv(
***********************************************************************
*/
/*
- * cert_parse - parse x509 certificate and create info/value structures.
- *
- * The server certificate includes the version number, issuer name,
- * subject name, public key and valid date interval. If the issuer name
- * is the same as the subject name, the certificate is self signed and
- * valid only if the server is configured as trustable. If the names are
- * different, another issuer has signed the server certificate and
- * vouched for it. In this case the server certificate is valid if
- * verified by the issuer public key.
- *
- * Returns certificate info/value pointer if valid, NULL if not.
- */
-struct cert_info * /* certificate information structure */
-cert_parse(
- u_char *asn1cert, /* X509 certificate */
- u_int len, /* certificate length */
- tstamp_t fstamp /* filestamp */
- )
-{
- X509 *cert; /* X509 certificate */
- X509_EXTENSION *ext; /* X509v3 extension */
- struct cert_info *ret; /* certificate info/value */
- BIO *bp;
- X509V3_EXT_METHOD *method;
- char pathbuf[MAXFILENAME];
- u_char *uptr;
- char *ptr;
- int temp, cnt, i;
-
- /*
- * Decode ASN.1 objects and construct certificate structure.
- */
- uptr = asn1cert;
- if ((cert = d2i_X509(NULL, &uptr, len)) == NULL) {
- msyslog(LOG_ERR, "cert_parse %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- return (NULL);
- }
-
- /*
- * Extract version, subject name and public key.
- */
- ret = emalloc(sizeof(struct cert_info));
- memset(ret, 0, sizeof(struct cert_info));
- if ((ret->pkey = X509_get_pubkey(cert)) == NULL) {
- msyslog(LOG_ERR, "cert_parse %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- cert_free(ret);
- X509_free(cert);
- return (NULL);
- }
- ret->version = X509_get_version(cert);
- X509_NAME_oneline(X509_get_subject_name(cert), pathbuf,
- MAXFILENAME - 1);
- ptr = strstr(pathbuf, "CN=");
- if (ptr == NULL) {
- msyslog(LOG_INFO, "cert_parse: invalid subject %s",
- pathbuf);
- cert_free(ret);
- X509_free(cert);
- return (NULL);
- }
- ret->subject = emalloc(strlen(ptr) + 1);
- strcpy(ret->subject, ptr + 3);
-
- /*
- * Extract remaining objects. Note that the NTP serial number is
- * the NTP seconds at the time of signing, but this might not be
- * the case for other authority. We don't bother to check the
- * objects at this time, since the real crunch can happen only
- * when the time is valid but not yet certificated.
- */
- ret->nid = OBJ_obj2nid(cert->cert_info->signature->algorithm);
- ret->digest = (const EVP_MD *)EVP_get_digestbynid(ret->nid);
- ret->serial =
- (u_long)ASN1_INTEGER_get(X509_get_serialNumber(cert));
- X509_NAME_oneline(X509_get_issuer_name(cert), pathbuf,
- MAXFILENAME);
- if ((ptr = strstr(pathbuf, "CN=")) == NULL) {
- msyslog(LOG_INFO, "cert_parse: invalid issuer %s",
- pathbuf);
- cert_free(ret);
- X509_free(cert);
- return (NULL);
- }
- ret->issuer = emalloc(strlen(ptr) + 1);
- strcpy(ret->issuer, ptr + 3);
- ret->first = asn2ntp(X509_get_notBefore(cert));
- ret->last = asn2ntp(X509_get_notAfter(cert));
-
- /*
- * Extract extension fields. These are ad hoc ripoffs of
- * currently assigned functions and will certainly be changed
- * before prime time.
- */
- cnt = X509_get_ext_count(cert);
- for (i = 0; i < cnt; i++) {
- ext = X509_get_ext(cert, i);
- method = X509V3_EXT_get(ext);
- temp = OBJ_obj2nid(ext->object);
- switch (temp) {
-
- /*
- * If a key_usage field is present, we decode whether
- * this is a trusted or private certificate. This is
- * dorky; all we want is to compare NIDs, but OpenSSL
- * insists on BIO text strings.
- */
- case NID_ext_key_usage:
- bp = BIO_new(BIO_s_mem());
- X509V3_EXT_print(bp, ext, 0, 0);
- BIO_gets(bp, pathbuf, MAXFILENAME);
- BIO_free(bp);
-#if DEBUG
- if (debug)
- printf("cert_parse: %s: %s\n",
- OBJ_nid2ln(temp), pathbuf);
-#endif
- if (strcmp(pathbuf, "Trust Root") == 0)
- ret->flags |= CERT_TRUST;
- else if (strcmp(pathbuf, "Private") == 0)
- ret->flags |= CERT_PRIV;
- break;
-
- /*
- * If a NID_subject_key_identifier field is present, it
- * contains the GQ public key.
- */
- case NID_subject_key_identifier:
- ret->grplen = ext->value->length - 2;
- ret->grpkey = emalloc(ret->grplen);
- memcpy(ret->grpkey, &ext->value->data[2],
- ret->grplen);
- break;
- }
- }
-
- /*
- * If certificate is self signed, verify signature.
- */
- if (strcmp(ret->subject, ret->issuer) == 0) {
- if (!X509_verify(cert, ret->pkey)) {
- msyslog(LOG_INFO,
- "cert_parse: signature not verified %s",
- pathbuf);
- cert_free(ret);
- X509_free(cert);
- return (NULL);
- }
- }
-
- /*
- * Verify certificate valid times. Note that certificates cannot
- * be retroactive.
- */
- if (ret->first > ret->last || ret->first < fstamp) {
- msyslog(LOG_INFO,
- "cert_parse: invalid certificate %s first %u last %u fstamp %u",
- ret->subject, ret->first, ret->last, fstamp);
- cert_free(ret);
- X509_free(cert);
- return (NULL);
- }
-
- /*
- * Build the value structure to sign and send later.
- */
- ret->cert.fstamp = htonl(fstamp);
- ret->cert.vallen = htonl(len);
- ret->cert.ptr = emalloc(len);
- memcpy(ret->cert.ptr, asn1cert, len);
-#ifdef DEBUG
- if (debug > 1)
- X509_print_fp(stdout, cert);
-#endif
- X509_free(cert);
- return (ret);
-}
-
-
-/*
* cert_sign - sign x509 certificate equest and update value structure.
*
* The certificate request includes a copy of the host certificate,
@@ -3254,10 +3044,10 @@ cert_parse(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
* XEVNT_CRT bad or missing certificate
- * XEVNT_VFY certificate not verified
* XEVNT_PER host certificate expired
+ * XEVNT_PUB bad or missing public key
+ * XEVNT_VFY certificate not verified
*/
static int
cert_sign(
@@ -3273,8 +3063,10 @@ cert_sign(
EVP_PKEY *pkey; /* public key */
EVP_MD_CTX ctx; /* message digest context */
tstamp_t tstamp; /* NTP timestamp */
+ struct calendar tscal;
u_int len;
- u_char *ptr;
+ const u_char *cptr;
+ u_char *ptr;
int i, temp;
/*
@@ -3286,12 +3078,9 @@ cert_sign(
if (tstamp == 0)
return (XEVNT_TSP);
- if (tstamp < cinfo->first || tstamp > cinfo->last)
- return (XEVNT_PER);
-
- ptr = (u_char *)ep->pkt;
- if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) {
- msyslog(LOG_ERR, "cert_sign %s\n",
+ cptr = (void *)ep->pkt;
+ if ((req = d2i_X509(NULL, &cptr, ntohl(ep->vallen))) == NULL) {
+ msyslog(LOG_ERR, "cert_sign: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_CRT);
}
@@ -3299,16 +3088,17 @@ cert_sign(
* Extract public key and check for errors.
*/
if ((pkey = X509_get_pubkey(req)) == NULL) {
- msyslog(LOG_ERR, "cert_sign %s\n",
+ msyslog(LOG_ERR, "cert_sign: %s",
ERR_error_string(ERR_get_error(), NULL));
X509_free(req);
return (XEVNT_PUB);
}
/*
- * Generate X509 certificate signed by this server. For this
- * purpose the issuer name is the server name. Also copy any
- * extensions that might be present.
+ * Generate X509 certificate signed by this server. If this is a
+ * trusted host, the issuer name is the group name; otherwise,
+ * it is the host name. Also copy any extensions that might be
+ * present.
*/
cert = X509_new();
X509_set_version(cert, X509_get_version(req));
@@ -3319,24 +3109,30 @@ cert_sign(
X509_gmtime_adj(X509_get_notAfter(cert), YEAR);
subj = X509_get_issuer_name(cert);
X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
- (u_char *)sys_hostname, strlen(sys_hostname), -1, 0);
+ hostval.ptr, strlen((const char *)hostval.ptr), -1, 0);
subj = X509_get_subject_name(req);
X509_set_subject_name(cert, subj);
X509_set_pubkey(cert, pkey);
- ext = X509_get_ext(req, 0);
temp = X509_get_ext_count(req);
for (i = 0; i < temp; i++) {
ext = X509_get_ext(req, i);
- X509_add_ext(cert, ext, -1);
+ INSIST(X509_add_ext(cert, ext, -1));
}
X509_free(req);
/*
- * Sign and verify the certificate.
+ * Sign and verify the client certificate, but only if the host
+ * certificate has not expired.
*/
+ (void)ntpcal_ntp_to_date(&tscal, tstamp, NULL);
+ if ((calcomp(&tscal, &(cert_host->first)) < 0)
+ || (calcomp(&tscal, &(cert_host->last)) > 0)) {
+ X509_free(cert);
+ return (XEVNT_PER);
+ }
X509_sign(cert, sign_pkey, sign_digest);
- if (!X509_verify(cert, sign_pkey)) {
- printf("cert_sign\n%s\n",
+ if (X509_verify(cert, sign_pkey) <= 0) {
+ msyslog(LOG_ERR, "cert_sign: %s",
ERR_error_string(ERR_get_error(), NULL));
X509_free(cert);
return (XEVNT_VFY);
@@ -3354,14 +3150,18 @@ cert_sign(
vp->vallen = htonl(len);
vp->ptr = emalloc(len);
ptr = vp->ptr;
- i2d_X509(cert, &ptr);
+ i2d_X509(cert, (unsigned char **)(intptr_t)&ptr);
vp->siglen = 0;
- vp->sig = emalloc(sign_siglen);
- EVP_SignInit(&ctx, sign_digest);
- EVP_SignUpdate(&ctx, (u_char *)vp, 12);
- EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
- vp->siglen = htonl(len);
+ if (tstamp != 0) {
+ vp->sig = emalloc(sign_siglen);
+ EVP_SignInit(&ctx, sign_digest);
+ EVP_SignUpdate(&ctx, (u_char *)vp, 12);
+ EVP_SignUpdate(&ctx, vp->ptr, len);
+ if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) {
+ NTP_INSIST(len <= sign_siglen);
+ vp->siglen = htonl(len);
+ }
+ }
#ifdef DEBUG
if (debug > 1)
X509_print_fp(stdout, cert);
@@ -3372,74 +3172,38 @@ cert_sign(
/*
- * cert_valid - verify certificate with given public key
- *
- * This is pretty ugly, as the certificate has to be verified in the
- * OpenSSL X509 structure, not in the DER format in the info/value
- * structure.
- *
- * Returns
- * XEVNT_OK success
- * XEVNT_VFY certificate not verified
- */
-int
-cert_valid(
- struct cert_info *cinf, /* certificate information structure */
- EVP_PKEY *pkey /* public key */
- )
-{
- X509 *cert; /* X509 certificate */
- u_char *ptr;
-
- if (cinf->flags & CERT_SIGN)
- return (XEVNT_OK);
-
- ptr = (u_char *)cinf->cert.ptr;
- cert = d2i_X509(NULL, &ptr, ntohl(cinf->cert.vallen));
- if (cert == NULL || !X509_verify(cert, pkey))
- return (XEVNT_VFY);
-
- X509_free(cert);
- return (XEVNT_OK);
-}
-
-
-/*
- * cert - install certificate in certificate list
+ * cert_install - install certificate in certificate cache
*
* This routine encodes an extension field into a certificate info/value
* structure. It searches the certificate list for duplicates and
- * expunges whichever is older. It then searches the list for other
- * certificates that might be verified by this latest one. Finally, it
- * inserts this certificate first on the list.
+ * expunges whichever is older. Finally, it inserts this certificate
+ * first on the list.
*
- * Returns
- * XEVNT_OK success
- * XEVNT_FSP bad or missing filestamp
- * XEVNT_CRT bad or missing certificate
+ * Returns certificate info pointer if valid, NULL if not.
*/
-int
+struct cert_info *
cert_install(
struct exten *ep, /* cert info/value */
struct peer *peer /* peer structure */
)
{
- struct cert_info *cp, *xp, *yp, **zp;
+ struct cert_info *cp, *xp, **zp;
/*
* Parse and validate the signed certificate. If valid,
- * construct the info/value structure; otherwise, scamper home.
+ * construct the info/value structure; otherwise, scamper home
+ * empty handed.
*/
- if ((cp = cert_parse((u_char *)ep->pkt, ntohl(ep->vallen),
- ntohl(ep->fstamp))) == NULL)
- return (XEVNT_CRT);
+ if ((cp = cert_parse((u_char *)ep->pkt, (long)ntohl(ep->vallen),
+ (tstamp_t)ntohl(ep->fstamp))) == NULL)
+ return (NULL);
/*
* Scan certificate list looking for another certificate with
* the same subject and issuer. If another is found with the
* same or older filestamp, unlink it and return the goodies to
* the heap. If another is found with a later filestamp, discard
- * the new one and leave the building.
+ * the new one and leave the building with the old one.
*
* Make a note to study this issue again. An earlier certificate
* with a long lifetime might be overtaken by a later
@@ -3447,112 +3211,314 @@ cert_install(
* earlier signature. However, we gotta find a way to leak old
* stuff from the cache, so we do it anyway.
*/
- yp = cp;
zp = &cinfo;
for (xp = cinfo; xp != NULL; xp = xp->link) {
if (strcmp(cp->subject, xp->subject) == 0 &&
strcmp(cp->issuer, xp->issuer) == 0) {
if (ntohl(cp->cert.fstamp) <=
ntohl(xp->cert.fstamp)) {
- *zp = xp->link;;
- cert_free(xp);
- } else {
cert_free(cp);
- return (XEVNT_FSP);
+ cp = xp;
+ } else {
+ *zp = xp->link;
+ cert_free(xp);
+ xp = NULL;
}
break;
}
zp = &xp->link;
}
- yp->link = cinfo;
- cinfo = yp;
+ if (xp == NULL) {
+ cp->link = cinfo;
+ cinfo = cp;
+ }
+ cp->flags |= CERT_VALID;
+ crypto_update();
+ return (cp);
+}
+
+
+/*
+ * cert_hike - verify the signature using the issuer public key
+ *
+ * Returns
+ * XEVNT_OK success
+ * XEVNT_CRT bad or missing certificate
+ * XEVNT_PER host certificate expired
+ * XEVNT_VFY certificate not verified
+ */
+int
+cert_hike(
+ struct peer *peer, /* peer structure pointer */
+ struct cert_info *yp /* issuer certificate */
+ )
+{
+ struct cert_info *xp; /* subject certificate */
+ X509 *cert; /* X509 certificate */
+ const u_char *ptr;
/*
- * Scan the certificate list to see if Y is signed by X. This is
- * independent of order.
+ * Save the issuer on the new certificate, but remember the old
+ * one.
*/
- for (yp = cinfo; yp != NULL; yp = yp->link) {
- for (xp = cinfo; xp != NULL; xp = xp->link) {
+ if (peer->issuer != NULL)
+ free(peer->issuer);
+ peer->issuer = estrdup(yp->issuer);
+ xp = peer->xinfo;
+ peer->xinfo = yp;
- /*
- * If the issuer of certificate Y matches the
- * subject of certificate X, verify the
- * signature of Y using the public key of X. If
- * so, X signs Y.
- */
- if (strcmp(yp->issuer, xp->subject) != 0 ||
- xp->flags & CERT_ERROR)
- continue;
+ /*
+ * If subject Y matches issuer Y, then the certificate trail is
+ * complete. If Y is not trusted, the server certificate has yet
+ * been signed, so keep trying. Otherwise, save the group key
+ * and light the valid bit. If the host certificate is trusted,
+ * do not execute a sign exchange. If no identity scheme is in
+ * use, light the identity and proventic bits.
+ */
+ if (strcmp(yp->subject, yp->issuer) == 0) {
+ if (!(yp->flags & CERT_TRUST))
+ return (XEVNT_OK);
- if (cert_valid(yp, xp->pkey) != XEVNT_OK) {
- yp->flags |= CERT_ERROR;
- continue;
- }
+ /*
+ * If the server has an an identity scheme, fetch the
+ * identity credentials. If not, the identity is
+ * verified only by the trusted certificate. The next
+ * signature will set the server proventic.
+ */
+ peer->crypto |= CRYPTO_FLAG_CERT;
+ peer->grpkey = yp->grpkey;
+ if (peer->ident == NULL || !(peer->crypto &
+ CRYPTO_FLAG_MASK))
+ peer->crypto |= CRYPTO_FLAG_VRFY;
+ }
- /*
- * The signature Y is valid only if it begins
- * during the lifetime of X; however, it is not
- * necessarily an error, since some other
- * certificate might sign Y.
- */
- if (yp->first < xp->first || yp->first >
- xp->last)
- continue;
+ /*
+ * If X exists, verify signature X using public key Y.
+ */
+ if (xp == NULL)
+ return (XEVNT_OK);
- yp->flags |= CERT_SIGN;
+ ptr = (u_char *)xp->cert.ptr;
+ cert = d2i_X509(NULL, &ptr, ntohl(xp->cert.vallen));
+ if (cert == NULL) {
+ xp->flags |= CERT_ERROR;
+ return (XEVNT_CRT);
+ }
+ if (X509_verify(cert, yp->pkey) <= 0) {
+ X509_free(cert);
+ xp->flags |= CERT_ERROR;
+ return (XEVNT_VFY);
+ }
+ X509_free(cert);
- /*
- * If X is trusted, then Y is trusted. Note that
- * we might stumble over a self-signed
- * certificate that is not trusted, at least
- * temporarily. This can happen when a dude
- * first comes up, but has not synchronized the
- * clock and had its certificate signed by its
- * server. In case of broken certificate trail,
- * this might result in a loop that could
- * persist until timeout.
- */
- if (!(xp->flags & (CERT_TRUST | CERT_VALID)))
- continue;
+ /*
+ * Signature X is valid only if it begins during the
+ * lifetime of Y.
+ */
+ if ((calcomp(&(xp->first), &(yp->first)) < 0)
+ || (calcomp(&(xp->first), &(yp->last)) > 0)) {
+ xp->flags |= CERT_ERROR;
+ return (XEVNT_PER);
+ }
+ xp->flags |= CERT_SIGN;
+ return (XEVNT_OK);
+}
- yp->flags |= CERT_VALID;
- /*
- * If subject Y matches the server subject name,
- * then Y has completed the certificate trail.
- * Save the group key and light the valid bit.
- */
- if (strcmp(yp->subject, peer->subject) != 0)
- continue;
+/*
+ * cert_parse - parse x509 certificate and create info/value structures.
+ *
+ * The server certificate includes the version number, issuer name,
+ * subject name, public key and valid date interval. If the issuer name
+ * is the same as the subject name, the certificate is self signed and
+ * valid only if the server is configured as trustable. If the names are
+ * different, another issuer has signed the server certificate and
+ * vouched for it. In this case the server certificate is valid if
+ * verified by the issuer public key.
+ *
+ * Returns certificate info/value pointer if valid, NULL if not.
+ */
+struct cert_info * /* certificate information structure */
+cert_parse(
+ const u_char *asn1cert, /* X509 certificate */
+ long len, /* certificate length */
+ tstamp_t fstamp /* filestamp */
+ )
+{
+ X509 *cert; /* X509 certificate */
+ X509_EXTENSION *ext; /* X509v3 extension */
+ struct cert_info *ret; /* certificate info/value */
+ BIO *bp;
+ char pathbuf[MAXFILENAME];
+ const u_char *ptr;
+ char *pch;
+ int temp, cnt, i;
+ struct calendar fscal;
- if (yp->grpkey != NULL) {
- if (peer->grpkey != NULL)
- BN_free(peer->grpkey);
- peer->grpkey = BN_bin2bn(yp->grpkey,
- yp->grplen, NULL);
- }
- peer->crypto |= CRYPTO_FLAG_VALID;
+ /*
+ * Decode ASN.1 objects and construct certificate structure.
+ */
+ ptr = asn1cert;
+ if ((cert = d2i_X509(NULL, &ptr, len)) == NULL) {
+ msyslog(LOG_ERR, "cert_parse: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return (NULL);
+ }
+#ifdef DEBUG
+ if (debug > 1)
+ X509_print_fp(stdout, cert);
+#endif
- /*
- * If the server has an an identity scheme,
- * fetch the identity credentials. If not, the
- * identity is verified only by the trusted
- * certificate. The next signature will set the
- * server proventic.
- */
- if (peer->crypto & (CRYPTO_FLAG_GQ |
- CRYPTO_FLAG_IFF | CRYPTO_FLAG_MV))
- continue;
+ /*
+ * Extract version, subject name and public key.
+ */
+ ret = emalloc_zero(sizeof(*ret));
+ if ((ret->pkey = X509_get_pubkey(cert)) == NULL) {
+ msyslog(LOG_ERR, "cert_parse: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ cert_free(ret);
+ X509_free(cert);
+ return (NULL);
+ }
+ ret->version = X509_get_version(cert);
+ X509_NAME_oneline(X509_get_subject_name(cert), pathbuf,
+ sizeof(pathbuf));
+ pch = strstr(pathbuf, "CN=");
+ if (NULL == pch) {
+ msyslog(LOG_NOTICE, "cert_parse: invalid subject %s",
+ pathbuf);
+ cert_free(ret);
+ X509_free(cert);
+ return (NULL);
+ }
+ ret->subject = estrdup(pch + 3);
- peer->crypto |= CRYPTO_FLAG_VRFY;
+ /*
+ * Extract remaining objects. Note that the NTP serial number is
+ * the NTP seconds at the time of signing, but this might not be
+ * the case for other authority. We don't bother to check the
+ * objects at this time, since the real crunch can happen only
+ * when the time is valid but not yet certificated.
+ */
+ ret->nid = OBJ_obj2nid(cert->cert_info->signature->algorithm);
+ ret->digest = (const EVP_MD *)EVP_get_digestbynid(ret->nid);
+ ret->serial =
+ (u_long)ASN1_INTEGER_get(X509_get_serialNumber(cert));
+ X509_NAME_oneline(X509_get_issuer_name(cert), pathbuf,
+ sizeof(pathbuf));
+ if ((pch = strstr(pathbuf, "CN=")) == NULL) {
+ msyslog(LOG_NOTICE, "cert_parse: invalid issuer %s",
+ pathbuf);
+ cert_free(ret);
+ X509_free(cert);
+ return (NULL);
+ }
+ ret->issuer = estrdup(pch + 3);
+ asn_to_calendar(X509_get_notBefore(cert), &(ret->first));
+ asn_to_calendar(X509_get_notAfter(cert), &(ret->last));
+
+ /*
+ * Extract extension fields. These are ad hoc ripoffs of
+ * currently assigned functions and will certainly be changed
+ * before prime time.
+ */
+ cnt = X509_get_ext_count(cert);
+ for (i = 0; i < cnt; i++) {
+ ext = X509_get_ext(cert, i);
+ temp = OBJ_obj2nid(ext->object);
+ switch (temp) {
+
+ /*
+ * If a key_usage field is present, we decode whether
+ * this is a trusted or private certificate. This is
+ * dorky; all we want is to compare NIDs, but OpenSSL
+ * insists on BIO text strings.
+ */
+ case NID_ext_key_usage:
+ bp = BIO_new(BIO_s_mem());
+ X509V3_EXT_print(bp, ext, 0, 0);
+ BIO_gets(bp, pathbuf, sizeof(pathbuf));
+ BIO_free(bp);
+ if (strcmp(pathbuf, "Trust Root") == 0)
+ ret->flags |= CERT_TRUST;
+ else if (strcmp(pathbuf, "Private") == 0)
+ ret->flags |= CERT_PRIV;
+ DPRINTF(1, ("cert_parse: %s: %s\n",
+ OBJ_nid2ln(temp), pathbuf));
+ break;
+
+ /*
+ * If a NID_subject_key_identifier field is present, it
+ * contains the GQ public key.
+ */
+ case NID_subject_key_identifier:
+ ret->grpkey = BN_bin2bn(&ext->value->data[2],
+ ext->value->length - 2, NULL);
+ /* fall through */
+ default:
+ DPRINTF(1, ("cert_parse: %s\n",
+ OBJ_nid2ln(temp)));
+ break;
+ }
+ }
+ if (strcmp(ret->subject, ret->issuer) == 0) {
+
+ /*
+ * If certificate is self signed, verify signature.
+ */
+ if (X509_verify(cert, ret->pkey) <= 0) {
+ msyslog(LOG_NOTICE,
+ "cert_parse: signature not verified %s",
+ ret->subject);
+ cert_free(ret);
+ X509_free(cert);
+ return (NULL);
+ }
+ } else {
+
+ /*
+ * Check for a certificate loop.
+ */
+ if (strcmp((const char *)hostval.ptr, ret->issuer) == 0) {
+ msyslog(LOG_NOTICE,
+ "cert_parse: certificate trail loop %s",
+ ret->subject);
+ cert_free(ret);
+ X509_free(cert);
+ return (NULL);
}
}
/*
- * That was awesome. Now update the timestamps and signatures.
+ * Verify certificate valid times. Note that certificates cannot
+ * be retroactive.
*/
- crypto_update();
- return (XEVNT_OK);
+ (void)ntpcal_ntp_to_date(&fscal, fstamp, NULL);
+ if ((calcomp(&(ret->first), &(ret->last)) > 0)
+ || (calcomp(&(ret->first), &fscal) < 0)) {
+ msyslog(LOG_NOTICE,
+ "cert_parse: invalid times %s first %u-%02u-%02uT%02u:%02u:%02u last %u-%02u-%02uT%02u:%02u:%02u fstamp %u-%02u-%02uT%02u:%02u:%02u",
+ ret->subject,
+ ret->first.year, ret->first.month, ret->first.monthday,
+ ret->first.hour, ret->first.minute, ret->first.second,
+ ret->last.year, ret->last.month, ret->last.monthday,
+ ret->last.hour, ret->last.minute, ret->last.second,
+ fscal.year, fscal.month, fscal.monthday,
+ fscal.hour, fscal.minute, fscal.second);
+ cert_free(ret);
+ X509_free(cert);
+ return (NULL);
+ }
+
+ /*
+ * Build the value structure to sign and send later.
+ */
+ ret->cert.fstamp = htonl(fstamp);
+ ret->cert.vallen = htonl(len);
+ ret->cert.ptr = emalloc(len);
+ memcpy(ret->cert.ptr, asn1cert, len);
+ X509_free(cert);
+ return (ret);
}
@@ -3571,50 +3537,56 @@ cert_free(
if (cinf->issuer != NULL)
free(cinf->issuer);
if (cinf->grpkey != NULL)
- free(cinf->grpkey);
+ BN_free(cinf->grpkey);
value_free(&cinf->cert);
free(cinf);
}
/*
- ***********************************************************************
- * *
- * The following routines are used only at initialization time *
- * *
- ***********************************************************************
- */
-/*
- * crypto_key - load cryptographic parameters and keys from files
- *
- * This routine loads a PEM-encoded public/private key pair and extracts
- * the filestamp from the file name.
- *
- * Returns public key pointer if valid, NULL if not. Side effect updates
- * the filestamp if valid.
+ * crypto_key - load cryptographic parameters and keys
+ *
+ * This routine searches the key cache for matching name in the form
+ * ntpkey_<key>_<name>, where <key> is one of host, sign, iff, gq, mv,
+ * and <name> is the host/group name. If not found, it tries to load a
+ * PEM-encoded file of the same name and extracts the filestamp from
+ * the first line of the file name. It returns the key pointer if valid,
+ * NULL if not.
*/
-static EVP_PKEY *
+static struct pkey_info *
crypto_key(
char *cp, /* file name */
- tstamp_t *fstamp /* filestamp */
+ char *passwd1, /* password */
+ sockaddr_u *addr /* IP address */
)
{
FILE *str; /* file handle */
+ struct pkey_info *pkp; /* generic key */
EVP_PKEY *pkey = NULL; /* public/private key */
+ tstamp_t fstamp;
char filename[MAXFILENAME]; /* name of key file */
char linkname[MAXFILENAME]; /* filestamp buffer) */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
char *ptr;
/*
+ * Search the key cache for matching key and name.
+ */
+ for (pkp = pkinfo; pkp != NULL; pkp = pkp->link) {
+ if (strcmp(cp, pkp->name) == 0)
+ return (pkp);
+ }
+
+ /*
* Open the key file. If the first character of the file name is
* not '/', prepend the keys directory string. If something goes
* wrong, abandon ship.
*/
if (*cp == '/')
- strcpy(filename, cp);
+ strlcpy(filename, cp, sizeof(filename));
else
- snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp);
+ snprintf(filename, sizeof(filename), "%s/%s", keysdir,
+ cp);
str = fopen(filename, "r");
if (str == NULL)
return (NULL);
@@ -3622,65 +3594,83 @@ crypto_key(
/*
* Read the filestamp, which is contained in the first line.
*/
- if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) {
- msyslog(LOG_ERR, "crypto_key: no data %s\n",
+ if ((ptr = fgets(linkname, sizeof(linkname), str)) == NULL) {
+ msyslog(LOG_ERR, "crypto_key: empty file %s",
filename);
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
if ((ptr = strrchr(ptr, '.')) == NULL) {
- msyslog(LOG_ERR, "crypto_key: no filestamp %s\n",
+ msyslog(LOG_ERR, "crypto_key: no filestamp %s",
filename);
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
- if (sscanf(++ptr, "%u", fstamp) != 1) {
- msyslog(LOG_ERR, "crypto_key: invalid timestamp %s\n",
+ if (sscanf(++ptr, "%u", &fstamp) != 1) {
+ msyslog(LOG_ERR, "crypto_key: invalid filestamp %s",
filename);
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
/*
- * Read and decrypt PEM-encoded private key.
+ * Read and decrypt PEM-encoded private key. If it fails to
+ * decrypt, game over.
*/
- pkey = PEM_read_PrivateKey(str, NULL, NULL, passwd);
+ pkey = PEM_read_PrivateKey(str, NULL, NULL, passwd1);
fclose(str);
if (pkey == NULL) {
- msyslog(LOG_ERR, "crypto_key %s\n",
+ msyslog(LOG_ERR, "crypto_key: %s",
ERR_error_string(ERR_get_error(), NULL));
- return (NULL);
+ exit (-1);
}
/*
+ * Make a new entry in the key cache.
+ */
+ pkp = emalloc(sizeof(struct pkey_info));
+ pkp->link = pkinfo;
+ pkinfo = pkp;
+ pkp->pkey = pkey;
+ pkp->name = estrdup(cp);
+ pkp->fstamp = fstamp;
+
+ /*
* Leave tracks in the cryptostats.
*/
if ((ptr = strrchr(linkname, '\n')) != NULL)
*ptr = '\0';
- snprintf(statstr, NTP_MAXSTRLEN, "%s mod %d", &linkname[2],
+ snprintf(statstr, sizeof(statstr), "%s mod %d", &linkname[2],
EVP_PKEY_size(pkey) * 8);
- record_crypto_stats(NULL, statstr);
+ record_crypto_stats(addr, statstr);
+
+ DPRINTF(1, ("crypto_key: %s\n", statstr));
#ifdef DEBUG
- if (debug)
- printf("crypto_key: %s\n", statstr);
if (debug > 1) {
if (pkey->type == EVP_PKEY_DSA)
DSA_print_fp(stdout, pkey->pkey.dsa, 0);
- else
+ else if (pkey->type == EVP_PKEY_RSA)
RSA_print_fp(stdout, pkey->pkey.rsa, 0);
}
#endif
- return (pkey);
+ return (pkp);
}
/*
+ ***********************************************************************
+ * *
+ * The following routines are used only at initialization time *
+ * *
+ ***********************************************************************
+ */
+/*
* crypto_cert - load certificate from file
*
- * This routine loads a X.509 RSA or DSA certificate from a file and
+ * This routine loads an X.509 RSA or DSA certificate from a file and
* constructs a info/cert value structure for this machine. The
* structure includes a filestamp extracted from the file name. Later
- * the certificate can be sent to another machine by request.
+ * the certificate can be sent to another machine on request.
*
* Returns certificate info/value pointer if valid, NULL if not.
*/
@@ -3706,9 +3696,10 @@ crypto_cert(
* something goes wrong, abandon ship.
*/
if (*cp == '/')
- strcpy(filename, cp);
+ strlcpy(filename, cp, sizeof(filename));
else
- snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp);
+ snprintf(filename, sizeof(filename), "%s/%s", keysdir,
+ cp);
str = fopen(filename, "r");
if (str == NULL)
return (NULL);
@@ -3716,22 +3707,22 @@ crypto_cert(
/*
* Read the filestamp, which is contained in the first line.
*/
- if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) {
- msyslog(LOG_ERR, "crypto_cert: no data %s\n",
+ if ((ptr = fgets(linkname, sizeof(linkname), str)) == NULL) {
+ msyslog(LOG_ERR, "crypto_cert: empty file %s",
filename);
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
if ((ptr = strrchr(ptr, '.')) == NULL) {
- msyslog(LOG_ERR, "crypto_cert: no filestamp %s\n",
+ msyslog(LOG_ERR, "crypto_cert: no filestamp %s",
filename);
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
if (sscanf(++ptr, "%u", &fstamp) != 1) {
- msyslog(LOG_ERR, "crypto_cert: invalid filestamp %s\n",
+ msyslog(LOG_ERR, "crypto_cert: invalid filestamp %s",
filename);
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
@@ -3739,266 +3730,144 @@ crypto_cert(
* Read PEM-encoded certificate and install.
*/
if (!PEM_read(str, &name, &header, &data, &len)) {
- msyslog(LOG_ERR, "crypto_cert %s\n",
+ msyslog(LOG_ERR, "crypto_cert: %s",
ERR_error_string(ERR_get_error(), NULL));
- (void)fclose(str);
+ fclose(str);
return (NULL);
}
+ fclose(str);
free(header);
- if (strcmp(name, "CERTIFICATE") !=0) {
- msyslog(LOG_INFO, "crypto_cert: wrong PEM type %s",
+ if (strcmp(name, "CERTIFICATE") != 0) {
+ msyslog(LOG_NOTICE, "crypto_cert: wrong PEM type %s",
name);
free(name);
free(data);
- (void)fclose(str);
return (NULL);
}
free(name);
/*
- * Parse certificate and generate info/value structure.
+ * Parse certificate and generate info/value structure. The
+ * pointer and copy nonsense is due something broken in Solaris.
*/
ret = cert_parse(data, len, fstamp);
free(data);
- (void)fclose(str);
if (ret == NULL)
return (NULL);
if ((ptr = strrchr(linkname, '\n')) != NULL)
*ptr = '\0';
- snprintf(statstr, NTP_MAXSTRLEN,
- "%s 0x%x len %lu", &linkname[2], ret->flags, len);
+ snprintf(statstr, sizeof(statstr), "%s 0x%x len %lu",
+ &linkname[2], ret->flags, len);
record_crypto_stats(NULL, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_cert: %s\n", statstr);
-#endif
+ DPRINTF(1, ("crypto_cert: %s\n", statstr));
return (ret);
}
/*
- * crypto_tai - load leapseconds table from file
- *
- * This routine loads the ERTS leapsecond file in NIST text format,
- * converts to a value structure and extracts a filestamp from the file
- * name. The data are used to establish the TAI offset from UTC, which
- * is provided to the kernel if supported. Later the data can be sent to
- * another machine on request.
- */
-static void
-crypto_tai(
- char *cp /* file name */
- )
-{
- FILE *str; /* file handle */
- char buf[NTP_MAXSTRLEN]; /* file line buffer */
- u_int32 leapsec[MAX_LEAP]; /* NTP time at leaps */
- int offset; /* offset at leap (s) */
- char filename[MAXFILENAME]; /* name of leapseconds file */
- char linkname[MAXFILENAME]; /* file link (for filestamp) */
- char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
- tstamp_t fstamp; /* filestamp */
- u_int len;
- u_int32 *ptr;
- char *dp;
- int rval, i, j;
-
- /*
- * Open the file and discard comment lines. If the first
- * character of the file name is not '/', prepend the keys
- * directory string. If the file is not found, not to worry; it
- * can be retrieved over the net. But, if it is found with
- * errors, we crash and burn.
- */
- if (*cp == '/')
- strcpy(filename, cp);
- else
- snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp);
- if ((str = fopen(filename, "r")) == NULL)
- return;
-
- /*
- * Extract filestamp if present.
- */
- rval = readlink(filename, linkname, MAXFILENAME - 1);
- if (rval > 0) {
- linkname[rval] = '\0';
- dp = strrchr(linkname, '.');
- } else {
- dp = strrchr(filename, '.');
- }
- if (dp != NULL)
- sscanf(++dp, "%u", &fstamp);
- else
- fstamp = 0;
- tai_leap.fstamp = htonl(fstamp);
-
- /*
- * We are rather paranoid here, since an intruder might cause a
- * coredump by infiltrating naughty values. Empty lines and
- * comments are ignored. Other lines must begin with two
- * integers followed by junk or comments. The first integer is
- * the NTP seconds of leap insertion, the second is the offset
- * of TAI relative to UTC after that insertion. The second word
- * must equal the initial insertion of ten seconds on 1 January
- * 1972 plus one second for each succeeding insertion.
- */
- i = 0;
- while (i < MAX_LEAP) {
- dp = fgets(buf, NTP_MAXSTRLEN - 1, str);
- if (dp == NULL)
- break;
-
- if (strlen(buf) < 1)
- continue;
-
- if (*buf == '#')
- continue;
-
- if (sscanf(buf, "%u %d", &leapsec[i], &offset) != 2)
- continue;
-
- if (i != offset - TAI_1972)
- break;
-
- i++;
- }
- fclose(str);
- if (dp != NULL) {
- msyslog(LOG_INFO,
- "crypto_tai: leapseconds file %s error %d", cp,
- rval);
- exit (-1);
- }
-
- /*
- * The extension field table entries consists of the NTP seconds
- * of leap insertion in network byte order.
- */
- len = i * sizeof(u_int32);
- tai_leap.vallen = htonl(len);
- ptr = emalloc(len);
- tai_leap.ptr = (u_char *)ptr;
- for (j = 0; j < i; j++)
- *ptr++ = htonl(leapsec[j]);
- crypto_flags |= CRYPTO_FLAG_TAI;
- snprintf(statstr, NTP_MAXSTRLEN, "%s fs %u leap %u len %u", cp, fstamp,
- leapsec[--j], len);
- record_crypto_stats(NULL, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_tai: %s\n", statstr);
-#endif
-}
-
-
-/*
- * crypto_setup - load keys, certificate and leapseconds table
+ * crypto_setup - load keys, certificate and identity parameters
*
* This routine loads the public/private host key and certificate. If
* available, it loads the public/private sign key, which defaults to
- * the host key, and leapseconds table. The host key must be RSA, but
- * the sign key can be either RSA or DSA. In either case, the public key
- * on the certificate must agree with the sign key.
+ * the host key. The host key must be RSA, but the sign key can be
+ * either RSA or DSA. If a trusted certificate, it loads the identity
+ * parameters. In either case, the public key on the certificate must
+ * agree with the sign key.
+ *
+ * Required but missing files and inconsistent data and errors are
+ * fatal. Allowing configuration to continue would be hazardous and
+ * require really messy error checks.
*/
void
crypto_setup(void)
{
- EVP_PKEY *pkey; /* private/public key pair */
+ struct pkey_info *pinfo; /* private/public key */
char filename[MAXFILENAME]; /* file name buffer */
+ char hostname[MAXFILENAME]; /* host name buffer */
+ char *randfile;
+ char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
l_fp seed; /* crypto PRNG seed as NTP timestamp */
- tstamp_t fstamp; /* filestamp */
- tstamp_t sstamp; /* sign filestamp */
- u_int len, bytes;
+ u_int len;
+ int bytes;
u_char *ptr;
/*
- * Initialize structures.
+ * Check for correct OpenSSL version and avoid initialization in
+ * the case of multiple crypto commands.
*/
- if (!crypto_flags)
+ if (crypto_flags & CRYPTO_FLAG_ENAB) {
+ msyslog(LOG_NOTICE,
+ "crypto_setup: spurious crypto command");
return;
-
- gethostname(filename, MAXFILENAME);
- bytes = strlen(filename) + 1;
- sys_hostname = emalloc(bytes);
- memcpy(sys_hostname, filename, bytes);
- if (passwd == NULL)
- passwd = sys_hostname;
- memset(&hostval, 0, sizeof(hostval));
- memset(&pubkey, 0, sizeof(pubkey));
- memset(&tai_leap, 0, sizeof(tai_leap));
+ }
+ ssl_check_version();
/*
* Load required random seed file and seed the random number
- * generator. Be default, it is found in the user home
+ * generator. Be default, it is found as .rnd in the user home
* directory. The root home directory may be / or /root,
* depending on the system. Wiggle the contents a bit and write
* it back so the sequence does not repeat when we next restart.
*/
- ERR_load_crypto_strings();
- if (rand_file == NULL) {
- if ((RAND_file_name(filename, MAXFILENAME)) != NULL) {
- rand_file = emalloc(strlen(filename) + 1);
- strcpy(rand_file, filename);
+ if (!RAND_status()) {
+ if (rand_file == NULL) {
+ RAND_file_name(filename, sizeof(filename));
+ randfile = filename;
+ } else if (*rand_file != '/') {
+ snprintf(filename, sizeof(filename), "%s/%s",
+ keysdir, rand_file);
+ randfile = filename;
+ } else
+ randfile = rand_file;
+
+ if ((bytes = RAND_load_file(randfile, -1)) == 0) {
+ msyslog(LOG_ERR,
+ "crypto_setup: random seed file %s missing",
+ randfile);
+ exit (-1);
}
- } else if (*rand_file != '/') {
- snprintf(filename, MAXFILENAME, "%s/%s", keysdir,
- rand_file);
- free(rand_file);
- rand_file = emalloc(strlen(filename) + 1);
- strcpy(rand_file, filename);
+ arc4random_buf(&seed, sizeof(l_fp));
+ RAND_seed(&seed, sizeof(l_fp));
+ RAND_write_file(randfile);
+ DPRINTF(1, ("crypto_setup: OpenSSL version %lx random seed file %s bytes read %d\n",
+ SSLeay(), randfile, bytes));
}
- if (rand_file == NULL) {
- msyslog(LOG_ERR,
- "crypto_setup: random seed file not specified");
- exit (-1);
- }
- if ((bytes = RAND_load_file(rand_file, -1)) == 0) {
- msyslog(LOG_ERR,
- "crypto_setup: random seed file %s not found\n",
- rand_file);
- exit (-1);
- }
- arc4random_buf(&seed, sizeof(l_fp));
- RAND_seed(&seed, sizeof(l_fp));
- RAND_write_file(rand_file);
- OpenSSL_add_all_algorithms();
-#ifdef DEBUG
- if (debug)
- printf(
- "crypto_setup: OpenSSL version %lx random seed file %s bytes read %d\n",
- SSLeay(), rand_file, bytes);
-#endif
/*
- * Load required host key from file "ntpkey_host_<hostname>". It
- * also becomes the default sign key.
+ * Initialize structures.
*/
- if (host_file == NULL) {
- snprintf(filename, MAXFILENAME, "ntpkey_host_%s",
- sys_hostname);
- host_file = emalloc(strlen(filename) + 1);
- strcpy(host_file, filename);
- }
- pkey = crypto_key(host_file, &fstamp);
- if (pkey == NULL) {
+ gethostname(hostname, sizeof(hostname));
+ if (host_filename != NULL)
+ strlcpy(hostname, host_filename, sizeof(hostname));
+ if (passwd == NULL)
+ passwd = estrdup(hostname);
+ memset(&hostval, 0, sizeof(hostval));
+ memset(&pubkey, 0, sizeof(pubkey));
+ memset(&tai_leap, 0, sizeof(tai_leap));
+
+ /*
+ * Load required host key from file "ntpkey_host_<hostname>". If
+ * no host key file is not found or has invalid password, life
+ * as we know it ends. The host key also becomes the default
+ * sign key.
+ */
+ snprintf(filename, sizeof(filename), "ntpkey_host_%s", hostname);
+ pinfo = crypto_key(filename, passwd, NULL);
+ if (pinfo == NULL) {
msyslog(LOG_ERR,
"crypto_setup: host key file %s not found or corrupt",
- host_file);
+ filename);
exit (-1);
}
- host_pkey = pkey;
- sign_pkey = pkey;
- sstamp = fstamp;
- hostval.fstamp = htonl(fstamp);
- if (host_pkey->type != EVP_PKEY_RSA) {
+ if (pinfo->pkey->type != EVP_PKEY_RSA) {
msyslog(LOG_ERR,
"crypto_setup: host key is not RSA key type");
exit (-1);
}
- hostval.vallen = htonl(strlen(sys_hostname));
- hostval.ptr = (u_char *)sys_hostname;
+ host_pkey = pinfo->pkey;
+ sign_pkey = host_pkey;
+ hostval.fstamp = htonl(pinfo->fstamp);
/*
* Construct public key extension field for agreement scheme.
@@ -4007,229 +3876,158 @@ crypto_setup(void)
ptr = emalloc(len);
pubkey.ptr = ptr;
i2d_PublicKey(host_pkey, &ptr);
- pubkey.vallen = htonl(len);
pubkey.fstamp = hostval.fstamp;
+ pubkey.vallen = htonl(len);
/*
* Load optional sign key from file "ntpkey_sign_<hostname>". If
- * loaded, it becomes the sign key.
+ * available, it becomes the sign key.
*/
- if (sign_file == NULL) {
- snprintf(filename, MAXFILENAME, "ntpkey_sign_%s",
- sys_hostname);
- sign_file = emalloc(strlen(filename) + 1);
- strcpy(sign_file, filename);
- }
- pkey = crypto_key(sign_file, &fstamp);
- if (pkey != NULL) {
- sign_pkey = pkey;
- sstamp = fstamp;
- }
- sign_siglen = EVP_PKEY_size(sign_pkey);
+ snprintf(filename, sizeof(filename), "ntpkey_sign_%s", hostname);
+ pinfo = crypto_key(filename, passwd, NULL);
+ if (pinfo != NULL)
+ sign_pkey = pinfo->pkey;
/*
- * Load optional IFF parameters from file
- * "ntpkey_iff_<hostname>".
- */
- if (iffpar_file == NULL) {
- snprintf(filename, MAXFILENAME, "ntpkey_iff_%s",
- sys_hostname);
- iffpar_file = emalloc(strlen(filename) + 1);
- strcpy(iffpar_file, filename);
- }
- iffpar_pkey = crypto_key(iffpar_file, &if_fstamp);
- if (iffpar_pkey != NULL)
- crypto_flags |= CRYPTO_FLAG_IFF;
-
- /*
- * Load optional GQ parameters from file "ntpkey_gq_<hostname>".
+ * Load required certificate from file "ntpkey_cert_<hostname>".
*/
- if (gqpar_file == NULL) {
- snprintf(filename, MAXFILENAME, "ntpkey_gq_%s",
- sys_hostname);
- gqpar_file = emalloc(strlen(filename) + 1);
- strcpy(gqpar_file, filename);
+ snprintf(filename, sizeof(filename), "ntpkey_cert_%s", hostname);
+ cinfo = crypto_cert(filename);
+ if (cinfo == NULL) {
+ msyslog(LOG_ERR,
+ "crypto_setup: certificate file %s not found or corrupt",
+ filename);
+ exit (-1);
}
- gqpar_pkey = crypto_key(gqpar_file, &gq_fstamp);
- if (gqpar_pkey != NULL)
- crypto_flags |= CRYPTO_FLAG_GQ;
+ cert_host = cinfo;
+ sign_digest = cinfo->digest;
+ sign_siglen = EVP_PKEY_size(sign_pkey);
+ if (cinfo->flags & CERT_PRIV)
+ crypto_flags |= CRYPTO_FLAG_PRIV;
/*
- * Load optional MV parameters from file "ntpkey_mv_<hostname>".
+ * The certificate must be self-signed.
*/
- if (mvpar_file == NULL) {
- snprintf(filename, MAXFILENAME, "ntpkey_mv_%s",
- sys_hostname);
- mvpar_file = emalloc(strlen(filename) + 1);
- strcpy(mvpar_file, filename);
+ if (strcmp(cinfo->subject, cinfo->issuer) != 0) {
+ msyslog(LOG_ERR,
+ "crypto_setup: certificate %s is not self-signed",
+ filename);
+ exit (-1);
}
- mvpar_pkey = crypto_key(mvpar_file, &mv_fstamp);
- if (mvpar_pkey != NULL)
- crypto_flags |= CRYPTO_FLAG_MV;
+ hostval.ptr = estrdup(cinfo->subject);
+ hostval.vallen = htonl(strlen(cinfo->subject));
+ sys_hostname = hostval.ptr;
+ ptr = (u_char *)strchr(sys_hostname, '@');
+ if (ptr != NULL)
+ sys_groupname = estrdup((char *)++ptr);
+ if (ident_filename != NULL)
+ strlcpy(hostname, ident_filename, sizeof(hostname));
/*
- * Load required certificate from file "ntpkey_cert_<hostname>".
+ * Load optional IFF parameters from file
+ * "ntpkey_iffkey_<hostname>".
*/
- if (cert_file == NULL) {
- snprintf(filename, MAXFILENAME, "ntpkey_cert_%s",
- sys_hostname);
- cert_file = emalloc(strlen(filename) + 1);
- strcpy(cert_file, filename);
- }
- if ((cinfo = crypto_cert(cert_file)) == NULL) {
- msyslog(LOG_ERR,
- "certificate file %s not found or corrupt",
- cert_file);
- exit (-1);
- }
+ snprintf(filename, sizeof(filename), "ntpkey_iffkey_%s",
+ hostname);
+ iffkey_info = crypto_key(filename, passwd, NULL);
+ if (iffkey_info != NULL)
+ crypto_flags |= CRYPTO_FLAG_IFF;
/*
- * The subject name must be the same as the host name, unless
- * the certificate is private, in which case it may have come
- * from another host.
+ * Load optional GQ parameters from file
+ * "ntpkey_gqkey_<hostname>".
*/
- if (!(cinfo->flags & CERT_PRIV) && strcmp(cinfo->subject,
- sys_hostname) != 0) {
- msyslog(LOG_ERR,
- "crypto_setup: certificate %s not for this host",
- cert_file);
- cert_free(cinfo);
- exit (-1);
- }
+ snprintf(filename, sizeof(filename), "ntpkey_gqkey_%s",
+ hostname);
+ gqkey_info = crypto_key(filename, passwd, NULL);
+ if (gqkey_info != NULL)
+ crypto_flags |= CRYPTO_FLAG_GQ;
/*
- * It the certificate is trusted, the subject must be the same
- * as the issuer, in other words it must be self signed.
+ * Load optional MV parameters from file
+ * "ntpkey_mvkey_<hostname>".
*/
- if (cinfo->flags & CERT_TRUST && strcmp(cinfo->subject,
- cinfo->issuer) != 0) {
- if (cert_valid(cinfo, sign_pkey) != XEVNT_OK) {
- msyslog(LOG_ERR,
- "crypto_setup: certificate %s is trusted, but not self signed.",
- cert_file);
- cert_free(cinfo);
- exit (-1);
- }
- }
- sign_digest = cinfo->digest;
- if (cinfo->flags & CERT_PRIV)
- crypto_flags |= CRYPTO_FLAG_PRIV;
- crypto_flags |= cinfo->nid << 16;
+ snprintf(filename, sizeof(filename), "ntpkey_mvkey_%s",
+ hostname);
+ mvkey_info = crypto_key(filename, passwd, NULL);
+ if (mvkey_info != NULL)
+ crypto_flags |= CRYPTO_FLAG_MV;
/*
- * Load optional leapseconds table from file "ntpkey_leap". If
- * the file is missing or defective, the values can later be
- * retrieved from a server.
+ * We met the enemy and he is us. Now strike up the dance.
*/
- if (leap_file == NULL)
- leap_file = "ntpkey_leap";
- crypto_tai(leap_file);
-#ifdef DEBUG
- if (debug)
- printf(
- "crypto_setup: flags 0x%x host %s signature %s\n",
- crypto_flags, sys_hostname, OBJ_nid2ln(cinfo->nid));
-#endif
+ crypto_flags |= CRYPTO_FLAG_ENAB | (cinfo->nid << 16);
+ snprintf(statstr, sizeof(statstr), "setup 0x%x host %s %s",
+ crypto_flags, hostname, OBJ_nid2ln(cinfo->nid));
+ record_crypto_stats(NULL, statstr);
+ DPRINTF(1, ("crypto_setup: %s\n", statstr));
}
/*
- * crypto_config - configure data from crypto configuration command.
+ * crypto_config - configure data from the crypto command.
*/
void
crypto_config(
int item, /* configuration item */
- char *cp /* file name */
+ char *cp /* item name */
)
{
- switch (item) {
+ int nid;
- /*
- * Set random seed file name.
- */
- case CRYPTO_CONF_RAND:
- rand_file = emalloc(strlen(cp) + 1);
- strcpy(rand_file, cp);
- break;
+ DPRINTF(1, ("crypto_config: item %d %s\n", item, cp));
- /*
- * Set private key password.
- */
- case CRYPTO_CONF_PW:
- passwd = emalloc(strlen(cp) + 1);
- strcpy(passwd, cp);
- break;
+ switch (item) {
/*
- * Set host file name.
+ * Set host name (host).
*/
case CRYPTO_CONF_PRIV:
- host_file = emalloc(strlen(cp) + 1);
- strcpy(host_file, cp);
+ if (NULL != host_filename)
+ free(host_filename);
+ host_filename = estrdup(cp);
break;
/*
- * Set sign key file name.
+ * Set group name (ident).
*/
- case CRYPTO_CONF_SIGN:
- sign_file = emalloc(strlen(cp) + 1);
- strcpy(sign_file, cp);
- break;
-
- /*
- * Set iff parameters file name.
- */
- case CRYPTO_CONF_IFFPAR:
- iffpar_file = emalloc(strlen(cp) + 1);
- strcpy(iffpar_file, cp);
- break;
-
- /*
- * Set gq parameters file name.
- */
- case CRYPTO_CONF_GQPAR:
- gqpar_file = emalloc(strlen(cp) + 1);
- strcpy(gqpar_file, cp);
- break;
-
- /*
- * Set mv parameters file name.
- */
- case CRYPTO_CONF_MVPAR:
- mvpar_file = emalloc(strlen(cp) + 1);
- strcpy(mvpar_file, cp);
+ case CRYPTO_CONF_IDENT:
+ if (NULL != ident_filename)
+ free(ident_filename);
+ ident_filename = estrdup(cp);
break;
/*
- * Set identity scheme.
+ * Set private key password (pw).
*/
- case CRYPTO_CONF_IDENT:
- if (!strcasecmp(cp, "iff"))
- ident_scheme |= CRYPTO_FLAG_IFF;
- else if (!strcasecmp(cp, "gq"))
- ident_scheme |= CRYPTO_FLAG_GQ;
- else if (!strcasecmp(cp, "mv"))
- ident_scheme |= CRYPTO_FLAG_MV;
+ case CRYPTO_CONF_PW:
+ if (NULL != passwd)
+ free(passwd);
+ passwd = estrdup(cp);
break;
/*
- * Set certificate file name.
+ * Set random seed file name (randfile).
*/
- case CRYPTO_CONF_CERT:
- cert_file = emalloc(strlen(cp) + 1);
- strcpy(cert_file, cp);
+ case CRYPTO_CONF_RAND:
+ if (NULL != rand_file)
+ free(rand_file);
+ rand_file = estrdup(cp);
break;
/*
- * Set leapseconds file name.
+ * Set message digest NID.
*/
- case CRYPTO_CONF_LEAP:
- leap_file = emalloc(strlen(cp) + 1);
- strcpy(leap_file, cp);
+ case CRYPTO_CONF_NID:
+ nid = OBJ_sn2nid(cp);
+ if (nid == 0)
+ msyslog(LOG_ERR,
+ "crypto_config: invalid digest name %s", cp);
+ else
+ crypto_nid = nid;
break;
}
- crypto_flags |= CRYPTO_FLAG_ENAB;
}
-# else
+# else /* !AUTOKEY follows */
int ntp_crypto_bs_pubkey;
-# endif /* OPENSSL */
+# endif /* !AUTOKEY */
diff --git a/contrib/ntp/ntpd/ntp_filegen.c b/contrib/ntp/ntpd/ntp_filegen.c
index 932d1b6..4ee9095 100644
--- a/contrib/ntp/ntpd/ntp_filegen.c
+++ b/contrib/ntp/ntpd/ntp_filegen.c
@@ -6,7 +6,7 @@
*
*
* Copyright (C) 1992, 1996 by Rainer Pruy
- * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
+ * Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
*
* This code may be modified and used freely
* provided credits remain intact.
@@ -44,34 +44,48 @@
*/
#define SUFFIX_SEP '.'
+static void filegen_open (FILEGEN *, u_int32, const time_t*);
+static int valid_fileref (const char *, const char *);
+static void filegen_init (const char *, const char *, FILEGEN *);
+#ifdef DEBUG
+static void filegen_uninit (FILEGEN *);
+#endif /* DEBUG */
+
+
/*
- * other constants
+ * filegen_init
*/
-#define FGEN_AGE_SECS (24*60*60) /* life time of FILEGEN_AGE in seconds */
-static void filegen_open P((FILEGEN *, u_long));
-static int valid_fileref P((char *, char *));
-#ifdef UNUSED
-static FILEGEN *filegen_unregister P((char *));
-#endif /* UNUSED */
+static void
+filegen_init(
+ const char * dir,
+ const char * fname,
+ FILEGEN * fgp
+ )
+{
+ fgp->fp = NULL;
+ fgp->dir = estrdup(dir);
+ fgp->fname = estrdup(fname);
+ fgp->id_lo = 0;
+ fgp->id_hi = 0;
+ fgp->type = FILEGEN_DAY;
+ fgp->flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
+}
-static void filegen_init P((char *, const char *, FILEGEN *));
/*
- * filegen_init
+ * filegen_uninit - free memory allocated by filegen_init
*/
-
+#ifdef DEBUG
static void
-filegen_init(char *prefix, const char *basename, FILEGEN *fp)
+filegen_uninit(
+ FILEGEN *fgp
+ )
{
- fp->fp = NULL;
- fp->prefix = prefix; /* Yes, this is TOTALLY lame! */
- fp->basename = (char*)emalloc(strlen(basename) + 1);
- strcpy(fp->basename, basename);
- fp->id = 0;
- fp->type = FILEGEN_DAY;
- fp->flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
+ free(fgp->dir);
+ free(fgp->fname);
}
+#endif
/*
@@ -81,81 +95,117 @@ filegen_init(char *prefix, const char *basename, FILEGEN *fp)
static void
filegen_open(
- FILEGEN *gen,
- u_long newid
+ FILEGEN * gen,
+ u_int32 stamp,
+ const time_t * pivot
)
{
- char *filename;
- char *basename;
- u_int len;
+ char *savename; /* temp store for name collision handling */
+ char *fullname; /* name with any designation extension */
+ char *filename; /* name without designation extension */
+ char *suffix; /* where to print suffix extension */
+ u_int len, suflen;
FILE *fp;
struct calendar cal;
+ struct isodate iso;
- len = strlen(gen->prefix) + strlen(gen->basename) + 1;
- basename = (char*)emalloc(len);
- sprintf(basename, "%s%s", gen->prefix, gen->basename);
-
- switch(gen->type) {
- default:
- msyslog(LOG_ERR, "unsupported file generations type %d for \"%s\" - reverting to FILEGEN_NONE",
- gen->type, basename);
+ /* get basic filename in buffer, leave room for extensions */
+ len = strlen(gen->dir) + strlen(gen->fname) + 65;
+ filename = emalloc(len);
+ fullname = emalloc(len);
+ savename = NULL;
+ snprintf(filename, len, "%s%s", gen->dir, gen->fname);
+
+ /* where to place suffix */
+ suflen = strlcpy(fullname, filename, len);
+ suffix = fullname + suflen;
+ suflen = len - suflen;
+
+ /* last octet of fullname set to '\0' for truncation check */
+ fullname[len - 1] = '\0';
+
+ switch (gen->type) {
+
+ default:
+ msyslog(LOG_ERR,
+ "unsupported file generations type %d for "
+ "\"%s\" - reverting to FILEGEN_NONE",
+ gen->type, filename);
gen->type = FILEGEN_NONE;
-
- /*FALLTHROUGH*/
- case FILEGEN_NONE:
- filename = (char*)emalloc(len);
- sprintf(filename,"%s", basename);
break;
- case FILEGEN_PID:
- filename = (char*)emalloc(len + 1 + 1 + 10);
- sprintf(filename,"%s%c#%ld", basename, SUFFIX_SEP, newid);
+ case FILEGEN_NONE:
+ /* no suffix, all set */
break;
-
- case FILEGEN_DAY:
- /* You can argue here in favor of using MJD, but
- * I would assume it to be easier for humans to interpret dates
- * in a format they are used to in everyday life.
- */
- caljulian(newid,&cal);
- filename = (char*)emalloc(len + 1 + 4 + 2 + 2);
- sprintf(filename, "%s%c%04d%02d%02d",
- basename, SUFFIX_SEP, cal.year, cal.month, cal.monthday);
+
+ case FILEGEN_PID:
+ gen->id_lo = getpid();
+ gen->id_hi = 0;
+ snprintf(suffix, suflen, "%c#%ld",
+ SUFFIX_SEP, gen->id_lo);
break;
-
- case FILEGEN_WEEK:
+
+ case FILEGEN_DAY:
/*
- * This is still a hack
- * - the term week is not correlated to week as it is used
- * normally - it just refers to a period of 7 days
- * starting at Jan 1 - 'weeks' are counted starting from zero
+ * You can argue here in favor of using MJD, but I
+ * would assume it to be easier for humans to interpret
+ * dates in a format they are used to in everyday life.
*/
- caljulian(newid,&cal);
- filename = (char*)emalloc(len + 1 + 4 + 1 + 2);
- sprintf(filename, "%s%c%04dw%02d",
- basename, SUFFIX_SEP, cal.year, cal.yearday / 7);
+ ntpcal_ntp_to_date(&cal, stamp, pivot);
+ snprintf(suffix, suflen, "%c%04d%02d%02d",
+ SUFFIX_SEP, cal.year, cal.month, cal.monthday);
+ cal.hour = cal.minute = cal.second = 0;
+ gen->id_lo = ntpcal_date_to_ntp(&cal);
+ gen->id_hi = (u_int32)(gen->id_lo + SECSPERDAY);
break;
- case FILEGEN_MONTH:
- caljulian(newid,&cal);
- filename = (char*)emalloc(len + 1 + 4 + 2);
- sprintf(filename, "%s%c%04d%02d",
- basename, SUFFIX_SEP, cal.year, cal.month);
+ case FILEGEN_WEEK:
+ isocal_ntp_to_date(&iso, stamp, pivot);
+ snprintf(suffix, suflen, "%c%04dw%02d",
+ SUFFIX_SEP, iso.year, iso.week);
+ iso.hour = iso.minute = iso.second = 0;
+ iso.weekday = 1;
+ gen->id_lo = isocal_date_to_ntp(&iso);
+ gen->id_hi = (u_int32)(gen->id_lo + 7 * SECSPERDAY);
break;
- case FILEGEN_YEAR:
- caljulian(newid,&cal);
- filename = (char*)emalloc(len + 1 + 4);
- sprintf(filename, "%s%c%04d", basename, SUFFIX_SEP, cal.year);
+ case FILEGEN_MONTH:
+ ntpcal_ntp_to_date(&cal, stamp, pivot);
+ snprintf(suffix, suflen, "%c%04d%02d",
+ SUFFIX_SEP, cal.year, cal.month);
+ cal.hour = cal.minute = cal.second = 0;
+ cal.monthday = 1;
+ gen->id_lo = ntpcal_date_to_ntp(&cal);
+ cal.month++;
+ gen->id_hi = ntpcal_date_to_ntp(&cal);
break;
- case FILEGEN_AGE:
- filename = (char*)emalloc(len + 1 + 2 + 10);
- sprintf(filename, "%s%ca%08ld", basename, SUFFIX_SEP, newid);
+ case FILEGEN_YEAR:
+ ntpcal_ntp_to_date(&cal, stamp, pivot);
+ snprintf(suffix, suflen, "%c%04d",
+ SUFFIX_SEP, cal.year);
+ cal.hour = cal.minute = cal.second = 0;
+ cal.month = cal.monthday = 1;
+ gen->id_lo = ntpcal_date_to_ntp(&cal);
+ cal.year++;
+ gen->id_hi = ntpcal_date_to_ntp(&cal);
break;
+
+ case FILEGEN_AGE:
+ gen->id_lo = current_time - (current_time % SECSPERDAY);
+ gen->id_hi = gen->id_lo + SECSPERDAY;
+ snprintf(suffix, suflen, "%ca%08ld",
+ SUFFIX_SEP, gen->id_lo);
}
- if (gen->type != FILEGEN_NONE) {
+ /* check possible truncation */
+ if ('\0' != fullname[len - 1]) {
+ fullname[len - 1] = '\0';
+ msyslog(LOG_ERR, "logfile name truncated: \"%s\"",
+ fullname);
+ }
+
+ if (FILEGEN_NONE != gen->type) {
/*
* check for existence of a file with name 'basename'
* as we disallow such a file
@@ -170,21 +220,23 @@ filegen_open(
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG)
#endif
- if (stat(basename, &stats) == 0) {
+ if (stat(filename, &stats) == 0) {
/* Hm, file exists... */
if (S_ISREG(stats.st_mode)) {
if (stats.st_nlink <= 1) {
/*
* Oh, it is not linked - try to save it
*/
- char *savename = (char*)emalloc(len + 1 + 1 + 10 + 10);
- sprintf(savename, "%s%c%dC%lu",
- basename,
- SUFFIX_SEP,
- (int) getpid(),
- (u_long)conflicts++);
- if (rename(basename, savename) != 0)
- msyslog(LOG_ERR," couldn't save %s: %m", basename);
+ savename = emalloc(len);
+ snprintf(savename, len,
+ "%s%c%dC%lu",
+ filename, SUFFIX_SEP,
+ (int)getpid(), conflicts++);
+
+ if (rename(filename, savename) != 0)
+ msyslog(LOG_ERR,
+ "couldn't save %s: %m",
+ filename);
free(savename);
} else {
/*
@@ -194,42 +246,45 @@ filegen_open(
*/
if (
#if !defined(VMS)
- unlink(basename) != 0
+ unlink(filename) != 0
#else
- delete(basename) != 0
+ delete(filename) != 0
#endif
)
- msyslog(LOG_ERR, "couldn't unlink %s: %m", basename);
+ msyslog(LOG_ERR,
+ "couldn't unlink %s: %m",
+ filename);
}
} else {
/*
* Ehh? Not a regular file ?? strange !!!!
*/
- msyslog(LOG_ERR, "expected regular file for %s (found mode 0%lo)",
- basename, (unsigned long)stats.st_mode);
+ msyslog(LOG_ERR,
+ "expected regular file for %s "
+ "(found mode 0%lo)",
+ filename,
+ (unsigned long)stats.st_mode);
}
} else {
/*
* stat(..) failed, but it is absolutely correct for
* 'basename' not to exist
*/
- if (errno != ENOENT)
- msyslog(LOG_ERR,"stat(%s) failed: %m", basename);
+ if (ENOENT != errno)
+ msyslog(LOG_ERR, "stat(%s) failed: %m",
+ filename);
}
}
/*
* now, try to open new file generation...
*/
- fp = fopen(filename, "a");
-
-#ifdef DEBUG
- if (debug > 3)
- printf("opening filegen (type=%d/id=%lu) \"%s\"\n",
- gen->type, (u_long)newid, filename);
-#endif
+ DPRINTF(4, ("opening filegen (type=%d/stamp=%u) \"%s\"\n",
+ gen->type, stamp, fullname));
- if (fp == NULL) {
+ fp = fopen(fullname, "a");
+
+ if (NULL == fp) {
/* open failed -- keep previous state
*
* If the file was open before keep the previous generation.
@@ -239,14 +294,14 @@ filegen_open(
* ignore errors due to missing directories
*/
- if (errno != ENOENT)
- msyslog(LOG_ERR, "can't open %s: %m", filename);
+ if (ENOENT != errno)
+ msyslog(LOG_ERR, "can't open %s: %m", fullname);
} else {
- if (gen->fp != NULL) {
+ if (NULL != gen->fp) {
fclose(gen->fp);
+ gen->fp = NULL;
}
gen->fp = fp;
- gen->id = newid;
if (gen->flag & FGEN_FLAG_LINK) {
/*
@@ -254,7 +309,7 @@ filegen_open(
* have to use hardlink for now as I want to allow
* gen->basename spanning directory levels
* this would make it more complex to get the correct
- * filename for symlink
+ * fullname for symlink
*
* Ok, it would just mean taking the part following
* the last '/' in the name.... Should add it later....
@@ -262,20 +317,22 @@ filegen_open(
/* Windows NT does not support file links -Greg Schueman 1/18/97 */
-#if defined SYS_WINNT || defined SYS_VXWORKS
+#if defined(SYS_WINNT) || defined(SYS_VXWORKS)
SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */
#elif defined(VMS)
errno = 0; /* On VMS, don't support FGEN_FLAG_LINK */
#else /* not (VMS) / VXWORKS / WINNT ; DO THE LINK) */
- if (link(filename, basename) != 0)
- if (errno != EEXIST)
- msyslog(LOG_ERR, "can't link(%s, %s): %m", filename, basename);
+ if (link(fullname, filename) != 0)
+ if (EEXIST != errno)
+ msyslog(LOG_ERR,
+ "can't link(%s, %s): %m",
+ fullname, filename);
#endif /* SYS_WINNT || VXWORKS */
} /* flags & FGEN_FLAG_LINK */
} /* else fp == NULL */
- free(basename);
free(filename);
+ free(fullname);
return;
}
@@ -289,78 +346,53 @@ filegen_open(
void
filegen_setup(
- FILEGEN *gen,
- u_long now
+ FILEGEN * gen,
+ u_int32 now
)
{
- u_long new_gen = ~ (u_long) 0;
- struct calendar cal;
+ int current;
+ time_t pivot;
if (!(gen->flag & FGEN_FLAG_ENABLED)) {
- if (gen->fp != NULL)
- fclose(gen->fp);
+ if (NULL != gen->fp) {
+ fclose(gen->fp);
+ gen->fp = NULL;
+ }
return;
}
-
+
switch (gen->type) {
- case FILEGEN_NONE:
- if (gen->fp != NULL) return; /* file already open */
- break;
-
- case FILEGEN_PID:
- new_gen = getpid();
- break;
- case FILEGEN_DAY:
- caljulian(now, &cal);
- cal.hour = cal.minute = cal.second = 0;
- new_gen = caltontp(&cal);
+ default:
+ case FILEGEN_NONE:
+ current = TRUE;
break;
-
- case FILEGEN_WEEK:
- /* Would be nice to have a calweekstart() routine */
- /* so just use a hack ... */
- /* just round time to integral 7 day period for actual year */
- new_gen = now - (now - calyearstart(now)) % TIMES7(SECSPERDAY)
- + 60;
- /*
- * just to be sure -
- * the computation above would fail in the presence of leap seconds
- * so at least carry the date to the next day (+60 (seconds))
- * and go back to the start of the day via calendar computations
- */
- caljulian(new_gen, &cal);
- cal.hour = cal.minute = cal.second = 0;
- new_gen = caltontp(&cal);
- break;
-
- case FILEGEN_MONTH:
- caljulian(now, &cal);
- cal.yearday = (u_short) (cal.yearday - cal.monthday + 1);
- cal.monthday = 1;
- cal.hour = cal.minute = cal.second = 0;
- new_gen = caltontp(&cal);
+
+ case FILEGEN_PID:
+ current = ((int)gen->id_lo == getpid());
break;
-
- case FILEGEN_YEAR:
- new_gen = calyearstart(now);
+
+ case FILEGEN_AGE:
+ current = (gen->id_lo <= current_time) &&
+ (gen->id_hi > current_time);
break;
- case FILEGEN_AGE:
- new_gen = current_time - (current_time % FGEN_AGE_SECS);
+ case FILEGEN_DAY:
+ case FILEGEN_WEEK:
+ case FILEGEN_MONTH:
+ case FILEGEN_YEAR:
+ current = (gen->id_lo <= now) &&
+ (gen->id_hi > now);
break;
}
/*
* try to open file if not yet open
* reopen new file generation file on change of generation id
*/
- if (gen->fp == NULL || gen->id != new_gen) {
-#if DEBUG
- if (debug)
- printf("filegen %0x %lu %lu %lu\n", gen->type, now,
- gen->id, new_gen);
-#endif
- filegen_open(gen, new_gen);
+ if (NULL == gen->fp || !current) {
+ DPRINTF(1, ("filegen %0x %u\n", gen->type, now));
+ pivot = time(NULL);
+ filegen_open(gen, now, &pivot);
}
}
@@ -370,41 +402,59 @@ filegen_setup(
*/
void
filegen_config(
- FILEGEN *gen,
- char *basename,
- u_int type,
- u_int flag
+ FILEGEN * gen,
+ const char * dir,
+ const char * fname,
+ u_int type,
+ u_int flag
)
{
+ int file_existed;
+ l_fp now;
+
+
/*
* if nothing would be changed...
*/
- if ((basename == gen->basename || strcmp(basename,gen->basename) == 0) &&
- type == gen->type &&
- flag == gen->flag)
- return;
-
+ if (strcmp(dir, gen->dir) == 0 && strcmp(fname, gen->fname) == 0
+ && type == gen->type && flag == gen->flag)
+ return;
+
/*
* validate parameters
*/
- if (!valid_fileref(gen->prefix,basename))
- return;
+ if (!valid_fileref(dir, fname))
+ return;
- if (gen->fp != NULL)
- fclose(gen->fp);
+ if (NULL != gen->fp) {
+ fclose(gen->fp);
+ gen->fp = NULL;
+ file_existed = TRUE;
+ } else {
+ file_existed = FALSE;
+ }
-#ifdef DEBUG
- if (debug > 2)
- printf("configuring filegen:\n\tprefix:\t%s\n\tbasename:\t%s -> %s\n\ttype:\t%d -> %d\n\tflag: %x -> %x\n",
- gen->prefix, gen->basename, basename, gen->type, type, gen->flag, flag);
-#endif
- if (gen->basename != basename || strcmp(gen->basename, basename) != 0) {
- free(gen->basename);
- gen->basename = (char*)emalloc(strlen(basename) + 1);
- strcpy(gen->basename, basename);
+ DPRINTF(3, ("configuring filegen:\n"
+ "\tdir:\t%s -> %s\n"
+ "\tfname:\t%s -> %s\n"
+ "\ttype:\t%d -> %d\n"
+ "\tflag: %x -> %x\n",
+ gen->dir, dir,
+ gen->fname, fname,
+ gen->type, type,
+ gen->flag, flag));
+
+ if (strcmp(gen->dir, dir) != 0) {
+ free(gen->dir);
+ gen->dir = estrdup(dir);
+ }
+
+ if (strcmp(gen->fname, fname) != 0) {
+ free(gen->fname);
+ gen->fname = estrdup(fname);
}
- gen->type = (u_char) type;
- gen->flag = (u_char) flag;
+ gen->type = (u_char)type;
+ gen->flag = (u_char)flag;
/*
* make filegen use the new settings
@@ -412,9 +462,7 @@ filegen_config(
* is currently open
* otherwise the new settings will be used anyway at the next open
*/
- if (gen->fp != NULL) {
- l_fp now;
-
+ if (file_existed) {
get_systime(&now);
filegen_setup(gen, now.l_ui);
}
@@ -427,40 +475,54 @@ filegen_config(
*/
static int
valid_fileref(
- char *prefix,
- char *basename
+ const char * dir,
+ const char * fname
)
{
/*
- * prefix cannot be changed dynamically
+ * dir cannot be changed dynamically
* (within the context of filegen)
* so just reject basenames containing '..'
*
* ASSUMPTION:
- * file system parts 'below' prefix may be
+ * file system parts 'below' dir may be
* specified without infringement of security
*
- * restricing prefix to legal values
+ * restricting dir to legal values
* has to be ensured by other means
* (however, it would be possible to perform some checks here...)
*/
- register char *p = basename;
-
+ const char *p;
+
/*
* Just to catch, dumb errors opening up the world...
*/
- if (prefix == NULL || *prefix == '\0')
- return 0;
+ if (NULL == dir || '\0' == dir[0])
+ return FALSE;
- if (basename == NULL)
- return 0;
-
- for (p = basename; p; p = strchr(p, '/')) {
- if (*p == '.' && *(p+1) == '.' && (*(p+2) == '\0' || *(p+2) == '/'))
- return 0;
+ if (NULL == fname)
+ return FALSE;
+
+#ifdef SYS_WINNT
+ /*
+ * Windows treats / equivalent to \, reject any / to ensure
+ * check below for DIR_SEP (\ on windows) are adequate.
+ */
+ if (strchr(fname, '/')) {
+ msyslog(LOG_ERR,
+ "filegen filenames must not contain '/': %s",
+ fname);
+ return FALSE;
}
-
- return 1;
+#endif
+
+ for (p = fname; p != NULL; p = strchr(p, DIR_SEP)) {
+ if ('.' == p[0] && '.' == p[1]
+ && ('\0' == p[2] || DIR_SEP == p[2]))
+ return FALSE;
+ }
+
+ return TRUE;
}
@@ -469,108 +531,115 @@ valid_fileref(
*/
static struct filegen_entry {
- char *name;
- FILEGEN *filegen;
- struct filegen_entry *next;
+ char * name;
+ FILEGEN * filegen;
+ struct filegen_entry * next;
} *filegen_registry = NULL;
FILEGEN *
filegen_get(
- char *name
+ const char * name
)
{
struct filegen_entry *f = filegen_registry;
- while(f) {
+ while (f) {
if (f->name == name || strcmp(name, f->name) == 0) {
-#ifdef XXX /* this gives the Alpha compiler fits */
- if (debug > 3)
- printf("filegen_get(\"%s\") = %x\n", name,
- (u_int)f->filegen);
-#endif
+ DPRINTF(4, ("filegen_get(%s) = %p\n",
+ name, f->filegen));
return f->filegen;
}
f = f->next;
}
-#ifdef DEBUG
- if (debug > 3)
- printf("filegen_get(\"%s\") = NULL\n", name);
-#endif
+ DPRINTF(4, ("filegen_get(%s) = NULL\n", name));
return NULL;
}
+
void
filegen_register(
- char *prefix,
- const char *name,
- FILEGEN *filegen
+ const char * dir,
+ const char * name,
+ FILEGEN * filegen
)
{
- struct filegen_entry **f = &filegen_registry;
+ struct filegen_entry **ppfe;
-#ifdef XXX /* this gives the Alpha compiler fits */
- if (debug > 3)
- printf("filegen_register(\"%s\",%x)\n", name, (u_int)filegen);
-#endif
+ DPRINTF(4, ("filegen_register(%s, %p)\n", name, filegen));
- filegen_init(prefix, name, filegen);
+ filegen_init(dir, name, filegen);
- while (*f) {
- if ((*f)->name == name || strcmp(name, (*f)->name) == 0) {
-#ifdef XXX /* this gives the Alpha compiler fits */
- if (debug > 4) {
- printf("replacing filegen %x\n", (u_int)(*f)->filegen);
- }
-#endif
- (*f)->filegen = filegen;
+ ppfe = &filegen_registry;
+ while (NULL != *ppfe) {
+ if ((*ppfe)->name == name
+ || !strcmp((*ppfe)->name, name)) {
+
+ DPRINTF(5, ("replacing filegen %p\n",
+ (*ppfe)->filegen));
+
+ (*ppfe)->filegen = filegen;
return;
}
- f = &((*f)->next);
+ ppfe = &((*ppfe)->next);
}
- *f = (struct filegen_entry *) emalloc(sizeof(struct filegen_entry));
- if (*f) {
- (*f)->next = NULL;
- (*f)->name = (char*)emalloc(strlen(name) + 1);
- strcpy((*f)->name, name);
- (*f)->filegen = filegen;
-#ifdef DEBUG
- if (debug > 5) {
- printf("adding new filegen\n");
- }
-#endif
- }
+ *ppfe = emalloc(sizeof **ppfe);
+
+ (*ppfe)->next = NULL;
+ (*ppfe)->name = estrdup(name);
+ (*ppfe)->filegen = filegen;
+
+ DPRINTF(6, ("adding new filegen\n"));
return;
}
-#ifdef UNUSED
-static FILEGEN *
+
+/*
+ * filegen_statsdir() - reset each filegen entry's dir to statsdir.
+ */
+void
+filegen_statsdir(void)
+{
+ struct filegen_entry *f;
+
+ for (f = filegen_registry; f != NULL; f = f->next)
+ filegen_config(f->filegen, statsdir, f->filegen->fname,
+ f->filegen->type, f->filegen->flag);
+}
+
+
+/*
+ * filegen_unregister frees memory allocated by filegen_register for
+ * name.
+ */
+#ifdef DEBUG
+void
filegen_unregister(
- char *name
+ const char *name
)
{
- struct filegen_entry **f = &filegen_registry;
-
-#ifdef DEBUG
- if (debug > 3)
- printf("filegen_unregister(\"%s\")\n", name);
-#endif
-
- while (*f) {
- if (strcmp((*f)->name,name) == 0) {
- struct filegen_entry *ff = *f;
- FILEGEN *fg;
+ struct filegen_entry ** ppfe;
+ struct filegen_entry * pfe;
+ FILEGEN * fg;
- *f = (*f)->next;
- fg = ff->filegen;
- free(ff->name);
- free(ff);
- return fg;
+ DPRINTF(4, ("filegen_unregister(%s)\n", name));
+
+ ppfe = &filegen_registry;
+
+ while (NULL != *ppfe) {
+ if ((*ppfe)->name == name
+ || !strcmp((*ppfe)->name, name)) {
+ pfe = *ppfe;
+ *ppfe = (*ppfe)->next;
+ fg = pfe->filegen;
+ free(pfe->name);
+ free(pfe);
+ filegen_uninit(fg);
+ break;
}
- f = &((*f)->next);
+ ppfe = &((*ppfe)->next);
}
- return NULL;
}
-#endif /* UNUSED */
+#endif /* DEBUG */
diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c
deleted file mode 100644
index e18888f..0000000
--- a/contrib/ntp/ntpd/ntp_intres.c
+++ /dev/null
@@ -1,1185 +0,0 @@
-/*
- * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92
- * routine callable from ntpd, rather than separate program
- * also, key info passed in via a global, so no key file needed.
- */
-
-/*
- * ntpres - process configuration entries which require use of the resolver
- *
- * This is meant to be run by ntpd on the fly. It is not guaranteed
- * to work properly if run by hand. This is actually a quick hack to
- * stave off violence from people who hate using numbers in the
- * configuration file (at least I hope the rest of the daemon is
- * better than this). Also might provide some ideas about how one
- * might go about autoconfiguring an NTP distribution network.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "ntp_machine.h"
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_request.h"
-#include "ntp_stdlib.h"
-#include "ntp_syslog.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#include <resolv.h>
-#include <signal.h>
-
-/**/
-#include <netinet/in.h>
-#include <arpa/inet.h>
-/**/
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h> /* MAXHOSTNAMELEN (often) */
-#endif
-
-#include <isc/net.h>
-#include <isc/result.h>
-
-#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
-
-/*
- * Each item we are to resolve and configure gets one of these
- * structures defined for it.
- */
-struct conf_entry {
- struct conf_entry *ce_next;
- char *ce_name; /* name we are trying to resolve */
- struct conf_peer ce_config; /* configuration info for peer */
- struct sockaddr_storage peer_store; /* address info for both fams */
-};
-#define ce_peeraddr ce_config.peeraddr
-#define ce_peeraddr6 ce_config.peeraddr6
-#define ce_hmode ce_config.hmode
-#define ce_version ce_config.version
-#define ce_minpoll ce_config.minpoll
-#define ce_maxpoll ce_config.maxpoll
-#define ce_flags ce_config.flags
-#define ce_ttl ce_config.ttl
-#define ce_keyid ce_config.keyid
-#define ce_keystr ce_config.keystr
-
-/*
- * confentries is a pointer to the list of configuration entries
- * we have left to do.
- */
-static struct conf_entry *confentries = NULL;
-
-/*
- * We take an interrupt every thirty seconds, at which time we decrement
- * config_timer and resolve_timer. The former is set to 2, so we retry
- * unsucessful reconfigurations every minute. The latter is set to
- * an exponentially increasing value which starts at 2 and increases to
- * 32. When this expires we retry failed name resolutions.
- *
- * We sleep SLEEPTIME seconds before doing anything, to give the server
- * time to arrange itself.
- */
-#define MINRESOLVE 2
-#define MAXRESOLVE 32
-#define CONFIG_TIME 2
-#define ALARM_TIME 30
-#define SLEEPTIME 2
-
-static volatile int config_timer = 0;
-static volatile int resolve_timer = 0;
-
-static int resolve_value; /* next value of resolve timer */
-
-/*
- * Big hack attack
- */
-#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */
-#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
-
-/*
- * Select time out. Set to 2 seconds. The server is on the local machine,
- * after all.
- */
-#define TIMEOUT_SEC 2
-#define TIMEOUT_USEC 0
-
-
-/*
- * Input processing. The data on each line in the configuration file
- * is supposed to consist of entries in the following order
- */
-#define TOK_HOSTNAME 0
-#define TOK_PEERAF 1
-#define TOK_HMODE 2
-#define TOK_VERSION 3
-#define TOK_MINPOLL 4
-#define TOK_MAXPOLL 5
-#define TOK_FLAGS 6
-#define TOK_TTL 7
-#define TOK_KEYID 8
-#define TOK_KEYSTR 9
-#define NUMTOK 10
-
-#define MAXLINESIZE 512
-
-
-/*
- * File descriptor for ntp request code.
- */
-static SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */
-
-/* stuff to be filled in by caller */
-
-keyid_t req_keyid; /* request keyid */
-char *req_file; /* name of the file with configuration info */
-
-/* end stuff to be filled in */
-
-
-static void checkparent P((void));
-static void removeentry P((struct conf_entry *));
-static void addentry P((char *, int, int, int, int, u_int,
- int, keyid_t, char *, u_char));
-static int findhostaddr P((struct conf_entry *));
-static void openntp P((void));
-static int request P((struct conf_peer *));
-static char * nexttoken P((char **));
-static void readconf P((FILE *, char *));
-static void doconfigure P((int));
-
-struct ntp_res_t_pkt { /* Tagged packet: */
- void *tag; /* For the caller */
- u_int32 paddr; /* IP to look up, or 0 */
- char name[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */
-};
-
-struct ntp_res_c_pkt { /* Control packet: */
- char name[MAXHOSTNAMELEN];
- u_int32 paddr;
- int mode;
- int version;
- int minpoll;
- int maxpoll;
- u_int flags;
- int ttl;
- keyid_t keyid;
- u_char keystr[MAXFILENAME];
-};
-
-
-static void resolver_exit P((int));
-
-/*
- * Call here instead of just exiting
- */
-
-static void resolver_exit (int code)
-{
-#ifdef SYS_WINNT
- CloseHandle(ResolverEventHandle);
- ResolverEventHandle = NULL;
- ExitThread(code); /* Just to kill the thread not the process */
-#else
- exit(code); /* kill the forked process */
-#endif
-}
-
-/*
- * ntp_res_recv: Process an answer from the resolver
- */
-
-void
-ntp_res_recv(void)
-{
- /*
- We have data ready on our descriptor.
- It may be an EOF, meaning the resolver process went away.
- Otherwise, it will be an "answer".
- */
-}
-
-
-/*
- * ntp_intres needs;
- *
- * req_key(???), req_keyid, req_file valid
- * syslog still open
- */
-
-void
-ntp_intres(void)
-{
- FILE *in;
- struct timeval tv;
- fd_set fdset;
-#ifdef SYS_WINNT
- DWORD rc;
-#else
- int rc;
-#endif
-
-#ifdef DEBUG
- if (debug > 1) {
- msyslog(LOG_INFO, "NTP_INTRES running");
- }
-#endif
-
- /* check out auth stuff */
- if (sys_authenticate) {
- if (!authistrusted(req_keyid)) {
- msyslog(LOG_ERR, "invalid request keyid %08x",
- req_keyid );
- resolver_exit(1);
- }
- }
-
- /*
- * Read the configuration info
- * {this is bogus, since we are forked, but it is easier
- * to keep this code - gdt}
- */
- if ((in = fopen(req_file, "r")) == NULL) {
- msyslog(LOG_ERR, "can't open configuration file %s: %m",
- req_file);
- resolver_exit(1);
- }
- readconf(in, req_file);
- (void) fclose(in);
-
-#ifdef DEBUG
- if (!debug )
-#endif
- (void) unlink(req_file);
-
- /*
- * Set up the timers to do first shot immediately.
- */
- resolve_timer = 0;
- resolve_value = MINRESOLVE;
- config_timer = CONFIG_TIME;
-
- for (;;) {
- checkparent();
-
- if (resolve_timer == 0) {
- /*
- * Sleep a little to make sure the network is completely up
- */
- sleep(SLEEPTIME);
- doconfigure(1);
-
- /* prepare retry, in case there's more work to do */
- resolve_timer = resolve_value;
-#ifdef DEBUG
- if (debug > 2)
- msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
-#endif
- if (resolve_value < MAXRESOLVE)
- resolve_value <<= 1;
-
- config_timer = CONFIG_TIME;
- } else if (config_timer == 0) { /* MB: in which case would this be required ? */
- doconfigure(0);
- /* MB: should we check now if we could exit, similar to the code above? */
- config_timer = CONFIG_TIME;
-#ifdef DEBUG
- if (debug > 2)
- msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
-#endif
- }
-
- if (confentries == NULL)
- resolver_exit(0); /* done */
-
-#ifdef SYS_WINNT
- rc = WaitForSingleObject(ResolverEventHandle, 1000 * ALARM_TIME); /* in milliseconds */
-
- if ( rc == WAIT_OBJECT_0 ) { /* signaled by the main thread */
- resolve_timer = 0; /* retry resolving immediately */
- continue;
- }
-
- if ( rc != WAIT_TIMEOUT ) /* not timeout: error */
- resolver_exit(1);
-
-#else /* not SYS_WINNT */
- tv.tv_sec = ALARM_TIME;
- tv.tv_usec = 0;
- FD_ZERO(&fdset);
- FD_SET(resolver_pipe_fd[0], &fdset);
- rc = select(resolver_pipe_fd[0] + 1, &fdset, (fd_set *)0, (fd_set *)0, &tv);
-
- if (rc > 0) { /* parent process has written to the pipe */
- read(resolver_pipe_fd[0], (char *)&rc, sizeof(rc)); /* make pipe empty */
- resolve_timer = 0; /* retry resolving immediately */
- continue;
- }
-
- if ( rc < 0 ) /* select() returned error */
- resolver_exit(1);
-#endif
-
- /* normal timeout, keep on waiting */
- if (config_timer > 0)
- config_timer--;
- if (resolve_timer > 0)
- resolve_timer--;
- }
-}
-
-
-
-/*
- * checkparent - see if our parent process is still running
- *
- * No need to worry in the Windows NT environment whether the
- * main thread is still running, because if it goes
- * down it takes the whole process down with it (in
- * which case we won't be running this thread either)
- * Turn function into NOP;
- */
-
-static void
-checkparent(void)
-{
-#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
-
- /*
- * If our parent (the server) has died we will have been
- * inherited by init. If so, exit.
- */
- if (getppid() == 1) {
- msyslog(LOG_INFO, "parent died before we finished, exiting");
- resolver_exit(0);
- }
-#endif /* SYS_WINNT && SYS_VXWORKS*/
-}
-
-
-
-/*
- * removeentry - we are done with an entry, remove it from the list
- */
-static void
-removeentry(
- struct conf_entry *entry
- )
-{
- register struct conf_entry *ce;
-
- ce = confentries;
- if (ce == entry) {
- confentries = ce->ce_next;
- return;
- }
-
- while (ce != NULL) {
- if (ce->ce_next == entry) {
- ce->ce_next = entry->ce_next;
- return;
- }
- ce = ce->ce_next;
- }
-}
-
-
-/*
- * addentry - add an entry to the configuration list
- */
-static void
-addentry(
- char *name,
- int mode,
- int version,
- int minpoll,
- int maxpoll,
- u_int flags,
- int ttl,
- keyid_t keyid,
- char *keystr,
- u_char peeraf
- )
-{
- register char *cp;
- register struct conf_entry *ce;
- unsigned int len;
-
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "intres: <%s> %u %d %d %d %d %x %d %x %s\n", name, peeraf,
- mode, version, minpoll, maxpoll, flags, ttl, keyid,
- keystr);
-#endif
- len = strlen(name) + 1;
- cp = (char *)emalloc(len);
- memmove(cp, name, len);
-
- ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry));
- ce->ce_name = cp;
- ce->ce_peeraddr = 0;
-#ifdef ISC_PLATFORM_HAVEIPV6
- ce->ce_peeraddr6 = in6addr_any;
-#endif
- ANYSOCK(&ce->peer_store);
- ce->peer_store.ss_family = peeraf; /* Save AF for getaddrinfo hints. */
- ce->ce_hmode = (u_char)mode;
- ce->ce_version = (u_char)version;
- ce->ce_minpoll = (u_char)minpoll;
- ce->ce_maxpoll = (u_char)maxpoll;
- ce->ce_flags = (u_char)flags;
- ce->ce_ttl = (u_char)ttl;
- ce->ce_keyid = keyid;
- strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME);
- ce->ce_next = NULL;
-
- if (confentries == NULL) {
- confentries = ce;
- } else {
- register struct conf_entry *cep;
-
- for (cep = confentries; cep->ce_next != NULL;
- cep = cep->ce_next)
- /* nothing */;
- cep->ce_next = ce;
- }
-}
-
-
-/*
- * findhostaddr - resolve a host name into an address (Or vice-versa)
- *
- * Given one of {ce_peeraddr,ce_name}, find the other one.
- * It returns 1 for "success" and 0 for an uncorrectable failure.
- * Note that "success" includes try again errors. You can tell that you
- * got a "try again" since {ce_peeraddr,ce_name} will still be zero.
- */
-static int
-findhostaddr(
- struct conf_entry *entry
- )
-{
- static int eai_again_seen = 0;
- struct addrinfo *addr;
- struct addrinfo hints;
- int again;
- int error;
-
- checkparent(); /* make sure our guy is still running */
-
- if (entry->ce_name != NULL && !SOCKNUL(&entry->peer_store)) {
- /* HMS: Squawk? */
- msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
- return 1;
- }
-
- if (entry->ce_name == NULL && SOCKNUL(&entry->peer_store)) {
- msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
- return 0;
- }
-
- if (entry->ce_name) {
- DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
- entry->ce_name));
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = entry->peer_store.ss_family;
- hints.ai_socktype = SOCK_DGRAM;
- /*
- * If the IPv6 stack is not available look only for IPv4 addresses
- */
- if (isc_net_probeipv6() != ISC_R_SUCCESS)
- hints.ai_family = AF_INET;
-
- error = getaddrinfo(entry->ce_name, NULL, &hints, &addr);
- if (error == 0) {
- entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr));
- if (entry->peer_store.ss_family == AF_INET) {
- entry->ce_peeraddr =
- GET_INADDR(entry->peer_store);
- entry->ce_config.v6_flag = 0;
- } else {
- entry->ce_peeraddr6 =
- GET_INADDR6(entry->peer_store);
- entry->ce_config.v6_flag = 1;
- }
- }
- } else {
- DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
- stoa(&entry->peer_store)));
-
- entry->ce_name = emalloc(MAXHOSTNAMELEN);
- error = getnameinfo((const struct sockaddr *)&entry->peer_store,
- SOCKLEN(&entry->peer_store),
- (char *)&entry->ce_name, MAXHOSTNAMELEN,
- NULL, 0, 0);
- }
-
- if (0 == error) {
-
- /* again is our return value, for success it is 1 */
- again = 1;
-
- DPRINTF(2, ("findhostaddr: %s resolved.\n",
- (entry->ce_name) ? "name" : "address"));
- } else {
- /*
- * If the resolver failed, see if the failure is
- * temporary. If so, return success.
- */
- again = 0;
-
- switch (error) {
-
- case EAI_FAIL:
- again = 1;
- break;
-
- case EAI_AGAIN:
- again = 1;
- eai_again_seen = 1;
- break;
-
- case EAI_NONAME:
-#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
- case EAI_NODATA:
-#endif
- msyslog(LOG_ERR, "host name not found%s%s: %s",
- (EAI_NONAME == error) ? "" : " EAI_NODATA",
- (eai_again_seen) ? " (permanent)" : "",
- entry->ce_name);
- again = !eai_again_seen;
- break;
-
-#ifdef EAI_SYSTEM
- case EAI_SYSTEM:
- /*
- * EAI_SYSTEM means the real error is in errno. We should be more
- * discriminating about which errno values require retrying, but
- * this matches existing behavior.
- */
- again = 1;
- DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
- errno, strerror(errno)));
- break;
-#endif
- }
-
- /* do this here to avoid perturbing errno earlier */
- DPRINTF(2, ("intres: got error status of: %d\n", error));
- }
-
- return again;
-}
-
-
-/*
- * openntp - open a socket to the ntp server
- */
-static void
-openntp(void)
-{
- const char *localhost = "127.0.0.1"; /* Use IPv4 loopback */
- struct addrinfo hints;
- struct addrinfo *addr;
- u_long on;
- int err;
-
- if (sockfd != INVALID_SOCKET)
- return;
-
- memset(&hints, 0, sizeof(hints));
-
- /*
- * For now only bother with IPv4
- */
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_DGRAM;
-
- err = getaddrinfo(localhost, "ntp", &hints, &addr);
-
- if (err) {
-#ifdef EAI_SYSTEM
- if (EAI_SYSTEM == err)
- msyslog(LOG_ERR, "getaddrinfo(%s) failed: %m",
- localhost);
- else
-#endif
- msyslog(LOG_ERR, "getaddrinfo(%s) failed: %s",
- localhost, gai_strerror(err));
- resolver_exit(1);
- }
-
- sockfd = socket(addr->ai_family, addr->ai_socktype, 0);
-
- if (INVALID_SOCKET == sockfd) {
- msyslog(LOG_ERR, "socket() failed: %m");
- resolver_exit(1);
- }
-
-#ifndef SYS_WINNT
- /*
- * On Windows only the count of sockets must be less than
- * FD_SETSIZE. On Unix each descriptor's value must be less
- * than FD_SETSIZE, as fd_set is a bit array.
- */
- if (sockfd >= FD_SETSIZE) {
- msyslog(LOG_ERR, "socket fd %d too large, FD_SETSIZE %d",
- (int)sockfd, FD_SETSIZE);
- resolver_exit(1);
- }
-
- /*
- * Make the socket non-blocking. We'll wait with select()
- * Unix: fcntl(O_NONBLOCK) or fcntl(FNDELAY)
- */
-# ifdef O_NONBLOCK
- if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
- msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
- resolver_exit(1);
- }
-# else
-# ifdef FNDELAY
- if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
- msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
- resolver_exit(1);
- }
-# else
-# include "Bletch: NEED NON BLOCKING IO"
-# endif /* FNDDELAY */
-# endif /* O_NONBLOCK */
- (void)on; /* quiet unused warning */
-#else /* !SYS_WINNT above */
- /*
- * Make the socket non-blocking. We'll wait with select()
- * Windows: ioctlsocket(FIONBIO)
- */
- on = 1;
- err = ioctlsocket(sockfd, FIONBIO, &on);
- if (SOCKET_ERROR == err) {
- msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
- resolver_exit(1);
- }
-#endif /* SYS_WINNT */
-
- err = connect(sockfd, addr->ai_addr, addr->ai_addrlen);
- if (SOCKET_ERROR == err) {
- msyslog(LOG_ERR, "openntp: connect() failed: %m");
- resolver_exit(1);
- }
-
- freeaddrinfo(addr);
-}
-
-
-/*
- * request - send a configuration request to the server, wait for a response
- */
-static int
-request(
- struct conf_peer *conf
- )
-{
- fd_set fdset;
- struct timeval tvout;
- struct req_pkt reqpkt;
- l_fp ts;
- int n;
-#ifdef SYS_WINNT
- HANDLE hReadWriteEvent = NULL;
- BOOL ret;
- DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait;
- OVERLAPPED overlap;
-#endif /* SYS_WINNT */
-
- checkparent(); /* make sure our guy is still running */
-
- if (sockfd == INVALID_SOCKET)
- openntp();
-
-#ifdef SYS_WINNT
- hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-#endif /* SYS_WINNT */
-
- /*
- * Try to clear out any previously received traffic so it
- * doesn't fool us. Note the socket is nonblocking.
- */
- tvout.tv_sec = 0;
- tvout.tv_usec = 0;
- FD_ZERO(&fdset);
- FD_SET(sockfd, &fdset);
- while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
- 0) {
- recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
- FD_ZERO(&fdset);
- FD_SET(sockfd, &fdset);
- }
-
- /*
- * Make up a request packet with the configuration info
- */
- memset((char *)&reqpkt, 0, sizeof(reqpkt));
-
- reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
- reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */
- reqpkt.implementation = IMPL_XNTPD; /* local implementation */
- reqpkt.request = REQ_CONFIG; /* configure a new peer */
- reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */
- reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer));
- /* Make sure mbz_itemsize <= sizeof reqpkt.data */
- if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) {
- msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!");
- resolver_exit(1);
- }
- memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer));
- reqpkt.keyid = htonl(req_keyid);
-
- get_systime(&ts);
- L_ADDUF(&ts, SKEWTIME);
- HTONL_FP(&ts, &reqpkt.tstamp);
- n = 0;
- if (sys_authenticate)
- n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC);
-
- /*
- * Done. Send it.
- */
-#ifndef SYS_WINNT
- n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0);
- if (n < 0) {
- msyslog(LOG_ERR, "send to NTP server failed: %m");
- return 0; /* maybe should exit */
- }
-#else
- /* In the NT world, documentation seems to indicate that there
- * exist _write and _read routines that can be used to do blocking
- * I/O on sockets. Problem is these routines require a socket
- * handle obtained through the _open_osf_handle C run-time API
- * of which there is no explanation in the documentation. We need
- * nonblocking write's and read's anyway for our purpose here.
- * We're therefore forced to deviate a little bit from the Unix
- * model here and use the ReadFile and WriteFile Win32 I/O API's
- * on the socket
- */
- overlap.Offset = overlap.OffsetHigh = (DWORD)0;
- overlap.hEvent = hReadWriteEvent;
- ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n,
- NULL, (LPOVERLAPPED)&overlap);
- if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
- msyslog(LOG_ERR, "send to NTP server failed: %m");
- return 0;
- }
- dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
- if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
- if (dwWait == WAIT_FAILED)
- msyslog(LOG_ERR, "WaitForSingleObject failed: %m");
- return 0;
- }
- if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
- (LPDWORD)&NumberOfBytesWritten, FALSE)) {
- msyslog(LOG_ERR, "GetOverlappedResult for WriteFile fails: %m");
- return 0;
- }
-#endif /* SYS_WINNT */
-
-
- /*
- * Wait for a response. A weakness of the mode 7 protocol used
- * is that there is no way to associate a response with a
- * particular request, i.e. the response to this configuration
- * request is indistinguishable from that to any other. I should
- * fix this some day. In any event, the time out is fairly
- * pessimistic to make sure that if an answer is coming back
- * at all, we get it.
- */
- for (;;) {
- FD_ZERO(&fdset);
- FD_SET(sockfd, &fdset);
- tvout.tv_sec = TIMEOUT_SEC;
- tvout.tv_usec = TIMEOUT_USEC;
-
- n = select(sockfd + 1, &fdset, (fd_set *)0,
- (fd_set *)0, &tvout);
-
- if (n < 0)
- {
- if (errno != EINTR)
- msyslog(LOG_ERR, "select() fails: %m");
- return 0;
- }
- else if (n == 0)
- {
-#ifdef DEBUG
- if (debug)
- msyslog(LOG_INFO, "select() returned 0.");
-#endif
- return 0;
- }
-
-#ifndef SYS_WINNT
- n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
- if (n <= 0) {
- if (n < 0) {
- msyslog(LOG_ERR, "recv() fails: %m");
- return 0;
- }
- continue;
- }
-#else /* Overlapped I/O used on non-blocking sockets on Windows NT */
- ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC,
- NULL, (LPOVERLAPPED)&overlap);
- if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
- msyslog(LOG_ERR, "ReadFile() fails: %m");
- return 0;
- }
- dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
- if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
- if (dwWait == WAIT_FAILED) {
- msyslog(LOG_ERR, "WaitForSingleObject for ReadFile fails: %m");
- return 0;
- }
- continue;
- }
- if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
- (LPDWORD)&NumberOfBytesRead, FALSE)) {
- msyslog(LOG_ERR, "GetOverlappedResult fails: %m");
- return 0;
- }
- n = NumberOfBytesRead;
-#endif /* SYS_WINNT */
-
- /*
- * Got one. Check through to make sure it is what
- * we expect.
- */
- if (n < RESP_HEADER_SIZE) {
- msyslog(LOG_ERR, "received runt response (%d octets)",
- n);
- continue;
- }
-
- if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO, "received non-response packet");
-#endif
- continue;
- }
-
- if (ISMORE(reqpkt.rm_vn_mode)) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO, "received fragmented packet");
-#endif
- continue;
- }
-
- if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2)
- || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION))
- || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "version (%d/%d) or mode (%d/%d) incorrect",
- INFO_VERSION(reqpkt.rm_vn_mode),
- NTP_VERSION,
- INFO_MODE(reqpkt.rm_vn_mode),
- MODE_PRIVATE);
-#endif
- continue;
- }
-
- if (INFO_SEQ(reqpkt.auth_seq) != 0) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "nonzero sequence number (%d)",
- INFO_SEQ(reqpkt.auth_seq));
-#endif
- continue;
- }
-
- if (reqpkt.implementation != IMPL_XNTPD ||
- reqpkt.request != REQ_CONFIG) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "implementation (%d) or request (%d) incorrect",
- reqpkt.implementation, reqpkt.request);
-#endif
- continue;
- }
-
- if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
- INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
- INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "nitems (%d) mbz (%d) or itemsize (%d) nonzero",
- INFO_NITEMS(reqpkt.err_nitems),
- INFO_MBZ(reqpkt.mbz_itemsize),
- INFO_ITEMSIZE(reqpkt.mbz_itemsize));
-#endif
- continue;
- }
-
- n = INFO_ERR(reqpkt.err_nitems);
- switch (n) {
- case INFO_OKAY:
- /* success */
- return 1;
-
- case INFO_ERR_IMPL:
- msyslog(LOG_ERR,
- "ntpd reports implementation mismatch!");
- return 0;
-
- case INFO_ERR_REQ:
- msyslog(LOG_ERR,
- "ntpd says configuration request is unknown!");
- return 0;
-
- case INFO_ERR_FMT:
- msyslog(LOG_ERR,
- "ntpd indicates a format error occurred!");
- return 0;
-
- case INFO_ERR_NODATA:
- msyslog(LOG_ERR,
- "ntpd indicates no data available!");
- return 0;
-
- case INFO_ERR_AUTH:
- msyslog(LOG_ERR,
- "ntpd returns a permission denied error!");
- return 0;
-
- default:
- msyslog(LOG_ERR,
- "ntpd returns unknown error code %d!", n);
- return 0;
- }
- }
-}
-
-
-/*
- * nexttoken - return the next token from a line
- */
-static char *
-nexttoken(
- char **lptr
- )
-{
- register char *cp;
- register char *tstart;
-
- cp = *lptr;
-
- /*
- * Skip leading white space
- */
- while (*cp == ' ' || *cp == '\t')
- cp++;
-
- /*
- * If this is the end of the line, return nothing.
- */
- if (*cp == '\n' || *cp == '\0') {
- *lptr = cp;
- return NULL;
- }
-
- /*
- * Must be the start of a token. Record the pointer and look
- * for the end.
- */
- tstart = cp++;
- while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
- cp++;
-
- /*
- * Terminate the token with a \0. If this isn't the end of the
- * line, space to the next character.
- */
- if (*cp == '\n' || *cp == '\0')
- *cp = '\0';
- else
- *cp++ = '\0';
-
- *lptr = cp;
- return tstart;
-}
-
-
-/*
- * readconf - read the configuration information out of the file we
- * were passed. Note that since the file is supposed to be
- * machine generated, we bail out at the first sign of trouble.
- */
-static void
-readconf(
- FILE *fp,
- char *name
- )
-{
- register int i;
- char *token[NUMTOK];
- u_long intval[NUMTOK];
- u_int flags;
- char buf[MAXLINESIZE];
- char *bp;
-
- while (fgets(buf, MAXLINESIZE, fp) != NULL) {
-
- bp = buf;
- for (i = 0; i < NUMTOK; i++) {
- if ((token[i] = nexttoken(&bp)) == NULL) {
- msyslog(LOG_ERR,
- "tokenizing error in file `%s', quitting",
- name);
- resolver_exit(1);
- }
- }
-
- for (i = 1; i < NUMTOK - 1; i++) {
- if (!atouint(token[i], &intval[i])) {
- msyslog(LOG_ERR,
- "format error for integer token `%s', file `%s', quitting",
- token[i], name);
- resolver_exit(1);
- }
- }
-
- if (intval[TOK_PEERAF] != AF_UNSPEC && intval[TOK_PEERAF] !=
- AF_INET && intval[TOK_PEERAF] != AF_INET6) {
- msyslog(LOG_ERR, "invalid peer address family (%u) in "
- "file %s", intval[TOK_PEERAF], name);
- exit(1);
- }
-
- if (intval[TOK_HMODE] != MODE_ACTIVE &&
- intval[TOK_HMODE] != MODE_CLIENT &&
- intval[TOK_HMODE] != MODE_BROADCAST) {
- msyslog(LOG_ERR, "invalid mode (%ld) in file %s",
- intval[TOK_HMODE], name);
- resolver_exit(1);
- }
-
- if (intval[TOK_VERSION] > NTP_VERSION ||
- intval[TOK_VERSION] < NTP_OLDVERSION) {
- msyslog(LOG_ERR, "invalid version (%ld) in file %s",
- intval[TOK_VERSION], name);
- resolver_exit(1);
- }
- if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
- intval[TOK_MINPOLL] > NTP_MAXPOLL) {
- msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
- intval[TOK_MINPOLL], name);
- resolver_exit(1);
- }
-
- if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
- intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
- msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
- intval[TOK_MAXPOLL], name);
- resolver_exit(1);
- }
-
- if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER |
- FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY))
- != 0) {
- msyslog(LOG_ERR, "invalid flags (%ld) in file %s",
- intval[TOK_FLAGS], name);
- resolver_exit(1);
- }
-
- flags = 0;
- if (intval[TOK_FLAGS] & FLAG_AUTHENABLE)
- flags |= CONF_FLAG_AUTHENABLE;
- if (intval[TOK_FLAGS] & FLAG_PREFER)
- flags |= CONF_FLAG_PREFER;
- if (intval[TOK_FLAGS] & FLAG_NOSELECT)
- flags |= CONF_FLAG_NOSELECT;
- if (intval[TOK_FLAGS] & FLAG_BURST)
- flags |= CONF_FLAG_BURST;
- if (intval[TOK_FLAGS] & FLAG_IBURST)
- flags |= CONF_FLAG_IBURST;
- if (intval[TOK_FLAGS] & FLAG_SKEY)
- flags |= CONF_FLAG_SKEY;
-
- /*
- * This is as good as we can check it. Add it in.
- */
- addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
- (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
- (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL],
- intval[TOK_KEYID], token[TOK_KEYSTR], (u_char)intval[TOK_PEERAF]);
- }
-}
-
-
-/*
- * doconfigure - attempt to resolve names and configure the server
- */
-static void
-doconfigure(
- int dores
- )
-{
- register struct conf_entry *ce;
- register struct conf_entry *ceremove;
-
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO, "Running doconfigure %s DNS",
- dores ? "with" : "without" );
-#endif
-
- if (dores) /* Reload /etc/resolv.conf - bug 1226 */
- res_init();
-
- ce = confentries;
- while (ce != NULL) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "doconfigure: <%s> has peeraddr %s",
- ce->ce_name, stoa(&ce->peer_store));
-#endif
- if (dores && SOCKNUL(&(ce->peer_store))) {
- if (!findhostaddr(ce)) {
-#ifndef IGNORE_DNS_ERRORS
- msyslog(LOG_ERR,
- "couldn't resolve `%s', giving up on it",
- ce->ce_name);
- ceremove = ce;
- ce = ceremove->ce_next;
- removeentry(ceremove);
- continue;
-#endif
- }
- }
-
- if (!SOCKNUL(&ce->peer_store)) {
- if (request(&ce->ce_config)) {
- ceremove = ce;
- ce = ceremove->ce_next;
- removeentry(ceremove);
- continue;
- }
-#ifdef DEBUG
- if (debug > 1) {
- msyslog(LOG_INFO,
- "doconfigure: request() FAILED, maybe next time.");
- }
-#endif
- }
- ce = ce->ce_next;
- }
-}
diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c
index 44e7f80..2b5a003 100644
--- a/contrib/ntp/ntpd/ntp_io.c
+++ b/contrib/ntp/ntpd/ntp_io.c
@@ -7,41 +7,61 @@
# include <config.h>
#endif
+#include <stdio.h>
+#include <signal.h>
+#ifdef HAVE_FNMATCH_H
+# include <fnmatch.h>
+# if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE)
+# define FNM_CASEFOLD FNM_IGNORECASE
+# endif
+#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */
+# include <sys/sockio.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+
#include "ntp_machine.h"
#include "ntpd.h"
#include "ntp_io.h"
#include "iosignal.h"
+#include "ntp_lists.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
+#include "ntp_worker.h"
#include "ntp_request.h"
-#include "ntp.h"
-#include "ntp_unixtime.h"
+#include "ntp_assert.h"
+#include "timevalops.h"
+#include "timespecops.h"
+#include "ntpd-opts.h"
/* Don't include ISC's version of IPv6 variables and structures */
#define ISC_IPV6_H 1
+#include <isc/mem.h>
#include <isc/interfaceiter.h>
-#include <isc/list.h>
+#include <isc/netaddr.h>
#include <isc/result.h>
+#include <isc/sockaddr.h>
#ifdef SIM
#include "ntpsim.h"
#endif
-#include <stdio.h>
-#include <signal.h>
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif /* HAVE_SYS_PARAM_H */
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */
-# include <sys/sockio.h>
-#endif
-#ifdef HAVE_SYS_UIO_H
-# include <sys/uio.h>
+#ifdef HAS_ROUTING_SOCKET
+# include <net/route.h>
+# ifdef HAVE_RTNETLINK
+# include <linux/rtnetlink.h>
+# endif
#endif
+
/*
* setsockopt does not always have the same arg declaration
* across all platforms. If it's not defined we make it empty
@@ -51,63 +71,76 @@
#define SETSOCKOPT_ARG_CAST
#endif
-/*
- * Set up some macros to look for IPv6 and IPv6 multicast
- */
-
-#if defined(ISC_PLATFORM_HAVEIPV6) && !defined(DISABLE_IPV6)
-
-#define INCLUDE_IPV6_SUPPORT
-
-#if defined(INCLUDE_IPV6_SUPPORT) && defined(IPV6_JOIN_GROUP) && defined(IPV6_LEAVE_GROUP)
-#define INCLUDE_IPV6_MULTICAST_SUPPORT
+extern int listen_to_virtual_ips;
-#endif /* IPV6 Multicast Support */
-#endif /* IPv6 Support */
+#ifndef IPTOS_DSCP_EF
+#define IPTOS_DSCP_EF 0xb8
+#endif
+int qos = IPTOS_DSCP_EF; /* QoS RFC3246 */
-#ifdef INCLUDE_IPV6_SUPPORT
-#include <netinet/in.h>
-#include <net/if_var.h>
-#include <netinet/in_var.h>
-#endif /* !INCLUDE_IPV6_SUPPORT */
+#ifdef LEAP_SMEAR
+/* TODO burnicki: This should be moved to ntp_timer.c, but if we do so
+ * we get a linker error. Since we're running out of time before the leap
+ * second occurs, we let it here where it just works.
+ */
+int leap_smear_intv;
+#endif
-extern int listen_to_virtual_ips;
-extern const char *specific_interface;
+/*
+ * NIC rule entry
+ */
+typedef struct nic_rule_tag nic_rule;
+
+struct nic_rule_tag {
+ nic_rule * next;
+ nic_rule_action action;
+ nic_rule_match match_type;
+ char * if_name;
+ sockaddr_u addr;
+ int prefixlen;
+};
-#if defined(SO_TIMESTAMP) && defined(SCM_TIMESTAMP)
-#if defined(CMSG_FIRSTHDR)
-#define HAVE_TIMESTAMP
-#define USE_TIMESTAMP_CMSG
-#ifndef TIMESTAMP_CTLMSGBUF_SIZE
-#define TIMESTAMP_CTLMSGBUF_SIZE 1536 /* moderate default */
-#endif
+/*
+ * NIC rule listhead. Entries are added at the head so that the first
+ * match in the list is the last matching rule specified.
+ */
+nic_rule *nic_rule_list;
+
+
+#if defined(SO_BINTIME) && defined(SCM_BINTIME) && defined(CMSG_FIRSTHDR)
+# define HAVE_PACKET_TIMESTAMP
+# define HAVE_BINTIME
+# ifdef BINTIME_CTLMSGBUF_SIZE
+# define CMSG_BUFSIZE BINTIME_CTLMSGBUF_SIZE
+# else
+# define CMSG_BUFSIZE 1536 /* moderate default */
+# endif
+#elif defined(SO_TIMESTAMPNS) && defined(SCM_TIMESTAMPNS) && defined(CMSG_FIRSTHDR)
+# define HAVE_PACKET_TIMESTAMP
+# define HAVE_TIMESTAMPNS
+# ifdef TIMESTAMPNS_CTLMSGBUF_SIZE
+# define CMSG_BUFSIZE TIMESTAMPNS_CTLMSGBUF_SIZE
+# else
+# define CMSG_BUFSIZE 1536 /* moderate default */
+# endif
+#elif defined(SO_TIMESTAMP) && defined(SCM_TIMESTAMP) && defined(CMSG_FIRSTHDR)
+# define HAVE_PACKET_TIMESTAMP
+# define HAVE_TIMESTAMP
+# ifdef TIMESTAMP_CTLMSGBUF_SIZE
+# define CMSG_BUFSIZE TIMESTAMP_CTLMSGBUF_SIZE
+# else
+# define CMSG_BUFSIZE 1536 /* moderate default */
+# endif
#else
/* fill in for old/other timestamp interfaces */
#endif
-#endif
#if defined(SYS_WINNT)
-#include <transmitbuff.h>
+#include "win32_io.h"
#include <isc/win32os.h>
-/*
- * Define this macro to control the behavior of connection
- * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823
- * for details.
- * NOTE: This requires that Windows 2000 systems install Service Pack 2
- * or later.
- */
-#ifndef SIO_UDP_CONNRESET
-#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
/*
- * Windows C runtime ioctl() can't deal properly with sockets,
- * map to ioctlsocket for this source file.
- */
-#define ioctl(fd, opt, val) ioctlsocket((fd), (opt), (u_long *)(val))
-#endif /* SYS_WINNT */
-
-/*
* We do asynchronous input using the SIGIO facility. A number of
* recvbuf buffers are preallocated for input. In the signal
* handler we poll to see which sockets are ready and read the
@@ -130,8 +163,8 @@ extern const char *specific_interface;
volatile u_long packets_dropped; /* total number of packets dropped on reception */
volatile u_long packets_ignored; /* packets received on wild card interface */
volatile u_long packets_received; /* total number of packets received */
-u_long packets_sent; /* total number of packets sent */
-u_long packets_notsent; /* total number of packets which couldn't be sent */
+ u_long packets_sent; /* total number of packets sent */
+ u_long packets_notsent; /* total number of packets which couldn't be sent */
volatile u_long handler_calls; /* number of calls to interrupt handler */
volatile u_long handler_pkts; /* number of pkts received by handler */
@@ -140,13 +173,15 @@ u_long io_timereset; /* time counters were reset */
/*
* Interface stuff
*/
-struct interface *any_interface; /* default ipv4 interface */
-struct interface *any6_interface; /* default ipv6 interface */
-struct interface *loopback_interface; /* loopback ipv4 interface */
+endpt * any_interface; /* wildcard ipv4 interface */
+endpt * any6_interface; /* wildcard ipv6 interface */
+endpt * loopback_interface; /* loopback ipv4 interface */
+isc_boolean_t broadcast_client_enabled; /* is broadcast client enabled */
+u_int sys_ifnum; /* next .ifnum to assign */
int ninterfaces; /* Total number of interfaces */
-volatile int disable_dynamic_updates; /* when set to != 0 dynamic updates won't happen */
+int disable_dynamic_updates; /* scan interfaces once only */
#ifdef REFCLOCK
/*
@@ -156,67 +191,62 @@ volatile int disable_dynamic_updates; /* when set to != 0 dynamic updates won'
static struct refclockio *refio;
#endif /* REFCLOCK */
-
-/*
- * Define what the possible "soft" errors can be. These are non-fatal returns
- * of various network related functions, like recv() and so on.
- *
- * For some reason, BSDI (and perhaps others) will sometimes return <0
- * from recv() but will have errno==0. This is broken, but we have to
- * work around it here.
- */
-#define SOFT_ERROR(e) ((e) == EAGAIN || \
- (e) == EWOULDBLOCK || \
- (e) == EINTR || \
- (e) == 0)
-
/*
* File descriptor masks etc. for call to select
- * Not needed for I/O Completion Ports
+ * Not needed for I/O Completion Ports or anything outside this file
*/
-fd_set activefds;
-int maxactivefd;
+static fd_set activefds;
+static int maxactivefd;
+
/*
* bit alternating value to detect verified interfaces during an update cycle
*/
-static u_char sys_interphase = 0;
+static u_short sys_interphase = 0;
-static struct interface *new_interface P((struct interface *));
-static void add_interface P((struct interface *));
-static int update_interfaces P((u_short, interface_receiver_t, void *));
-static void remove_interface P((struct interface *));
-static struct interface *create_interface P((u_short, struct interface *));
+static endpt * new_interface(endpt *);
+static void add_interface(endpt *);
+static int update_interfaces(u_short, interface_receiver_t,
+ void *);
+static void remove_interface(endpt *);
+static endpt * create_interface(u_short, endpt *);
-static int move_fd P((SOCKET));
+static int is_wildcard_addr (const sockaddr_u *);
/*
* Multicast functions
*/
-static isc_boolean_t addr_ismulticast P((struct sockaddr_storage *));
+static isc_boolean_t addr_ismulticast (sockaddr_u *);
+static isc_boolean_t is_not_bindable (sockaddr_u *,
+ const char *);
+
/*
* Not all platforms support multicast
*/
#ifdef MCAST
-static isc_boolean_t socket_multicast_enable P((struct interface *, int, struct sockaddr_storage *));
-static isc_boolean_t socket_multicast_disable P((struct interface *, struct sockaddr_storage *));
+static isc_boolean_t socket_multicast_enable (endpt *, sockaddr_u *);
+static isc_boolean_t socket_multicast_disable(endpt *, sockaddr_u *);
#endif
#ifdef DEBUG
-static void print_interface P((struct interface *, char *, char *));
-#define DPRINT_INTERFACE(_LVL_, _ARGS_) do { if (debug >= (_LVL_)) { print_interface _ARGS_; } } while (0)
+static void interface_dump (const endpt *);
+static void sockaddr_dump (const sockaddr_u *);
+static void print_interface (const endpt *, const char *, const char *);
+#define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0)
#else
-#define DPRINT_INTERFACE(_LVL_, _ARGS_) do {} while (0)
+#define DPRINT_INTERFACE(level, args) do {} while (0)
#endif
typedef struct vsock vsock_t;
enum desc_type { FD_TYPE_SOCKET, FD_TYPE_FILE };
struct vsock {
- SOCKET fd;
- enum desc_type type;
- ISC_LINK(vsock_t) link;
+ vsock_t * link;
+ SOCKET fd;
+ enum desc_type type;
};
+vsock_t *fd_list;
+
#if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
/*
* async notification processing (e. g. routing sockets)
@@ -226,213 +256,132 @@ struct vsock {
* like e. g. routing sockets
*/
struct asyncio_reader {
- SOCKET fd; /* fd to be read */
- void *data; /* possibly local data */
+ struct asyncio_reader *link; /* the list this is being kept in */
+ SOCKET fd; /* fd to be read */
+ void *data; /* possibly local data */
void (*receiver)(struct asyncio_reader *); /* input handler */
- ISC_LINK(struct asyncio_reader) link; /* the list this is being kept in */
};
-ISC_LIST(struct asyncio_reader) asyncio_reader_list;
+struct asyncio_reader *asyncio_reader_list;
-static void delete_asyncio_reader P((struct asyncio_reader *));
-static struct asyncio_reader *new_asyncio_reader P((void));
-static void add_asyncio_reader P((struct asyncio_reader *, enum desc_type));
-static void remove_asyncio_reader P((struct asyncio_reader *));
+static void delete_asyncio_reader (struct asyncio_reader *);
+static struct asyncio_reader *new_asyncio_reader (void);
+static void add_asyncio_reader (struct asyncio_reader *, enum desc_type);
+static void remove_asyncio_reader (struct asyncio_reader *);
#endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */
-static void init_async_notifications P((void));
-
-static int create_sockets P((u_short));
-static SOCKET open_socket P((struct sockaddr_storage *, int, int, struct interface *));
-static char * fdbits P((int, fd_set *));
-static void set_reuseaddr P((int));
-static isc_boolean_t socket_broadcast_enable P((struct interface *, SOCKET, struct sockaddr_storage *));
-static isc_boolean_t socket_broadcast_disable P((struct interface *, struct sockaddr_storage *));
-
-ISC_LIST(vsock_t) fd_list;
+static void init_async_notifications (void);
+
+static int addr_eqprefix (const sockaddr_u *, const sockaddr_u *,
+ int);
+static int addr_samesubnet (const sockaddr_u *, const sockaddr_u *,
+ const sockaddr_u *, const sockaddr_u *);
+static int create_sockets (u_short);
+static SOCKET open_socket (sockaddr_u *, int, int, endpt *);
+static char * fdbits (int, fd_set *);
+static void set_reuseaddr (int);
+static isc_boolean_t socket_broadcast_enable (struct interface *, SOCKET, sockaddr_u *);
+#ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES
+static isc_boolean_t socket_broadcast_disable (struct interface *, sockaddr_u *);
+#endif
typedef struct remaddr remaddr_t;
struct remaddr {
- struct sockaddr_storage addr;
- struct interface *interface;
- ISC_LINK(remaddr_t) link;
+ remaddr_t * link;
+ sockaddr_u addr;
+ endpt * ep;
};
-ISC_LIST(remaddr_t) remoteaddr_list;
+remaddr_t * remoteaddr_list;
+endpt * ep_list; /* complete endpt list */
+endpt * mc4_list; /* IPv4 mcast-capable unicast endpts */
+endpt * mc6_list; /* IPv6 mcast-capable unicast endpts */
-ISC_LIST(struct interface) inter_list;
+static endpt * wildipv4;
+static endpt * wildipv6;
-static struct interface *wildipv4 = NULL;
-static struct interface *wildipv6 = NULL;
+#ifdef SYS_WINNT
+int accept_wildcard_if_for_winnt;
+#else
+const int accept_wildcard_if_for_winnt = FALSE;
+#endif
-static void add_fd_to_list P((SOCKET, enum desc_type));
-static void close_and_delete_fd_from_list P((SOCKET));
-static void add_addr_to_list P((struct sockaddr_storage *, struct interface *));
-static void delete_addr_from_list P((struct sockaddr_storage *));
-static struct interface *find_addr_in_list P((struct sockaddr_storage *));
-static struct interface *find_flagged_addr_in_list P((struct sockaddr_storage *, int));
-static void create_wildcards P((u_short));
-static isc_boolean_t address_okay P((struct interface *));
-static void convert_isc_if P((isc_interface_t *, struct interface *, u_short));
-static void delete_interface_from_list P((struct interface *));
-static struct interface *getinterface P((struct sockaddr_storage *, int));
-static struct interface *findlocalinterface P((struct sockaddr_storage *, int));
-static struct interface *findlocalcastinterface P((struct sockaddr_storage *, int));
+static void add_fd_to_list (SOCKET, enum desc_type);
+static endpt * find_addr_in_list (sockaddr_u *);
+static endpt * find_flagged_addr_in_list(sockaddr_u *, u_int32);
+static void delete_addr_from_list (sockaddr_u *);
+static void delete_interface_from_list(endpt *);
+static void close_and_delete_fd_from_list(SOCKET);
+static void add_addr_to_list (sockaddr_u *, endpt *);
+static void create_wildcards (u_short);
+static endpt * findlocalinterface (sockaddr_u *, int, int);
+static endpt * findclosestinterface (sockaddr_u *, int);
+#ifdef DEBUG
+static const char * action_text (nic_rule_action);
+#endif
+static nic_rule_action interface_action(char *, sockaddr_u *, u_int32);
+static void convert_isc_if (isc_interface_t *,
+ endpt *, u_short);
+static void calc_addr_distance(sockaddr_u *,
+ const sockaddr_u *,
+ const sockaddr_u *);
+static int cmp_addr_distance(const sockaddr_u *,
+ const sockaddr_u *);
/*
* Routines to read the ntp packets
*/
#if !defined(HAVE_IO_COMPLETION_PORT)
-static inline int read_network_packet P((SOCKET, struct interface *, l_fp));
-static inline int read_refclock_packet P((SOCKET, struct refclockio *, l_fp));
-#endif
-
-#ifdef SYS_WINNT
-/*
- * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom
- * to not work correctly, returning a WSACONNRESET error when a WSASendTo
- * fails with an "ICMP port unreachable" response and preventing the
- * socket from using the WSARecvFrom in subsequent operations.
- * The function below fixes this, but requires that Windows 2000
- * Service Pack 2 or later be installed on the system. NT 4.0
- * systems are not affected by this and work correctly.
- * See Microsoft Knowledge Base Article Q263823 for details of this.
- */
-void
-connection_reset_fix(
- SOCKET fd,
- struct sockaddr_storage *addr
- )
-{
- DWORD dwBytesReturned = 0;
- BOOL bNewBehavior = FALSE;
- DWORD status;
-
- /*
- * disable bad behavior using IOCTL: SIO_UDP_CONNRESET
- * NT 4.0 has no problem
- */
- if (isc_win32os_majorversion() >= 5) {
- status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
- sizeof(bNewBehavior), NULL, 0,
- &dwBytesReturned, NULL, NULL);
- if (SOCKET_ERROR == status)
- netsyslog(LOG_ERR, "connection_reset_fix() "
- "failed for address %s: %m",
- stoa(addr));
- }
-}
-#endif
-
-/*
- * on Unix systems the stdio library typically
- * makes use of file descriptors in the lower
- * integer range. stdio usually will make use
- * of the file descriptor in the range of
- * [0..FOPEN_MAX)
- * in order to keep this range clean for socket
- * file descriptors we attempt to move them above
- * FOPEM_MAX. This is not as easy as it sounds as
- * FOPEN_MAX changes from implementation to implementation
- * and may exceed to current file decriptor limits.
- * We are using following strategy:
- * - keep a current socket fd boundary initialized with
- * max(0, min(getdtablesize() - FD_CHUNK, FOPEN_MAX))
- * - attempt to move the descriptor to the boundary or
- * above.
- * - if that fails and boundary > 0 set boundary
- * to min(0, socket_fd_boundary - FD_CHUNK)
- * -> retry
- * if failure and boundary == 0 return old fd
- * - on success close old fd return new fd
- *
- * effects:
- * - fds will be moved above the socket fd boundary
- * if at all possible.
- * - the socket boundary will be reduced until
- * allocation is possible or 0 is reached - at this
- * point the algrithm will be disabled
- */
-static int move_fd(SOCKET fd)
-{
-#if !defined(SYS_WINNT) && defined(F_DUPFD)
-#ifndef FD_CHUNK
-#define FD_CHUNK 10
+static inline int read_network_packet (SOCKET, struct interface *, l_fp);
+static void ntpd_addremove_io_fd (int, int, int);
+static input_handler_t input_handler;
+#ifdef REFCLOCK
+static inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp);
#endif
-/*
- * number of fds we would like to have for
- * stdio FILE* available.
- * we can pick a "low" number as our use of
- * FILE* is limited to log files and temporarily
- * to data and config files. Except for log files
- * we don't keep the other FILE* open beyond the
- * scope of the function that opened it.
- */
-#ifndef FD_PREFERRED_SOCKBOUNDARY
-#define FD_PREFERRED_SOCKBOUNDARY 48
#endif
-#ifndef HAVE_GETDTABLESIZE
-/*
- * if we have no idea about the max fd value set up things
- * so we will start at FOPEN_MAX
- */
-#define getdtablesize() (FOPEN_MAX+FD_CHUNK)
-#endif
-#ifndef FOPEN_MAX
-#define FOPEN_MAX 20 /* assume that for the lack of anything better */
-#endif
- static SOCKET socket_boundary = -1;
- SOCKET newfd;
- /*
- * check whether boundary has be set up
- * already
- */
- if (socket_boundary == -1) {
- socket_boundary = max(0, min(getdtablesize() - FD_CHUNK,
- min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
-#ifdef DEBUG
- msyslog(LOG_DEBUG, "ntp_io: estimated max descriptors: %d, initial socket boundary: %d",
- getdtablesize(), socket_boundary);
-#endif
+#ifndef HAVE_IO_COMPLETION_PORT
+void
+maintain_activefds(
+ int fd,
+ int closing
+ )
+{
+ int i;
+
+ if (fd < 0 || fd >= FD_SETSIZE) {
+ msyslog(LOG_ERR,
+ "Too many sockets in use, FD_SETSIZE %d exceeded by fd %d",
+ FD_SETSIZE, fd);
+ exit(1);
}
- /*
- * Leave a space for stdio to work in. potentially moving the
- * socket_boundary lower until allocation succeeds.
- */
- do {
- if (fd >= 0 && fd < socket_boundary) {
- /* inside reserved range: attempt to move fd */
- newfd = fcntl(fd, F_DUPFD, socket_boundary);
-
- if (newfd != -1) {
- /* success: drop the old one - return the new one */
- (void)close(fd);
- return (newfd);
- }
- } else {
- /* outside reserved range: no work - return the original one */
- return (fd);
+ if (!closing) {
+ FD_SET(fd, &activefds);
+ maxactivefd = max(fd, maxactivefd);
+ } else {
+ FD_CLR(fd, &activefds);
+ if (maxactivefd && fd == maxactivefd) {
+ for (i = maxactivefd - 1; i >= 0; i--)
+ if (FD_ISSET(i, &activefds)) {
+ maxactivefd = i;
+ break;
+ }
+ NTP_INSIST(fd != maxactivefd);
}
- socket_boundary = max(0, socket_boundary - FD_CHUNK);
-#ifdef DEBUG
- msyslog(LOG_DEBUG, "ntp_io: selecting new socket boundary: %d",
- socket_boundary);
-#endif
- } while (socket_boundary > 0);
-#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
- return (fd);
+ }
}
+#endif /* !HAVE_IO_COMPLETION_PORT */
+
#ifdef DEBUG_TIMING
/*
* collect timing information for various processing
- * paths. currently we only pass then on to the file
+ * paths. currently we only pass them on to the file
* for later processing. this could also do histogram
* based analysis in other to reduce the load (and skew)
* dur to the file output
@@ -440,16 +389,19 @@ static int move_fd(SOCKET fd)
void
collect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts)
{
- char buf[2048];
-
- snprintf(buf, sizeof(buf), "%s %d %s %s",
- (rb != NULL) ?
- ((rb->dstadr) ? stoa(&rb->recv_srcadr) : "-REFCLOCK-") : "-",
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "%s %d %s %s",
+ (rb != NULL)
+ ? ((rb->dstadr != NULL)
+ ? stoa(&rb->recv_srcadr)
+ : "-REFCLOCK-")
+ : "-",
count, lfptoa(dts, 9), tag);
record_timing_stats(buf);
}
#endif
-
+
/*
* About dynamic interfaces, sockets, reception and more...
*
@@ -459,7 +411,7 @@ collect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts)
* to bind to to the interface address on NTP_PORT so that
* all wild and specific bindings for NTP_PORT are taken by ntpd
* to avoid other daemons messing with the time or sockets.
- * - all interfaces keep a list of peers that are referencing
+ * - all interfaces keep a list of peers that are referencing
* the interface in order to quickly re-assign the peers to
* new interface in case an interface is deleted (=> gone from system or
* down)
@@ -483,114 +435,95 @@ collect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts)
* but a list of interfaces that represent a unique address as determined by the kernel
* by the procedure in findlocalinterface. Thus it is perfectly legal to see only
* one representative of a group of real interfaces if they share the same address.
- *
+ *
* Frank Kardel 20050910
*/
/*
- * init_io - initialize I/O data structures and call socket creation routine
+ * init_io - initialize I/O module.
*/
void
init_io(void)
{
-#ifdef SYS_WINNT
- init_io_completion_port();
-
- if (!Win32InitSockets())
- {
- netsyslog(LOG_ERR, "No useable winsock.dll: %m");
- exit(1);
- }
- init_transmitbuff();
-#endif /* SYS_WINNT */
-
- /*
- * Init buffer free list and stat counters
- */
+ /* Init buffer free list and stat counters */
init_recvbuff(RECV_INIT);
+ /* update interface every 5 minutes as default */
+ interface_interval = 300;
- packets_dropped = packets_received = 0;
- packets_ignored = 0;
- packets_sent = packets_notsent = 0;
- handler_calls = handler_pkts = 0;
- io_timereset = 0;
- loopback_interface = NULL;
- any_interface = NULL;
- any6_interface = NULL;
+#ifdef WORK_PIPE
+ addremove_io_fd = &ntpd_addremove_io_fd;
+#endif
-#ifdef REFCLOCK
- refio = NULL;
+#ifdef SYS_WINNT
+ init_io_completion_port();
#endif
#if defined(HAVE_SIGNALED_IO)
- (void) set_signal();
+ (void) set_signal(input_handler);
#endif
+}
- ISC_LIST_INIT(fd_list);
-#if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
- ISC_LIST_INIT(asyncio_reader_list);
-#endif
+static void
+ntpd_addremove_io_fd(
+ int fd,
+ int is_pipe,
+ int remove_it
+ )
+{
+ UNUSED_ARG(is_pipe);
+
+#ifdef HAVE_SIGNALED_IO
+ init_socket_sig(fd);
+#endif /* not HAVE_SIGNALED_IO */
+
+ maintain_activefds(fd, remove_it);
+}
+
+
+/*
+ * io_open_sockets - call socket creation routine
+ */
+void
+io_open_sockets(void)
+{
+ static int already_opened;
- ISC_LIST_INIT(remoteaddr_list);
+ if (already_opened || HAVE_OPT( SAVECONFIGQUIT ))
+ return;
- ISC_LIST_INIT(inter_list);
+ already_opened = 1;
/*
* Create the sockets
*/
BLOCKIO();
- (void) create_sockets(htons(NTP_PORT));
+ create_sockets(NTP_PORT);
UNBLOCKIO();
init_async_notifications();
- DPRINTF(3, ("init_io: maxactivefd %d\n", maxactivefd));
+ DPRINTF(3, ("io_open_sockets: maxactivefd %d\n", maxactivefd));
}
+
#ifdef DEBUG
/*
* function to dump the contents of the interface structure
* for debugging use only.
*/
void
-interface_dump(struct interface *itf)
+interface_dump(const endpt *itf)
{
- u_char* cp;
- int i;
- /* Limit the size of the sockaddr_storage hex dump */
- int maxsize = min(32, sizeof(struct sockaddr_storage));
-
printf("Dumping interface: %p\n", itf);
printf("fd = %d\n", itf->fd);
printf("bfd = %d\n", itf->bfd);
- printf("sin = %s,\n", stoa(&(itf->sin)));
- cp = (u_char*) &(itf->sin);
- for(i = 0; i < maxsize; i++)
- {
- printf("%02x", *cp++);
- if((i+1)%4 == 0)
- printf(" ");
- }
- printf("\n");
- printf("bcast = %s,\n", stoa(&(itf->bcast)));
- cp = (u_char*) &(itf->bcast);
- for(i = 0; i < maxsize; i++)
- {
- printf("%02x", *cp++);
- if((i+1)%4 == 0)
- printf(" ");
- }
- printf("\n");
- printf("mask = %s,\n", stoa(&(itf->mask)));
- cp = (u_char*) &(itf->mask);
- for(i = 0; i < maxsize; i++)
- {
- printf("%02x", *cp++);
- if((i+1)%4 == 0)
- printf(" ");
- }
- printf("\n");
+ printf("sin = %s,\n", stoa(&itf->sin));
+ sockaddr_dump(&itf->sin);
+ printf("bcast = %s,\n", stoa(&itf->bcast));
+ sockaddr_dump(&itf->bcast);
+ printf("mask = %s,\n", stoa(&itf->mask));
+ sockaddr_dump(&itf->mask);
printf("name = %s\n", itf->name);
printf("flags = 0x%08x\n", itf->flags);
printf("last_ttl = %d\n", itf->last_ttl);
@@ -600,40 +533,60 @@ interface_dump(struct interface *itf)
printf("sent = %ld\n", itf->sent);
printf("notsent = %ld\n", itf->notsent);
printf("ifindex = %u\n", itf->ifindex);
- printf("scopeid = %u\n", itf->scopeid);
printf("peercnt = %u\n", itf->peercnt);
printf("phase = %u\n", itf->phase);
}
/*
+ * sockaddr_dump - hex dump the start of a sockaddr_u
+ */
+static void
+sockaddr_dump(const sockaddr_u *psau)
+{
+ /* Limit the size of the sockaddr_in6 hex dump */
+ const int maxsize = min(32, sizeof(psau->sa6));
+ const u_char * cp;
+ int i;
+
+ /* XXX: Should we limit maxsize based on psau->saX.sin_family? */
+ cp = (const void *)&psau->sa6;
+
+ for(i = 0; i < maxsize; i++) {
+ printf("%02x", *cp++);
+ if (!((i + 1) % 4))
+ printf(" ");
+ }
+ printf("\n");
+}
+
+/*
* print_interface - helper to output debug information
*/
static void
-print_interface(struct interface *iface, char *pfx, char *sfx)
+print_interface(const endpt *iface, const char *pfx, const char *sfx)
{
- printf("%sinterface #%d: fd=%d, bfd=%d, name=%s, flags=0x%x, scope=%d, ifindex=%d",
+ printf("%sinterface #%d: fd=%d, bfd=%d, name=%s, flags=0x%x, ifindex=%u, sin=%s",
pfx,
iface->ifnum,
iface->fd,
iface->bfd,
iface->name,
iface->flags,
- iface->scopeid,
- iface->ifindex);
- /* Leave these as three printf calls. */
- printf(", sin=%s",
- stoa((&iface->sin)));
- if (iface->flags & INT_BROADCAST)
- printf(", bcast=%s,",
- stoa((&iface->bcast)));
- if (iface->family == AF_INET)
- printf(", mask=%s",
- stoa((&iface->mask)));
- printf(", %s:%s", iface->ignore_packets == ISC_FALSE ? "Enabled" : "Disabled", sfx);
+ iface->ifindex,
+ stoa(&iface->sin));
+ if (AF_INET == iface->family) {
+ if (iface->flags & INT_BROADCAST)
+ printf(", bcast=%s", stoa(&iface->bcast));
+ printf(", mask=%s", stoa(&iface->mask));
+ }
+ printf(", %s:%s",
+ (iface->ignore_packets)
+ ? "Disabled"
+ : "Enabled",
+ sfx);
if (debug > 4) /* in-depth debugging only */
interface_dump(iface);
}
-
#endif
#if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
@@ -641,15 +594,13 @@ print_interface(struct interface *iface, char *pfx, char *sfx)
* create an asyncio_reader structure
*/
static struct asyncio_reader *
-new_asyncio_reader()
+new_asyncio_reader(void)
{
struct asyncio_reader *reader;
- reader = (struct asyncio_reader *)emalloc(sizeof(struct asyncio_reader));
-
- memset((char *)reader, 0, sizeof(*reader));
- ISC_LINK_INIT(reader, link);
+ reader = emalloc_zero(sizeof(*reader));
reader->fd = INVALID_SOCKET;
+
return reader;
}
@@ -657,7 +608,9 @@ new_asyncio_reader()
* delete a reader
*/
static void
-delete_asyncio_reader(struct asyncio_reader *reader)
+delete_asyncio_reader(
+ struct asyncio_reader *reader
+ )
{
free(reader);
}
@@ -666,19 +619,26 @@ delete_asyncio_reader(struct asyncio_reader *reader)
* add asynchio_reader
*/
static void
-add_asyncio_reader(struct asyncio_reader *reader, enum desc_type type)
+add_asyncio_reader(
+ struct asyncio_reader * reader,
+ enum desc_type type)
{
- ISC_LIST_APPEND(asyncio_reader_list, reader, link);
+ LINK_SLIST(asyncio_reader_list, reader, link);
add_fd_to_list(reader->fd, type);
}
-
+
/*
* remove asynchio_reader
*/
static void
-remove_asyncio_reader(struct asyncio_reader *reader)
+remove_asyncio_reader(
+ struct asyncio_reader *reader
+ )
{
- ISC_LIST_UNLINK_TYPE(asyncio_reader_list, reader, link, struct asyncio_reader);
+ struct asyncio_reader *unlinked;
+
+ UNLINK_SLIST(unlinked, asyncio_reader_list, reader, link,
+ struct asyncio_reader);
if (reader->fd != INVALID_SOCKET)
close_and_delete_fd_from_list(reader->fd);
@@ -687,366 +647,874 @@ remove_asyncio_reader(struct asyncio_reader *reader)
}
#endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */
+
+/* compare two sockaddr prefixes */
+static int
+addr_eqprefix(
+ const sockaddr_u * a,
+ const sockaddr_u * b,
+ int prefixlen
+ )
+{
+ isc_netaddr_t isc_a;
+ isc_netaddr_t isc_b;
+ isc_sockaddr_t isc_sa;
+
+ ZERO(isc_sa);
+ memcpy(&isc_sa.type, a, min(sizeof(isc_sa.type), sizeof(*a)));
+ isc_netaddr_fromsockaddr(&isc_a, &isc_sa);
+
+ ZERO(isc_sa);
+ memcpy(&isc_sa.type, b, min(sizeof(isc_sa.type), sizeof(*b)));
+ isc_netaddr_fromsockaddr(&isc_b, &isc_sa);
+
+ return (int)isc_netaddr_eqprefix(&isc_a, &isc_b,
+ (u_int)prefixlen);
+}
+
+
+static int
+addr_samesubnet(
+ const sockaddr_u * a,
+ const sockaddr_u * a_mask,
+ const sockaddr_u * b,
+ const sockaddr_u * b_mask
+ )
+{
+ const u_int32 * pa;
+ const u_int32 * pa_limit;
+ const u_int32 * pb;
+ const u_int32 * pm;
+ size_t loops;
+
+ NTP_REQUIRE(AF(a) == AF(a_mask));
+ NTP_REQUIRE(AF(b) == AF(b_mask));
+ /*
+ * With address and mask families verified to match, comparing
+ * the masks also validates the address's families match.
+ */
+ if (!SOCK_EQ(a_mask, b_mask))
+ return FALSE;
+
+ if (IS_IPV6(a)) {
+ loops = sizeof(NSRCADR6(a)) / sizeof(*pa);
+ pa = (const void *)&NSRCADR6(a);
+ pb = (const void *)&NSRCADR6(b);
+ pm = (const void *)&NSRCADR6(a_mask);
+ } else {
+ loops = sizeof(NSRCADR(a)) / sizeof(*pa);
+ pa = (const void *)&NSRCADR(a);
+ pb = (const void *)&NSRCADR(b);
+ pm = (const void *)&NSRCADR(a_mask);
+ }
+ for (pa_limit = pa + loops; pa < pa_limit; pa++, pb++, pm++)
+ if ((*pa & *pm) != (*pb & *pm))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Code to tell if we have an IP address
+ * If we have then return the sockaddr structure
+ * and set the return value
+ * see the bind9/getaddresses.c for details
+ */
+int
+is_ip_address(
+ const char * host,
+ u_short af,
+ sockaddr_u * addr
+ )
+{
+ struct in_addr in4;
+ struct addrinfo hints;
+ struct addrinfo *result;
+ struct sockaddr_in6 *resaddr6;
+ char tmpbuf[128];
+ char *pch;
+
+ NTP_REQUIRE(host != NULL);
+ NTP_REQUIRE(addr != NULL);
+
+ ZERO_SOCK(addr);
+
+ /*
+ * Try IPv4, then IPv6. In order to handle the extended format
+ * for IPv6 scoped addresses (address%scope_ID), we'll use a local
+ * working buffer of 128 bytes. The length is an ad-hoc value, but
+ * should be enough for this purpose; the buffer can contain a string
+ * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
+ * addresses (up to 46 bytes), the delimiter character and the
+ * terminating NULL character.
+ */
+ if (AF_UNSPEC == af || AF_INET == af)
+ if (inet_pton(AF_INET, host, &in4) == 1) {
+ AF(addr) = AF_INET;
+ SET_ADDR4N(addr, in4.s_addr);
+
+ return TRUE;
+ }
+
+ if (AF_UNSPEC == af || AF_INET6 == af)
+ if (sizeof(tmpbuf) > strlen(host)) {
+ if ('[' == host[0]) {
+ strlcpy(tmpbuf, &host[1], sizeof(tmpbuf));
+ pch = strchr(tmpbuf, ']');
+ if (pch != NULL)
+ *pch = '\0';
+ } else {
+ strlcpy(tmpbuf, host, sizeof(tmpbuf));
+ }
+ ZERO(hints);
+ hints.ai_family = AF_INET6;
+ hints.ai_flags |= AI_NUMERICHOST;
+ if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) {
+ AF(addr) = AF_INET6;
+ resaddr6 = (struct sockaddr_in6 *)result->ai_addr;
+ SET_ADDR6N(addr, resaddr6->sin6_addr);
+ SET_SCOPE(addr, resaddr6->sin6_scope_id);
+
+ freeaddrinfo(result);
+ return TRUE;
+ }
+ }
+ /*
+ * If we got here it was not an IP address
+ */
+ return FALSE;
+}
+
+
/*
* interface list enumerator - visitor pattern
*/
void
-interface_enumerate(interface_receiver_t receiver, void *data)
+interface_enumerate(
+ interface_receiver_t receiver,
+ void * data
+ )
{
interface_info_t ifi;
- struct interface *interf;
ifi.action = IFS_EXISTS;
-
- for (interf = ISC_LIST_HEAD(inter_list);
- interf != NULL;
- interf = ISC_LIST_NEXT(interf, link)) {
- ifi.interface = interf;
- receiver(data, &ifi);
- }
+ for (ifi.ep = ep_list; ifi.ep != NULL; ifi.ep = ifi.ep->elink)
+ (*receiver)(data, &ifi);
}
/*
* do standard initialization of interface structure
*/
static void
-init_interface(struct interface *interface)
+init_interface(
+ endpt *ep
+ )
{
- memset((char *)interface, 0, sizeof(struct interface));
- ISC_LINK_INIT(interface, link);
- ISC_LIST_INIT(interface->peers);
- interface->fd = INVALID_SOCKET;
- interface->bfd = INVALID_SOCKET;
- interface->num_mcast = 0;
- interface->received = 0;
- interface->sent = 0;
- interface->notsent = 0;
- interface->peercnt = 0;
- interface->phase = sys_interphase;
+ ZERO(*ep);
+ ep->fd = INVALID_SOCKET;
+ ep->bfd = INVALID_SOCKET;
+ ep->phase = sys_interphase;
}
+
/*
* create new interface structure initialize from
* template structure or via standard initialization
* function
*/
static struct interface *
-new_interface(struct interface *interface)
+new_interface(
+ struct interface *interface
+ )
{
- static u_int sys_ifnum = 0;
+ struct interface * iface;
- struct interface *iface = (struct interface *)emalloc(sizeof(struct interface));
+ iface = emalloc(sizeof(*iface));
- if (interface != NULL)
- {
- memcpy((char*)iface, (char*)interface, sizeof(*interface));
- }
- else
- {
+ if (NULL == interface)
init_interface(iface);
- }
+ else /* use the template */
+ memcpy(iface, interface, sizeof(*iface));
- iface->ifnum = sys_ifnum++; /* count every new instance of an interface in the system */
+ /* count every new instance of an interface in the system */
+ iface->ifnum = sys_ifnum++;
iface->starttime = current_time;
return iface;
}
+
/*
* return interface storage into free memory pool
*/
-static void
-delete_interface(struct interface *interface)
+static inline void
+delete_interface(
+ endpt *ep
+ )
{
- free(interface);
+ free(ep);
}
+
/*
* link interface into list of known interfaces
*/
static void
-add_interface(struct interface *interface)
+add_interface(
+ endpt * ep
+ )
{
- static struct interface *listhead = NULL;
-
+ endpt ** pmclisthead;
+ endpt * scan;
+ endpt * scan_next;
+ endpt * unlinked;
+ sockaddr_u * addr;
+ int ep_local;
+ int scan_local;
+ int same_subnet;
+ int ep_univ_iid; /* iface ID from MAC address */
+ int scan_univ_iid; /* see RFC 4291 */
+ int ep_privacy; /* random local iface ID */
+ int scan_privacy; /* see RFC 4941 */
+ int rc;
+
+ /* Calculate the refid */
+ ep->addr_refid = addr2refid(&ep->sin);
+ /* link at tail so ntpdc -c ifstats index increases each row */
+ LINK_TAIL_SLIST(ep_list, ep, elink, endpt);
+ ninterfaces++;
+#ifdef MCAST
+ /* the rest is for enabled multicast-capable addresses only */
+ if (ep->ignore_packets || !(INT_MULTICAST & ep->flags) ||
+ INT_LOOPBACK & ep->flags)
+ return;
+# ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
+ if (AF_INET6 == ep->family)
+ return;
+# endif
+ pmclisthead = (AF_INET == ep->family)
+ ? &mc4_list
+ : &mc6_list;
+
+ if (AF_INET6 == ep->family) {
+ ep_local =
+ IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&ep->sin)) ||
+ IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(&ep->sin));
+ ep_univ_iid = IS_IID_UNIV(&ep->sin);
+ ep_privacy = !!(INT_PRIVACY & ep->flags);
+ } else {
+ ep_local = FALSE;
+ ep_univ_iid = FALSE;
+ ep_privacy = FALSE;
+ }
+ DPRINTF(4, ("add_interface mcast-capable %s%s%s%s\n",
+ stoa(&ep->sin),
+ (ep_local) ? " link/scope-local" : "",
+ (ep_univ_iid) ? " univ-IID" : "",
+ (ep_privacy) ? " privacy" : ""));
/*
- * For ntpd, the first few interfaces (wildcard, localhost)
- * will never be removed. This means inter_list.head is
- * unchanging once initialized. Take advantage of that to
- * watch for changes and catch corruption earlier. This
- * helped track down corruption caused by using FD_SET with
- * a descriptor numerically larger than FD_SETSIZE.
+ * If we have multiple local addresses on the same network
+ * interface, and some are link- or site-local, do not multicast
+ * out from the link-/site-local addresses by default, to avoid
+ * duplicate manycastclient associations between v6 peers using
+ * link-local and global addresses. link-local can still be
+ * chosen using "nic ignore myv6globalprefix::/64".
+ * Similarly, if we have multiple global addresses from the same
+ * prefix on the same network interface, multicast from one,
+ * preferring EUI-64, then static, then least RFC 4941 privacy
+ * addresses.
*/
- if (NULL == listhead)
- listhead = inter_list.head;
-
- if (listhead != inter_list.head) {
- msyslog(LOG_ERR, "add_interface inter_list.head corrupted: was %p now %p",
- listhead, inter_list.head);
- exit(1);
+ for (scan = *pmclisthead; scan != NULL; scan = scan_next) {
+ scan_next = scan->mclink;
+ if (ep->family != scan->family)
+ continue;
+ if (strcmp(ep->name, scan->name))
+ continue;
+ same_subnet = addr_samesubnet(&ep->sin, &ep->mask,
+ &scan->sin, &scan->mask);
+ if (AF_INET6 == ep->family) {
+ addr = &scan->sin;
+ scan_local =
+ IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) ||
+ IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr));
+ scan_univ_iid = IS_IID_UNIV(addr);
+ scan_privacy = !!(INT_PRIVACY & scan->flags);
+ } else {
+ scan_local = FALSE;
+ scan_univ_iid = FALSE;
+ scan_privacy = FALSE;
+ }
+ DPRINTF(4, ("add_interface mcast-capable scan %s%s%s%s\n",
+ stoa(&scan->sin),
+ (scan_local) ? " link/scope-local" : "",
+ (scan_univ_iid) ? " univ-IID" : "",
+ (scan_privacy) ? " privacy" : ""));
+ if ((ep_local && !scan_local) || (same_subnet &&
+ ((ep_privacy && !scan_privacy) ||
+ (!ep_univ_iid && scan_univ_iid)))) {
+ DPRINTF(4, ("did not add %s to %s of IPv6 multicast-capable list which already has %s\n",
+ stoa(&ep->sin),
+ (ep_local)
+ ? "tail"
+ : "head",
+ stoa(&scan->sin)));
+ return;
+ }
+ if ((scan_local && !ep_local) || (same_subnet &&
+ ((scan_privacy && !ep_privacy) ||
+ (!scan_univ_iid && ep_univ_iid)))) {
+ UNLINK_SLIST(unlinked, *pmclisthead,
+ scan, mclink, endpt);
+ DPRINTF(4, ("%s %s from IPv6 multicast-capable list to add %s\n",
+ (unlinked != scan)
+ ? "Failed to remove"
+ : "removed",
+ stoa(&scan->sin), stoa(&ep->sin)));
+ }
}
/*
- * Calculate the address hash
+ * Add link/site local at the tail of the multicast-
+ * capable unicast interfaces list, so that ntpd will
+ * send from global addresses before link-/site-local
+ * ones.
*/
- interface->addr_refid = addr2refid(&interface->sin);
-
- ISC_LIST_APPEND(inter_list, interface, link);
- ninterfaces++;
+ if (ep_local)
+ LINK_TAIL_SLIST(*pmclisthead, ep, mclink, endpt);
+ else
+ LINK_SLIST(*pmclisthead, ep, mclink);
+ DPRINTF(4, ("added %s to %s of IPv%s multicast-capable unicast local address list\n",
+ stoa(&ep->sin),
+ (ep_local)
+ ? "tail"
+ : "head",
+ (AF_INET == ep->family)
+ ? "4"
+ : "6"));
+
+ if (INVALID_SOCKET == ep->fd)
+ return;
+
+ /*
+ * select the local address from which to send to multicast.
+ */
+ switch (AF(&ep->sin)) {
+
+ case AF_INET :
+ rc = setsockopt(ep->fd, IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (void *)&NSRCADR(&ep->sin),
+ sizeof(NSRCADR(&ep->sin)));
+ if (rc)
+ msyslog(LOG_ERR,
+ "setsockopt IP_MULTICAST_IF %s fails: %m",
+ stoa(&ep->sin));
+ break;
+
+# ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
+ case AF_INET6 :
+ rc = setsockopt(ep->fd, IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ (void *)&ep->ifindex,
+ sizeof(ep->ifindex));
+ /* do not complain if bound addr scope is ifindex */
+ if (rc && ep->ifindex != SCOPE(&ep->sin))
+ msyslog(LOG_ERR,
+ "setsockopt IPV6_MULTICAST_IF %u for %s fails: %m",
+ ep->ifindex, stoa(&ep->sin));
+ break;
+# endif
+ }
+#endif /* MCAST */
}
+
/*
* remove interface from known interface list and clean up
* associated resources
*/
static void
-remove_interface(struct interface *interface)
+remove_interface(
+ endpt * ep
+ )
{
- struct sockaddr_storage resmask;
-
- ISC_LIST_UNLINK_TYPE(inter_list, interface, link, struct interface);
-
- delete_interface_from_list(interface);
-
- if (interface->fd != INVALID_SOCKET)
- {
- msyslog(LOG_INFO, "Deleting interface #%d %s, %s#%d, interface stats: received=%ld, sent=%ld, dropped=%ld, active_time=%ld secs",
- interface->ifnum,
- interface->name,
- stoa((&interface->sin)),
- NTP_PORT, /* XXX should extract port from sin structure */
- interface->received,
- interface->sent,
- interface->notsent,
- current_time - interface->starttime);
-
- close_and_delete_fd_from_list(interface->fd);
+ endpt * unlinked;
+ endpt ** pmclisthead;
+ sockaddr_u resmask;
+
+ UNLINK_SLIST(unlinked, ep_list, ep, elink, endpt);
+ if (!ep->ignore_packets && INT_MULTICAST & ep->flags) {
+ pmclisthead = (AF_INET == ep->family)
+ ? &mc4_list
+ : &mc6_list;
+ UNLINK_SLIST(unlinked, *pmclisthead, ep, mclink, endpt);
+ DPRINTF(4, ("%s %s IPv%s multicast-capable unicast local address list\n",
+ stoa(&ep->sin),
+ (unlinked != NULL)
+ ? "removed from"
+ : "not found on",
+ (AF_INET == ep->family)
+ ? "4"
+ : "6"));
}
-
- if (interface->bfd != INVALID_SOCKET)
- {
- msyslog(LOG_INFO, "Deleting interface #%d %s, broadcast address %s#%d",
- interface->ifnum,
- interface->name,
- stoa((&interface->bcast)),
- (u_short) NTP_PORT); /* XXX extract port from sin structure */
- close_and_delete_fd_from_list(interface->bfd);
+ delete_interface_from_list(ep);
+
+ if (ep->fd != INVALID_SOCKET) {
+ msyslog(LOG_INFO,
+ "Deleting interface #%d %s, %s#%d, interface stats: received=%ld, sent=%ld, dropped=%ld, active_time=%ld secs",
+ ep->ifnum,
+ ep->name,
+ stoa(&ep->sin),
+ SRCPORT(&ep->sin),
+ ep->received,
+ ep->sent,
+ ep->notsent,
+ current_time - ep->starttime);
+ close_and_delete_fd_from_list(ep->fd);
+ ep->fd = INVALID_SOCKET;
+ }
+
+ if (ep->bfd != INVALID_SOCKET) {
+ msyslog(LOG_INFO,
+ "stop listening for broadcasts to %s on interface #%d %s",
+ stoa(&ep->bcast), ep->ifnum, ep->name);
+ close_and_delete_fd_from_list(ep->bfd);
+ ep->bfd = INVALID_SOCKET;
+ ep->flags &= ~INT_BCASTOPEN;
}
ninterfaces--;
- ntp_monclearinterface(interface);
+ mon_clearinterface(ep);
/* remove restrict interface entry */
-
- /*
- * Blacklist bound interface address
- */
- SET_HOSTMASK(&resmask, interface->sin.ss_family);
- hack_restrict(RESTRICT_REMOVEIF, &interface->sin, &resmask,
- RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE);
+ SET_HOSTMASK(&resmask, AF(&ep->sin));
+ hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask,
+ RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0);
}
+
static void
-list_if_listening(struct interface *interface, u_short port)
+log_listen_address(
+ endpt * ep
+ )
{
- msyslog(LOG_INFO, "Listening on interface #%d %s, %s#%d %s",
- interface->ifnum,
- interface->name,
- stoa((&interface->sin)),
- ntohs( (u_short) port),
- (interface->ignore_packets == ISC_FALSE) ?
- "Enabled": "Disabled");
+ msyslog(LOG_INFO, "%s on %d %s %s",
+ (ep->ignore_packets)
+ ? "Listen and drop"
+ : "Listen normally",
+ ep->ifnum,
+ ep->name,
+ sptoa(&ep->sin));
}
+
static void
-create_wildcards(u_short port) {
- isc_boolean_t okipv4 = ISC_TRUE;
+create_wildcards(
+ u_short port
+ )
+{
+ int v4wild;
+#ifdef INCLUDE_IPV6_SUPPORT
+ int v6wild;
+#endif
+ sockaddr_u wildaddr;
+ nic_rule_action action;
+ struct interface * wildif;
+
/*
- * create pseudo-interface with wildcard IPv4 address
+ * silence "potentially uninitialized" warnings from VC9
+ * failing to follow the logic. Ideally action could remain
+ * uninitialized, and the memset be the first statement under
+ * the first if (v4wild).
*/
-#ifdef IPV6_V6ONLY
- if(isc_net_probeipv4() != ISC_R_SUCCESS)
- okipv4 = ISC_FALSE;
-#endif
-
- if(okipv4 == ISC_TRUE) {
- struct interface *interface = new_interface(NULL);
-
- interface->family = AF_INET;
- interface->sin.ss_family = AF_INET;
- ((struct sockaddr_in*)&interface->sin)->sin_addr.s_addr = htonl(INADDR_ANY);
- ((struct sockaddr_in*)&interface->sin)->sin_port = port;
- (void) strncpy(interface->name, "wildcard", sizeof(interface->name));
- interface->mask.ss_family = AF_INET;
- ((struct sockaddr_in*)&interface->mask)->sin_addr.s_addr = htonl(~(u_int32)0);
- interface->flags = INT_BROADCAST | INT_UP | INT_WILDCARD;
- interface->ignore_packets = ISC_TRUE;
-#if defined(MCAST)
- /*
- * enable possible multicast reception on the broadcast socket
- */
- interface->bcast.ss_family = AF_INET;
- ((struct sockaddr_in*)&interface->bcast)->sin_port = port;
- ((struct sockaddr_in*)&interface->bcast)->sin_addr.s_addr = htonl(INADDR_ANY);
-#endif /* MCAST */
- interface->fd = open_socket(&interface->sin,
- interface->flags, 1, interface);
-
- if (interface->fd != INVALID_SOCKET) {
- wildipv4 = interface;
- any_interface = interface;
-
- add_addr_to_list(&interface->sin, interface);
- add_interface(interface);
- list_if_listening(interface, port);
+ action = ACTION_LISTEN;
+ ZERO(wildaddr);
+
+#ifdef INCLUDE_IPV6_SUPPORT
+ /*
+ * create pseudo-interface with wildcard IPv6 address
+ */
+ v6wild = ipv6_works;
+ if (v6wild) {
+ /* set wildaddr to the v6 wildcard address :: */
+ ZERO(wildaddr);
+ AF(&wildaddr) = AF_INET6;
+ SET_ADDR6N(&wildaddr, in6addr_any);
+ SET_PORT(&wildaddr, port);
+ SET_SCOPE(&wildaddr, 0);
+
+ /* check for interface/nic rules affecting the wildcard */
+ action = interface_action(NULL, &wildaddr, 0);
+ v6wild = (ACTION_IGNORE != action);
+ }
+ if (v6wild) {
+ wildif = new_interface(NULL);
+
+ strlcpy(wildif->name, "v6wildcard", sizeof(wildif->name));
+ memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin));
+ wildif->family = AF_INET6;
+ AF(&wildif->mask) = AF_INET6;
+ SET_ONESMASK(&wildif->mask);
+
+ wildif->flags = INT_UP | INT_WILDCARD;
+ wildif->ignore_packets = (ACTION_DROP == action);
+
+ wildif->fd = open_socket(&wildif->sin, 0, 1, wildif);
+
+ if (wildif->fd != INVALID_SOCKET) {
+ wildipv6 = wildif;
+ any6_interface = wildif;
+ add_addr_to_list(&wildif->sin, wildif);
+ add_interface(wildif);
+ log_listen_address(wildif);
} else {
- msyslog(LOG_ERR, "unable to bind to wildcard socket address %s - another process may be running - EXITING",
- stoa((&interface->sin)));
+ msyslog(LOG_ERR,
+ "unable to bind to wildcard address %s - another process may be running - EXITING",
+ stoa(&wildif->sin));
exit(1);
}
+ DPRINT_INTERFACE(2, (wildif, "created ", "\n"));
}
+#endif
-#ifdef INCLUDE_IPV6_SUPPORT
/*
- * create pseudo-interface with wildcard IPv6 address
+ * create pseudo-interface with wildcard IPv4 address
*/
- if (isc_net_probeipv6() == ISC_R_SUCCESS) {
- struct interface *interface = new_interface(NULL);
+ v4wild = ipv4_works;
+ if (v4wild) {
+ /* set wildaddr to the v4 wildcard address 0.0.0.0 */
+ AF(&wildaddr) = AF_INET;
+ SET_ADDR4N(&wildaddr, INADDR_ANY);
+ SET_PORT(&wildaddr, port);
+
+ /* check for interface/nic rules affecting the wildcard */
+ action = interface_action(NULL, &wildaddr, 0);
+ v4wild = (ACTION_IGNORE != action);
+ }
+ if (v4wild) {
+ wildif = new_interface(NULL);
- interface->family = AF_INET6;
- interface->sin.ss_family = AF_INET6;
- ((struct sockaddr_in6*)&interface->sin)->sin6_addr = in6addr_any;
- ((struct sockaddr_in6*)&interface->sin)->sin6_port = port;
-# ifdef ISC_PLATFORM_HAVESCOPEID
- ((struct sockaddr_in6*)&interface->sin)->sin6_scope_id = 0;
-# endif
- (void) strncpy(interface->name, "wildcard", sizeof(interface->name));
- interface->mask.ss_family = AF_INET6;
- memset(&((struct sockaddr_in6*)&interface->mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr));
- interface->flags = INT_UP | INT_WILDCARD;
- interface->ignore_packets = ISC_TRUE;
+ strlcpy(wildif->name, "v4wildcard", sizeof(wildif->name));
+ memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin));
+ wildif->family = AF_INET;
+ AF(&wildif->mask) = AF_INET;
+ SET_ONESMASK(&wildif->mask);
- interface->fd = open_socket(&interface->sin,
- interface->flags, 1, interface);
-
- if (interface->fd != INVALID_SOCKET) {
- wildipv6 = interface;
- any6_interface = interface;
- add_addr_to_list(&interface->sin, interface);
- add_interface(interface);
- list_if_listening(interface, port);
+ wildif->flags = INT_BROADCAST | INT_UP | INT_WILDCARD;
+ wildif->ignore_packets = (ACTION_DROP == action);
+#if defined(MCAST)
+ /*
+ * enable multicast reception on the broadcast socket
+ */
+ AF(&wildif->bcast) = AF_INET;
+ SET_ADDR4N(&wildif->bcast, INADDR_ANY);
+ SET_PORT(&wildif->bcast, port);
+#endif /* MCAST */
+ wildif->fd = open_socket(&wildif->sin, 0, 1, wildif);
+
+ if (wildif->fd != INVALID_SOCKET) {
+ wildipv4 = wildif;
+ any_interface = wildif;
+
+ add_addr_to_list(&wildif->sin, wildif);
+ add_interface(wildif);
+ log_listen_address(wildif);
} else {
- msyslog(LOG_ERR, "unable to bind to wildcard socket address %s - another process may be running - EXITING",
- stoa((&interface->sin)));
+ msyslog(LOG_ERR,
+ "unable to bind to wildcard address %s - another process may be running - EXITING",
+ stoa(&wildif->sin));
exit(1);
}
+ DPRINT_INTERFACE(2, (wildif, "created ", "\n"));
}
-#endif
}
-static isc_boolean_t
-address_okay(struct interface *iface) {
+/*
+ * add_nic_rule() -- insert a rule entry at the head of nic_rule_list.
+ */
+void
+add_nic_rule(
+ nic_rule_match match_type,
+ const char * if_name, /* interface name or numeric address */
+ int prefixlen,
+ nic_rule_action action
+ )
+{
+ nic_rule * rule;
+ isc_boolean_t is_ip;
+
+ rule = emalloc_zero(sizeof(*rule));
+ rule->match_type = match_type;
+ rule->prefixlen = prefixlen;
+ rule->action = action;
+
+ if (MATCH_IFNAME == match_type) {
+ NTP_REQUIRE(NULL != if_name);
+ rule->if_name = estrdup(if_name);
+ } else if (MATCH_IFADDR == match_type) {
+ NTP_REQUIRE(NULL != if_name);
+ /* set rule->addr */
+ is_ip = is_ip_address(if_name, AF_UNSPEC, &rule->addr);
+ NTP_REQUIRE(is_ip);
+ } else
+ NTP_REQUIRE(NULL == if_name);
+
+ LINK_SLIST(nic_rule_list, rule, next);
+}
+
+
+#ifdef DEBUG
+static const char *
+action_text(
+ nic_rule_action action
+ )
+{
+ const char *t;
+
+ switch (action) {
+
+ default:
+ t = "ERROR"; /* quiet uninit warning */
+ DPRINTF(1, ("fatal: unknown nic_rule_action %d\n",
+ action));
+ NTP_ENSURE(0);
+ break;
+
+ case ACTION_LISTEN:
+ t = "listen";
+ break;
+
+ case ACTION_IGNORE:
+ t = "ignore";
+ break;
+
+ case ACTION_DROP:
+ t = "drop";
+ break;
+ }
+
+ return t;
+}
+#endif /* DEBUG */
- DPRINTF(4, ("address_okay: listen Virtual: %d, IF name: %s\n",
- listen_to_virtual_ips, iface->name));
+
+static nic_rule_action
+interface_action(
+ char * if_name,
+ sockaddr_u * if_addr,
+ u_int32 if_flags
+ )
+{
+ nic_rule * rule;
+ int isloopback;
+ int iswildcard;
+
+ DPRINTF(4, ("interface_action: interface %s ",
+ (if_name != NULL) ? if_name : "wildcard"));
+
+ iswildcard = is_wildcard_addr(if_addr);
+ isloopback = !!(INT_LOOPBACK & if_flags);
+
+ /*
+ * Find any matching NIC rule from --interface / -I or ntp.conf
+ * interface/nic rules.
+ */
+ for (rule = nic_rule_list; rule != NULL; rule = rule->next) {
+
+ switch (rule->match_type) {
+
+ case MATCH_ALL:
+ /* loopback and wildcard excluded from "all" */
+ if (isloopback || iswildcard)
+ break;
+ DPRINTF(4, ("nic all %s\n",
+ action_text(rule->action)));
+ return rule->action;
+
+ case MATCH_IPV4:
+ if (IS_IPV4(if_addr)) {
+ DPRINTF(4, ("nic ipv4 %s\n",
+ action_text(rule->action)));
+ return rule->action;
+ }
+ break;
+
+ case MATCH_IPV6:
+ if (IS_IPV6(if_addr)) {
+ DPRINTF(4, ("nic ipv6 %s\n",
+ action_text(rule->action)));
+ return rule->action;
+ }
+ break;
+
+ case MATCH_WILDCARD:
+ if (iswildcard) {
+ DPRINTF(4, ("nic wildcard %s\n",
+ action_text(rule->action)));
+ return rule->action;
+ }
+ break;
+
+ case MATCH_IFADDR:
+ if (rule->prefixlen != -1) {
+ if (addr_eqprefix(if_addr, &rule->addr,
+ rule->prefixlen)) {
+
+ DPRINTF(4, ("subnet address match - %s\n",
+ action_text(rule->action)));
+ return rule->action;
+ }
+ } else
+ if (SOCK_EQ(if_addr, &rule->addr)) {
+
+ DPRINTF(4, ("address match - %s\n",
+ action_text(rule->action)));
+ return rule->action;
+ }
+ break;
+
+ case MATCH_IFNAME:
+ if (if_name != NULL
+#if defined(HAVE_FNMATCH) && defined(FNM_CASEFOLD)
+ && !fnmatch(rule->if_name, if_name, FNM_CASEFOLD)
+#else
+ && !strcasecmp(if_name, rule->if_name)
+#endif
+ ) {
+
+ DPRINTF(4, ("interface name match - %s\n",
+ action_text(rule->action)));
+ return rule->action;
+ }
+ break;
+ }
+ }
/*
- * Always allow the loopback
+ * Unless explicitly disabled such as with "nic ignore ::1"
+ * listen on loopback addresses. Since ntpq and ntpdc query
+ * "localhost" by default, which typically resolves to ::1 and
+ * 127.0.0.1, it's useful to default to listening on both.
*/
- if((iface->flags & INT_LOOPBACK) != 0) {
- DPRINTF(4, ("address_okay: loopback - OK\n"));
- return (ISC_TRUE);
+ if (isloopback) {
+ DPRINTF(4, ("default loopback listen\n"));
+ return ACTION_LISTEN;
}
/*
- * Check if the interface is specified
+ * Treat wildcard addresses specially. If there is no explicit
+ * "nic ... wildcard" or "nic ... 0.0.0.0" or "nic ... ::" rule
+ * default to drop.
*/
- if (specific_interface != NULL) {
- if (strcasecmp(iface->name, specific_interface) == 0) {
- DPRINTF(4, ("address_okay: specific interface name matched - OK\n"));
- return (ISC_TRUE);
- } else {
- DPRINTF(4, ("address_okay: specific interface name NOT matched - FAIL\n"));
- return (ISC_FALSE);
- }
+ if (iswildcard) {
+ DPRINTF(4, ("default wildcard drop\n"));
+ return ACTION_DROP;
}
- else {
- if (listen_to_virtual_ips == 0 &&
- (strchr(iface->name, (int)':') != NULL)) {
- DPRINTF(4, ("address_okay: virtual ip/alias - FAIL\n"));
- return (ISC_FALSE);
- }
+
+ /*
+ * Check for "virtual IP" (colon in the interface name) after
+ * the rules so that "ntpd --interface eth0:1 -novirtualips"
+ * does indeed listen on eth0:1's addresses.
+ */
+ if (!listen_to_virtual_ips && if_name != NULL
+ && (strchr(if_name, ':') != NULL)) {
+
+ DPRINTF(4, ("virtual ip - ignore\n"));
+ return ACTION_IGNORE;
+ }
+
+ /*
+ * If there are no --interface/-I command-line options and no
+ * interface/nic rules in ntp.conf, the default action is to
+ * listen. In the presence of rules from either, the default
+ * is to ignore. This implements ntpd's traditional listen-
+ * every default with no interface listen configuration, and
+ * ensures a single -I eth0 or "nic listen eth0" means do not
+ * listen on any other addresses.
+ */
+ if (NULL == nic_rule_list) {
+ DPRINTF(4, ("default listen\n"));
+ return ACTION_LISTEN;
}
- DPRINTF(4, ("address_okay: OK\n"));
- return (ISC_TRUE);
+ DPRINTF(4, ("implicit ignore\n"));
+ return ACTION_IGNORE;
}
+
static void
-convert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port)
+convert_isc_if(
+ isc_interface_t *isc_if,
+ endpt *itf,
+ u_short port
+ )
{
- itf->scopeid = 0;
- itf->family = (short) isc_if->af;
- strcpy(itf->name, isc_if->name);
-
- if(isc_if->af == AF_INET) {
- itf->sin.ss_family = (u_short) isc_if->af;
- memcpy(&(((struct sockaddr_in*)&itf->sin)->sin_addr),
- &(isc_if->address.type.in),
- sizeof(struct in_addr));
- ((struct sockaddr_in*)&itf->sin)->sin_port = port;
-
- if((isc_if->flags & INTERFACE_F_BROADCAST) != 0) {
+ const u_char v6loop[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1};
+
+ strlcpy(itf->name, isc_if->name, sizeof(itf->name));
+ itf->ifindex = isc_if->ifindex;
+ itf->family = (u_short)isc_if->af;
+ AF(&itf->sin) = itf->family;
+ AF(&itf->mask) = itf->family;
+ AF(&itf->bcast) = itf->family;
+ SET_PORT(&itf->sin, port);
+ SET_PORT(&itf->mask, port);
+ SET_PORT(&itf->bcast, port);
+
+ if (IS_IPV4(&itf->sin)) {
+ NSRCADR(&itf->sin) = isc_if->address.type.in.s_addr;
+ NSRCADR(&itf->mask) = isc_if->netmask.type.in.s_addr;
+
+ if (isc_if->flags & INTERFACE_F_BROADCAST) {
itf->flags |= INT_BROADCAST;
- itf->bcast.ss_family = itf->sin.ss_family;
- memcpy(&(((struct sockaddr_in*)&itf->bcast)->sin_addr),
- &(isc_if->broadcast.type.in),
- sizeof(struct in_addr));
- ((struct sockaddr_in*)&itf->bcast)->sin_port = port;
+ NSRCADR(&itf->bcast) =
+ isc_if->broadcast.type.in.s_addr;
}
-
- itf->mask.ss_family = itf->sin.ss_family;
- memcpy(&(((struct sockaddr_in*)&itf->mask)->sin_addr),
- &(isc_if->netmask.type.in),
- sizeof(struct in_addr));
- ((struct sockaddr_in*)&itf->mask)->sin_port = port;
}
#ifdef INCLUDE_IPV6_SUPPORT
- else if (isc_if->af == AF_INET6) {
- itf->sin.ss_family = (u_short) isc_if->af;
- memcpy(&(((struct sockaddr_in6 *)&itf->sin)->sin6_addr),
- &(isc_if->address.type.in6),
- sizeof(((struct sockaddr_in6 *)&itf->sin)->sin6_addr));
- ((struct sockaddr_in6 *)&itf->sin)->sin6_port = port;
-
-#ifdef ISC_PLATFORM_HAVESCOPEID
- ((struct sockaddr_in6 *)&itf->sin)->sin6_scope_id = isc_netaddr_getzone(&isc_if->address);
- itf->scopeid = isc_netaddr_getzone(&isc_if->address);
-#endif
- itf->mask.ss_family = itf->sin.ss_family;
- memcpy(&(((struct sockaddr_in6 *)&itf->mask)->sin6_addr),
- &(isc_if->netmask.type.in6),
- sizeof(struct in6_addr));
- ((struct sockaddr_in6 *)&itf->mask)->sin6_port = port;
- /* Copy the interface index */
- itf->ifindex = isc_if->ifindex;
+ else if (IS_IPV6(&itf->sin)) {
+ SET_ADDR6N(&itf->sin, isc_if->address.type.in6);
+ SET_ADDR6N(&itf->mask, isc_if->netmask.type.in6);
+
+ SET_SCOPE(&itf->sin, isc_if->address.zone);
}
#endif /* INCLUDE_IPV6_SUPPORT */
/* Process the rest of the flags */
- if((isc_if->flags & INTERFACE_F_UP) != 0)
- itf->flags |= INT_UP;
- if((isc_if->flags & INTERFACE_F_LOOPBACK) != 0)
- itf->flags |= INT_LOOPBACK;
- if((isc_if->flags & INTERFACE_F_POINTTOPOINT) != 0)
- itf->flags |= INT_PPP;
- if((isc_if->flags & INTERFACE_F_MULTICAST) != 0)
- itf->flags |= INT_MULTICAST;
+ itf->flags |=
+ ((INTERFACE_F_UP & isc_if->flags)
+ ? INT_UP : 0)
+ | ((INTERFACE_F_LOOPBACK & isc_if->flags)
+ ? INT_LOOPBACK : 0)
+ | ((INTERFACE_F_POINTTOPOINT & isc_if->flags)
+ ? INT_PPP : 0)
+ | ((INTERFACE_F_MULTICAST & isc_if->flags)
+ ? INT_MULTICAST : 0)
+ | ((INTERFACE_F_PRIVACY & isc_if->flags)
+ ? INT_PRIVACY : 0)
+ ;
+ /*
+ * Clear the loopback flag if the address is not localhost.
+ * http://bugs.ntp.org/1683
+ */
+ if (INT_LOOPBACK & itf->flags) {
+ if (AF_INET == itf->family) {
+ if (127 != (SRCADR(&itf->sin) >> 24))
+ itf->flags &= ~INT_LOOPBACK;
+ } else {
+ if (memcmp(v6loop, NSRCADR6(&itf->sin),
+ sizeof(NSRCADR6(&itf->sin))))
+ itf->flags &= ~INT_LOOPBACK;
+ }
+ }
}
+
/*
* refresh_interface
*
@@ -1057,27 +1525,34 @@ convert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port)
* the socket.
*/
static int
-refresh_interface(struct interface * interface)
+refresh_interface(
+ struct interface * interface
+ )
{
#ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES
- if (interface->fd != INVALID_SOCKET)
- {
+ if (interface->fd != INVALID_SOCKET) {
+ int bcast = (interface->flags & INT_BCASTXMIT) != 0;
+ /* as we forcibly close() the socket remove the
+ broadcast permission indication */
+ if (bcast)
+ socket_broadcast_disable(interface, &interface->sin);
+
close_and_delete_fd_from_list(interface->fd);
+
+ /* create new socket picking up a new first hop binding
+ at connect() time */
interface->fd = open_socket(&interface->sin,
- interface->flags, 0, interface);
+ bcast, 0, interface);
/*
- * reset TTL indication so TTL is is set again
+ * reset TTL indication so TTL is is set again
* next time around
*/
interface->last_ttl = 0;
- return interface->fd != INVALID_SOCKET;
- }
- else
- {
+ return (interface->fd != INVALID_SOCKET);
+ } else
return 0; /* invalid sockets are not refreshable */
- }
#else /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */
- return interface->fd != INVALID_SOCKET;
+ return (interface->fd != INVALID_SOCKET);
#endif /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */
}
@@ -1085,113 +1560,125 @@ refresh_interface(struct interface * interface)
* interface_update - externally callable update function
*/
void
-interface_update(interface_receiver_t receiver, void *data)
+interface_update(
+ interface_receiver_t receiver,
+ void * data)
{
- if (!disable_dynamic_updates) {
- int new_interface_found;
+ int new_interface_found;
- BLOCKIO();
- new_interface_found = update_interfaces(htons(NTP_PORT), receiver, data);
- UNBLOCKIO();
+ if (disable_dynamic_updates)
+ return;
+
+ BLOCKIO();
+ new_interface_found = update_interfaces(NTP_PORT, receiver, data);
+ UNBLOCKIO();
+
+ if (!new_interface_found)
+ return;
- if (new_interface_found) {
#ifdef DEBUG
- msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
+ msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
#endif
-#ifdef SYS_WINNT
- /* wake up the resolver thread */
- if (ResolverEventHandle != NULL)
- SetEvent(ResolverEventHandle);
-#else
- /* write any single byte to the pipe to wake up the resolver process */
- write( resolver_pipe_fd[1], &new_interface_found, 1 );
-#endif
- }
- }
+ interrupt_worker_sleep();
}
+
/*
- * find out if a given interface structure contains
- * a wildcard address
+ * sau_from_netaddr() - convert network address on-wire formats.
+ * Convert from libisc's isc_netaddr_t to NTP's sockaddr_u
*/
+void
+sau_from_netaddr(
+ sockaddr_u *psau,
+ const isc_netaddr_t *pna
+ )
+{
+ ZERO_SOCK(psau);
+ AF(psau) = (u_short)pna->family;
+ switch (pna->family) {
+
+ case AF_INET:
+ memcpy(&psau->sa4.sin_addr, &pna->type.in,
+ sizeof(psau->sa4.sin_addr));
+ break;
+
+ case AF_INET6:
+ memcpy(&psau->sa6.sin6_addr, &pna->type.in6,
+ sizeof(psau->sa6.sin6_addr));
+ break;
+ }
+}
+
+
static int
-is_wildcard_addr(struct sockaddr_storage *sas)
+is_wildcard_addr(
+ const sockaddr_u *psau
+ )
{
- if (sas->ss_family == AF_INET &&
- ((struct sockaddr_in*)sas)->sin_addr.s_addr == htonl(INADDR_ANY))
+ if (IS_IPV4(psau) && !NSRCADR(psau))
return 1;
#ifdef INCLUDE_IPV6_SUPPORT
- if (sas->ss_family == AF_INET6 &&
- memcmp(&((struct sockaddr_in6*)sas)->sin6_addr, &in6addr_any,
- sizeof(in6addr_any)) == 0)
+ if (IS_IPV6(psau) && S_ADDR6_EQ(psau, &in6addr_any))
return 1;
#endif
return 0;
}
+
#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
/*
* enable/disable re-use of wildcard address socket
*/
static void
-set_wildcard_reuse(int family, int on)
+set_wildcard_reuse(
+ u_short family,
+ int on
+ )
{
- int onvalue = 1;
- int offvalue = 0;
- int *onoff;
+ struct interface *any;
SOCKET fd = INVALID_SOCKET;
- onoff = on ? &onvalue : &offvalue;
-
- switch (family) {
- case AF_INET:
- if (any_interface) {
- fd = any_interface->fd;
- }
- break;
-
-#ifdef INCLUDE_IPV6_SUPPORT
- case AF_INET6:
- if (any6_interface) {
- fd = any6_interface->fd;
- }
- break;
-#endif /* !INCLUDE_IPV6_SUPPORT */
- }
+ any = ANY_INTERFACE_BYFAM(family);
+ if (any != NULL)
+ fd = any->fd;
if (fd != INVALID_SOCKET) {
- if (setsockopt(fd, SOL_SOCKET,
- SO_REUSEADDR, (char *)onoff,
- sizeof(*onoff))) {
- netsyslog(LOG_ERR, "set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m", *onoff ? "on" : "off");
- }
- DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n", *onoff ? "ON" : "OFF",
- stoa((family == AF_INET) ?
- &any_interface->sin : &any6_interface->sin)));
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on)))
+ msyslog(LOG_ERR,
+ "set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m",
+ on ? "on" : "off");
+
+ DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n",
+ on ? "on" : "off",
+ stoa(&any->sin)));
}
}
#endif /* OS_NEEDS_REUSEADDR_FOR_IFADDRBIND */
-#ifdef INCLUDE_IPV6_SUPPORT
+
static isc_boolean_t
-is_not_bindable(struct sockaddr *sa, char *name)
+check_flags6(
+ sockaddr_u *psau,
+ const char *name,
+ u_int32 flags6
+ )
{
-#if defined(SIOCGIFAFLAG_IN6) && \
- (defined(IN6_IFF_ANYCAST) || defined(IN6_IFF_NOTREADY))
+#if defined(INCLUDE_IPV6_SUPPORT) && defined(SIOCGIFAFLAG_IN6) && \
+ (defined(IN6_IFF_ANYCAST) || defined(IN6_IFF_NOTREADY))
struct in6_ifreq ifr6;
int fd;
- u_int32_t flags6, exclude = 0;
+ u_int32 exclude = 0;
- if (sa->sa_family != AF_INET6)
+ if (psau->sa.sa_family != AF_INET6)
return ISC_FALSE;
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
return ISC_FALSE;
- memset(&ifr6, 0, sizeof(ifr6));
- memcpy(&ifr6.ifr_addr, (struct sockaddr_in6 *)sa,
- sizeof(struct sockaddr_in6));
- strlcpy(ifr6.ifr_name, name, IF_NAMESIZE);
+ ZERO(ifr6);
+ memcpy(&ifr6.ifr_addr, &psau->sa6, sizeof(ifr6.ifr_addr));
+ strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
if (ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
close(fd);
return ISC_FALSE;
@@ -1206,10 +1693,43 @@ is_not_bindable(struct sockaddr *sa, char *name)
#endif /* !IN6_IFF_NOTREADY */
if ((flags6 & exclude) != 0)
return ISC_TRUE;
-#endif /* !SIOCGIFAFLAG_IN6 || !(IN6_IFF_ANYCAST && IN6_IFF_NOTREADY) */
+#endif /* INCLUDE_IPV6_SUPPORT && SIOCGIFAFLAG_IN6 && (IN6_IFF_ANYCAST && IN6_IFF_NOTREADY) */
return ISC_FALSE;
}
-#endif /* !INCLUDE_IPV6_SUPPORT */
+
+static isc_boolean_t
+is_not_bindable(
+ sockaddr_u *psau,
+ const char *name
+ )
+{
+#ifdef IN6_IFF_ANYCAST
+ return check_flags6(psau, name, IN6_IFF_ANYCAST);
+#else
+ return ISC_FALSE;
+#endif
+}
+
+static isc_boolean_t
+is_valid(
+ sockaddr_u *psau,
+ const char *name
+ )
+{
+ u_int32 flags6;
+
+ flags6 = 0;
+#ifdef IN6_IFF_DEPARTED
+ flags6 |= IN6_IFF_DEPARTED;
+#endif
+#ifdef IN6_IFF_DETACHED
+ flags6 |= IN6_IFF_DETACHED;
+#endif
+#ifdef IN6_IFF_TENTATIVE
+ flags6 |= IN6_IFF_TENTATIVE;
+#endif
+ return check_flags6(psau, name, flags6) ? ISC_FALSE : ISC_TRUE;
+}
/*
* update_interface strategy
@@ -1219,17 +1739,17 @@ is_not_bindable(struct sockaddr *sa, char *name)
* Phase 1:
* forall currently existing interfaces
* if address is known:
- * drop socket - rebind again
+ * drop socket - rebind again
*
* if address is NOT known:
- * attempt to create a new interface entry
+ * attempt to create a new interface entry
*
* Phase 2:
* forall currently known non MCAST and WILDCARD interfaces
* if interface does not match configuration phase (not seen in phase 1):
- * remove interface from known interface list
- * forall peers associated with this interface
- * disconnect peer from this interface
+ * remove interface from known interface list
+ * forall peers associated with this interface
+ * disconnect peer from this interface
*
* Phase 3:
* attempt to re-assign interfaces to peers
@@ -1238,67 +1758,47 @@ is_not_bindable(struct sockaddr *sa, char *name)
static int
update_interfaces(
- u_short port,
- interface_receiver_t receiver,
- void *data
+ u_short port,
+ interface_receiver_t receiver,
+ void * data
)
{
- interface_info_t ifi;
- isc_mem_t *mctx = NULL;
- isc_interfaceiter_t *iter = NULL;
- isc_boolean_t scan_ipv4 = ISC_FALSE;
- isc_boolean_t scan_ipv6 = ISC_FALSE;
- isc_result_t result;
- int new_interface_found = 0;
+ isc_mem_t * mctx = (void *)-1;
+ interface_info_t ifi;
+ isc_interfaceiter_t * iter;
+ isc_result_t result;
+ isc_interface_t isc_if;
+ int new_interface_found;
+ unsigned int family;
+ endpt enumep;
+ endpt * ep;
+ endpt * next_ep;
+
+ DPRINTF(3, ("update_interfaces(%d)\n", port));
- DPRINTF(3, ("update_interfaces(%d)\n", ntohs( (u_short) port)));
-
-#ifdef INCLUDE_IPV6_SUPPORT
- if (isc_net_probeipv6() == ISC_R_SUCCESS)
- scan_ipv6 = ISC_TRUE;
-#if defined(DEBUG)
- else
- if (debug)
- netsyslog(LOG_ERR, "no IPv6 interfaces found");
-#endif
-#endif
- if (isc_net_probeipv6() == ISC_R_SUCCESS)
- scan_ipv6 = ISC_TRUE;
-#if defined(ISC_PLATFORM_HAVEIPV6) && defined(DEBUG)
- else
- if (debug)
- netsyslog(LOG_ERR, "no IPv6 interfaces found");
-#endif
-
- if (isc_net_probeipv4() == ISC_R_SUCCESS)
- scan_ipv4 = ISC_TRUE;
-#ifdef DEBUG
- else
- if(debug)
- netsyslog(LOG_ERR, "no IPv4 interfaces found");
-#endif
/*
* phase one - scan interfaces
* - create those that are not found
* - update those that are found
*/
+ new_interface_found = FALSE;
+ iter = NULL;
result = isc_interfaceiter_create(mctx, &iter);
if (result != ISC_R_SUCCESS)
return 0;
- sys_interphase ^= 0x1; /* toggle system phase for finding untouched (to be deleted) interfaces */
-
+ /*
+ * Toggle system interface scan phase to find untouched
+ * interfaces to be deleted.
+ */
+ sys_interphase ^= 0x1;
+
for (result = isc_interfaceiter_first(iter);
- result == ISC_R_SUCCESS;
- result = isc_interfaceiter_next(iter))
- {
- isc_interface_t isc_if;
- unsigned int family;
- struct interface interface;
- struct interface *iface;
-
+ ISC_R_SUCCESS == result;
+ result = isc_interfaceiter_next(iter)) {
+
result = isc_interfaceiter_current(iter, &isc_if);
if (result != ISC_R_SUCCESS)
@@ -1306,39 +1806,48 @@ update_interfaces(
/* See if we have a valid family to use */
family = isc_if.address.family;
- if (family != AF_INET && family != AF_INET6)
+ if (AF_INET != family && AF_INET6 != family)
continue;
- if (scan_ipv4 == ISC_FALSE && family == AF_INET)
+ if (AF_INET == family && !ipv4_works)
continue;
- if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
+ if (AF_INET6 == family && !ipv6_works)
continue;
+ /* create prototype */
+ init_interface(&enumep);
+
+ convert_isc_if(&isc_if, &enumep, port);
+
+ DPRINT_INTERFACE(4, (&enumep, "examining ", "\n"));
+
/*
- * create prototype
+ * Check if and how we are going to use the interface.
*/
- init_interface(&interface);
+ switch (interface_action(enumep.name, &enumep.sin,
+ enumep.flags)) {
- convert_isc_if(&isc_if, &interface, port);
+ case ACTION_IGNORE:
+ DPRINTF(4, ("ignoring interface %s (%s) - by nic rules\n",
+ enumep.name, stoa(&enumep.sin)));
+ continue;
- /*
- * Check to see if we are going to use the interface
- * If we don't use it we mark it to drop any packet
- * received but we still must create the socket and
- * bind to it. This prevents other apps binding to it
- * and potentially causing problems with more than one
- * process fiddling with the clock
- */
- if (address_okay(&interface) == ISC_TRUE) {
- interface.ignore_packets = ISC_FALSE;
- }
- else {
- interface.ignore_packets = ISC_TRUE;
- }
+ case ACTION_LISTEN:
+ DPRINTF(4, ("listen interface %s (%s) - by nic rules\n",
+ enumep.name, stoa(&enumep.sin)));
+ enumep.ignore_packets = ISC_FALSE;
+ break;
- DPRINT_INTERFACE(4, (&interface, "examining ", "\n"));
+ case ACTION_DROP:
+ DPRINTF(4, ("drop on interface %s (%s) - by nic rules\n",
+ enumep.name, stoa(&enumep.sin)));
+ enumep.ignore_packets = ISC_TRUE;
+ break;
+ }
- if (!(interface.flags & INT_UP)) { /* interfaces must be UP to be usable */
- DPRINTF(4, ("skipping interface %s (%s) - DOWN\n", interface.name, stoa(&interface.sin)));
+ /* interfaces must be UP to be usable */
+ if (!(enumep.flags & INT_UP)) {
+ DPRINTF(4, ("skipping interface %s (%s) - DOWN\n",
+ enumep.name, stoa(&enumep.sin)));
continue;
}
@@ -1347,62 +1856,119 @@ update_interfaces(
* address - some dhcp clients produce that in the
* wild
*/
- if (is_wildcard_addr(&interface.sin))
+ if (is_wildcard_addr(&enumep.sin))
continue;
-#ifdef INCLUDE_IPV6_SUPPORT
- if (is_not_bindable((struct sockaddr *)&interface.sin, isc_if.name))
+ if (is_not_bindable(&enumep.sin, isc_if.name))
continue;
-#endif /* !INCLUDE_IPV6_SUPPORT */
/*
- * map to local *address* in order
- * to map all duplicate interfaces to an interface structure
- * with the appropriate socket (our name space is
- * (ip-address) - NOT (interface name, ip-address))
+ * skip any address that is an invalid state to be used
*/
- iface = getinterface(&interface.sin, INT_WILDCARD);
-
- if (iface && refresh_interface(iface))
- {
+ if (!is_valid(&enumep.sin, isc_if.name))
+ continue;
+
+ /*
+ * map to local *address* in order to map all duplicate
+ * interfaces to an endpt structure with the appropriate
+ * socket. Our name space is (ip-address), NOT
+ * (interface name, ip-address).
+ */
+ ep = getinterface(&enumep.sin, INT_WILDCARD);
+
+ if (ep != NULL && refresh_interface(ep)) {
/*
- * found existing and up to date interface - mark present
+ * found existing and up to date interface -
+ * mark present.
*/
+ if (ep->phase != sys_interphase) {
+ /*
+ * On a new round we reset the name so
+ * the interface name shows up again if
+ * this address is no longer shared.
+ * We reset ignore_packets from the
+ * new prototype to respect any runtime
+ * changes to the nic rules.
+ */
+ strlcpy(ep->name, enumep.name,
+ sizeof(ep->name));
+ ep->ignore_packets =
+ enumep.ignore_packets;
+ } else {
+ /* name collision - rename interface */
+ strlcpy(ep->name, "*multiple*",
+ sizeof(ep->name));
+ }
+
+ DPRINT_INTERFACE(4, (ep, "updating ",
+ " present\n"));
+
+ if (ep->ignore_packets !=
+ enumep.ignore_packets) {
+ /*
+ * We have conflicting configurations
+ * for the interface address. This is
+ * caused by using -I <interfacename>
+ * for an interface that shares its
+ * address with other interfaces. We
+ * can not disambiguate incoming
+ * packets delivered to this socket
+ * without extra syscalls/features.
+ * These are not (commonly) available.
+ * Note this is a more unusual
+ * configuration where several
+ * interfaces share an address but
+ * filtering via interface name is
+ * attempted. We resolve the
+ * configuration conflict by disabling
+ * the processing of received packets.
+ * This leads to no service on the
+ * interface address where the conflict
+ * occurs.
+ */
+ msyslog(LOG_ERR,
+ "WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED",
+ enumep.name, ep->name,
+ stoa(&enumep.sin));
+
+ ep->ignore_packets = ISC_TRUE;
+ }
+
+ ep->phase = sys_interphase;
- iface->phase = sys_interphase;
- DPRINT_INTERFACE(4, (iface, "updating ", " present\n"));
ifi.action = IFS_EXISTS;
- ifi.interface = iface;
- if (receiver)
- receiver(data, &ifi);
- }
- else
- {
+ ifi.ep = ep;
+ if (receiver != NULL)
+ (*receiver)(data, &ifi);
+ } else {
/*
- * this is new or refreshing failed - add to our interface list
- * if refreshing failed we will delete the interface structure in
- * phase 2 as the interface was not marked current. We can bind to
- * the address as the refresh code already closed the offending socket
+ * This is new or refreshing failed - add to
+ * our interface list. If refreshing failed we
+ * will delete the interface structure in phase
+ * 2 as the interface was not marked current.
+ * We can bind to the address as the refresh
+ * code already closed the offending socket
*/
-
- iface = create_interface(port, &interface);
+ ep = create_interface(port, &enumep);
- if (iface)
- {
+ if (ep != NULL) {
ifi.action = IFS_CREATED;
- ifi.interface = iface;
- if (receiver)
- receiver(data, &ifi);
-
- new_interface_found = 1;
-
- DPRINT_INTERFACE(3, (iface, "updating ", " new - created\n"));
- }
- else
- {
- DPRINT_INTERFACE(3, (&interface, "updating ", " new - creation FAILED"));
-
- msyslog(LOG_INFO, "failed to initialize interface for address %s", stoa(&interface.sin));
+ ifi.ep = ep;
+ if (receiver != NULL)
+ (*receiver)(data, &ifi);
+
+ new_interface_found = TRUE;
+ DPRINT_INTERFACE(3,
+ (ep, "updating ",
+ " new - created\n"));
+ } else {
+ DPRINT_INTERFACE(3,
+ (&enumep, "updating ",
+ " new - creation FAILED"));
+
+ msyslog(LOG_INFO,
+ "failed to init interface for address %s",
+ stoa(&enumep.sin));
continue;
}
}
@@ -1411,64 +1977,86 @@ update_interfaces(
isc_interfaceiter_destroy(&iter);
/*
- * phase 2 - delete gone interfaces - reassigning peers to other interfaces
+ * phase 2 - delete gone interfaces - reassigning peers to
+ * other interfaces
*/
- {
- struct interface *interf = ISC_LIST_HEAD(inter_list);
+ for (ep = ep_list; ep != NULL; ep = next_ep) {
+ next_ep = ep->elink;
- while (interf != NULL)
- {
- struct interface *next = ISC_LIST_NEXT(interf, link);
-
- if (!(interf->flags & (INT_WILDCARD|INT_MCASTIF))) {
- /*
- * if phase does not match sys_phase this interface was not
- * enumerated during interface scan - so it is gone and
- * will be deleted here unless it is solely an MCAST/WILDCARD interface
- */
- if (interf->phase != sys_interphase) {
- struct peer *peer;
- DPRINT_INTERFACE(3, (interf, "updating ", "GONE - deleting\n"));
- remove_interface(interf);
-
- ifi.action = IFS_DELETED;
- ifi.interface = interf;
- if (receiver)
- receiver(data, &ifi);
-
- peer = ISC_LIST_HEAD(interf->peers);
- /*
- * disconnect peer from deleted interface
- */
- while (peer != NULL) {
- struct peer *npeer = ISC_LIST_NEXT(peer, ilink);
-
- /*
- * this one just lost it's interface
- */
- set_peerdstadr(peer, NULL);
-
- peer = npeer;
- }
-
- /*
- * update globals in case we lose
- * a loopback interface
- */
- if (interf == loopback_interface)
- loopback_interface = NULL;
-
- delete_interface(interf);
- }
- }
- interf = next;
- }
+ /*
+ * if phase does not match sys_phase this interface was
+ * not enumerated during the last interface scan - so it
+ * is gone and will be deleted here unless it did not
+ * originate from interface enumeration (INT_WILDCARD,
+ * INT_MCASTIF).
+ */
+ if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) ||
+ ep->phase == sys_interphase)
+ continue;
+
+ DPRINT_INTERFACE(3, (ep, "updating ",
+ "GONE - deleting\n"));
+ remove_interface(ep);
+
+ ifi.action = IFS_DELETED;
+ ifi.ep = ep;
+ if (receiver != NULL)
+ (*receiver)(data, &ifi);
+
+ /* disconnect peers from deleted endpt. */
+ while (ep->peers != NULL)
+ set_peerdstadr(ep->peers, NULL);
+
+ /*
+ * update globals in case we lose
+ * a loopback interface
+ */
+ if (ep == loopback_interface)
+ loopback_interface = NULL;
+
+ delete_interface(ep);
}
/*
- * phase 3 - re-configure as the world has changed if necessary
+ * phase 3 - re-configure as the world has possibly changed
+ *
+ * never ever make this conditional again - it is needed to track
+ * routing updates. see bug #2506
*/
refresh_all_peerinterfaces();
+
+ if (broadcast_client_enabled)
+ io_setbclient();
+
+ if (sys_bclient)
+ io_setbclient();
+
+ /*
+ * Check multicast interfaces and try to join multicast groups if
+ * not joined yet.
+ */
+ for (ep = ep_list; ep != NULL; ep = ep->elink) {
+ remaddr_t *entry;
+
+ if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags))
+ continue;
+
+ /* Find remote address that was linked to this interface */
+ for (entry = remoteaddr_list;
+ entry != NULL;
+ entry = entry->link) {
+ if (entry->ep == ep) {
+ if (socket_multicast_enable(ep, &entry->addr)) {
+ msyslog(LOG_INFO,
+ "Joined %s socket to multicast group %s",
+ stoa(&ep->sin),
+ stoa(&entry->addr));
+ }
+ break;
+ }
+ }
+ }
+
return new_interface_found;
}
@@ -1490,12 +2078,12 @@ create_sockets(
FD_ZERO(&activefds);
#endif
- DPRINTF(2, ("create_sockets(%d)\n", ntohs( (u_short) port)));
+ DPRINTF(2, ("create_sockets(%d)\n", port));
create_wildcards(port);
update_interfaces(port, NULL, NULL);
-
+
/*
* Now that we have opened all the sockets, turn off the reuse
* flag for security.
@@ -1513,87 +2101,137 @@ create_sockets(
*/
static struct interface *
create_interface(
- u_short port,
- struct interface *iface
- )
+ u_short port,
+ struct interface * protot
+ )
{
- struct sockaddr_storage resmask;
- struct interface *interface;
-
- DPRINTF(2, ("create_interface(%s#%d)\n", stoa(&iface->sin), ntohs( (u_short) port)));
+ sockaddr_u resmask;
+ endpt * iface;
+#if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
+ remaddr_t * entry;
+ remaddr_t * next_entry;
+#endif
+ DPRINTF(2, ("create_interface(%s#%d)\n", stoa(&protot->sin),
+ port));
/* build an interface */
- interface = new_interface(iface);
-
+ iface = new_interface(protot);
+
/*
* create socket
*/
- interface->fd = open_socket(&interface->sin,
- interface->flags, 0, interface);
+ iface->fd = open_socket(&iface->sin, 0, 0, iface);
- if (interface->fd != INVALID_SOCKET)
- list_if_listening(interface, port);
+ if (iface->fd != INVALID_SOCKET)
+ log_listen_address(iface);
- if ((interface->flags & INT_BROADCAST) &&
- interface->bfd != INVALID_SOCKET)
- msyslog(LOG_INFO, "Listening on broadcast address %s#%d",
- stoa((&interface->bcast)),
- ntohs( (u_short) port));
+ if ((INT_BROADCAST & iface->flags)
+ && iface->bfd != INVALID_SOCKET)
+ msyslog(LOG_INFO, "Listening on broadcast address %s#%d",
+ stoa((&iface->bcast)), port);
- if (interface->fd == INVALID_SOCKET &&
- interface->bfd == INVALID_SOCKET) {
+ if (INVALID_SOCKET == iface->fd
+ && INVALID_SOCKET == iface->bfd) {
msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s#%d",
- interface->name,
- interface->ifnum,
- stoa((&interface->sin)),
- ntohs( (u_short) port));
- delete_interface(interface);
+ iface->name,
+ iface->ifnum,
+ stoa((&iface->sin)),
+ port);
+ delete_interface(iface);
return NULL;
}
-
- /*
- * Blacklist bound interface address
+
+ /*
+ * Blacklist our own addresses, no use talking to ourself
*/
-
- SET_HOSTMASK(&resmask, interface->sin.ss_family);
- hack_restrict(RESTRICT_FLAGS, &interface->sin, &resmask,
- RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE);
-
+ SET_HOSTMASK(&resmask, AF(&iface->sin));
+ hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask,
+ RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0);
+
/*
* set globals with the first found
* loopback interface of the appropriate class
*/
- if ((loopback_interface == NULL) &&
- (interface->family == AF_INET) &&
- ((interface->flags & INT_LOOPBACK) != 0))
- {
- loopback_interface = interface;
- }
+ if (NULL == loopback_interface && AF_INET == iface->family
+ && (INT_LOOPBACK & iface->flags))
+ loopback_interface = iface;
/*
* put into our interface list
*/
- add_addr_to_list(&interface->sin, interface);
- add_interface(interface);
+ add_addr_to_list(&iface->sin, iface);
+ add_interface(iface);
+
+#if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
+ /*
+ * Join any previously-configured compatible multicast groups.
+ */
+ if (INT_MULTICAST & iface->flags &&
+ !((INT_LOOPBACK | INT_WILDCARD) & iface->flags) &&
+ !iface->ignore_packets) {
+ for (entry = remoteaddr_list;
+ entry != NULL;
+ entry = next_entry) {
+ next_entry = entry->link;
+ if (AF(&iface->sin) != AF(&entry->addr) ||
+ !IS_MCAST(&entry->addr))
+ continue;
+ if (socket_multicast_enable(iface,
+ &entry->addr))
+ msyslog(LOG_INFO,
+ "Joined %s socket to multicast group %s",
+ stoa(&iface->sin),
+ stoa(&entry->addr));
+ else
+ msyslog(LOG_ERR,
+ "Failed to join %s socket to multicast group %s",
+ stoa(&iface->sin),
+ stoa(&entry->addr));
+ }
+ }
+#endif /* MCAST && MCAST_NONEWSOCKET */
- DPRINT_INTERFACE(2, (interface, "created ", "\n"));
- return interface;
+ DPRINT_INTERFACE(2, (iface, "created ", "\n"));
+ return iface;
}
#ifdef SO_EXCLUSIVEADDRUSE
static void
-set_excladdruse(int fd)
+set_excladdruse(
+ SOCKET fd
+ )
{
int one = 1;
int failed;
+#ifdef SYS_WINNT
+ DWORD err;
+#endif
failed = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(char *)&one, sizeof(one));
- if (failed)
- netsyslog(LOG_ERR,
- "setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m", fd);
+ if (!failed)
+ return;
+
+#ifdef SYS_WINNT
+ /*
+ * Prior to Windows XP setting SO_EXCLUSIVEADDRUSE can fail with
+ * error WSAINVAL depending on service pack level and whether
+ * the user account is in the Administrators group. Do not
+ * complain if it fails that way on versions prior to XP (5.1).
+ */
+ err = GetLastError();
+
+ if (isc_win32os_versioncheck(5, 1, 0, 0) < 0 /* < 5.1/XP */
+ && WSAEINVAL == err)
+ return;
+
+ SetLastError(err);
+#endif
+ msyslog(LOG_ERR,
+ "setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m",
+ (int)fd);
}
#endif /* SO_EXCLUSIVEADDRUSE */
@@ -1604,29 +2242,30 @@ set_excladdruse(int fd)
* fd's also?
*/
static void
-set_reuseaddr(int flag) {
- struct interface *interf;
-
+set_reuseaddr(
+ int flag
+ )
+{
#ifndef SO_EXCLUSIVEADDRUSE
+ endpt *ep;
- for (interf = ISC_LIST_HEAD(inter_list);
- interf != NULL;
- interf = ISC_LIST_NEXT(interf, link)) {
-
- if (interf->flags & INT_WILDCARD)
+ for (ep = ep_list; ep != NULL; ep = ep->elink) {
+ if (ep->flags & INT_WILDCARD)
continue;
-
+
/*
- * if interf->fd is INVALID_SOCKET, we might have a adapter
+ * if ep->fd is INVALID_SOCKET, we might have a adapter
* configured but not present
*/
- DPRINTF(4, ("setting SO_REUSEADDR on %.16s@%s to %s\n", interf->name, stoa(&interf->sin), flag ? "on" : "off"));
-
- if (interf->fd != INVALID_SOCKET) {
- if (setsockopt(interf->fd, SOL_SOCKET,
- SO_REUSEADDR, (char *)&flag,
- sizeof(flag))) {
- netsyslog(LOG_ERR, "set_reuseaddr: setsockopt(SO_REUSEADDR, %s) failed: %m", flag ? "on" : "off");
+ DPRINTF(4, ("setting SO_REUSEADDR on %.16s@%s to %s\n",
+ ep->name, stoa(&ep->sin),
+ flag ? "on" : "off"));
+
+ if (ep->fd != INVALID_SOCKET) {
+ if (setsockopt(ep->fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&flag, sizeof(flag))) {
+ msyslog(LOG_ERR, "set_reuseaddr: setsockopt(%s, SO_REUSEADDR, %s) failed: %m",
+ stoa(&ep->sin), flag ? "on" : "off");
}
}
}
@@ -1638,117 +2277,114 @@ set_reuseaddr(int flag) {
* make other changes as necessary later on
*/
void
-enable_broadcast(struct interface *iface, struct sockaddr_storage *baddr)
+enable_broadcast(
+ struct interface * iface,
+ sockaddr_u * baddr
+ )
{
-#ifdef SO_BROADCAST
+#ifdef OPEN_BCAST_SOCKET
socket_broadcast_enable(iface, iface->fd, baddr);
#endif
}
-#ifdef OPEN_BCAST_SOCKET
+#ifdef OPEN_BCAST_SOCKET
/*
* Enable a broadcast address to a given socket
- * The socket is in the inter_list all we need to do is enable
+ * The socket is in the ep_list all we need to do is enable
* broadcasting. It is not this function's job to select the socket
*/
static isc_boolean_t
-socket_broadcast_enable(struct interface *iface, SOCKET fd, struct sockaddr_storage *maddr)
+socket_broadcast_enable(
+ struct interface * iface,
+ SOCKET fd,
+ sockaddr_u * baddr
+ )
{
#ifdef SO_BROADCAST
int on = 1;
- if (maddr->ss_family == AF_INET)
- {
+ if (IS_IPV4(baddr)) {
/* if this interface can support broadcast, set SO_BROADCAST */
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
(char *)&on, sizeof(on)))
- {
- netsyslog(LOG_ERR, "setsockopt(SO_BROADCAST) enable failure on address %s: %m",
- stoa(maddr));
- }
-#ifdef DEBUG
- else if (debug > 1) {
- printf("Broadcast enabled on socket %d for address %s\n",
- fd, stoa(maddr));
- }
-#endif
+ msyslog(LOG_ERR,
+ "setsockopt(SO_BROADCAST) enable failure on address %s: %m",
+ stoa(baddr));
+ else
+ DPRINTF(2, ("Broadcast enabled on socket %d for address %s\n",
+ fd, stoa(baddr)));
}
- iface->flags |= INT_BCASTOPEN;
+ iface->flags |= INT_BCASTXMIT;
return ISC_TRUE;
#else
return ISC_FALSE;
#endif /* SO_BROADCAST */
}
+#ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES
/*
* Remove a broadcast address from a given socket
- * The socket is in the inter_list all we need to do is disable
+ * The socket is in the ep_list all we need to do is disable
* broadcasting. It is not this function's job to select the socket
*/
static isc_boolean_t
-socket_broadcast_disable(struct interface *iface, struct sockaddr_storage *maddr)
+socket_broadcast_disable(
+ struct interface * iface,
+ sockaddr_u * baddr
+ )
{
#ifdef SO_BROADCAST
int off = 0; /* This seems to be OK as an int */
- if (maddr->ss_family == AF_INET)
- {
- if (setsockopt(iface->fd, SOL_SOCKET, SO_BROADCAST,
- (char *)&off, sizeof(off)))
- {
- netsyslog(LOG_ERR, "setsockopt(SO_BROADCAST) disable failure on address %s: %m",
- stoa(maddr));
- }
- }
- iface->flags &= ~INT_BCASTOPEN;
+ if (IS_IPV4(baddr) && setsockopt(iface->fd, SOL_SOCKET,
+ SO_BROADCAST, (char *)&off, sizeof(off)))
+ msyslog(LOG_ERR,
+ "setsockopt(SO_BROADCAST) disable failure on address %s: %m",
+ stoa(baddr));
+
+ iface->flags &= ~INT_BCASTXMIT;
return ISC_TRUE;
#else
return ISC_FALSE;
#endif /* SO_BROADCAST */
}
+#endif /* OS_MISSES_SPECIFIC_ROUTE_UPDATES */
#endif /* OPEN_BCAST_SOCKET */
+
+/*
+ * return the broadcast client flag value
+ */
+isc_boolean_t
+get_broadcastclient_flag(void)
+{
+ return (broadcast_client_enabled);
+}
/*
* Check to see if the address is a multicast address
*/
static isc_boolean_t
-addr_ismulticast(struct sockaddr_storage *maddr)
+addr_ismulticast(
+ sockaddr_u *maddr
+ )
{
- switch (maddr->ss_family)
- {
- case AF_INET :
- if (!IN_CLASSD(ntohl(((struct sockaddr_in*)maddr)->sin_addr.s_addr))) {
- DPRINTF(4, ("multicast address %s not class D\n", stoa(maddr)));
- return (ISC_FALSE);
- }
- else
- {
- return (ISC_TRUE);
- }
+ isc_boolean_t result;
- case AF_INET6 :
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- if (!IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)maddr)->sin6_addr)) {
- DPRINTF(4, ("address %s not IPv6 multicast address\n", stoa(maddr)));
- return (ISC_FALSE);
- }
- else
- {
- return (ISC_TRUE);
- }
-
-/*
- * If we don't have IPV6 support any IPV6 address is not multicast
- */
-#else
- return (ISC_FALSE);
-#endif
+#ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
/*
- * Never valid
+ * If we don't have IPV6 support any IPV6 addr is not multicast
*/
- default:
- return (ISC_FALSE);
- }
+ if (IS_IPV6(maddr))
+ result = ISC_FALSE;
+ else
+#endif
+ result = IS_MCAST(maddr);
+
+ if (!result)
+ DPRINTF(4, ("address %s is not multicast\n",
+ stoa(maddr)));
+
+ return result;
}
/*
@@ -1757,67 +2393,57 @@ addr_ismulticast(struct sockaddr_storage *maddr)
* send the multicast packet.
*/
void
-enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr)
+enable_multicast_if(
+ struct interface * iface,
+ sockaddr_u * maddr
+ )
{
#ifdef MCAST
#ifdef IP_MULTICAST_LOOP
- /*u_char*/ TYPEOF_IP_MULTICAST_LOOP off = 0;
+ TYPEOF_IP_MULTICAST_LOOP off = 0;
#endif
-#ifdef IPV6_MULTICAST_LOOP
- u_int off6 = 0; /* RFC 3493, 5.2. defines type unsigned int */
+#if defined(INCLUDE_IPV6_MULTICAST_SUPPORT) && defined(IPV6_MULTICAST_LOOP)
+ u_int off6 = 0;
#endif
- switch (maddr->ss_family)
- {
+ NTP_REQUIRE(AF(maddr) == AF(&iface->sin));
+
+ switch (AF(&iface->sin)) {
+
case AF_INET:
- if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
- (char *)&(((struct sockaddr_in*)&iface->sin)->sin_addr.s_addr),
- sizeof(struct in_addr)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IP_MULTICAST_IF failure: %m on socket %d, addr %s for multicast address %s",
- iface->fd, stoa(&iface->sin), stoa(maddr));
- return;
- }
#ifdef IP_MULTICAST_LOOP
/*
- * Don't send back to itself, but allow it to fail to set it
+ * Don't send back to itself, but allow failure to set
*/
- if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
- SETSOCKOPT_ARG_CAST &off, sizeof(off)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IP_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s",
- iface->fd, stoa(&iface->sin), stoa(maddr));
+ if (setsockopt(iface->fd, IPPROTO_IP,
+ IP_MULTICAST_LOOP,
+ SETSOCKOPT_ARG_CAST &off,
+ sizeof(off))) {
+
+ msyslog(LOG_ERR,
+ "setsockopt IP_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s",
+ iface->fd, stoa(&iface->sin),
+ stoa(maddr));
}
#endif
- DPRINTF(4, ("Added IPv4 multicast interface on socket %d, addr %s for multicast address %s\n",
- iface->fd, stoa(&iface->sin),
- stoa(maddr)));
break;
case AF_INET6:
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- (char *) &iface->scopeid, sizeof(iface->scopeid)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IPV6_MULTICAST_IF failure: %m on socket %d, addr %s, scope %d for multicast address %s",
- iface->fd, stoa(&iface->sin), iface->scopeid,
- stoa(maddr));
- return;
- }
#ifdef IPV6_MULTICAST_LOOP
/*
- * Don't send back to itself, but allow it to fail to set it
+ * Don't send back to itself, but allow failure to set
*/
- if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
- (char *) &off6, sizeof(off6)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IPV6_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s",
- iface->fd, stoa(&iface->sin), stoa(maddr));
+ if (setsockopt(iface->fd, IPPROTO_IPV6,
+ IPV6_MULTICAST_LOOP,
+ (char *) &off6, sizeof(off6))) {
+
+ msyslog(LOG_ERR,
+ "setsockopt IPV6_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s",
+ iface->fd, stoa(&iface->sin),
+ stoa(maddr));
}
#endif
- DPRINTF(4, ("Added IPv6 multicast interface on socket %d, addr %s, scope %d for multicast address %s\n",
- iface->fd, stoa(&iface->sin), iface->scopeid,
- stoa(maddr)));
break;
#else
return;
@@ -1829,37 +2455,37 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr)
/*
* Add a multicast address to a given socket
- * The socket is in the inter_list all we need to do is enable
+ * The socket is in the ep_list all we need to do is enable
* multicasting. It is not this function's job to select the socket
*/
+#if defined(MCAST)
static isc_boolean_t
-socket_multicast_enable(struct interface *iface, int lscope, struct sockaddr_storage *maddr)
+socket_multicast_enable(
+ endpt * iface,
+ sockaddr_u * maddr
+ )
{
+ struct ip_mreq mreq;
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- struct ipv6_mreq mreq6;
- struct in6_addr iaddr6;
-#endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
-
- struct ip_mreq mreq;
-
- if (find_addr_in_list(maddr)) {
- DPRINTF(4, ("socket_multicast_enable(%s): already enabled\n", stoa(maddr)));
- return ISC_TRUE;
- }
+ struct ipv6_mreq mreq6;
+#endif
+ switch (AF(maddr)) {
- switch (maddr->ss_family)
- {
case AF_INET:
- memset((char *)&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = (((struct sockaddr_in*)maddr)->sin_addr);
+ ZERO(mreq);
+ mreq.imr_multiaddr = SOCK_ADDR4(maddr);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- (char *)&mreq, sizeof(mreq)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IP_ADD_MEMBERSHIP failure: %m on socket %d, addr %s for %x / %x (%s)",
- iface->fd, stoa(&iface->sin),
- mreq.imr_multiaddr.s_addr,
- mreq.imr_interface.s_addr, stoa(maddr));
+ if (setsockopt(iface->fd,
+ IPPROTO_IP,
+ IP_ADD_MEMBERSHIP,
+ (char *)&mreq,
+ sizeof(mreq))) {
+ DPRINTF(2, (
+ "setsockopt IP_ADD_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)",
+ iface->fd, stoa(&iface->sin),
+ mreq.imr_multiaddr.s_addr,
+ mreq.imr_interface.s_addr,
+ stoa(maddr)));
return ISC_FALSE;
}
DPRINTF(4, ("Added IPv4 multicast membership on socket %d, addr %s for %x / %x (%s)\n",
@@ -1871,71 +2497,79 @@ socket_multicast_enable(struct interface *iface, int lscope, struct sockaddr_sto
case AF_INET6:
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
/*
- * Enable reception of multicast packets
- * If the address is link-local we can get the interface index
- * from the scope id. Don't do this for other types of multicast
- * addresses. For now let the kernel figure it out.
+ * Enable reception of multicast packets.
+ * If the address is link-local we can get the
+ * interface index from the scope id. Don't do this
+ * for other types of multicast addresses. For now let
+ * the kernel figure it out.
*/
- memset((char *)&mreq6, 0, sizeof(mreq6));
- iaddr6 = ((struct sockaddr_in6*)maddr)->sin6_addr;
- mreq6.ipv6mr_multiaddr = iaddr6;
- mreq6.ipv6mr_interface = lscope;
-
- if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- (char *)&mreq6, sizeof(mreq6)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IPV6_JOIN_GROUP failure: %m on socket %d, addr %s for interface %d(%s)",
- iface->fd, stoa(&iface->sin),
- mreq6.ipv6mr_interface, stoa(maddr));
+ ZERO(mreq6);
+ mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
+ mreq6.ipv6mr_interface = iface->ifindex;
+
+ if (setsockopt(iface->fd, IPPROTO_IPV6,
+ IPV6_JOIN_GROUP, (char *)&mreq6,
+ sizeof(mreq6))) {
+ DPRINTF(2, (
+ "setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %u (%s)",
+ iface->fd, stoa(&iface->sin),
+ mreq6.ipv6mr_interface, stoa(maddr)));
return ISC_FALSE;
}
- DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %d(%s)\n",
+ DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %u (%s)\n",
iface->fd, stoa(&iface->sin),
mreq6.ipv6mr_interface, stoa(maddr)));
- break;
#else
return ISC_FALSE;
#endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
}
iface->flags |= INT_MCASTOPEN;
iface->num_mcast++;
- add_addr_to_list(maddr, iface);
+
return ISC_TRUE;
}
+#endif /* MCAST */
+
/*
* Remove a multicast address from a given socket
- * The socket is in the inter_list all we need to do is disable
+ * The socket is in the ep_list all we need to do is disable
* multicasting. It is not this function's job to select the socket
*/
+#ifdef MCAST
static isc_boolean_t
-socket_multicast_disable(struct interface *iface, struct sockaddr_storage *maddr)
+socket_multicast_disable(
+ struct interface * iface,
+ sockaddr_u * maddr
+ )
{
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
struct ipv6_mreq mreq6;
- struct in6_addr iaddr6;
-#endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
-
+#endif
struct ip_mreq mreq;
- memset((char *)&mreq, 0, sizeof(mreq));
+
+ ZERO(mreq);
if (find_addr_in_list(maddr) == NULL) {
- DPRINTF(4, ("socket_multicast_disable(%s): not enabled\n", stoa(maddr)));
+ DPRINTF(4, ("socket_multicast_disable(%s): not found\n",
+ stoa(maddr)));
return ISC_TRUE;
}
- switch (maddr->ss_family)
- {
+ switch (AF(maddr)) {
+
case AF_INET:
- mreq.imr_multiaddr = (((struct sockaddr_in*)&maddr)->sin_addr);
- mreq.imr_interface.s_addr = ((struct sockaddr_in*)&iface->sin)->sin_addr.s_addr;
- if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
- (char *)&mreq, sizeof(mreq)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IP_DROP_MEMBERSHIP failure: %m on socket %d, addr %s for %x / %x (%s)",
- iface->fd, stoa(&iface->sin),
- mreq.imr_multiaddr.s_addr,
- mreq.imr_interface.s_addr, stoa(maddr));
+ mreq.imr_multiaddr = SOCK_ADDR4(maddr);
+ mreq.imr_interface = SOCK_ADDR4(&iface->sin);
+ if (setsockopt(iface->fd, IPPROTO_IP,
+ IP_DROP_MEMBERSHIP, (char *)&mreq,
+ sizeof(mreq))) {
+
+ msyslog(LOG_ERR,
+ "setsockopt IP_DROP_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)",
+ iface->fd, stoa(&iface->sin),
+ SRCADR(maddr), SRCADR(&iface->sin),
+ stoa(maddr));
return ISC_FALSE;
}
break;
@@ -1943,35 +2577,37 @@ socket_multicast_disable(struct interface *iface, struct sockaddr_storage *maddr
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
/*
* Disable reception of multicast packets
- * If the address is link-local we can get the interface index
- * from the scope id. Don't do this for other types of multicast
- * addresses. For now let the kernel figure it out.
+ * If the address is link-local we can get the
+ * interface index from the scope id. Don't do this
+ * for other types of multicast addresses. For now let
+ * the kernel figure it out.
*/
- iaddr6 = ((struct sockaddr_in6*)&maddr)->sin6_addr;
- mreq6.ipv6mr_multiaddr = iaddr6;
- mreq6.ipv6mr_interface = iface->scopeid;
-
- if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
- (char *)&mreq6, sizeof(mreq6)) == -1) {
- netsyslog(LOG_ERR,
- "setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d(%s)",
- iface->fd, stoa(&iface->sin),
- mreq6.ipv6mr_interface, stoa(maddr));
+ mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
+ mreq6.ipv6mr_interface = iface->ifindex;
+
+ if (setsockopt(iface->fd, IPPROTO_IPV6,
+ IPV6_LEAVE_GROUP, (char *)&mreq6,
+ sizeof(mreq6))) {
+
+ msyslog(LOG_ERR,
+ "setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d (%s)",
+ iface->fd, stoa(&iface->sin),
+ iface->ifindex, stoa(maddr));
return ISC_FALSE;
}
break;
#else
return ISC_FALSE;
#endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
-
}
+
iface->num_mcast--;
- if (iface->num_mcast <= 0) {
- iface->num_mcast = 0;
+ if (!iface->num_mcast)
iface->flags &= ~INT_MCASTOPEN;
- }
+
return ISC_TRUE;
}
+#endif /* MCAST */
/*
* io_setbclient - open the broadcast client sockets
@@ -1979,38 +2615,37 @@ socket_multicast_disable(struct interface *iface, struct sockaddr_storage *maddr
void
io_setbclient(void)
{
-#ifdef OPEN_BCAST_SOCKET
- struct interface *interf;
- int nif = 0;
- isc_boolean_t jstatus;
- SOCKET fd;
+#ifdef OPEN_BCAST_SOCKET
+ struct interface * interf;
+ int nif;
+ nif = 0;
set_reuseaddr(1);
- for (interf = ISC_LIST_HEAD(inter_list);
+ for (interf = ep_list;
interf != NULL;
- interf = ISC_LIST_NEXT(interf, link)) {
- if (interf->flags & INT_WILDCARD)
- continue;
-
- /* use only allowed addresses */
- if (interf->ignore_packets == ISC_TRUE)
+ interf = interf->elink) {
+
+ if (interf->flags & (INT_WILDCARD | INT_LOOPBACK))
continue;
- /* Only IPv4 addresses are valid for broadcast */
- if (interf->sin.ss_family != AF_INET)
+
+ /* use only allowed addresses */
+ if (interf->ignore_packets)
continue;
- /* Is this a broadcast address? */
+ /* Need a broadcast-capable interface */
if (!(interf->flags & INT_BROADCAST))
continue;
- /* Skip the loopback addresses */
- if (interf->flags & INT_LOOPBACK)
- continue;
+ /* Only IPv4 addresses are valid for broadcast */
+ NTP_REQUIRE(IS_IPV4(&interf->sin));
/* Do we already have the broadcast address open? */
if (interf->flags & INT_BCASTOPEN) {
- /* account for already open interfaces to aviod misleading warning below */
+ /*
+ * account for already open interfaces to avoid
+ * misleading warning below
+ */
nif++;
continue;
}
@@ -2019,41 +2654,41 @@ io_setbclient(void)
* Try to open the broadcast address
*/
interf->family = AF_INET;
- interf->bfd = open_socket(&interf->bcast,
- INT_BROADCAST, 0, interf);
+ interf->bfd = open_socket(&interf->bcast, 1, 0, interf);
- /*
- * If we succeeded then we use it otherwise
- * enable the underlying address
+ /*
+ * If we succeeded then we use it otherwise enable
+ * broadcast on the interface address
*/
- if (interf->bfd == INVALID_SOCKET) {
- fd = interf->fd;
- }
- else {
- fd = interf->bfd;
- }
-
- /* Enable Broadcast on socket */
- jstatus = socket_broadcast_enable(interf, fd, &interf->sin);
- if (jstatus == ISC_TRUE)
- {
+ if (interf->bfd != INVALID_SOCKET) {
nif++;
- netsyslog(LOG_INFO,"io_setbclient: Opened broadcast client on interface #%d %s, socket: %d",
- interf->ifnum, interf->name, fd);
- interf->addr_refid = addr2refid(&interf->sin);
+ interf->flags |= INT_BCASTOPEN;
+ msyslog(LOG_INFO,
+ "Listen for broadcasts to %s on interface #%d %s",
+ stoa(&interf->bcast), interf->ifnum, interf->name);
+ } else {
+ /* silently ignore EADDRINUSE as we probably opened
+ the socket already for an address in the same network */
+ if (errno != EADDRINUSE)
+ msyslog(LOG_INFO,
+ "failed to listen for broadcasts to %s on interface #%d %s",
+ stoa(&interf->bcast), interf->ifnum, interf->name);
}
}
set_reuseaddr(0);
-#ifdef DEBUG
- if (debug)
- if (nif > 0)
- printf("io_setbclient: Opened broadcast clients\n");
-#endif
- if (nif == 0)
- netsyslog(LOG_ERR, "Unable to listen for broadcasts, no broadcast interfaces available");
+ if (nif > 0) {
+ broadcast_client_enabled = ISC_TRUE;
+ DPRINTF(1, ("io_setbclient: listening to %d broadcast addresses\n", nif));
+ }
+ else if (!nif) {
+ broadcast_client_enabled = ISC_FALSE;
+ msyslog(LOG_ERR,
+ "Unable to listen for broadcasts, no broadcast interfaces available");
+ }
#else
- netsyslog(LOG_ERR, "io_setbclient: Broadcast Client disabled by build");
-#endif
+ msyslog(LOG_ERR,
+ "io_setbclient: Broadcast Client disabled by build");
+#endif /* OPEN_BCAST_SOCKET */
}
/*
@@ -2062,20 +2697,25 @@ io_setbclient(void)
void
io_unsetbclient(void)
{
- struct interface *interf;
- isc_boolean_t lstatus;
+ endpt *ep;
- for (interf = ISC_LIST_HEAD(inter_list);
- interf != NULL;
- interf = ISC_LIST_NEXT(interf, link))
- {
- if (interf->flags & INT_WILDCARD)
- continue;
-
- if (!(interf->flags & INT_BCASTOPEN))
- continue;
- lstatus = socket_broadcast_disable(interf, &interf->sin);
+ for (ep = ep_list; ep != NULL; ep = ep->elink) {
+ if (INT_WILDCARD & ep->flags)
+ continue;
+ if (!(INT_BCASTOPEN & ep->flags))
+ continue;
+
+ if (ep->bfd != INVALID_SOCKET) {
+ /* destroy broadcast listening socket */
+ msyslog(LOG_INFO,
+ "stop listening for broadcasts to %s on interface #%d %s",
+ stoa(&ep->bcast), ep->ifnum, ep->name);
+ close_and_delete_fd_from_list(ep->bfd);
+ ep->bfd = INVALID_SOCKET;
+ ep->flags &= ~INT_BCASTOPEN;
+ }
}
+ broadcast_client_enabled = ISC_FALSE;
}
/*
@@ -2083,279 +2723,146 @@ io_unsetbclient(void)
*/
void
io_multicast_add(
- struct sockaddr_storage addr
+ sockaddr_u *addr
)
{
#ifdef MCAST
- struct interface *interface;
-#ifndef MULTICAST_NONEWSOCKET
- struct interface *iface;
-#endif
- int lscope = 0;
-
+ endpt * ep;
+ endpt * one_ep;
+
/*
* Check to see if this is a multicast address
*/
- if (addr_ismulticast(&addr) == ISC_FALSE)
+ if (!addr_ismulticast(addr))
return;
/* If we already have it we can just return */
- if (find_flagged_addr_in_list(&addr, INT_MCASTOPEN|INT_MCASTIF) != NULL)
- {
- netsyslog(LOG_INFO, "Duplicate request found for multicast address %s",
- stoa(&addr));
+ if (NULL != find_flagged_addr_in_list(addr, INT_MCASTOPEN)) {
+ msyslog(LOG_INFO,
+ "Duplicate request found for multicast address %s",
+ stoa(addr));
return;
}
#ifndef MULTICAST_NONEWSOCKET
- interface = new_interface(NULL);
-
+ ep = new_interface(NULL);
+
/*
* Open a new socket for the multicast address
*/
- interface->sin.ss_family = addr.ss_family;
- interface->family = addr.ss_family;
+ ep->sin = *addr;
+ SET_PORT(&ep->sin, NTP_PORT);
+ ep->family = AF(&ep->sin);
+ AF(&ep->mask) = ep->family;
+ SET_ONESMASK(&ep->mask);
- switch(addr.ss_family) {
- case AF_INET:
- memcpy(&(((struct sockaddr_in *)&interface->sin)->sin_addr),
- &(((struct sockaddr_in*)&addr)->sin_addr),
- sizeof(struct in_addr));
- ((struct sockaddr_in*)&interface->sin)->sin_port = htons(NTP_PORT);
- memset(&((struct sockaddr_in*)&interface->mask)->sin_addr.s_addr, 0xff, sizeof(struct in_addr));
- break;
- case AF_INET6:
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- memcpy(&(((struct sockaddr_in6 *)&interface->sin)->sin6_addr),
- &((struct sockaddr_in6*)&addr)->sin6_addr,
- sizeof(struct in6_addr));
- ((struct sockaddr_in6*)&interface->sin)->sin6_port = htons(NTP_PORT);
-#ifdef ISC_PLATFORM_HAVESCOPEID
- ((struct sockaddr_in6*)&interface->sin)->sin6_scope_id = ((struct sockaddr_in6*)&addr)->sin6_scope_id;
-#endif
- memset(&((struct sockaddr_in6*)&interface->mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr));
-#endif
- iface = findlocalcastinterface(&addr, INT_MULTICAST);
- if (iface) {
-# ifdef ISC_PLATFORM_HAVESCOPEID
- lscope = ((struct sockaddr_in6*)&iface->sin)->sin6_scope_id;
-# endif
- DPRINTF(4, ("Found interface #%d %s, scope: %d for address %s\n", iface->ifnum, iface->name, lscope, stoa(&addr)));
- }
- break;
- }
-
set_reuseaddr(1);
- interface->bfd = INVALID_SOCKET;
- interface->fd = open_socket(&interface->sin,
- INT_MULTICAST, 0, interface);
+ ep->bfd = INVALID_SOCKET;
+ ep->fd = open_socket(&ep->sin, 0, 0, ep);
+ if (ep->fd != INVALID_SOCKET) {
+ ep->ignore_packets = ISC_FALSE;
+ ep->flags |= INT_MCASTIF;
+
+ strlcpy(ep->name, "multicast", sizeof(ep->name));
+ DPRINT_INTERFACE(2, (ep, "multicast add ", "\n"));
+ add_interface(ep);
+ log_listen_address(ep);
+ } else {
+ /* bind failed, re-use wildcard interface */
+ delete_interface(ep);
- if (interface->fd != INVALID_SOCKET)
- {
- interface->bfd = INVALID_SOCKET;
- interface->ignore_packets = ISC_FALSE;
- interface->flags |= INT_MCASTIF;
-
- (void) strncpy(interface->name, "multicast",
- sizeof(interface->name));
- ((struct sockaddr_in*)&interface->mask)->sin_addr.s_addr =
- htonl(~(u_int32)0);
- DPRINT_INTERFACE(2, (interface, "multicast add ", "\n"));
- /* socket_multicast_enable() will add this address to the addresslist */
- add_interface(interface);
- list_if_listening(interface, htons(NTP_PORT));
- }
- else
- {
- delete_interface(interface); /* re-use existing interface */
- interface = NULL;
- if (addr.ss_family == AF_INET)
- interface = wildipv4;
- else if (addr.ss_family == AF_INET6)
- interface = wildipv6;
-
- if (interface != NULL) {
+ if (IS_IPV4(addr))
+ ep = wildipv4;
+ else if (IS_IPV6(addr))
+ ep = wildipv6;
+ else
+ ep = NULL;
+
+ if (ep != NULL) {
/* HACK ! -- stuff in an address */
- interface->bcast = addr;
- netsyslog(LOG_ERR,
- "...multicast address %s using wildcard interface #%d %s",
- stoa(&addr), interface->ifnum, interface->name);
+ /* because we don't bind addr? DH */
+ ep->bcast = *addr;
+ msyslog(LOG_ERR,
+ "multicast address %s using wildcard interface #%d %s",
+ stoa(addr), ep->ifnum, ep->name);
} else {
- netsyslog(LOG_ERR,
- "No multicast socket available to use for address %s",
- stoa(&addr));
+ msyslog(LOG_ERR,
+ "No multicast socket available to use for address %s",
+ stoa(addr));
return;
}
}
-#else
- /*
- * For the case where we can't use a separate socket
- */
- interface = findlocalcastinterface(&addr, INT_MULTICAST);
+ { /* in place of the { following for in #else clause */
+ one_ep = ep;
+#else /* MULTICAST_NONEWSOCKET follows */
/*
- * If we don't have a valid socket, just return
+ * For the case where we can't use a separate socket (Windows)
+ * join each applicable endpoint socket to the group address.
*/
- if (!interface)
- {
- netsyslog(LOG_ERR,
- "Cannot add multicast address %s: Cannot find slot",
- stoa(&addr));
- return;
+ if (IS_IPV4(addr))
+ one_ep = wildipv4;
+ else
+ one_ep = wildipv6;
+ for (ep = ep_list; ep != NULL; ep = ep->elink) {
+ if (ep->ignore_packets || AF(&ep->sin) != AF(addr) ||
+ !(INT_MULTICAST & ep->flags) ||
+ (INT_LOOPBACK | INT_WILDCARD) & ep->flags)
+ continue;
+ one_ep = ep;
+#endif /* MULTICAST_NONEWSOCKET */
+ if (socket_multicast_enable(ep, addr))
+ msyslog(LOG_INFO,
+ "Joined %s socket to multicast group %s",
+ stoa(&ep->sin),
+ stoa(addr));
}
+ add_addr_to_list(addr, one_ep);
+#else /* !MCAST follows*/
+ msyslog(LOG_ERR,
+ "Can not add multicast address %s: no multicast support",
+ stoa(addr));
#endif
- {
- isc_boolean_t jstatus;
- jstatus = socket_multicast_enable(interface, lscope, &addr);
-
- if (jstatus == ISC_TRUE)
- netsyslog(LOG_INFO, "Added Multicast Listener %s on interface #%d %s\n", stoa(&addr), interface->ifnum, interface->name);
- else
- netsyslog(LOG_ERR, "Failed to add Multicast Listener %s\n", stoa(&addr));
- }
-#else /* MCAST */
- netsyslog(LOG_ERR,
- "Cannot add multicast address %s: no Multicast support",
- stoa(&addr));
-#endif /* MCAST */
return;
}
+
/*
* io_multicast_del() - delete multicast group address
*/
void
io_multicast_del(
- struct sockaddr_storage addr
+ sockaddr_u * addr
)
{
#ifdef MCAST
- struct interface *interface;
- isc_boolean_t lstatus;
+ endpt *iface;
/*
* Check to see if this is a multicast address
*/
- if (addr_ismulticast(&addr) == ISC_FALSE)
- {
- netsyslog(LOG_ERR,
- "invalid multicast address %s", stoa(&addr));
+ if (!addr_ismulticast(addr)) {
+ msyslog(LOG_ERR, "invalid multicast address %s",
+ stoa(addr));
return;
}
- switch (addr.ss_family)
- {
- case AF_INET :
- /*
- * Disable reception of multicast packets
- */
- interface = find_flagged_addr_in_list(&addr, INT_MCASTOPEN);
- while ( interface != NULL) {
- lstatus = socket_multicast_disable(interface, &addr);
- interface = find_flagged_addr_in_list(&addr, INT_MCASTOPEN);
- }
- break;
-
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- case AF_INET6 :
- /*
- * Disable reception of multicast packets
- */
- for (interface = ISC_LIST_HEAD(inter_list);
- interface != NULL;
- interface = ISC_LIST_NEXT(interface, link))
- {
- if (interface->flags & INT_WILDCARD)
- continue;
-
- /* Be sure it's the correct family */
- if (interface->sin.ss_family != AF_INET6)
- continue;
- if (!(interface->flags & INT_MCASTOPEN))
- continue;
- if (!(interface->fd < 0))
- continue;
- if (!SOCKCMP(&addr, &interface->sin))
- continue;
- lstatus = socket_multicast_disable(interface, &addr);
- }
- break;
-#endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
-
- }/* switch */
+ /*
+ * Disable reception of multicast packets
+ */
+ while ((iface = find_flagged_addr_in_list(addr, INT_MCASTOPEN))
+ != NULL)
+ socket_multicast_disable(iface, addr);
- delete_addr_from_list(&addr);
+ delete_addr_from_list(addr);
#else /* not MCAST */
- netsyslog(LOG_ERR, "this function requires multicast kernel");
+ msyslog(LOG_ERR,
+ "Can not delete multicast address %s: no multicast support",
+ stoa(addr));
#endif /* not MCAST */
}
-/*
- * init_nonblocking_io() - set up descriptor to be non blocking
- */
-static void init_nonblocking_io(SOCKET fd)
-{
- /*
- * set non-blocking,
- */
-
-#ifdef USE_FIONBIO
- /* in vxWorks we use FIONBIO, but the others are defined for old systems, so
- * all hell breaks loose if we leave them defined
- */
-#undef O_NONBLOCK
-#undef FNDELAY
-#undef O_NDELAY
-#endif
-
-#if defined(O_NONBLOCK) /* POSIX */
- if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
- {
- netsyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails on fd #%d: %m",
- fd);
- exit(1);
- /*NOTREACHED*/
- }
-#elif defined(FNDELAY)
- if (fcntl(fd, F_SETFL, FNDELAY) < 0)
- {
- netsyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
- fd);
- exit(1);
- /*NOTREACHED*/
- }
-#elif defined(O_NDELAY) /* generally the same as FNDELAY */
- if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
- {
- netsyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
- fd);
- exit(1);
- /*NOTREACHED*/
- }
-#elif defined(FIONBIO)
- {
- int on = 1;
- if (ioctl(fd,FIONBIO,&on) < 0)
- {
- netsyslog(LOG_ERR, "ioctl(FIONBIO) fails on fd #%d: %m",
- fd);
- exit(1);
- /*NOTREACHED*/
- }
- }
-#elif defined(FIOSNBIO)
- if (ioctl(fd,FIOSNBIO,&on) < 0)
- {
- netsyslog(LOG_ERR, "ioctl(FIOSNBIO) fails on fd #%d: %m",
- fd);
- exit(1);
- /*NOTREACHED*/
- }
-#else
-# include "Bletch: Need non-blocking I/O!"
-#endif
-}
/*
* open_socket - open a socket, returning the file descriptor
@@ -2363,48 +2870,42 @@ static void init_nonblocking_io(SOCKET fd)
static SOCKET
open_socket(
- struct sockaddr_storage *addr,
- int flags,
- int turn_off_reuse,
- struct interface *interf
+ sockaddr_u * addr,
+ int bcast,
+ int turn_off_reuse,
+ endpt * interf
)
{
- int errval;
- SOCKET fd;
+ SOCKET fd;
+ int errval;
/*
- * int is OK for REUSEADR per
+ * int is OK for REUSEADR per
* http://www.kohala.com/start/mcast.api.txt
*/
- int on = 1;
- int off = 0;
-
-#if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS)
- int tos;
-#endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */
+ int on = 1;
+ int off = 0;
- if ((addr->ss_family == AF_INET6) && (isc_net_probeipv6() != ISC_R_SUCCESS))
- return (INVALID_SOCKET);
+ if (IS_IPV6(addr) && !ipv6_works)
+ return INVALID_SOCKET;
/* create a datagram (UDP) socket */
- fd = socket(addr->ss_family, SOCK_DGRAM, 0);
+ fd = socket(AF(addr), SOCK_DGRAM, 0);
if (INVALID_SOCKET == fd) {
-#ifndef SYS_WINNT
- errval = errno;
-#else
- errval = WSAGetLastError();
-#endif
- netsyslog(LOG_ERR,
- "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m",
- (addr->ss_family == AF_INET6) ? "6" : "",
- stoa(addr));
+ errval = socket_errno();
+ msyslog(LOG_ERR,
+ "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m",
+ IS_IPV6(addr) ? "6" : "", stoa(addr));
- if (errval == EPROTONOSUPPORT ||
+ if (errval == EPROTONOSUPPORT ||
errval == EAFNOSUPPORT ||
errval == EPFNOSUPPORT)
return (INVALID_SOCKET);
- msyslog(LOG_ERR, "unexpected error code %d (not PROTONOSUPPORT|AFNOSUPPORT|FPNOSUPPORT) - exiting", errval);
+
+ errno = errval;
+ msyslog(LOG_ERR,
+ "unexpected socket() error %m code %d (not EPROTONOSUPPORT nor EAFNOSUPPORT nor EPFNOSUPPORT) - exiting",
+ errno);
exit(1);
- /*NOTREACHED*/
}
#ifdef SYS_WINNT
@@ -2426,17 +2927,17 @@ open_socket(
if (isc_win32os_versioncheck(5, 1, 0, 0) < 0) /* before 5.1 */
#endif
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
- (char *)(turn_off_reuse
- ? &off
- : &on),
+ (char *)((turn_off_reuse)
+ ? &off
+ : &on),
sizeof(on))) {
- netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR %s"
- " fails for address %s: %m",
- turn_off_reuse
- ? "off"
- : "on",
- stoa(addr));
+ msyslog(LOG_ERR,
+ "setsockopt SO_REUSEADDR %s fails for address %s: %m",
+ (turn_off_reuse)
+ ? "off"
+ : "on",
+ stoa(addr));
closesocket(fd);
return INVALID_SOCKET;
}
@@ -2452,39 +2953,44 @@ open_socket(
/*
* IPv4 specific options go here
*/
- if (addr->ss_family == AF_INET) {
-#if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS)
- /* set IP_TOS to minimize packet delay */
- tos = IPTOS_LOWDELAY;
- if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)) < 0)
- {
- netsyslog(LOG_ERR, "setsockopt IPTOS_LOWDELAY on fails on address %s: %m",
- stoa(addr));
- }
-#endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */
+ if (IS_IPV4(addr)) {
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char*)&qos,
+ sizeof(qos)))
+ msyslog(LOG_ERR,
+ "setsockopt IP_TOS (%02x) fails on address %s: %m",
+ qos, stoa(addr));
+#endif /* IPPROTO_IP && IP_TOS */
+ if (bcast)
+ socket_broadcast_enable(interf, fd, addr);
}
/*
* IPv6 specific options go here
*/
- if (addr->ss_family == AF_INET6) {
-#if defined(IPV6_V6ONLY)
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
- (char*)&on, sizeof(on)))
- {
- netsyslog(LOG_ERR, "setsockopt IPV6_V6ONLY on fails on address %s: %m",
+ if (IS_IPV6(addr)) {
+#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, (char*)&qos,
+ sizeof(qos)))
+ msyslog(LOG_ERR,
+ "setsockopt IPV6_TCLASS (%02x) fails on address %s: %m",
+ qos, stoa(addr));
+#endif /* IPPROTO_IPV6 && IPV6_TCLASS */
+#ifdef IPV6_V6ONLY
+ if (isc_net_probe_ipv6only() == ISC_R_SUCCESS
+ && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char*)&on, sizeof(on)))
+ msyslog(LOG_ERR,
+ "setsockopt IPV6_V6ONLY on fails on address %s: %m",
stoa(addr));
- }
-#endif /* IPV6_V6ONLY */
-#if defined(IPV6_BINDV6ONLY)
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
- (char*)&on, sizeof(on)))
- {
- netsyslog(LOG_ERR,
- "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m",
- stoa(addr));
- }
-#endif /* IPV6_BINDV6ONLY */
+#endif
+#ifdef IPV6_BINDV6ONLY
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
+ (char*)&on, sizeof(on)))
+ msyslog(LOG_ERR,
+ "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m",
+ stoa(addr));
+#endif
}
#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
@@ -2493,25 +2999,18 @@ open_socket(
* addresses if a wildcard address already bound
* to the port and SO_REUSEADDR is not set
*/
- if (!is_wildcard_addr(addr)) {
- set_wildcard_reuse(addr->ss_family, 1);
- }
+ if (!is_wildcard_addr(addr))
+ set_wildcard_reuse(AF(addr), 1);
#endif
/*
* bind the local address.
*/
- errval = bind(fd, (struct sockaddr *)addr, SOCKLEN(addr));
+ errval = bind(fd, &addr->sa, SOCKLEN(addr));
#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
- /*
- * some OSes don't allow binding to more specific
- * addresses if a wildcard address already bound
- * to the port and REUSE_ADDR is not set
- */
- if (!is_wildcard_addr(addr)) {
- set_wildcard_reuse(addr->ss_family, 0);
- }
+ if (!is_wildcard_addr(addr))
+ set_wildcard_reuse(AF(addr), 0);
#endif
if (errval < 0) {
@@ -2522,32 +3021,17 @@ open_socket(
#ifdef DEBUG
|| debug > 1
#endif
- ) {
- if (addr->ss_family == AF_INET)
- netsyslog(LOG_ERR,
- "bind() fd %d, family AF_INET, port %d, addr %s, in_classd=%d flags=0x%x fails: %m",
- fd, (int)ntohs(((struct sockaddr_in*)addr)->sin_port),
- stoa(addr),
- IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)),
- flags);
-#ifdef INCLUDE_IPV6_SUPPORT
- else if (addr->ss_family == AF_INET6)
- netsyslog(LOG_ERR,
- "bind() fd %d, family AF_INET6, port %d, scope %d, addr %s, mcast=%d flags=0x%x fails: %m",
- fd, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port),
-# ifdef ISC_PLATFORM_HAVESCOPEID
- ((struct sockaddr_in6*)addr)->sin6_scope_id
-# else
- -1
-# endif
- , stoa(addr),
- IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr),
- flags);
-#endif
+ ) {
+ msyslog(LOG_ERR,
+ "bind(%d) AF_INET%s %s#%d%s flags 0x%x failed: %m",
+ fd, IS_IPV6(addr) ? "6" : "",
+ stoa(addr), SRCPORT(addr),
+ IS_MCAST(addr) ? " (multicast)" : "",
+ interf->flags);
}
closesocket(fd);
-
+
return INVALID_SOCKET;
}
@@ -2555,28 +3039,45 @@ open_socket(
{
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP,
(char*)&on, sizeof(on)))
- {
- netsyslog(LOG_DEBUG,
- "setsockopt SO_TIMESTAMP on fails on address %s: %m",
- stoa(addr));
- }
-#ifdef DEBUG
+ msyslog(LOG_DEBUG,
+ "setsockopt SO_TIMESTAMP on fails on address %s: %m",
+ stoa(addr));
else
- {
- DPRINTF(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n", fd, stoa(addr)));
- }
+ DPRINTF(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n",
+ fd, stoa(addr)));
+ }
#endif
- }
+#ifdef HAVE_TIMESTAMPNS
+ {
+ if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS,
+ (char*)&on, sizeof(on)))
+ msyslog(LOG_DEBUG,
+ "setsockopt SO_TIMESTAMPNS on fails on address %s: %m",
+ stoa(addr));
+ else
+ DPRINTF(4, ("setsockopt SO_TIMESTAMPNS enabled on fd %d address %s\n",
+ fd, stoa(addr)));
+ }
#endif
- DPRINTF(4, ("bind() fd %d, family %d, port %d, addr %s, flags=0x%x\n",
- fd,
- addr->ss_family,
- (int)ntohs(((struct sockaddr_in*)addr)->sin_port),
- stoa(addr),
- interf->flags));
+#ifdef HAVE_BINTIME
+ {
+ if (setsockopt(fd, SOL_SOCKET, SO_BINTIME,
+ (char*)&on, sizeof(on)))
+ msyslog(LOG_DEBUG,
+ "setsockopt SO_BINTIME on fails on address %s: %m",
+ stoa(addr));
+ else
+ DPRINTF(4, ("setsockopt SO_BINTIME enabled on fd %d address %s\n",
+ fd, stoa(addr)));
+ }
+#endif
+
+ DPRINTF(4, ("bind(%d) AF_INET%s, addr %s%%%d#%d, flags 0x%x\n",
+ fd, IS_IPV6(addr) ? "6" : "", stoa(addr),
+ SCOPE(addr), SRCPORT(addr), interf->flags));
+
+ make_socket_nonblocking(fd);
- init_nonblocking_io(fd);
-
#ifdef HAVE_SIGNALED_IO
init_socket_sig(fd);
#endif /* not HAVE_SIGNALED_IO */
@@ -2592,8 +3093,7 @@ open_socket(
/*
* Add the socket to the completion port
*/
- if (io_completion_port_add_socket(fd, interf))
- {
+ if (io_completion_port_add_socket(fd, interf)) {
msyslog(LOG_ERR, "unable to set up io completion port - EXITING");
exit(1);
}
@@ -2601,6 +3101,12 @@ open_socket(
return fd;
}
+
+#ifdef SYS_WINNT
+#define sendto(fd, buf, len, flags, dest, destsz) \
+ io_completion_port_sendto(fd, buf, len, (sockaddr_u *)(dest))
+#endif
+
/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
/*
* sendpkt - send a packet to the specified destination. Maintain a
@@ -2609,216 +3115,101 @@ open_socket(
*/
void
sendpkt(
- struct sockaddr_storage *dest,
- struct interface *inter,
- int ttl,
- struct pkt *pkt,
- int len
+ sockaddr_u * dest,
+ struct interface * ep,
+ int ttl,
+ struct pkt * pkt,
+ int len
)
{
- int cc, slot;
-
- /*
- * Send error caches. Empty slots have port == 0
- * Set ERRORCACHESIZE to 0 to disable
- */
- struct cache {
- u_short port;
- struct in_addr addr;
- };
-
-#ifdef INCLUDE_IPV6_SUPPORT
- struct cache6 {
- u_short port;
- struct in6_addr addr;
- };
-#endif /* INCLUDE_IPV6_SUPPORT */
-
-
-#ifndef ERRORCACHESIZE
-#define ERRORCACHESIZE 8
-#endif
-#if ERRORCACHESIZE > 0
- static struct cache badaddrs[ERRORCACHESIZE];
-#ifdef INCLUDE_IPV6_SUPPORT
- static struct cache6 badaddrs6[ERRORCACHESIZE];
-#endif /* INCLUDE_IPV6_SUPPORT */
-#else
-#define badaddrs ((struct cache *)0) /* Only used in empty loops! */
-#ifdef INCLUDE_IPV6_SUPPORT
-#define badaddrs6 ((struct cache6 *)0) /* Only used in empty loops! */
-#endif /* INCLUDE_IPV6_SUPPORT */
-#endif
-#ifdef DEBUG
- if (debug > 1)
- {
- if (inter != NULL)
- {
- printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n",
- (ttl > 0) ? "\tMCAST\t***** " : "",
- inter->fd, stoa(dest),
- stoa(&inter->sin), ttl, len);
- }
- else
- {
- printf("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n",
- (ttl > 0) ? "\tMCAST\t***** " : "",
- stoa(dest),
- ttl, len);
- }
- }
-#endif
-
- if (inter == NULL) /* unbound peer - drop request and wait for better network conditions */
- return;
-
-#ifdef MCAST
+ endpt * src;
+ int ismcast;
+ int cc;
+ int rc;
+ u_char cttl;
+
+ ismcast = IS_MCAST(dest);
+ if (!ismcast)
+ src = ep;
+ else
+ src = (IS_IPV4(dest))
+ ? mc4_list
+ : mc6_list;
- /*
- * for the moment we use the bcast option to set multicast ttl
- */
- if (ttl > 0 && ttl != inter->last_ttl) {
-
+ if (NULL == src) {
/*
- * set the multicast ttl for outgoing packets
+ * unbound peer - drop request and wait for better
+ * network conditions
*/
- int rtc;
-
- switch (inter->sin.ss_family) {
-
- case AF_INET :
- {
- u_char mttl = (u_char) ttl;
-
- rtc = setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL,
- (const void *) &mttl, sizeof(mttl));
- break;
- }
-
-#ifdef INCLUDE_IPV6_SUPPORT
- case AF_INET6 :
- {
- u_int ittl = (u_char) ttl;
-
- rtc = setsockopt(inter->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
- (const void *) &ittl, sizeof(ittl));
- break;
- }
-
-#endif /* INCLUDE_IPV6_SUPPORT */
- default: /* just NOP if not supported */
- rtc = 0;
- break;
- }
-
- if (rtc != 0) {
- netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m",
- stoa(&inter->sin));
- }
- else
- inter->last_ttl = ttl;
+ DPRINTF(2, ("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n",
+ ismcast ? "\tMCAST\t***** " : "",
+ stoa(dest), ttl, len));
+ return;
}
-#endif /* MCAST */
-
- for (slot = ERRORCACHESIZE; --slot >= 0; )
- if(dest->ss_family == AF_INET) {
- if (badaddrs[slot].port == SRCPORT(dest) &&
- badaddrs[slot].addr.s_addr == ((struct sockaddr_in*)dest)->sin_addr.s_addr)
- break;
- }
-#ifdef INCLUDE_IPV6_SUPPORT
- else if (dest->ss_family == AF_INET6) {
- if (badaddrs6[slot].port == SRCPORT(dest) &&
- !memcmp(&badaddrs6[slot].addr, &((struct sockaddr_in6*)dest)->sin6_addr, sizeof(struct in6_addr)))
- break;
- }
-#endif /* INCLUDE_IPV6_SUPPORT */
-
-#if defined(HAVE_IO_COMPLETION_PORT)
- cc = io_completion_port_sendto(inter, pkt, len, dest);
- if (cc != ERROR_SUCCESS)
-#else
-#ifdef SIM
- cc = srvr_rply(&ntp_node, dest, inter, pkt);
-#else /* SIM */
- cc = sendto(inter->fd, (char *)pkt, (unsigned int)len, 0, (struct sockaddr *)dest,
- SOCKLEN(dest));
-#endif /* SIM */
- if (cc == -1)
-#endif
- {
- inter->notsent++;
- packets_notsent++;
-
-#if defined(HAVE_IO_COMPLETION_PORT)
- if (cc != WSAEWOULDBLOCK && cc != WSAENOBUFS && slot < 0)
-#else
- if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0)
-#endif
- {
+ do {
+ DPRINTF(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n",
+ ismcast ? "\tMCAST\t***** " : "", src->fd,
+ stoa(dest), stoa(&src->sin), ttl, len));
+#ifdef MCAST
+ /*
+ * for the moment we use the bcast option to set multicast ttl
+ */
+ if (ismcast && ttl > 0 && ttl != src->last_ttl) {
/*
- * Remember this, if there's an empty slot
+ * set the multicast ttl for outgoing packets
*/
- switch (dest->ss_family) {
+ switch (AF(&src->sin)) {
case AF_INET :
-
- for (slot = ERRORCACHESIZE; --slot >= 0; )
- if (badaddrs[slot].port == 0)
- {
- badaddrs[slot].port = SRCPORT(dest);
- badaddrs[slot].addr = ((struct sockaddr_in*)dest)->sin_addr;
- break;
- }
+ cttl = (u_char)ttl;
+ rc = setsockopt(src->fd, IPPROTO_IP,
+ IP_MULTICAST_TTL,
+ (void *)&cttl,
+ sizeof(cttl));
break;
-#ifdef INCLUDE_IPV6_SUPPORT
+# ifdef INCLUDE_IPV6_SUPPORT
case AF_INET6 :
-
- for (slot = ERRORCACHESIZE; --slot >= 0; )
- if (badaddrs6[slot].port == 0)
- {
- badaddrs6[slot].port = SRCPORT(dest);
- badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr;
- break;
- }
- break;
-#endif /* INCLUDE_IPV6_SUPPORT */
- default: /* don't care if not supported */
+ rc = setsockopt(src->fd, IPPROTO_IPV6,
+ IPV6_MULTICAST_HOPS,
+ (void *)&ttl,
+ sizeof(ttl));
break;
+# endif /* INCLUDE_IPV6_SUPPORT */
+
+ default:
+ rc = 0;
}
- netsyslog(LOG_ERR, "sendto(%s) (fd=%d): %m",
- stoa(dest), inter->fd);
+ if (!rc)
+ src->last_ttl = ttl;
+ else
+ msyslog(LOG_ERR,
+ "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m",
+ stoa(&src->sin));
}
- }
- else
- {
- inter->sent++;
- packets_sent++;
- /*
- * He's not bad any more
- */
- if (slot >= 0)
- {
- netsyslog(LOG_INFO, "Connection re-established to %s", stoa(dest));
- switch (dest->ss_family) {
- case AF_INET :
- badaddrs[slot].port = 0;
- break;
-#ifdef INCLUDE_IPV6_SUPPORT
- case AF_INET6 :
- badaddrs6[slot].port = 0;
- break;
-#endif /* INCLUDE_IPV6_SUPPORT */
- default: /* don't care if not supported */
- break;
- }
+#endif /* MCAST */
+
+#ifdef SIM
+ cc = simulate_server(dest, src, pkt);
+#else
+ cc = sendto(src->fd, (char *)pkt, (u_int)len, 0,
+ &dest->sa, SOCKLEN(dest));
+#endif
+ if (cc == -1) {
+ src->notsent++;
+ packets_notsent++;
+ } else {
+ src->sent++;
+ packets_sent++;
}
- }
+ if (ismcast)
+ src = src->mclink;
+ } while (ismcast && src != NULL);
}
+
#if !defined(HAVE_IO_COMPLETION_PORT)
/*
* fdbits - generate ascii representation of fd_set (FAU debug support)
@@ -2833,10 +3224,9 @@ fdbits(
static char buffer[256];
char * buf = buffer;
- count = (count < 256) ? count : 255;
+ count = min(count, 255);
- while (count >= 0)
- {
+ while (count >= 0) {
*buf++ = FD_ISSET(count, set) ? '#' : '-';
count--;
}
@@ -2845,22 +3235,29 @@ fdbits(
return buffer;
}
+
+#ifdef REFCLOCK
/*
* Routine to read the refclock packets for a specific interface
* Return the number of bytes read. That way we know if we should
* read it again or go on to the next one if no bytes returned
*/
static inline int
-read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
+read_refclock_packet(
+ SOCKET fd,
+ struct refclockio * rp,
+ l_fp ts
+ )
{
- int i;
- int buflen;
- register struct recvbuf *rb;
+ int i;
+ int buflen;
+ int saved_errno;
+ int consumed;
+ struct recvbuf * rb;
rb = get_free_recv_buffer();
- if (rb == NULL)
- {
+ if (NULL == rb) {
/*
* No buffer space available - just drop the packet
*/
@@ -2872,17 +3269,18 @@ read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
}
i = (rp->datalen == 0
- || rp->datalen > sizeof(rb->recv_space))
- ? sizeof(rb->recv_space) : rp->datalen;
- buflen = read(fd, (char *)&rb->recv_space, (unsigned)i);
+ || rp->datalen > (int)sizeof(rb->recv_space))
+ ? (int)sizeof(rb->recv_space)
+ : rp->datalen;
+ do {
+ buflen = read(fd, (char *)&rb->recv_space, (u_int)i);
+ } while (buflen < 0 && EINTR == errno);
- if (buflen < 0)
- {
- if (errno != EINTR && errno != EAGAIN) {
- netsyslog(LOG_ERR, "clock read fd %d: %m", fd);
- }
+ if (buflen <= 0) {
+ saved_errno = errno;
freerecvbuf(rb);
- return (buflen);
+ errno = saved_errno;
+ return buflen;
}
/*
@@ -2890,85 +3288,141 @@ read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
* put it on the full list and do bookkeeping.
*/
rb->recv_length = buflen;
- rb->recv_srcclock = rp->srcclock;
+ rb->recv_peer = rp->srcclock;
rb->dstadr = 0;
rb->fd = fd;
rb->recv_time = ts;
rb->receiver = rp->clock_recv;
- if (rp->io_input)
- {
- /*
- * have direct input routine for refclocks
- */
- if (rp->io_input(rb) == 0)
- {
- /*
- * data was consumed - nothing to pass up
- * into block input machine
- */
- freerecvbuf(rb);
- return (buflen);
- }
+ consumed = indicate_refclock_packet(rp, rb);
+ if (!consumed) {
+ rp->recvcount++;
+ packets_received++;
}
-
- add_full_recv_buffer(rb);
- rp->recvcount++;
- packets_received++;
- return (buflen);
+ return buflen;
}
+#endif /* REFCLOCK */
-#ifdef HAVE_TIMESTAMP
+
+#ifdef HAVE_PACKET_TIMESTAMP
/*
* extract timestamps from control message buffer
*/
static l_fp
- fetch_timestamp(struct recvbuf *rb, struct msghdr *msghdr, l_fp ts)
+fetch_timestamp(
+ struct recvbuf * rb,
+ struct msghdr * msghdr,
+ l_fp ts
+ )
{
-#ifdef USE_TIMESTAMP_CMSG
- struct cmsghdr *cmsghdr;
+ struct cmsghdr * cmsghdr;
+#ifdef HAVE_BINTIME
+ struct bintime * btp;
+#endif
+#ifdef HAVE_TIMESTAMPNS
+ struct timespec * tsp;
+#endif
+#ifdef HAVE_TIMESTAMP
+ struct timeval * tvp;
+#endif
+ unsigned long ticks;
+ double fuzz;
+ l_fp lfpfuzz;
+ l_fp nts;
+#ifdef DEBUG_TIMING
+ l_fp dts;
+#endif
cmsghdr = CMSG_FIRSTHDR(msghdr);
while (cmsghdr != NULL) {
switch (cmsghdr->cmsg_type)
{
+#ifdef HAVE_BINTIME
+ case SCM_BINTIME:
+#endif /* HAVE_BINTIME */
+#ifdef HAVE_TIMESTAMPNS
+ case SCM_TIMESTAMPNS:
+#endif /* HAVE_TIMESTAMPNS */
+#ifdef HAVE_TIMESTAMP
case SCM_TIMESTAMP:
- {
- struct timeval *tvp = (struct timeval *)CMSG_DATA(cmsghdr);
- double dtemp;
- l_fp nts;
- DPRINTF(4, ("fetch_timestamp: system network time stamp: %ld.%06ld\n", tvp->tv_sec, tvp->tv_usec));
- nts.l_i = tvp->tv_sec + JAN_1970;
- dtemp = tvp->tv_usec / 1e6;
-
- /* fuzz lower bits not covered by precision */
- if (sys_precision != 0)
- dtemp += (ntp_random() / FRAC - .5) / (1 <<
- -sys_precision);
-
- nts.l_uf = (u_int32)(dtemp*FRAC);
-#ifdef DEBUG_TIMING
+#endif /* HAVE_TIMESTAMP */
+#if defined(HAVE_BINTIME) || defined (HAVE_TIMESTAMPNS) || defined(HAVE_TIMESTAMP)
+ switch (cmsghdr->cmsg_type)
{
- l_fp dts = ts;
- L_SUB(&dts, &nts);
- collect_timing(rb, "input processing delay", 1, &dts);
- DPRINTF(4, ("fetch_timestamp: timestamp delta: %s (incl. prec fuzz)\n", lfptoa(&dts, 9)));
+#ifdef HAVE_BINTIME
+ case SCM_BINTIME:
+ btp = (struct bintime *)CMSG_DATA(cmsghdr);
+ /*
+ * bintime documentation is at http://phk.freebsd.dk/pubs/timecounter.pdf
+ */
+ nts.l_i = btp->sec + JAN_1970;
+ nts.l_uf = (u_int32)(btp->frac >> 32);
+ if (sys_tick > measured_tick &&
+ sys_tick > 1e-9) {
+ ticks = (unsigned long)(nts.l_uf / (unsigned long)(sys_tick * FRAC));
+ nts.l_uf = (unsigned long)(ticks * (unsigned long)(sys_tick * FRAC));
+ }
+ DPRINTF(4, ("fetch_timestamp: system bintime network time stamp: %ld.%09lu\n",
+ btp->sec, (unsigned long)((nts.l_uf / FRAC) * 1e9)));
+ break;
+#endif /* HAVE_BINTIME */
+#ifdef HAVE_TIMESTAMPNS
+ case SCM_TIMESTAMPNS:
+ tsp = (struct timespec *)CMSG_DATA(cmsghdr);
+ if (sys_tick > measured_tick &&
+ sys_tick > 1e-9) {
+ ticks = (unsigned long)((tsp->tv_nsec * 1e-9) /
+ sys_tick);
+ tsp->tv_nsec = (long)(ticks * 1e9 *
+ sys_tick);
+ }
+ DPRINTF(4, ("fetch_timestamp: system nsec network time stamp: %ld.%09ld\n",
+ tsp->tv_sec, tsp->tv_nsec));
+ nts = tspec_stamp_to_lfp(*tsp);
+ break;
+#endif /* HAVE_TIMESTAMPNS */
+#ifdef HAVE_TIMESTAMP
+ case SCM_TIMESTAMP:
+ tvp = (struct timeval *)CMSG_DATA(cmsghdr);
+ if (sys_tick > measured_tick &&
+ sys_tick > 1e-6) {
+ ticks = (unsigned long)((tvp->tv_usec * 1e-6) /
+ sys_tick);
+ tvp->tv_usec = (long)(ticks * 1e6 *
+ sys_tick);
+ }
+ DPRINTF(4, ("fetch_timestamp: system usec network time stamp: %jd.%06ld\n",
+ (intmax_t)tvp->tv_sec, (long)tvp->tv_usec));
+ nts = tval_stamp_to_lfp(*tvp);
+ break;
+#endif /* HAVE_TIMESTAMP */
}
-#endif
+ fuzz = ntp_random() * 2. / FRAC * sys_fuzz;
+ DTOLFP(fuzz, &lfpfuzz);
+ L_ADD(&nts, &lfpfuzz);
+#ifdef DEBUG_TIMING
+ dts = ts;
+ L_SUB(&dts, &nts);
+ collect_timing(rb, "input processing delay", 1,
+ &dts);
+ DPRINTF(4, ("fetch_timestamp: timestamp delta: %s (incl. fuzz)\n",
+ lfptoa(&dts, 9)));
+#endif /* DEBUG_TIMING */
ts = nts; /* network time stamp */
break;
- }
+#endif /* HAVE_BINTIME || HAVE_TIMESTAMPNS || HAVE_TIMESTAMP */
+
default:
- DPRINTF(4, ("fetch_timestamp: skipping control message 0x%x\n", cmsghdr->cmsg_type));
- break;
+ DPRINTF(4, ("fetch_timestamp: skipping control message 0x%x\n",
+ cmsghdr->cmsg_type));
}
cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr);
}
-#endif
return ts;
}
-#endif
+#endif /* HAVE_PACKET_TIMESTAMP */
+
/*
* Routine to read the network NTP packets for a specific interface
@@ -2976,15 +3430,19 @@ static l_fp
* read it again or go on to the next one if no bytes returned
*/
static inline int
-read_network_packet(SOCKET fd, struct interface *itf, l_fp ts)
+read_network_packet(
+ SOCKET fd,
+ struct interface * itf,
+ l_fp ts
+ )
{
GETSOCKNAME_SOCKLEN_TYPE fromlen;
int buflen;
register struct recvbuf *rb;
-#ifdef HAVE_TIMESTAMP
+#ifdef HAVE_PACKET_TIMESTAMP
struct msghdr msghdr;
struct iovec iovec;
- char control[TIMESTAMP_CTLMSGBUF_SIZE]; /* pick up control messages */
+ char control[CMSG_BUFSIZE];
#endif
/*
@@ -2995,41 +3453,39 @@ read_network_packet(SOCKET fd, struct interface *itf, l_fp ts)
*/
rb = get_free_recv_buffer();
-
- if (rb == NULL || itf->ignore_packets == ISC_TRUE)
- {
+ if (NULL == rb || itf->ignore_packets) {
char buf[RX_BUFF_SIZE];
- struct sockaddr_storage from;
+ sockaddr_u from;
+
if (rb != NULL)
freerecvbuf(rb);
fromlen = sizeof(from);
buflen = recvfrom(fd, buf, sizeof(buf), 0,
- (struct sockaddr*)&from, &fromlen);
+ &from.sa, &fromlen);
DPRINTF(4, ("%s on (%lu) fd=%d from %s\n",
- (itf->ignore_packets == ISC_TRUE) ? "ignore" : "drop",
- free_recvbuffs(), fd,
- stoa(&from)));
- if (itf->ignore_packets == ISC_TRUE)
+ (itf->ignore_packets)
+ ? "ignore"
+ : "drop",
+ free_recvbuffs(), fd, stoa(&from)));
+ if (itf->ignore_packets)
packets_ignored++;
else
packets_dropped++;
return (buflen);
}
- fromlen = sizeof(struct sockaddr_storage);
+ fromlen = sizeof(rb->recv_srcadr);
-#ifndef HAVE_TIMESTAMP
- rb->recv_length = recvfrom(fd,
- (char *)&rb->recv_space,
- sizeof(rb->recv_space), 0,
- (struct sockaddr *)&rb->recv_srcadr,
- &fromlen);
+#ifndef HAVE_PACKET_TIMESTAMP
+ rb->recv_length = recvfrom(fd, (char *)&rb->recv_space,
+ sizeof(rb->recv_space), 0,
+ &rb->recv_srcadr.sa, &fromlen);
#else
- iovec.iov_base = (void *)&rb->recv_space;
+ iovec.iov_base = &rb->recv_space;
iovec.iov_len = sizeof(rb->recv_space);
- msghdr.msg_name = (void *)&rb->recv_srcadr;
- msghdr.msg_namelen = sizeof(rb->recv_srcadr);
+ msghdr.msg_name = &rb->recv_srcadr;
+ msghdr.msg_namelen = fromlen;
msghdr.msg_iov = &iovec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = (void *)&control;
@@ -3040,38 +3496,48 @@ read_network_packet(SOCKET fd, struct interface *itf, l_fp ts)
buflen = rb->recv_length;
- if (buflen == 0 || (buflen == -1 &&
- (errno==EWOULDBLOCK
+ if (buflen == 0 || (buflen == -1 &&
+ (EWOULDBLOCK == errno
#ifdef EAGAIN
- || errno==EAGAIN
+ || EAGAIN == errno
#endif
- ))) {
+ ))) {
freerecvbuf(rb);
return (buflen);
- }
- else if (buflen < 0)
- {
- netsyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m",
- stoa(&rb->recv_srcadr), fd);
- DPRINTF(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n", fd));
+ } else if (buflen < 0) {
+ msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m",
+ stoa(&rb->recv_srcadr), fd);
+ DPRINTF(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n",
+ fd));
freerecvbuf(rb);
return (buflen);
}
-#ifdef DEBUG
- if (debug > 2) {
- if(rb->recv_srcadr.ss_family == AF_INET)
- printf("read_network_packet: fd=%d length %d from %08lx %s\n",
- fd, buflen,
- (u_long)ntohl(((struct sockaddr_in*)&rb->recv_srcadr)->sin_addr.s_addr) &
- 0x00000000ffffffff,
- stoa(&rb->recv_srcadr));
- else
- printf("read_network_packet: fd=%d length %d from %s\n",
- fd, buflen,
- stoa(&rb->recv_srcadr));
+ DPRINTF(3, ("read_network_packet: fd=%d length %d from %s\n",
+ fd, buflen, stoa(&rb->recv_srcadr)));
+
+ /*
+ ** Bug 2672: Some OSes (MacOSX and Linux) don't block spoofed ::1
+ */
+
+ if (AF_INET6 == itf->family) {
+ DPRINTF(2, ("Got an IPv6 packet, from <%s> (%d) to <%s> (%d)\n",
+ stoa(&rb->recv_srcadr),
+ IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)),
+ stoa(&itf->sin),
+ !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin))
+ ));
+
+ if ( IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr))
+ && !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin))
+ ) {
+ packets_dropped++;
+ DPRINTF(2, ("DROPPING that packet\n"));
+ freerecvbuf(rb);
+ return buflen;
+ }
+ DPRINTF(2, ("processing that packet\n"));
}
-#endif
/*
* Got one. Mark how and when it got here,
@@ -3079,8 +3545,9 @@ read_network_packet(SOCKET fd, struct interface *itf, l_fp ts)
*/
rb->dstadr = itf;
rb->fd = fd;
-#ifdef HAVE_TIMESTAMP
- ts = fetch_timestamp(rb, &msghdr, ts); /* pick up a network time stamp if possible */
+#ifdef HAVE_PACKET_TIMESTAMP
+ /* pick up a network time stamp if possible */
+ ts = fetch_timestamp(rb, &msghdr, ts);
#endif
rb->recv_time = ts;
rb->receiver = receive;
@@ -3093,35 +3560,106 @@ read_network_packet(SOCKET fd, struct interface *itf, l_fp ts)
}
/*
- * input_handler - receive packets asynchronously
+ * attempt to handle io (select()/signaled IO)
*/
void
+io_handler(void)
+{
+# ifndef HAVE_SIGNALED_IO
+ fd_set rdfdes;
+ int nfound;
+
+ /*
+ * Use select() on all on all input fd's for unlimited
+ * time. select() will terminate on SIGALARM or on the
+ * reception of input. Using select() means we can't do
+ * robust signal handling and we get a potential race
+ * between checking for alarms and doing the select().
+ * Mostly harmless, I think.
+ */
+ /*
+ * On VMS, I suspect that select() can't be interrupted
+ * by a "signal" either, so I take the easy way out and
+ * have select() time out after one second.
+ * System clock updates really aren't time-critical,
+ * and - lacking a hardware reference clock - I have
+ * yet to learn about anything else that is.
+ */
+ rdfdes = activefds;
+# if !defined(VMS) && !defined(SYS_VXWORKS)
+ nfound = select(maxactivefd + 1, &rdfdes, NULL,
+ NULL, NULL);
+# else /* VMS, VxWorks */
+ /* make select() wake up after one second */
+ {
+ struct timeval t1;
+
+ t1.tv_sec = 1;
+ t1.tv_usec = 0;
+ nfound = select(maxactivefd + 1,
+ &rdfdes, NULL, NULL,
+ &t1);
+ }
+# endif /* VMS, VxWorks */
+ if (nfound > 0) {
+ l_fp ts;
+
+ get_systime(&ts);
+
+ input_handler(&ts);
+ } else if (nfound == -1 && errno != EINTR) {
+ msyslog(LOG_ERR, "select() error: %m");
+ }
+# ifdef DEBUG
+ else if (debug > 4) {
+ msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
+ } else {
+ DPRINTF(3, ("select() returned %d: %m\n", nfound));
+ }
+# endif /* DEBUG */
+# else /* HAVE_SIGNALED_IO */
+ wait_for_signal();
+# endif /* HAVE_SIGNALED_IO */
+}
+
+/*
+ * input_handler - receive packets asynchronously
+ */
+static void
input_handler(
- l_fp *cts
+ l_fp * cts
)
{
-
- int buflen;
- int n;
- int doing;
- SOCKET fd;
- struct timeval tvzero;
- l_fp ts; /* Timestamp at BOselect() gob */
+ int buflen;
+ int n;
+ u_int idx;
+ int doing;
+ SOCKET fd;
+ blocking_child *c;
+ struct timeval tvzero;
+ l_fp ts; /* Timestamp at BOselect() gob */
#ifdef DEBUG_TIMING
- l_fp ts_e; /* Timestamp at EOselect() gob */
+ l_fp ts_e; /* Timestamp at EOselect() gob */
#endif
- fd_set fds;
- int select_count = 0;
- struct interface *interface;
-#if defined(HAS_ROUTING_SOCKET)
- struct asyncio_reader *asyncio_reader;
+ fd_set fds;
+ size_t select_count;
+ endpt * ep;
+#ifdef REFCLOCK
+ struct refclockio *rp;
+ int saved_errno;
+ const char * clk;
+#endif
+#ifdef HAS_ROUTING_SOCKET
+ struct asyncio_reader * asyncio_reader;
+ struct asyncio_reader * next_asyncio_reader;
#endif
handler_calls++;
+ select_count = 0;
/*
* If we have something to do, freeze a timestamp.
- * See below for the other cases (nothing (left) to do or error)
+ * See below for the other cases (nothing left to do or error)
*/
ts = *cts;
@@ -3132,33 +3670,43 @@ input_handler(
fds = activefds;
tvzero.tv_sec = tvzero.tv_usec = 0;
- n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
+ n = select(maxactivefd + 1, &fds, (fd_set *)0, (fd_set *)0,
+ &tvzero);
/*
* If there are no packets waiting just return
*/
- if (n < 0)
- {
+ if (n < 0) {
int err = errno;
+ int j, b, prior;
/*
* extended FAU debugging output
*/
if (err != EINTR)
- netsyslog(LOG_ERR,
- "select(%d, %s, 0L, 0L, &0.0) error: %m",
- maxactivefd+1,
- fdbits(maxactivefd, &activefds));
- if (err == EBADF) {
- int j, b;
- fds = activefds;
- for (j = 0; j <= maxactivefd; j++)
- if ((FD_ISSET(j, &fds) && (read(j, &b, 0) == -1)))
- netsyslog(LOG_ERR, "Bad file descriptor %d", j);
+ msyslog(LOG_ERR,
+ "select(%d, %s, 0L, 0L, &0.0) error: %m",
+ maxactivefd + 1,
+ fdbits(maxactivefd, &activefds));
+ if (err != EBADF)
+ goto ih_return;
+ for (j = 0, prior = 0; j <= maxactivefd; j++) {
+ if (FD_ISSET(j, &activefds)) {
+ if (-1 != read(j, &b, 0)) {
+ prior = j;
+ continue;
+ }
+ msyslog(LOG_ERR,
+ "Removing bad file descriptor %d from select set",
+ j);
+ FD_CLR(j, &activefds);
+ if (j == maxactivefd)
+ maxactivefd = prior;
+ }
}
- return;
+ goto ih_return;
}
else if (n == 0)
- return;
+ goto ih_return;
++handler_pkts;
@@ -3167,55 +3715,64 @@ input_handler(
* Check out the reference clocks first, if any
*/
- if (refio != NULL)
- {
- register struct refclockio *rp;
-
- for (rp = refio; rp != NULL; rp = rp->next)
- {
+ if (refio != NULL) {
+ for (rp = refio; rp != NULL; rp = rp->next) {
fd = rp->fd;
- if (FD_ISSET(fd, &fds))
- {
+ if (!FD_ISSET(fd, &fds))
+ continue;
+ ++select_count;
+ buflen = read_refclock_packet(fd, rp, ts);
+ /*
+ * The first read must succeed after select()
+ * indicates readability, or we've reached
+ * a permanent EOF. http://bugs.ntp.org/1732
+ * reported ntpd munching CPU after a USB GPS
+ * was unplugged because select was indicating
+ * EOF but ntpd didn't remove the descriptor
+ * from the activefds set.
+ */
+ if (buflen < 0 && EAGAIN != errno) {
+ saved_errno = errno;
+ clk = refnumtoa(&rp->srcclock->srcadr);
+ errno = saved_errno;
+ msyslog(LOG_ERR, "%s read: %m", clk);
+ maintain_activefds(fd, TRUE);
+ } else if (0 == buflen) {
+ clk = refnumtoa(&rp->srcclock->srcadr);
+ msyslog(LOG_ERR, "%s read EOF", clk);
+ maintain_activefds(fd, TRUE);
+ } else {
+ /* drain any remaining refclock input */
do {
- ++select_count;
buflen = read_refclock_packet(fd, rp, ts);
} while (buflen > 0);
-
- } /* End if (FD_ISSET(fd, &fds)) */
- } /* End for (rp = refio; rp != 0 && n > 0; rp = rp->next) */
- } /* End if (refio != 0) */
-
+ }
+ }
+ }
#endif /* REFCLOCK */
/*
* Loop through the interfaces looking for data to read.
*/
- for (interface = ISC_LIST_TAIL(inter_list);
- interface != NULL;
- interface = ISC_LIST_PREV(interface, link))
- {
- for (doing = 0; (doing < 2); doing++)
- {
- if (doing == 0)
- {
- fd = interface->fd;
- }
- else
- {
- if (!(interface->flags & INT_BCASTOPEN))
- break;
- fd = interface->bfd;
+ for (ep = ep_list; ep != NULL; ep = ep->elink) {
+ for (doing = 0; doing < 2; doing++) {
+ if (!doing) {
+ fd = ep->fd;
+ } else {
+ if (!(ep->flags & INT_BCASTOPEN))
+ break;
+ fd = ep->bfd;
}
- if (fd < 0) continue;
+ if (fd < 0)
+ continue;
if (FD_ISSET(fd, &fds))
- {
do {
++select_count;
- buflen = read_network_packet(fd, interface, ts);
+ buflen = read_network_packet(
+ fd, ep, ts);
} while (buflen > 0);
- }
- /* Check more interfaces */
+ /* Check more interfaces */
}
}
@@ -3223,36 +3780,45 @@ input_handler(
/*
* scan list of asyncio readers - currently only used for routing sockets
*/
- asyncio_reader = ISC_LIST_TAIL(asyncio_reader_list);
+ asyncio_reader = asyncio_reader_list;
- while (asyncio_reader != NULL)
- {
- struct asyncio_reader *next = ISC_LIST_PREV(asyncio_reader, link);
+ while (asyncio_reader != NULL) {
+ /* callback may unlink and free asyncio_reader */
+ next_asyncio_reader = asyncio_reader->link;
if (FD_ISSET(asyncio_reader->fd, &fds)) {
++select_count;
- asyncio_reader->receiver(asyncio_reader);
+ (*asyncio_reader->receiver)(asyncio_reader);
}
- asyncio_reader = next;
+ asyncio_reader = next_asyncio_reader;
}
#endif /* HAS_ROUTING_SOCKET */
-
+
/*
- * Done everything from that select.
+ * Check for a response from a blocking child
*/
+ for (idx = 0; idx < blocking_children_alloc; idx++) {
+ c = blocking_children[idx];
+ if (NULL == c || -1 == c->resp_read_pipe)
+ continue;
+ if (FD_ISSET(c->resp_read_pipe, &fds)) {
+ select_count++;
+ process_blocking_resp(c);
+ }
+ }
/*
+ * Done everything from that select.
* If nothing to do, just return.
* If an error occurred, complain and return.
*/
- if (select_count == 0) /* We really had nothing to do */
- {
+ if (select_count == 0) { /* We really had nothing to do */
#ifdef DEBUG
if (debug)
- netsyslog(LOG_DEBUG, "input_handler: select() returned 0");
-#endif
- return;
+ msyslog(LOG_DEBUG, "input_handler: select() returned 0");
+#endif /* DEBUG */
+ goto ih_return;
}
- /* We've done our work */
+ /* We've done our work */
#ifdef DEBUG_TIMING
get_systime(&ts_e);
/*
@@ -3263,44 +3829,109 @@ input_handler(
L_SUB(&ts_e, &ts);
collect_timing(NULL, "input handler", 1, &ts_e);
if (debug > 3)
- netsyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6));
-#endif
- /* just bail. */
+ msyslog(LOG_DEBUG,
+ "input_handler: Processed a gob of fd's in %s msec",
+ lfptoms(&ts_e, 6));
+#endif /* DEBUG_TIMING */
+ /* We're done... */
+ ih_return:
return;
}
+#endif /* !HAVE_IO_COMPLETION_PORT */
+
+/*
+ * find an interface suitable for the src address
+ */
+endpt *
+select_peerinterface(
+ struct peer * peer,
+ sockaddr_u * srcadr,
+ endpt * dstadr
+ )
+{
+ endpt *ep;
+#ifndef SIM
+ endpt *wild;
+
+ wild = ANY_INTERFACE_CHOOSE(srcadr);
+
+ /*
+ * Initialize the peer structure and dance the interface jig.
+ * Reference clocks step the loopback waltz, the others
+ * squaredance around the interface list looking for a buddy. If
+ * the dance peters out, there is always the wildcard interface.
+ * This might happen in some systems and would preclude proper
+ * operation with public key cryptography.
+ */
+ if (ISREFCLOCKADR(srcadr)) {
+ ep = loopback_interface;
+ } else if (peer->cast_flags &
+ (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
+ ep = findbcastinter(srcadr);
+ if (ep != NULL)
+ DPRINTF(4, ("Found *-cast interface %s for address %s\n",
+ stoa(&ep->sin), stoa(srcadr)));
+ else
+ DPRINTF(4, ("No *-cast local address found for address %s\n",
+ stoa(srcadr)));
+ } else {
+ ep = dstadr;
+ if (NULL == ep)
+ ep = wild;
+ }
+ /*
+ * If it is a multicast address, findbcastinter() may not find
+ * it. For unicast, we get to find the interface when dstadr is
+ * given to us as the wildcard (ANY_INTERFACE_CHOOSE). Either
+ * way, try a little harder.
+ */
+ if (wild == ep)
+ ep = findinterface(srcadr);
+ /*
+ * we do not bind to the wildcard interfaces for output
+ * as our (network) source address would be undefined and
+ * crypto will not work without knowing the own transmit address
+ */
+ if (ep != NULL && INT_WILDCARD & ep->flags)
+ if (!accept_wildcard_if_for_winnt)
+ ep = NULL;
+#else /* SIM follows */
+ ep = loopback_interface;
#endif
+ return ep;
+}
+
+
/*
* findinterface - find local interface corresponding to address
*/
-struct interface *
+endpt *
findinterface(
- struct sockaddr_storage *addr
+ sockaddr_u *addr
)
{
- struct interface *interface;
-
- interface = findlocalinterface(addr, INT_WILDCARD);
+ endpt *iface;
- if (interface == NULL)
- {
+ iface = findlocalinterface(addr, INT_WILDCARD, 0);
+
+ if (NULL == iface) {
DPRINTF(4, ("Found no interface for address %s - returning wildcard\n",
stoa(addr)));
- return (ANY_INTERFACE_CHOOSE(addr));
- }
- else
- {
+ iface = ANY_INTERFACE_CHOOSE(addr);
+ } else
DPRINTF(4, ("Found interface #%d %s for address %s\n",
- interface->ifnum, interface->name, stoa(addr)));
+ iface->ifnum, iface->name, stoa(addr)));
- return (interface);
- }
+ return iface;
}
/*
- * findlocalinterface - find local interface index corresponding to address
+ * findlocalinterface - find local interface corresponding to addr,
+ * which does not have any of flags set. If bast is nonzero, addr is
+ * a broadcast address.
*
* This code attempts to find the local sending address for an outgoing
* address by connecting a new socket to destinationaddress:NTP_PORT
@@ -3312,246 +3943,307 @@ findinterface(
* logic in ntpd which would be a silly and really unportable thing to do.
*
*/
-static struct interface *
+static endpt *
findlocalinterface(
- struct sockaddr_storage *addr,
- int flags
+ sockaddr_u * addr,
+ int flags,
+ int bcast
)
{
- SOCKET s;
- int rtn;
- struct sockaddr_storage saddr;
- GETSOCKNAME_SOCKLEN_TYPE saddrlen = SOCKLEN(addr);
- struct interface *iface;
+ GETSOCKNAME_SOCKLEN_TYPE sockaddrlen;
+ endpt * iface;
+ sockaddr_u saddr;
+ SOCKET s;
+ int rtn;
+ int on;
DPRINTF(4, ("Finding interface for addr %s in list of addresses\n",
stoa(addr)));
- memset(&saddr, 0, sizeof(saddr));
- saddr.ss_family = addr->ss_family;
- if(addr->ss_family == AF_INET) {
- memcpy(&((struct sockaddr_in*)&saddr)->sin_addr, &((struct sockaddr_in*)addr)->sin_addr, sizeof(struct in_addr));
- ((struct sockaddr_in*)&saddr)->sin_port = htons(NTP_PORT);
- }
-#ifdef INCLUDE_IPV6_SUPPORT
- else if(addr->ss_family == AF_INET6) {
- memcpy(&((struct sockaddr_in6*)&saddr)->sin6_addr, &((struct sockaddr_in6*)addr)->sin6_addr, sizeof(struct in6_addr));
- ((struct sockaddr_in6*)&saddr)->sin6_port = htons(NTP_PORT);
-# ifdef ISC_PLATFORM_HAVESCOPEID
- ((struct sockaddr_in6*)&saddr)->sin6_scope_id = ((struct sockaddr_in6*)addr)->sin6_scope_id;
-# endif
- }
-#endif
-
- s = socket(addr->ss_family, SOCK_DGRAM, 0);
- if (s == INVALID_SOCKET)
+ s = socket(AF(addr), SOCK_DGRAM, 0);
+ if (INVALID_SOCKET == s)
return NULL;
- rtn = connect(s, (struct sockaddr *)&saddr, SOCKLEN(&saddr));
-#ifndef SYS_WINNT
- if (rtn < 0)
-#else
- if (rtn == SOCKET_ERROR)
-#endif
- {
+ /*
+ * If we are looking for broadcast interface we need to set this
+ * socket to allow broadcast
+ */
+ if (bcast) {
+ on = 1;
+ if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET,
+ SO_BROADCAST,
+ (char *)&on,
+ sizeof(on))) {
+ closesocket(s);
+ return NULL;
+ }
+ }
+
+ rtn = connect(s, &addr->sa, SOCKLEN(addr));
+ if (SOCKET_ERROR == rtn) {
closesocket(s);
return NULL;
}
- rtn = getsockname(s, (struct sockaddr *)&saddr, &saddrlen);
+ sockaddrlen = sizeof(saddr);
+ rtn = getsockname(s, &saddr.sa, &sockaddrlen);
closesocket(s);
-#ifndef SYS_WINNT
- if (rtn < 0)
-#else
- if (rtn == SOCKET_ERROR)
-#endif
+ if (SOCKET_ERROR == rtn)
return NULL;
- DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n", stoa(addr), stoa(&saddr)));
-
+ DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n",
+ stoa(addr), stoa(&saddr)));
+
iface = getinterface(&saddr, flags);
- /* Don't both with ignore interfaces */
- if (iface != NULL && iface->ignore_packets == ISC_TRUE)
- {
- return NULL;
- }
- else
- {
- return iface;
- }
+ /*
+ * if we didn't find an exact match on saddr, find the closest
+ * available local address. This handles the case of the
+ * address suggested by the kernel being excluded by nic rules
+ * or the user's -I and -L options to ntpd.
+ * See http://bugs.ntp.org/1184 and http://bugs.ntp.org/1683
+ * for more background.
+ */
+ if (NULL == iface || iface->ignore_packets)
+ iface = findclosestinterface(&saddr,
+ flags | INT_LOOPBACK);
+
+ /* Don't use an interface which will ignore replies */
+ if (iface != NULL && iface->ignore_packets)
+ iface = NULL;
+
+ return iface;
}
+
/*
- * fetch an interface structure the matches the
- * address is has the given flags not set
+ * findclosestinterface
+ *
+ * If there are -I/--interface or -L/novirtualips command-line options,
+ * or "nic" or "interface" rules in ntp.conf, findlocalinterface() may
+ * find the kernel's preferred local address for a given peer address is
+ * administratively unavailable to ntpd, and punt to this routine's more
+ * expensive search.
+ *
+ * Find the numerically closest local address to the one connect()
+ * suggested. This matches an address on the same subnet first, as
+ * needed by Bug 1184, and provides a consistent choice if there are
+ * multiple feasible local addresses, regardless of the order ntpd
+ * enumerated them.
*/
-static struct interface *
-getinterface(struct sockaddr_storage *addr, int flags)
+endpt *
+findclosestinterface(
+ sockaddr_u * addr,
+ int flags
+ )
{
- struct interface *interface = find_addr_in_list(addr);
+ endpt * ep;
+ endpt * winner;
+ sockaddr_u addr_dist;
+ sockaddr_u min_dist;
+
+ ZERO_SOCK(&min_dist);
+ winner = NULL;
+
+ for (ep = ep_list; ep != NULL; ep = ep->elink) {
+ if (ep->ignore_packets ||
+ AF(addr) != ep->family ||
+ flags & ep->flags)
+ continue;
- if (interface != NULL && interface->flags & flags)
- {
- return NULL;
+ calc_addr_distance(&addr_dist, addr, &ep->sin);
+ if (NULL == winner ||
+ -1 == cmp_addr_distance(&addr_dist, &min_dist)) {
+ min_dist = addr_dist;
+ winner = ep;
+ }
}
+ if (NULL == winner)
+ DPRINTF(4, ("findclosestinterface(%s) failed\n",
+ stoa(addr)));
else
- {
- return interface;
- }
+ DPRINTF(4, ("findclosestinterface(%s) -> %s\n",
+ stoa(addr), stoa(&winner->sin)));
+
+ return winner;
}
+
/*
- * findlocalcastinterface - find local *cast interface index corresponding to address
- * depending on the flags passed
+ * calc_addr_distance - calculate the distance between two addresses,
+ * the absolute value of the difference between
+ * the addresses numerically, stored as an address.
*/
-static struct interface *
-findlocalcastinterface(
- struct sockaddr_storage *addr, int flags
+static void
+calc_addr_distance(
+ sockaddr_u * dist,
+ const sockaddr_u * a1,
+ const sockaddr_u * a2
)
{
- struct interface *interface;
- struct interface *nif = NULL;
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- isc_boolean_t want_linklocal;
-#endif
-
- /*
- * see how kernel maps the mcast address
- */
- nif = findlocalinterface(addr, 0);
+ u_int32 a1val;
+ u_int32 a2val;
+ u_int32 v4dist;
+ int found_greater;
+ int a1_greater;
+ int i;
+
+ NTP_REQUIRE(AF(a1) == AF(a2));
+
+ ZERO_SOCK(dist);
+ AF(dist) = AF(a1);
+
+ /* v4 can be done a bit simpler */
+ if (IS_IPV4(a1)) {
+ a1val = SRCADR(a1);
+ a2val = SRCADR(a2);
+ v4dist = (a1val > a2val)
+ ? a1val - a2val
+ : a2val - a1val;
+ SET_ADDR4(dist, v4dist);
- if (nif) {
- DPRINTF(2, ("findlocalcastinterface: kernel recommends interface #%d %s\n", nif->ifnum, nif->name));
- return nif;
+ return;
}
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- want_linklocal = ISC_FALSE;
- if (addr_ismulticast(addr) && flags == INT_MULTICAST)
- {
- if (IN6_IS_ADDR_MC_LINKLOCAL(&((struct sockaddr_in6*)addr)->sin6_addr))
- {
- want_linklocal = ISC_TRUE;
+ found_greater = FALSE;
+ a1_greater = FALSE; /* suppress pot. uninit. warning */
+ for (i = 0; i < (int)sizeof(NSRCADR6(a1)); i++) {
+ if (!found_greater &&
+ NSRCADR6(a1)[i] != NSRCADR6(a2)[i]) {
+ found_greater = TRUE;
+ a1_greater = (NSRCADR6(a1)[i] > NSRCADR6(a2)[i]);
}
- else if (IN6_IS_ADDR_MC_SITELOCAL(&((struct sockaddr_in6*)addr)->sin6_addr))
- {
- want_linklocal = ISC_TRUE;
+ if (!found_greater) {
+ NSRCADR6(dist)[i] = 0;
+ } else {
+ if (a1_greater)
+ NSRCADR6(dist)[i] = NSRCADR6(a1)[i] -
+ NSRCADR6(a2)[i];
+ else
+ NSRCADR6(dist)[i] = NSRCADR6(a2)[i] -
+ NSRCADR6(a1)[i];
}
}
-#endif
+}
- for (interface = ISC_LIST_HEAD(inter_list);
- interface != NULL;
- interface = ISC_LIST_NEXT(interface, link))
- {
- /* use only allowed addresses */
- if (interface->ignore_packets == ISC_TRUE)
- continue;
- /* Skip the loopback and wildcard addresses */
- if (interface->flags & (INT_LOOPBACK|INT_WILDCARD))
- continue;
-
- /* Skip if different family */
- if(interface->sin.ss_family != addr->ss_family)
- continue;
+/*
+ * cmp_addr_distance - compare two address distances, returning -1, 0,
+ * 1 to indicate their relationship.
+ */
+static int
+cmp_addr_distance(
+ const sockaddr_u * d1,
+ const sockaddr_u * d2
+ )
+{
+ int i;
- /* Is this it one of these based on flags? */
- if (!(interface->flags & flags))
- continue;
+ NTP_REQUIRE(AF(d1) == AF(d2));
- /* for IPv6 multicast check the address for linklocal */
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
- if (flags == INT_MULTICAST && interface->sin.ss_family == AF_INET6 &&
- (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6*)&interface->sin)->sin6_addr))
- && want_linklocal == ISC_TRUE)
- {
- nif = interface;
- break;
- }
- /* If we want a linklocal address and this isn't it, skip */\
- if (want_linklocal == ISC_TRUE)
- continue;
-#endif
- /* Otherwise just look for the flag */
- if((interface->flags & flags))
- {
- nif = interface;
- break;
- }
- }
-#ifdef DEBUG
- if (debug > 2)
- {
- if (nif)
- printf("findlocalcastinterface: found interface #%d %s\n", nif->ifnum, nif->name);
+ if (IS_IPV4(d1)) {
+ if (SRCADR(d1) < SRCADR(d2))
+ return -1;
+ else if (SRCADR(d1) == SRCADR(d2))
+ return 0;
else
- printf("findlocalcastinterface: no interface found for %s flags 0x%x\n", stoa(addr), flags);
+ return 1;
}
-#endif
- return (nif);
+
+ for (i = 0; i < (int)sizeof(NSRCADR6(d1)); i++) {
+ if (NSRCADR6(d1)[i] < NSRCADR6(d2)[i])
+ return -1;
+ else if (NSRCADR6(d1)[i] > NSRCADR6(d2)[i])
+ return 1;
+ }
+
+ return 0;
}
+
+
+/*
+ * fetch an interface structure the matches the
+ * address and has the given flags NOT set
+ */
+endpt *
+getinterface(
+ sockaddr_u * addr,
+ u_int32 flags
+ )
+{
+ endpt *iface;
+
+ iface = find_addr_in_list(addr);
+
+ if (iface != NULL && (iface->flags & flags))
+ iface = NULL;
+
+ return iface;
+}
+
+
/*
* findbcastinter - find broadcast interface corresponding to address
*/
-struct interface *
+endpt *
findbcastinter(
- struct sockaddr_storage *addr
+ sockaddr_u *addr
)
{
+ endpt * iface;
+
+ iface = NULL;
#if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT))
- struct interface *interface;
-
-
DPRINTF(4, ("Finding broadcast/multicast interface for addr %s in list of addresses\n",
stoa(addr)));
- interface = findlocalinterface(addr, INT_LOOPBACK|INT_WILDCARD);
-
- if (interface != NULL)
- {
- DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n", interface->ifnum, interface->name));
- return interface;
+ iface = findlocalinterface(addr, INT_LOOPBACK | INT_WILDCARD,
+ 1);
+ if (iface != NULL) {
+ DPRINTF(4, ("Easily found bcast-/mcast- interface index #%d %s\n",
+ iface->ifnum, iface->name));
+ return iface;
}
- /* plan B - try to find something reasonable in our lists in case kernel lookup doesn't help */
+ /*
+ * plan B - try to find something reasonable in our lists in
+ * case kernel lookup doesn't help
+ */
+ for (iface = ep_list; iface != NULL; iface = iface->elink) {
+ if (iface->flags & INT_WILDCARD)
+ continue;
- for (interface = ISC_LIST_HEAD(inter_list);
- interface != NULL;
- interface = ISC_LIST_NEXT(interface, link))
- {
- if (interface->flags & INT_WILDCARD)
- continue;
-
/* Don't bother with ignored interfaces */
- if (interface->ignore_packets == ISC_TRUE)
+ if (iface->ignore_packets)
continue;
-
+
/*
* First look if this is the correct family
*/
- if(interface->sin.ss_family != addr->ss_family)
- continue;
+ if(AF(&iface->sin) != AF(addr))
+ continue;
/* Skip the loopback addresses */
- if (interface->flags & INT_LOOPBACK)
+ if (iface->flags & INT_LOOPBACK)
continue;
/*
- * If we are looking to match a multicast address grab it.
+ * If we are looking to match a multicast address and
+ * this interface is one...
*/
- if (addr_ismulticast(addr) == ISC_TRUE && interface->flags & INT_MULTICAST)
- {
+ if (addr_ismulticast(addr)
+ && (iface->flags & INT_MULTICAST)) {
#ifdef INCLUDE_IPV6_SUPPORT
- if(addr->ss_family == AF_INET6) {
- /* Only use link-local address for link-scope mcast */
- if(IN6_IS_ADDR_MC_LINKLOCAL(&((struct sockaddr_in6*)addr)->sin6_addr) &&
- !IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6*)&interface->sin)->sin6_addr)) {
- continue;
- }
- }
+ /*
+ * ...it is the winner unless we're looking for
+ * an interface to use for link-local multicast
+ * and its address is not link-local.
+ */
+ if (IS_IPV6(addr)
+ && IN6_IS_ADDR_MC_LINKLOCAL(PSOCK_ADDR6(addr))
+ && !IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&iface->sin)))
+ continue;
#endif
break;
}
@@ -3562,34 +4254,35 @@ findbcastinter(
* address or the network portion of the IP address.
* Sloppy.
*/
- if(addr->ss_family == AF_INET) {
- if (SOCKCMP(&interface->bcast, addr)) {
+ if (IS_IPV4(addr)) {
+ if (SOCK_EQ(&iface->bcast, addr))
break;
- }
- if ((NSRCADR(&interface->sin) &
- NSRCADR(&interface->mask)) == (NSRCADR(addr) &
- NSRCADR(&interface->mask)))
+
+ if ((NSRCADR(&iface->sin) & NSRCADR(&iface->mask))
+ == (NSRCADR(addr) & NSRCADR(&iface->mask)))
break;
}
#ifdef INCLUDE_IPV6_SUPPORT
- else if(addr->ss_family == AF_INET6) {
- if (SOCKCMP(&interface->bcast, addr)) {
+ else if (IS_IPV6(addr)) {
+ if (SOCK_EQ(&iface->bcast, addr))
break;
- }
- if (SOCKCMP(netof(&interface->sin), netof(addr))) {
+
+ if (SOCK_EQ(netof(&iface->sin), netof(addr)))
break;
- }
}
#endif
}
#endif /* SIOCGIFCONF */
- if (interface == NULL) {
- DPRINTF(4, ("No bcast interface found for %s\n", stoa(addr)));
- return ANY_INTERFACE_CHOOSE(addr);
+ if (NULL == iface) {
+ DPRINTF(4, ("No bcast interface found for %s\n",
+ stoa(addr)));
+ iface = ANY_INTERFACE_CHOOSE(addr);
} else {
- DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n", interface->ifnum, interface->name));
- return interface;
+ DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n",
+ iface->ifnum, iface->name));
}
+
+ return iface;
}
@@ -3622,21 +4315,20 @@ io_addclock(
)
{
BLOCKIO();
+
/*
* Stuff the I/O structure in the list and mark the descriptor
- * in use. There is a harmless (I hope) race condition here.
+ * in use. There is a harmless (I hope) race condition here.
*/
- rio->next = refio;
+ rio->active = TRUE;
# ifdef HAVE_SIGNALED_IO
- if (init_clock_sig(rio))
- {
+ if (init_clock_sig(rio)) {
UNBLOCKIO();
return 0;
}
# elif defined(HAVE_IO_COMPLETION_PORT)
- if (io_completion_port_add_clock_io(rio))
- {
+ if (io_completion_port_add_clock_io(rio)) {
UNBLOCKIO();
return 0;
}
@@ -3645,9 +4337,9 @@ io_addclock(
/*
* enqueue
*/
- refio = rio;
+ LINK_SLIST(refio, rio, next);
- /*
+ /*
* register fd
*/
add_fd_to_list(rio->fd, FD_TYPE_FILE);
@@ -3656,6 +4348,7 @@ io_addclock(
return 1;
}
+
/*
* io_closeclock - close the clock in the I/O structure given
*/
@@ -3664,267 +4357,270 @@ io_closeclock(
struct refclockio *rio
)
{
+ struct refclockio *unlinked;
+
BLOCKIO();
+
/*
* Remove structure from the list
*/
- if (refio == rio)
- {
- refio = rio->next;
- }
- else
- {
- register struct refclockio *rp;
-
- for (rp = refio; rp != NULL; rp = rp->next)
- if (rp->next == rio)
- {
- rp->next = rio->next;
- break;
- }
-
- if (rp == NULL) {
- UNBLOCKIO();
- return;
- }
+ rio->active = FALSE;
+ UNLINK_SLIST(unlinked, refio, rio, next, struct refclockio);
+ if (NULL != unlinked) {
+ purge_recv_buffers_for_fd(rio->fd);
+ /*
+ * Close the descriptor.
+ */
+ close_and_delete_fd_from_list(rio->fd);
}
+ rio->fd = -1;
- /*
- * Close the descriptor.
- */
- close_and_delete_fd_from_list(rio->fd);
UNBLOCKIO();
}
#endif /* REFCLOCK */
+
/*
* On NT a SOCKET is an unsigned int so we cannot possibly keep it in
* an array. So we use one of the ISC_LIST functions to hold the
* socket value and use that when we want to enumerate it.
+ *
+ * This routine is called by the forked intres child process to close
+ * all open sockets. On Windows there's no need as intres runs in
+ * the same process as a thread.
*/
+#ifndef SYS_WINNT
void
-kill_asyncio(int startfd)
+kill_asyncio(
+ int startfd
+ )
{
- vsock_t *lsock;
- vsock_t *next;
-
BLOCKIO();
- lsock = ISC_LIST_HEAD(fd_list);
- while (lsock != NULL) {
- /*
- * careful here - list is being dismantled while
- * we scan it - setting next here insures that
- * we are able to correctly scan the list
- */
- next = ISC_LIST_NEXT(lsock, link);
- /*
- * will remove socket from list
- */
- close_and_delete_fd_from_list(lsock->fd);
- lsock = next;
- }
+ /*
+ * In the child process we do not maintain activefds and
+ * maxactivefd. Zeroing maxactivefd disables code which
+ * maintains it in close_and_delete_fd_from_list().
+ */
+ maxactivefd = 0;
+
+ while (fd_list != NULL)
+ close_and_delete_fd_from_list(fd_list->fd);
UNBLOCKIO();
}
+#endif /* !SYS_WINNT */
+
/*
* Add and delete functions for the list of open sockets
*/
static void
-add_fd_to_list(SOCKET fd, enum desc_type type) {
- vsock_t *lsock = (vsock_t *)emalloc(sizeof(vsock_t));
+add_fd_to_list(
+ SOCKET fd,
+ enum desc_type type
+ )
+{
+ vsock_t *lsock = emalloc(sizeof(*lsock));
+
lsock->fd = fd;
lsock->type = type;
- ISC_LIST_APPEND(fd_list, lsock, link);
- /*
- * I/O Completion Ports don't care about the select and FD_SET
- */
-#ifndef HAVE_IO_COMPLETION_PORT
- if (fd < 0 || fd >= FD_SETSIZE) {
- msyslog(LOG_ERR, "Too many sockets in use, FD_SETSIZE %d exceeded",
- FD_SETSIZE);
- exit(1);
- }
- /*
- * keep activefds in sync
- */
- if (fd > maxactivefd)
- maxactivefd = fd;
- FD_SET( (u_int)fd, &activefds);
-#endif
+ LINK_SLIST(fd_list, lsock, link);
+ maintain_activefds(fd, 0);
}
+
static void
-close_and_delete_fd_from_list(SOCKET fd) {
+close_and_delete_fd_from_list(
+ SOCKET fd
+ )
+{
+ vsock_t *lsock;
- vsock_t *next;
- vsock_t *lsock = ISC_LIST_HEAD(fd_list);
+ UNLINK_EXPR_SLIST(lsock, fd_list, fd ==
+ UNLINK_EXPR_SLIST_CURRENT()->fd, link, vsock_t);
- while(lsock != NULL) {
- next = ISC_LIST_NEXT(lsock, link);
- if(lsock->fd == fd) {
- ISC_LIST_DEQUEUE_TYPE(fd_list, lsock, link, vsock_t);
+ if (NULL == lsock)
+ return;
- switch (lsock->type) {
- case FD_TYPE_SOCKET:
-#ifdef SYS_WINNT
- closesocket(lsock->fd);
- break;
-#endif
- case FD_TYPE_FILE:
- (void) close(lsock->fd);
- break;
- default:
- msyslog(LOG_ERR, "internal error - illegal descriptor type %d - EXITING", (int)lsock->type);
- exit(1);
- }
+ switch (lsock->type) {
- free(lsock);
- /*
- * I/O Completion Ports don't care about select and fd_set
- */
-#ifndef HAVE_IO_COMPLETION_PORT
- /*
- * remove from activefds
- */
- FD_CLR( (u_int) fd, &activefds);
-
- if (fd == maxactivefd) {
- int i, newmax = 0;
- for (i = 0; i < maxactivefd; i++)
- if (FD_ISSET(i, &activefds))
- newmax = i;
- maxactivefd = newmax;
- }
-#endif
- break;
- }
- lsock = next;
+ case FD_TYPE_SOCKET:
+ closesocket(lsock->fd);
+ break;
+
+ case FD_TYPE_FILE:
+ closeserial(lsock->fd);
+ break;
+
+ default:
+ msyslog(LOG_ERR,
+ "internal error - illegal descriptor type %d - EXITING",
+ (int)lsock->type);
+ exit(1);
}
+
+ free(lsock);
+ /*
+ * remove from activefds
+ */
+ maintain_activefds(fd, 1);
}
+
static void
-add_addr_to_list(struct sockaddr_storage *addr, struct interface *interface){
+add_addr_to_list(
+ sockaddr_u * addr,
+ endpt * ep
+ )
+{
+ remaddr_t *laddr;
+
#ifdef DEBUG
if (find_addr_in_list(addr) == NULL) {
#endif
/* not there yet - add to list */
- remaddr_t *laddr = (remaddr_t *)emalloc(sizeof(remaddr_t));
- memcpy(&laddr->addr, addr, sizeof(struct sockaddr_storage));
- laddr->interface = interface;
-
- ISC_LIST_APPEND(remoteaddr_list, laddr, link);
-
+ laddr = emalloc(sizeof(*laddr));
+ laddr->addr = *addr;
+ laddr->ep = ep;
+
+ LINK_SLIST(remoteaddr_list, laddr, link);
+
DPRINTF(4, ("Added addr %s to list of addresses\n",
stoa(addr)));
#ifdef DEBUG
- } else {
+ } else
DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n",
stoa(addr)));
- }
#endif
}
+
static void
-delete_addr_from_list(struct sockaddr_storage *addr) {
-
- remaddr_t *next;
- remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
-
- while(laddr != NULL) {
- next = ISC_LIST_NEXT(laddr, link);
- if(SOCKCMP(&laddr->addr, addr)) {
- ISC_LIST_DEQUEUE_TYPE(remoteaddr_list, laddr, link, remaddr_t);
- DPRINTF(4, ("Deleted addr %s from list of addresses\n",
- stoa(addr)));
- free(laddr);
- break;
- }
- laddr = next;
+delete_addr_from_list(
+ sockaddr_u *addr
+ )
+{
+ remaddr_t *unlinked;
+
+ UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, SOCK_EQ(addr,
+ &(UNLINK_EXPR_SLIST_CURRENT()->addr)), link, remaddr_t);
+
+ if (unlinked != NULL) {
+ DPRINTF(4, ("Deleted addr %s from list of addresses\n",
+ stoa(addr)));
+ free(unlinked);
}
}
+
static void
-delete_interface_from_list(struct interface *iface) {
- remaddr_t *next;
- remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
-
- while(laddr != NULL) {
- next = ISC_LIST_NEXT(laddr, link);
- if (laddr->interface == iface) {
- ISC_LIST_DEQUEUE_TYPE(remoteaddr_list, laddr, link, remaddr_t);
- DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n",
- stoa(&laddr->addr), iface->ifnum, iface->name));
- free(laddr);
- }
- laddr = next;
+delete_interface_from_list(
+ endpt *iface
+ )
+{
+ remaddr_t *unlinked;
+
+ for (;;) {
+ UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, iface ==
+ UNLINK_EXPR_SLIST_CURRENT()->ep, link,
+ remaddr_t);
+
+ if (unlinked == NULL)
+ break;
+ DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n",
+ stoa(&unlinked->addr), iface->ifnum,
+ iface->name));
+ free(unlinked);
}
}
+
static struct interface *
-find_addr_in_list(struct sockaddr_storage *addr) {
+find_addr_in_list(
+ sockaddr_u *addr
+ )
+{
+ remaddr_t *entry;
- remaddr_t *next;
- remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
DPRINTF(4, ("Searching for addr %s in list of addresses - ",
stoa(addr)));
- while(laddr != NULL) {
- next = ISC_LIST_NEXT(laddr, link);
- if(SOCKCMP(&laddr->addr, addr)) {
+ for (entry = remoteaddr_list;
+ entry != NULL;
+ entry = entry->link)
+ if (SOCK_EQ(&entry->addr, addr)) {
DPRINTF(4, ("FOUND\n"));
- return laddr->interface;
+ return entry->ep;
}
- else
- laddr = next;
- }
+
DPRINTF(4, ("NOT FOUND\n"));
- return NULL; /* Not found */
+ return NULL;
}
+
/*
- * Find the given address with the associated flag in the list
+ * Find the given address with the all given flags set in the list
*/
-static struct interface *
-find_flagged_addr_in_list(struct sockaddr_storage *addr, int flag) {
+static endpt *
+find_flagged_addr_in_list(
+ sockaddr_u * addr,
+ u_int32 flags
+ )
+{
+ remaddr_t *entry;
- remaddr_t *next;
- remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
- DPRINTF(4, ("Finding addr %s in list of addresses\n",
- stoa(addr)));
+ DPRINTF(4, ("Finding addr %s with flags %d in list: ",
+ stoa(addr), flags));
- while(laddr != NULL) {
- next = ISC_LIST_NEXT(laddr, link);
- if(SOCKCMP(&laddr->addr, addr) && (laddr->interface->flags & flag)) {
- return laddr->interface;
- break;
+ for (entry = remoteaddr_list;
+ entry != NULL;
+ entry = entry->link)
+
+ if (SOCK_EQ(&entry->addr, addr)
+ && (entry->ep->flags & flags) == flags) {
+
+ DPRINTF(4, ("FOUND\n"));
+ return entry->ep;
}
- else
- laddr = next;
- }
- return NULL; /* Not found */
+
+ DPRINTF(4, ("NOT FOUND\n"));
+ return NULL;
}
-#ifdef HAS_ROUTING_SOCKET
-#include <net/route.h>
-#ifndef UPDATE_GRACE
-#define UPDATE_GRACE 2 /* wait UPDATE_GRACE seconds before scanning */
-#endif
+const char *
+localaddrtoa(
+ endpt *la
+ )
+{
+ return (NULL == la)
+ ? "<null>"
+ : stoa(&la->sin);
+}
+
+
+#ifdef HAS_ROUTING_SOCKET
+# ifndef UPDATE_GRACE
+# define UPDATE_GRACE 2 /* wait UPDATE_GRACE seconds before scanning */
+# endif
static void
process_routing_msgs(struct asyncio_reader *reader)
{
char buffer[5120];
- char *p = buffer;
+ int cnt, msg_type;
+#ifdef HAVE_RTNETLINK
+ struct nlmsghdr *nh;
+#else
+ struct rt_msghdr rtm;
+ char *p;
+#endif
- int cnt;
-
if (disable_dynamic_updates) {
/*
- * discard ourselves if we are not need any more
+ * discard ourselves if we are not needed any more
* usually happens when running unprivileged
*/
remove_asyncio_reader(reader);
@@ -3933,9 +4629,10 @@ process_routing_msgs(struct asyncio_reader *reader)
}
cnt = read(reader->fd, buffer, sizeof(buffer));
-
+
if (cnt < 0) {
- msyslog(LOG_ERR, "i/o error on routing socket %m - disabling");
+ msyslog(LOG_ERR,
+ "i/o error on routing socket %m - disabling");
remove_asyncio_reader(reader);
delete_asyncio_reader(reader);
return;
@@ -3944,19 +4641,28 @@ process_routing_msgs(struct asyncio_reader *reader)
/*
* process routing message
*/
- while ((p + sizeof(struct rt_msghdr)) <= (buffer + cnt))
- {
- struct rt_msghdr *rtm;
-
- rtm = (struct rt_msghdr *)p;
- if (rtm->rtm_version != RTM_VERSION) {
- msyslog(LOG_ERR, "version mismatch on routing socket %m - disabling");
+#ifdef HAVE_RTNETLINK
+ for (nh = (struct nlmsghdr *)buffer;
+ NLMSG_OK(nh, cnt);
+ nh = NLMSG_NEXT(nh, cnt)) {
+ msg_type = nh->nlmsg_type;
+#else
+ for (p = buffer;
+ (p + sizeof(struct rt_msghdr)) <= (buffer + cnt);
+ p += rtm.rtm_msglen) {
+ memcpy(&rtm, p, sizeof(rtm));
+ if (rtm.rtm_version != RTM_VERSION) {
+ msyslog(LOG_ERR,
+ "version mismatch (got %d - expected %d) on routing socket - disabling",
+ rtm.rtm_version, RTM_VERSION);
+
remove_asyncio_reader(reader);
delete_asyncio_reader(reader);
return;
}
-
- switch (rtm->rtm_type) {
+ msg_type = rtm.rtm_type;
+#endif
+ switch (msg_type) {
#ifdef RTM_NEWADDR
case RTM_NEWADDR:
#endif
@@ -3984,20 +4690,40 @@ process_routing_msgs(struct asyncio_reader *reader)
#ifdef RTM_IFANNOUNCE
case RTM_IFANNOUNCE:
#endif
+#ifdef RTM_NEWLINK
+ case RTM_NEWLINK:
+#endif
+#ifdef RTM_DELLINK
+ case RTM_DELLINK:
+#endif
+#ifdef RTM_NEWROUTE
+ case RTM_NEWROUTE:
+#endif
+#ifdef RTM_DELROUTE
+ case RTM_DELROUTE:
+#endif
/*
- * we are keen on new and deleted addresses and if an interface goes up and down or routing changes
+ * we are keen on new and deleted addresses and
+ * if an interface goes up and down or routing
+ * changes
*/
- DPRINTF(3, ("routing message op = %d: scheduling interface update\n", rtm->rtm_type));
+ DPRINTF(3, ("routing message op = %d: scheduling interface update\n",
+ msg_type));
timer_interfacetimeout(current_time + UPDATE_GRACE);
break;
+#ifdef HAVE_RTNETLINK
+ case NLMSG_DONE:
+ /* end of multipart message */
+ return;
+#endif
default:
/*
* the rest doesn't bother us.
*/
- DPRINTF(4, ("routing message op = %d: ignored\n", rtm->rtm_type));
+ DPRINTF(4, ("routing message op = %d: ignored\n",
+ msg_type));
break;
}
- p += rtm->rtm_msglen;
}
}
@@ -4008,29 +4734,52 @@ static void
init_async_notifications()
{
struct asyncio_reader *reader;
+#ifdef HAVE_RTNETLINK
+ int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ struct sockaddr_nl sa;
+#else
int fd = socket(PF_ROUTE, SOCK_RAW, 0);
-
- if (fd >= 0) {
- fd = move_fd(fd);
- init_nonblocking_io(fd);
+#endif
+ if (fd < 0) {
+ msyslog(LOG_ERR,
+ "unable to open routing socket (%m) - using polled interface update");
+ return;
+ }
+
+ fd = move_fd(fd);
+#ifdef HAVE_RTNETLINK
+ ZERO(sa);
+ sa.nl_family = PF_NETLINK;
+ sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR
+ | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE
+ | RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_ROUTE
+ | RTMGRP_IPV6_MROUTE;
+ if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+ msyslog(LOG_ERR,
+ "bind failed on routing socket (%m) - using polled interface update");
+ return;
+ }
+#endif
+ make_socket_nonblocking(fd);
#if defined(HAVE_SIGNALED_IO)
- init_socket_sig(fd);
+ init_socket_sig(fd);
#endif /* HAVE_SIGNALED_IO */
-
- reader = new_asyncio_reader();
-
- reader->fd = fd;
- reader->receiver = process_routing_msgs;
-
- add_asyncio_reader(reader, FD_TYPE_SOCKET);
- msyslog(LOG_INFO, "Listening on routing socket on fd #%d for interface updates", fd);
- } else {
- msyslog(LOG_ERR, "unable to open routing socket (%m) - using polled interface update");
- }
+
+ reader = new_asyncio_reader();
+
+ reader->fd = fd;
+ reader->receiver = process_routing_msgs;
+
+ add_asyncio_reader(reader, FD_TYPE_SOCKET);
+ msyslog(LOG_INFO,
+ "Listening on routing socket on fd #%d for interface updates",
+ fd);
}
#else
+/* HAS_ROUTING_SOCKET not defined */
static void
-init_async_notifications()
+init_async_notifications(void)
{
}
#endif
+
diff --git a/contrib/ntp/ntpd/ntp_keyword.h b/contrib/ntp/ntpd/ntp_keyword.h
new file mode 100644
index 0000000..0a593f6
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_keyword.h
@@ -0,0 +1,1068 @@
+/*
+ * ntp_keyword.h
+ *
+ * NOTE: edit this file with caution, it is generated by keyword-gen.c
+ * Generated 2015-06-25 03:57:00 UTC diff_ignore_line
+ *
+ */
+#include "ntp_scanner.h"
+#include "ntp_parser.h"
+
+#define LOWEST_KEYWORD_ID 258
+
+const char * const keyword_text[191] = {
+ /* 0 258 T_Abbrev */ "abbrev",
+ /* 1 259 T_Age */ "age",
+ /* 2 260 T_All */ "all",
+ /* 3 261 T_Allan */ "allan",
+ /* 4 262 T_Allpeers */ "allpeers",
+ /* 5 263 T_Auth */ "auth",
+ /* 6 264 T_Autokey */ "autokey",
+ /* 7 265 T_Automax */ "automax",
+ /* 8 266 T_Average */ "average",
+ /* 9 267 T_Bclient */ "bclient",
+ /* 10 268 T_Beacon */ "beacon",
+ /* 11 269 T_Broadcast */ "broadcast",
+ /* 12 270 T_Broadcastclient */ "broadcastclient",
+ /* 13 271 T_Broadcastdelay */ "broadcastdelay",
+ /* 14 272 T_Burst */ "burst",
+ /* 15 273 T_Calibrate */ "calibrate",
+ /* 16 274 T_Ceiling */ "ceiling",
+ /* 17 275 T_Clockstats */ "clockstats",
+ /* 18 276 T_Cohort */ "cohort",
+ /* 19 277 T_ControlKey */ "controlkey",
+ /* 20 278 T_Crypto */ "crypto",
+ /* 21 279 T_Cryptostats */ "cryptostats",
+ /* 22 280 T_Ctl */ "ctl",
+ /* 23 281 T_Day */ "day",
+ /* 24 282 T_Default */ "default",
+ /* 25 283 T_Digest */ "digest",
+ /* 26 284 T_Disable */ "disable",
+ /* 27 285 T_Discard */ "discard",
+ /* 28 286 T_Dispersion */ "dispersion",
+ /* 29 287 T_Double */ NULL,
+ /* 30 288 T_Driftfile */ "driftfile",
+ /* 31 289 T_Drop */ "drop",
+ /* 32 290 T_Dscp */ "dscp",
+ /* 33 291 T_Ellipsis */ "...",
+ /* 34 292 T_Enable */ "enable",
+ /* 35 293 T_End */ "end",
+ /* 36 294 T_False */ NULL,
+ /* 37 295 T_File */ "file",
+ /* 38 296 T_Filegen */ "filegen",
+ /* 39 297 T_Filenum */ "filenum",
+ /* 40 298 T_Flag1 */ "flag1",
+ /* 41 299 T_Flag2 */ "flag2",
+ /* 42 300 T_Flag3 */ "flag3",
+ /* 43 301 T_Flag4 */ "flag4",
+ /* 44 302 T_Flake */ "flake",
+ /* 45 303 T_Floor */ "floor",
+ /* 46 304 T_Freq */ "freq",
+ /* 47 305 T_Fudge */ "fudge",
+ /* 48 306 T_Host */ "host",
+ /* 49 307 T_Huffpuff */ "huffpuff",
+ /* 50 308 T_Iburst */ "iburst",
+ /* 51 309 T_Ident */ "ident",
+ /* 52 310 T_Ignore */ "ignore",
+ /* 53 311 T_Incalloc */ "incalloc",
+ /* 54 312 T_Incmem */ "incmem",
+ /* 55 313 T_Initalloc */ "initalloc",
+ /* 56 314 T_Initmem */ "initmem",
+ /* 57 315 T_Includefile */ "includefile",
+ /* 58 316 T_Integer */ NULL,
+ /* 59 317 T_Interface */ "interface",
+ /* 60 318 T_Intrange */ NULL,
+ /* 61 319 T_Io */ "io",
+ /* 62 320 T_Ipv4 */ "ipv4",
+ /* 63 321 T_Ipv4_flag */ "-4",
+ /* 64 322 T_Ipv6 */ "ipv6",
+ /* 65 323 T_Ipv6_flag */ "-6",
+ /* 66 324 T_Kernel */ "kernel",
+ /* 67 325 T_Key */ "key",
+ /* 68 326 T_Keys */ "keys",
+ /* 69 327 T_Keysdir */ "keysdir",
+ /* 70 328 T_Kod */ "kod",
+ /* 71 329 T_Mssntp */ "mssntp",
+ /* 72 330 T_Leapfile */ "leapfile",
+ /* 73 331 T_Leapsmearinterval */ "leapsmearinterval",
+ /* 74 332 T_Limited */ "limited",
+ /* 75 333 T_Link */ "link",
+ /* 76 334 T_Listen */ "listen",
+ /* 77 335 T_Logconfig */ "logconfig",
+ /* 78 336 T_Logfile */ "logfile",
+ /* 79 337 T_Loopstats */ "loopstats",
+ /* 80 338 T_Lowpriotrap */ "lowpriotrap",
+ /* 81 339 T_Manycastclient */ "manycastclient",
+ /* 82 340 T_Manycastserver */ "manycastserver",
+ /* 83 341 T_Mask */ "mask",
+ /* 84 342 T_Maxage */ "maxage",
+ /* 85 343 T_Maxclock */ "maxclock",
+ /* 86 344 T_Maxdepth */ "maxdepth",
+ /* 87 345 T_Maxdist */ "maxdist",
+ /* 88 346 T_Maxmem */ "maxmem",
+ /* 89 347 T_Maxpoll */ "maxpoll",
+ /* 90 348 T_Mdnstries */ "mdnstries",
+ /* 91 349 T_Mem */ "mem",
+ /* 92 350 T_Memlock */ "memlock",
+ /* 93 351 T_Minclock */ "minclock",
+ /* 94 352 T_Mindepth */ "mindepth",
+ /* 95 353 T_Mindist */ "mindist",
+ /* 96 354 T_Minimum */ "minimum",
+ /* 97 355 T_Minpoll */ "minpoll",
+ /* 98 356 T_Minsane */ "minsane",
+ /* 99 357 T_Mode */ "mode",
+ /* 100 358 T_Mode7 */ "mode7",
+ /* 101 359 T_Monitor */ "monitor",
+ /* 102 360 T_Month */ "month",
+ /* 103 361 T_Mru */ "mru",
+ /* 104 362 T_Multicastclient */ "multicastclient",
+ /* 105 363 T_Nic */ "nic",
+ /* 106 364 T_Nolink */ "nolink",
+ /* 107 365 T_Nomodify */ "nomodify",
+ /* 108 366 T_Nomrulist */ "nomrulist",
+ /* 109 367 T_None */ "none",
+ /* 110 368 T_Nonvolatile */ "nonvolatile",
+ /* 111 369 T_Nopeer */ "nopeer",
+ /* 112 370 T_Noquery */ "noquery",
+ /* 113 371 T_Noselect */ "noselect",
+ /* 114 372 T_Noserve */ "noserve",
+ /* 115 373 T_Notrap */ "notrap",
+ /* 116 374 T_Notrust */ "notrust",
+ /* 117 375 T_Ntp */ "ntp",
+ /* 118 376 T_Ntpport */ "ntpport",
+ /* 119 377 T_NtpSignDsocket */ "ntpsigndsocket",
+ /* 120 378 T_Orphan */ "orphan",
+ /* 121 379 T_Orphanwait */ "orphanwait",
+ /* 122 380 T_Panic */ "panic",
+ /* 123 381 T_Peer */ "peer",
+ /* 124 382 T_Peerstats */ "peerstats",
+ /* 125 383 T_Phone */ "phone",
+ /* 126 384 T_Pid */ "pid",
+ /* 127 385 T_Pidfile */ "pidfile",
+ /* 128 386 T_Pool */ "pool",
+ /* 129 387 T_Port */ "port",
+ /* 130 388 T_Preempt */ "preempt",
+ /* 131 389 T_Prefer */ "prefer",
+ /* 132 390 T_Protostats */ "protostats",
+ /* 133 391 T_Pw */ "pw",
+ /* 134 392 T_Randfile */ "randfile",
+ /* 135 393 T_Rawstats */ "rawstats",
+ /* 136 394 T_Refid */ "refid",
+ /* 137 395 T_Requestkey */ "requestkey",
+ /* 138 396 T_Reset */ "reset",
+ /* 139 397 T_Restrict */ "restrict",
+ /* 140 398 T_Revoke */ "revoke",
+ /* 141 399 T_Rlimit */ "rlimit",
+ /* 142 400 T_Saveconfigdir */ "saveconfigdir",
+ /* 143 401 T_Server */ "server",
+ /* 144 402 T_Setvar */ "setvar",
+ /* 145 403 T_Source */ "source",
+ /* 146 404 T_Stacksize */ "stacksize",
+ /* 147 405 T_Statistics */ "statistics",
+ /* 148 406 T_Stats */ "stats",
+ /* 149 407 T_Statsdir */ "statsdir",
+ /* 150 408 T_Step */ "step",
+ /* 151 409 T_Stepback */ "stepback",
+ /* 152 410 T_Stepfwd */ "stepfwd",
+ /* 153 411 T_Stepout */ "stepout",
+ /* 154 412 T_Stratum */ "stratum",
+ /* 155 413 T_String */ NULL,
+ /* 156 414 T_Sys */ "sys",
+ /* 157 415 T_Sysstats */ "sysstats",
+ /* 158 416 T_Tick */ "tick",
+ /* 159 417 T_Time1 */ "time1",
+ /* 160 418 T_Time2 */ "time2",
+ /* 161 419 T_Timer */ "timer",
+ /* 162 420 T_Timingstats */ "timingstats",
+ /* 163 421 T_Tinker */ "tinker",
+ /* 164 422 T_Tos */ "tos",
+ /* 165 423 T_Trap */ "trap",
+ /* 166 424 T_True */ "true",
+ /* 167 425 T_Trustedkey */ "trustedkey",
+ /* 168 426 T_Ttl */ "ttl",
+ /* 169 427 T_Type */ "type",
+ /* 170 428 T_U_int */ NULL,
+ /* 171 429 T_Unconfig */ "unconfig",
+ /* 172 430 T_Unpeer */ "unpeer",
+ /* 173 431 T_Version */ "version",
+ /* 174 432 T_WanderThreshold */ NULL,
+ /* 175 433 T_Week */ "week",
+ /* 176 434 T_Wildcard */ "wildcard",
+ /* 177 435 T_Xleave */ "xleave",
+ /* 178 436 T_Year */ "year",
+ /* 179 437 T_Flag */ NULL,
+ /* 180 438 T_EOC */ NULL,
+ /* 181 439 T_Simulate */ "simulate",
+ /* 182 440 T_Beep_Delay */ "beep_delay",
+ /* 183 441 T_Sim_Duration */ "simulation_duration",
+ /* 184 442 T_Server_Offset */ "server_offset",
+ /* 185 443 T_Duration */ "duration",
+ /* 186 444 T_Freq_Offset */ "freq_offset",
+ /* 187 445 T_Wander */ "wander",
+ /* 188 446 T_Jitter */ "jitter",
+ /* 189 447 T_Prop_Delay */ "prop_delay",
+ /* 190 448 T_Proc_Delay */ "proc_delay"
+};
+
+#define SCANNER_INIT_S 853
+
+const scan_state sst[856] = {
+/*SS_T( ch, f-by, match, other ), */
+ 0, /* 0 */
+ S_ST( '-', 3, 323, 0 ), /* 1 */
+ S_ST( '.', 3, 3, 1 ), /* 2 */
+ S_ST( '.', 3, 291, 0 ), /* 3 . */
+ S_ST( 'a', 3, 23, 2 ), /* 4 */
+ S_ST( 'b', 3, 6, 0 ), /* 5 a */
+ S_ST( 'b', 3, 7, 0 ), /* 6 ab */
+ S_ST( 'r', 3, 8, 0 ), /* 7 abb */
+ S_ST( 'e', 3, 258, 0 ), /* 8 abbr */
+ S_ST( 'g', 3, 259, 5 ), /* 9 a */
+ S_ST( 'l', 3, 260, 9 ), /* 10 a */
+ S_ST( 'a', 3, 261, 0 ), /* 11 all */
+ S_ST( 'p', 3, 13, 11 ), /* 12 all */
+ S_ST( 'e', 3, 14, 0 ), /* 13 allp */
+ S_ST( 'e', 3, 15, 0 ), /* 14 allpe */
+ S_ST( 'r', 3, 262, 0 ), /* 15 allpee */
+ S_ST( 'u', 3, 17, 10 ), /* 16 a */
+ S_ST( 't', 3, 18, 0 ), /* 17 au */
+ S_ST( 'o', 3, 21, 263 ), /* 18 aut */
+ S_ST( 'k', 3, 20, 0 ), /* 19 auto */
+ S_ST( 'e', 3, 264, 0 ), /* 20 autok */
+ S_ST( 'm', 3, 22, 19 ), /* 21 auto */
+ S_ST( 'a', 3, 265, 0 ), /* 22 autom */
+ S_ST( 'v', 3, 24, 16 ), /* 23 a */
+ S_ST( 'e', 3, 25, 0 ), /* 24 av */
+ S_ST( 'r', 3, 26, 0 ), /* 25 ave */
+ S_ST( 'a', 3, 27, 0 ), /* 26 aver */
+ S_ST( 'g', 3, 266, 0 ), /* 27 avera */
+ S_ST( 'b', 3, 61, 4 ), /* 28 */
+ S_ST( 'c', 3, 30, 0 ), /* 29 b */
+ S_ST( 'l', 3, 31, 0 ), /* 30 bc */
+ S_ST( 'i', 3, 32, 0 ), /* 31 bcl */
+ S_ST( 'e', 3, 33, 0 ), /* 32 bcli */
+ S_ST( 'n', 3, 267, 0 ), /* 33 bclie */
+ S_ST( 'e', 3, 38, 29 ), /* 34 b */
+ S_ST( 'a', 3, 36, 0 ), /* 35 be */
+ S_ST( 'c', 3, 37, 0 ), /* 36 bea */
+ S_ST( 'o', 3, 268, 0 ), /* 37 beac */
+ S_ST( 'e', 3, 39, 35 ), /* 38 be */
+ S_ST( 'p', 3, 40, 0 ), /* 39 bee */
+ S_ST( '_', 3, 41, 0 ), /* 40 beep */
+ S_ST( 'd', 3, 42, 0 ), /* 41 beep_ */
+ S_ST( 'e', 3, 43, 0 ), /* 42 beep_d */
+ S_ST( 'l', 3, 44, 0 ), /* 43 beep_de */
+ S_ST( 'a', 3, 440, 0 ), /* 44 beep_del */
+ S_ST( 'r', 3, 46, 34 ), /* 45 b */
+ S_ST( 'o', 3, 47, 0 ), /* 46 br */
+ S_ST( 'a', 3, 48, 0 ), /* 47 bro */
+ S_ST( 'd', 3, 49, 0 ), /* 48 broa */
+ S_ST( 'c', 3, 50, 0 ), /* 49 broad */
+ S_ST( 'a', 3, 51, 0 ), /* 50 broadc */
+ S_ST( 's', 3, 269, 0 ), /* 51 broadca */
+ S_ST( 'c', 3, 53, 0 ), /* 52 broadcast */
+ S_ST( 'l', 3, 54, 0 ), /* 53 broadcastc */
+ S_ST( 'i', 3, 55, 0 ), /* 54 broadcastcl */
+ S_ST( 'e', 3, 56, 0 ), /* 55 broadcastcli */
+ S_ST( 'n', 3, 270, 0 ), /* 56 broadcastclie */
+ S_ST( 'd', 3, 58, 52 ), /* 57 broadcast */
+ S_ST( 'e', 3, 59, 0 ), /* 58 broadcastd */
+ S_ST( 'l', 3, 60, 0 ), /* 59 broadcastde */
+ S_ST( 'a', 3, 271, 0 ), /* 60 broadcastdel */
+ S_ST( 'u', 3, 62, 45 ), /* 61 b */
+ S_ST( 'r', 3, 63, 0 ), /* 62 bu */
+ S_ST( 's', 3, 272, 0 ), /* 63 bur */
+ S_ST( 'c', 3, 104, 28 ), /* 64 */
+ S_ST( 'a', 3, 66, 0 ), /* 65 c */
+ S_ST( 'l', 3, 67, 0 ), /* 66 ca */
+ S_ST( 'i', 3, 68, 0 ), /* 67 cal */
+ S_ST( 'b', 3, 69, 0 ), /* 68 cali */
+ S_ST( 'r', 3, 70, 0 ), /* 69 calib */
+ S_ST( 'a', 3, 71, 0 ), /* 70 calibr */
+ S_ST( 't', 3, 273, 0 ), /* 71 calibra */
+ S_ST( 'e', 3, 73, 65 ), /* 72 c */
+ S_ST( 'i', 3, 74, 0 ), /* 73 ce */
+ S_ST( 'l', 3, 75, 0 ), /* 74 cei */
+ S_ST( 'i', 3, 76, 0 ), /* 75 ceil */
+ S_ST( 'n', 3, 274, 0 ), /* 76 ceili */
+ S_ST( 'l', 3, 78, 72 ), /* 77 c */
+ S_ST( 'o', 3, 79, 0 ), /* 78 cl */
+ S_ST( 'c', 3, 80, 0 ), /* 79 clo */
+ S_ST( 'k', 3, 81, 0 ), /* 80 cloc */
+ S_ST( 's', 3, 82, 0 ), /* 81 clock */
+ S_ST( 't', 3, 83, 0 ), /* 82 clocks */
+ S_ST( 'a', 3, 84, 0 ), /* 83 clockst */
+ S_ST( 't', 3, 275, 0 ), /* 84 clocksta */
+ S_ST( 'o', 3, 89, 77 ), /* 85 c */
+ S_ST( 'h', 3, 87, 0 ), /* 86 co */
+ S_ST( 'o', 3, 88, 0 ), /* 87 coh */
+ S_ST( 'r', 3, 276, 0 ), /* 88 coho */
+ S_ST( 'n', 3, 90, 86 ), /* 89 co */
+ S_ST( 't', 3, 91, 0 ), /* 90 con */
+ S_ST( 'r', 3, 92, 0 ), /* 91 cont */
+ S_ST( 'o', 3, 93, 0 ), /* 92 contr */
+ S_ST( 'l', 3, 94, 0 ), /* 93 contro */
+ S_ST( 'k', 3, 95, 0 ), /* 94 control */
+ S_ST( 'e', 3, 277, 0 ), /* 95 controlk */
+ S_ST( 'r', 3, 97, 85 ), /* 96 c */
+ S_ST( 'y', 3, 98, 0 ), /* 97 cr */
+ S_ST( 'p', 3, 99, 0 ), /* 98 cry */
+ S_ST( 't', 3, 278, 0 ), /* 99 cryp */
+ S_ST( 's', 3, 101, 0 ), /* 100 crypto */
+ S_ST( 't', 3, 102, 0 ), /* 101 cryptos */
+ S_ST( 'a', 3, 103, 0 ), /* 102 cryptost */
+ S_ST( 't', 3, 279, 0 ), /* 103 cryptosta */
+ S_ST( 't', 3, 280, 96 ), /* 104 c */
+ S_ST( 'd', 3, 139, 64 ), /* 105 */
+ S_ST( 'a', 3, 281, 0 ), /* 106 d */
+ S_ST( 'e', 3, 108, 106 ), /* 107 d */
+ S_ST( 'f', 3, 109, 0 ), /* 108 de */
+ S_ST( 'a', 3, 110, 0 ), /* 109 def */
+ S_ST( 'u', 3, 111, 0 ), /* 110 defa */
+ S_ST( 'l', 3, 282, 0 ), /* 111 defau */
+ S_ST( 'i', 3, 116, 107 ), /* 112 d */
+ S_ST( 'g', 3, 114, 0 ), /* 113 di */
+ S_ST( 'e', 3, 115, 0 ), /* 114 dig */
+ S_ST( 's', 3, 283, 0 ), /* 115 dige */
+ S_ST( 's', 3, 123, 113 ), /* 116 di */
+ S_ST( 'a', 3, 118, 0 ), /* 117 dis */
+ S_ST( 'b', 3, 119, 0 ), /* 118 disa */
+ S_ST( 'l', 3, 284, 0 ), /* 119 disab */
+ S_ST( 'c', 3, 121, 117 ), /* 120 dis */
+ S_ST( 'a', 3, 122, 0 ), /* 121 disc */
+ S_ST( 'r', 3, 285, 0 ), /* 122 disca */
+ S_ST( 'p', 3, 124, 120 ), /* 123 dis */
+ S_ST( 'e', 3, 125, 0 ), /* 124 disp */
+ S_ST( 'r', 3, 126, 0 ), /* 125 dispe */
+ S_ST( 's', 3, 127, 0 ), /* 126 disper */
+ S_ST( 'i', 3, 128, 0 ), /* 127 dispers */
+ S_ST( 'o', 3, 286, 0 ), /* 128 dispersi */
+ S_ST( 'r', 3, 136, 112 ), /* 129 d */
+ S_ST( 'i', 3, 131, 0 ), /* 130 dr */
+ S_ST( 'f', 3, 132, 0 ), /* 131 dri */
+ S_ST( 't', 3, 133, 0 ), /* 132 drif */
+ S_ST( 'f', 3, 134, 0 ), /* 133 drift */
+ S_ST( 'i', 3, 135, 0 ), /* 134 driftf */
+ S_ST( 'l', 3, 288, 0 ), /* 135 driftfi */
+ S_ST( 'o', 3, 289, 130 ), /* 136 dr */
+ S_ST( 's', 3, 138, 129 ), /* 137 d */
+ S_ST( 'c', 3, 290, 0 ), /* 138 ds */
+ S_ST( 'u', 3, 140, 137 ), /* 139 d */
+ S_ST( 'r', 3, 141, 0 ), /* 140 du */
+ S_ST( 'a', 3, 142, 0 ), /* 141 dur */
+ S_ST( 't', 3, 143, 0 ), /* 142 dura */
+ S_ST( 'i', 3, 144, 0 ), /* 143 durat */
+ S_ST( 'o', 3, 443, 0 ), /* 144 durati */
+ S_ST( 'e', 3, 146, 105 ), /* 145 */
+ S_ST( 'n', 3, 293, 0 ), /* 146 e */
+ S_ST( 'a', 3, 148, 0 ), /* 147 en */
+ S_ST( 'b', 3, 149, 0 ), /* 148 ena */
+ S_ST( 'l', 3, 292, 0 ), /* 149 enab */
+ S_ST( 'f', 3, 171, 145 ), /* 150 */
+ S_ST( 'i', 3, 152, 0 ), /* 151 f */
+ S_ST( 'l', 3, 295, 0 ), /* 152 fi */
+ S_ST( 'g', 3, 154, 0 ), /* 153 file */
+ S_ST( 'e', 3, 296, 0 ), /* 154 fileg */
+ S_ST( 'n', 3, 156, 153 ), /* 155 file */
+ S_ST( 'u', 3, 297, 0 ), /* 156 filen */
+ S_ST( 'l', 3, 161, 151 ), /* 157 f */
+ S_ST( 'a', 3, 160, 0 ), /* 158 fl */
+ S_ST( 'g', 3, 301, 0 ), /* 159 fla */
+ S_ST( 'k', 3, 302, 159 ), /* 160 fla */
+ S_ST( 'o', 3, 162, 158 ), /* 161 fl */
+ S_ST( 'o', 3, 303, 0 ), /* 162 flo */
+ S_ST( 'r', 3, 164, 157 ), /* 163 f */
+ S_ST( 'e', 3, 304, 0 ), /* 164 fr */
+ S_ST( '_', 3, 166, 0 ), /* 165 freq */
+ S_ST( 'o', 3, 167, 0 ), /* 166 freq_ */
+ S_ST( 'f', 3, 168, 0 ), /* 167 freq_o */
+ S_ST( 'f', 3, 169, 0 ), /* 168 freq_of */
+ S_ST( 's', 3, 170, 0 ), /* 169 freq_off */
+ S_ST( 'e', 3, 444, 0 ), /* 170 freq_offs */
+ S_ST( 'u', 3, 172, 163 ), /* 171 f */
+ S_ST( 'd', 3, 173, 0 ), /* 172 fu */
+ S_ST( 'g', 3, 305, 0 ), /* 173 fud */
+ S_ST( 'h', 3, 177, 150 ), /* 174 */
+ S_ST( 'o', 3, 176, 0 ), /* 175 h */
+ S_ST( 's', 3, 306, 0 ), /* 176 ho */
+ S_ST( 'u', 3, 178, 175 ), /* 177 h */
+ S_ST( 'f', 3, 179, 0 ), /* 178 hu */
+ S_ST( 'f', 3, 180, 0 ), /* 179 huf */
+ S_ST( 'p', 3, 181, 0 ), /* 180 huff */
+ S_ST( 'u', 3, 182, 0 ), /* 181 huffp */
+ S_ST( 'f', 3, 307, 0 ), /* 182 huffpu */
+ S_ST( 'i', 3, 224, 174 ), /* 183 */
+ S_ST( 'b', 3, 185, 0 ), /* 184 i */
+ S_ST( 'u', 3, 186, 0 ), /* 185 ib */
+ S_ST( 'r', 3, 187, 0 ), /* 186 ibu */
+ S_ST( 's', 3, 308, 0 ), /* 187 ibur */
+ S_ST( 'd', 3, 189, 184 ), /* 188 i */
+ S_ST( 'e', 3, 190, 0 ), /* 189 id */
+ S_ST( 'n', 3, 309, 0 ), /* 190 ide */
+ S_ST( 'g', 3, 192, 188 ), /* 191 i */
+ S_ST( 'n', 3, 193, 0 ), /* 192 ig */
+ S_ST( 'o', 3, 194, 0 ), /* 193 ign */
+ S_ST( 'r', 3, 310, 0 ), /* 194 igno */
+ S_ST( 'n', 3, 218, 191 ), /* 195 i */
+ S_ST( 'c', 3, 208, 0 ), /* 196 in */
+ S_ST( 'a', 3, 198, 0 ), /* 197 inc */
+ S_ST( 'l', 3, 199, 0 ), /* 198 inca */
+ S_ST( 'l', 3, 200, 0 ), /* 199 incal */
+ S_ST( 'o', 3, 311, 0 ), /* 200 incall */
+ S_ST( 'l', 3, 202, 197 ), /* 201 inc */
+ S_ST( 'u', 3, 203, 0 ), /* 202 incl */
+ S_ST( 'd', 3, 204, 0 ), /* 203 inclu */
+ S_ST( 'e', 3, 205, 0 ), /* 204 includ */
+ S_ST( 'f', 3, 206, 0 ), /* 205 include */
+ S_ST( 'i', 3, 207, 0 ), /* 206 includef */
+ S_ST( 'l', 3, 315, 0 ), /* 207 includefi */
+ S_ST( 'm', 3, 209, 201 ), /* 208 inc */
+ S_ST( 'e', 3, 312, 0 ), /* 209 incm */
+ S_ST( 'i', 3, 211, 196 ), /* 210 in */
+ S_ST( 't', 3, 216, 0 ), /* 211 ini */
+ S_ST( 'a', 3, 213, 0 ), /* 212 init */
+ S_ST( 'l', 3, 214, 0 ), /* 213 inita */
+ S_ST( 'l', 3, 215, 0 ), /* 214 inital */
+ S_ST( 'o', 3, 313, 0 ), /* 215 initall */
+ S_ST( 'm', 3, 217, 212 ), /* 216 init */
+ S_ST( 'e', 3, 314, 0 ), /* 217 initm */
+ S_ST( 't', 3, 219, 210 ), /* 218 in */
+ S_ST( 'e', 3, 220, 0 ), /* 219 int */
+ S_ST( 'r', 3, 221, 0 ), /* 220 inte */
+ S_ST( 'f', 3, 222, 0 ), /* 221 inter */
+ S_ST( 'a', 3, 223, 0 ), /* 222 interf */
+ S_ST( 'c', 3, 317, 0 ), /* 223 interfa */
+ S_ST( 'p', 3, 225, 319 ), /* 224 i */
+ S_ST( 'v', 3, 322, 0 ), /* 225 ip */
+ S_ST( 'j', 3, 227, 183 ), /* 226 */
+ S_ST( 'i', 3, 228, 0 ), /* 227 j */
+ S_ST( 't', 3, 229, 0 ), /* 228 ji */
+ S_ST( 't', 3, 230, 0 ), /* 229 jit */
+ S_ST( 'e', 3, 446, 0 ), /* 230 jitt */
+ S_ST( 'k', 3, 238, 226 ), /* 231 */
+ S_ST( 'e', 3, 325, 0 ), /* 232 k */
+ S_ST( 'r', 3, 234, 0 ), /* 233 ke */
+ S_ST( 'n', 3, 235, 0 ), /* 234 ker */
+ S_ST( 'e', 3, 324, 0 ), /* 235 kern */
+ S_ST( 'd', 3, 237, 0 ), /* 236 keys */
+ S_ST( 'i', 3, 327, 0 ), /* 237 keysd */
+ S_ST( 'o', 3, 328, 232 ), /* 238 k */
+ S_ST( 'l', 3, 449, 231 ), /* 239 */
+ S_ST( 'e', 3, 241, 0 ), /* 240 l */
+ S_ST( 'a', 3, 242, 0 ), /* 241 le */
+ S_ST( 'p', 3, 246, 0 ), /* 242 lea */
+ S_ST( 'f', 3, 244, 0 ), /* 243 leap */
+ S_ST( 'i', 3, 245, 0 ), /* 244 leapf */
+ S_ST( 'l', 3, 330, 0 ), /* 245 leapfi */
+ S_ST( 's', 3, 247, 243 ), /* 246 leap */
+ S_ST( 'm', 3, 248, 0 ), /* 247 leaps */
+ S_ST( 'e', 3, 249, 0 ), /* 248 leapsm */
+ S_ST( 'a', 3, 250, 0 ), /* 249 leapsme */
+ S_ST( 'r', 3, 251, 0 ), /* 250 leapsmea */
+ S_ST( 'i', 3, 252, 0 ), /* 251 leapsmear */
+ S_ST( 'n', 3, 253, 0 ), /* 252 leapsmeari */
+ S_ST( 't', 3, 254, 0 ), /* 253 leapsmearin */
+ S_ST( 'e', 3, 255, 0 ), /* 254 leapsmearint */
+ S_ST( 'r', 3, 256, 0 ), /* 255 leapsmearinte */
+ S_ST( 'v', 3, 257, 0 ), /* 256 leapsmearinter */
+ S_ST( 'a', 3, 331, 0 ), /* 257 leapsmearinterv */
+ S_ST( 'v', 1, 0, 0 ), /* 258 T_Abbrev */
+ S_ST( 'e', 0, 0, 0 ), /* 259 T_Age */
+ S_ST( 'l', 0, 12, 0 ), /* 260 T_All */
+ S_ST( 'n', 0, 0, 0 ), /* 261 T_Allan */
+ S_ST( 's', 0, 0, 0 ), /* 262 T_Allpeers */
+ S_ST( 'h', 0, 0, 0 ), /* 263 T_Auth */
+ S_ST( 'y', 0, 0, 0 ), /* 264 T_Autokey */
+ S_ST( 'x', 0, 0, 0 ), /* 265 T_Automax */
+ S_ST( 'e', 0, 0, 0 ), /* 266 T_Average */
+ S_ST( 't', 0, 0, 0 ), /* 267 T_Bclient */
+ S_ST( 'n', 0, 0, 0 ), /* 268 T_Beacon */
+ S_ST( 't', 1, 57, 0 ), /* 269 T_Broadcast */
+ S_ST( 't', 0, 0, 0 ), /* 270 T_Broadcastclient */
+ S_ST( 'y', 0, 0, 0 ), /* 271 T_Broadcastdelay */
+ S_ST( 't', 0, 0, 0 ), /* 272 T_Burst */
+ S_ST( 'e', 0, 0, 0 ), /* 273 T_Calibrate */
+ S_ST( 'g', 0, 0, 0 ), /* 274 T_Ceiling */
+ S_ST( 's', 0, 0, 0 ), /* 275 T_Clockstats */
+ S_ST( 't', 0, 0, 0 ), /* 276 T_Cohort */
+ S_ST( 'y', 0, 0, 0 ), /* 277 T_ControlKey */
+ S_ST( 'o', 0, 100, 0 ), /* 278 T_Crypto */
+ S_ST( 's', 0, 0, 0 ), /* 279 T_Cryptostats */
+ S_ST( 'l', 0, 0, 0 ), /* 280 T_Ctl */
+ S_ST( 'y', 0, 0, 0 ), /* 281 T_Day */
+ S_ST( 't', 0, 0, 0 ), /* 282 T_Default */
+ S_ST( 't', 1, 0, 0 ), /* 283 T_Digest */
+ S_ST( 'e', 0, 0, 0 ), /* 284 T_Disable */
+ S_ST( 'd', 0, 0, 0 ), /* 285 T_Discard */
+ S_ST( 'n', 0, 0, 0 ), /* 286 T_Dispersion */
+ S_ST( 'i', 3, 432, 240 ), /* 287 l */
+ S_ST( 'e', 1, 0, 0 ), /* 288 T_Driftfile */
+ S_ST( 'p', 0, 0, 0 ), /* 289 T_Drop */
+ S_ST( 'p', 0, 0, 0 ), /* 290 T_Dscp */
+ S_ST( '.', 0, 0, 0 ), /* 291 T_Ellipsis */
+ S_ST( 'e', 0, 0, 0 ), /* 292 T_Enable */
+ S_ST( 'd', 0, 0, 147 ), /* 293 T_End */
+ S_ST( 'm', 3, 316, 0 ), /* 294 li */
+ S_ST( 'e', 1, 155, 0 ), /* 295 T_File */
+ S_ST( 'n', 0, 0, 0 ), /* 296 T_Filegen */
+ S_ST( 'm', 0, 0, 0 ), /* 297 T_Filenum */
+ S_ST( '1', 0, 0, 0 ), /* 298 T_Flag1 */
+ S_ST( '2', 0, 0, 298 ), /* 299 T_Flag2 */
+ S_ST( '3', 0, 0, 299 ), /* 300 T_Flag3 */
+ S_ST( '4', 0, 0, 300 ), /* 301 T_Flag4 */
+ S_ST( 'e', 0, 0, 0 ), /* 302 T_Flake */
+ S_ST( 'r', 0, 0, 0 ), /* 303 T_Floor */
+ S_ST( 'q', 0, 165, 0 ), /* 304 T_Freq */
+ S_ST( 'e', 1, 0, 0 ), /* 305 T_Fudge */
+ S_ST( 't', 1, 0, 0 ), /* 306 T_Host */
+ S_ST( 'f', 0, 0, 0 ), /* 307 T_Huffpuff */
+ S_ST( 't', 0, 0, 0 ), /* 308 T_Iburst */
+ S_ST( 't', 1, 0, 0 ), /* 309 T_Ident */
+ S_ST( 'e', 0, 0, 0 ), /* 310 T_Ignore */
+ S_ST( 'c', 0, 0, 0 ), /* 311 T_Incalloc */
+ S_ST( 'm', 0, 0, 0 ), /* 312 T_Incmem */
+ S_ST( 'c', 0, 0, 0 ), /* 313 T_Initalloc */
+ S_ST( 'm', 0, 0, 0 ), /* 314 T_Initmem */
+ S_ST( 'e', 1, 0, 0 ), /* 315 T_Includefile */
+ S_ST( 'i', 3, 318, 0 ), /* 316 lim */
+ S_ST( 'e', 0, 0, 0 ), /* 317 T_Interface */
+ S_ST( 't', 3, 413, 0 ), /* 318 limi */
+ S_ST( 'o', 0, 0, 195 ), /* 319 T_Io */
+ S_ST( '4', 0, 0, 0 ), /* 320 T_Ipv4 */
+ S_ST( '4', 0, 0, 0 ), /* 321 T_Ipv4_flag */
+ S_ST( '6', 0, 0, 320 ), /* 322 T_Ipv6 */
+ S_ST( '6', 0, 0, 321 ), /* 323 T_Ipv6_flag */
+ S_ST( 'l', 0, 0, 0 ), /* 324 T_Kernel */
+ S_ST( 'y', 0, 326, 233 ), /* 325 T_Key */
+ S_ST( 's', 1, 236, 0 ), /* 326 T_Keys */
+ S_ST( 'r', 1, 0, 0 ), /* 327 T_Keysdir */
+ S_ST( 'd', 0, 0, 0 ), /* 328 T_Kod */
+ S_ST( 'p', 0, 0, 0 ), /* 329 T_Mssntp */
+ S_ST( 'e', 1, 0, 0 ), /* 330 T_Leapfile */
+ S_ST( 'l', 0, 0, 0 ), /* 331 T_Leapsmearinterval */
+ S_ST( 'd', 0, 0, 0 ), /* 332 T_Limited */
+ S_ST( 'k', 0, 0, 0 ), /* 333 T_Link */
+ S_ST( 'n', 0, 0, 0 ), /* 334 T_Listen */
+ S_ST( 'g', 2, 0, 0 ), /* 335 T_Logconfig */
+ S_ST( 'e', 1, 0, 0 ), /* 336 T_Logfile */
+ S_ST( 's', 0, 0, 0 ), /* 337 T_Loopstats */
+ S_ST( 'p', 0, 0, 0 ), /* 338 T_Lowpriotrap */
+ S_ST( 't', 1, 0, 0 ), /* 339 T_Manycastclient */
+ S_ST( 'r', 2, 0, 0 ), /* 340 T_Manycastserver */
+ S_ST( 'k', 0, 0, 0 ), /* 341 T_Mask */
+ S_ST( 'e', 0, 0, 0 ), /* 342 T_Maxage */
+ S_ST( 'k', 0, 0, 0 ), /* 343 T_Maxclock */
+ S_ST( 'h', 0, 0, 0 ), /* 344 T_Maxdepth */
+ S_ST( 't', 0, 0, 0 ), /* 345 T_Maxdist */
+ S_ST( 'm', 0, 0, 0 ), /* 346 T_Maxmem */
+ S_ST( 'l', 0, 0, 0 ), /* 347 T_Maxpoll */
+ S_ST( 's', 0, 0, 0 ), /* 348 T_Mdnstries */
+ S_ST( 'm', 0, 518, 0 ), /* 349 T_Mem */
+ S_ST( 'k', 0, 0, 0 ), /* 350 T_Memlock */
+ S_ST( 'k', 0, 0, 0 ), /* 351 T_Minclock */
+ S_ST( 'h', 0, 0, 0 ), /* 352 T_Mindepth */
+ S_ST( 't', 0, 0, 0 ), /* 353 T_Mindist */
+ S_ST( 'm', 0, 0, 0 ), /* 354 T_Minimum */
+ S_ST( 'l', 0, 0, 0 ), /* 355 T_Minpoll */
+ S_ST( 'e', 0, 0, 0 ), /* 356 T_Minsane */
+ S_ST( 'e', 0, 358, 0 ), /* 357 T_Mode */
+ S_ST( '7', 0, 0, 0 ), /* 358 T_Mode7 */
+ S_ST( 'r', 0, 0, 0 ), /* 359 T_Monitor */
+ S_ST( 'h', 0, 0, 0 ), /* 360 T_Month */
+ S_ST( 'u', 0, 0, 0 ), /* 361 T_Mru */
+ S_ST( 't', 2, 0, 0 ), /* 362 T_Multicastclient */
+ S_ST( 'c', 0, 0, 0 ), /* 363 T_Nic */
+ S_ST( 'k', 0, 0, 0 ), /* 364 T_Nolink */
+ S_ST( 'y', 0, 0, 0 ), /* 365 T_Nomodify */
+ S_ST( 't', 0, 0, 0 ), /* 366 T_Nomrulist */
+ S_ST( 'e', 0, 0, 0 ), /* 367 T_None */
+ S_ST( 'e', 0, 0, 0 ), /* 368 T_Nonvolatile */
+ S_ST( 'r', 0, 0, 0 ), /* 369 T_Nopeer */
+ S_ST( 'y', 0, 0, 0 ), /* 370 T_Noquery */
+ S_ST( 't', 0, 0, 0 ), /* 371 T_Noselect */
+ S_ST( 'e', 0, 0, 0 ), /* 372 T_Noserve */
+ S_ST( 'p', 0, 0, 0 ), /* 373 T_Notrap */
+ S_ST( 't', 0, 0, 0 ), /* 374 T_Notrust */
+ S_ST( 'p', 0, 614, 0 ), /* 375 T_Ntp */
+ S_ST( 't', 0, 0, 0 ), /* 376 T_Ntpport */
+ S_ST( 't', 1, 0, 0 ), /* 377 T_NtpSignDsocket */
+ S_ST( 'n', 0, 629, 0 ), /* 378 T_Orphan */
+ S_ST( 't', 0, 0, 0 ), /* 379 T_Orphanwait */
+ S_ST( 'c', 0, 0, 0 ), /* 380 T_Panic */
+ S_ST( 'r', 1, 638, 0 ), /* 381 T_Peer */
+ S_ST( 's', 0, 0, 0 ), /* 382 T_Peerstats */
+ S_ST( 'e', 2, 0, 0 ), /* 383 T_Phone */
+ S_ST( 'd', 0, 646, 0 ), /* 384 T_Pid */
+ S_ST( 'e', 1, 0, 0 ), /* 385 T_Pidfile */
+ S_ST( 'l', 1, 0, 0 ), /* 386 T_Pool */
+ S_ST( 't', 0, 0, 0 ), /* 387 T_Port */
+ S_ST( 't', 0, 0, 0 ), /* 388 T_Preempt */
+ S_ST( 'r', 0, 0, 0 ), /* 389 T_Prefer */
+ S_ST( 's', 0, 0, 0 ), /* 390 T_Protostats */
+ S_ST( 'w', 1, 0, 652 ), /* 391 T_Pw */
+ S_ST( 'e', 1, 0, 0 ), /* 392 T_Randfile */
+ S_ST( 's', 0, 0, 0 ), /* 393 T_Rawstats */
+ S_ST( 'd', 1, 0, 0 ), /* 394 T_Refid */
+ S_ST( 'y', 0, 0, 0 ), /* 395 T_Requestkey */
+ S_ST( 't', 0, 0, 0 ), /* 396 T_Reset */
+ S_ST( 't', 0, 0, 0 ), /* 397 T_Restrict */
+ S_ST( 'e', 0, 0, 0 ), /* 398 T_Revoke */
+ S_ST( 't', 0, 0, 0 ), /* 399 T_Rlimit */
+ S_ST( 'r', 1, 0, 0 ), /* 400 T_Saveconfigdir */
+ S_ST( 'r', 1, 729, 0 ), /* 401 T_Server */
+ S_ST( 'r', 1, 0, 0 ), /* 402 T_Setvar */
+ S_ST( 'e', 0, 0, 0 ), /* 403 T_Source */
+ S_ST( 'e', 0, 0, 0 ), /* 404 T_Stacksize */
+ S_ST( 's', 0, 0, 0 ), /* 405 T_Statistics */
+ S_ST( 's', 0, 772, 767 ), /* 406 T_Stats */
+ S_ST( 'r', 1, 0, 0 ), /* 407 T_Statsdir */
+ S_ST( 'p', 0, 780, 0 ), /* 408 T_Step */
+ S_ST( 'k', 0, 0, 0 ), /* 409 T_Stepback */
+ S_ST( 'd', 0, 0, 0 ), /* 410 T_Stepfwd */
+ S_ST( 't', 0, 0, 0 ), /* 411 T_Stepout */
+ S_ST( 'm', 0, 0, 0 ), /* 412 T_Stratum */
+ S_ST( 'e', 3, 332, 0 ), /* 413 limit */
+ S_ST( 's', 0, 787, 0 ), /* 414 T_Sys */
+ S_ST( 's', 0, 0, 0 ), /* 415 T_Sysstats */
+ S_ST( 'k', 0, 0, 0 ), /* 416 T_Tick */
+ S_ST( '1', 0, 0, 0 ), /* 417 T_Time1 */
+ S_ST( '2', 0, 0, 417 ), /* 418 T_Time2 */
+ S_ST( 'r', 0, 0, 418 ), /* 419 T_Timer */
+ S_ST( 's', 0, 0, 0 ), /* 420 T_Timingstats */
+ S_ST( 'r', 0, 0, 0 ), /* 421 T_Tinker */
+ S_ST( 's', 0, 0, 0 ), /* 422 T_Tos */
+ S_ST( 'p', 1, 0, 0 ), /* 423 T_Trap */
+ S_ST( 'e', 0, 0, 0 ), /* 424 T_True */
+ S_ST( 'y', 0, 0, 0 ), /* 425 T_Trustedkey */
+ S_ST( 'l', 0, 0, 0 ), /* 426 T_Ttl */
+ S_ST( 'e', 0, 0, 0 ), /* 427 T_Type */
+ S_ST( 'n', 3, 333, 294 ), /* 428 li */
+ S_ST( 'g', 1, 0, 0 ), /* 429 T_Unconfig */
+ S_ST( 'r', 1, 0, 0 ), /* 430 T_Unpeer */
+ S_ST( 'n', 0, 0, 0 ), /* 431 T_Version */
+ S_ST( 's', 3, 437, 428 ), /* 432 li */
+ S_ST( 'k', 0, 0, 0 ), /* 433 T_Week */
+ S_ST( 'd', 0, 0, 0 ), /* 434 T_Wildcard */
+ S_ST( 'e', 0, 0, 0 ), /* 435 T_Xleave */
+ S_ST( 'r', 0, 0, 0 ), /* 436 T_Year */
+ S_ST( 't', 3, 438, 0 ), /* 437 lis */
+ S_ST( 'e', 3, 334, 0 ), /* 438 list */
+ S_ST( 'e', 0, 0, 0 ), /* 439 T_Simulate */
+ S_ST( 'y', 0, 0, 0 ), /* 440 T_Beep_Delay */
+ S_ST( 'n', 0, 0, 0 ), /* 441 T_Sim_Duration */
+ S_ST( 't', 0, 0, 0 ), /* 442 T_Server_Offset */
+ S_ST( 'n', 0, 0, 0 ), /* 443 T_Duration */
+ S_ST( 't', 0, 0, 0 ), /* 444 T_Freq_Offset */
+ S_ST( 'r', 0, 0, 0 ), /* 445 T_Wander */
+ S_ST( 'r', 0, 0, 0 ), /* 446 T_Jitter */
+ S_ST( 'y', 0, 0, 0 ), /* 447 T_Prop_Delay */
+ S_ST( 'y', 0, 0, 0 ), /* 448 T_Proc_Delay */
+ S_ST( 'o', 3, 465, 287 ), /* 449 l */
+ S_ST( 'g', 3, 456, 0 ), /* 450 lo */
+ S_ST( 'c', 3, 452, 0 ), /* 451 log */
+ S_ST( 'o', 3, 453, 0 ), /* 452 logc */
+ S_ST( 'n', 3, 454, 0 ), /* 453 logco */
+ S_ST( 'f', 3, 455, 0 ), /* 454 logcon */
+ S_ST( 'i', 3, 335, 0 ), /* 455 logconf */
+ S_ST( 'f', 3, 457, 451 ), /* 456 log */
+ S_ST( 'i', 3, 458, 0 ), /* 457 logf */
+ S_ST( 'l', 3, 336, 0 ), /* 458 logfi */
+ S_ST( 'o', 3, 460, 450 ), /* 459 lo */
+ S_ST( 'p', 3, 461, 0 ), /* 460 loo */
+ S_ST( 's', 3, 462, 0 ), /* 461 loop */
+ S_ST( 't', 3, 463, 0 ), /* 462 loops */
+ S_ST( 'a', 3, 464, 0 ), /* 463 loopst */
+ S_ST( 't', 3, 337, 0 ), /* 464 loopsta */
+ S_ST( 'w', 3, 466, 459 ), /* 465 lo */
+ S_ST( 'p', 3, 467, 0 ), /* 466 low */
+ S_ST( 'r', 3, 468, 0 ), /* 467 lowp */
+ S_ST( 'i', 3, 469, 0 ), /* 468 lowpr */
+ S_ST( 'o', 3, 470, 0 ), /* 469 lowpri */
+ S_ST( 't', 3, 471, 0 ), /* 470 lowprio */
+ S_ST( 'r', 3, 472, 0 ), /* 471 lowpriot */
+ S_ST( 'a', 3, 338, 0 ), /* 472 lowpriotr */
+ S_ST( 'm', 3, 554, 239 ), /* 473 */
+ S_ST( 'a', 3, 492, 0 ), /* 474 m */
+ S_ST( 'n', 3, 476, 0 ), /* 475 ma */
+ S_ST( 'y', 3, 477, 0 ), /* 476 man */
+ S_ST( 'c', 3, 478, 0 ), /* 477 many */
+ S_ST( 'a', 3, 479, 0 ), /* 478 manyc */
+ S_ST( 's', 3, 480, 0 ), /* 479 manyca */
+ S_ST( 't', 3, 486, 0 ), /* 480 manycas */
+ S_ST( 'c', 3, 482, 0 ), /* 481 manycast */
+ S_ST( 'l', 3, 483, 0 ), /* 482 manycastc */
+ S_ST( 'i', 3, 484, 0 ), /* 483 manycastcl */
+ S_ST( 'e', 3, 485, 0 ), /* 484 manycastcli */
+ S_ST( 'n', 3, 339, 0 ), /* 485 manycastclie */
+ S_ST( 's', 3, 487, 481 ), /* 486 manycast */
+ S_ST( 'e', 3, 488, 0 ), /* 487 manycasts */
+ S_ST( 'r', 3, 489, 0 ), /* 488 manycastse */
+ S_ST( 'v', 3, 490, 0 ), /* 489 manycastser */
+ S_ST( 'e', 3, 340, 0 ), /* 490 manycastserv */
+ S_ST( 's', 3, 341, 475 ), /* 491 ma */
+ S_ST( 'x', 3, 507, 491 ), /* 492 ma */
+ S_ST( 'a', 3, 494, 0 ), /* 493 max */
+ S_ST( 'g', 3, 342, 0 ), /* 494 maxa */
+ S_ST( 'c', 3, 496, 493 ), /* 495 max */
+ S_ST( 'l', 3, 497, 0 ), /* 496 maxc */
+ S_ST( 'o', 3, 498, 0 ), /* 497 maxcl */
+ S_ST( 'c', 3, 343, 0 ), /* 498 maxclo */
+ S_ST( 'd', 3, 503, 495 ), /* 499 max */
+ S_ST( 'e', 3, 501, 0 ), /* 500 maxd */
+ S_ST( 'p', 3, 502, 0 ), /* 501 maxde */
+ S_ST( 't', 3, 344, 0 ), /* 502 maxdep */
+ S_ST( 'i', 3, 504, 500 ), /* 503 maxd */
+ S_ST( 's', 3, 345, 0 ), /* 504 maxdi */
+ S_ST( 'm', 3, 506, 499 ), /* 505 max */
+ S_ST( 'e', 3, 346, 0 ), /* 506 maxm */
+ S_ST( 'p', 3, 508, 505 ), /* 507 max */
+ S_ST( 'o', 3, 509, 0 ), /* 508 maxp */
+ S_ST( 'l', 3, 347, 0 ), /* 509 maxpo */
+ S_ST( 'd', 3, 511, 474 ), /* 510 m */
+ S_ST( 'n', 3, 512, 0 ), /* 511 md */
+ S_ST( 's', 3, 513, 0 ), /* 512 mdn */
+ S_ST( 't', 3, 514, 0 ), /* 513 mdns */
+ S_ST( 'r', 3, 515, 0 ), /* 514 mdnst */
+ S_ST( 'i', 3, 516, 0 ), /* 515 mdnstr */
+ S_ST( 'e', 3, 348, 0 ), /* 516 mdnstri */
+ S_ST( 'e', 3, 349, 510 ), /* 517 m */
+ S_ST( 'l', 3, 519, 0 ), /* 518 mem */
+ S_ST( 'o', 3, 520, 0 ), /* 519 meml */
+ S_ST( 'c', 3, 350, 0 ), /* 520 memlo */
+ S_ST( 'i', 3, 522, 517 ), /* 521 m */
+ S_ST( 'n', 3, 539, 0 ), /* 522 mi */
+ S_ST( 'c', 3, 524, 0 ), /* 523 min */
+ S_ST( 'l', 3, 525, 0 ), /* 524 minc */
+ S_ST( 'o', 3, 526, 0 ), /* 525 mincl */
+ S_ST( 'c', 3, 351, 0 ), /* 526 minclo */
+ S_ST( 'd', 3, 531, 523 ), /* 527 min */
+ S_ST( 'e', 3, 529, 0 ), /* 528 mind */
+ S_ST( 'p', 3, 530, 0 ), /* 529 minde */
+ S_ST( 't', 3, 352, 0 ), /* 530 mindep */
+ S_ST( 'i', 3, 532, 528 ), /* 531 mind */
+ S_ST( 's', 3, 353, 0 ), /* 532 mindi */
+ S_ST( 'i', 3, 534, 527 ), /* 533 min */
+ S_ST( 'm', 3, 535, 0 ), /* 534 mini */
+ S_ST( 'u', 3, 354, 0 ), /* 535 minim */
+ S_ST( 'p', 3, 537, 533 ), /* 536 min */
+ S_ST( 'o', 3, 538, 0 ), /* 537 minp */
+ S_ST( 'l', 3, 355, 0 ), /* 538 minpo */
+ S_ST( 's', 3, 540, 536 ), /* 539 min */
+ S_ST( 'a', 3, 541, 0 ), /* 540 mins */
+ S_ST( 'n', 3, 356, 0 ), /* 541 minsa */
+ S_ST( 'o', 3, 544, 521 ), /* 542 m */
+ S_ST( 'd', 3, 357, 0 ), /* 543 mo */
+ S_ST( 'n', 3, 548, 543 ), /* 544 mo */
+ S_ST( 'i', 3, 546, 0 ), /* 545 mon */
+ S_ST( 't', 3, 547, 0 ), /* 546 moni */
+ S_ST( 'o', 3, 359, 0 ), /* 547 monit */
+ S_ST( 't', 3, 360, 545 ), /* 548 mon */
+ S_ST( 'r', 3, 361, 542 ), /* 549 m */
+ S_ST( 's', 3, 551, 549 ), /* 550 m */
+ S_ST( 's', 3, 552, 0 ), /* 551 ms */
+ S_ST( 'n', 3, 553, 0 ), /* 552 mss */
+ S_ST( 't', 3, 329, 0 ), /* 553 mssn */
+ S_ST( 'u', 3, 555, 550 ), /* 554 m */
+ S_ST( 'l', 3, 556, 0 ), /* 555 mu */
+ S_ST( 't', 3, 557, 0 ), /* 556 mul */
+ S_ST( 'i', 3, 558, 0 ), /* 557 mult */
+ S_ST( 'c', 3, 559, 0 ), /* 558 multi */
+ S_ST( 'a', 3, 560, 0 ), /* 559 multic */
+ S_ST( 's', 3, 561, 0 ), /* 560 multica */
+ S_ST( 't', 3, 562, 0 ), /* 561 multicas */
+ S_ST( 'c', 3, 563, 0 ), /* 562 multicast */
+ S_ST( 'l', 3, 564, 0 ), /* 563 multicastc */
+ S_ST( 'i', 3, 565, 0 ), /* 564 multicastcl */
+ S_ST( 'e', 3, 566, 0 ), /* 565 multicastcli */
+ S_ST( 'n', 3, 362, 0 ), /* 566 multicastclie */
+ S_ST( 'n', 3, 610, 473 ), /* 567 */
+ S_ST( 'i', 3, 363, 0 ), /* 568 n */
+ S_ST( 'o', 3, 605, 568 ), /* 569 n */
+ S_ST( 'l', 3, 571, 0 ), /* 570 no */
+ S_ST( 'i', 3, 572, 0 ), /* 571 nol */
+ S_ST( 'n', 3, 364, 0 ), /* 572 noli */
+ S_ST( 'm', 3, 578, 570 ), /* 573 no */
+ S_ST( 'o', 3, 575, 0 ), /* 574 nom */
+ S_ST( 'd', 3, 576, 0 ), /* 575 nomo */
+ S_ST( 'i', 3, 577, 0 ), /* 576 nomod */
+ S_ST( 'f', 3, 365, 0 ), /* 577 nomodi */
+ S_ST( 'r', 3, 579, 574 ), /* 578 nom */
+ S_ST( 'u', 3, 580, 0 ), /* 579 nomr */
+ S_ST( 'l', 3, 581, 0 ), /* 580 nomru */
+ S_ST( 'i', 3, 582, 0 ), /* 581 nomrul */
+ S_ST( 's', 3, 366, 0 ), /* 582 nomruli */
+ S_ST( 'n', 3, 584, 573 ), /* 583 no */
+ S_ST( 'v', 3, 585, 367 ), /* 584 non */
+ S_ST( 'o', 3, 586, 0 ), /* 585 nonv */
+ S_ST( 'l', 3, 587, 0 ), /* 586 nonvo */
+ S_ST( 'a', 3, 588, 0 ), /* 587 nonvol */
+ S_ST( 't', 3, 589, 0 ), /* 588 nonvola */
+ S_ST( 'i', 3, 590, 0 ), /* 589 nonvolat */
+ S_ST( 'l', 3, 368, 0 ), /* 590 nonvolati */
+ S_ST( 'p', 3, 592, 583 ), /* 591 no */
+ S_ST( 'e', 3, 593, 0 ), /* 592 nop */
+ S_ST( 'e', 3, 369, 0 ), /* 593 nope */
+ S_ST( 'q', 3, 595, 591 ), /* 594 no */
+ S_ST( 'u', 3, 596, 0 ), /* 595 noq */
+ S_ST( 'e', 3, 597, 0 ), /* 596 noqu */
+ S_ST( 'r', 3, 370, 0 ), /* 597 noque */
+ S_ST( 's', 3, 599, 594 ), /* 598 no */
+ S_ST( 'e', 3, 603, 0 ), /* 599 nos */
+ S_ST( 'l', 3, 601, 0 ), /* 600 nose */
+ S_ST( 'e', 3, 602, 0 ), /* 601 nosel */
+ S_ST( 'c', 3, 371, 0 ), /* 602 nosele */
+ S_ST( 'r', 3, 604, 600 ), /* 603 nose */
+ S_ST( 'v', 3, 372, 0 ), /* 604 noser */
+ S_ST( 't', 3, 606, 598 ), /* 605 no */
+ S_ST( 'r', 3, 608, 0 ), /* 606 not */
+ S_ST( 'a', 3, 373, 0 ), /* 607 notr */
+ S_ST( 'u', 3, 609, 607 ), /* 608 notr */
+ S_ST( 's', 3, 374, 0 ), /* 609 notru */
+ S_ST( 't', 3, 375, 569 ), /* 610 n */
+ S_ST( 'p', 3, 612, 0 ), /* 611 ntp */
+ S_ST( 'o', 3, 613, 0 ), /* 612 ntpp */
+ S_ST( 'r', 3, 376, 0 ), /* 613 ntppo */
+ S_ST( 's', 3, 615, 611 ), /* 614 ntp */
+ S_ST( 'i', 3, 616, 0 ), /* 615 ntps */
+ S_ST( 'g', 3, 617, 0 ), /* 616 ntpsi */
+ S_ST( 'n', 3, 618, 0 ), /* 617 ntpsig */
+ S_ST( 'd', 3, 619, 0 ), /* 618 ntpsign */
+ S_ST( 's', 3, 620, 0 ), /* 619 ntpsignd */
+ S_ST( 'o', 3, 621, 0 ), /* 620 ntpsignds */
+ S_ST( 'c', 3, 622, 0 ), /* 621 ntpsigndso */
+ S_ST( 'k', 3, 623, 0 ), /* 622 ntpsigndsoc */
+ S_ST( 'e', 3, 377, 0 ), /* 623 ntpsigndsock */
+ S_ST( 'o', 3, 625, 567 ), /* 624 */
+ S_ST( 'r', 3, 626, 0 ), /* 625 o */
+ S_ST( 'p', 3, 627, 0 ), /* 626 or */
+ S_ST( 'h', 3, 628, 0 ), /* 627 orp */
+ S_ST( 'a', 3, 378, 0 ), /* 628 orph */
+ S_ST( 'w', 3, 630, 0 ), /* 629 orphan */
+ S_ST( 'a', 3, 631, 0 ), /* 630 orphanw */
+ S_ST( 'i', 3, 379, 0 ), /* 631 orphanwa */
+ S_ST( 'p', 3, 391, 624 ), /* 632 */
+ S_ST( 'a', 3, 634, 0 ), /* 633 p */
+ S_ST( 'n', 3, 635, 0 ), /* 634 pa */
+ S_ST( 'i', 3, 380, 0 ), /* 635 pan */
+ S_ST( 'e', 3, 637, 633 ), /* 636 p */
+ S_ST( 'e', 3, 381, 0 ), /* 637 pe */
+ S_ST( 's', 3, 639, 0 ), /* 638 peer */
+ S_ST( 't', 3, 640, 0 ), /* 639 peers */
+ S_ST( 'a', 3, 641, 0 ), /* 640 peerst */
+ S_ST( 't', 3, 382, 0 ), /* 641 peersta */
+ S_ST( 'h', 3, 643, 636 ), /* 642 p */
+ S_ST( 'o', 3, 644, 0 ), /* 643 ph */
+ S_ST( 'n', 3, 383, 0 ), /* 644 pho */
+ S_ST( 'i', 3, 384, 642 ), /* 645 p */
+ S_ST( 'f', 3, 647, 0 ), /* 646 pid */
+ S_ST( 'i', 3, 648, 0 ), /* 647 pidf */
+ S_ST( 'l', 3, 385, 0 ), /* 648 pidfi */
+ S_ST( 'o', 3, 651, 645 ), /* 649 p */
+ S_ST( 'o', 3, 386, 0 ), /* 650 po */
+ S_ST( 'r', 3, 387, 650 ), /* 651 po */
+ S_ST( 'r', 3, 659, 649 ), /* 652 p */
+ S_ST( 'e', 3, 657, 0 ), /* 653 pr */
+ S_ST( 'e', 3, 655, 0 ), /* 654 pre */
+ S_ST( 'm', 3, 656, 0 ), /* 655 pree */
+ S_ST( 'p', 3, 388, 0 ), /* 656 preem */
+ S_ST( 'f', 3, 658, 654 ), /* 657 pre */
+ S_ST( 'e', 3, 389, 0 ), /* 658 pref */
+ S_ST( 'o', 3, 672, 653 ), /* 659 pr */
+ S_ST( 'c', 3, 661, 0 ), /* 660 pro */
+ S_ST( '_', 3, 662, 0 ), /* 661 proc */
+ S_ST( 'd', 3, 663, 0 ), /* 662 proc_ */
+ S_ST( 'e', 3, 664, 0 ), /* 663 proc_d */
+ S_ST( 'l', 3, 665, 0 ), /* 664 proc_de */
+ S_ST( 'a', 3, 448, 0 ), /* 665 proc_del */
+ S_ST( 'p', 3, 667, 660 ), /* 666 pro */
+ S_ST( '_', 3, 668, 0 ), /* 667 prop */
+ S_ST( 'd', 3, 669, 0 ), /* 668 prop_ */
+ S_ST( 'e', 3, 670, 0 ), /* 669 prop_d */
+ S_ST( 'l', 3, 671, 0 ), /* 670 prop_de */
+ S_ST( 'a', 3, 447, 0 ), /* 671 prop_del */
+ S_ST( 't', 3, 673, 666 ), /* 672 pro */
+ S_ST( 'o', 3, 674, 0 ), /* 673 prot */
+ S_ST( 's', 3, 675, 0 ), /* 674 proto */
+ S_ST( 't', 3, 676, 0 ), /* 675 protos */
+ S_ST( 'a', 3, 677, 0 ), /* 676 protost */
+ S_ST( 't', 3, 390, 0 ), /* 677 protosta */
+ S_ST( 'r', 3, 709, 632 ), /* 678 */
+ S_ST( 'a', 3, 685, 0 ), /* 679 r */
+ S_ST( 'n', 3, 681, 0 ), /* 680 ra */
+ S_ST( 'd', 3, 682, 0 ), /* 681 ran */
+ S_ST( 'f', 3, 683, 0 ), /* 682 rand */
+ S_ST( 'i', 3, 684, 0 ), /* 683 randf */
+ S_ST( 'l', 3, 392, 0 ), /* 684 randfi */
+ S_ST( 'w', 3, 686, 680 ), /* 685 ra */
+ S_ST( 's', 3, 687, 0 ), /* 686 raw */
+ S_ST( 't', 3, 688, 0 ), /* 687 raws */
+ S_ST( 'a', 3, 689, 0 ), /* 688 rawst */
+ S_ST( 't', 3, 393, 0 ), /* 689 rawsta */
+ S_ST( 'e', 3, 706, 679 ), /* 690 r */
+ S_ST( 'f', 3, 692, 0 ), /* 691 re */
+ S_ST( 'i', 3, 394, 0 ), /* 692 ref */
+ S_ST( 'q', 3, 694, 691 ), /* 693 re */
+ S_ST( 'u', 3, 695, 0 ), /* 694 req */
+ S_ST( 'e', 3, 696, 0 ), /* 695 requ */
+ S_ST( 's', 3, 697, 0 ), /* 696 reque */
+ S_ST( 't', 3, 698, 0 ), /* 697 reques */
+ S_ST( 'k', 3, 699, 0 ), /* 698 request */
+ S_ST( 'e', 3, 395, 0 ), /* 699 requestk */
+ S_ST( 's', 3, 702, 693 ), /* 700 re */
+ S_ST( 'e', 3, 396, 0 ), /* 701 res */
+ S_ST( 't', 3, 703, 701 ), /* 702 res */
+ S_ST( 'r', 3, 704, 0 ), /* 703 rest */
+ S_ST( 'i', 3, 705, 0 ), /* 704 restr */
+ S_ST( 'c', 3, 397, 0 ), /* 705 restri */
+ S_ST( 'v', 3, 707, 700 ), /* 706 re */
+ S_ST( 'o', 3, 708, 0 ), /* 707 rev */
+ S_ST( 'k', 3, 398, 0 ), /* 708 revo */
+ S_ST( 'l', 3, 710, 690 ), /* 709 r */
+ S_ST( 'i', 3, 711, 0 ), /* 710 rl */
+ S_ST( 'm', 3, 712, 0 ), /* 711 rli */
+ S_ST( 'i', 3, 399, 0 ), /* 712 rlim */
+ S_ST( 's', 3, 786, 678 ), /* 713 */
+ S_ST( 'a', 3, 715, 0 ), /* 714 s */
+ S_ST( 'v', 3, 716, 0 ), /* 715 sa */
+ S_ST( 'e', 3, 717, 0 ), /* 716 sav */
+ S_ST( 'c', 3, 718, 0 ), /* 717 save */
+ S_ST( 'o', 3, 719, 0 ), /* 718 savec */
+ S_ST( 'n', 3, 720, 0 ), /* 719 saveco */
+ S_ST( 'f', 3, 721, 0 ), /* 720 savecon */
+ S_ST( 'i', 3, 722, 0 ), /* 721 saveconf */
+ S_ST( 'g', 3, 723, 0 ), /* 722 saveconfi */
+ S_ST( 'd', 3, 724, 0 ), /* 723 saveconfig */
+ S_ST( 'i', 3, 400, 0 ), /* 724 saveconfigd */
+ S_ST( 'e', 3, 735, 714 ), /* 725 s */
+ S_ST( 'r', 3, 727, 0 ), /* 726 se */
+ S_ST( 'v', 3, 728, 0 ), /* 727 ser */
+ S_ST( 'e', 3, 401, 0 ), /* 728 serv */
+ S_ST( '_', 3, 730, 0 ), /* 729 server */
+ S_ST( 'o', 3, 731, 0 ), /* 730 server_ */
+ S_ST( 'f', 3, 732, 0 ), /* 731 server_o */
+ S_ST( 'f', 3, 733, 0 ), /* 732 server_of */
+ S_ST( 's', 3, 734, 0 ), /* 733 server_off */
+ S_ST( 'e', 3, 442, 0 ), /* 734 server_offs */
+ S_ST( 't', 3, 736, 726 ), /* 735 se */
+ S_ST( 'v', 3, 737, 0 ), /* 736 set */
+ S_ST( 'a', 3, 402, 0 ), /* 737 setv */
+ S_ST( 'i', 3, 739, 725 ), /* 738 s */
+ S_ST( 'm', 3, 740, 0 ), /* 739 si */
+ S_ST( 'u', 3, 741, 0 ), /* 740 sim */
+ S_ST( 'l', 3, 742, 0 ), /* 741 simu */
+ S_ST( 'a', 3, 743, 0 ), /* 742 simul */
+ S_ST( 't', 3, 744, 0 ), /* 743 simula */
+ S_ST( 'i', 3, 745, 439 ), /* 744 simulat */
+ S_ST( 'o', 3, 746, 0 ), /* 745 simulati */
+ S_ST( 'n', 3, 747, 0 ), /* 746 simulatio */
+ S_ST( '_', 3, 748, 0 ), /* 747 simulation */
+ S_ST( 'd', 3, 749, 0 ), /* 748 simulation_ */
+ S_ST( 'u', 3, 750, 0 ), /* 749 simulation_d */
+ S_ST( 'r', 3, 751, 0 ), /* 750 simulation_du */
+ S_ST( 'a', 3, 752, 0 ), /* 751 simulation_dur */
+ S_ST( 't', 3, 753, 0 ), /* 752 simulation_dura */
+ S_ST( 'i', 3, 754, 0 ), /* 753 simulation_durat */
+ S_ST( 'o', 3, 441, 0 ), /* 754 simulation_durati */
+ S_ST( 'o', 3, 756, 738 ), /* 755 s */
+ S_ST( 'u', 3, 757, 0 ), /* 756 so */
+ S_ST( 'r', 3, 758, 0 ), /* 757 sou */
+ S_ST( 'c', 3, 403, 0 ), /* 758 sour */
+ S_ST( 't', 3, 782, 755 ), /* 759 s */
+ S_ST( 'a', 3, 766, 0 ), /* 760 st */
+ S_ST( 'c', 3, 762, 0 ), /* 761 sta */
+ S_ST( 'k', 3, 763, 0 ), /* 762 stac */
+ S_ST( 's', 3, 764, 0 ), /* 763 stack */
+ S_ST( 'i', 3, 765, 0 ), /* 764 stacks */
+ S_ST( 'z', 3, 404, 0 ), /* 765 stacksi */
+ S_ST( 't', 3, 406, 761 ), /* 766 sta */
+ S_ST( 'i', 3, 768, 0 ), /* 767 stat */
+ S_ST( 's', 3, 769, 0 ), /* 768 stati */
+ S_ST( 't', 3, 770, 0 ), /* 769 statis */
+ S_ST( 'i', 3, 771, 0 ), /* 770 statist */
+ S_ST( 'c', 3, 405, 0 ), /* 771 statisti */
+ S_ST( 'd', 3, 773, 0 ), /* 772 stats */
+ S_ST( 'i', 3, 407, 0 ), /* 773 statsd */
+ S_ST( 'e', 3, 408, 760 ), /* 774 st */
+ S_ST( 'b', 3, 776, 0 ), /* 775 step */
+ S_ST( 'a', 3, 777, 0 ), /* 776 stepb */
+ S_ST( 'c', 3, 409, 0 ), /* 777 stepba */
+ S_ST( 'f', 3, 779, 775 ), /* 778 step */
+ S_ST( 'w', 3, 410, 0 ), /* 779 stepf */
+ S_ST( 'o', 3, 781, 778 ), /* 780 step */
+ S_ST( 'u', 3, 411, 0 ), /* 781 stepo */
+ S_ST( 'r', 3, 783, 774 ), /* 782 st */
+ S_ST( 'a', 3, 784, 0 ), /* 783 str */
+ S_ST( 't', 3, 785, 0 ), /* 784 stra */
+ S_ST( 'u', 3, 412, 0 ), /* 785 strat */
+ S_ST( 'y', 3, 414, 759 ), /* 786 s */
+ S_ST( 's', 3, 788, 0 ), /* 787 sys */
+ S_ST( 't', 3, 789, 0 ), /* 788 syss */
+ S_ST( 'a', 3, 790, 0 ), /* 789 sysst */
+ S_ST( 't', 3, 415, 0 ), /* 790 syssta */
+ S_ST( 't', 3, 817, 713 ), /* 791 */
+ S_ST( 'i', 3, 803, 0 ), /* 792 t */
+ S_ST( 'c', 3, 416, 0 ), /* 793 ti */
+ S_ST( 'm', 3, 796, 793 ), /* 794 ti */
+ S_ST( 'e', 3, 419, 0 ), /* 795 tim */
+ S_ST( 'i', 3, 797, 795 ), /* 796 tim */
+ S_ST( 'n', 3, 798, 0 ), /* 797 timi */
+ S_ST( 'g', 3, 799, 0 ), /* 798 timin */
+ S_ST( 's', 3, 800, 0 ), /* 799 timing */
+ S_ST( 't', 3, 801, 0 ), /* 800 timings */
+ S_ST( 'a', 3, 802, 0 ), /* 801 timingst */
+ S_ST( 't', 3, 420, 0 ), /* 802 timingsta */
+ S_ST( 'n', 3, 804, 794 ), /* 803 ti */
+ S_ST( 'k', 3, 805, 0 ), /* 804 tin */
+ S_ST( 'e', 3, 421, 0 ), /* 805 tink */
+ S_ST( 'o', 3, 422, 792 ), /* 806 t */
+ S_ST( 'r', 3, 809, 806 ), /* 807 t */
+ S_ST( 'a', 3, 423, 0 ), /* 808 tr */
+ S_ST( 'u', 3, 810, 808 ), /* 809 tr */
+ S_ST( 's', 3, 811, 424 ), /* 810 tru */
+ S_ST( 't', 3, 812, 0 ), /* 811 trus */
+ S_ST( 'e', 3, 813, 0 ), /* 812 trust */
+ S_ST( 'd', 3, 814, 0 ), /* 813 truste */
+ S_ST( 'k', 3, 815, 0 ), /* 814 trusted */
+ S_ST( 'e', 3, 425, 0 ), /* 815 trustedk */
+ S_ST( 't', 3, 426, 807 ), /* 816 t */
+ S_ST( 'y', 3, 818, 816 ), /* 817 t */
+ S_ST( 'p', 3, 427, 0 ), /* 818 ty */
+ S_ST( 'u', 3, 820, 791 ), /* 819 */
+ S_ST( 'n', 3, 826, 0 ), /* 820 u */
+ S_ST( 'c', 3, 822, 0 ), /* 821 un */
+ S_ST( 'o', 3, 823, 0 ), /* 822 unc */
+ S_ST( 'n', 3, 824, 0 ), /* 823 unco */
+ S_ST( 'f', 3, 825, 0 ), /* 824 uncon */
+ S_ST( 'i', 3, 429, 0 ), /* 825 unconf */
+ S_ST( 'p', 3, 827, 821 ), /* 826 un */
+ S_ST( 'e', 3, 828, 0 ), /* 827 unp */
+ S_ST( 'e', 3, 430, 0 ), /* 828 unpe */
+ S_ST( 'v', 3, 830, 819 ), /* 829 */
+ S_ST( 'e', 3, 831, 0 ), /* 830 v */
+ S_ST( 'r', 3, 832, 0 ), /* 831 ve */
+ S_ST( 's', 3, 833, 0 ), /* 832 ver */
+ S_ST( 'i', 3, 834, 0 ), /* 833 vers */
+ S_ST( 'o', 3, 431, 0 ), /* 834 versi */
+ S_ST( 'w', 3, 842, 829 ), /* 835 */
+ S_ST( 'a', 3, 837, 0 ), /* 836 w */
+ S_ST( 'n', 3, 838, 0 ), /* 837 wa */
+ S_ST( 'd', 3, 839, 0 ), /* 838 wan */
+ S_ST( 'e', 3, 445, 0 ), /* 839 wand */
+ S_ST( 'e', 3, 841, 836 ), /* 840 w */
+ S_ST( 'e', 3, 433, 0 ), /* 841 we */
+ S_ST( 'i', 3, 843, 840 ), /* 842 w */
+ S_ST( 'l', 3, 844, 0 ), /* 843 wi */
+ S_ST( 'd', 3, 845, 0 ), /* 844 wil */
+ S_ST( 'c', 3, 846, 0 ), /* 845 wild */
+ S_ST( 'a', 3, 847, 0 ), /* 846 wildc */
+ S_ST( 'r', 3, 434, 0 ), /* 847 wildca */
+ S_ST( 'x', 3, 849, 835 ), /* 848 */
+ S_ST( 'l', 3, 850, 0 ), /* 849 x */
+ S_ST( 'e', 3, 851, 0 ), /* 850 xl */
+ S_ST( 'a', 3, 852, 0 ), /* 851 xle */
+ S_ST( 'v', 3, 435, 0 ), /* 852 xlea */
+ S_ST( 'y', 3, 854, 848 ), /* 853 [initial state] */
+ S_ST( 'e', 3, 855, 0 ), /* 854 y */
+ S_ST( 'a', 3, 436, 0 ) /* 855 ye */
+};
+
diff --git a/contrib/ntp/ntpd/ntp_leapsec.c b/contrib/ntp/ntpd/ntp_leapsec.c
new file mode 100644
index 0000000..7a652f5
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_leapsec.c
@@ -0,0 +1,1186 @@
+/*
+ * ntp_leapsec.c - leap second processing for NTPD
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ * ----------------------------------------------------------------------
+ * This is an attempt to get the leap second handling into a dedicated
+ * module to make the somewhat convoluted logic testable.
+ */
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include "ntp_types.h"
+#include "ntp_fp.h"
+#include "ntp_stdlib.h"
+#include "ntp_calendar.h"
+#include "ntp_leapsec.h"
+#include "ntp.h"
+#include "vint64ops.h"
+#include "lib_strbuf.h"
+
+#include "isc/sha1.h"
+
+static const char * const logPrefix = "leapsecond file";
+
+/* ---------------------------------------------------------------------
+ * GCC is rather sticky with its 'const' attribute. We have to do it more
+ * explicit than with a cast if we want to get rid of a CONST qualifier.
+ * Greetings from the PASCAL world, where casting was only possible via
+ * untagged unions...
+ */
+static inline void*
+noconst(
+ const void* ptr
+ )
+{
+ union {
+ const void * cp;
+ void * vp;
+ } tmp;
+ tmp.cp = ptr;
+ return tmp.vp;
+}
+
+/* ---------------------------------------------------------------------
+ * Our internal data structure
+ */
+#define MAX_HIST 10 /* history of leap seconds */
+
+struct leap_info {
+ vint64 ttime; /* transition time (after the step, ntp scale) */
+ uint32_t stime; /* schedule limit (a month before transition) */
+ int16_t taiof; /* TAI offset on and after the transition */
+ uint8_t dynls; /* dynamic: inserted on peer/clock request */
+};
+typedef struct leap_info leap_info_t;
+
+struct leap_head {
+ vint64 update; /* time of information update */
+ vint64 expire; /* table expiration time */
+ uint16_t size; /* number of infos in table */
+ int16_t base_tai; /* total leaps before first entry */
+ int16_t this_tai; /* current TAI offset */
+ int16_t next_tai; /* TAI offset after 'when' */
+ vint64 dtime; /* due time (current era end) */
+ vint64 ttime; /* nominal transition time (next era start) */
+ vint64 stime; /* schedule time (when we take notice) */
+ vint64 ebase; /* base time of this leap era */
+ uint8_t dynls; /* next leap is dynamic (by peer request) */
+};
+typedef struct leap_head leap_head_t;
+
+struct leap_table {
+ leap_signature_t lsig;
+ leap_head_t head;
+ leap_info_t info[MAX_HIST];
+};
+
+/* Where we store our tables */
+static leap_table_t _ltab[2], *_lptr;
+static int/*BOOL*/ _electric;
+
+/* Forward decls of local helpers */
+static int add_range(leap_table_t*, const leap_info_t*);
+static char * get_line(leapsec_reader, void*, char*, size_t);
+static char * skipws(const char*);
+static int parsefail(const char * cp, const char * ep);
+static void reload_limits(leap_table_t*, const vint64*);
+static void fetch_leap_era(leap_era_t*, const leap_table_t*,
+ const vint64*);
+static int betweenu32(uint32_t, uint32_t, uint32_t);
+static void reset_times(leap_table_t*);
+static int leapsec_add(leap_table_t*, const vint64*, int);
+static int leapsec_raw(leap_table_t*, const vint64 *, int, int);
+static const char * lstostr(const vint64 * ts);
+
+/* =====================================================================
+ * Get & Set the current leap table
+ */
+
+/* ------------------------------------------------------------------ */
+leap_table_t *
+leapsec_get_table(
+ int alternate)
+{
+ leap_table_t *p1, *p2;
+
+ p1 = _lptr;
+ if (p1 == &_ltab[0]) {
+ p2 = &_ltab[1];
+ } else if (p1 == &_ltab[1]) {
+ p2 = &_ltab[0];
+ } else {
+ p1 = &_ltab[0];
+ p2 = &_ltab[1];
+ reset_times(p1);
+ reset_times(p2);
+ _lptr = p1;
+ }
+ if (alternate) {
+ memcpy(p2, p1, sizeof(leap_table_t));
+ p1 = p2;
+ }
+
+ return p1;
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_set_table(
+ leap_table_t * pt)
+{
+ if (pt == &_ltab[0] || pt == &_ltab[1])
+ _lptr = pt;
+ return _lptr == pt;
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_electric(
+ int/*BOOL*/ on)
+{
+ int res = _electric;
+ if (on < 0)
+ return res;
+
+ _electric = (on != 0);
+ if (_electric == res)
+ return res;
+
+ if (_lptr == &_ltab[0] || _lptr == &_ltab[1])
+ reset_times(_lptr);
+
+ return res;
+}
+
+/* =====================================================================
+ * API functions that operate on tables
+ */
+
+/* ---------------------------------------------------------------------
+ * Clear all leap second data. Use it for init & cleanup
+ */
+void
+leapsec_clear(
+ leap_table_t * pt)
+{
+ memset(&pt->lsig, 0, sizeof(pt->lsig));
+ memset(&pt->head, 0, sizeof(pt->head));
+ reset_times(pt);
+}
+
+/* ---------------------------------------------------------------------
+ * Load a leap second file and check expiration on the go
+ */
+int/*BOOL*/
+leapsec_load(
+ leap_table_t * pt ,
+ leapsec_reader func,
+ void * farg,
+ int use_build_limit)
+{
+ char *cp, *ep, linebuf[50];
+ vint64 ttime, limit;
+ long taiof;
+ struct calendar build;
+
+ leapsec_clear(pt);
+ if (use_build_limit && ntpcal_get_build_date(&build)) {
+ /* don't prune everything -- permit the last 10yrs
+ * before build.
+ */
+ build.year -= 10;
+ limit = ntpcal_date_to_ntp64(&build);
+ } else {
+ memset(&limit, 0, sizeof(limit));
+ }
+
+ while (get_line(func, farg, linebuf, sizeof(linebuf))) {
+ cp = linebuf;
+ if (*cp == '#') {
+ cp++;
+ if (*cp == '@') {
+ cp = skipws(cp+1);
+ pt->head.expire = strtouv64(cp, &ep, 10);
+ if (parsefail(cp, ep))
+ goto fail_read;
+ pt->lsig.etime = pt->head.expire.D_s.lo;
+ } else if (*cp == '$') {
+ cp = skipws(cp+1);
+ pt->head.update = strtouv64(cp, &ep, 10);
+ if (parsefail(cp, ep))
+ goto fail_read;
+ }
+ } else if (isdigit((u_char)*cp)) {
+ ttime = strtouv64(cp, &ep, 10);
+ if (parsefail(cp, ep))
+ goto fail_read;
+ cp = skipws(ep);
+ taiof = strtol(cp, &ep, 10);
+ if ( parsefail(cp, ep)
+ || taiof > SHRT_MAX || taiof < SHRT_MIN)
+ goto fail_read;
+ if (ucmpv64(&ttime, &limit) >= 0) {
+ if (!leapsec_raw(pt, &ttime,
+ taiof, FALSE))
+ goto fail_insn;
+ } else {
+ pt->head.base_tai = (int16_t)taiof;
+ }
+ pt->lsig.ttime = ttime.D_s.lo;
+ pt->lsig.taiof = (int16_t)taiof;
+ }
+ }
+ return TRUE;
+
+fail_read:
+ errno = EILSEQ;
+fail_insn:
+ leapsec_clear(pt);
+ return FALSE;
+}
+
+/* ---------------------------------------------------------------------
+ * Dump a table in human-readable format. Use 'fprintf' and a FILE
+ * pointer if you want to get it printed into a stream.
+ */
+void
+leapsec_dump(
+ const leap_table_t * pt ,
+ leapsec_dumper func,
+ void * farg)
+{
+ int idx;
+ vint64 ts;
+ struct calendar atb, ttb;
+
+ ntpcal_ntp64_to_date(&ttb, &pt->head.expire);
+ (*func)(farg, "leap table (%u entries) expires at %04u-%02u-%02u:\n",
+ pt->head.size,
+ ttb.year, ttb.month, ttb.monthday);
+ idx = pt->head.size;
+ while (idx-- != 0) {
+ ts = pt->info[idx].ttime;
+ ntpcal_ntp64_to_date(&ttb, &ts);
+ ts = subv64u32(&ts, pt->info[idx].stime);
+ ntpcal_ntp64_to_date(&atb, &ts);
+
+ (*func)(farg, "%04u-%02u-%02u [%c] (%04u-%02u-%02u) - %d\n",
+ ttb.year, ttb.month, ttb.monthday,
+ "-*"[pt->info[idx].dynls != 0],
+ atb.year, atb.month, atb.monthday,
+ pt->info[idx].taiof);
+ }
+}
+
+/* =====================================================================
+ * usecase driven API functions
+ */
+
+int/*BOOL*/
+leapsec_query(
+ leap_result_t * qr ,
+ uint32_t ts32 ,
+ const time_t * pivot)
+{
+ leap_table_t * pt;
+ vint64 ts64, last, next;
+ uint32_t due32;
+ int fired;
+
+ /* preset things we use later on... */
+ fired = FALSE;
+ ts64 = ntpcal_ntp_to_ntp(ts32, pivot);
+ pt = leapsec_get_table(FALSE);
+ memset(qr, 0, sizeof(leap_result_t));
+
+ if (ucmpv64(&ts64, &pt->head.ebase) < 0) {
+ /* Most likely after leap frame reset. Could also be a
+ * backstep of the system clock. Anyway, get the new
+ * leap era frame.
+ */
+ reload_limits(pt, &ts64);
+ } else if (ucmpv64(&ts64, &pt->head.dtime) >= 0) {
+ /* Boundary crossed in forward direction. This might
+ * indicate a leap transition, so we prepare for that
+ * case.
+ *
+ * Some operations below are actually NOPs in electric
+ * mode, but having only one code path that works for
+ * both modes is easier to maintain.
+ *
+ * There's another quirk we must keep looking out for:
+ * If we just stepped the clock, the step might have
+ * crossed a leap boundary. As with backward steps, we
+ * do not want to raise the 'fired' event in that case.
+ * So we raise the 'fired' event only if we're close to
+ * the transition and just reload the limits otherwise.
+ */
+ last = addv64i32(&pt->head.dtime, 3); /* get boundary */
+ if (ucmpv64(&ts64, &last) >= 0) {
+ /* that was likely a query after a step */
+ reload_limits(pt, &ts64);
+ } else {
+ /* close enough for deeper examination */
+ last = pt->head.ttime;
+ qr->warped = (int16_t)(last.D_s.lo -
+ pt->head.dtime.D_s.lo);
+ next = addv64i32(&ts64, qr->warped);
+ reload_limits(pt, &next);
+ fired = ucmpv64(&pt->head.ebase, &last) == 0;
+ if (fired) {
+ ts64 = next;
+ ts32 = next.D_s.lo;
+ } else {
+ qr->warped = 0;
+ }
+ }
+ }
+
+ qr->tai_offs = pt->head.this_tai;
+ qr->ebase = pt->head.ebase;
+ qr->ttime = pt->head.ttime;
+
+ /* If before the next scheduling alert, we're done. */
+ if (ucmpv64(&ts64, &pt->head.stime) < 0)
+ return fired;
+
+ /* now start to collect the remaining data */
+ due32 = pt->head.dtime.D_s.lo;
+
+ qr->tai_diff = pt->head.next_tai - pt->head.this_tai;
+ qr->ddist = due32 - ts32;
+ qr->dynamic = pt->head.dynls;
+ qr->proximity = LSPROX_SCHEDULE;
+
+ /* if not in the last day before transition, we're done. */
+ if (!betweenu32(due32 - SECSPERDAY, ts32, due32))
+ return fired;
+
+ qr->proximity = LSPROX_ANNOUNCE;
+ if (!betweenu32(due32 - 10, ts32, due32))
+ return fired;
+
+ /* The last 10s before the transition. Prepare for action! */
+ qr->proximity = LSPROX_ALERT;
+ return fired;
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_query_era(
+ leap_era_t * qr ,
+ uint32_t ntpts,
+ const time_t * pivot)
+{
+ const leap_table_t * pt;
+ vint64 ts64;
+
+ pt = leapsec_get_table(FALSE);
+ ts64 = ntpcal_ntp_to_ntp(ntpts, pivot);
+ fetch_leap_era(qr, pt, &ts64);
+ return TRUE;
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_frame(
+ leap_result_t *qr)
+{
+ const leap_table_t * pt;
+
+ memset(qr, 0, sizeof(leap_result_t));
+ pt = leapsec_get_table(FALSE);
+
+ qr->tai_offs = pt->head.this_tai;
+ qr->tai_diff = pt->head.next_tai - pt->head.this_tai;
+ qr->ebase = pt->head.ebase;
+ qr->ttime = pt->head.ttime;
+ qr->dynamic = pt->head.dynls;
+
+ return ucmpv64(&pt->head.ttime, &pt->head.stime) >= 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* Reset the current leap frame */
+void
+leapsec_reset_frame(void)
+{
+ reset_times(leapsec_get_table(FALSE));
+}
+
+/* ------------------------------------------------------------------ */
+/* load a file from a FILE pointer. Note: If hcheck is true, load
+ * only after successful signature check. The stream must be seekable
+ * or this will fail.
+ */
+int/*BOOL*/
+leapsec_load_stream(
+ FILE * ifp ,
+ const char * fname,
+ int/*BOOL*/ logall)
+{
+ leap_table_t *pt;
+ int rcheck;
+
+ if (NULL == fname)
+ fname = "<unknown>";
+
+ rcheck = leapsec_validate((leapsec_reader)getc, ifp);
+ if (logall)
+ switch (rcheck)
+ {
+ case LSVALID_GOODHASH:
+ msyslog(LOG_NOTICE, "%s ('%s'): good hash signature",
+ logPrefix, fname);
+ break;
+
+ case LSVALID_NOHASH:
+ msyslog(LOG_ERR, "%s ('%s'): no hash signature",
+ logPrefix, fname);
+ break;
+ case LSVALID_BADHASH:
+ msyslog(LOG_ERR, "%s ('%s'): signature mismatch",
+ logPrefix, fname);
+ break;
+ case LSVALID_BADFORMAT:
+ msyslog(LOG_ERR, "%s ('%s'): malformed hash signature",
+ logPrefix, fname);
+ break;
+ default:
+ msyslog(LOG_ERR, "%s ('%s'): unknown error code %d",
+ logPrefix, fname, rcheck);
+ break;
+ }
+ if (rcheck < 0)
+ return FALSE;
+
+ rewind(ifp);
+ pt = leapsec_get_table(TRUE);
+ if (!leapsec_load(pt, (leapsec_reader)getc, ifp, TRUE)) {
+ switch (errno) {
+ case EINVAL:
+ msyslog(LOG_ERR, "%s ('%s'): bad transition time",
+ logPrefix, fname);
+ break;
+ case ERANGE:
+ msyslog(LOG_ERR, "%s ('%s'): times not ascending",
+ logPrefix, fname);
+ break;
+ default:
+ msyslog(LOG_ERR, "%s ('%s'): parsing error",
+ logPrefix, fname);
+ break;
+ }
+ return FALSE;
+ }
+
+ if (pt->head.size)
+ msyslog(LOG_NOTICE, "%s ('%s'): loaded, expire=%s last=%s ofs=%d",
+ logPrefix, fname, lstostr(&pt->head.expire),
+ lstostr(&pt->info[0].ttime), pt->info[0].taiof);
+ else
+ msyslog(LOG_NOTICE,
+ "%s ('%s'): loaded, expire=%s ofs=%d (no entries after build date)",
+ logPrefix, fname, lstostr(&pt->head.expire),
+ pt->head.base_tai);
+
+ return leapsec_set_table(pt);
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_load_file(
+ const char * fname,
+ struct stat * sb_old,
+ int/*BOOL*/ force,
+ int/*BOOL*/ logall)
+{
+ FILE * fp;
+ struct stat sb_new;
+ int rc;
+
+ /* just do nothing if there is no leap file */
+ if ( !(fname && *fname) )
+ return FALSE;
+
+ /* try to stat the leapfile */
+ if (0 != stat(fname, &sb_new)) {
+ if (logall)
+ msyslog(LOG_ERR, "%s ('%s'): stat failed: %m",
+ logPrefix, fname);
+ return FALSE;
+ }
+
+ /* silently skip to postcheck if no new file found */
+ if (NULL != sb_old) {
+ if (!force
+ && sb_old->st_mtime == sb_new.st_mtime
+ && sb_old->st_ctime == sb_new.st_ctime
+ )
+ return FALSE;
+ *sb_old = sb_new;
+ }
+
+ /* try to open the leap file, complain if that fails
+ *
+ * [perlinger@ntp.org]
+ * coverity raises a TOCTOU (time-of-check/time-of-use) issue
+ * here, which is not entirely helpful: While there is indeed a
+ * possible race condition between the 'stat()' call above and
+ * the 'fopen)' call below, I intentionally want to omit the
+ * overhead of opening the file and calling 'fstat()', because
+ * in most cases the file would have be to closed anyway without
+ * reading the contents. I chose to disable the coverity
+ * warning instead.
+ *
+ * So unless someone comes up with a reasonable argument why
+ * this could be a real issue, I'll just try to silence coverity
+ * on that topic.
+ */
+ /* coverity[toctou] */
+ if ((fp = fopen(fname, "r")) == NULL) {
+ if (logall)
+ msyslog(LOG_ERR,
+ "%s ('%s'): open failed: %m",
+ logPrefix, fname);
+ return FALSE;
+ }
+
+ rc = leapsec_load_stream(fp, fname, logall);
+ fclose(fp);
+ return rc;
+}
+
+/* ------------------------------------------------------------------ */
+void
+leapsec_getsig(
+ leap_signature_t * psig)
+{
+ const leap_table_t * pt;
+
+ pt = leapsec_get_table(FALSE);
+ memcpy(psig, &pt->lsig, sizeof(leap_signature_t));
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_expired(
+ uint32_t when,
+ const time_t * tpiv)
+{
+ const leap_table_t * pt;
+ vint64 limit;
+
+ pt = leapsec_get_table(FALSE);
+ limit = ntpcal_ntp_to_ntp(when, tpiv);
+ return ucmpv64(&limit, &pt->head.expire) >= 0;
+}
+
+/* ------------------------------------------------------------------ */
+int32_t
+leapsec_daystolive(
+ uint32_t when,
+ const time_t * tpiv)
+{
+ const leap_table_t * pt;
+ vint64 limit;
+
+ pt = leapsec_get_table(FALSE);
+ limit = ntpcal_ntp_to_ntp(when, tpiv);
+ limit = subv64(&pt->head.expire, &limit);
+ return ntpcal_daysplit(&limit).hi;
+}
+
+/* ------------------------------------------------------------------ */
+#if 0 /* currently unused -- possibly revived later */
+int/*BOOL*/
+leapsec_add_fix(
+ int total,
+ uint32_t ttime,
+ uint32_t etime,
+ const time_t * pivot)
+{
+ time_t tpiv;
+ leap_table_t * pt;
+ vint64 tt64, et64;
+
+ if (pivot == NULL) {
+ time(&tpiv);
+ pivot = &tpiv;
+ }
+
+ et64 = ntpcal_ntp_to_ntp(etime, pivot);
+ tt64 = ntpcal_ntp_to_ntp(ttime, pivot);
+ pt = leapsec_get_table(TRUE);
+
+ if ( ucmpv64(&et64, &pt->head.expire) <= 0
+ || !leapsec_raw(pt, &tt64, total, FALSE) )
+ return FALSE;
+
+ pt->lsig.etime = etime;
+ pt->lsig.ttime = ttime;
+ pt->lsig.taiof = (int16_t)total;
+
+ pt->head.expire = et64;
+
+ return leapsec_set_table(pt);
+}
+#endif
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_add_dyn(
+ int insert,
+ uint32_t ntpnow,
+ const time_t * pivot )
+{
+ leap_table_t * pt;
+ vint64 now64;
+
+ pt = leapsec_get_table(TRUE);
+ now64 = ntpcal_ntp_to_ntp(ntpnow, pivot);
+ return ( leapsec_add(pt, &now64, (insert != 0))
+ && leapsec_set_table(pt));
+}
+
+/* ------------------------------------------------------------------ */
+int/*BOOL*/
+leapsec_autokey_tai(
+ int tai_offset,
+ uint32_t ntpnow ,
+ const time_t * pivot )
+{
+ leap_table_t * pt;
+ leap_era_t era;
+ vint64 now64;
+ int idx;
+
+ (void)tai_offset;
+ pt = leapsec_get_table(FALSE);
+
+ /* Bail out if the basic offset is not zero and the putative
+ * offset is bigger than 10s. That was in 1972 -- we don't want
+ * to go back that far!
+ */
+ if (pt->head.base_tai != 0 || tai_offset < 10)
+ return FALSE;
+
+ /* If there's already data in the table, check if an update is
+ * possible. Update is impossible if there are static entries
+ * (since this indicates a valid leapsecond file) or if we're
+ * too close to a leapsecond transition: We do not know on what
+ * side the transition the sender might have been, so we use a
+ * dead zone around the transition.
+ */
+
+ /* Check for static entries */
+ for (idx = 0; idx != pt->head.size; idx++)
+ if ( ! pt->info[idx].dynls)
+ return FALSE;
+
+ /* get the fulll time stamp and leap era for it */
+ now64 = ntpcal_ntp_to_ntp(ntpnow, pivot);
+ fetch_leap_era(&era, pt, &now64);
+
+ /* check the limits with 20s dead band */
+ era.ebase = addv64i32(&era.ebase, 20);
+ if (ucmpv64(&now64, &era.ebase) < 0)
+ return FALSE;
+
+ era.ttime = addv64i32(&era.ttime, -20);
+ if (ucmpv64(&now64, &era.ttime) > 0)
+ return FALSE;
+
+ /* Here we can proceed. Calculate the delta update. */
+ tai_offset -= era.taiof;
+
+ /* Shift the header info offsets. */
+ pt->head.base_tai += tai_offset;
+ pt->head.this_tai += tai_offset;
+ pt->head.next_tai += tai_offset;
+
+ /* Shift table entry offsets (if any) */
+ for (idx = 0; idx != pt->head.size; idx++)
+ pt->info[idx].taiof += tai_offset;
+
+ /* claim success... */
+ return TRUE;
+}
+
+
+/* =====================================================================
+ * internal helpers
+ */
+
+/* [internal] Reset / init the time window in the leap processor to
+ * force reload on next query. Since a leap transition cannot take place
+ * at an odd second, the value chosen avoids spurious leap transition
+ * triggers. Making all three times equal forces a reload. Using the
+ * maximum value for unsigned 64 bits makes finding the next leap frame
+ * a bit easier.
+ */
+static void
+reset_times(
+ leap_table_t * pt)
+{
+ memset(&pt->head.ebase, 0xFF, sizeof(vint64));
+ pt->head.stime = pt->head.ebase;
+ pt->head.ttime = pt->head.ebase;
+ pt->head.dtime = pt->head.ebase;
+}
+
+/* [internal] Add raw data to the table, removing old entries on the
+ * fly. This cannot fail currently.
+ */
+static int/*BOOL*/
+add_range(
+ leap_table_t * pt,
+ const leap_info_t * pi)
+{
+ /* If the table is full, make room by throwing out the oldest
+ * entry. But remember the accumulated leap seconds! Likewise,
+ * assume a positive leap insertion if this is the first entry
+ * in the table. This is not necessarily the best of all ideas,
+ * but it helps a great deal if a system does not have a leap
+ * table and gets updated from an upstream server.
+ */
+ if (pt->head.size == 0) {
+ pt->head.base_tai = pi->taiof - 1;
+ } else if (pt->head.size >= MAX_HIST) {
+ pt->head.size = MAX_HIST - 1;
+ pt->head.base_tai = pt->info[pt->head.size].taiof;
+ }
+
+ /* make room in lower end and insert item */
+ memmove(pt->info+1, pt->info, pt->head.size*sizeof(*pt->info));
+ pt->info[0] = *pi;
+ pt->head.size++;
+
+ /* invalidate the cached limit data -- we might have news ;-)
+ *
+ * This blocks a spurious transition detection. OTOH, if you add
+ * a value after the last query before a leap transition was
+ * expected to occur, this transition trigger is lost. But we
+ * can probably live with that.
+ */
+ reset_times(pt);
+ return TRUE;
+}
+
+/* [internal] given a reader function, read characters into a buffer
+ * until either EOL or EOF is reached. Makes sure that the buffer is
+ * always NUL terminated, but silently truncates excessive data. The
+ * EOL-marker ('\n') is *not* stored in the buffer.
+ *
+ * Returns the pointer to the buffer, unless EOF was reached when trying
+ * to read the first character of a line.
+ */
+static char *
+get_line(
+ leapsec_reader func,
+ void * farg,
+ char * buff,
+ size_t size)
+{
+ int ch;
+ char *ptr;
+
+ /* if we cannot even store the delimiter, declare failure */
+ if (buff == NULL || size == 0)
+ return NULL;
+
+ ptr = buff;
+ while (EOF != (ch = (*func)(farg)) && '\n' != ch)
+ if (size > 1) {
+ size--;
+ *ptr++ = (char)ch;
+ }
+ /* discard trailing whitespace */
+ while (ptr != buff && isspace((u_char)ptr[-1]))
+ ptr--;
+ *ptr = '\0';
+ return (ptr == buff && ch == EOF) ? NULL : buff;
+}
+
+/* [internal] skips whitespace characters from a character buffer. */
+static char *
+skipws(
+ const char *ptr)
+{
+ while (isspace((u_char)*ptr))
+ ptr++;
+ return (char*)noconst(ptr);
+}
+
+/* [internal] check if a strtoXYZ ended at EOL or whitespace and
+ * converted something at all. Return TRUE if something went wrong.
+ */
+static int/*BOOL*/
+parsefail(
+ const char * cp,
+ const char * ep)
+{
+ return (cp == ep)
+ || (*ep && *ep != '#' && !isspace((u_char)*ep));
+}
+
+/* [internal] reload the table limits around the given time stamp. This
+ * is where the real work is done when it comes to table lookup and
+ * evaluation. Some care has been taken to have correct code for dealing
+ * with boundary conditions and empty tables.
+ *
+ * In electric mode, transition and trip time are the same. In dumb
+ * mode, the difference of the TAI offsets must be taken into account
+ * and trip time and transition time become different. The difference
+ * becomes the warping distance when the trip time is reached.
+ */
+static void
+reload_limits(
+ leap_table_t * pt,
+ const vint64 * ts)
+{
+ int idx;
+
+ /* Get full time and search the true lower bound. Use a
+ * simple loop here, since the number of entries does
+ * not warrant a binary search. This also works for an empty
+ * table, so there is no shortcut for that case.
+ */
+ for (idx = 0; idx != pt->head.size; idx++)
+ if (ucmpv64(ts, &pt->info[idx].ttime) >= 0)
+ break;
+
+ /* get time limits with proper bound conditions. Note that the
+ * bounds of the table will be observed even if the table is
+ * empty -- no undefined condition must arise from this code.
+ */
+ if (idx >= pt->head.size) {
+ memset(&pt->head.ebase, 0x00, sizeof(vint64));
+ pt->head.this_tai = pt->head.base_tai;
+ } else {
+ pt->head.ebase = pt->info[idx].ttime;
+ pt->head.this_tai = pt->info[idx].taiof;
+ }
+ if (--idx >= 0) {
+ pt->head.next_tai = pt->info[idx].taiof;
+ pt->head.dynls = pt->info[idx].dynls;
+ pt->head.ttime = pt->info[idx].ttime;
+
+ if (_electric)
+ pt->head.dtime = pt->head.ttime;
+ else
+ pt->head.dtime = addv64i32(
+ &pt->head.ttime,
+ pt->head.next_tai - pt->head.this_tai);
+
+ pt->head.stime = subv64u32(
+ &pt->head.ttime, pt->info[idx].stime);
+
+ } else {
+ memset(&pt->head.ttime, 0xFF, sizeof(vint64));
+ pt->head.stime = pt->head.ttime;
+ pt->head.dtime = pt->head.ttime;
+ pt->head.next_tai = pt->head.this_tai;
+ pt->head.dynls = 0;
+ }
+}
+
+/* [internal] fetch the leap era for a given time stamp.
+ * This is a cut-down version the algorithm used to reload the table
+ * limits, but it does not update any global state and provides just the
+ * era information for a given time stamp.
+ */
+static void
+fetch_leap_era(
+ leap_era_t * into,
+ const leap_table_t * pt ,
+ const vint64 * ts )
+{
+ int idx;
+
+ /* Simple search loop, also works with empty table. */
+ for (idx = 0; idx != pt->head.size; idx++)
+ if (ucmpv64(ts, &pt->info[idx].ttime) >= 0)
+ break;
+ /* fetch era data, keeping an eye on boundary conditions */
+ if (idx >= pt->head.size) {
+ memset(&into->ebase, 0x00, sizeof(vint64));
+ into->taiof = pt->head.base_tai;
+ } else {
+ into->ebase = pt->info[idx].ttime;
+ into->taiof = pt->info[idx].taiof;
+ }
+ if (--idx >= 0)
+ into->ttime = pt->info[idx].ttime;
+ else
+ memset(&into->ttime, 0xFF, sizeof(vint64));
+}
+
+/* [internal] Take a time stamp and create a leap second frame for
+ * it. This will schedule a leap second for the beginning of the next
+ * month, midnight UTC. The 'insert' argument tells if a leap second is
+ * added (!=0) or removed (==0). We do not handle multiple inserts
+ * (yet?)
+ *
+ * Returns 1 if the insert worked, 0 otherwise. (It's not possible to
+ * insert a leap second into the current history -- only appending
+ * towards the future is allowed!)
+ */
+static int/*BOOL*/
+leapsec_add(
+ leap_table_t* pt ,
+ const vint64 * now64 ,
+ int insert)
+{
+ vint64 ttime, starttime;
+ struct calendar fts;
+ leap_info_t li;
+
+ /* Check against the table expiration and the latest available
+ * leap entry. Do not permit inserts, only appends, and only if
+ * the extend the table beyond the expiration!
+ */
+ if ( ucmpv64(now64, &pt->head.expire) < 0
+ || (pt->head.size && ucmpv64(now64, &pt->info[0].ttime) <= 0)) {
+ errno = ERANGE;
+ return FALSE;
+ }
+
+ ntpcal_ntp64_to_date(&fts, now64);
+ /* To guard against dangling leap flags: do not accept leap
+ * second request on the 1st hour of the 1st day of the month.
+ */
+ if (fts.monthday == 1 && fts.hour == 0) {
+ errno = EINVAL;
+ return FALSE;
+ }
+
+ /* Ok, do the remaining calculations */
+ fts.monthday = 1;
+ fts.hour = 0;
+ fts.minute = 0;
+ fts.second = 0;
+ starttime = ntpcal_date_to_ntp64(&fts);
+ fts.month++;
+ ttime = ntpcal_date_to_ntp64(&fts);
+
+ li.ttime = ttime;
+ li.stime = ttime.D_s.lo - starttime.D_s.lo;
+ li.taiof = (pt->head.size ? pt->info[0].taiof : pt->head.base_tai)
+ + (insert ? 1 : -1);
+ li.dynls = 1;
+ return add_range(pt, &li);
+}
+
+/* [internal] Given a time stamp for a leap insertion (the exact begin
+ * of the new leap era), create new leap frame and put it into the
+ * table. This is the work horse for reading a leap file and getting a
+ * leap second update via authenticated network packet.
+ */
+int/*BOOL*/
+leapsec_raw(
+ leap_table_t * pt,
+ const vint64 * ttime,
+ int taiof,
+ int dynls)
+{
+ vint64 starttime;
+ struct calendar fts;
+ leap_info_t li;
+
+ /* Check that we either extend the table or get a duplicate of
+ * the latest entry. The latter is a benevolent overwrite with
+ * identical data and could happen if we get an autokey message
+ * that extends the lifetime of the current leapsecond table.
+ * Otherwise paranoia rulez!
+ */
+ if (pt->head.size) {
+ int cmp = ucmpv64(ttime, &pt->info[0].ttime);
+ if (cmp == 0)
+ cmp -= (taiof != pt->info[0].taiof);
+ if (cmp < 0) {
+ errno = ERANGE;
+ return FALSE;
+ }
+ if (cmp == 0)
+ return TRUE;
+ }
+
+ ntpcal_ntp64_to_date(&fts, ttime);
+ /* If this does not match the exact month start, bail out. */
+ if (fts.monthday != 1 || fts.hour || fts.minute || fts.second) {
+ errno = EINVAL;
+ return FALSE;
+ }
+ fts.month--; /* was in range 1..12, no overflow here! */
+ starttime = ntpcal_date_to_ntp64(&fts);
+ li.ttime = *ttime;
+ li.stime = ttime->D_s.lo - starttime.D_s.lo;
+ li.taiof = (int16_t)taiof;
+ li.dynls = (dynls != 0);
+ return add_range(pt, &li);
+}
+
+/* [internal] Do a wrap-around save range inclusion check.
+ * Returns TRUE if x in [lo,hi[ (intervall open on right side) with full
+ * handling of an overflow / wrap-around.
+ */
+static int/*BOOL*/
+betweenu32(
+ uint32_t lo,
+ uint32_t x,
+ uint32_t hi)
+{
+ int rc;
+
+ if (lo <= hi)
+ rc = (lo <= x) && (x < hi);
+ else
+ rc = (lo <= x) || (x < hi);
+ return rc;
+}
+
+/* =====================================================================
+ * validation stuff
+ */
+
+typedef struct {
+ unsigned char hv[ISC_SHA1_DIGESTLENGTH];
+} sha1_digest;
+
+/* [internal] parse a digest line to get the hash signature
+ * The NIST code creating the hash writes them out as 5 hex integers
+ * without leading zeros. This makes reading them back as hex-encoded
+ * BLOB impossible, because there might be less than 40 hex digits.
+ *
+ * The solution is to read the values back as integers, and then do the
+ * byte twiddle necessary to get it into an array of 20 chars. The
+ * drawback is that it permits any acceptable number syntax provided by
+ * 'scanf()' and 'strtoul()', including optional signs and '0x'
+ * prefixes.
+ */
+static int/*BOOL*/
+do_leap_hash(
+ sha1_digest * mac,
+ char const * cp )
+{
+ int wi, di, num, len;
+ unsigned long tmp[5];
+
+ memset(mac, 0, sizeof(*mac));
+ num = sscanf(cp, " %lx %lx %lx %lx %lx%n",
+ &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4],
+ &len);
+ if (num != 5 || cp[len] > ' ')
+ return FALSE;
+
+ /* now do the byte twiddle */
+ for (wi=0; wi < 5; ++wi)
+ for (di=3; di >= 0; --di) {
+ mac->hv[wi*4 + di] =
+ (unsigned char)(tmp[wi] & 0x0FF);
+ tmp[wi] >>= 8;
+ }
+ return TRUE;
+}
+
+/* [internal] add the digits of a data line to the hash, stopping at the
+ * next hash ('#') character.
+ */
+static void
+do_hash_data(
+ isc_sha1_t * mdctx,
+ char const * cp )
+{
+ unsigned char text[32]; // must be power of two!
+ unsigned int tlen = 0;
+ unsigned char ch;
+
+ while ('\0' != (ch = *cp++) && '#' != ch)
+ if (isdigit(ch)) {
+ text[tlen++] = ch;
+ tlen &= (sizeof(text)-1);
+ if (0 == tlen)
+ isc_sha1_update(
+ mdctx, text, sizeof(text));
+ }
+
+ if (0 < tlen)
+ isc_sha1_update(mdctx, text, tlen);
+}
+
+/* given a reader and a reader arg, calculate and validate the the hash
+ * signature of a NIST leap second file.
+ */
+int
+leapsec_validate(
+ leapsec_reader func,
+ void * farg)
+{
+ isc_sha1_t mdctx;
+ sha1_digest rdig, ldig; /* remote / local digests */
+ char line[50];
+ int hlseen = -1;
+
+ isc_sha1_init(&mdctx);
+ while (get_line(func, farg, line, sizeof(line))) {
+ if (!strncmp(line, "#h", 2))
+ hlseen = do_leap_hash(&rdig, line+2);
+ else if (!strncmp(line, "#@", 2))
+ do_hash_data(&mdctx, line+2);
+ else if (!strncmp(line, "#$", 2))
+ do_hash_data(&mdctx, line+2);
+ else if (isdigit((unsigned char)line[0]))
+ do_hash_data(&mdctx, line);
+ }
+ isc_sha1_final(&mdctx, ldig.hv);
+ isc_sha1_invalidate(&mdctx);
+
+ if (0 > hlseen)
+ return LSVALID_NOHASH;
+ if (0 == hlseen)
+ return LSVALID_BADFORMAT;
+ if (0 != memcmp(&rdig, &ldig, sizeof(sha1_digest)))
+ return LSVALID_BADHASH;
+ return LSVALID_GOODHASH;
+}
+
+/*
+ * lstostr - prettyprint NTP seconds
+ */
+static const char *
+lstostr(
+ const vint64 * ts)
+{
+ char * buf;
+ struct calendar tm;
+
+ LIB_GETBUF(buf);
+
+ if ( ! (ts->d_s.hi >= 0 && ntpcal_ntp64_to_date(&tm, ts) >= 0))
+ snprintf(buf, LIB_BUFLENGTH, "%s", "9999-12-31T23:59:59Z");
+ else
+ snprintf(buf, LIB_BUFLENGTH, "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ tm.year, tm.month, tm.monthday,
+ tm.hour, tm.minute, tm.second);
+
+ return buf;
+}
+
+/* reset the global state for unit tests */
+void
+leapsec_ut_pristine(void)
+{
+ memset(_ltab, 0, sizeof(_ltab));
+ _lptr = NULL;
+ _electric = 0;
+}
+
+
+
+/* -*- that's all folks! -*- */
diff --git a/contrib/ntp/ntpd/ntp_leapsec.h b/contrib/ntp/ntpd/ntp_leapsec.h
new file mode 100644
index 0000000..120b75f
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_leapsec.h
@@ -0,0 +1,276 @@
+/*
+ * ntp_leapsec.h - leap second processing for NTPD
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ * ----------------------------------------------------------------------
+ * This is an attempt to get the leap second handling into a dedicated
+ * module to make the somewhat convoluted logic testable.
+ */
+
+#ifndef NTP_LEAPSEC_H
+#define NTP_LEAPSEC_H
+
+struct stat;
+
+
+/* function pointer types. Note that 'fprintf' and 'getc' can be casted
+ * to the dumper resp. reader type, provided the auxiliary argument is a
+ * valid FILE pointer in hat case.
+ */
+typedef void (*leapsec_dumper)(void*, const char *fmt, ...);
+typedef int (*leapsec_reader)(void*);
+
+struct leap_table;
+typedef struct leap_table leap_table_t;
+
+/* Validate a stream containing a leap second file in the NIST / NTPD
+ * format that can also be loaded via 'leapsec_load()'. This uses
+ * the SHA1 hash and preprocessing as described in the NIST leapsecond
+ * file.
+ */
+#define LSVALID_GOODHASH 1 /* valid signature */
+#define LSVALID_NOHASH 0 /* no signature in file */
+#define LSVALID_BADHASH -1 /* signature mismatch */
+#define LSVALID_BADFORMAT -2 /* signature not parseable */
+
+extern int leapsec_validate(leapsec_reader, void*);
+
+
+/* Set/get electric mode
+ * Electric mode is defined as the operation mode where the system clock
+ * automagically manages the leap second, so we don't have to care about
+ * stepping the clock. (This should be the case with most systems,
+ * including the current implementation of the Win32 timekeeping.)
+ *
+ * The consequence of electric mode is that we do not 'see' the leap
+ * second, and no client actions are needed when crossing the leap era
+ * boundary. In manual (aka non-electric) mode the clock will simply
+ * step forward untill *we* (that is, this module) tells the client app
+ * to step at the right time. This needs a slightly different type of
+ * processing, so switching between those two modes should not be done
+ * too close to a leap second. The transition might be lost in that
+ * case. (The limit is actual 2 sec before transition.)
+ *
+ * OTOH, this is a system characteristic, so it's expected to be set
+ * properly somewhere after system start and retain the value.
+ *
+ * Simply querying the state or setting it to the same value as before
+ * does not have any unwanted side effects. You can query by giving a
+ * negative value for the switch.
+ */
+extern int/*BOOL*/ leapsec_electric(int/*BOOL*/ on);
+
+/* Query result for a leap era. This is the minimal stateless
+ * information available for a time stamp in UTC.
+ */
+struct leap_era {
+ vint64 ebase; /* era base (UTC of start) */
+ vint64 ttime; /* era end (UTC of next leap second) */
+ int16_t taiof; /* offset to TAI in this era */
+};
+typedef struct leap_era leap_era_t;
+
+/* Query result for a leap second schedule
+ * 'ebase' is the nominal UTC time when the current leap era
+ * started. (Era base time)
+ * 'ttime' is the next transition point in full time scale. (Nominal UTC
+ * time when the next leap era starts.)
+ * 'ddist' is the distance to the transition, in clock seconds.
+ * This is the distance to the due time, which is different
+ * from the transition time if the mode is non-electric.
+ * Only valid if 'tai_diff' is not zero.
+ * 'tai_offs' is the CURRENT distance from clock (UTC) to TAI. Always
+ * valid.
+ * 'tai_diff' is the change in TAI offset after the next leap
+ * transition. Zero if nothing is pending or too far ahead.
+ * 'warped' is set only once, when the the leap second occurred between
+ * two queries. Always zero in electric mode. If non-zero,
+ * immediately step the clock.
+ * 'proximity' is a proximity warning. See definitions below. This is
+ * more useful than an absolute difference to the leap second.
+ * 'dynamic' != 0 if entry was requested by clock/peer
+ */
+struct leap_result {
+ vint64 ebase;
+ vint64 ttime;
+ uint32_t ddist;
+ int16_t tai_offs;
+ int16_t tai_diff;
+ int16_t warped;
+ uint8_t proximity;
+ uint8_t dynamic;
+};
+typedef struct leap_result leap_result_t;
+
+/* The leap signature is used in two distinct circumstances, and it has
+ * slightly different content in these cases:
+ * - it is used to indictae the time range covered by the leap second
+ * table, and then it contains the last transition, TAI offset after
+ * the final transition, and the expiration time.
+ * - it is used to query data for AUTOKEY updates, and then it contains
+ * the *current* TAI offset, the *next* transition time and the
+ * expiration time of the table.
+ */
+struct leap_signature {
+ uint32_t etime; /* expiration time */
+ uint32_t ttime; /* transition time */
+ int16_t taiof; /* total offset to TAI */
+};
+typedef struct leap_signature leap_signature_t;
+
+
+#ifdef LEAP_SMEAR
+
+struct leap_smear_info {
+ int enabled; /* not 0 if smearing is generally enabled */
+ int in_progress; /* not 0 if smearing is in progress, i.e. the offset has been computed */
+ int leap_occurred; /* not 0 if the leap second has already occurred, i.e., during the leap second */
+ double doffset; /* the current smear offset as double */
+ l_fp offset; /* the current smear offset */
+ uint32_t t_offset; /* the current time for which a smear offset has been computed */
+ long interval; /* smear interval, in [s], should be at least some hours */
+ double intv_start; /* start time of the smear interval */
+ double intv_end; /* end time of the smear interval */
+};
+typedef struct leap_smear_info leap_smear_info_t;
+
+#endif /* LEAP_SMEAR */
+
+
+#define LSPROX_NOWARN 0 /* clear radar screen */
+#define LSPROX_SCHEDULE 1 /* less than 1 month to target*/
+#define LSPROX_ANNOUNCE 2 /* less than 1 day to target */
+#define LSPROX_ALERT 3 /* less than 10 sec to target */
+
+/* Get the current or alternate table pointer. Getting the alternate
+ * pointer will automatically copy the primary table, so it can be
+ * subsequently modified.
+ */
+extern leap_table_t *leapsec_get_table(int alternate);
+
+/* Set the current leap table. Accepts only return values from
+ * 'leapsec_get_table()', so it's hard to do something wrong. Returns
+ * TRUE if the current table is the requested one.
+ */
+extern int/*BOOL*/ leapsec_set_table(leap_table_t *);
+
+/* Clear all leap second data. Use it for init & cleanup */
+extern void leapsec_clear(leap_table_t*);
+
+/* Load a leap second file. If 'blimit' is set, do not store (but
+ * register with their TAI offset) leap entries before the build date.
+ * Update the leap signature data on the fly.
+ */
+extern int/*BOOL*/ leapsec_load(leap_table_t*, leapsec_reader,
+ void*, int blimit);
+
+/* Dump the current leap table in readable format, using the provided
+ * dump formatter function.
+ */
+extern void leapsec_dump(const leap_table_t*, leapsec_dumper func, void *farg);
+
+/* Read a leap second file from stream. This is a convenience wrapper
+ * around the generic load function, 'leapsec_load()'.
+ */
+extern int/*BOOL*/ leapsec_load_stream(FILE * fp, const char * fname,
+ int/*BOOL*/logall);
+
+/* Read a leap second file from file. It checks that the file exists and
+ * (if 'force' is not applied) the ctime/mtime has changed since the
+ * last load. If the file has to be loaded, either due to 'force' or
+ * changed time stamps, the 'stat()' results of the file are stored in
+ * '*sb' for the next cycle. Returns TRUE on successful load, FALSE
+ * otherwise. Uses 'leapsec_load_stream()' internally.
+ */
+extern int/*BOOL*/ leapsec_load_file(const char * fname, struct stat * sb,
+ int/*BOOL*/force, int/*BOOL*/logall);
+
+/* Get the current leap data signature. This consists of the last
+ * ransition, the table expiration, and the total TAI difference at the
+ * last transition. This is valid even if the leap transition itself was
+ * culled due to the build date limit.
+ */
+extern void leapsec_getsig(leap_signature_t * psig);
+
+/* Check if the leap table is expired at the given time.
+ */
+extern int/*BOOL*/ leapsec_expired(uint32_t when, const time_t * pivot);
+
+/* Get the distance to expiration in days.
+ * Returns negative values if expired, zero if there are less than 24hrs
+ * left, and positive numbers otherwise.
+ */
+extern int32_t leapsec_daystolive(uint32_t when, const time_t * pivot);
+
+/* Reset the current leap frame, so the next query will do proper table
+ * lookup from fresh. Suppresses a possible leap era transition detection
+ * for the next query.
+ */
+extern void leapsec_reset_frame(void);
+
+#if 0 /* currently unused -- possibly revived later */
+/* Given a transition time, the TAI offset valid after that and an
+ * expiration time, try to establish a system leap transition. Only
+ * works if the existing table is extended. On success, updates the
+ * signature data.
+ */
+extern int/*BOOL*/ leapsec_add_fix(int offset, uint32_t ttime, uint32_t etime,
+ const time_t * pivot);
+#endif
+
+/* Take a time stamp and create a leap second frame for it. This will
+ * schedule a leap second for the beginning of the next month, midnight
+ * UTC. The 'insert' argument tells if a leap second is added (!=0) or
+ * removed (==0). We do not handle multiple inserts (yet?)
+ *
+ * Returns 1 if the insert worked, 0 otherwise. (It's not possible to
+ * insert a leap second into the current history -- only appending
+ * towards the future is allowed!)
+ *
+ * 'ntp_now' is subject to era unfolding. The entry is marked
+ * dynamic. The leap signature is NOT updated.
+ */
+extern int/*BOOL*/ leapsec_add_dyn(int/*BOOL*/ insert, uint32_t ntp_now,
+ const time_t * pivot);
+
+/* Take a time stamp and get the associated leap information. The time
+ * stamp is subject to era unfolding around the pivot or the current
+ * system time if pivot is NULL. Sets the information in '*qr' and
+ * returns TRUE if a leap second era boundary was crossed between the
+ * last and the current query. In that case, qr->warped contains the
+ * required clock stepping, which is always zero in electric mode.
+ */
+extern int/*BOOL*/ leapsec_query(leap_result_t * qr, uint32_t ntpts,
+ const time_t * pivot);
+
+/* For a given time stamp, fetch the data for the bracketing leap
+ * era. The time stamp is subject to NTP era unfolding.
+ */
+extern int/*BOOL*/ leapsec_query_era(leap_era_t * qr, uint32_t ntpts,
+ const time_t * pivot);
+
+/* Get the current leap frame info. Returns TRUE if the result contains
+ * useable data, FALSE if there is currently no leap second frame.
+ * This merely replicates some results from a previous query, but since
+ * it does not check the current time, only the following entries are
+ * meaningful:
+ * qr->ttime;
+ * qr->tai_offs;
+ * qr->tai_diff;
+ * qr->dynamic;
+ */
+extern int/*BOOL*/ leapsec_frame(leap_result_t *qr);
+
+
+/* Process a AUTOKEY TAI offset information. This *might* augment the
+ * current leap data table with the given TAI offset.
+ * Returns TRUE if action was taken, FALSE otherwise.
+ */
+extern int/*BOOL*/ leapsec_autokey_tai(int tai_offset, uint32_t ntpnow,
+ const time_t * pivot);
+
+/* reset global state for unit tests */
+extern void leapsec_ut_pristine(void);
+
+#endif /* !defined(NTP_LEAPSEC_H) */
diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c
index 600f683..cb183b9 100644
--- a/contrib/ntp/ntpd/ntp_loopfilter.c
+++ b/contrib/ntp/ntpd/ntp_loopfilter.c
@@ -8,21 +8,21 @@
# include <config.h>
#endif
+#ifdef USE_SNPRINTB
+# include <util.h>
+#endif
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
+#include <limits.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
-#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/
-#include "ntp_refclock.h"
-#endif /* VMS */
-
#ifdef KERNEL_PLL
#include "ntp_syscall.h"
#endif /* KERNEL_PLL */
@@ -35,18 +35,19 @@
* All units are in s and s/s, unless noted otherwise.
*/
#define CLOCK_MAX .128 /* default step threshold (s) */
-#define CLOCK_MINSTEP 900. /* default stepout threshold (s) */
+#define CLOCK_MINSTEP 300. /* default stepout threshold (s) */
#define CLOCK_PANIC 1000. /* default panic threshold (s) */
#define CLOCK_PHI 15e-6 /* max frequency error (s/s) */
#define CLOCK_PLL 16. /* PLL loop gain (log2) */
#define CLOCK_AVG 8. /* parameter averaging constant */
-#define CLOCK_FLL (NTP_MAXPOLL + CLOCK_AVG) /* FLL loop gain */
-#define CLOCK_ALLAN 1500. /* compromise Allan intercept (s) */
-#define CLOCK_DAY 86400. /* one day in seconds (s) */
-#define CLOCK_JUNE (CLOCK_DAY * 30) /* June in seconds (s) */
+#define CLOCK_FLL .25 /* FLL loop gain */
+#define CLOCK_FLOOR .0005 /* startup offset floor (s) */
+#define CLOCK_ALLAN 11 /* Allan intercept (log2 s) */
#define CLOCK_LIMIT 30 /* poll-adjust threshold */
#define CLOCK_PGATE 4. /* poll-adjust gate */
#define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */
+#define FREQTOD(x) ((x) / 65536e6) /* NTP to double */
+#define DTOFREQ(x) ((int32)((x) * 65536e6)) /* double to NTP */
/*
* Clock discipline state machine. This is used to control the
@@ -54,32 +55,25 @@
* timewarp.
*
* State < step > step Comments
- * ====================================================
- * NSET FREQ step, FREQ no ntp.drift
+ * ========================================================
+ * NSET FREQ step, FREQ freq not set
*
- * FSET SYNC step, SYNC ntp.drift
+ * FSET SYNC step, SYNC freq set
*
- * FREQ if (mu < 900) if (mu < 900) set freq
+ * FREQ if (mu < 900) if (mu < 900) set freq direct
* ignore ignore
* else else
* freq, SYNC freq, step, SYNC
*
- * SYNC SYNC if (mu < 900) adjust phase/freq
- * ignore
- * else
- * SPIK
+ * SYNC SYNC SPIK, ignore adjust phase/freq
*
- * SPIK SYNC step, SYNC set phase
+ * SPIK SYNC if (mu < 900) adjust phase/freq
+ * ignore
+ * step, SYNC
*/
-#define S_NSET 0 /* clock never set */
-#define S_FSET 1 /* frequency set from the drift file */
-#define S_SPIK 2 /* spike detected */
-#define S_FREQ 3 /* frequency mode */
-#define S_SYNC 4 /* clock synchronized */
-
/*
* Kernel PLL/PPS state machine. This is used with the kernel PLL
- * modifications described in the README.kernel file.
+ * modifications described in the documentation.
*
* If kernel support for the ntp_adjtime() system call is available, the
* ntp_control flag is set. The ntp_enable and kern_enable flags can be
@@ -97,65 +91,80 @@
* includes TAI offset and is identified by the symbol NTP_API with
* value 4.
*
- * Each update to a prefer peer sets pps_stratum 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_stratum 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.
+ * Each PPS time/frequency discipline can be enabled by the atom driver
+ * or another driver. If enabled, the STA_PPSTIME and STA_FREQ bits are
+ * set in the kernel status word; otherwise, these bits are cleared.
+ * These bits are also cleard if the kernel reports an error.
*
* If an external clock is present, the clock driver sets STA_CLK in the
* status word. When the local clock driver sees this bit, it updates
* via this routine, which then calls ntp_adjtime() with the STA_PLL bit
* set to zero, in which case the system clock is not adjusted. This is
* also a signal for the external clock driver to discipline the system
- * clock.
+ * clock. Unless specified otherwise, all times are in seconds.
*/
/*
* Program variables that can be tinkered.
*/
-double clock_max = CLOCK_MAX; /* step threshold (s) */
-double clock_minstep = CLOCK_MINSTEP; /* stepout threshold (s) */
-double clock_panic = CLOCK_PANIC; /* panic threshold (s) */
+double clock_max_back = CLOCK_MAX; /* step threshold */
+double clock_max_fwd = CLOCK_MAX; /* step threshold */
+double clock_minstep = CLOCK_MINSTEP; /* stepout threshold */
+double clock_panic = CLOCK_PANIC; /* panic threshold */
double clock_phi = CLOCK_PHI; /* dispersion rate (s/s) */
-double allan_xpt = CLOCK_ALLAN; /* Allan intercept (s) */
+u_char allan_xpt = CLOCK_ALLAN; /* Allan intercept (log2 s) */
/*
* Program variables
*/
-static double clock_offset; /* offset (s) */
-double clock_jitter; /* offset jitter (s) */
+static double clock_offset; /* offset */
+double clock_jitter; /* offset jitter */
double drift_comp; /* frequency (s/s) */
+static double init_drift_comp; /* initial frequency (PPM) */
double clock_stability; /* frequency stability (wander) (s/s) */
-u_long sys_clocktime; /* last system clock update */
-u_long pps_control; /* last pps update */
-u_long sys_tai; /* UTC offset from TAI (s) */
-static void rstclock P((int, u_long, double)); /* transition function */
+double clock_codec; /* audio codec frequency (samples/s) */
+static u_long clock_epoch; /* last update */
+u_int sys_tai; /* TAI offset from UTC */
+static int loop_started; /* TRUE after LOOP_DRIFTINIT */
+static void rstclock (int, double); /* transition function */
+static double direct_freq(double); /* direct set frequency */
+static void set_freq(double); /* set frequency */
+#ifndef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif
+static char relative_path[PATH_MAX + 1]; /* relative path per recursive make */
+static char *this_file = NULL;
#ifdef KERNEL_PLL
-struct timex ntv; /* kernel API parameters */
-int pll_status; /* status bits for kernel pll */
+static struct timex ntv; /* ntp_adjtime() parameters */
+int pll_status; /* last kernel status bits */
+#if defined(STA_NANO) && NTP_API == 4
+static u_int loop_tai; /* last TAI offset */
+#endif /* STA_NANO */
+static void start_kern_loop(void);
+static void stop_kern_loop(void);
#endif /* KERNEL_PLL */
/*
* Clock state machine control flags
*/
-int ntp_enable; /* clock discipline enabled */
+int ntp_enable = TRUE; /* clock discipline enabled */
int pll_control; /* kernel support available */
-int kern_enable; /* kernel support enabled */
-int pps_enable; /* kernel PPS discipline enabled */
+int kern_enable = TRUE; /* kernel support enabled */
+int hardpps_enable; /* kernel PPS discipline enabled */
int ext_enable; /* external clock enabled */
int pps_stratum; /* pps stratum */
-int allow_panic = FALSE; /* allow panic correction */
-int mode_ntpdate = FALSE; /* exit on first clock set */
+int kernel_status; /* from ntp_adjtime */
+int allow_panic = FALSE; /* allow panic correction (-g) */
+int force_step_once = FALSE; /* always step time once at startup (-G) */
+int mode_ntpdate = FALSE; /* exit on first clock set (-q) */
+int freq_cnt; /* initial frequency clamp */
+int freq_set; /* initial set frequency switch */
/*
* Clock state machine variables
*/
-int state; /* clock discipline state */
-u_char sys_poll = NTP_MINDPOLL; /* time constant/poll (log2 s) */
+int state = 0; /* clock discipline state */
+u_char sys_poll; /* time constant/poll (log2 s) */
int tc_counter; /* jiggle counter */
double last_offset; /* last offset (s) */
@@ -172,13 +181,42 @@ static double sys_mindly; /* huff-n'-puff filter min delay */
#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \
MOD_STATUS | MOD_TIMECONST)
#ifdef SIGSYS
-static void pll_trap P((int)); /* configuration trap */
+static void pll_trap (int); /* configuration trap */
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 */
+static void
+sync_status(const char *what, int ostatus, int nstatus)
+{
+ char obuf[256], nbuf[256], tbuf[1024];
+#if defined(USE_SNPRINTB) && defined (STA_FMT)
+ snprintb(obuf, sizeof(obuf), STA_FMT, ostatus);
+ snprintb(nbuf, sizeof(nbuf), STA_FMT, nstatus);
+#else
+ snprintf(obuf, sizeof(obuf), "%04x", ostatus);
+ snprintf(nbuf, sizeof(nbuf), "%04x", nstatus);
+#endif
+ snprintf(tbuf, sizeof(tbuf), "%s status: %s -> %s", what, obuf, nbuf);
+ report_event(EVNT_KERN, NULL, tbuf);
+}
+
+/*
+ * file_name - return pointer to non-relative portion of this C file pathname
+ */
+static char *file_name(void)
+{
+ if (this_file == NULL) {
+ (void)strncpy(relative_path, __FILE__, PATH_MAX);
+ for (this_file=relative_path;
+ *this_file && ! isalnum((unsigned char)*this_file);
+ this_file++) ;
+ }
+ return this_file;
+}
+
/*
* init_loopfilter - initialize loop filter data
*/
@@ -186,13 +224,214 @@ void
init_loopfilter(void)
{
/*
- * Initialize state variables. Initially, we expect no drift
- * file, so set the state to S_NSET. If a drift file is present,
- * it will be detected later and the state set to S_FSET.
+ * Initialize state variables.
*/
- rstclock(S_NSET, 0, 0);
+ sys_poll = ntp_minpoll;
clock_jitter = LOGTOD(sys_precision);
+ freq_cnt = (int)clock_minstep;
+}
+
+#ifdef KERNEL_PLL
+/*
+ * ntp_adjtime_error_handler - process errors from ntp_adjtime
+ */
+static void
+ntp_adjtime_error_handler(
+ const char *caller, /* name of calling function */
+ struct timex *ptimex, /* pointer to struct timex */
+ int ret, /* return value from ntp_adjtime */
+ int saved_errno, /* value of errno when ntp_adjtime returned */
+ int pps_call, /* ntp_adjtime call was PPS-related */
+ int tai_call, /* ntp_adjtime call was TAI-related */
+ int line /* line number of ntp_adjtime call */
+ )
+{
+ char des[1024] = ""; /* Decoded Error Status */
+
+ switch (ret) {
+ case -1:
+ switch (saved_errno) {
+ case EFAULT:
+ msyslog(LOG_ERR, "%s: %s line %d: invalid struct timex pointer: 0x%lx",
+ caller, file_name(), line,
+ (long)((void *)ptimex)
+ );
+ break;
+ case EINVAL:
+ msyslog(LOG_ERR, "%s: %s line %d: invalid struct timex \"constant\" element value: %ld",
+ caller, file_name(), line,
+ (long)(ptimex->constant)
+ );
+ break;
+ case EPERM:
+ if (tai_call) {
+ errno = saved_errno;
+ msyslog(LOG_ERR,
+ "%s: ntp_adjtime(TAI) failed: %m",
+ caller);
+ }
+ errno = saved_errno;
+ msyslog(LOG_ERR, "%s: %s line %d: ntp_adjtime: %m",
+ caller, file_name(), line
+ );
+ break;
+ default:
+ msyslog(LOG_NOTICE, "%s: %s line %d: unhandled errno value %d after failed ntp_adjtime call",
+ caller, file_name(), line,
+ saved_errno
+ );
+ break;
+ }
+ break;
+#ifdef TIME_OK
+ case TIME_OK: /* 0: synchronized, no leap second warning */
+ /* msyslog(LOG_INFO, "kernel reports time is synchronized normally"); */
+ break;
+#else
+# warning TIME_OK is not defined
+#endif
+#ifdef TIME_INS
+ case TIME_INS: /* 1: positive leap second warning */
+ msyslog(LOG_INFO, "kernel reports leap second insertion scheduled");
+ break;
+#else
+# warning TIME_INS is not defined
+#endif
+#ifdef TIME_DEL
+ case TIME_DEL: /* 2: negative leap second warning */
+ msyslog(LOG_INFO, "kernel reports leap second deletion scheduled");
+ break;
+#else
+# warning TIME_DEL is not defined
+#endif
+#ifdef TIME_OOP
+ case TIME_OOP: /* 3: leap second in progress */
+ msyslog(LOG_INFO, "kernel reports leap second in progress");
+ break;
+#else
+# warning TIME_OOP is not defined
+#endif
+#ifdef TIME_WAIT
+ case TIME_WAIT: /* 4: leap second has occured */
+ msyslog(LOG_INFO, "kernel reports leap second has occurred");
+ break;
+#else
+# warning TIME_WAIT is not defined
+#endif
+#ifdef TIME_ERROR
+#if 0
+
+from the reference implementation of ntp_gettime():
+
+ // Hardware or software error
+ if ((time_status & (STA_UNSYNC | STA_CLOCKERR))
+
+ /*
+ * PPS signal lost when either time or frequency synchronization
+ * requested
+ */
+ || (time_status & (STA_PPSFREQ | STA_PPSTIME)
+ && !(time_status & STA_PPSSIGNAL))
+
+ /*
+ * PPS jitter exceeded when time synchronization requested
+ */
+ || (time_status & STA_PPSTIME &&
+ time_status & STA_PPSJITTER)
+
+ /*
+ * PPS wander exceeded or calibration error when frequency
+ * synchronization requested
+ */
+ || (time_status & STA_PPSFREQ &&
+ time_status & (STA_PPSWANDER | STA_PPSERROR)))
+ return (TIME_ERROR);
+
+or, from ntp_adjtime():
+
+ if ( (time_status & (STA_UNSYNC | STA_CLOCKERR))
+ || (time_status & (STA_PPSFREQ | STA_PPSTIME)
+ && !(time_status & STA_PPSSIGNAL))
+ || (time_status & STA_PPSTIME
+ && time_status & STA_PPSJITTER)
+ || (time_status & STA_PPSFREQ
+ && time_status & (STA_PPSWANDER | STA_PPSERROR))
+ )
+ return (TIME_ERROR);
+#endif
+
+ case TIME_ERROR: /* 5: unsynchronized, or loss of synchronization */
+ /* error (see status word) */
+
+ if (ptimex->status & STA_UNSYNC)
+ snprintf(des, sizeof(des), "%s%sClock Unsynchronized",
+ des, (*des) ? "; " : "");
+
+ if (ptimex->status & STA_CLOCKERR)
+ snprintf(des, sizeof(des), "%s%sClock Error",
+ des, (*des) ? "; " : "");
+
+ if (!(ptimex->status & STA_PPSSIGNAL)
+ && ptimex->status & STA_PPSFREQ)
+ snprintf(des, sizeof(des), "%s%sPPS Frequency Sync wanted but no PPS",
+ des, (*des) ? "; " : "");
+
+ if (!(ptimex->status & STA_PPSSIGNAL)
+ && ptimex->status & STA_PPSTIME)
+ snprintf(des, sizeof(des), "%s%sPPS Time Sync wanted but no PPS signal",
+ des, (*des) ? "; " : "");
+
+ if ( ptimex->status & STA_PPSTIME
+ && ptimex->status & STA_PPSJITTER)
+ snprintf(des, sizeof(des), "%s%sPPS Time Sync wanted but PPS Jitter exceeded",
+ des, (*des) ? "; " : "");
+
+ if ( ptimex->status & STA_PPSFREQ
+ && ptimex->status & STA_PPSWANDER)
+ snprintf(des, sizeof(des), "%s%sPPS Frequency Sync wanted but PPS Wander exceeded",
+ des, (*des) ? "; " : "");
+
+ if ( ptimex->status & STA_PPSFREQ
+ && ptimex->status & STA_PPSERROR)
+ snprintf(des, sizeof(des), "%s%sPPS Frequency Sync wanted but Calibration error detected",
+ des, (*des) ? "; " : "");
+
+ if (pps_call && !(ptimex->status & STA_PPSSIGNAL))
+ report_event(EVNT_KERN, NULL,
+ "no PPS signal");
+ DPRINTF(1, ("kernel loop status %#x (%s)\n",
+ ptimex->status, des));
+ /*
+ * This code may be returned when ntp_adjtime() has just
+ * been called for the first time, quite a while after
+ * startup, when ntpd just starts to discipline the kernel
+ * time. In this case the occurrence of this message
+ * can be pretty confusing.
+ *
+ * HMS: How about a message when we begin kernel processing:
+ * Determining kernel clock state...
+ * so an initial TIME_ERROR message is less confising,
+ * or skipping the first message (ugh),
+ * or ???
+ * msyslog(LOG_INFO, "kernel reports time synchronization lost");
+ */
+ msyslog(LOG_INFO, "kernel reports TIME_ERROR: %#x: %s",
+ ptimex->status, des);
+ break;
+#else
+# warning TIME_ERROR is not defined
+#endif
+ default:
+ msyslog(LOG_NOTICE, "%s: %s line %d: unhandled return value %d from ntp_adjtime() in %s at line %d",
+ caller, file_name(), line,
+ ret,
+ __func__, __LINE__
+ );
+ break;
+ }
+ return;
}
+#endif
/*
* local_clock - the NTP logical clock loop filter.
@@ -204,7 +443,7 @@ init_loopfilter(void)
* 2 clock was stepped
*
* LOCKCLOCK: The only thing this routine does is set the
- * sys_rootdispersion variable equal to the peer dispersion.
+ * sys_rootdisp variable equal to the peer dispersion.
*/
int
local_clock(
@@ -213,39 +452,29 @@ local_clock(
)
{
int rval; /* return code */
- u_long mu; /* interval since last update (s) */
- double flladj; /* FLL frequency adjustment (ppm) */
- double plladj; /* PLL frequency adjustment (ppm) */
- double clock_frequency; /* clock frequency adjustment (ppm) */
+ int osys_poll; /* old system poll */
+ int ntp_adj_ret; /* returned by ntp_adjtime */
+ double mu; /* interval since last update */
+ double clock_frequency; /* clock frequency */
double dtemp, etemp; /* double temps */
-#ifdef OPENSSL
- u_int32 *tpt;
- int i;
- u_int len;
- long togo;
-#endif /* OPENSSL */
+ char tbuf[80]; /* report buffer */
/*
* If the loop is opened or the NIST LOCKCLOCK is in use,
* monitor and record the offsets anyway in order to determine
* the open-loop response and then go home.
*/
-#ifdef DEBUG
- if (debug)
- printf(
- "local_clock: assocID %d offset %.9f freq %.3f state %d\n",
- peer->associd, fp_offset, drift_comp * 1e6, state);
-#endif
#ifdef LOCKCLOCK
- return (0);
-
-#else /* LOCKCLOCK */
+ {
+#else
if (!ntp_enable) {
+#endif /* LOCKCLOCK */
record_loop_stats(fp_offset, drift_comp, clock_jitter,
clock_stability, sys_poll);
return (0);
}
+#ifndef LOCKCLOCK
/*
* If the clock is way off, panic is declared. The clock_panic
* defaults to 1000 s; if set to zero, the panic will never
@@ -257,33 +486,32 @@ local_clock(
*/
if (fabs(fp_offset) > clock_panic && clock_panic > 0 &&
!allow_panic) {
- msyslog(LOG_ERR,
- "time correction of %.0f seconds exceeds sanity limit (%.0f); set clock manually to the correct UTC time.",
+ snprintf(tbuf, sizeof(tbuf),
+ "%+.0f s; set clock manually within %.0f s.",
fp_offset, clock_panic);
+ report_event(EVNT_SYSFAULT, NULL, tbuf);
return (-1);
}
/*
- * If simulating ntpdate, set the clock directly, rather than
- * using the discipline. The clock_max defines the step
- * threshold, above which the clock will be stepped instead of
- * slewed. The value defaults to 128 ms, but can be set to even
- * unreasonable values. If set to zero, the clock will never be
- * stepped. Note that a slew will persist beyond the life of
- * this program.
- *
- * Note that if ntpdate is active, the terminal does not detach,
- * so the termination comments print directly to the console.
+ * This section simulates ntpdate. If the offset exceeds the
+ * step threshold (128 ms), step the clock to that time and
+ * exit. Otherwise, slew the clock to that time and exit. Note
+ * that the slew will persist and eventually complete beyond the
+ * life of this program. Note that while ntpdate is active, the
+ * terminal does not detach, so the termination message prints
+ * directly to the terminal.
*/
if (mode_ntpdate) {
- if (fabs(fp_offset) > clock_max && clock_max > 0) {
+ if ( ( fp_offset > clock_max_fwd && clock_max_fwd > 0)
+ || (-fp_offset > clock_max_back && clock_max_back > 0)) {
step_systime(fp_offset);
- msyslog(LOG_NOTICE, "time reset %+.6f s",
- fp_offset);
+ msyslog(LOG_NOTICE, "ntpd: time set %+.6f s",
+ fp_offset);
printf("ntpd: time set %+.6fs\n", fp_offset);
} else {
adj_systime(fp_offset);
- msyslog(LOG_NOTICE, "time slew %+.6f s",
+ msyslog(LOG_NOTICE, "ntpd: time slew %+.6f s",
fp_offset);
printf("ntpd: time slew %+.6fs\n", fp_offset);
}
@@ -299,12 +527,8 @@ local_clock(
* is most effective if the delays are highly assymetric and
* clockhopping is avoided and the clock frequency wander is
* relatively small.
- *
- * Note either there is no prefer peer or this update is from
- * the prefer peer.
*/
- if (sys_huffpuff != NULL && (sys_prefer == NULL || sys_prefer ==
- peer)) {
+ if (sys_huffpuff != NULL) {
if (peer->delay < sys_huffpuff[sys_huffptr])
sys_huffpuff[sys_huffptr] = peer->delay;
if (peer->delay < sys_mindly)
@@ -323,107 +547,115 @@ local_clock(
}
/*
- * Clock state machine transition function. This is where the
- * action is and defines how the system reacts to large phase
- * and frequency errors. There are two main regimes: when the
- * offset exceeds the step threshold and when it does not.
- * However, if the step threshold is set to zero, a step will
- * never occur. See the instruction manual for the details how
- * these actions interact with the command line options.
+ * Clock state machine transition function which defines how the
+ * system reacts to large phase and frequency excursion. There
+ * are two main regimes: when the offset exceeds the step
+ * threshold (128 ms) and when it does not. Under certain
+ * conditions updates are suspended until the stepout theshold
+ * (900 s) is exceeded. See the documentation on how these
+ * thresholds interact with commands and command line options.
*
- * Note the system poll is set to minpoll only if the clock is
- * stepped. Note also the kernel is disabled if step is
- * disabled or greater than 0.5 s.
+ * Note the kernel is disabled if step is disabled or greater
+ * than 0.5 s or in ntpdate mode.
*/
- clock_frequency = flladj = plladj = 0;
- mu = peer->epoch - sys_clocktime;
- if (clock_max == 0 || clock_max > 0.5)
- kern_enable = 0;
+ osys_poll = sys_poll;
+ if (sys_poll < peer->minpoll)
+ sys_poll = peer->minpoll;
+ if (sys_poll > peer->maxpoll)
+ sys_poll = peer->maxpoll;
+ mu = current_time - clock_epoch;
+ clock_frequency = drift_comp;
rval = 1;
- if (fabs(fp_offset) > clock_max && clock_max > 0) {
+ if ( ( fp_offset > clock_max_fwd && clock_max_fwd > 0)
+ || (-fp_offset > clock_max_back && clock_max_back > 0)
+ || force_step_once ) {
+ if (force_step_once) {
+ force_step_once = FALSE; /* we want this only once after startup */
+ msyslog(LOG_NOTICE, "Doing intital time step" );
+ }
+
switch (state) {
/*
- * In S_SYNC state we ignore the first outlyer amd
- * switch to S_SPIK state.
+ * In SYNC state we ignore the first outlyer and switch
+ * to SPIK state.
*/
- case S_SYNC:
- state = S_SPIK;
+ case EVNT_SYNC:
+ snprintf(tbuf, sizeof(tbuf), "%+.6f s",
+ fp_offset);
+ report_event(EVNT_SPIK, NULL, tbuf);
+ state = EVNT_SPIK;
return (0);
/*
- * In S_FREQ state we ignore outlyers and inlyers. At
- * the first outlyer after the stepout threshold,
- * compute the apparent frequency correction and step
- * the phase.
+ * In FREQ state we ignore outlyers and inlyers. At the
+ * first outlyer after the stepout threshold, compute
+ * the apparent frequency correction and step the phase.
*/
- case S_FREQ:
+ case EVNT_FREQ:
if (mu < clock_minstep)
return (0);
- clock_frequency = (fp_offset - clock_offset) /
- mu;
+ clock_frequency = direct_freq(fp_offset);
- /* fall through to S_SPIK */
+ /* fall through to EVNT_SPIK */
/*
- * In S_SPIK state we ignore succeeding outlyers until
+ * In SPIK state we ignore succeeding outlyers until
* either an inlyer is found or the stepout threshold is
* exceeded.
*/
- case S_SPIK:
+ case EVNT_SPIK:
if (mu < clock_minstep)
return (0);
/* fall through to default */
/*
- * We get here by default in S_NSET and S_FSET states
- * and from above in S_FREQ or S_SPIK states.
+ * We get here by default in NSET and FSET states and
+ * from above in FREQ or SPIK states.
*
- * In S_NSET state an initial frequency correction is
- * not available, usually because the frequency file has
- * not yet been written. Since the time is outside the
- * step threshold, the clock is stepped. The frequency
- * will be set directly following the stepout interval.
+ * In NSET state an initial frequency correction is not
+ * available, usually because the frequency file has not
+ * yet been written. Since the time is outside the step
+ * threshold, the clock is stepped. The frequency will
+ * be set directly following the stepout interval.
*
- * In S_FSET state the initial frequency has been set
- * from the frequency file. Since the time is outside
- * the step threshold, the clock is stepped immediately,
+ * In FSET state the initial frequency has been set from
+ * the frequency file. Since the time is outside the
+ * step threshold, the clock is stepped immediately,
* rather than after the stepout interval. Guys get
- * nervous if it takes 17 minutes to set the clock for
+ * nervous if it takes 15 minutes to set the clock for
* the first time.
*
- * In S_FREQ and S_SPIK states the stepout threshold has
+ * In FREQ and SPIK states the stepout threshold has
* expired and the phase is still above the step
* threshold. Note that a single spike greater than the
- * step threshold is always suppressed, even at the
- * longer poll intervals.
- */
+ * step threshold is always suppressed, even with a
+ * long time constant.
+ */
default:
- step_systime(fp_offset);
- msyslog(LOG_NOTICE, "time reset %+.6f s",
+ snprintf(tbuf, sizeof(tbuf), "%+.6f s",
fp_offset);
+ report_event(EVNT_CLOCKRESET, NULL, tbuf);
+ step_systime(fp_offset);
reinit_timer();
tc_counter = 0;
- sys_poll = NTP_MINPOLL;
- sys_tai = 0;
clock_jitter = LOGTOD(sys_precision);
rval = 2;
- if (state == S_NSET) {
- rstclock(S_FREQ, peer->epoch, 0);
+ if (state == EVNT_NSET) {
+ rstclock(EVNT_FREQ, 0);
return (rval);
}
break;
}
- rstclock(S_SYNC, peer->epoch, 0);
+ rstclock(EVNT_SYNC, 0);
} else {
-
/*
* The offset is less than the step threshold. Calculate
* the jitter as the exponentially weighted offset
* differences.
- */
+ */
etemp = SQUARE(clock_jitter);
dtemp = SQUARE(max(fabs(fp_offset - last_offset),
LOGTOD(sys_precision)));
@@ -432,105 +664,69 @@ local_clock(
switch (state) {
/*
- * In S_NSET state this is the first update received and
+ * In NSET state this is the first update received and
* the frequency has not been initialized. Adjust the
* phase, but do not adjust the frequency until after
* the stepout threshold.
*/
- case S_NSET:
- rstclock(S_FREQ, peer->epoch, fp_offset);
- break;
-
- /*
- * In S_FSET state this is the first update received and
- * the frequency has been initialized. Adjust the phase,
- * but do not adjust the frequency until the next
- * update.
- */
- case S_FSET:
- rstclock(S_SYNC, peer->epoch, fp_offset);
+ case EVNT_NSET:
+ adj_systime(fp_offset);
+ rstclock(EVNT_FREQ, fp_offset);
break;
/*
- * In S_FREQ state ignore updates until the stepout
- * threshold. After that, correct the phase and
- * frequency and switch to S_SYNC state.
+ * In FREQ state ignore updates until the stepout
+ * threshold. After that, compute the new frequency, but
+ * do not adjust the frequency until the holdoff counter
+ * decrements to zero.
*/
- case S_FREQ:
+ case EVNT_FREQ:
if (mu < clock_minstep)
return (0);
- clock_frequency = (fp_offset - clock_offset) /
- mu;
- rstclock(S_SYNC, peer->epoch, fp_offset);
- break;
+ clock_frequency = direct_freq(fp_offset);
+ /* fall through */
/*
- * We get here by default in S_SYNC and S_SPIK states.
- * Here we compute the frequency update due to PLL and
- * FLL contributions.
+ * We get here by default in FSET, SPIK and SYNC states.
+ * Here compute the frequency update due to PLL and FLL
+ * contributions. Note, we avoid frequency discipline at
+ * startup until the initial transient has subsided.
*/
default:
allow_panic = FALSE;
-
- /*
- * The FLL and PLL frequency gain constants
- * depend on the poll interval and Allan
- * intercept. The PLL is always used, but
- * becomes ineffective above the Allan
- * intercept. The FLL is not used below one-half
- * the Allan intercept. Above that the loop gain
- * increases in steps to 1 / CLOCK_AVG.
- */
- if (ULOGTOD(sys_poll) > allan_xpt / 2) {
- dtemp = CLOCK_FLL - sys_poll;
- flladj = (fp_offset - clock_offset) /
- (max(mu, allan_xpt) * dtemp);
+ if (freq_cnt == 0) {
+
+ /*
+ * The FLL and PLL frequency gain constants
+ * depend on the time constant and Allan
+ * intercept. The PLL is always used, but
+ * becomes ineffective above the Allan intercept
+ * where the FLL becomes effective.
+ */
+ if (sys_poll >= allan_xpt)
+ clock_frequency += (fp_offset -
+ clock_offset) / max(ULOGTOD(sys_poll),
+ mu) * CLOCK_FLL;
+
+ /*
+ * The PLL frequency gain (numerator) depends on
+ * the minimum of the update interval and Allan
+ * intercept. This reduces the PLL gain when the
+ * FLL becomes effective.
+ */
+ etemp = min(ULOGTOD(allan_xpt), mu);
+ dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll);
+ clock_frequency += fp_offset * etemp / (dtemp *
+ dtemp);
}
-
- /*
- * For the PLL the integration interval
- * (numerator) is the minimum of the update
- * interval and poll interval. This allows
- * oversampling, but not undersampling.
- */
- etemp = min(mu, (u_long)ULOGTOD(sys_poll));
- dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll);
- plladj = fp_offset * etemp / (dtemp * dtemp);
- rstclock(S_SYNC, peer->epoch, fp_offset);
+ rstclock(EVNT_SYNC, fp_offset);
+ if (fabs(fp_offset) < CLOCK_FLOOR)
+ freq_cnt = 0;
break;
}
}
-#ifdef OPENSSL
- /*
- * Scan the loopsecond table to determine the TAI offset. If
- * there is a scheduled leap in future, set the leap warning,
- * but only if less than 30 days before the leap.
- */
- tpt = (u_int32 *)tai_leap.ptr;
- len = ntohl(tai_leap.vallen) / sizeof(u_int32);
- if (tpt != NULL) {
- for (i = 0; i < len; i++) {
- togo = (long)ntohl(tpt[i]) -
- (long)peer->rec.l_ui;
- if (togo > 0) {
- if (togo < CLOCK_JUNE)
- leap_next |= LEAP_ADDSECOND;
- break;
- }
- }
-#if defined(STA_NANO) && NTP_API == 4
- if (pll_control && kern_enable && sys_tai == 0) {
- memset(&ntv, 0, sizeof(ntv));
- ntv.modes = MOD_TAI;
- ntv.constant = i + TAI_1972 - 1;
- ntp_adjtime(&ntv);
- }
-#endif /* STA_NANO */
- sys_tai = i + TAI_1972 - 1;
- }
-#endif /* OPENSSL */
#ifdef KERNEL_PLL
/*
* This code segment works when clock adjustments are made using
@@ -547,7 +743,7 @@ local_clock(
* lead to overflow problems. This might occur if some misguided
* lad set the step threshold to something ridiculous.
*/
- if (pll_control && kern_enable) {
+ if (pll_control && kern_enable && freq_cnt == 0) {
/*
* We initialize the structure for the ntp_adjtime()
@@ -560,13 +756,10 @@ local_clock(
* frequency offsets for jitter and stability values and
* to update the frequency file.
*/
- memset(&ntv, 0, sizeof(ntv));
+ ZERO(ntv);
if (ext_enable) {
ntv.modes = MOD_STATUS;
} else {
- struct tm *tm = NULL;
- time_t tstamp;
-
#ifdef STA_NANO
ntv.modes = MOD_BITS | MOD_NANO;
#else /* STA_NANO */
@@ -585,67 +778,48 @@ local_clock(
dtemp);
ntv.constant = sys_poll - 4;
#endif /* STA_NANO */
+ if (ntv.constant < 0)
+ ntv.constant = 0;
- /*
- * The frequency is set directly only if
- * clock_frequency is nonzero coming out of FREQ
- * state.
- */
- if (clock_frequency != 0) {
- ntv.modes |= MOD_FREQUENCY;
- ntv.freq = (int32)((clock_frequency +
- drift_comp) * 65536e6);
- }
ntv.esterror = (u_int32)(clock_jitter * 1e6);
ntv.maxerror = (u_int32)((sys_rootdelay / 2 +
- sys_rootdispersion) * 1e6);
+ sys_rootdisp) * 1e6);
ntv.status = STA_PLL;
/*
- * Set the leap bits in the status word, but
- * only on the last day of June or December.
- */
- tstamp = peer->rec.l_ui - JAN_1970;
- tm = gmtime(&tstamp);
- if (tm != NULL) {
- if ((tm->tm_mon + 1 == 6 &&
- tm->tm_mday == 30) || (tm->tm_mon +
- 1 == 12 && tm->tm_mday == 31)) {
- if (leap_next & LEAP_ADDSECOND)
- ntv.status |= STA_INS;
- else if (leap_next &
- LEAP_DELSECOND)
- ntv.status |= STA_DEL;
- }
- }
-
- /*
- * If the PPS signal is up and enabled, light
- * the frequency bit. If the PPS driver is
- * working, light the phase bit as well. If not,
- * douse the lights, since somebody else may
- * have left the switch on.
+ * Enable/disable the PPS if requested.
*/
- if (pps_enable && pll_status & STA_PPSSIGNAL) {
- ntv.status |= STA_PPSFREQ;
- if (pps_stratum < STRATUM_UNSPEC)
- ntv.status |= STA_PPSTIME;
+ if (hardpps_enable) {
+ ntv.status |= (STA_PPSTIME | STA_PPSFREQ);
+ if (!(pll_status & STA_PPSTIME))
+ sync_status("PPS enabled",
+ pll_status,
+ ntv.status);
} else {
- ntv.status &= ~(STA_PPSFREQ |
- STA_PPSTIME);
+ ntv.status &= ~(STA_PPSTIME | STA_PPSFREQ);
+ if (pll_status & STA_PPSTIME)
+ sync_status("PPS disabled",
+ pll_status,
+ ntv.status);
}
+ if (sys_leap == LEAP_ADDSECOND)
+ ntv.status |= STA_INS;
+ else if (sys_leap == LEAP_DELSECOND)
+ ntv.status |= STA_DEL;
}
/*
* Pass the stuff to the kernel. If it squeals, turn off
- * the pig. In any case, fetch the kernel offset and
- * frequency and pretend we did it here.
+ * the pps. In any case, fetch the kernel offset,
+ * frequency and jitter.
+ */
+ ntp_adj_ret = ntp_adjtime(&ntv);
+ /*
+ * A squeal is a return status < 0, or a state change.
*/
- if (ntp_adjtime(&ntv) == TIME_ERROR) {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "kernel time sync error %04x", ntv.status);
- ntv.status &= ~(STA_PPSFREQ | STA_PPSTIME);
+ if ((0 > ntp_adj_ret) || (ntp_adj_ret != kernel_status)) {
+ kernel_status = ntp_adj_ret;
+ ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, hardpps_enable, 0, __LINE__ - 1);
}
pll_status = ntv.status;
#ifdef STA_NANO
@@ -653,42 +827,41 @@ local_clock(
#else /* STA_NANO */
clock_offset = ntv.offset / 1e6;
#endif /* STA_NANO */
- clock_frequency = ntv.freq / 65536e6;
- flladj = plladj = 0;
+ clock_frequency = FREQTOD(ntv.freq);
/*
* If the kernel PPS is lit, monitor its performance.
*/
if (ntv.status & STA_PPSTIME) {
- pps_control = current_time;
#ifdef STA_NANO
clock_jitter = ntv.jitter / 1e9;
#else /* STA_NANO */
clock_jitter = ntv.jitter / 1e6;
#endif /* STA_NANO */
}
- } else {
-#endif /* KERNEL_PLL */
-
+
+#if defined(STA_NANO) && NTP_API == 4
/*
- * We get here if the kernel discipline is not enabled.
- * Adjust the clock frequency as the sum of the directly
- * computed frequency (if measured) and the PLL and FLL
- * increments.
+ * If the TAI changes, update the kernel TAI.
*/
- clock_frequency = drift_comp + clock_frequency +
- flladj + plladj;
-#ifdef KERNEL_PLL
+ if (loop_tai != sys_tai) {
+ loop_tai = sys_tai;
+ ntv.modes = MOD_TAI;
+ ntv.constant = sys_tai;
+ if ((ntp_adj_ret = ntp_adjtime(&ntv)) != 0) {
+ ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, 0, 1, __LINE__ - 1);
+ }
+ }
+#endif /* STA_NANO */
}
#endif /* KERNEL_PLL */
/*
* Clamp the frequency within the tolerance range and calculate
- * the frequency change since the last update.
+ * the frequency difference since the last update.
*/
if (fabs(clock_frequency) > NTP_MAXFREQ)
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
+ msyslog(LOG_NOTICE,
"frequency error %.0f PPM exceeds tolerance %.0f PPM",
clock_frequency * 1e6, NTP_MAXFREQ * 1e6);
dtemp = SQUARE(clock_frequency - drift_comp);
@@ -700,20 +873,24 @@ local_clock(
drift_comp = clock_frequency;
/*
- * Calculate the wander as the exponentially weighted frequency
- * differences.
+ * Calculate the wander as the exponentially weighted RMS
+ * frequency differences. Record the change for the frequency
+ * file update.
*/
etemp = SQUARE(clock_stability);
clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG);
/*
- * Here we adjust the poll interval by comparing the current
+ * Here we adjust the time constant by comparing the current
* offset with the clock jitter. If the offset is less than the
* clock jitter times a constant, then the averaging interval is
* increased, otherwise it is decreased. A bit of hysteresis
- * helps calm the dance. Works best using burst mode.
+ * helps calm the dance. Works best using burst mode. Don't
+ * fiddle with the poll during the startup clamp period.
*/
- if (fabs(clock_offset) < CLOCK_PGATE * clock_jitter) {
+ if (freq_cnt > 0) {
+ tc_counter = 0;
+ } else if (fabs(clock_offset) < CLOCK_PGATE * clock_jitter) {
tc_counter += sys_poll;
if (tc_counter > CLOCK_LIMIT) {
tc_counter = CLOCK_LIMIT;
@@ -734,6 +911,12 @@ local_clock(
}
/*
+ * If the time constant has changed, update the poll variables.
+ */
+ if (osys_poll != sys_poll)
+ poll_update(peer, sys_poll);
+
+ /*
* Yibbidy, yibbbidy, yibbidy; that'h all folks.
*/
record_loop_stats(clock_offset, drift_comp, clock_jitter,
@@ -741,9 +924,9 @@ local_clock(
#ifdef DEBUG
if (debug)
printf(
- "local_clock: mu %lu jitr %.6f freq %.3f stab %.6f poll %d count %d\n",
- mu, clock_jitter, drift_comp * 1e6,
- clock_stability * 1e6, sys_poll, tc_counter);
+ "local_clock: offset %.9f jit %.9f freq %.3f stab %.3f poll %d\n",
+ clock_offset, clock_jitter, drift_comp * 1e6,
+ clock_stability * 1e6, sys_poll);
#endif /* DEBUG */
return (rval);
#endif /* LOCKCLOCK */
@@ -754,82 +937,267 @@ local_clock(
* adj_host_clock - Called once every second to update the local clock.
*
* LOCKCLOCK: The only thing this routine does is increment the
- * sys_rootdispersion variable.
+ * sys_rootdisp variable.
*/
void
adj_host_clock(
void
)
{
- double adjustment;
+ double offset_adj;
+ double freq_adj;
/*
* Update the dispersion since the last update. In contrast to
* NTPv3, NTPv4 does not declare unsynchronized after one day,
* since the dispersion check serves this function. Also,
* since the poll interval can exceed one day, the old test
- * would be counterproductive. Note we do this even with
- * external clocks, since the clock driver will recompute the
- * maximum error and the local clock driver will pick it up and
- * pass to the common refclock routines. Very elegant.
+ * would be counterproductive. During the startup clamp period, the
+ * time constant is clamped at 2.
*/
- sys_rootdispersion += clock_phi;
-
+ sys_rootdisp += clock_phi;
#ifndef LOCKCLOCK
+ if (!ntp_enable || mode_ntpdate)
+ return;
/*
- * If clock discipline is disabled or if the kernel is enabled,
- * get out of Dodge quick.
+ * Determine the phase adjustment. The gain factor (denominator)
+ * increases with poll interval, so is dominated by the FLL
+ * above the Allan intercept. Note the reduced time constant at
+ * startup.
*/
- if (!ntp_enable || mode_ntpdate || (pll_control &&
- kern_enable))
- return;
+ if (state != EVNT_SYNC) {
+ offset_adj = 0.;
+ } else if (freq_cnt > 0) {
+ offset_adj = clock_offset / (CLOCK_PLL * ULOGTOD(1));
+ freq_cnt--;
+#ifdef KERNEL_PLL
+ } else if (pll_control && kern_enable) {
+ offset_adj = 0.;
+#endif /* KERNEL_PLL */
+ } else {
+ offset_adj = clock_offset / (CLOCK_PLL * ULOGTOD(sys_poll));
+ }
/*
- * Declare PPS kernel unsync if the pps signal has not been
- * heard for a few minutes.
+ * If the kernel discipline is enabled the frequency correction
+ * drift_comp has already been engaged via ntp_adjtime() in
+ * set_freq(). Otherwise it is a component of the adj_systime()
+ * offset.
*/
- if (pps_control && current_time - pps_control > PPS_MAXAGE) {
- if (pps_control)
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE, "pps sync disabled");
- pps_control = 0;
- }
+#ifdef KERNEL_PLL
+ if (pll_control && kern_enable)
+ freq_adj = 0.;
+ else
+#endif /* KERNEL_PLL */
+ freq_adj = drift_comp;
+ /* Bound absolute value of total adjustment to NTP_MAXFREQ. */
+ if (offset_adj + freq_adj > NTP_MAXFREQ)
+ offset_adj = NTP_MAXFREQ - freq_adj;
+ else if (offset_adj + freq_adj < -NTP_MAXFREQ)
+ offset_adj = -NTP_MAXFREQ - freq_adj;
+
+ clock_offset -= offset_adj;
/*
- * Implement the phase and frequency adjustments. The gain
- * factor (denominator) is not allowed to increase beyond the
- * Allan intercept. It doesn't make sense to average phase noise
- * beyond this point and it helps to damp residual offset at the
- * longer poll intervals.
+ * Windows port adj_systime() must be called each second,
+ * even if the argument is zero, to ease emulation of
+ * adjtime() using Windows' slew API which controls the rate
+ * but does not automatically stop slewing when an offset
+ * has decayed to zero.
*/
- adjustment = clock_offset / (CLOCK_PLL * min(ULOGTOD(sys_poll),
- allan_xpt));
- clock_offset -= adjustment;
- adj_systime(adjustment + drift_comp);
+ adj_systime(offset_adj + freq_adj);
#endif /* LOCKCLOCK */
}
/*
- * Clock state machine. Enter new state and set state variables. Note we
- * use the time of the last clock filter sample, which may be earlier
- * than the current time.
+ * Clock state machine. Enter new state and set state variables.
*/
static void
rstclock(
int trans, /* new state */
- u_long update, /* new update time */
double offset /* new offset */
)
{
#ifdef DEBUG
- if (debug)
- printf("local_clock: time %lu offset %.6f freq %.3f state %d\n",
- update, offset, drift_comp * 1e6, trans);
+ if (debug > 1)
+ printf("local_clock: mu %lu state %d poll %d count %d\n",
+ current_time - clock_epoch, trans, sys_poll,
+ tc_counter);
#endif
+ if (trans != state && trans != EVNT_FSET)
+ report_event(trans, NULL, NULL);
state = trans;
- sys_clocktime = update;
last_offset = clock_offset = offset;
+ clock_epoch = current_time;
+}
+
+
+/*
+ * calc_freq - calculate frequency directly
+ *
+ * This is very carefully done. When the offset is first computed at the
+ * first update, a residual frequency component results. Subsequently,
+ * updates are suppresed until the end of the measurement interval while
+ * the offset is amortized. At the end of the interval the frequency is
+ * calculated from the current offset, residual offset, length of the
+ * interval and residual frequency component. At the same time the
+ * frequenchy file is armed for update at the next hourly stats.
+ */
+static double
+direct_freq(
+ double fp_offset
+ )
+{
+ set_freq(fp_offset / (current_time - clock_epoch));
+
+ return drift_comp;
+}
+
+
+/*
+ * set_freq - set clock frequency correction
+ *
+ * Used to step the frequency correction at startup, possibly again once
+ * the frequency is measured (that is, transitioning from EVNT_NSET to
+ * EVNT_FSET), and finally to switch between daemon and kernel loop
+ * discipline at runtime.
+ *
+ * When the kernel loop discipline is available but the daemon loop is
+ * in use, the kernel frequency correction is disabled (set to 0) to
+ * ensure drift_comp is applied by only one of the loops.
+ */
+static void
+set_freq(
+ double freq /* frequency update */
+ )
+{
+ const char * loop_desc;
+ int ntp_adj_ret;
+
+ drift_comp = freq;
+ loop_desc = "ntpd";
+#ifdef KERNEL_PLL
+ if (pll_control) {
+ ZERO(ntv);
+ ntv.modes = MOD_FREQUENCY;
+ if (kern_enable) {
+ loop_desc = "kernel";
+ ntv.freq = DTOFREQ(drift_comp);
+ }
+ if ((ntp_adj_ret = ntp_adjtime(&ntv)) != 0) {
+ ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, 0, 0, __LINE__ - 1);
+ }
+ }
+#endif /* KERNEL_PLL */
+ mprintf_event(EVNT_FSET, NULL, "%s %.3f PPM", loop_desc,
+ drift_comp * 1e6);
+}
+
+
+#ifdef KERNEL_PLL
+static void
+start_kern_loop(void)
+{
+ static int atexit_done;
+ int ntp_adj_ret;
+
+ pll_control = TRUE;
+ ZERO(ntv);
+ ntv.modes = MOD_BITS;
+ ntv.status = STA_PLL;
+ ntv.maxerror = MAXDISPERSE;
+ ntv.esterror = MAXDISPERSE;
+ ntv.constant = sys_poll; /* why is it that here constant is unconditionally set to sys_poll, whereas elsewhere is is modified depending on nanosecond vs. microsecond kernel? */
+#ifdef SIGSYS
+ /*
+ * Use sigsetjmp() to save state and then call ntp_adjtime(); if
+ * it fails, then pll_trap() will set pll_control FALSE before
+ * returning control using siglogjmp().
+ */
+ newsigsys.sa_handler = pll_trap;
+ newsigsys.sa_flags = 0;
+ if (sigaction(SIGSYS, &newsigsys, &sigsys)) {
+ msyslog(LOG_ERR, "sigaction() trap SIGSYS: %m");
+ pll_control = FALSE;
+ } else {
+ if (sigsetjmp(env, 1) == 0) {
+ if ((ntp_adj_ret = ntp_adjtime(&ntv)) != 0) {
+ ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, 0, 0, __LINE__ - 1);
+ }
+ }
+ if (sigaction(SIGSYS, &sigsys, NULL)) {
+ msyslog(LOG_ERR,
+ "sigaction() restore SIGSYS: %m");
+ pll_control = FALSE;
+ }
+ }
+#else /* SIGSYS */
+ if ((ntp_adj_ret = ntp_adjtime(&ntv)) != 0) {
+ ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, 0, 0, __LINE__ - 1);
+ }
+#endif /* SIGSYS */
+
+ /*
+ * Save the result status and light up an external clock
+ * if available.
+ */
+ pll_status = ntv.status;
+ if (pll_control) {
+ if (!atexit_done) {
+ atexit_done = TRUE;
+ atexit(&stop_kern_loop);
+ }
+#ifdef STA_NANO
+ if (pll_status & STA_CLK)
+ ext_enable = TRUE;
+#endif /* STA_NANO */
+ report_event(EVNT_KERN, NULL,
+ "kernel time sync enabled");
+ }
+}
+#endif /* KERNEL_PLL */
+
+
+#ifdef KERNEL_PLL
+static void
+stop_kern_loop(void)
+{
+ if (pll_control && kern_enable)
+ report_event(EVNT_KERN, NULL,
+ "kernel time sync disabled");
+}
+#endif /* KERNEL_PLL */
+
+
+/*
+ * select_loop() - choose kernel or daemon loop discipline.
+ */
+void
+select_loop(
+ int use_kern_loop
+ )
+{
+ if (kern_enable == use_kern_loop)
+ return;
+#ifdef KERNEL_PLL
+ if (pll_control && !use_kern_loop)
+ stop_kern_loop();
+#endif
+ kern_enable = use_kern_loop;
+#ifdef KERNEL_PLL
+ if (pll_control && use_kern_loop)
+ start_kern_loop();
+#endif
+ /*
+ * If this loop selection change occurs after initial startup,
+ * call set_freq() to switch the frequency compensation to or
+ * from the kernel loop.
+ */
+#ifdef KERNEL_PLL
+ if (pll_control && loop_started)
+ set_freq(drift_comp);
+#endif
}
@@ -837,7 +1205,7 @@ rstclock(
* huff-n'-puff filter
*/
void
-huffpuff()
+huffpuff(void)
{
int i;
@@ -861,173 +1229,144 @@ huffpuff()
*/
void
loop_config(
- int item,
- double freq
+ int item,
+ double freq
)
{
- int i;
+ int i;
+ double ftemp;
+#ifdef DEBUG
+ if (debug > 1)
+ printf("loop_config: item %d freq %f\n", item, freq);
+#endif
switch (item) {
+ /*
+ * We first assume the kernel supports the ntp_adjtime()
+ * syscall. If that syscall works, initialize the kernel time
+ * variables. Otherwise, continue leaving no harm behind.
+ */
case LOOP_DRIFTINIT:
-
#ifndef LOCKCLOCK
#ifdef KERNEL_PLL
- /*
- * Assume the kernel supports the ntp_adjtime() syscall.
- * If that syscall works, initialize the kernel time
- * variables. Otherwise, continue leaving no harm
- * behind. While at it, ask to set nanosecond mode. If
- * the kernel agrees, rejoice; othewise, it does only
- * microseconds.
- */
if (mode_ntpdate)
break;
- pll_control = 1;
- memset(&ntv, 0, sizeof(ntv));
-#ifdef STA_NANO
- ntv.modes = MOD_BITS | MOD_NANO;
-#else /* STA_NANO */
- ntv.modes = MOD_BITS;
-#endif /* STA_NANO */
- ntv.maxerror = MAXDISPERSE;
- ntv.esterror = MAXDISPERSE;
- ntv.status = STA_UNSYNC;
-#ifdef SIGSYS
- /*
- * Use sigsetjmp() to save state and then call
- * ntp_adjtime(); if it fails, then siglongjmp() is used
- * to return control
- */
- newsigsys.sa_handler = pll_trap;
- newsigsys.sa_flags = 0;
- if (sigaction(SIGSYS, &newsigsys, &sigsys)) {
- msyslog(LOG_ERR,
- "sigaction() fails to save SIGSYS trap: %m");
- pll_control = 0;
- }
- if (sigsetjmp(env, 1) == 0)
- ntp_adjtime(&ntv);
- if ((sigaction(SIGSYS, &sigsys,
- (struct sigaction *)NULL))) {
- msyslog(LOG_ERR,
- "sigaction() fails to restore SIGSYS trap: %m");
- pll_control = 0;
- }
-#else /* SIGSYS */
- ntp_adjtime(&ntv);
-#endif /* SIGSYS */
-
- /*
- * Save the result status and light up an external clock
- * if available.
- */
- pll_status = ntv.status;
- if (pll_control) {
-#ifdef STA_NANO
- if (pll_status & STA_CLK)
- ext_enable = 1;
-#endif /* STA_NANO */
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_INFO,
- "kernel time sync status %04x",
- pll_status);
- }
+ start_kern_loop();
#endif /* KERNEL_PLL */
-#endif /* LOCKCLOCK */
- break;
- case LOOP_DRIFTCOMP:
-
-#ifndef LOCKCLOCK
/*
- * If the frequency value is reasonable, set the initial
- * frequency to the given value and the state to S_FSET.
- * Otherwise, the drift file may be missing or broken,
- * so set the frequency to zero. This erases past
- * history should somebody break something.
+ * Initialize frequency if given; otherwise, begin frequency
+ * calibration phase.
*/
- if (freq <= NTP_MAXFREQ && freq >= -NTP_MAXFREQ) {
- drift_comp = freq;
- rstclock(S_FSET, 0, 0);
- } else {
- drift_comp = 0;
- }
-
-#ifdef KERNEL_PLL
- /*
- * Sanity check. If the kernel is available, load the
- * frequency and light up the loop. Make sure the offset
- * is zero to cancel any previous nonsense. If you don't
- * want this initialization, remove the ntp.drift file.
- */
- if (pll_control && kern_enable) {
- memset((char *)&ntv, 0, sizeof(ntv));
- ntv.modes = MOD_OFFSET | MOD_FREQUENCY;
- ntv.freq = (int32)(drift_comp * 65536e6);
- ntp_adjtime(&ntv);
- }
-#endif /* KERNEL_PLL */
+ ftemp = init_drift_comp / 1e6;
+ if (ftemp > NTP_MAXFREQ)
+ ftemp = NTP_MAXFREQ;
+ else if (ftemp < -NTP_MAXFREQ)
+ ftemp = -NTP_MAXFREQ;
+ set_freq(ftemp);
+ if (freq_set)
+ rstclock(EVNT_FSET, 0);
+ else
+ rstclock(EVNT_NSET, 0);
+ loop_started = TRUE;
#endif /* LOCKCLOCK */
break;
case LOOP_KERN_CLEAR:
+#if 0 /* XXX: needs more review, and how can we get here? */
#ifndef LOCKCLOCK
-#ifdef KERNEL_PLL
- /* Completely turn off the kernel time adjustments. */
- if (pll_control) {
+# ifdef KERNEL_PLL
+ if (pll_control && kern_enable) {
memset((char *)&ntv, 0, sizeof(ntv));
- ntv.modes = MOD_BITS | MOD_OFFSET | MOD_FREQUENCY;
+ ntv.modes = MOD_STATUS;
ntv.status = STA_UNSYNC;
ntp_adjtime(&ntv);
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_INFO,
- "kernel time sync disabled %04x",
- ntv.status);
+ sync_status("kernel time sync disabled",
+ pll_status,
+ ntv.status);
}
-#endif /* KERNEL_PLL */
+# endif /* KERNEL_PLL */
#endif /* LOCKCLOCK */
+#endif
break;
/*
- * Special tinker variables for Ulrich Windl. Very dangerous.
+ * Tinker command variables for Ulrich Windl. Very dangerous.
*/
- case LOOP_MAX: /* step threshold */
- clock_max = freq;
+ case LOOP_ALLAN: /* Allan intercept (log2) (allan) */
+ allan_xpt = (u_char)freq;
break;
- case LOOP_PANIC: /* panic threshold */
- clock_panic = freq;
+ case LOOP_CODEC: /* audio codec frequency (codec) */
+ clock_codec = freq / 1e6;
break;
- case LOOP_PHI: /* dispersion rate */
- clock_phi = freq;
+ case LOOP_PHI: /* dispersion threshold (dispersion) */
+ clock_phi = freq / 1e6;
break;
- case LOOP_MINSTEP: /* watchdog bark */
- clock_minstep = freq;
+ case LOOP_FREQ: /* initial frequency (freq) */
+ init_drift_comp = freq;
+ freq_set++;
break;
- case LOOP_ALLAN: /* Allan intercept */
- allan_xpt = freq;
- break;
-
- case LOOP_HUFFPUFF: /* huff-n'-puff filter length */
+ case LOOP_HUFFPUFF: /* huff-n'-puff length (huffpuff) */
if (freq < HUFFPUFF)
freq = HUFFPUFF;
sys_hufflen = (int)(freq / HUFFPUFF);
- sys_huffpuff = (double *)emalloc(sizeof(double) *
+ sys_huffpuff = emalloc(sizeof(sys_huffpuff[0]) *
sys_hufflen);
for (i = 0; i < sys_hufflen; i++)
sys_huffpuff[i] = 1e9;
sys_mindly = 1e9;
break;
- case LOOP_FREQ: /* initial frequency */
- drift_comp = freq / 1e6;
- rstclock(S_FSET, 0, 0);
+ case LOOP_PANIC: /* panic threshold (panic) */
+ clock_panic = freq;
+ break;
+
+ case LOOP_MAX: /* step threshold (step) */
+ clock_max_fwd = clock_max_back = freq;
+ if (freq == 0 || freq > 0.5)
+ select_loop(FALSE);
+ break;
+
+ case LOOP_MAX_BACK: /* step threshold (step) */
+ clock_max_back = freq;
+ /*
+ * Leave using the kernel discipline code unless both
+ * limits are massive. This assumes the reason to stop
+ * using it is that it's pointless, not that it goes wrong.
+ */
+ if ( (clock_max_back == 0 || clock_max_back > 0.5)
+ || (clock_max_fwd == 0 || clock_max_fwd > 0.5))
+ select_loop(FALSE);
+ break;
+
+ case LOOP_MAX_FWD: /* step threshold (step) */
+ clock_max_fwd = freq;
+ if ( (clock_max_back == 0 || clock_max_back > 0.5)
+ || (clock_max_fwd == 0 || clock_max_fwd > 0.5))
+ select_loop(FALSE);
+ break;
+
+ case LOOP_MINSTEP: /* stepout threshold (stepout) */
+ if (freq < CLOCK_MINSTEP)
+ clock_minstep = CLOCK_MINSTEP;
+ else
+ clock_minstep = freq;
+ break;
+
+ case LOOP_TICK: /* tick increment (tick) */
+ set_sys_tick_precision(freq);
break;
+
+ case LOOP_LEAP: /* not used, fall through */
+ default:
+ msyslog(LOG_NOTICE,
+ "loop_config: unsupported option %d", item);
}
}
@@ -1046,7 +1385,7 @@ pll_trap(
int arg
)
{
- pll_control = 0;
+ pll_control = FALSE;
siglongjmp(env, 1);
}
#endif /* KERNEL_PLL && SIGSYS */
diff --git a/contrib/ntp/ntpd/ntp_monitor.c b/contrib/ntp/ntpd/ntp_monitor.c
index 753fa76..02fd757 100644
--- a/contrib/ntp/ntpd/ntp_monitor.c
+++ b/contrib/ntp/ntpd/ntp_monitor.c
@@ -8,6 +8,7 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_if.h"
+#include "ntp_lists.h"
#include "ntp_stdlib.h"
#include <ntp_random.h>
@@ -18,17 +19,14 @@
#endif
/*
- * I'm still not sure I like what I've done here. It certainly consumes
- * memory like it is going out of style, and also may not be as low
- * overhead as I'd imagined.
+ * Record statistics based on source address, mode and version. The
+ * receive procedure calls us with the incoming rbufp before it does
+ * anything else. While at it, implement rate controls for inbound
+ * traffic.
*
- * Anyway, we record statistics based on source address, mode and
- * version (for now, anyway. Check the code). The receive procedure
- * calls us with the incoming rbufp before it does anything else.
- *
- * Each entry is doubly linked into two lists, a hash table and a
- * most-recently-used list. When a packet arrives it is looked up in
- * the hash table. If found, the statistics are updated and the entry
+ * Each entry is doubly linked into two lists, a hash table and a most-
+ * recently-used (MRU) list. When a packet arrives it is looked up in
+ * the hash table. If found, the statistics are updated and the entry
* relinked at the head of the MRU list. If not found, a new entry is
* allocated, initialized and linked into both the hash table and at the
* head of the MRU list.
@@ -39,55 +37,70 @@
* tail for the MRU list, unlinking from the hash table, and
* reinitializing.
*
- * trimmed back memory consumption ... jdg 8/94
- */
-/*
- * Limits on the number of structures allocated. This limit is picked
- * with the illicit knowlege that we can only return somewhat less
- * than 8K bytes in a mode 7 response packet, and that each structure
- * will require about 20 bytes of space in the response.
- *
- * ... I don't believe the above is true anymore ... jdg
+ * INC_MONLIST is the default allocation granularity in entries.
+ * INIT_MONLIST is the default initial allocation in entries.
*/
-#ifndef MAXMONMEM
-#define MAXMONMEM 600 /* we allocate up to 600 structures */
+#ifdef MONMEMINC /* old name */
+# define INC_MONLIST MONMEMINC
+#elif !defined(INC_MONLIST)
+# define INC_MONLIST (4 * 1024 / sizeof(mon_entry))
#endif
-#ifndef MONMEMINC
-#define MONMEMINC 40 /* allocate them 40 at a time */
+#ifndef INIT_MONLIST
+# define INIT_MONLIST (4 * 1024 / sizeof(mon_entry))
+#endif
+#ifndef MRU_MAXDEPTH_DEF
+# define MRU_MAXDEPTH_DEF (1024 * 1024 / sizeof(mon_entry))
#endif
/*
* Hashing stuff
*/
-#define MON_HASH_SIZE 128
-#define MON_HASH_MASK (MON_HASH_SIZE-1)
-#define MON_HASH(addr) sock_hash(addr)
+u_char mon_hash_bits;
/*
- * Pointers to the hash table, the MRU list and the count table. Memory
- * for the hash and count tables is only allocated if monitoring is
- * turned on.
+ * Pointers to the hash table and the MRU list. Memory for the hash
+ * table is allocated only if monitoring is enabled.
*/
-static struct mon_data *mon_hash[MON_HASH_SIZE]; /* list ptrs */
-struct mon_data mon_mru_list;
+mon_entry ** mon_hash; /* MRU hash table */
+mon_entry mon_mru_list; /* mru listhead */
/*
- * List of free structures structures, and counters of free and total
- * structures. The free structures are linked with the hash_next field.
+ * List of free structures structures, and counters of in-use and total
+ * structures. The free structures are linked with the hash_next field.
*/
-static struct mon_data *mon_free; /* free list or null if none */
-static int mon_total_mem; /* total structures allocated */
-static int mon_mem_increments; /* times called malloc() */
+static mon_entry *mon_free; /* free list or null if none */
+ u_int mru_alloc; /* mru list + free list count */
+ u_int mru_entries; /* mru list count */
+ u_int mru_peakentries; /* highest mru_entries seen */
+ u_int mru_initalloc = INIT_MONLIST;/* entries to preallocate */
+ u_int mru_incalloc = INC_MONLIST;/* allocation batch factor */
+static u_int mon_mem_increments; /* times called malloc() */
+
+/*
+ * Parameters of the RES_LIMITED restriction option. We define headway
+ * as the idle time between packets. A packet is discarded if the
+ * headway is less than the minimum, as well as if the average headway
+ * is less than eight times the increment.
+ */
+int ntp_minpkt = NTP_MINPKT; /* minimum (log 2 s) */
+u_char ntp_minpoll = NTP_MINPOLL; /* increment (log 2 s) */
/*
* Initialization state. We may be monitoring, we may not. If
* we aren't, we may not even have allocated any memory yet.
*/
-int mon_enabled; /* enable switch */
-u_long mon_age = 3000; /* preemption limit */
-static int mon_have_memory;
-static void mon_getmoremem P((void));
-static void remove_from_hash P((struct mon_data *));
+ u_int mon_enabled; /* enable switch */
+ u_int mru_mindepth = 600; /* preempt above this */
+ int mru_maxage = 64; /* for entries older than */
+ u_int mru_maxdepth = /* MRU count hard limit */
+ MRU_MAXDEPTH_DEF;
+ int mon_age = 3000; /* preemption limit */
+
+static void mon_getmoremem(void);
+static void remove_from_hash(mon_entry *);
+static inline void mon_free_entry(mon_entry *);
+static inline void mon_reclaim_entry(mon_entry *);
+
/*
* init_mon - initialize monitoring global data
@@ -97,16 +110,86 @@ init_mon(void)
{
/*
* Don't do much of anything here. We don't allocate memory
- * until someone explicitly starts us.
+ * until mon_start().
*/
mon_enabled = MON_OFF;
- mon_have_memory = 0;
+ INIT_DLIST(mon_mru_list, mru);
+}
+
+
+/*
+ * remove_from_hash - removes an entry from the address hash table and
+ * decrements mru_entries.
+ */
+static void
+remove_from_hash(
+ mon_entry *mon
+ )
+{
+ u_int hash;
+ mon_entry *punlinked;
+
+ mru_entries--;
+ hash = MON_HASH(&mon->rmtadr);
+ UNLINK_SLIST(punlinked, mon_hash[hash], mon, hash_next,
+ mon_entry);
+ NTP_ENSURE(punlinked == mon);
+}
- mon_total_mem = 0;
- mon_mem_increments = 0;
- mon_free = NULL;
- memset(&mon_hash[0], 0, sizeof mon_hash);
- memset(&mon_mru_list, 0, sizeof mon_mru_list);
+
+static inline void
+mon_free_entry(
+ mon_entry *m
+ )
+{
+ ZERO(*m);
+ LINK_SLIST(mon_free, m, hash_next);
+}
+
+
+/*
+ * mon_reclaim_entry - Remove an entry from the MRU list and from the
+ * hash array, then zero-initialize it. Indirectly
+ * decrements mru_entries.
+
+ * The entry is prepared to be reused. Before return, in
+ * remove_from_hash(), mru_entries is decremented. It is the caller's
+ * responsibility to increment it again.
+ */
+static inline void
+mon_reclaim_entry(
+ mon_entry *m
+ )
+{
+ DEBUG_INSIST(NULL != m);
+
+ UNLINK_DLIST(m, mru);
+ remove_from_hash(m);
+ ZERO(*m);
+}
+
+
+/*
+ * mon_getmoremem - get more memory and put it on the free list
+ */
+static void
+mon_getmoremem(void)
+{
+ mon_entry *chunk;
+ u_int entries;
+
+ entries = (0 == mon_mem_increments)
+ ? mru_initalloc
+ : mru_incalloc;
+
+ if (entries) {
+ chunk = eallocarray(entries, sizeof(*chunk));
+ mru_alloc += entries;
+ for (chunk += entries; entries; entries--)
+ mon_free_entry(--chunk);
+
+ mon_mem_increments++;
+ }
}
@@ -118,24 +201,31 @@ mon_start(
int mode
)
{
+ size_t octets;
+ u_int min_hash_slots;
- if (mon_enabled != MON_OFF) {
+ if (MON_OFF == mode) /* MON_OFF is 0 */
+ return;
+ if (mon_enabled) {
mon_enabled |= mode;
return;
}
- if (mode == MON_OFF)
- return;
-
- if (!mon_have_memory) {
- mon_total_mem = 0;
- mon_mem_increments = 0;
- mon_free = NULL;
+ if (0 == mon_mem_increments)
mon_getmoremem();
- mon_have_memory = 1;
- }
+ /*
+ * Select the MRU hash table size to limit the average count
+ * per bucket at capacity (mru_maxdepth) to 8, if possible
+ * given our hash is limited to 16 bits.
+ */
+ min_hash_slots = (mru_maxdepth / 8) + 1;
+ mon_hash_bits = 0;
+ while (min_hash_slots >>= 1)
+ mon_hash_bits++;
+ mon_hash_bits = max(4, mon_hash_bits);
+ mon_hash_bits = min(16, mon_hash_bits);
+ octets = sizeof(*mon_hash) * MON_HASH_SIZE;
+ mon_hash = erealloc_zero(mon_hash, octets, 0);
- mon_mru_list.mru_next = &mon_mru_list;
- mon_mru_list.mru_prev = &mon_mru_list;
mon_enabled = mode;
}
@@ -148,211 +238,259 @@ mon_stop(
int mode
)
{
- register struct mon_data *md, *md_next;
- register int i;
+ mon_entry *mon;
- if (mon_enabled == MON_OFF)
- return;
+ if (MON_OFF == mon_enabled)
+ return;
if ((mon_enabled & mode) == 0 || mode == MON_OFF)
- return;
+ return;
mon_enabled &= ~mode;
if (mon_enabled != MON_OFF)
- return;
+ return;
/*
- * Put everything back on the free list
+ * Move everything on the MRU list to the free list quickly,
+ * without bothering to remove each from either the MRU list or
+ * the hash table.
*/
- for (i = 0; i < MON_HASH_SIZE; i++) {
- md = mon_hash[i]; /* get next list */
- mon_hash[i] = NULL; /* zero the list head */
- while (md != NULL) {
- md_next = md->hash_next;
- md->hash_next = mon_free;
- mon_free = md;
- md = md_next;
- }
- }
-
- mon_mru_list.mru_next = &mon_mru_list;
- mon_mru_list.mru_prev = &mon_mru_list;
+ ITER_DLIST_BEGIN(mon_mru_list, mon, mru, mon_entry)
+ mon_free_entry(mon);
+ ITER_DLIST_END()
+
+ /* empty the MRU list and hash table. */
+ mru_entries = 0;
+ INIT_DLIST(mon_mru_list, mru);
+ zero_mem(mon_hash, sizeof(*mon_hash) * MON_HASH_SIZE);
}
+
+/*
+ * mon_clearinterface -- remove mru entries referring to a local address
+ * which is going away.
+ */
void
-ntp_monclearinterface(struct interface *interface)
+mon_clearinterface(
+ endpt *lcladr
+ )
{
- struct mon_data *md;
-
- for (md = mon_mru_list.mru_next; md != &mon_mru_list;
- md = md->mru_next) {
- if (md->interface == interface)
- {
- /* dequeue from mru list and put to free list */
- md->mru_prev->mru_next = md->mru_next;
- md->mru_next->mru_prev = md->mru_prev;
- remove_from_hash(md);
- md->hash_next = mon_free;
- mon_free = md;
- }
- }
+ mon_entry *mon;
+
+ /* iterate mon over mon_mru_list */
+ ITER_DLIST_BEGIN(mon_mru_list, mon, mru, mon_entry)
+ if (mon->lcladr == lcladr) {
+ /* remove from mru list */
+ UNLINK_DLIST(mon, mru);
+ /* remove from hash list, adjust mru_entries */
+ remove_from_hash(mon);
+ /* put on free list */
+ mon_free_entry(mon);
+ }
+ ITER_DLIST_END()
}
+
/*
* ntp_monitor - record stats about this packet
*
- * Returns 1 if the packet is at the head of the list, 0 otherwise.
+ * Returns supplied restriction flags, with RES_LIMITED and RES_KOD
+ * cleared unless the packet should not be responded to normally
+ * (RES_LIMITED) and possibly should trigger a KoD response (RES_KOD).
+ * The returned flags are saved in the MRU entry, so that it reflects
+ * whether the last packet from that source triggered rate limiting,
+ * and if so, possible KoD response. This implies you can not tell
+ * whether a given address is eligible for rate limiting/KoD from the
+ * monlist restrict bits, only whether or not the last packet triggered
+ * such responses. ntpdc -c reslist lets you see whether RES_LIMITED
+ * or RES_KOD is lit for a particular address before ntp_monitor()'s
+ * typical dousing.
*/
-int
+u_short
ntp_monitor(
- struct recvbuf *rbufp
+ struct recvbuf *rbufp,
+ u_short flags
)
{
- register struct pkt *pkt;
- register struct mon_data *md;
- struct sockaddr_storage addr;
- register int hash;
- register int mode;
+ l_fp interval_fp;
+ struct pkt * pkt;
+ mon_entry * mon;
+ mon_entry * oldest;
+ int oldest_age;
+ u_int hash;
+ u_short restrict_mask;
+ u_char mode;
+ u_char version;
+ int interval;
+ int head; /* headway increment */
+ int leak; /* new headway */
+ int limit; /* average threshold */
if (mon_enabled == MON_OFF)
- return 0;
+ return ~(RES_LIMITED | RES_KOD) & flags;
pkt = &rbufp->recv_pkt;
- memset(&addr, 0, sizeof(addr));
- memcpy(&addr, &(rbufp->recv_srcadr), sizeof(addr));
- hash = MON_HASH(&addr);
+ hash = MON_HASH(&rbufp->recv_srcadr);
mode = PKT_MODE(pkt->li_vn_mode);
- md = mon_hash[hash];
- while (md != NULL) {
+ version = PKT_VERSION(pkt->li_vn_mode);
+ mon = mon_hash[hash];
+
+ /*
+ * We keep track of all traffic for a given IP in one entry,
+ * otherwise cron'ed ntpdate or similar evades RES_LIMITED.
+ */
+
+ for (; mon != NULL; mon = mon->hash_next)
+ if (SOCK_EQ(&mon->rmtadr, &rbufp->recv_srcadr))
+ break;
+
+ if (mon != NULL) {
+ interval_fp = rbufp->recv_time;
+ L_SUB(&interval_fp, &mon->last);
+ /* add one-half second to round up */
+ L_ADDUF(&interval_fp, 0x80000000);
+ interval = interval_fp.l_i;
+ mon->last = rbufp->recv_time;
+ NSRCPORT(&mon->rmtadr) = NSRCPORT(&rbufp->recv_srcadr);
+ mon->count++;
+ restrict_mask = flags;
+ mon->vn_mode = VN_MODE(version, mode);
+
+ /* Shuffle to the head of the MRU list. */
+ UNLINK_DLIST(mon, mru);
+ LINK_DLIST(mon_mru_list, mon, mru);
/*
- * Match address only to conserve MRU size.
+ * At this point the most recent arrival is first in the
+ * MRU list. Decrease the counter by the headway, but
+ * not less than zero.
*/
- if (SOCKCMP(&md->rmtadr, &addr)) {
- md->drop_count = current_time - md->lasttime;
- md->lasttime = current_time;
- md->count++;
- md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
- md->mode = (u_char) mode;
- md->version = PKT_VERSION(pkt->li_vn_mode);
-
- /*
- * Shuffle to the head of the MRU list.
- */
- md->mru_next->mru_prev = md->mru_prev;
- md->mru_prev->mru_next = md->mru_next;
- md->mru_next = mon_mru_list.mru_next;
- md->mru_prev = &mon_mru_list;
- mon_mru_list.mru_next->mru_prev = md;
- mon_mru_list.mru_next = md;
- return 1;
- }
- md = md->hash_next;
+ mon->leak -= interval;
+ mon->leak = max(0, mon->leak);
+ head = 1 << ntp_minpoll;
+ leak = mon->leak + head;
+ limit = NTP_SHIFT * head;
+
+ DPRINTF(2, ("MRU: interval %d headway %d limit %d\n",
+ interval, leak, limit));
+
+ /*
+ * If the minimum and average thresholds are not
+ * exceeded, douse the RES_LIMITED and RES_KOD bits and
+ * increase the counter by the headway increment. Note
+ * that we give a 1-s grace for the minimum threshold
+ * and a 2-s grace for the headway increment. If one or
+ * both thresholds are exceeded and the old counter is
+ * less than the average threshold, set the counter to
+ * the average threshold plus the increment and leave
+ * the RES_LIMITED and RES_KOD bits lit. Otherwise,
+ * leave the counter alone and douse the RES_KOD bit.
+ * This rate-limits the KoDs to no less than the average
+ * headway.
+ */
+ if (interval + 1 >= ntp_minpkt && leak < limit) {
+ mon->leak = leak - 2;
+ restrict_mask &= ~(RES_LIMITED | RES_KOD);
+ } else if (mon->leak < limit)
+ mon->leak = limit + head;
+ else
+ restrict_mask &= ~RES_KOD;
+
+ mon->flags = restrict_mask;
+
+ return mon->flags;
}
/*
* If we got here, this is the first we've heard of this
* guy. Get him some memory, either from the free list
* or from the tail of the MRU list.
+ *
+ * The following ntp.conf "mru" knobs come into play determining
+ * the depth (or count) of the MRU list:
+ * - mru_mindepth ("mru mindepth") is a floor beneath which
+ * entries are kept without regard to their age. The
+ * default is 600 which matches the longtime implementation
+ * limit on the total number of entries.
+ * - mru_maxage ("mru maxage") is a ceiling on the age in
+ * seconds of entries. Entries older than this are
+ * reclaimed once mon_mindepth is exceeded. 64s default.
+ * Note that entries older than this can easily survive
+ * as they are reclaimed only as needed.
+ * - mru_maxdepth ("mru maxdepth") is a hard limit on the
+ * number of entries.
+ * - "mru maxmem" sets mru_maxdepth to the number of entries
+ * which fit in the given number of kilobytes. The default is
+ * 1024, or 1 megabyte.
+ * - mru_initalloc ("mru initalloc" sets the count of the
+ * initial allocation of MRU entries.
+ * - "mru initmem" sets mru_initalloc in units of kilobytes.
+ * The default is 4.
+ * - mru_incalloc ("mru incalloc" sets the number of entries to
+ * allocate on-demand each time the free list is empty.
+ * - "mru incmem" sets mru_incalloc in units of kilobytes.
+ * The default is 4.
+ * Whichever of "mru maxmem" or "mru maxdepth" occurs last in
+ * ntp.conf controls. Similarly for "mru initalloc" and "mru
+ * initmem", and for "mru incalloc" and "mru incmem".
*/
- if (mon_free == NULL && mon_total_mem >= MAXMONMEM) {
-
- /*
- * Preempt from the MRU list if old enough.
- */
- md = mon_mru_list.mru_prev;
- /* We get 31 bits from ntp_random() */
- if (((u_long)ntp_random()) / FRAC >
- (double)(current_time - md->lasttime) / mon_age)
- return 0;
-
- md->mru_prev->mru_next = &mon_mru_list;
- mon_mru_list.mru_prev = md->mru_prev;
- remove_from_hash(md);
- } else {
- if (mon_free == NULL)
+ if (mru_entries < mru_mindepth) {
+ if (NULL == mon_free)
mon_getmoremem();
- md = mon_free;
- mon_free = md->hash_next;
+ UNLINK_HEAD_SLIST(mon, mon_free, hash_next);
+ } else {
+ oldest = TAIL_DLIST(mon_mru_list, mru);
+ oldest_age = 0; /* silence uninit warning */
+ if (oldest != NULL) {
+ interval_fp = rbufp->recv_time;
+ L_SUB(&interval_fp, &oldest->last);
+ /* add one-half second to round up */
+ L_ADDUF(&interval_fp, 0x80000000);
+ oldest_age = interval_fp.l_i;
+ }
+ /* note -1 is legal for mru_maxage (disables) */
+ if (oldest != NULL && mru_maxage < oldest_age) {
+ mon_reclaim_entry(oldest);
+ mon = oldest;
+ } else if (mon_free != NULL || mru_alloc <
+ mru_maxdepth) {
+ if (NULL == mon_free)
+ mon_getmoremem();
+ UNLINK_HEAD_SLIST(mon, mon_free, hash_next);
+ /* Preempt from the MRU list if old enough. */
+ } else if (ntp_random() / (2. * FRAC) >
+ (double)oldest_age / mon_age) {
+ return ~(RES_LIMITED | RES_KOD) & flags;
+ } else {
+ mon_reclaim_entry(oldest);
+ mon = oldest;
+ }
}
/*
* Got one, initialize it
*/
- md->avg_interval = 0;
- md->lasttime = current_time;
- md->count = 1;
- md->drop_count = 0;
- memset(&md->rmtadr, 0, sizeof(md->rmtadr));
- memcpy(&md->rmtadr, &addr, sizeof(addr));
- md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
- md->mode = (u_char) mode;
- md->version = PKT_VERSION(pkt->li_vn_mode);
- md->interface = rbufp->dstadr;
- md->cast_flags = (u_char)(((rbufp->dstadr->flags & INT_MCASTOPEN) &&
- rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd ==
- md->interface->bfd ? MDF_BCAST : MDF_UCAST);
+ mru_entries++;
+ mru_peakentries = max(mru_peakentries, mru_entries);
+ mon->last = rbufp->recv_time;
+ mon->first = mon->last;
+ mon->count = 1;
+ mon->flags = ~(RES_LIMITED | RES_KOD) & flags;
+ mon->leak = 0;
+ memcpy(&mon->rmtadr, &rbufp->recv_srcadr, sizeof(mon->rmtadr));
+ mon->vn_mode = VN_MODE(version, mode);
+ mon->lcladr = rbufp->dstadr;
+ mon->cast_flags = (u_char)(((rbufp->dstadr->flags &
+ INT_MCASTOPEN) && rbufp->fd == mon->lcladr->fd) ? MDF_MCAST
+ : rbufp->fd == mon->lcladr->bfd ? MDF_BCAST : MDF_UCAST);
/*
* Drop him into front of the hash table. Also put him on top of
* the MRU list.
*/
- md->hash_next = mon_hash[hash];
- mon_hash[hash] = md;
- md->mru_next = mon_mru_list.mru_next;
- md->mru_prev = &mon_mru_list;
- mon_mru_list.mru_next->mru_prev = md;
- mon_mru_list.mru_next = md;
- return 1;
-}
-
+ LINK_SLIST(mon_hash[hash], mon, hash_next);
+ LINK_DLIST(mon_mru_list, mon, mru);
-/*
- * mon_getmoremem - get more memory and put it on the free list
- */
-static void
-mon_getmoremem(void)
-{
- register struct mon_data *md;
- register int i;
- struct mon_data *freedata; /* 'old' free list (null) */
-
- md = (struct mon_data *)emalloc(MONMEMINC *
- sizeof(struct mon_data));
- freedata = mon_free;
- mon_free = md;
- for (i = 0; i < (MONMEMINC-1); i++) {
- md->hash_next = (md + 1);
- md++;
- }
-
- /*
- * md now points at the last. Link in the rest of the chain.
- */
- md->hash_next = freedata;
- mon_total_mem += MONMEMINC;
- mon_mem_increments++;
+ return mon->flags;
}
-static void
-remove_from_hash(
- struct mon_data *md
- )
-{
- register int hash;
- register struct mon_data *md_prev;
- hash = MON_HASH(&md->rmtadr);
- if (mon_hash[hash] == md) {
- mon_hash[hash] = md->hash_next;
- } else {
- md_prev = mon_hash[hash];
- while (md_prev->hash_next != md) {
- md_prev = md_prev->hash_next;
- if (md_prev == NULL) {
- /* logic error */
- return;
- }
- }
- md_prev->hash_next = md->hash_next;
- }
-}
diff --git a/contrib/ntp/ntpd/ntp_parser.c b/contrib/ntp/ntpd/ntp_parser.c
new file mode 100644
index 0000000..d76ac33
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_parser.c
@@ -0,0 +1,3888 @@
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.7.12-4996"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+/* Line 371 of yacc.c */
+#line 11 "../../ntpd/ntp_parser.y"
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+ #endif
+
+ #include "ntp.h"
+ #include "ntpd.h"
+ #include "ntp_machine.h"
+ #include "ntp_stdlib.h"
+ #include "ntp_filegen.h"
+ #include "ntp_scanner.h"
+ #include "ntp_config.h"
+ #include "ntp_crypto.h"
+
+ #include "ntpsim.h" /* HMS: Do we really want this all the time? */
+ /* SK: It might be a good idea to always
+ include the simulator code. That way
+ someone can use the same configuration file
+ for both the simulator and the daemon
+ */
+
+ #define YYMALLOC emalloc
+ #define YYFREE free
+ #define YYERROR_VERBOSE
+ #define YYMAXDEPTH 1000 /* stop the madness sooner */
+ void yyerror(const char *msg);
+
+ #ifdef SIM
+ # define ONLY_SIM(a) (a)
+ #else
+ # define ONLY_SIM(a) NULL
+ #endif
+
+/* Line 371 of yacc.c */
+#line 102 "ntp_parser.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef YY_YY_NTP_PARSER_H_INCLUDED
+# define YY_YY_NTP_PARSER_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_Abbrev = 258,
+ T_Age = 259,
+ T_All = 260,
+ T_Allan = 261,
+ T_Allpeers = 262,
+ T_Auth = 263,
+ T_Autokey = 264,
+ T_Automax = 265,
+ T_Average = 266,
+ T_Bclient = 267,
+ T_Beacon = 268,
+ T_Broadcast = 269,
+ T_Broadcastclient = 270,
+ T_Broadcastdelay = 271,
+ T_Burst = 272,
+ T_Calibrate = 273,
+ T_Ceiling = 274,
+ T_Clockstats = 275,
+ T_Cohort = 276,
+ T_ControlKey = 277,
+ T_Crypto = 278,
+ T_Cryptostats = 279,
+ T_Ctl = 280,
+ T_Day = 281,
+ T_Default = 282,
+ T_Digest = 283,
+ T_Disable = 284,
+ T_Discard = 285,
+ T_Dispersion = 286,
+ T_Double = 287,
+ T_Driftfile = 288,
+ T_Drop = 289,
+ T_Dscp = 290,
+ T_Ellipsis = 291,
+ T_Enable = 292,
+ T_End = 293,
+ T_False = 294,
+ T_File = 295,
+ T_Filegen = 296,
+ T_Filenum = 297,
+ T_Flag1 = 298,
+ T_Flag2 = 299,
+ T_Flag3 = 300,
+ T_Flag4 = 301,
+ T_Flake = 302,
+ T_Floor = 303,
+ T_Freq = 304,
+ T_Fudge = 305,
+ T_Host = 306,
+ T_Huffpuff = 307,
+ T_Iburst = 308,
+ T_Ident = 309,
+ T_Ignore = 310,
+ T_Incalloc = 311,
+ T_Incmem = 312,
+ T_Initalloc = 313,
+ T_Initmem = 314,
+ T_Includefile = 315,
+ T_Integer = 316,
+ T_Interface = 317,
+ T_Intrange = 318,
+ T_Io = 319,
+ T_Ipv4 = 320,
+ T_Ipv4_flag = 321,
+ T_Ipv6 = 322,
+ T_Ipv6_flag = 323,
+ T_Kernel = 324,
+ T_Key = 325,
+ T_Keys = 326,
+ T_Keysdir = 327,
+ T_Kod = 328,
+ T_Mssntp = 329,
+ T_Leapfile = 330,
+ T_Leapsmearinterval = 331,
+ T_Limited = 332,
+ T_Link = 333,
+ T_Listen = 334,
+ T_Logconfig = 335,
+ T_Logfile = 336,
+ T_Loopstats = 337,
+ T_Lowpriotrap = 338,
+ T_Manycastclient = 339,
+ T_Manycastserver = 340,
+ T_Mask = 341,
+ T_Maxage = 342,
+ T_Maxclock = 343,
+ T_Maxdepth = 344,
+ T_Maxdist = 345,
+ T_Maxmem = 346,
+ T_Maxpoll = 347,
+ T_Mdnstries = 348,
+ T_Mem = 349,
+ T_Memlock = 350,
+ T_Minclock = 351,
+ T_Mindepth = 352,
+ T_Mindist = 353,
+ T_Minimum = 354,
+ T_Minpoll = 355,
+ T_Minsane = 356,
+ T_Mode = 357,
+ T_Mode7 = 358,
+ T_Monitor = 359,
+ T_Month = 360,
+ T_Mru = 361,
+ T_Multicastclient = 362,
+ T_Nic = 363,
+ T_Nolink = 364,
+ T_Nomodify = 365,
+ T_Nomrulist = 366,
+ T_None = 367,
+ T_Nonvolatile = 368,
+ T_Nopeer = 369,
+ T_Noquery = 370,
+ T_Noselect = 371,
+ T_Noserve = 372,
+ T_Notrap = 373,
+ T_Notrust = 374,
+ T_Ntp = 375,
+ T_Ntpport = 376,
+ T_NtpSignDsocket = 377,
+ T_Orphan = 378,
+ T_Orphanwait = 379,
+ T_Panic = 380,
+ T_Peer = 381,
+ T_Peerstats = 382,
+ T_Phone = 383,
+ T_Pid = 384,
+ T_Pidfile = 385,
+ T_Pool = 386,
+ T_Port = 387,
+ T_Preempt = 388,
+ T_Prefer = 389,
+ T_Protostats = 390,
+ T_Pw = 391,
+ T_Randfile = 392,
+ T_Rawstats = 393,
+ T_Refid = 394,
+ T_Requestkey = 395,
+ T_Reset = 396,
+ T_Restrict = 397,
+ T_Revoke = 398,
+ T_Rlimit = 399,
+ T_Saveconfigdir = 400,
+ T_Server = 401,
+ T_Setvar = 402,
+ T_Source = 403,
+ T_Stacksize = 404,
+ T_Statistics = 405,
+ T_Stats = 406,
+ T_Statsdir = 407,
+ T_Step = 408,
+ T_Stepback = 409,
+ T_Stepfwd = 410,
+ T_Stepout = 411,
+ T_Stratum = 412,
+ T_String = 413,
+ T_Sys = 414,
+ T_Sysstats = 415,
+ T_Tick = 416,
+ T_Time1 = 417,
+ T_Time2 = 418,
+ T_Timer = 419,
+ T_Timingstats = 420,
+ T_Tinker = 421,
+ T_Tos = 422,
+ T_Trap = 423,
+ T_True = 424,
+ T_Trustedkey = 425,
+ T_Ttl = 426,
+ T_Type = 427,
+ T_U_int = 428,
+ T_Unconfig = 429,
+ T_Unpeer = 430,
+ T_Version = 431,
+ T_WanderThreshold = 432,
+ T_Week = 433,
+ T_Wildcard = 434,
+ T_Xleave = 435,
+ T_Year = 436,
+ T_Flag = 437,
+ T_EOC = 438,
+ T_Simulate = 439,
+ T_Beep_Delay = 440,
+ T_Sim_Duration = 441,
+ T_Server_Offset = 442,
+ T_Duration = 443,
+ T_Freq_Offset = 444,
+ T_Wander = 445,
+ T_Jitter = 446,
+ T_Prop_Delay = 447,
+ T_Proc_Delay = 448
+ };
+#endif
+/* Tokens. */
+#define T_Abbrev 258
+#define T_Age 259
+#define T_All 260
+#define T_Allan 261
+#define T_Allpeers 262
+#define T_Auth 263
+#define T_Autokey 264
+#define T_Automax 265
+#define T_Average 266
+#define T_Bclient 267
+#define T_Beacon 268
+#define T_Broadcast 269
+#define T_Broadcastclient 270
+#define T_Broadcastdelay 271
+#define T_Burst 272
+#define T_Calibrate 273
+#define T_Ceiling 274
+#define T_Clockstats 275
+#define T_Cohort 276
+#define T_ControlKey 277
+#define T_Crypto 278
+#define T_Cryptostats 279
+#define T_Ctl 280
+#define T_Day 281
+#define T_Default 282
+#define T_Digest 283
+#define T_Disable 284
+#define T_Discard 285
+#define T_Dispersion 286
+#define T_Double 287
+#define T_Driftfile 288
+#define T_Drop 289
+#define T_Dscp 290
+#define T_Ellipsis 291
+#define T_Enable 292
+#define T_End 293
+#define T_False 294
+#define T_File 295
+#define T_Filegen 296
+#define T_Filenum 297
+#define T_Flag1 298
+#define T_Flag2 299
+#define T_Flag3 300
+#define T_Flag4 301
+#define T_Flake 302
+#define T_Floor 303
+#define T_Freq 304
+#define T_Fudge 305
+#define T_Host 306
+#define T_Huffpuff 307
+#define T_Iburst 308
+#define T_Ident 309
+#define T_Ignore 310
+#define T_Incalloc 311
+#define T_Incmem 312
+#define T_Initalloc 313
+#define T_Initmem 314
+#define T_Includefile 315
+#define T_Integer 316
+#define T_Interface 317
+#define T_Intrange 318
+#define T_Io 319
+#define T_Ipv4 320
+#define T_Ipv4_flag 321
+#define T_Ipv6 322
+#define T_Ipv6_flag 323
+#define T_Kernel 324
+#define T_Key 325
+#define T_Keys 326
+#define T_Keysdir 327
+#define T_Kod 328
+#define T_Mssntp 329
+#define T_Leapfile 330
+#define T_Leapsmearinterval 331
+#define T_Limited 332
+#define T_Link 333
+#define T_Listen 334
+#define T_Logconfig 335
+#define T_Logfile 336
+#define T_Loopstats 337
+#define T_Lowpriotrap 338
+#define T_Manycastclient 339
+#define T_Manycastserver 340
+#define T_Mask 341
+#define T_Maxage 342
+#define T_Maxclock 343
+#define T_Maxdepth 344
+#define T_Maxdist 345
+#define T_Maxmem 346
+#define T_Maxpoll 347
+#define T_Mdnstries 348
+#define T_Mem 349
+#define T_Memlock 350
+#define T_Minclock 351
+#define T_Mindepth 352
+#define T_Mindist 353
+#define T_Minimum 354
+#define T_Minpoll 355
+#define T_Minsane 356
+#define T_Mode 357
+#define T_Mode7 358
+#define T_Monitor 359
+#define T_Month 360
+#define T_Mru 361
+#define T_Multicastclient 362
+#define T_Nic 363
+#define T_Nolink 364
+#define T_Nomodify 365
+#define T_Nomrulist 366
+#define T_None 367
+#define T_Nonvolatile 368
+#define T_Nopeer 369
+#define T_Noquery 370
+#define T_Noselect 371
+#define T_Noserve 372
+#define T_Notrap 373
+#define T_Notrust 374
+#define T_Ntp 375
+#define T_Ntpport 376
+#define T_NtpSignDsocket 377
+#define T_Orphan 378
+#define T_Orphanwait 379
+#define T_Panic 380
+#define T_Peer 381
+#define T_Peerstats 382
+#define T_Phone 383
+#define T_Pid 384
+#define T_Pidfile 385
+#define T_Pool 386
+#define T_Port 387
+#define T_Preempt 388
+#define T_Prefer 389
+#define T_Protostats 390
+#define T_Pw 391
+#define T_Randfile 392
+#define T_Rawstats 393
+#define T_Refid 394
+#define T_Requestkey 395
+#define T_Reset 396
+#define T_Restrict 397
+#define T_Revoke 398
+#define T_Rlimit 399
+#define T_Saveconfigdir 400
+#define T_Server 401
+#define T_Setvar 402
+#define T_Source 403
+#define T_Stacksize 404
+#define T_Statistics 405
+#define T_Stats 406
+#define T_Statsdir 407
+#define T_Step 408
+#define T_Stepback 409
+#define T_Stepfwd 410
+#define T_Stepout 411
+#define T_Stratum 412
+#define T_String 413
+#define T_Sys 414
+#define T_Sysstats 415
+#define T_Tick 416
+#define T_Time1 417
+#define T_Time2 418
+#define T_Timer 419
+#define T_Timingstats 420
+#define T_Tinker 421
+#define T_Tos 422
+#define T_Trap 423
+#define T_True 424
+#define T_Trustedkey 425
+#define T_Ttl 426
+#define T_Type 427
+#define T_U_int 428
+#define T_Unconfig 429
+#define T_Unpeer 430
+#define T_Version 431
+#define T_WanderThreshold 432
+#define T_Week 433
+#define T_Wildcard 434
+#define T_Xleave 435
+#define T_Year 436
+#define T_Flag 437
+#define T_EOC 438
+#define T_Simulate 439
+#define T_Beep_Delay 440
+#define T_Sim_Duration 441
+#define T_Server_Offset 442
+#define T_Duration 443
+#define T_Freq_Offset 444
+#define T_Wander 445
+#define T_Jitter 446
+#define T_Prop_Delay 447
+#define T_Proc_Delay 448
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 387 of yacc.c */
+#line 51 "../../ntpd/ntp_parser.y"
+
+ char * String;
+ double Double;
+ int Integer;
+ unsigned U_int;
+ gen_fifo * Generic_fifo;
+ attr_val * Attr_val;
+ attr_val_fifo * Attr_val_fifo;
+ int_fifo * Int_fifo;
+ string_fifo * String_fifo;
+ address_node * Address_node;
+ address_fifo * Address_fifo;
+ setvar_node * Set_var;
+ server_info * Sim_server;
+ server_info_fifo * Sim_server_fifo;
+ script_info * Sim_script;
+ script_info_fifo * Sim_script_fifo;
+
+
+/* Line 387 of yacc.c */
+#line 551 "ntp_parser.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_NTP_PARSER_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+/* Line 390 of yacc.c */
+#line 579 "ntp_parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 210
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 647
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 199
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 105
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 313
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 419
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 448
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 195, 196, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 194, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 197, 2, 198, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 5, 9, 12, 15, 16, 18, 20,
+ 22, 24, 26, 28, 30, 32, 34, 36, 38, 40,
+ 42, 46, 48, 50, 52, 54, 56, 58, 61, 63,
+ 65, 67, 68, 71, 73, 75, 77, 79, 81, 83,
+ 85, 87, 89, 91, 93, 95, 98, 101, 103, 105,
+ 107, 109, 111, 113, 116, 118, 121, 123, 125, 127,
+ 130, 133, 136, 139, 142, 145, 148, 151, 154, 157,
+ 160, 163, 164, 167, 170, 173, 175, 177, 179, 181,
+ 183, 186, 189, 191, 194, 197, 200, 202, 204, 206,
+ 208, 210, 212, 214, 216, 218, 220, 223, 226, 230,
+ 233, 235, 237, 239, 241, 243, 245, 247, 249, 251,
+ 252, 255, 258, 261, 263, 265, 267, 269, 271, 273,
+ 275, 277, 279, 281, 283, 285, 287, 290, 293, 297,
+ 303, 307, 312, 317, 321, 322, 325, 327, 329, 331,
+ 333, 335, 337, 339, 341, 343, 345, 347, 349, 351,
+ 353, 355, 358, 360, 363, 365, 367, 369, 372, 374,
+ 377, 379, 381, 383, 385, 387, 389, 391, 393, 397,
+ 400, 402, 405, 408, 411, 414, 417, 419, 421, 423,
+ 425, 427, 429, 432, 435, 437, 440, 442, 444, 446,
+ 449, 452, 455, 457, 459, 461, 463, 465, 467, 469,
+ 471, 473, 475, 477, 480, 483, 485, 488, 490, 492,
+ 494, 496, 498, 500, 502, 504, 506, 508, 510, 512,
+ 515, 518, 521, 524, 528, 530, 533, 536, 539, 542,
+ 546, 549, 551, 553, 555, 557, 559, 561, 563, 565,
+ 567, 569, 571, 574, 575, 580, 582, 583, 584, 587,
+ 590, 593, 596, 598, 600, 604, 608, 610, 612, 614,
+ 616, 618, 620, 622, 624, 626, 629, 632, 634, 636,
+ 638, 640, 642, 644, 646, 648, 651, 653, 656, 658,
+ 660, 662, 668, 671, 673, 676, 678, 680, 682, 684,
+ 686, 688, 694, 696, 700, 703, 707, 709, 711, 714,
+ 716, 722, 727, 731, 734, 736, 743, 747, 750, 754,
+ 756, 758, 760, 762
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 200, 0, -1, 201, -1, 201, 202, 183, -1, 202,
+ 183, -1, 1, 183, -1, -1, 203, -1, 216, -1,
+ 218, -1, 219, -1, 228, -1, 236, -1, 223, -1,
+ 245, -1, 250, -1, 254, -1, 259, -1, 263, -1,
+ 290, -1, 204, 205, 208, -1, 146, -1, 131, -1,
+ 126, -1, 14, -1, 84, -1, 206, -1, 207, 158,
+ -1, 158, -1, 66, -1, 68, -1, -1, 208, 209,
+ -1, 210, -1, 212, -1, 214, -1, 211, -1, 9,
+ -1, 17, -1, 53, -1, 116, -1, 133, -1, 134,
+ -1, 169, -1, 180, -1, 213, 61, -1, 213, 173,
+ -1, 70, -1, 100, -1, 92, -1, 171, -1, 102,
+ -1, 176, -1, 215, 158, -1, 54, -1, 217, 205,
+ -1, 174, -1, 175, -1, 15, -1, 85, 287, -1,
+ 107, 287, -1, 93, 61, -1, 10, 61, -1, 22,
+ 61, -1, 23, 220, -1, 71, 158, -1, 72, 158,
+ -1, 140, 61, -1, 143, 61, -1, 170, 283, -1,
+ 122, 158, -1, -1, 220, 221, -1, 222, 158, -1,
+ 143, 61, -1, 51, -1, 54, -1, 136, -1, 137,
+ -1, 28, -1, 167, 224, -1, 224, 225, -1, 225,
+ -1, 226, 61, -1, 227, 289, -1, 21, 288, -1,
+ 19, -1, 48, -1, 123, -1, 124, -1, 101, -1,
+ 13, -1, 98, -1, 90, -1, 96, -1, 88, -1,
+ 150, 229, -1, 152, 158, -1, 41, 230, 231, -1,
+ 229, 230, -1, 230, -1, 20, -1, 24, -1, 82,
+ -1, 127, -1, 138, -1, 160, -1, 165, -1, 135,
+ -1, -1, 231, 232, -1, 40, 158, -1, 172, 235,
+ -1, 233, -1, 234, -1, 78, -1, 109, -1, 37,
+ -1, 29, -1, 112, -1, 129, -1, 26, -1, 178,
+ -1, 105, -1, 181, -1, 4, -1, 30, 239, -1,
+ 106, 242, -1, 142, 205, 237, -1, 142, 206, 86,
+ 206, 237, -1, 142, 27, 237, -1, 142, 66, 27,
+ 237, -1, 142, 68, 27, 237, -1, 142, 148, 237,
+ -1, -1, 237, 238, -1, 47, -1, 55, -1, 73,
+ -1, 74, -1, 77, -1, 83, -1, 110, -1, 111,
+ -1, 114, -1, 115, -1, 117, -1, 118, -1, 119,
+ -1, 121, -1, 176, -1, 239, 240, -1, 240, -1,
+ 241, 61, -1, 11, -1, 99, -1, 104, -1, 242,
+ 243, -1, 243, -1, 244, 61, -1, 56, -1, 57,
+ -1, 58, -1, 59, -1, 87, -1, 89, -1, 91,
+ -1, 97, -1, 50, 205, 246, -1, 246, 247, -1,
+ 247, -1, 248, 289, -1, 249, 288, -1, 157, 61,
+ -1, 3, 158, -1, 139, 158, -1, 162, -1, 163,
+ -1, 43, -1, 44, -1, 45, -1, 46, -1, 144,
+ 251, -1, 251, 252, -1, 252, -1, 253, 61, -1,
+ 95, -1, 149, -1, 42, -1, 37, 255, -1, 29,
+ 255, -1, 255, 256, -1, 256, -1, 257, -1, 258,
+ -1, 8, -1, 12, -1, 18, -1, 69, -1, 104,
+ -1, 120, -1, 103, -1, 151, -1, 166, 260, -1,
+ 260, 261, -1, 261, -1, 262, 289, -1, 6, -1,
+ 31, -1, 49, -1, 52, -1, 125, -1, 153, -1,
+ 154, -1, 155, -1, 156, -1, 161, -1, 275, -1,
+ 279, -1, 264, 289, -1, 265, 61, -1, 266, 158,
+ -1, 267, 158, -1, 60, 158, 202, -1, 38, -1,
+ 33, 268, -1, 80, 273, -1, 128, 286, -1, 147,
+ 269, -1, 168, 206, 271, -1, 171, 282, -1, 16,
+ -1, 113, -1, 161, -1, 35, -1, 76, -1, 54,
+ -1, 75, -1, 130, -1, 81, -1, 145, -1, 158,
+ -1, 158, 32, -1, -1, 158, 194, 158, 270, -1,
+ 27, -1, -1, -1, 271, 272, -1, 132, 61, -1,
+ 62, 206, -1, 273, 274, -1, 274, -1, 158, -1,
+ 276, 278, 277, -1, 276, 278, 158, -1, 62, -1,
+ 108, -1, 5, -1, 65, -1, 67, -1, 179, -1,
+ 79, -1, 55, -1, 34, -1, 141, 280, -1, 280,
+ 281, -1, 281, -1, 7, -1, 8, -1, 25, -1,
+ 64, -1, 94, -1, 159, -1, 164, -1, 282, 61,
+ -1, 61, -1, 283, 284, -1, 284, -1, 61, -1,
+ 285, -1, 195, 61, 36, 61, 196, -1, 286, 158,
+ -1, 158, -1, 287, 205, -1, 205, -1, 61, -1,
+ 169, -1, 39, -1, 61, -1, 32, -1, 291, 197,
+ 292, 295, 198, -1, 184, -1, 292, 293, 183, -1,
+ 293, 183, -1, 294, 194, 289, -1, 185, -1, 186,
+ -1, 295, 296, -1, 296, -1, 298, 197, 297, 299,
+ 198, -1, 187, 194, 289, 183, -1, 146, 194, 205,
+ -1, 299, 300, -1, 300, -1, 188, 194, 289, 197,
+ 301, 198, -1, 301, 302, 183, -1, 302, 183, -1,
+ 303, 194, 289, -1, 189, -1, 190, -1, 191, -1,
+ 192, -1, 193, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 366, 366, 370, 371, 372, 387, 388, 389, 390,
+ 391, 392, 393, 394, 395, 396, 397, 398, 399, 400,
+ 408, 418, 419, 420, 421, 422, 426, 427, 432, 437,
+ 439, 445, 446, 454, 455, 456, 460, 465, 466, 467,
+ 468, 469, 470, 471, 472, 476, 478, 483, 484, 485,
+ 486, 487, 488, 492, 497, 506, 516, 517, 527, 529,
+ 531, 533, 544, 551, 553, 558, 560, 562, 564, 566,
+ 575, 581, 582, 590, 592, 604, 605, 606, 607, 608,
+ 617, 622, 627, 635, 637, 639, 644, 645, 646, 647,
+ 648, 649, 653, 654, 655, 656, 665, 667, 676, 686,
+ 691, 699, 700, 701, 702, 703, 704, 705, 706, 711,
+ 712, 720, 730, 739, 754, 759, 760, 764, 765, 769,
+ 770, 771, 772, 773, 774, 775, 784, 788, 792, 800,
+ 808, 816, 831, 846, 859, 860, 868, 869, 870, 871,
+ 872, 873, 874, 875, 876, 877, 878, 879, 880, 881,
+ 882, 886, 891, 899, 904, 905, 906, 910, 915, 923,
+ 928, 929, 930, 931, 932, 933, 934, 935, 943, 953,
+ 958, 966, 968, 970, 972, 974, 979, 980, 984, 985,
+ 986, 987, 995, 1000, 1005, 1013, 1018, 1019, 1020, 1029,
+ 1031, 1036, 1041, 1049, 1051, 1068, 1069, 1070, 1071, 1072,
+ 1073, 1077, 1078, 1086, 1091, 1096, 1104, 1109, 1110, 1111,
+ 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1127, 1128, 1129,
+ 1136, 1143, 1150, 1166, 1185, 1187, 1189, 1191, 1193, 1195,
+ 1202, 1207, 1208, 1209, 1213, 1217, 1226, 1227, 1228, 1232,
+ 1233, 1237, 1244, 1254, 1263, 1268, 1270, 1275, 1276, 1284,
+ 1286, 1294, 1299, 1307, 1332, 1339, 1349, 1350, 1354, 1355,
+ 1356, 1357, 1361, 1362, 1363, 1367, 1372, 1377, 1385, 1386,
+ 1387, 1388, 1389, 1390, 1391, 1401, 1406, 1414, 1419, 1427,
+ 1429, 1433, 1438, 1443, 1451, 1456, 1464, 1473, 1474, 1478,
+ 1479, 1488, 1506, 1510, 1515, 1523, 1528, 1529, 1533, 1538,
+ 1546, 1551, 1556, 1561, 1566, 1574, 1579, 1584, 1592, 1597,
+ 1598, 1599, 1600, 1601
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 1
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "T_Abbrev", "T_Age", "T_All", "T_Allan",
+ "T_Allpeers", "T_Auth", "T_Autokey", "T_Automax", "T_Average",
+ "T_Bclient", "T_Beacon", "T_Broadcast", "T_Broadcastclient",
+ "T_Broadcastdelay", "T_Burst", "T_Calibrate", "T_Ceiling",
+ "T_Clockstats", "T_Cohort", "T_ControlKey", "T_Crypto", "T_Cryptostats",
+ "T_Ctl", "T_Day", "T_Default", "T_Digest", "T_Disable", "T_Discard",
+ "T_Dispersion", "T_Double", "T_Driftfile", "T_Drop", "T_Dscp",
+ "T_Ellipsis", "T_Enable", "T_End", "T_False", "T_File", "T_Filegen",
+ "T_Filenum", "T_Flag1", "T_Flag2", "T_Flag3", "T_Flag4", "T_Flake",
+ "T_Floor", "T_Freq", "T_Fudge", "T_Host", "T_Huffpuff", "T_Iburst",
+ "T_Ident", "T_Ignore", "T_Incalloc", "T_Incmem", "T_Initalloc",
+ "T_Initmem", "T_Includefile", "T_Integer", "T_Interface", "T_Intrange",
+ "T_Io", "T_Ipv4", "T_Ipv4_flag", "T_Ipv6", "T_Ipv6_flag", "T_Kernel",
+ "T_Key", "T_Keys", "T_Keysdir", "T_Kod", "T_Mssntp", "T_Leapfile",
+ "T_Leapsmearinterval", "T_Limited", "T_Link", "T_Listen", "T_Logconfig",
+ "T_Logfile", "T_Loopstats", "T_Lowpriotrap", "T_Manycastclient",
+ "T_Manycastserver", "T_Mask", "T_Maxage", "T_Maxclock", "T_Maxdepth",
+ "T_Maxdist", "T_Maxmem", "T_Maxpoll", "T_Mdnstries", "T_Mem",
+ "T_Memlock", "T_Minclock", "T_Mindepth", "T_Mindist", "T_Minimum",
+ "T_Minpoll", "T_Minsane", "T_Mode", "T_Mode7", "T_Monitor", "T_Month",
+ "T_Mru", "T_Multicastclient", "T_Nic", "T_Nolink", "T_Nomodify",
+ "T_Nomrulist", "T_None", "T_Nonvolatile", "T_Nopeer", "T_Noquery",
+ "T_Noselect", "T_Noserve", "T_Notrap", "T_Notrust", "T_Ntp", "T_Ntpport",
+ "T_NtpSignDsocket", "T_Orphan", "T_Orphanwait", "T_Panic", "T_Peer",
+ "T_Peerstats", "T_Phone", "T_Pid", "T_Pidfile", "T_Pool", "T_Port",
+ "T_Preempt", "T_Prefer", "T_Protostats", "T_Pw", "T_Randfile",
+ "T_Rawstats", "T_Refid", "T_Requestkey", "T_Reset", "T_Restrict",
+ "T_Revoke", "T_Rlimit", "T_Saveconfigdir", "T_Server", "T_Setvar",
+ "T_Source", "T_Stacksize", "T_Statistics", "T_Stats", "T_Statsdir",
+ "T_Step", "T_Stepback", "T_Stepfwd", "T_Stepout", "T_Stratum",
+ "T_String", "T_Sys", "T_Sysstats", "T_Tick", "T_Time1", "T_Time2",
+ "T_Timer", "T_Timingstats", "T_Tinker", "T_Tos", "T_Trap", "T_True",
+ "T_Trustedkey", "T_Ttl", "T_Type", "T_U_int", "T_Unconfig", "T_Unpeer",
+ "T_Version", "T_WanderThreshold", "T_Week", "T_Wildcard", "T_Xleave",
+ "T_Year", "T_Flag", "T_EOC", "T_Simulate", "T_Beep_Delay",
+ "T_Sim_Duration", "T_Server_Offset", "T_Duration", "T_Freq_Offset",
+ "T_Wander", "T_Jitter", "T_Prop_Delay", "T_Proc_Delay", "'='", "'('",
+ "')'", "'{'", "'}'", "$accept", "configuration", "command_list",
+ "command", "server_command", "client_type", "address", "ip_address",
+ "address_fam", "option_list", "option", "option_flag",
+ "option_flag_keyword", "option_int", "option_int_keyword", "option_str",
+ "option_str_keyword", "unpeer_command", "unpeer_keyword",
+ "other_mode_command", "authentication_command", "crypto_command_list",
+ "crypto_command", "crypto_str_keyword", "orphan_mode_command",
+ "tos_option_list", "tos_option", "tos_option_int_keyword",
+ "tos_option_dbl_keyword", "monitoring_command", "stats_list", "stat",
+ "filegen_option_list", "filegen_option", "link_nolink", "enable_disable",
+ "filegen_type", "access_control_command", "ac_flag_list",
+ "access_control_flag", "discard_option_list", "discard_option",
+ "discard_option_keyword", "mru_option_list", "mru_option",
+ "mru_option_keyword", "fudge_command", "fudge_factor_list",
+ "fudge_factor", "fudge_factor_dbl_keyword", "fudge_factor_bool_keyword",
+ "rlimit_command", "rlimit_option_list", "rlimit_option",
+ "rlimit_option_keyword", "system_option_command", "system_option_list",
+ "system_option", "system_option_flag_keyword",
+ "system_option_local_flag_keyword", "tinker_command",
+ "tinker_option_list", "tinker_option", "tinker_option_keyword",
+ "miscellaneous_command", "misc_cmd_dbl_keyword", "misc_cmd_int_keyword",
+ "misc_cmd_str_keyword", "misc_cmd_str_lcl_keyword", "drift_parm",
+ "variable_assign", "t_default_or_zero", "trap_option_list",
+ "trap_option", "log_config_list", "log_config_command",
+ "interface_command", "interface_nic", "nic_rule_class",
+ "nic_rule_action", "reset_command", "counter_set_list",
+ "counter_set_keyword", "integer_list", "integer_list_range",
+ "integer_list_range_elt", "integer_range", "string_list", "address_list",
+ "boolean", "number", "simulate_command", "sim_conf_start",
+ "sim_init_statement_list", "sim_init_statement", "sim_init_keyword",
+ "sim_server_list", "sim_server", "sim_server_offset", "sim_server_name",
+ "sim_act_list", "sim_act", "sim_act_stmt_list", "sim_act_stmt",
+ "sim_act_keyword", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 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, 61, 40, 41, 123, 125
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint16 yyr1[] =
+{
+ 0, 199, 200, 201, 201, 201, 202, 202, 202, 202,
+ 202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
+ 203, 204, 204, 204, 204, 204, 205, 205, 206, 207,
+ 207, 208, 208, 209, 209, 209, 210, 211, 211, 211,
+ 211, 211, 211, 211, 211, 212, 212, 213, 213, 213,
+ 213, 213, 213, 214, 215, 216, 217, 217, 218, 218,
+ 218, 218, 219, 219, 219, 219, 219, 219, 219, 219,
+ 219, 220, 220, 221, 221, 222, 222, 222, 222, 222,
+ 223, 224, 224, 225, 225, 225, 226, 226, 226, 226,
+ 226, 226, 227, 227, 227, 227, 228, 228, 228, 229,
+ 229, 230, 230, 230, 230, 230, 230, 230, 230, 231,
+ 231, 232, 232, 232, 232, 233, 233, 234, 234, 235,
+ 235, 235, 235, 235, 235, 235, 236, 236, 236, 236,
+ 236, 236, 236, 236, 237, 237, 238, 238, 238, 238,
+ 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
+ 238, 239, 239, 240, 241, 241, 241, 242, 242, 243,
+ 244, 244, 244, 244, 244, 244, 244, 244, 245, 246,
+ 246, 247, 247, 247, 247, 247, 248, 248, 249, 249,
+ 249, 249, 250, 251, 251, 252, 253, 253, 253, 254,
+ 254, 255, 255, 256, 256, 257, 257, 257, 257, 257,
+ 257, 258, 258, 259, 260, 260, 261, 262, 262, 262,
+ 262, 262, 262, 262, 262, 262, 262, 263, 263, 263,
+ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263,
+ 263, 264, 264, 264, 265, 265, 266, 266, 266, 267,
+ 267, 268, 268, 268, 269, 270, 270, 271, 271, 272,
+ 272, 273, 273, 274, 275, 275, 276, 276, 277, 277,
+ 277, 277, 278, 278, 278, 279, 280, 280, 281, 281,
+ 281, 281, 281, 281, 281, 282, 282, 283, 283, 284,
+ 284, 285, 286, 286, 287, 287, 288, 288, 288, 289,
+ 289, 290, 291, 292, 292, 293, 294, 294, 295, 295,
+ 296, 297, 298, 299, 299, 300, 301, 301, 302, 303,
+ 303, 303, 303, 303
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 3, 2, 2, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 1, 1, 1, 1, 1, 1, 2, 1, 1,
+ 1, 0, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 1, 1, 1,
+ 1, 1, 1, 2, 1, 2, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 0, 2, 2, 2, 1, 1, 1, 1, 1,
+ 2, 2, 1, 2, 2, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 3, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 3, 5,
+ 3, 4, 4, 3, 0, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 2, 1, 1, 1, 2, 1, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 2,
+ 1, 2, 2, 2, 2, 2, 1, 1, 1, 1,
+ 1, 1, 2, 2, 1, 2, 1, 1, 1, 2,
+ 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 1, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 3, 1, 2, 2, 2, 2, 3,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 0, 4, 1, 0, 0, 2, 2,
+ 2, 2, 1, 1, 3, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 1, 2, 1, 1,
+ 1, 5, 2, 1, 2, 1, 1, 1, 1, 1,
+ 1, 5, 1, 3, 2, 3, 1, 1, 2, 1,
+ 5, 4, 3, 2, 1, 6, 3, 2, 3, 1,
+ 1, 1, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint16 yydefact[] =
+{
+ 0, 0, 0, 24, 58, 231, 0, 71, 0, 0,
+ 243, 234, 0, 224, 0, 0, 236, 0, 256, 0,
+ 0, 237, 235, 0, 239, 25, 0, 0, 0, 0,
+ 257, 232, 0, 23, 0, 238, 22, 0, 0, 0,
+ 0, 0, 240, 21, 0, 0, 0, 233, 0, 0,
+ 0, 0, 0, 56, 57, 292, 0, 2, 0, 7,
+ 0, 8, 0, 9, 10, 13, 11, 12, 14, 15,
+ 16, 17, 18, 0, 0, 0, 0, 217, 0, 218,
+ 19, 0, 5, 62, 63, 64, 195, 196, 197, 198,
+ 201, 199, 200, 202, 190, 192, 193, 194, 154, 155,
+ 156, 126, 152, 0, 241, 225, 189, 101, 102, 103,
+ 104, 108, 105, 106, 107, 109, 29, 30, 28, 0,
+ 26, 0, 6, 65, 66, 253, 226, 252, 285, 59,
+ 61, 160, 161, 162, 163, 164, 165, 166, 167, 127,
+ 158, 0, 60, 70, 283, 227, 67, 268, 269, 270,
+ 271, 272, 273, 274, 265, 267, 134, 29, 30, 134,
+ 134, 26, 68, 188, 186, 187, 182, 184, 0, 0,
+ 228, 96, 100, 97, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 216, 203, 205, 0, 91, 86, 0,
+ 87, 95, 93, 94, 92, 90, 88, 89, 80, 82,
+ 0, 0, 247, 279, 0, 69, 278, 280, 276, 230,
+ 1, 0, 4, 31, 55, 290, 289, 219, 220, 221,
+ 222, 264, 263, 262, 0, 0, 79, 75, 76, 77,
+ 78, 0, 72, 0, 191, 151, 153, 242, 98, 0,
+ 178, 179, 180, 181, 0, 0, 176, 177, 168, 170,
+ 0, 0, 27, 223, 251, 284, 157, 159, 282, 266,
+ 130, 134, 134, 133, 128, 0, 183, 185, 0, 99,
+ 204, 206, 288, 286, 287, 85, 81, 83, 84, 229,
+ 0, 277, 275, 3, 20, 258, 259, 260, 255, 261,
+ 254, 296, 297, 0, 0, 0, 74, 73, 118, 117,
+ 0, 115, 116, 0, 110, 113, 114, 174, 175, 173,
+ 169, 171, 172, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150, 135, 131,
+ 132, 134, 246, 0, 0, 248, 0, 37, 38, 39,
+ 54, 47, 49, 48, 51, 40, 41, 42, 43, 50,
+ 52, 44, 32, 33, 36, 34, 0, 35, 0, 0,
+ 0, 0, 299, 0, 294, 0, 111, 125, 121, 123,
+ 119, 120, 122, 124, 112, 129, 245, 244, 250, 249,
+ 0, 45, 46, 53, 0, 293, 291, 298, 0, 295,
+ 281, 302, 0, 0, 0, 0, 0, 304, 0, 0,
+ 300, 303, 301, 0, 0, 309, 310, 311, 312, 313,
+ 0, 0, 0, 305, 0, 307, 0, 306, 308
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 56, 57, 58, 59, 60, 128, 120, 121, 284,
+ 352, 353, 354, 355, 356, 357, 358, 61, 62, 63,
+ 64, 85, 232, 233, 65, 198, 199, 200, 201, 66,
+ 171, 115, 238, 304, 305, 306, 374, 67, 260, 328,
+ 101, 102, 103, 139, 140, 141, 68, 248, 249, 250,
+ 251, 69, 166, 167, 168, 70, 94, 95, 96, 97,
+ 71, 184, 185, 186, 72, 73, 74, 75, 76, 105,
+ 170, 377, 279, 335, 126, 127, 77, 78, 290, 224,
+ 79, 154, 155, 209, 205, 206, 207, 145, 129, 275,
+ 217, 80, 81, 293, 294, 295, 361, 362, 393, 363,
+ 396, 397, 410, 411, 412
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -185
+static const yytype_int16 yypact[] =
+{
+ 78, -169, -34, -185, -185, -185, -29, -185, 17, 43,
+ -124, -185, 17, -185, -5, -27, -185, -121, -185, -112,
+ -110, -185, -185, -100, -185, -185, -27, 0, 116, -27,
+ -185, -185, -91, -185, -89, -185, -185, 11, 35, 30,
+ 13, 31, -185, -185, -83, -5, -78, -185, 186, 523,
+ -76, -56, 15, -185, -185, -185, 83, 244, -99, -185,
+ -27, -185, -27, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -12, 24, -71, -69, -185, -11, -185,
+ -185, -107, -185, -185, -185, 8, -185, -185, -185, -185,
+ -185, -185, -185, -185, 17, -185, -185, -185, -185, -185,
+ -185, 43, -185, 34, 59, -185, 17, -185, -185, -185,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, 7,
+ -185, -61, 407, -185, -185, -185, -100, -185, -185, -27,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, 116,
+ -185, 44, -27, -185, -185, -52, -185, -185, -185, -185,
+ -185, -185, -185, -185, 35, -185, -185, 85, 96, -185,
+ -185, 39, -185, -185, -185, -185, 31, -185, 75, -46,
+ -185, -5, -185, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, 186, -185, -12, -185, -185, -35,
+ -185, -185, -185, -185, -185, -185, -185, -185, 523, -185,
+ 82, -12, -185, -185, 91, -56, -185, -185, -185, 100,
+ -185, -26, -185, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, -2, -130, -185, -185, -185, -185,
+ -185, 105, -185, 9, -185, -185, -185, -185, -7, 18,
+ -185, -185, -185, -185, 25, 121, -185, -185, 7, -185,
+ -12, -35, -185, -185, -185, -185, -185, -185, -185, -185,
+ 391, -185, -185, 391, 391, -76, -185, -185, 29, -185,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, -51,
+ 153, -185, -185, -185, 464, -185, -185, -185, -185, -185,
+ -185, -185, -185, -82, 14, 1, -185, -185, -185, -185,
+ 38, -185, -185, 12, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, 391,
+ 391, -185, 171, -76, 140, -185, 141, -185, -185, -185,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, -185, -185, -55, -185, 53, 20,
+ 33, -128, -185, 32, -185, -12, -185, -185, -185, -185,
+ -185, -185, -185, -185, -185, 391, -185, -185, -185, -185,
+ 16, -185, -185, -185, -27, -185, -185, -185, 46, -185,
+ -185, -185, 37, 48, -12, 40, -167, -185, 54, -12,
+ -185, -185, -185, 45, 79, -185, -185, -185, -185, -185,
+ 98, 57, 47, -185, 60, -185, -12, -185, -185
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -185, -185, -185, -44, -185, -185, -15, -38, -185, -185,
+ -185, -185, -185, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, -185, -185, 28, -185, -185, -185,
+ -185, -36, -185, -185, -185, -185, -185, -185, -152, -185,
+ -185, 146, -185, -185, 111, -185, -185, -185, 3, -185,
+ -185, -185, -185, 89, -185, -185, 245, -66, -185, -185,
+ -185, -185, 72, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, -185, -185, 137, -185, -185, -185, -185,
+ -185, -185, 110, -185, -185, 70, -185, -185, 236, 27,
+ -184, -185, -185, -185, -17, -185, -185, -81, -185, -185,
+ -185, -113, -185, -126, -185
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -7
+static const yytype_int16 yytable[] =
+{
+ 119, 161, 271, 285, 272, 203, 381, 263, 264, 172,
+ 239, 333, 202, 211, 82, 107, 367, 278, 359, 108,
+ 215, 395, 298, 221, 160, 86, 273, 83, 234, 87,
+ 299, 400, 84, 300, 104, 88, 226, 122, 368, 116,
+ 234, 117, 147, 148, 222, 213, 123, 214, 124, 216,
+ 240, 241, 242, 243, 98, 291, 292, 156, 125, 227,
+ 149, 130, 228, 286, 359, 287, 311, 143, 223, 144,
+ 386, 301, 146, 163, 162, 169, 208, 109, 253, 1,
+ 173, 334, 118, 210, 212, 218, 89, 219, 2, 220,
+ 225, 237, 3, 4, 5, 236, 157, 252, 158, 150,
+ 6, 7, 302, 291, 292, 257, 258, 8, 9, 329,
+ 330, 10, 261, 11, 255, 12, 13, 369, 382, 14,
+ 90, 91, 110, 262, 370, 265, 164, 255, 15, 151,
+ 111, 118, 16, 112, 274, 269, 267, 92, 17, 204,
+ 18, 371, 99, 277, 229, 230, 244, 100, 268, 19,
+ 20, 231, 280, 21, 22, 113, 288, 283, 23, 24,
+ 114, 282, 25, 26, 245, 303, 296, 297, 93, 246,
+ 247, 27, 131, 132, 133, 134, 307, 289, 159, 375,
+ 165, 389, 309, 308, 28, 29, 30, 332, 118, 336,
+ 372, 31, 174, 373, 152, 365, 366, 364, 376, 153,
+ 32, 379, 380, 135, 33, 136, 34, 137, 35, 36,
+ 398, 383, 390, 138, 384, 403, 385, 175, 37, 38,
+ 39, 40, 41, 42, 43, 44, 276, 331, 45, 388,
+ 46, 394, 418, 392, 399, 176, 395, 402, 177, 47,
+ 415, 416, 404, 417, 48, 49, 50, 235, 51, 52,
+ 256, 310, 53, 54, 2, 266, 270, 106, 3, 4,
+ 5, -6, 55, 254, 259, 142, 6, 7, 405, 406,
+ 407, 408, 409, 8, 9, 281, 360, 10, 312, 11,
+ 387, 12, 13, 401, 414, 14, 0, 405, 406, 407,
+ 408, 409, 0, 0, 15, 378, 413, 0, 16, 0,
+ 0, 0, 0, 0, 17, 0, 18, 0, 0, 0,
+ 0, 178, 0, 0, 0, 19, 20, 0, 0, 21,
+ 22, 0, 0, 0, 23, 24, 0, 0, 25, 26,
+ 0, 0, 0, 0, 0, 0, 0, 27, 0, 179,
+ 180, 181, 182, 0, 0, 0, 0, 183, 0, 0,
+ 28, 29, 30, 0, 0, 0, 0, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 32, 0, 0, 391,
+ 33, 0, 34, 0, 35, 36, 0, 0, 0, 0,
+ 0, 0, 0, 0, 37, 38, 39, 40, 41, 42,
+ 43, 44, 0, 0, 45, 0, 46, 0, 0, 0,
+ 0, 0, 0, 0, 0, 47, 0, 0, 0, 0,
+ 48, 49, 50, 0, 51, 52, 0, 2, 53, 54,
+ 0, 3, 4, 5, 0, 0, 0, -6, 55, 6,
+ 7, 0, 0, 0, 0, 0, 8, 9, 313, 0,
+ 10, 0, 11, 0, 12, 13, 314, 0, 14, 0,
+ 0, 0, 0, 0, 0, 0, 0, 15, 0, 0,
+ 0, 16, 0, 0, 315, 316, 0, 17, 317, 18,
+ 0, 0, 0, 337, 318, 0, 0, 0, 19, 20,
+ 0, 338, 21, 22, 0, 0, 0, 23, 24, 0,
+ 0, 25, 26, 0, 0, 0, 0, 0, 0, 0,
+ 27, 319, 320, 0, 0, 321, 322, 0, 323, 324,
+ 325, 0, 326, 28, 29, 30, 0, 339, 340, 0,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 32,
+ 0, 0, 0, 33, 341, 34, 187, 35, 36, 0,
+ 0, 0, 188, 0, 189, 0, 0, 37, 38, 39,
+ 40, 41, 42, 43, 44, 0, 342, 45, 0, 46,
+ 0, 0, 0, 0, 343, 0, 344, 327, 47, 0,
+ 0, 190, 0, 48, 49, 50, 0, 51, 52, 0,
+ 345, 53, 54, 0, 0, 0, 0, 0, 0, 0,
+ 0, 55, 0, 0, 0, 0, 0, 346, 347, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 191, 0, 192, 0, 0, 0, 0, 0, 193,
+ 0, 194, 0, 0, 195, 0, 0, 0, 0, 0,
+ 0, 0, 0, 348, 0, 349, 0, 0, 0, 0,
+ 350, 0, 0, 0, 351, 0, 196, 197
+};
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-185)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 15, 39, 186, 5, 39, 61, 61, 159, 160, 45,
+ 3, 62, 50, 57, 183, 20, 4, 201, 146, 24,
+ 32, 188, 29, 34, 39, 8, 61, 61, 94, 12,
+ 37, 198, 61, 40, 158, 18, 28, 158, 26, 66,
+ 106, 68, 7, 8, 55, 60, 158, 62, 158, 61,
+ 43, 44, 45, 46, 11, 185, 186, 27, 158, 51,
+ 25, 61, 54, 65, 146, 67, 250, 158, 79, 158,
+ 198, 78, 61, 42, 61, 158, 61, 82, 122, 1,
+ 158, 132, 158, 0, 183, 61, 69, 158, 10, 158,
+ 197, 32, 14, 15, 16, 61, 66, 158, 68, 64,
+ 22, 23, 109, 185, 186, 61, 158, 29, 30, 261,
+ 262, 33, 27, 35, 129, 37, 38, 105, 173, 41,
+ 103, 104, 127, 27, 112, 86, 95, 142, 50, 94,
+ 135, 158, 54, 138, 169, 171, 61, 120, 60, 195,
+ 62, 129, 99, 61, 136, 137, 139, 104, 194, 71,
+ 72, 143, 61, 75, 76, 160, 158, 183, 80, 81,
+ 165, 61, 84, 85, 157, 172, 61, 158, 151, 162,
+ 163, 93, 56, 57, 58, 59, 158, 179, 148, 331,
+ 149, 365, 61, 158, 106, 107, 108, 158, 158, 36,
+ 178, 113, 6, 181, 159, 194, 158, 183, 27, 164,
+ 122, 61, 61, 87, 126, 89, 128, 91, 130, 131,
+ 394, 158, 196, 97, 194, 399, 183, 31, 140, 141,
+ 142, 143, 144, 145, 146, 147, 198, 265, 150, 197,
+ 152, 194, 416, 187, 194, 49, 188, 183, 52, 161,
+ 183, 194, 197, 183, 166, 167, 168, 101, 170, 171,
+ 139, 248, 174, 175, 10, 166, 184, 12, 14, 15,
+ 16, 183, 184, 126, 154, 29, 22, 23, 189, 190,
+ 191, 192, 193, 29, 30, 205, 293, 33, 251, 35,
+ 361, 37, 38, 396, 410, 41, -1, 189, 190, 191,
+ 192, 193, -1, -1, 50, 333, 198, -1, 54, -1,
+ -1, -1, -1, -1, 60, -1, 62, -1, -1, -1,
+ -1, 125, -1, -1, -1, 71, 72, -1, -1, 75,
+ 76, -1, -1, -1, 80, 81, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, -1, -1, 93, -1, 153,
+ 154, 155, 156, -1, -1, -1, -1, 161, -1, -1,
+ 106, 107, 108, -1, -1, -1, -1, 113, -1, -1,
+ -1, -1, -1, -1, -1, -1, 122, -1, -1, 384,
+ 126, -1, 128, -1, 130, 131, -1, -1, -1, -1,
+ -1, -1, -1, -1, 140, 141, 142, 143, 144, 145,
+ 146, 147, -1, -1, 150, -1, 152, -1, -1, -1,
+ -1, -1, -1, -1, -1, 161, -1, -1, -1, -1,
+ 166, 167, 168, -1, 170, 171, -1, 10, 174, 175,
+ -1, 14, 15, 16, -1, -1, -1, 183, 184, 22,
+ 23, -1, -1, -1, -1, -1, 29, 30, 47, -1,
+ 33, -1, 35, -1, 37, 38, 55, -1, 41, -1,
+ -1, -1, -1, -1, -1, -1, -1, 50, -1, -1,
+ -1, 54, -1, -1, 73, 74, -1, 60, 77, 62,
+ -1, -1, -1, 9, 83, -1, -1, -1, 71, 72,
+ -1, 17, 75, 76, -1, -1, -1, 80, 81, -1,
+ -1, 84, 85, -1, -1, -1, -1, -1, -1, -1,
+ 93, 110, 111, -1, -1, 114, 115, -1, 117, 118,
+ 119, -1, 121, 106, 107, 108, -1, 53, 54, -1,
+ 113, -1, -1, -1, -1, -1, -1, -1, -1, 122,
+ -1, -1, -1, 126, 70, 128, 13, 130, 131, -1,
+ -1, -1, 19, -1, 21, -1, -1, 140, 141, 142,
+ 143, 144, 145, 146, 147, -1, 92, 150, -1, 152,
+ -1, -1, -1, -1, 100, -1, 102, 176, 161, -1,
+ -1, 48, -1, 166, 167, 168, -1, 170, 171, -1,
+ 116, 174, 175, -1, -1, -1, -1, -1, -1, -1,
+ -1, 184, -1, -1, -1, -1, -1, 133, 134, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 88, -1, 90, -1, -1, -1, -1, -1, 96,
+ -1, 98, -1, -1, 101, -1, -1, -1, -1, -1,
+ -1, -1, -1, 169, -1, 171, -1, -1, -1, -1,
+ 176, -1, -1, -1, 180, -1, 123, 124
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint16 yystos[] =
+{
+ 0, 1, 10, 14, 15, 16, 22, 23, 29, 30,
+ 33, 35, 37, 38, 41, 50, 54, 60, 62, 71,
+ 72, 75, 76, 80, 81, 84, 85, 93, 106, 107,
+ 108, 113, 122, 126, 128, 130, 131, 140, 141, 142,
+ 143, 144, 145, 146, 147, 150, 152, 161, 166, 167,
+ 168, 170, 171, 174, 175, 184, 200, 201, 202, 203,
+ 204, 216, 217, 218, 219, 223, 228, 236, 245, 250,
+ 254, 259, 263, 264, 265, 266, 267, 275, 276, 279,
+ 290, 291, 183, 61, 61, 220, 8, 12, 18, 69,
+ 103, 104, 120, 151, 255, 256, 257, 258, 11, 99,
+ 104, 239, 240, 241, 158, 268, 255, 20, 24, 82,
+ 127, 135, 138, 160, 165, 230, 66, 68, 158, 205,
+ 206, 207, 158, 158, 158, 158, 273, 274, 205, 287,
+ 61, 56, 57, 58, 59, 87, 89, 91, 97, 242,
+ 243, 244, 287, 158, 158, 286, 61, 7, 8, 25,
+ 64, 94, 159, 164, 280, 281, 27, 66, 68, 148,
+ 205, 206, 61, 42, 95, 149, 251, 252, 253, 158,
+ 269, 229, 230, 158, 6, 31, 49, 52, 125, 153,
+ 154, 155, 156, 161, 260, 261, 262, 13, 19, 21,
+ 48, 88, 90, 96, 98, 101, 123, 124, 224, 225,
+ 226, 227, 206, 61, 195, 283, 284, 285, 61, 282,
+ 0, 202, 183, 205, 205, 32, 61, 289, 61, 158,
+ 158, 34, 55, 79, 278, 197, 28, 51, 54, 136,
+ 137, 143, 221, 222, 256, 240, 61, 32, 231, 3,
+ 43, 44, 45, 46, 139, 157, 162, 163, 246, 247,
+ 248, 249, 158, 202, 274, 205, 243, 61, 158, 281,
+ 237, 27, 27, 237, 237, 86, 252, 61, 194, 230,
+ 261, 289, 39, 61, 169, 288, 225, 61, 289, 271,
+ 61, 284, 61, 183, 208, 5, 65, 67, 158, 179,
+ 277, 185, 186, 292, 293, 294, 61, 158, 29, 37,
+ 40, 78, 109, 172, 232, 233, 234, 158, 158, 61,
+ 247, 289, 288, 47, 55, 73, 74, 77, 83, 110,
+ 111, 114, 115, 117, 118, 119, 121, 176, 238, 237,
+ 237, 206, 158, 62, 132, 272, 36, 9, 17, 53,
+ 54, 70, 92, 100, 102, 116, 133, 134, 169, 171,
+ 176, 180, 209, 210, 211, 212, 213, 214, 215, 146,
+ 293, 295, 296, 298, 183, 194, 158, 4, 26, 105,
+ 112, 129, 178, 181, 235, 237, 27, 270, 206, 61,
+ 61, 61, 173, 158, 194, 183, 198, 296, 197, 289,
+ 196, 205, 187, 297, 194, 188, 299, 300, 289, 194,
+ 198, 300, 183, 289, 197, 189, 190, 191, 192, 193,
+ 301, 302, 303, 198, 302, 183, 194, 183, 289
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YYUSE (yytype);
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 5:
+/* Line 1787 of yacc.c */
+#line 373 "../../ntpd/ntp_parser.y"
+ {
+ /* I will need to incorporate much more fine grained
+ * error messages. The following should suffice for
+ * the time being.
+ */
+ struct FILE_INFO * ip_ctx = lex_current();
+ msyslog(LOG_ERR,
+ "syntax error in %s line %d, column %d",
+ ip_ctx->fname,
+ ip_ctx->errpos.nline,
+ ip_ctx->errpos.ncol);
+ }
+ break;
+
+ case 20:
+/* Line 1787 of yacc.c */
+#line 409 "../../ntpd/ntp_parser.y"
+ {
+ peer_node *my_node;
+
+ my_node = create_peer_node((yyvsp[(1) - (3)].Integer), (yyvsp[(2) - (3)].Address_node), (yyvsp[(3) - (3)].Attr_val_fifo));
+ APPEND_G_FIFO(cfgt.peers, my_node);
+ }
+ break;
+
+ case 27:
+/* Line 1787 of yacc.c */
+#line 428 "../../ntpd/ntp_parser.y"
+ { (yyval.Address_node) = create_address_node((yyvsp[(2) - (2)].String), (yyvsp[(1) - (2)].Integer)); }
+ break;
+
+ case 28:
+/* Line 1787 of yacc.c */
+#line 433 "../../ntpd/ntp_parser.y"
+ { (yyval.Address_node) = create_address_node((yyvsp[(1) - (1)].String), AF_UNSPEC); }
+ break;
+
+ case 29:
+/* Line 1787 of yacc.c */
+#line 438 "../../ntpd/ntp_parser.y"
+ { (yyval.Integer) = AF_INET; }
+ break;
+
+ case 30:
+/* Line 1787 of yacc.c */
+#line 440 "../../ntpd/ntp_parser.y"
+ { (yyval.Integer) = AF_INET6; }
+ break;
+
+ case 31:
+/* Line 1787 of yacc.c */
+#line 445 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val_fifo) = NULL; }
+ break;
+
+ case 32:
+/* Line 1787 of yacc.c */
+#line 447 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 36:
+/* Line 1787 of yacc.c */
+#line 461 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[(1) - (1)].Integer)); }
+ break;
+
+ case 45:
+/* Line 1787 of yacc.c */
+#line 477 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 46:
+/* Line 1787 of yacc.c */
+#line 479 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_uval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 53:
+/* Line 1787 of yacc.c */
+#line 493 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String)); }
+ break;
+
+ case 55:
+/* Line 1787 of yacc.c */
+#line 507 "../../ntpd/ntp_parser.y"
+ {
+ unpeer_node *my_node;
+
+ my_node = create_unpeer_node((yyvsp[(2) - (2)].Address_node));
+ if (my_node)
+ APPEND_G_FIFO(cfgt.unpeers, my_node);
+ }
+ break;
+
+ case 58:
+/* Line 1787 of yacc.c */
+#line 528 "../../ntpd/ntp_parser.y"
+ { cfgt.broadcastclient = 1; }
+ break;
+
+ case 59:
+/* Line 1787 of yacc.c */
+#line 530 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.manycastserver, (yyvsp[(2) - (2)].Address_fifo)); }
+ break;
+
+ case 60:
+/* Line 1787 of yacc.c */
+#line 532 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.multicastclient, (yyvsp[(2) - (2)].Address_fifo)); }
+ break;
+
+ case 61:
+/* Line 1787 of yacc.c */
+#line 534 "../../ntpd/ntp_parser.y"
+ { cfgt.mdnstries = (yyvsp[(2) - (2)].Integer); }
+ break;
+
+ case 62:
+/* Line 1787 of yacc.c */
+#line 545 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *atrv;
+
+ atrv = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer));
+ APPEND_G_FIFO(cfgt.vars, atrv);
+ }
+ break;
+
+ case 63:
+/* Line 1787 of yacc.c */
+#line 552 "../../ntpd/ntp_parser.y"
+ { cfgt.auth.control_key = (yyvsp[(2) - (2)].Integer); }
+ break;
+
+ case 64:
+/* Line 1787 of yacc.c */
+#line 554 "../../ntpd/ntp_parser.y"
+ {
+ cfgt.auth.cryptosw++;
+ CONCAT_G_FIFOS(cfgt.auth.crypto_cmd_list, (yyvsp[(2) - (2)].Attr_val_fifo));
+ }
+ break;
+
+ case 65:
+/* Line 1787 of yacc.c */
+#line 559 "../../ntpd/ntp_parser.y"
+ { cfgt.auth.keys = (yyvsp[(2) - (2)].String); }
+ break;
+
+ case 66:
+/* Line 1787 of yacc.c */
+#line 561 "../../ntpd/ntp_parser.y"
+ { cfgt.auth.keysdir = (yyvsp[(2) - (2)].String); }
+ break;
+
+ case 67:
+/* Line 1787 of yacc.c */
+#line 563 "../../ntpd/ntp_parser.y"
+ { cfgt.auth.request_key = (yyvsp[(2) - (2)].Integer); }
+ break;
+
+ case 68:
+/* Line 1787 of yacc.c */
+#line 565 "../../ntpd/ntp_parser.y"
+ { cfgt.auth.revoke = (yyvsp[(2) - (2)].Integer); }
+ break;
+
+ case 69:
+/* Line 1787 of yacc.c */
+#line 567 "../../ntpd/ntp_parser.y"
+ {
+ cfgt.auth.trusted_key_list = (yyvsp[(2) - (2)].Attr_val_fifo);
+
+ // if (!cfgt.auth.trusted_key_list)
+ // cfgt.auth.trusted_key_list = $2;
+ // else
+ // LINK_SLIST(cfgt.auth.trusted_key_list, $2, link);
+ }
+ break;
+
+ case 70:
+/* Line 1787 of yacc.c */
+#line 576 "../../ntpd/ntp_parser.y"
+ { cfgt.auth.ntp_signd_socket = (yyvsp[(2) - (2)].String); }
+ break;
+
+ case 71:
+/* Line 1787 of yacc.c */
+#line 581 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val_fifo) = NULL; }
+ break;
+
+ case 72:
+/* Line 1787 of yacc.c */
+#line 583 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 73:
+/* Line 1787 of yacc.c */
+#line 591 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String)); }
+ break;
+
+ case 74:
+/* Line 1787 of yacc.c */
+#line 593 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val) = NULL;
+ cfgt.auth.revoke = (yyvsp[(2) - (2)].Integer);
+ msyslog(LOG_WARNING,
+ "'crypto revoke %d' is deprecated, "
+ "please use 'revoke %d' instead.",
+ cfgt.auth.revoke, cfgt.auth.revoke);
+ }
+ break;
+
+ case 80:
+/* Line 1787 of yacc.c */
+#line 618 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.orphan_cmds, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 81:
+/* Line 1787 of yacc.c */
+#line 623 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 82:
+/* Line 1787 of yacc.c */
+#line 628 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 83:
+/* Line 1787 of yacc.c */
+#line 636 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (2)].Integer), (double)(yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 84:
+/* Line 1787 of yacc.c */
+#line 638 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Double)); }
+ break;
+
+ case 85:
+/* Line 1787 of yacc.c */
+#line 640 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (2)].Integer), (double)(yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 96:
+/* Line 1787 of yacc.c */
+#line 666 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.stats_list, (yyvsp[(2) - (2)].Int_fifo)); }
+ break;
+
+ case 97:
+/* Line 1787 of yacc.c */
+#line 668 "../../ntpd/ntp_parser.y"
+ {
+ if (lex_from_file()) {
+ cfgt.stats_dir = (yyvsp[(2) - (2)].String);
+ } else {
+ YYFREE((yyvsp[(2) - (2)].String));
+ yyerror("statsdir remote configuration ignored");
+ }
+ }
+ break;
+
+ case 98:
+/* Line 1787 of yacc.c */
+#line 677 "../../ntpd/ntp_parser.y"
+ {
+ filegen_node *fgn;
+
+ fgn = create_filegen_node((yyvsp[(2) - (3)].Integer), (yyvsp[(3) - (3)].Attr_val_fifo));
+ APPEND_G_FIFO(cfgt.filegen_opts, fgn);
+ }
+ break;
+
+ case 99:
+/* Line 1787 of yacc.c */
+#line 687 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Int_fifo) = (yyvsp[(1) - (2)].Int_fifo);
+ APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[(2) - (2)].Integer)));
+ }
+ break;
+
+ case 100:
+/* Line 1787 of yacc.c */
+#line 692 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Int_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[(1) - (1)].Integer)));
+ }
+ break;
+
+ case 109:
+/* Line 1787 of yacc.c */
+#line 711 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val_fifo) = NULL; }
+ break;
+
+ case 110:
+/* Line 1787 of yacc.c */
+#line 713 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 111:
+/* Line 1787 of yacc.c */
+#line 721 "../../ntpd/ntp_parser.y"
+ {
+ if (lex_from_file()) {
+ (yyval.Attr_val) = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String));
+ } else {
+ (yyval.Attr_val) = NULL;
+ YYFREE((yyvsp[(2) - (2)].String));
+ yyerror("filegen file remote config ignored");
+ }
+ }
+ break;
+
+ case 112:
+/* Line 1787 of yacc.c */
+#line 731 "../../ntpd/ntp_parser.y"
+ {
+ if (lex_from_file()) {
+ (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer));
+ } else {
+ (yyval.Attr_val) = NULL;
+ yyerror("filegen type remote config ignored");
+ }
+ }
+ break;
+
+ case 113:
+/* Line 1787 of yacc.c */
+#line 740 "../../ntpd/ntp_parser.y"
+ {
+ const char *err;
+
+ if (lex_from_file()) {
+ (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[(1) - (1)].Integer));
+ } else {
+ (yyval.Attr_val) = NULL;
+ if (T_Link == (yyvsp[(1) - (1)].Integer))
+ err = "filegen link remote config ignored";
+ else
+ err = "filegen nolink remote config ignored";
+ yyerror(err);
+ }
+ }
+ break;
+
+ case 114:
+/* Line 1787 of yacc.c */
+#line 755 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[(1) - (1)].Integer)); }
+ break;
+
+ case 126:
+/* Line 1787 of yacc.c */
+#line 785 "../../ntpd/ntp_parser.y"
+ {
+ CONCAT_G_FIFOS(cfgt.discard_opts, (yyvsp[(2) - (2)].Attr_val_fifo));
+ }
+ break;
+
+ case 127:
+/* Line 1787 of yacc.c */
+#line 789 "../../ntpd/ntp_parser.y"
+ {
+ CONCAT_G_FIFOS(cfgt.mru_opts, (yyvsp[(2) - (2)].Attr_val_fifo));
+ }
+ break;
+
+ case 128:
+/* Line 1787 of yacc.c */
+#line 793 "../../ntpd/ntp_parser.y"
+ {
+ restrict_node *rn;
+
+ rn = create_restrict_node((yyvsp[(2) - (3)].Address_node), NULL, (yyvsp[(3) - (3)].Int_fifo),
+ lex_current()->curpos.nline);
+ APPEND_G_FIFO(cfgt.restrict_opts, rn);
+ }
+ break;
+
+ case 129:
+/* Line 1787 of yacc.c */
+#line 801 "../../ntpd/ntp_parser.y"
+ {
+ restrict_node *rn;
+
+ rn = create_restrict_node((yyvsp[(2) - (5)].Address_node), (yyvsp[(4) - (5)].Address_node), (yyvsp[(5) - (5)].Int_fifo),
+ lex_current()->curpos.nline);
+ APPEND_G_FIFO(cfgt.restrict_opts, rn);
+ }
+ break;
+
+ case 130:
+/* Line 1787 of yacc.c */
+#line 809 "../../ntpd/ntp_parser.y"
+ {
+ restrict_node *rn;
+
+ rn = create_restrict_node(NULL, NULL, (yyvsp[(3) - (3)].Int_fifo),
+ lex_current()->curpos.nline);
+ APPEND_G_FIFO(cfgt.restrict_opts, rn);
+ }
+ break;
+
+ case 131:
+/* Line 1787 of yacc.c */
+#line 817 "../../ntpd/ntp_parser.y"
+ {
+ restrict_node *rn;
+
+ rn = create_restrict_node(
+ create_address_node(
+ estrdup("0.0.0.0"),
+ AF_INET),
+ create_address_node(
+ estrdup("0.0.0.0"),
+ AF_INET),
+ (yyvsp[(4) - (4)].Int_fifo),
+ lex_current()->curpos.nline);
+ APPEND_G_FIFO(cfgt.restrict_opts, rn);
+ }
+ break;
+
+ case 132:
+/* Line 1787 of yacc.c */
+#line 832 "../../ntpd/ntp_parser.y"
+ {
+ restrict_node *rn;
+
+ rn = create_restrict_node(
+ create_address_node(
+ estrdup("::"),
+ AF_INET6),
+ create_address_node(
+ estrdup("::"),
+ AF_INET6),
+ (yyvsp[(4) - (4)].Int_fifo),
+ lex_current()->curpos.nline);
+ APPEND_G_FIFO(cfgt.restrict_opts, rn);
+ }
+ break;
+
+ case 133:
+/* Line 1787 of yacc.c */
+#line 847 "../../ntpd/ntp_parser.y"
+ {
+ restrict_node * rn;
+
+ APPEND_G_FIFO((yyvsp[(3) - (3)].Int_fifo), create_int_node((yyvsp[(2) - (3)].Integer)));
+ rn = create_restrict_node(
+ NULL, NULL, (yyvsp[(3) - (3)].Int_fifo), lex_current()->curpos.nline);
+ APPEND_G_FIFO(cfgt.restrict_opts, rn);
+ }
+ break;
+
+ case 134:
+/* Line 1787 of yacc.c */
+#line 859 "../../ntpd/ntp_parser.y"
+ { (yyval.Int_fifo) = NULL; }
+ break;
+
+ case 135:
+/* Line 1787 of yacc.c */
+#line 861 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Int_fifo) = (yyvsp[(1) - (2)].Int_fifo);
+ APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[(2) - (2)].Integer)));
+ }
+ break;
+
+ case 151:
+/* Line 1787 of yacc.c */
+#line 887 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 152:
+/* Line 1787 of yacc.c */
+#line 892 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 153:
+/* Line 1787 of yacc.c */
+#line 900 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 157:
+/* Line 1787 of yacc.c */
+#line 911 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 158:
+/* Line 1787 of yacc.c */
+#line 916 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 159:
+/* Line 1787 of yacc.c */
+#line 924 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 168:
+/* Line 1787 of yacc.c */
+#line 944 "../../ntpd/ntp_parser.y"
+ {
+ addr_opts_node *aon;
+
+ aon = create_addr_opts_node((yyvsp[(2) - (3)].Address_node), (yyvsp[(3) - (3)].Attr_val_fifo));
+ APPEND_G_FIFO(cfgt.fudge, aon);
+ }
+ break;
+
+ case 169:
+/* Line 1787 of yacc.c */
+#line 954 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 170:
+/* Line 1787 of yacc.c */
+#line 959 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 171:
+/* Line 1787 of yacc.c */
+#line 967 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Double)); }
+ break;
+
+ case 172:
+/* Line 1787 of yacc.c */
+#line 969 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 173:
+/* Line 1787 of yacc.c */
+#line 971 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 174:
+/* Line 1787 of yacc.c */
+#line 973 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String)); }
+ break;
+
+ case 175:
+/* Line 1787 of yacc.c */
+#line 975 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String)); }
+ break;
+
+ case 182:
+/* Line 1787 of yacc.c */
+#line 996 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.rlimit, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 183:
+/* Line 1787 of yacc.c */
+#line 1001 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 184:
+/* Line 1787 of yacc.c */
+#line 1006 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 185:
+/* Line 1787 of yacc.c */
+#line 1014 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 189:
+/* Line 1787 of yacc.c */
+#line 1030 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.enable_opts, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 190:
+/* Line 1787 of yacc.c */
+#line 1032 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.disable_opts, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 191:
+/* Line 1787 of yacc.c */
+#line 1037 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 192:
+/* Line 1787 of yacc.c */
+#line 1042 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 193:
+/* Line 1787 of yacc.c */
+#line 1050 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[(1) - (1)].Integer)); }
+ break;
+
+ case 194:
+/* Line 1787 of yacc.c */
+#line 1052 "../../ntpd/ntp_parser.y"
+ {
+ if (lex_from_file()) {
+ (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[(1) - (1)].Integer));
+ } else {
+ char err_str[128];
+
+ (yyval.Attr_val) = NULL;
+ snprintf(err_str, sizeof(err_str),
+ "enable/disable %s remote configuration ignored",
+ keyword((yyvsp[(1) - (1)].Integer)));
+ yyerror(err_str);
+ }
+ }
+ break;
+
+ case 203:
+/* Line 1787 of yacc.c */
+#line 1087 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.tinker, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 204:
+/* Line 1787 of yacc.c */
+#line 1092 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 205:
+/* Line 1787 of yacc.c */
+#line 1097 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 206:
+/* Line 1787 of yacc.c */
+#line 1105 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Double)); }
+ break;
+
+ case 219:
+/* Line 1787 of yacc.c */
+#line 1130 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *av;
+
+ av = create_attr_dval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Double));
+ APPEND_G_FIFO(cfgt.vars, av);
+ }
+ break;
+
+ case 220:
+/* Line 1787 of yacc.c */
+#line 1137 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *av;
+
+ av = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer));
+ APPEND_G_FIFO(cfgt.vars, av);
+ }
+ break;
+
+ case 221:
+/* Line 1787 of yacc.c */
+#line 1144 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *av;
+
+ av = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String));
+ APPEND_G_FIFO(cfgt.vars, av);
+ }
+ break;
+
+ case 222:
+/* Line 1787 of yacc.c */
+#line 1151 "../../ntpd/ntp_parser.y"
+ {
+ char error_text[64];
+ attr_val *av;
+
+ if (lex_from_file()) {
+ av = create_attr_sval((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].String));
+ APPEND_G_FIFO(cfgt.vars, av);
+ } else {
+ YYFREE((yyvsp[(2) - (2)].String));
+ snprintf(error_text, sizeof(error_text),
+ "%s remote config ignored",
+ keyword((yyvsp[(1) - (2)].Integer)));
+ yyerror(error_text);
+ }
+ }
+ break;
+
+ case 223:
+/* Line 1787 of yacc.c */
+#line 1167 "../../ntpd/ntp_parser.y"
+ {
+ if (!lex_from_file()) {
+ YYFREE((yyvsp[(2) - (3)].String)); /* avoid leak */
+ yyerror("remote includefile ignored");
+ break;
+ }
+ if (lex_level() > MAXINCLUDELEVEL) {
+ fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
+ msyslog(LOG_ERR, "getconfig: Maximum include file level exceeded.");
+ } else {
+ const char * path = FindConfig((yyvsp[(2) - (3)].String)); /* might return $2! */
+ if (!lex_push_file(path, "r")) {
+ fprintf(stderr, "getconfig: Couldn't open <%s>\n", path);
+ msyslog(LOG_ERR, "getconfig: Couldn't open <%s>", path);
+ }
+ }
+ YYFREE((yyvsp[(2) - (3)].String)); /* avoid leak */
+ }
+ break;
+
+ case 224:
+/* Line 1787 of yacc.c */
+#line 1186 "../../ntpd/ntp_parser.y"
+ { lex_flush_stack(); }
+ break;
+
+ case 225:
+/* Line 1787 of yacc.c */
+#line 1188 "../../ntpd/ntp_parser.y"
+ { /* see drift_parm below for actions */ }
+ break;
+
+ case 226:
+/* Line 1787 of yacc.c */
+#line 1190 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.logconfig, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 227:
+/* Line 1787 of yacc.c */
+#line 1192 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.phone, (yyvsp[(2) - (2)].String_fifo)); }
+ break;
+
+ case 228:
+/* Line 1787 of yacc.c */
+#line 1194 "../../ntpd/ntp_parser.y"
+ { APPEND_G_FIFO(cfgt.setvar, (yyvsp[(2) - (2)].Set_var)); }
+ break;
+
+ case 229:
+/* Line 1787 of yacc.c */
+#line 1196 "../../ntpd/ntp_parser.y"
+ {
+ addr_opts_node *aon;
+
+ aon = create_addr_opts_node((yyvsp[(2) - (3)].Address_node), (yyvsp[(3) - (3)].Attr_val_fifo));
+ APPEND_G_FIFO(cfgt.trap, aon);
+ }
+ break;
+
+ case 230:
+/* Line 1787 of yacc.c */
+#line 1203 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.ttl, (yyvsp[(2) - (2)].Attr_val_fifo)); }
+ break;
+
+ case 235:
+/* Line 1787 of yacc.c */
+#line 1218 "../../ntpd/ntp_parser.y"
+ {
+#ifndef LEAP_SMEAR
+ yyerror("Built without LEAP_SMEAR support.");
+#endif
+ }
+ break;
+
+ case 241:
+/* Line 1787 of yacc.c */
+#line 1238 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *av;
+
+ av = create_attr_sval(T_Driftfile, (yyvsp[(1) - (1)].String));
+ APPEND_G_FIFO(cfgt.vars, av);
+ }
+ break;
+
+ case 242:
+/* Line 1787 of yacc.c */
+#line 1245 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *av;
+
+ av = create_attr_sval(T_Driftfile, (yyvsp[(1) - (2)].String));
+ APPEND_G_FIFO(cfgt.vars, av);
+ av = create_attr_dval(T_WanderThreshold, (yyvsp[(2) - (2)].Double));
+ APPEND_G_FIFO(cfgt.vars, av);
+ }
+ break;
+
+ case 243:
+/* Line 1787 of yacc.c */
+#line 1254 "../../ntpd/ntp_parser.y"
+ {
+ attr_val *av;
+
+ av = create_attr_sval(T_Driftfile, "");
+ APPEND_G_FIFO(cfgt.vars, av);
+ }
+ break;
+
+ case 244:
+/* Line 1787 of yacc.c */
+#line 1264 "../../ntpd/ntp_parser.y"
+ { (yyval.Set_var) = create_setvar_node((yyvsp[(1) - (4)].String), (yyvsp[(3) - (4)].String), (yyvsp[(4) - (4)].Integer)); }
+ break;
+
+ case 246:
+/* Line 1787 of yacc.c */
+#line 1270 "../../ntpd/ntp_parser.y"
+ { (yyval.Integer) = 0; }
+ break;
+
+ case 247:
+/* Line 1787 of yacc.c */
+#line 1275 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val_fifo) = NULL; }
+ break;
+
+ case 248:
+/* Line 1787 of yacc.c */
+#line 1277 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 249:
+/* Line 1787 of yacc.c */
+#line 1285 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival((yyvsp[(1) - (2)].Integer), (yyvsp[(2) - (2)].Integer)); }
+ break;
+
+ case 250:
+/* Line 1787 of yacc.c */
+#line 1287 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val) = create_attr_sval((yyvsp[(1) - (2)].Integer), estrdup((yyvsp[(2) - (2)].Address_node)->address));
+ destroy_address_node((yyvsp[(2) - (2)].Address_node));
+ }
+ break;
+
+ case 251:
+/* Line 1787 of yacc.c */
+#line 1295 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 252:
+/* Line 1787 of yacc.c */
+#line 1300 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 253:
+/* Line 1787 of yacc.c */
+#line 1308 "../../ntpd/ntp_parser.y"
+ {
+ char prefix;
+ char * type;
+
+ switch ((yyvsp[(1) - (1)].String)[0]) {
+
+ case '+':
+ case '-':
+ case '=':
+ prefix = (yyvsp[(1) - (1)].String)[0];
+ type = (yyvsp[(1) - (1)].String) + 1;
+ break;
+
+ default:
+ prefix = '=';
+ type = (yyvsp[(1) - (1)].String);
+ }
+
+ (yyval.Attr_val) = create_attr_sval(prefix, estrdup(type));
+ YYFREE((yyvsp[(1) - (1)].String));
+ }
+ break;
+
+ case 254:
+/* Line 1787 of yacc.c */
+#line 1333 "../../ntpd/ntp_parser.y"
+ {
+ nic_rule_node *nrn;
+
+ nrn = create_nic_rule_node((yyvsp[(3) - (3)].Integer), NULL, (yyvsp[(2) - (3)].Integer));
+ APPEND_G_FIFO(cfgt.nic_rules, nrn);
+ }
+ break;
+
+ case 255:
+/* Line 1787 of yacc.c */
+#line 1340 "../../ntpd/ntp_parser.y"
+ {
+ nic_rule_node *nrn;
+
+ nrn = create_nic_rule_node(0, (yyvsp[(3) - (3)].String), (yyvsp[(2) - (3)].Integer));
+ APPEND_G_FIFO(cfgt.nic_rules, nrn);
+ }
+ break;
+
+ case 265:
+/* Line 1787 of yacc.c */
+#line 1368 "../../ntpd/ntp_parser.y"
+ { CONCAT_G_FIFOS(cfgt.reset_counters, (yyvsp[(2) - (2)].Int_fifo)); }
+ break;
+
+ case 266:
+/* Line 1787 of yacc.c */
+#line 1373 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Int_fifo) = (yyvsp[(1) - (2)].Int_fifo);
+ APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[(2) - (2)].Integer)));
+ }
+ break;
+
+ case 267:
+/* Line 1787 of yacc.c */
+#line 1378 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Int_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[(1) - (1)].Integer)));
+ }
+ break;
+
+ case 275:
+/* Line 1787 of yacc.c */
+#line 1402 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), create_int_node((yyvsp[(2) - (2)].Integer)));
+ }
+ break;
+
+ case 276:
+/* Line 1787 of yacc.c */
+#line 1407 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), create_int_node((yyvsp[(1) - (1)].Integer)));
+ }
+ break;
+
+ case 277:
+/* Line 1787 of yacc.c */
+#line 1415 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (2)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (2)].Attr_val));
+ }
+ break;
+
+ case 278:
+/* Line 1787 of yacc.c */
+#line 1420 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (1)].Attr_val));
+ }
+ break;
+
+ case 279:
+/* Line 1787 of yacc.c */
+#line 1428 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_ival('i', (yyvsp[(1) - (1)].Integer)); }
+ break;
+
+ case 281:
+/* Line 1787 of yacc.c */
+#line 1434 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_rangeval('-', (yyvsp[(2) - (5)].Integer), (yyvsp[(4) - (5)].Integer)); }
+ break;
+
+ case 282:
+/* Line 1787 of yacc.c */
+#line 1439 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.String_fifo) = (yyvsp[(1) - (2)].String_fifo);
+ APPEND_G_FIFO((yyval.String_fifo), create_string_node((yyvsp[(2) - (2)].String)));
+ }
+ break;
+
+ case 283:
+/* Line 1787 of yacc.c */
+#line 1444 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.String_fifo) = NULL;
+ APPEND_G_FIFO((yyval.String_fifo), create_string_node((yyvsp[(1) - (1)].String)));
+ }
+ break;
+
+ case 284:
+/* Line 1787 of yacc.c */
+#line 1452 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Address_fifo) = (yyvsp[(1) - (2)].Address_fifo);
+ APPEND_G_FIFO((yyval.Address_fifo), (yyvsp[(2) - (2)].Address_node));
+ }
+ break;
+
+ case 285:
+/* Line 1787 of yacc.c */
+#line 1457 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Address_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Address_fifo), (yyvsp[(1) - (1)].Address_node));
+ }
+ break;
+
+ case 286:
+/* Line 1787 of yacc.c */
+#line 1465 "../../ntpd/ntp_parser.y"
+ {
+ if ((yyvsp[(1) - (1)].Integer) != 0 && (yyvsp[(1) - (1)].Integer) != 1) {
+ yyerror("Integer value is not boolean (0 or 1). Assuming 1");
+ (yyval.Integer) = 1;
+ } else {
+ (yyval.Integer) = (yyvsp[(1) - (1)].Integer);
+ }
+ }
+ break;
+
+ case 287:
+/* Line 1787 of yacc.c */
+#line 1473 "../../ntpd/ntp_parser.y"
+ { (yyval.Integer) = 1; }
+ break;
+
+ case 288:
+/* Line 1787 of yacc.c */
+#line 1474 "../../ntpd/ntp_parser.y"
+ { (yyval.Integer) = 0; }
+ break;
+
+ case 289:
+/* Line 1787 of yacc.c */
+#line 1478 "../../ntpd/ntp_parser.y"
+ { (yyval.Double) = (double)(yyvsp[(1) - (1)].Integer); }
+ break;
+
+ case 291:
+/* Line 1787 of yacc.c */
+#line 1489 "../../ntpd/ntp_parser.y"
+ {
+ sim_node *sn;
+
+ sn = create_sim_node((yyvsp[(3) - (5)].Attr_val_fifo), (yyvsp[(4) - (5)].Sim_server_fifo));
+ APPEND_G_FIFO(cfgt.sim_details, sn);
+
+ /* Revert from ; to \n for end-of-command */
+ old_config_style = 1;
+ }
+ break;
+
+ case 292:
+/* Line 1787 of yacc.c */
+#line 1506 "../../ntpd/ntp_parser.y"
+ { old_config_style = 0; }
+ break;
+
+ case 293:
+/* Line 1787 of yacc.c */
+#line 1511 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (3)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (3)].Attr_val));
+ }
+ break;
+
+ case 294:
+/* Line 1787 of yacc.c */
+#line 1516 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (2)].Attr_val));
+ }
+ break;
+
+ case 295:
+/* Line 1787 of yacc.c */
+#line 1524 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (3)].Integer), (yyvsp[(3) - (3)].Double)); }
+ break;
+
+ case 298:
+/* Line 1787 of yacc.c */
+#line 1534 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Sim_server_fifo) = (yyvsp[(1) - (2)].Sim_server_fifo);
+ APPEND_G_FIFO((yyval.Sim_server_fifo), (yyvsp[(2) - (2)].Sim_server));
+ }
+ break;
+
+ case 299:
+/* Line 1787 of yacc.c */
+#line 1539 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Sim_server_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Sim_server_fifo), (yyvsp[(1) - (1)].Sim_server));
+ }
+ break;
+
+ case 300:
+/* Line 1787 of yacc.c */
+#line 1547 "../../ntpd/ntp_parser.y"
+ { (yyval.Sim_server) = ONLY_SIM(create_sim_server((yyvsp[(1) - (5)].Address_node), (yyvsp[(3) - (5)].Double), (yyvsp[(4) - (5)].Sim_script_fifo))); }
+ break;
+
+ case 301:
+/* Line 1787 of yacc.c */
+#line 1552 "../../ntpd/ntp_parser.y"
+ { (yyval.Double) = (yyvsp[(3) - (4)].Double); }
+ break;
+
+ case 302:
+/* Line 1787 of yacc.c */
+#line 1557 "../../ntpd/ntp_parser.y"
+ { (yyval.Address_node) = (yyvsp[(3) - (3)].Address_node); }
+ break;
+
+ case 303:
+/* Line 1787 of yacc.c */
+#line 1562 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Sim_script_fifo) = (yyvsp[(1) - (2)].Sim_script_fifo);
+ APPEND_G_FIFO((yyval.Sim_script_fifo), (yyvsp[(2) - (2)].Sim_script));
+ }
+ break;
+
+ case 304:
+/* Line 1787 of yacc.c */
+#line 1567 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Sim_script_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Sim_script_fifo), (yyvsp[(1) - (1)].Sim_script));
+ }
+ break;
+
+ case 305:
+/* Line 1787 of yacc.c */
+#line 1575 "../../ntpd/ntp_parser.y"
+ { (yyval.Sim_script) = ONLY_SIM(create_sim_script_info((yyvsp[(3) - (6)].Double), (yyvsp[(5) - (6)].Attr_val_fifo))); }
+ break;
+
+ case 306:
+/* Line 1787 of yacc.c */
+#line 1580 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = (yyvsp[(1) - (3)].Attr_val_fifo);
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(2) - (3)].Attr_val));
+ }
+ break;
+
+ case 307:
+/* Line 1787 of yacc.c */
+#line 1585 "../../ntpd/ntp_parser.y"
+ {
+ (yyval.Attr_val_fifo) = NULL;
+ APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[(1) - (2)].Attr_val));
+ }
+ break;
+
+ case 308:
+/* Line 1787 of yacc.c */
+#line 1593 "../../ntpd/ntp_parser.y"
+ { (yyval.Attr_val) = create_attr_dval((yyvsp[(1) - (3)].Integer), (yyvsp[(3) - (3)].Double)); }
+ break;
+
+
+/* Line 1787 of yacc.c */
+#line 3600 "ntp_parser.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2050 of yacc.c */
+#line 1604 "../../ntpd/ntp_parser.y"
+
+
+void
+yyerror(
+ const char *msg
+ )
+{
+ int retval;
+ struct FILE_INFO * ip_ctx;
+
+ ip_ctx = lex_current();
+ ip_ctx->errpos = ip_ctx->tokpos;
+
+ msyslog(LOG_ERR, "line %d column %d %s",
+ ip_ctx->errpos.nline, ip_ctx->errpos.ncol, msg);
+ if (!lex_from_file()) {
+ /* Save the error message in the correct buffer */
+ retval = snprintf(remote_config.err_msg + remote_config.err_pos,
+ MAXLINE - remote_config.err_pos,
+ "column %d %s",
+ ip_ctx->errpos.ncol, msg);
+
+ /* Increment the value of err_pos */
+ if (retval > 0)
+ remote_config.err_pos += retval;
+
+ /* Increment the number of errors */
+ ++remote_config.no_errors;
+ }
+}
+
+
+/*
+ * token_name - convert T_ token integers to text
+ * example: token_name(T_Server) returns "T_Server"
+ */
+const char *
+token_name(
+ int token
+ )
+{
+ return yytname[YYTRANSLATE(token)];
+}
+
+
+/* Initial Testing function -- ignore */
+#if 0
+int main(int argc, char *argv[])
+{
+ ip_file = FOPEN(argv[1], "r");
+ if (!ip_file)
+ fprintf(stderr, "ERROR!! Could not open file: %s\n", argv[1]);
+ yyparse();
+ return 0;
+}
+#endif
+
diff --git a/contrib/ntp/ntpd/ntp_parser.h b/contrib/ntp/ntpd/ntp_parser.h
new file mode 100644
index 0000000..b474fc2
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_parser.h
@@ -0,0 +1,485 @@
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_NTP_PARSER_H_INCLUDED
+# define YY_YY_NTP_PARSER_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_Abbrev = 258,
+ T_Age = 259,
+ T_All = 260,
+ T_Allan = 261,
+ T_Allpeers = 262,
+ T_Auth = 263,
+ T_Autokey = 264,
+ T_Automax = 265,
+ T_Average = 266,
+ T_Bclient = 267,
+ T_Beacon = 268,
+ T_Broadcast = 269,
+ T_Broadcastclient = 270,
+ T_Broadcastdelay = 271,
+ T_Burst = 272,
+ T_Calibrate = 273,
+ T_Ceiling = 274,
+ T_Clockstats = 275,
+ T_Cohort = 276,
+ T_ControlKey = 277,
+ T_Crypto = 278,
+ T_Cryptostats = 279,
+ T_Ctl = 280,
+ T_Day = 281,
+ T_Default = 282,
+ T_Digest = 283,
+ T_Disable = 284,
+ T_Discard = 285,
+ T_Dispersion = 286,
+ T_Double = 287,
+ T_Driftfile = 288,
+ T_Drop = 289,
+ T_Dscp = 290,
+ T_Ellipsis = 291,
+ T_Enable = 292,
+ T_End = 293,
+ T_False = 294,
+ T_File = 295,
+ T_Filegen = 296,
+ T_Filenum = 297,
+ T_Flag1 = 298,
+ T_Flag2 = 299,
+ T_Flag3 = 300,
+ T_Flag4 = 301,
+ T_Flake = 302,
+ T_Floor = 303,
+ T_Freq = 304,
+ T_Fudge = 305,
+ T_Host = 306,
+ T_Huffpuff = 307,
+ T_Iburst = 308,
+ T_Ident = 309,
+ T_Ignore = 310,
+ T_Incalloc = 311,
+ T_Incmem = 312,
+ T_Initalloc = 313,
+ T_Initmem = 314,
+ T_Includefile = 315,
+ T_Integer = 316,
+ T_Interface = 317,
+ T_Intrange = 318,
+ T_Io = 319,
+ T_Ipv4 = 320,
+ T_Ipv4_flag = 321,
+ T_Ipv6 = 322,
+ T_Ipv6_flag = 323,
+ T_Kernel = 324,
+ T_Key = 325,
+ T_Keys = 326,
+ T_Keysdir = 327,
+ T_Kod = 328,
+ T_Mssntp = 329,
+ T_Leapfile = 330,
+ T_Leapsmearinterval = 331,
+ T_Limited = 332,
+ T_Link = 333,
+ T_Listen = 334,
+ T_Logconfig = 335,
+ T_Logfile = 336,
+ T_Loopstats = 337,
+ T_Lowpriotrap = 338,
+ T_Manycastclient = 339,
+ T_Manycastserver = 340,
+ T_Mask = 341,
+ T_Maxage = 342,
+ T_Maxclock = 343,
+ T_Maxdepth = 344,
+ T_Maxdist = 345,
+ T_Maxmem = 346,
+ T_Maxpoll = 347,
+ T_Mdnstries = 348,
+ T_Mem = 349,
+ T_Memlock = 350,
+ T_Minclock = 351,
+ T_Mindepth = 352,
+ T_Mindist = 353,
+ T_Minimum = 354,
+ T_Minpoll = 355,
+ T_Minsane = 356,
+ T_Mode = 357,
+ T_Mode7 = 358,
+ T_Monitor = 359,
+ T_Month = 360,
+ T_Mru = 361,
+ T_Multicastclient = 362,
+ T_Nic = 363,
+ T_Nolink = 364,
+ T_Nomodify = 365,
+ T_Nomrulist = 366,
+ T_None = 367,
+ T_Nonvolatile = 368,
+ T_Nopeer = 369,
+ T_Noquery = 370,
+ T_Noselect = 371,
+ T_Noserve = 372,
+ T_Notrap = 373,
+ T_Notrust = 374,
+ T_Ntp = 375,
+ T_Ntpport = 376,
+ T_NtpSignDsocket = 377,
+ T_Orphan = 378,
+ T_Orphanwait = 379,
+ T_Panic = 380,
+ T_Peer = 381,
+ T_Peerstats = 382,
+ T_Phone = 383,
+ T_Pid = 384,
+ T_Pidfile = 385,
+ T_Pool = 386,
+ T_Port = 387,
+ T_Preempt = 388,
+ T_Prefer = 389,
+ T_Protostats = 390,
+ T_Pw = 391,
+ T_Randfile = 392,
+ T_Rawstats = 393,
+ T_Refid = 394,
+ T_Requestkey = 395,
+ T_Reset = 396,
+ T_Restrict = 397,
+ T_Revoke = 398,
+ T_Rlimit = 399,
+ T_Saveconfigdir = 400,
+ T_Server = 401,
+ T_Setvar = 402,
+ T_Source = 403,
+ T_Stacksize = 404,
+ T_Statistics = 405,
+ T_Stats = 406,
+ T_Statsdir = 407,
+ T_Step = 408,
+ T_Stepback = 409,
+ T_Stepfwd = 410,
+ T_Stepout = 411,
+ T_Stratum = 412,
+ T_String = 413,
+ T_Sys = 414,
+ T_Sysstats = 415,
+ T_Tick = 416,
+ T_Time1 = 417,
+ T_Time2 = 418,
+ T_Timer = 419,
+ T_Timingstats = 420,
+ T_Tinker = 421,
+ T_Tos = 422,
+ T_Trap = 423,
+ T_True = 424,
+ T_Trustedkey = 425,
+ T_Ttl = 426,
+ T_Type = 427,
+ T_U_int = 428,
+ T_Unconfig = 429,
+ T_Unpeer = 430,
+ T_Version = 431,
+ T_WanderThreshold = 432,
+ T_Week = 433,
+ T_Wildcard = 434,
+ T_Xleave = 435,
+ T_Year = 436,
+ T_Flag = 437,
+ T_EOC = 438,
+ T_Simulate = 439,
+ T_Beep_Delay = 440,
+ T_Sim_Duration = 441,
+ T_Server_Offset = 442,
+ T_Duration = 443,
+ T_Freq_Offset = 444,
+ T_Wander = 445,
+ T_Jitter = 446,
+ T_Prop_Delay = 447,
+ T_Proc_Delay = 448
+ };
+#endif
+/* Tokens. */
+#define T_Abbrev 258
+#define T_Age 259
+#define T_All 260
+#define T_Allan 261
+#define T_Allpeers 262
+#define T_Auth 263
+#define T_Autokey 264
+#define T_Automax 265
+#define T_Average 266
+#define T_Bclient 267
+#define T_Beacon 268
+#define T_Broadcast 269
+#define T_Broadcastclient 270
+#define T_Broadcastdelay 271
+#define T_Burst 272
+#define T_Calibrate 273
+#define T_Ceiling 274
+#define T_Clockstats 275
+#define T_Cohort 276
+#define T_ControlKey 277
+#define T_Crypto 278
+#define T_Cryptostats 279
+#define T_Ctl 280
+#define T_Day 281
+#define T_Default 282
+#define T_Digest 283
+#define T_Disable 284
+#define T_Discard 285
+#define T_Dispersion 286
+#define T_Double 287
+#define T_Driftfile 288
+#define T_Drop 289
+#define T_Dscp 290
+#define T_Ellipsis 291
+#define T_Enable 292
+#define T_End 293
+#define T_False 294
+#define T_File 295
+#define T_Filegen 296
+#define T_Filenum 297
+#define T_Flag1 298
+#define T_Flag2 299
+#define T_Flag3 300
+#define T_Flag4 301
+#define T_Flake 302
+#define T_Floor 303
+#define T_Freq 304
+#define T_Fudge 305
+#define T_Host 306
+#define T_Huffpuff 307
+#define T_Iburst 308
+#define T_Ident 309
+#define T_Ignore 310
+#define T_Incalloc 311
+#define T_Incmem 312
+#define T_Initalloc 313
+#define T_Initmem 314
+#define T_Includefile 315
+#define T_Integer 316
+#define T_Interface 317
+#define T_Intrange 318
+#define T_Io 319
+#define T_Ipv4 320
+#define T_Ipv4_flag 321
+#define T_Ipv6 322
+#define T_Ipv6_flag 323
+#define T_Kernel 324
+#define T_Key 325
+#define T_Keys 326
+#define T_Keysdir 327
+#define T_Kod 328
+#define T_Mssntp 329
+#define T_Leapfile 330
+#define T_Leapsmearinterval 331
+#define T_Limited 332
+#define T_Link 333
+#define T_Listen 334
+#define T_Logconfig 335
+#define T_Logfile 336
+#define T_Loopstats 337
+#define T_Lowpriotrap 338
+#define T_Manycastclient 339
+#define T_Manycastserver 340
+#define T_Mask 341
+#define T_Maxage 342
+#define T_Maxclock 343
+#define T_Maxdepth 344
+#define T_Maxdist 345
+#define T_Maxmem 346
+#define T_Maxpoll 347
+#define T_Mdnstries 348
+#define T_Mem 349
+#define T_Memlock 350
+#define T_Minclock 351
+#define T_Mindepth 352
+#define T_Mindist 353
+#define T_Minimum 354
+#define T_Minpoll 355
+#define T_Minsane 356
+#define T_Mode 357
+#define T_Mode7 358
+#define T_Monitor 359
+#define T_Month 360
+#define T_Mru 361
+#define T_Multicastclient 362
+#define T_Nic 363
+#define T_Nolink 364
+#define T_Nomodify 365
+#define T_Nomrulist 366
+#define T_None 367
+#define T_Nonvolatile 368
+#define T_Nopeer 369
+#define T_Noquery 370
+#define T_Noselect 371
+#define T_Noserve 372
+#define T_Notrap 373
+#define T_Notrust 374
+#define T_Ntp 375
+#define T_Ntpport 376
+#define T_NtpSignDsocket 377
+#define T_Orphan 378
+#define T_Orphanwait 379
+#define T_Panic 380
+#define T_Peer 381
+#define T_Peerstats 382
+#define T_Phone 383
+#define T_Pid 384
+#define T_Pidfile 385
+#define T_Pool 386
+#define T_Port 387
+#define T_Preempt 388
+#define T_Prefer 389
+#define T_Protostats 390
+#define T_Pw 391
+#define T_Randfile 392
+#define T_Rawstats 393
+#define T_Refid 394
+#define T_Requestkey 395
+#define T_Reset 396
+#define T_Restrict 397
+#define T_Revoke 398
+#define T_Rlimit 399
+#define T_Saveconfigdir 400
+#define T_Server 401
+#define T_Setvar 402
+#define T_Source 403
+#define T_Stacksize 404
+#define T_Statistics 405
+#define T_Stats 406
+#define T_Statsdir 407
+#define T_Step 408
+#define T_Stepback 409
+#define T_Stepfwd 410
+#define T_Stepout 411
+#define T_Stratum 412
+#define T_String 413
+#define T_Sys 414
+#define T_Sysstats 415
+#define T_Tick 416
+#define T_Time1 417
+#define T_Time2 418
+#define T_Timer 419
+#define T_Timingstats 420
+#define T_Tinker 421
+#define T_Tos 422
+#define T_Trap 423
+#define T_True 424
+#define T_Trustedkey 425
+#define T_Ttl 426
+#define T_Type 427
+#define T_U_int 428
+#define T_Unconfig 429
+#define T_Unpeer 430
+#define T_Version 431
+#define T_WanderThreshold 432
+#define T_Week 433
+#define T_Wildcard 434
+#define T_Xleave 435
+#define T_Year 436
+#define T_Flag 437
+#define T_EOC 438
+#define T_Simulate 439
+#define T_Beep_Delay 440
+#define T_Sim_Duration 441
+#define T_Server_Offset 442
+#define T_Duration 443
+#define T_Freq_Offset 444
+#define T_Wander 445
+#define T_Jitter 446
+#define T_Prop_Delay 447
+#define T_Proc_Delay 448
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2053 of yacc.c */
+#line 51 "../../ntpd/ntp_parser.y"
+
+ char * String;
+ double Double;
+ int Integer;
+ unsigned U_int;
+ gen_fifo * Generic_fifo;
+ attr_val * Attr_val;
+ attr_val_fifo * Attr_val_fifo;
+ int_fifo * Int_fifo;
+ string_fifo * String_fifo;
+ address_node * Address_node;
+ address_fifo * Address_fifo;
+ setvar_node * Set_var;
+ server_info * Sim_server;
+ server_info_fifo * Sim_server_fifo;
+ script_info * Sim_script;
+ script_info_fifo * Sim_script_fifo;
+
+
+/* Line 2053 of yacc.c */
+#line 463 "ntp_parser.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_NTP_PARSER_H_INCLUDED */
diff --git a/contrib/ntp/ntpd/ntp_peer.c b/contrib/ntp/ntpd/ntp_peer.c
index deeec5b..d42d804 100644
--- a/contrib/ntp/ntpd/ntp_peer.c
+++ b/contrib/ntp/ntpd/ntp_peer.c
@@ -9,19 +9,14 @@
#include <sys/types.h>
#include "ntpd.h"
+#include "ntp_lists.h"
#include "ntp_stdlib.h"
+#include "ntp_control.h"
#include <ntp_random.h>
-#ifdef OPENSSL
-#include "openssl/rand.h"
-#endif /* OPENSSL */
-
-#ifdef SYS_WINNT
-extern int accept_wildcard_if_for_winnt;
-#endif
/*
- * Table of valid association combinations
- * ---------------------------------------
+ * Table of valid association combinations
+ * ---------------------------------------
*
* packet->mode
* peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST
@@ -29,7 +24,7 @@ extern int accept_wildcard_if_for_winnt;
* NO_PEER | e 1 0 1 1 1
* ACTIVE | e 1 1 0 0 0
* PASSIVE | e 1 e 0 0 0
- * CLIENT | e 0 0 0 1 1
+ * CLIENT | e 0 0 0 1 0
* SERVER | e 0 0 0 0 0
* BCAST | e 0 0 0 0 0
* BCLIENT | e 0 0 0 e 1
@@ -45,15 +40,16 @@ extern int accept_wildcard_if_for_winnt;
#define NO_PEER 0 /* action when no peer is found */
int AM[AM_MODES][AM_MODES] = {
-/* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */
-
+/* packet->mode */
+/* peer { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */
+/* mode */
/*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, AM_FXMIT, AM_MANYCAST, AM_NEWBCL},
/*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
/*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
-/*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_POSSBCL},
+/*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_NOMATCH},
/*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
@@ -62,53 +58,70 @@ int AM[AM_MODES][AM_MODES] = {
/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT},
};
-#define MATCH_ASSOC(x,y) AM[(x)][(y)]
+#define MATCH_ASSOC(x, y) AM[(x)][(y)]
/*
* These routines manage the allocation of memory to peer structures
- * and the maintenance of the peer hash table. The two main entry
- * points are findpeer(), which looks for matching peer sturctures in
- * the peer list, newpeer(), which allocates a new peer structure and
- * adds it to the list, and unpeer(), which demobilizes the association
- * and deallocates the structure.
+ * and the maintenance of three data structures involving all peers:
+ *
+ * - peer_list is a single list with all peers, suitable for scanning
+ * operations over all peers.
+ * - peer_adr_hash is an array of lists indexed by hashed peer address.
+ * - peer_aid_hash is an array of lists indexed by hashed associd.
+ *
+ * They also maintain a free list of peer structures, peer_free.
+ *
+ * The three main entry points are findpeer(), which looks for matching
+ * peer structures in the peer list, newpeer(), which allocates a new
+ * peer structure and adds it to the list, and unpeer(), which
+ * demobilizes the association and deallocates the structure.
*/
/*
* Peer hash tables
*/
struct peer *peer_hash[NTP_HASH_SIZE]; /* peer hash table */
-int peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
+int peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
struct peer *assoc_hash[NTP_HASH_SIZE]; /* association ID hash table */
-int assoc_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
+int assoc_hash_count[NTP_HASH_SIZE];/* peers in each bucket */
+struct peer *peer_list; /* peer structures list */
static struct peer *peer_free; /* peer structures free list */
-int peer_free_count; /* count of free structures */
+int peer_free_count; /* count of free structures */
/*
* Association ID. We initialize this value randomly, then assign a new
- * value every time the peer structure is incremented.
+ * value every time an association is mobilized.
*/
static associd_t current_association_ID; /* association ID */
+static associd_t initial_association_ID; /* association ID */
/*
* Memory allocation watermarks.
*/
-#define INIT_PEER_ALLOC 15 /* initialize for 15 peers */
-#define INC_PEER_ALLOC 5 /* when run out, add 5 more */
+#define INIT_PEER_ALLOC 8 /* static preallocation */
+#define INC_PEER_ALLOC 4 /* add N more when empty */
/*
* Miscellaneous statistic counters which may be queried.
*/
-u_long peer_timereset; /* time stat counters zeroed */
-u_long findpeer_calls; /* calls to findpeer */
-u_long assocpeer_calls; /* calls to findpeerbyassoc */
-u_long peer_allocations; /* allocations from free list */
-u_long peer_demobilizations; /* structs freed to free list */
-int total_peer_structs; /* peer structs */
-int peer_associations; /* mobilized associations */
-int peer_preempt; /* preemptable associations */
+u_long peer_timereset; /* time stat counters zeroed */
+u_long findpeer_calls; /* calls to findpeer */
+u_long assocpeer_calls; /* calls to findpeerbyassoc */
+u_long peer_allocations; /* allocations from free list */
+u_long peer_demobilizations; /* structs freed to free list */
+int total_peer_structs; /* peer structs */
+int peer_associations; /* mobilized associations */
+int peer_preempt; /* preemptable associations */
static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
-static void getmorepeermem P((void));
-static struct interface *select_peerinterface P((struct peer *, struct sockaddr_storage *, struct interface *, u_char));
+static struct peer * findexistingpeer_name(const char *, u_short,
+ struct peer *, int);
+static struct peer * findexistingpeer_addr(sockaddr_u *,
+ struct peer *, int,
+ u_char);
+static void free_peer(struct peer *, int);
+static void getmorepeermem(void);
+static int score(struct peer *);
+
/*
* init_peer - initialize peer data structures and counters
@@ -119,39 +132,23 @@ static struct interface *select_peerinterface P((struct peer *, struct sockaddr_
void
init_peer(void)
{
- register int i;
-
- /*
- * Clear hash table and counters.
- */
- for (i = 0; i < NTP_HASH_SIZE; i++) {
- peer_hash[i] = 0;
- peer_hash_count[i] = 0;
- assoc_hash[i] = 0;
- assoc_hash_count[i] = 0;
- }
-
- /*
- * Clear stat counters
- */
- findpeer_calls = peer_allocations = 0;
- assocpeer_calls = peer_demobilizations = 0;
+ int i;
/*
- * Initialize peer memory.
+ * Initialize peer free list from static allocation.
*/
- peer_free = 0;
- for (i = 0; i < INIT_PEER_ALLOC; i++) {
- init_peer_alloc[i].next = peer_free;
- peer_free = &init_peer_alloc[i];
- }
- total_peer_structs = INIT_PEER_ALLOC;
- peer_free_count = INIT_PEER_ALLOC;
+ for (i = COUNTOF(init_peer_alloc) - 1; i >= 0; i--)
+ LINK_SLIST(peer_free, &init_peer_alloc[i], p_link);
+ total_peer_structs = COUNTOF(init_peer_alloc);
+ peer_free_count = COUNTOF(init_peer_alloc);
/*
* Initialize our first association ID
*/
- while ((current_association_ID = ntp_random() & 0xffff) == 0);
+ do
+ current_association_ID = ntp_random() & ASSOCID_MAX;
+ while (!current_association_ID);
+ initial_association_ID = current_association_ID;
}
@@ -161,90 +158,172 @@ init_peer(void)
static void
getmorepeermem(void)
{
- register int i;
- register struct peer *peer;
-
- peer = (struct peer *)emalloc(INC_PEER_ALLOC *
- sizeof(struct peer));
- for (i = 0; i < INC_PEER_ALLOC; i++) {
- peer->next = peer_free;
- peer_free = peer;
- peer++;
- }
+ int i;
+ struct peer *peers;
+
+ peers = emalloc_zero(INC_PEER_ALLOC * sizeof(*peers));
+
+ for (i = INC_PEER_ALLOC - 1; i >= 0; i--)
+ LINK_SLIST(peer_free, &peers[i], p_link);
total_peer_structs += INC_PEER_ALLOC;
peer_free_count += INC_PEER_ALLOC;
}
-/*
- * findexistingpeer - return a pointer to a peer in the hash table
- */
-struct peer *
-findexistingpeer(
- struct sockaddr_storage *addr,
- struct peer *start_peer,
- int mode
+static struct peer *
+findexistingpeer_name(
+ const char * hostname,
+ u_short hname_fam,
+ struct peer * start_peer,
+ int mode
+ )
+{
+ struct peer *p;
+
+ if (NULL == start_peer)
+ p = peer_list;
+ else
+ p = start_peer->p_link;
+ for (; p != NULL; p = p->p_link)
+ if (p->hostname != NULL
+ && (-1 == mode || p->hmode == mode)
+ && (AF_UNSPEC == hname_fam
+ || AF_UNSPEC == AF(&p->srcadr)
+ || hname_fam == AF(&p->srcadr))
+ && !strcasecmp(p->hostname, hostname))
+ break;
+ return p;
+}
+
+
+static
+struct peer *
+findexistingpeer_addr(
+ sockaddr_u * addr,
+ struct peer * start_peer,
+ int mode,
+ u_char cast_flags
)
{
- register struct peer *peer;
+ struct peer *peer;
+
+ DPRINTF(2, ("findexistingpeer_addr(%s, %s, %d, 0x%x)\n",
+ sptoa(addr),
+ (start_peer)
+ ? sptoa(&start_peer->srcadr)
+ : "NULL",
+ mode, (u_int)cast_flags));
/*
* start_peer is included so we can locate instances of the
* same peer through different interfaces in the hash table.
+ * Without MDF_BCLNT, a match requires the same mode and remote
+ * address. MDF_BCLNT associations start out as MODE_CLIENT
+ * if broadcastdelay is not specified, and switch to
+ * MODE_BCLIENT after estimating the one-way delay. Duplicate
+ * associations are expanded in definition to match any other
+ * MDF_BCLNT with the same srcadr (remote, unicast address).
*/
- if (start_peer == 0)
+ if (NULL == start_peer)
peer = peer_hash[NTP_HASH_ADDR(addr)];
else
- peer = start_peer->next;
+ peer = start_peer->adr_link;
- while (peer != 0) {
- if (SOCKCMP(addr, &peer->srcadr)
- && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) {
- if (mode == -1)
- return (peer);
- else if (peer->hmode == mode)
- break;
+ while (peer != NULL) {
+ DPRINTF(3, ("%s %s %d %d 0x%x 0x%x ", sptoa(addr),
+ sptoa(&peer->srcadr), mode, peer->hmode,
+ (u_int)cast_flags, (u_int)peer->cast_flags));
+ if ((-1 == mode || peer->hmode == mode ||
+ ((MDF_BCLNT & peer->cast_flags) &&
+ (MDF_BCLNT & cast_flags))) &&
+ ADDR_PORT_EQ(addr, &peer->srcadr)) {
+ DPRINTF(3, ("found.\n"));
+ break;
}
- peer = peer->next;
+ DPRINTF(3, ("\n"));
+ peer = peer->adr_link;
}
- return (peer);
+
+ return peer;
+}
+
+
+/*
+ * findexistingpeer - search by address and return a pointer to a peer.
+ */
+struct peer *
+findexistingpeer(
+ sockaddr_u * addr,
+ const char * hostname,
+ struct peer * start_peer,
+ int mode,
+ u_char cast_flags
+ )
+{
+ if (hostname != NULL)
+ return findexistingpeer_name(hostname, AF(addr),
+ start_peer, mode);
+ else
+ return findexistingpeer_addr(addr, start_peer, mode,
+ cast_flags);
}
/*
- * findpeer - find and return a peer in the hash table.
+ * findpeer - find and return a peer match for a received datagram in
+ * the peer_hash table.
*/
struct peer *
findpeer(
- struct sockaddr_storage *srcadr,
- struct interface *dstadr,
- int pkt_mode,
- int *action
+ struct recvbuf *rbufp,
+ int pkt_mode,
+ int * action
)
{
- register struct peer *peer;
- int hash;
+ struct peer * p;
+ sockaddr_u * srcadr;
+ u_int hash;
+ struct pkt * pkt;
+ l_fp pkt_org;
findpeer_calls++;
+ srcadr = &rbufp->recv_srcadr;
hash = NTP_HASH_ADDR(srcadr);
- for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) {
- if (SOCKCMP(srcadr, &peer->srcadr) &&
- NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
+ for (p = peer_hash[hash]; p != NULL; p = p->adr_link) {
+ if (ADDR_PORT_EQ(srcadr, &p->srcadr)) {
/*
* if the association matching rules determine
* that this is not a valid combination, then
* look for the next valid peer association.
*/
- *action = MATCH_ASSOC(peer->hmode, pkt_mode);
+ *action = MATCH_ASSOC(p->hmode, pkt_mode);
+
+ /*
+ * A response to our manycastclient solicitation
+ * might be misassociated with an ephemeral peer
+ * already spun for the server. If the packet's
+ * org timestamp doesn't match the peer's, check
+ * if it matches the ACST prototype peer's. If
+ * so it is a redundant solicitation response,
+ * return AM_ERR to discard it. [Bug 1762]
+ */
+ if (MODE_SERVER == pkt_mode &&
+ AM_PROCPKT == *action) {
+ pkt = &rbufp->recv_pkt;
+ NTOHL_FP(&pkt->org, &pkt_org);
+ if (!L_ISEQU(&p->aorg, &pkt_org) &&
+ findmanycastpeer(rbufp))
+ *action = AM_ERR;
+ }
/*
* if an error was returned, exit back right
* here.
*/
if (*action == AM_ERR)
- return ((struct peer *)0);
+ return NULL;
/*
* if a match is found, we stop our search.
@@ -257,36 +336,36 @@ findpeer(
/*
* If no matching association is found
*/
- if (peer == 0) {
+ if (NULL == p) {
*action = MATCH_ASSOC(NO_PEER, pkt_mode);
- return ((struct peer *)0);
+ } else if (p->dstadr != rbufp->dstadr) {
+ set_peerdstadr(p, rbufp->dstadr);
+ if (p->dstadr == rbufp->dstadr) {
+ DPRINTF(1, ("Changed %s local address to match response\n",
+ stoa(&p->srcadr)));
+ return findpeer(rbufp, pkt_mode, action);
+ }
}
-
- set_peerdstadr(peer, dstadr);
-
- return (peer);
+ return p;
}
/*
- * findpeerbyassocid - find and return a peer using his association ID
+ * findpeerbyassoc - find and return a peer using his association ID
*/
struct peer *
findpeerbyassoc(
- u_int assoc
+ associd_t assoc
)
{
- register struct peer *peer;
- int hash;
+ struct peer *p;
+ u_int hash;
assocpeer_calls++;
-
hash = assoc & NTP_HASH_MASK;
- for (peer = assoc_hash[hash]; peer != 0; peer =
- peer->ass_next) {
- if (assoc == peer->associd)
- return (peer);
- }
- return (NULL);
+ for (p = assoc_hash[hash]; p != NULL; p = p->aid_link)
+ if (assoc == p->associd)
+ break;
+ return p;
}
@@ -296,27 +375,148 @@ findpeerbyassoc(
void
clear_all(void)
{
- struct peer *peer, *next_peer;
- int n;
+ struct peer *p;
/*
* This routine is called when the clock is stepped, and so all
* previously saved time values are untrusted.
*/
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- if (!(peer->cast_flags & (MDF_ACAST | MDF_MCAST |
- MDF_BCAST))) {
- peer->hpoll = peer->minpoll;
- peer_clear(peer, "STEP");
- }
+ for (p = peer_list; p != NULL; p = p->p_link)
+ if (!(MDF_TXONLY_MASK & p->cast_flags))
+ peer_clear(p, "STEP");
+
+ DPRINTF(1, ("clear_all: at %lu\n", current_time));
+}
+
+
+/*
+ * score_all() - determine if an association can be demobilized
+ */
+int
+score_all(
+ struct peer *peer /* peer structure pointer */
+ )
+{
+ struct peer *speer;
+ int temp, tamp;
+ int x;
+
+ /*
+ * This routine finds the minimum score for all preemptible
+ * associations and returns > 0 if the association can be
+ * demobilized.
+ */
+ tamp = score(peer);
+ temp = 100;
+ for (speer = peer_list; speer != NULL; speer = speer->p_link)
+ if (speer->flags & FLAG_PREEMPT) {
+ x = score(speer);
+ if (x < temp)
+ temp = x;
+ }
+ DPRINTF(1, ("score_all: at %lu score %d min %d\n",
+ current_time, tamp, temp));
+
+ if (tamp != temp)
+ temp = 0;
+
+ return temp;
+}
+
+
+/*
+ * score() - calculate preemption score
+ */
+static int
+score(
+ struct peer *peer /* peer structure pointer */
+ )
+{
+ int temp;
+
+ /*
+ * This routine calculates the premption score from the peer
+ * error bits and status. Increasing values are more cherished.
+ */
+ temp = 0;
+ if (!(peer->flash & TEST10))
+ temp++; /* 1 good synch and stratum */
+ if (!(peer->flash & TEST13))
+ temp++; /* 2 reachable */
+ if (!(peer->flash & TEST12))
+ temp++; /* 3 no loop */
+ if (!(peer->flash & TEST11))
+ temp++; /* 4 good distance */
+ if (peer->status >= CTL_PST_SEL_SELCAND)
+ temp++; /* 5 in the hunt */
+ if (peer->status != CTL_PST_SEL_EXCESS)
+ temp++; /* 6 not spare tire */
+ return (temp); /* selection status */
+}
+
+
+/*
+ * free_peer - internal routine to free memory referred to by a struct
+ * peer and return it to the peer free list. If unlink is
+ * nonzero, unlink from the various lists.
+ */
+static void
+free_peer(
+ struct peer * p,
+ int unlink_peer
+ )
+{
+ struct peer * unlinked;
+ int hash;
+
+ if (unlink_peer) {
+ hash = NTP_HASH_ADDR(&p->srcadr);
+ peer_hash_count[hash]--;
+
+ UNLINK_SLIST(unlinked, peer_hash[hash], p, adr_link,
+ struct peer);
+ if (NULL == unlinked) {
+ peer_hash_count[hash]++;
+ msyslog(LOG_ERR, "peer %s not in address table!",
+ stoa(&p->srcadr));
+ }
+
+ /*
+ * Remove him from the association hash as well.
+ */
+ hash = p->associd & NTP_HASH_MASK;
+ assoc_hash_count[hash]--;
+
+ UNLINK_SLIST(unlinked, assoc_hash[hash], p, aid_link,
+ struct peer);
+ if (NULL == unlinked) {
+ assoc_hash_count[hash]++;
+ msyslog(LOG_ERR,
+ "peer %s not in association ID table!",
+ stoa(&p->srcadr));
}
+
+ /* Remove him from the overall list. */
+ UNLINK_SLIST(unlinked, peer_list, p, p_link,
+ struct peer);
+ if (NULL == unlinked)
+ msyslog(LOG_ERR, "%s not in peer list!",
+ stoa(&p->srcadr));
}
-#ifdef DEBUG
- if (debug)
- printf("clear_all: at %lu\n", current_time);
-#endif
+
+ if (p->hostname != NULL)
+ free(p->hostname);
+
+ if (p->ident != NULL)
+ free(p->ident);
+
+ if (p->addrs != NULL)
+ free(p->addrs); /* from copy_addrinfo_list() */
+
+ /* Add his corporeal form to peer free list */
+ ZERO(*p);
+ LINK_SLIST(peer_free, p, p_link);
+ peer_free_count++;
}
@@ -325,91 +525,25 @@ clear_all(void)
*/
void
unpeer(
- struct peer *peer_to_remove
+ struct peer *peer
)
{
- int hash;
-#ifdef OPENSSL
- char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
-
- if (peer_to_remove->flags & FLAG_SKEY) {
- sprintf(statstr, "unpeer %d flash %x reach %03o flags %04x",
- peer_to_remove->associd, peer_to_remove->flash,
- peer_to_remove->reach, peer_to_remove->flags);
- record_crypto_stats(&peer_to_remove->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("peer: %s\n", statstr);
-#endif
- }
-#endif /* OPENSSL */
-#ifdef DEBUG
- if (debug)
- printf("demobilize %u %d %d\n", peer_to_remove->associd,
- peer_associations, peer_preempt);
-#endif
- set_peerdstadr(peer_to_remove, NULL);
-
- /* XXXMEMLEAK? peer_clear->crypto allocation */
-
- hash = NTP_HASH_ADDR(&peer_to_remove->srcadr);
- peer_hash_count[hash]--;
+ mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd);
+ restrict_source(&peer->srcadr, 1, 0);
+ set_peerdstadr(peer, NULL);
peer_demobilizations++;
peer_associations--;
- if (peer_to_remove->flags & FLAG_PREEMPT)
+ if (FLAG_PREEMPT & peer->flags)
peer_preempt--;
#ifdef REFCLOCK
/*
* If this peer is actually a clock, shut it down first
*/
- if (peer_to_remove->flags & FLAG_REFCLOCK)
- refclock_unpeer(peer_to_remove);
+ if (FLAG_REFCLOCK & peer->flags)
+ refclock_unpeer(peer);
#endif
- peer_to_remove->action = 0; /* disable timeout actions */
- if (peer_hash[hash] == peer_to_remove)
- peer_hash[hash] = peer_to_remove->next;
- else {
- register struct peer *peer;
-
- peer = peer_hash[hash];
- while (peer != 0 && peer->next != peer_to_remove)
- peer = peer->next;
-
- if (peer == 0) {
- peer_hash_count[hash]++;
- msyslog(LOG_ERR, "peer struct for %s not in table!",
- stoa(&peer->srcadr));
- } else {
- peer->next = peer_to_remove->next;
- }
- }
- /*
- * Remove him from the association hash as well.
- */
- hash = peer_to_remove->associd & NTP_HASH_MASK;
- assoc_hash_count[hash]--;
- if (assoc_hash[hash] == peer_to_remove)
- assoc_hash[hash] = peer_to_remove->ass_next;
- else {
- register struct peer *peer;
-
- peer = assoc_hash[hash];
- while (peer != 0 && peer->ass_next != peer_to_remove)
- peer = peer->ass_next;
-
- if (peer == 0) {
- assoc_hash_count[hash]++;
- msyslog(LOG_ERR,
- "peer struct for %s not in association table!",
- stoa(&peer->srcadr));
- } else {
- peer->ass_next = peer_to_remove->ass_next;
- }
- }
- peer_to_remove->next = peer_free;
- peer_free = peer_to_remove;
- peer_free_count++;
+ free_peer(peer, TRUE);
}
@@ -418,152 +552,98 @@ unpeer(
*/
struct peer *
peer_config(
- struct sockaddr_storage *srcadr,
- struct interface *dstadr,
- int hmode,
- int version,
- int minpoll,
- int maxpoll,
- u_int flags,
- int ttl,
- keyid_t key,
- u_char *keystr
+ sockaddr_u * srcadr,
+ const char * hostname,
+ endpt * dstadr,
+ u_char hmode,
+ u_char version,
+ u_char minpoll,
+ u_char maxpoll,
+ u_int flags,
+ u_int32 ttl,
+ keyid_t key,
+ const char * ident /* autokey group */
)
{
- register struct peer *peer;
u_char cast_flags;
/*
- * First search from the beginning for an association with given
- * remote address and mode. If an interface is given, search
- * from there to find the association which matches that
- * destination. If the given interface is "any", track down
- * the actual interface, because that's what gets put into the
- * peer structure.
- */
- peer = findexistingpeer(srcadr, (struct peer *)0, hmode);
- if (dstadr != 0) {
- while (peer != 0) {
- if (peer->dstadr == dstadr)
- break;
- if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) &&
- peer->dstadr == findinterface(srcadr))
- break;
- peer = findexistingpeer(srcadr, peer, hmode);
- }
- }
-
- /*
* We do a dirty little jig to figure the cast flags. This is
* probably not the best place to do this, at least until the
* configure code is rebuilt. Note only one flag can be set.
*/
switch (hmode) {
-
case MODE_BROADCAST:
- if(srcadr->ss_family == AF_INET) {
- if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr)))
- cast_flags = MDF_MCAST;
- else
- cast_flags = MDF_BCAST;
- break;
- }
- else {
- if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr))
- cast_flags = MDF_MCAST;
- else
- cast_flags = MDF_BCAST;
- break;
- }
+ if (IS_MCAST(srcadr))
+ cast_flags = MDF_MCAST;
+ else
+ cast_flags = MDF_BCAST;
+ break;
case MODE_CLIENT:
- if(srcadr->ss_family == AF_INET) {
- if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr)))
- cast_flags = MDF_ACAST;
- else
- cast_flags = MDF_UCAST;
- break;
- }
- else {
- if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr))
- cast_flags = MDF_ACAST;
- else
- cast_flags = MDF_UCAST;
- break;
- }
+ if (hostname != NULL && SOCK_UNSPEC(srcadr))
+ cast_flags = MDF_POOL;
+ else if (IS_MCAST(srcadr))
+ cast_flags = MDF_ACAST;
+ else
+ cast_flags = MDF_UCAST;
+ break;
default:
cast_flags = MDF_UCAST;
}
/*
- * If the peer is already configured, some dope has a duplicate
- * configureation entry or another dope is wiggling from afar.
- */
- if (peer != 0) {
- peer->hmode = (u_char)hmode;
- peer->version = (u_char) version;
- peer->minpoll = (u_char) minpoll;
- peer->maxpoll = (u_char) maxpoll;
- peer->flags = flags | FLAG_CONFIG |
- (peer->flags & FLAG_REFCLOCK);
- peer->cast_flags = cast_flags;
- peer->ttl = (u_char) ttl;
- peer->keyid = key;
- peer->precision = sys_precision;
- peer_clear(peer, "RMOT");
- return (peer);
- }
-
- /*
- * Here no match has been found, so presumably this is a new
- * persistent association. Mobilize the thing and initialize its
- * variables. If emulating ntpdate, force iburst.
+ * Mobilize the association and initialize its variables. If
+ * emulating ntpdate, force iburst. For pool and manycastclient
+ * strip FLAG_PREEMPT as the prototype associations are not
+ * themselves preemptible, though the resulting associations
+ * are.
*/
+ flags |= FLAG_CONFIG;
if (mode_ntpdate)
flags |= FLAG_IBURST;
- peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
- flags | FLAG_CONFIG, cast_flags, ttl, key);
- return (peer);
+ if ((MDF_ACAST | MDF_POOL) & cast_flags)
+ flags &= ~FLAG_PREEMPT;
+ return newpeer(srcadr, hostname, dstadr, hmode, version,
+ minpoll, maxpoll, flags, cast_flags, ttl, key, ident);
}
/*
- * setup peer dstadr field keeping it in sync with the interface structures
+ * setup peer dstadr field keeping it in sync with the interface
+ * structures
*/
void
-set_peerdstadr(struct peer *peer, struct interface *interface)
+set_peerdstadr(
+ struct peer * p,
+ endpt * dstadr
+ )
{
- if (peer->dstadr != interface) {
- if (interface != NULL &&
- (peer->cast_flags & MDF_BCLNT) &&
- (interface->flags & INT_MCASTIF) &&
- peer->burst) {
- /*
- * don't accept updates to a true multicast reception
- * interface while a BCLNT peer is running it's
- * unicast protocol
- */
- return;
- }
-
- if (peer->dstadr != NULL)
- {
- peer->dstadr->peercnt--;
- ISC_LIST_UNLINK_TYPE(peer->dstadr->peers, peer, ilink, struct peer);
- }
-
- DPRINTF(4, ("set_peerdstadr(%s): change interface from %s to %s\n",
- stoa(&peer->srcadr),
- (peer->dstadr != NULL) ? stoa(&peer->dstadr->sin) : "<null>",
- (interface != NULL) ? stoa(&interface->sin) : "<null>"));
+ struct peer * unlinked;
- peer->dstadr = interface;
+ if (p->dstadr == dstadr)
+ return;
- if (peer->dstadr != NULL)
- {
- ISC_LIST_APPEND(peer->dstadr->peers, peer, ilink);
- peer->dstadr->peercnt++;
- }
+ /*
+ * Don't accept updates to a separate multicast receive-only
+ * endpt while a BCLNT peer is running its unicast protocol.
+ */
+ if (dstadr != NULL && (FLAG_BC_VOL & p->flags) &&
+ (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) {
+ return;
+ }
+ if (p->dstadr != NULL) {
+ p->dstadr->peercnt--;
+ UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink,
+ struct peer);
+ msyslog(LOG_INFO, "%s local addr %s -> %s",
+ stoa(&p->srcadr), latoa(p->dstadr),
+ latoa(dstadr));
+ }
+ p->dstadr = dstadr;
+ if (dstadr != NULL) {
+ LINK_SLIST(dstadr->peers, p, ilink);
+ dstadr->peercnt++;
}
}
@@ -571,176 +651,164 @@ set_peerdstadr(struct peer *peer, struct interface *interface)
* attempt to re-rebind interface if necessary
*/
static void
-peer_refresh_interface(struct peer *peer)
+peer_refresh_interface(
+ struct peer *p
+ )
{
- struct interface *niface, *piface;
-
- niface = select_peerinterface(peer, &peer->srcadr, NULL, peer->cast_flags);
-
-#ifdef DEBUG
- if (debug > 3)
- {
- printf(
- "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x: new interface: ",
- peer->dstadr == NULL ? "<null>" : stoa(&peer->dstadr->sin),
- stoa(&peer->srcadr),
- peer->hmode, peer->version, peer->minpoll,
- peer->maxpoll, peer->flags, peer->cast_flags,
- peer->ttl, peer->keyid);
- if (niface != NULL)
- {
- printf("fd=%d, bfd=%d, name=%.16s, flags=0x%x, scope=%d, ",
- niface->fd,
- niface->bfd,
- niface->name,
- niface->flags,
- niface->scopeid);
- /* Leave these as three printf calls. */
- printf(", sin=%s",
- stoa((&niface->sin)));
- if (niface->flags & INT_BROADCAST)
- printf(", bcast=%s,",
- stoa((&niface->bcast)));
- printf(", mask=%s\n",
- stoa((&niface->mask)));
- }
- else
- {
- printf("<NONE>\n");
- }
+ endpt * niface;
+ endpt * piface;
+
+ niface = select_peerinterface(p, &p->srcadr, NULL);
+
+ DPRINTF(4, (
+ "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %u key %08x: new interface: ",
+ p->dstadr == NULL ? "<null>" :
+ stoa(&p->dstadr->sin), stoa(&p->srcadr), p->hmode,
+ p->version, p->minpoll, p->maxpoll, p->flags, p->cast_flags,
+ p->ttl, p->keyid));
+ if (niface != NULL) {
+ DPRINTF(4, (
+ "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s",
+ niface->fd, niface->bfd, niface->name,
+ niface->flags, niface->ifindex,
+ stoa(&niface->sin)));
+ if (niface->flags & INT_BROADCAST)
+ DPRINTF(4, (", bcast=%s",
+ stoa(&niface->bcast)));
+ DPRINTF(4, (", mask=%s\n", stoa(&niface->mask)));
+ } else {
+ DPRINTF(4, ("<NONE>\n"));
}
-#endif
- piface = peer->dstadr;
-
- set_peerdstadr(peer, niface);
-
- if (peer->dstadr) {
- /*
- * clear crypto if we change the local address
- */
- if (peer->dstadr != piface && !(peer->cast_flags & MDF_BCLNT)) {
- peer_crypto_clear(peer);
- }
+ piface = p->dstadr;
+ set_peerdstadr(p, niface);
+ if (p->dstadr != NULL) {
+ /*
+ * clear crypto if we change the local address
+ */
+ if (p->dstadr != piface && !(MDF_ACAST & p->cast_flags)
+ && MODE_BROADCAST != p->pmode)
+ peer_clear(p, "XFAC");
/*
* Broadcast needs the socket enabled for broadcast
*/
- if (peer->cast_flags & MDF_BCAST) {
- enable_broadcast(peer->dstadr, &peer->srcadr);
- }
+ if (MDF_BCAST & p->cast_flags)
+ enable_broadcast(p->dstadr, &p->srcadr);
/*
- * Multicast needs the socket interface enabled for multicast
+ * Multicast needs the socket interface enabled for
+ * multicast
*/
- if (peer->cast_flags & MDF_MCAST) {
- enable_multicast_if(peer->dstadr, &peer->srcadr);
- }
+ if (MDF_MCAST & p->cast_flags)
+ enable_multicast_if(p->dstadr, &p->srcadr);
}
}
+
/*
- * refresh_all_peerinterfaces - see that all interface bindings are up to date
+ * refresh_all_peerinterfaces - see that all interface bindings are up
+ * to date
*/
void
refresh_all_peerinterfaces(void)
{
- struct peer *peer, *next_peer;
- int n;
+ struct peer *p;
/*
* this is called when the interface list has changed
* give all peers a chance to find a better interface
*/
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- peer_refresh_interface(peer);
- }
- }
+ for (p = peer_list; p != NULL; p = p->p_link)
+ peer_refresh_interface(p);
}
-
+
/*
- * find an interface suitable for the src address
+ * newpeer - initialize a new peer association
*/
-static struct interface *
-select_peerinterface(struct peer *peer, struct sockaddr_storage *srcadr, struct interface *dstadr, u_char cast_flags)
+struct peer *
+newpeer(
+ sockaddr_u * srcadr,
+ const char * hostname,
+ endpt * dstadr,
+ u_char hmode,
+ u_char version,
+ u_char minpoll,
+ u_char maxpoll,
+ u_int flags,
+ u_char cast_flags,
+ u_int32 ttl,
+ keyid_t key,
+ const char * ident
+ )
{
- struct interface *interface;
-
+ struct peer * peer;
+ u_int hash;
+
+#ifdef AUTOKEY
/*
- * Initialize the peer structure and dance the interface jig.
- * Reference clocks step the loopback waltz, the others
- * squaredance around the interface list looking for a buddy. If
- * the dance peters out, there is always the wildcard interface.
- * This might happen in some systems and would preclude proper
- * operation with public key cryptography.
+ * If Autokey is requested but not configured, complain loudly.
*/
- if (ISREFCLOCKADR(srcadr))
- interface = loopback_interface;
- else
- if (cast_flags & (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
- interface = findbcastinter(srcadr);
-#ifdef DEBUG
- if (debug > 3) {
- if (interface != NULL)
- printf("Found *-cast interface address %s, for address %s\n",
- stoa(&(interface)->sin), stoa(srcadr));
- else
- printf("No *-cast local address found for address %s\n",
- stoa(srcadr));
- }
-#endif
- /*
- * If it was a multicast packet, findbcastinter() may not
- * find it, so try a little harder.
- */
- if (interface == ANY_INTERFACE_CHOOSE(srcadr))
- interface = findinterface(srcadr);
- }
- else if (dstadr != NULL && dstadr != ANY_INTERFACE_CHOOSE(srcadr))
- interface = dstadr;
- else
- interface = findinterface(srcadr);
+ if (!crypto_flags) {
+ if (key > NTP_MAXKEY) {
+ return (NULL);
+
+ } else if (flags & FLAG_SKEY) {
+ msyslog(LOG_ERR, "Autokey not configured");
+ return (NULL);
+ }
+ }
+#endif /* AUTOKEY */
/*
- * we do not bind to the wildcard interfaces for output
- * as our (network) source address would be undefined and
- * crypto will not work without knowing the own transmit address
+ * For now only pool associations have a hostname.
*/
- if (interface != NULL && interface->flags & INT_WILDCARD)
-#ifdef SYS_WINNT
- if ( !accept_wildcard_if_for_winnt )
-#endif
- interface = NULL;
+ NTP_INSIST(NULL == hostname || (MDF_POOL & cast_flags));
+ /*
+ * First search from the beginning for an association with given
+ * remote address and mode. If an interface is given, search
+ * from there to find the association which matches that
+ * destination. If the given interface is "any", track down the
+ * actual interface, because that's what gets put into the peer
+ * structure.
+ */
+ if (dstadr != NULL) {
+ peer = findexistingpeer(srcadr, hostname, NULL, hmode,
+ cast_flags);
+ while (peer != NULL) {
+ if (peer->dstadr == dstadr ||
+ ((MDF_BCLNT & cast_flags) &&
+ (MDF_BCLNT & peer->cast_flags)))
+ break;
- return interface;
-}
+ if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) &&
+ peer->dstadr == findinterface(srcadr))
+ break;
-/*
- * newpeer - initialize a new peer association
- */
-struct peer *
-newpeer(
- struct sockaddr_storage *srcadr,
- struct interface *dstadr,
- int hmode,
- int version,
- int minpoll,
- int maxpoll,
- u_int flags,
- u_char cast_flags,
- int ttl,
- keyid_t key
- )
-{
- register struct peer *peer;
- register int i;
-#ifdef OPENSSL
- char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
-#endif /* OPENSSL */
+ peer = findexistingpeer(srcadr, hostname, peer,
+ hmode, cast_flags);
+ }
+ } else {
+ /* no endpt address given */
+ peer = findexistingpeer(srcadr, hostname, NULL, hmode,
+ cast_flags);
+ }
+
+ /*
+ * If a peer is found, this would be a duplicate and we don't
+ * allow that. This avoids duplicate ephemeral (broadcast/
+ * multicast) and preemptible (manycast and pool) client
+ * associations.
+ */
+ if (peer != NULL) {
+ DPRINTF(2, ("newpeer(%s) found existing association\n",
+ (hostname)
+ ? hostname
+ : stoa(srcadr)));
+ return NULL;
+ }
/*
* Allocate a new peer structure. Some dirt here, since some of
@@ -748,13 +816,11 @@ newpeer(
*/
if (peer_free_count == 0)
getmorepeermem();
- peer = peer_free;
- peer_free = peer->next;
+ UNLINK_HEAD_SLIST(peer, peer_free, p_link);
peer_free_count--;
peer_associations++;
- if (flags & FLAG_PREEMPT)
+ if (FLAG_PREEMPT & flags)
peer_preempt++;
- memset((char *)peer, 0, sizeof(struct peer));
/*
* Assign an association ID and increment the system variable.
@@ -763,52 +829,68 @@ newpeer(
if (++current_association_ID == 0)
++current_association_ID;
- DPRINTF(3, ("newpeer: cast flags: 0x%x for address: %s\n",
- cast_flags, stoa(srcadr)));
-
- ISC_LINK_INIT(peer, ilink); /* set up interface link chain */
peer->srcadr = *srcadr;
- set_peerdstadr(peer, select_peerinterface(peer, srcadr, dstadr,
- cast_flags));
- peer->hmode = (u_char)hmode;
- peer->version = (u_char)version;
- peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll);
- peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll);
+ if (hostname != NULL)
+ peer->hostname = estrdup(hostname);
+ peer->hmode = hmode;
+ peer->version = version;
peer->flags = flags;
-#ifdef DEBUG
- if (debug > 2) {
- if (peer->dstadr)
- printf("newpeer: using fd %d and our addr %s\n",
- peer->dstadr->fd,
- stoa(&peer->dstadr->sin));
- else
- printf("newpeer: local interface currently not bound\n");
- }
-#endif
+ peer->cast_flags = cast_flags;
+ set_peerdstadr(peer,
+ select_peerinterface(peer, srcadr, dstadr));
+
+ /*
+ * It is an error to set minpoll less than NTP_MINPOLL or to
+ * set maxpoll greater than NTP_MAXPOLL. However, minpoll is
+ * clamped not greater than NTP_MAXPOLL and maxpoll is clamped
+ * not less than NTP_MINPOLL without complaint. Finally,
+ * minpoll is clamped not greater than maxpoll.
+ */
+ if (minpoll == 0)
+ peer->minpoll = NTP_MINDPOLL;
+ else
+ peer->minpoll = min(minpoll, NTP_MAXPOLL);
+ if (maxpoll == 0)
+ peer->maxpoll = NTP_MAXDPOLL;
+ else
+ peer->maxpoll = max(maxpoll, NTP_MINPOLL);
+ if (peer->minpoll > peer->maxpoll)
+ peer->minpoll = peer->maxpoll;
+
+ if (peer->dstadr != NULL)
+ DPRINTF(3, ("newpeer(%s): using fd %d and our addr %s\n",
+ stoa(srcadr), peer->dstadr->fd,
+ stoa(&peer->dstadr->sin)));
+ else
+ DPRINTF(3, ("newpeer(%s): local interface currently not bound\n",
+ stoa(srcadr)));
/*
* Broadcast needs the socket enabled for broadcast
*/
- if (cast_flags & MDF_BCAST && peer->dstadr) {
+ if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL)
enable_broadcast(peer->dstadr, srcadr);
- }
+
/*
* Multicast needs the socket interface enabled for multicast
*/
- if (cast_flags & MDF_MCAST && peer->dstadr) {
+ if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL)
enable_multicast_if(peer->dstadr, srcadr);
- }
- if (key != 0)
- peer->flags |= FLAG_AUTHENABLE;
+
+#ifdef AUTOKEY
if (key > NTP_MAXKEY)
peer->flags |= FLAG_SKEY;
- peer->cast_flags = cast_flags;
- peer->ttl = (u_char)ttl;
+#endif /* AUTOKEY */
+ peer->ttl = ttl;
peer->keyid = key;
+ if (ident != NULL)
+ peer->ident = estrdup(ident);
peer->precision = sys_precision;
peer->hpoll = peer->minpoll;
if (cast_flags & MDF_ACAST)
peer_clear(peer, "ACST");
+ else if (cast_flags & MDF_POOL)
+ peer_clear(peer, "POOL");
else if (cast_flags & MDF_MCAST)
peer_clear(peer, "MCST");
else if (cast_flags & MDF_BCAST)
@@ -825,105 +907,56 @@ newpeer(
peer->timereachable = current_time;
peer->timereceived = current_time;
-#ifdef REFCLOCK
if (ISREFCLOCKADR(&peer->srcadr)) {
-
+#ifdef REFCLOCK
/*
* We let the reference clock support do clock
* dependent initialization. This includes setting
* the peer timer, since the clock may have requirements
* for this.
*/
+ if (maxpoll == 0)
+ peer->maxpoll = peer->minpoll;
if (!refclock_newpeer(peer)) {
/*
* Dump it, something screwed up
*/
set_peerdstadr(peer, NULL);
-
- peer->next = peer_free;
- peer_free = peer;
- peer_free_count++;
- return (NULL);
+ free_peer(peer, 0);
+ return NULL;
}
+#else /* REFCLOCK */
+ msyslog(LOG_ERR, "refclock %s isn't supported. ntpd was compiled without refclock support.",
+ stoa(&peer->srcadr));
+ set_peerdstadr(peer, NULL);
+ free_peer(peer, 0);
+ return NULL;
+#endif /* REFCLOCK */
}
-#endif
/*
* Put the new peer in the hash tables.
*/
- i = NTP_HASH_ADDR(&peer->srcadr);
- peer->next = peer_hash[i];
- peer_hash[i] = peer;
- peer_hash_count[i]++;
- i = peer->associd & NTP_HASH_MASK;
- peer->ass_next = assoc_hash[i];
- assoc_hash[i] = peer;
- assoc_hash_count[i]++;
-
-#ifdef OPENSSL
- if (peer->flags & FLAG_SKEY) {
- sprintf(statstr, "newpeer %d", peer->associd);
- record_crypto_stats(&peer->srcadr, statstr);
- DPRINTF(1, ("peer: %s\n", statstr));
- }
-#endif /* OPENSSL */
-
- DPRINTF(1, ("newpeer: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x\n",
- peer->dstadr == NULL ? "<null>" : stoa(&peer->dstadr->sin),
- stoa(&peer->srcadr),
- peer->hmode, peer->version, peer->minpoll,
- peer->maxpoll, peer->flags, peer->cast_flags,
- peer->ttl, peer->keyid));
-
- return (peer);
+ hash = NTP_HASH_ADDR(&peer->srcadr);
+ LINK_SLIST(peer_hash[hash], peer, adr_link);
+ peer_hash_count[hash]++;
+ hash = peer->associd & NTP_HASH_MASK;
+ LINK_SLIST(assoc_hash[hash], peer, aid_link);
+ assoc_hash_count[hash]++;
+ LINK_SLIST(peer_list, peer, p_link);
+
+ restrict_source(&peer->srcadr, 0, 0);
+ mprintf_event(PEVNT_MOBIL, peer, "assoc %d", peer->associd);
+ DPRINTF(1, ("newpeer: %s->%s mode %u vers %u poll %u %u flags 0x%x 0x%x ttl %u key %08x\n",
+ latoa(peer->dstadr), stoa(&peer->srcadr), peer->hmode,
+ peer->version, peer->minpoll, peer->maxpoll, peer->flags,
+ peer->cast_flags, peer->ttl, peer->keyid));
+ return peer;
}
/*
- * peer_unconfig - remove the configuration bit from a peer
- */
-int
-peer_unconfig(
- struct sockaddr_storage *srcadr,
- struct interface *dstadr,
- int mode
- )
-{
- register struct peer *peer;
- int num_found;
-
- num_found = 0;
- peer = findexistingpeer(srcadr, (struct peer *)0, mode);
- while (peer != 0) {
- if (peer->flags & FLAG_CONFIG
- && (dstadr == 0 || peer->dstadr == dstadr)) {
- num_found++;
-
- /*
- * Tricky stuff here. If the peer is polling us
- * in active mode, turn off the configuration
- * bit and make the mode passive. This allows us
- * to avoid dumping a lot of history for peers
- * we might choose to keep track of in passive
- * mode. The protocol will eventually terminate
- * undesirables on its own.
- */
- if (peer->hmode == MODE_ACTIVE
- && peer->pmode == MODE_ACTIVE) {
- peer->hmode = MODE_PASSIVE;
- peer->flags &= ~FLAG_CONFIG;
- } else {
- unpeer(peer);
- peer = 0;
- }
- }
- peer = findexistingpeer(srcadr, peer, mode);
- }
- return (num_found);
-}
-
-/*
- * peer_clr_stats - clear peer module stat counters
+ * peer_clr_stats - clear peer module statistics counters
*/
void
peer_clr_stats(void)
@@ -935,16 +968,19 @@ peer_clr_stats(void)
peer_timereset = current_time;
}
+
/*
- * peer_reset - reset stat counters in a peer structure
+ * peer_reset - reset statistics counters
*/
void
peer_reset(
struct peer *peer
)
{
- if (peer == 0)
- return;
+ if (peer == NULL)
+ return;
+
+ peer->timereset = current_time;
peer->sent = 0;
peer->received = 0;
peer->processed = 0;
@@ -952,100 +988,71 @@ peer_reset(
peer->bogusorg = 0;
peer->oldpkt = 0;
peer->seldisptoolarge = 0;
- peer->timereset = current_time;
+ peer->selbroken = 0;
}
/*
- * peer_all_reset - reset all peer stat counters
+ * peer_all_reset - reset all peer statistics counters
*/
void
peer_all_reset(void)
{
struct peer *peer;
- int hash;
- for (hash = 0; hash < NTP_HASH_SIZE; hash++)
- for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
+ for (peer = peer_list; peer != NULL; peer = peer->p_link)
peer_reset(peer);
}
-#ifdef OPENSSL
/*
- * expire_all - flush all crypto data and update timestamps.
- */
-void
-expire_all(void)
-{
- struct peer *peer, *next_peer;
- int n;
-
- /*
- * This routine is called about once per day from the timer
- * routine and when the client is first synchronized. Search the
- * peer list for all associations and flush only the key list
- * and cookie. If a manycast client association, flush
- * everything. Then, recompute and sign the agreement public
- * value, if present.
- */
- if (!crypto_flags)
- return;
-
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- if (!(peer->flags & FLAG_SKEY)) {
- continue;
-
- } else if (peer->hmode == MODE_ACTIVE ||
- peer->hmode == MODE_PASSIVE) {
- key_expire(peer);
- peer->crypto &= ~(CRYPTO_FLAG_AUTO |
- CRYPTO_FLAG_AGREE);
- }
-
- }
- }
- RAND_bytes((u_char *)&sys_private, 4);
- crypto_update();
-}
-#endif /* OPENSSL */
-
-
-/*
- * findmanycastpeer - find and return a manycast peer
+ * findmanycastpeer - find and return a manycastclient or pool
+ * association matching a received response.
*/
struct peer *
findmanycastpeer(
- struct recvbuf *rbufp
+ struct recvbuf *rbufp /* receive buffer pointer */
)
{
- register struct peer *peer;
+ struct peer *peer;
struct pkt *pkt;
l_fp p_org;
- int i;
/*
- * This routine is called upon arrival of a server-mode message
- * from a manycast client. Search the peer list for a manycast
- * client association where the last transmit timestamp matches
- * the originate timestamp. This assumes the transmit timestamps
- * for possibly more than one manycast association are unique.
+ * This routine is called upon arrival of a server-mode response
+ * to a manycastclient multicast solicitation, or to a pool
+ * server unicast solicitation. Search the peer list for a
+ * manycastclient association where the last transmit timestamp
+ * matches the response packet's originate timestamp. There can
+ * be multiple manycastclient associations, or multiple pool
+ * solicitation assocations, so this assumes the transmit
+ * timestamps are unique for such.
*/
pkt = &rbufp->recv_pkt;
- for (i = 0; i < NTP_HASH_SIZE; i++) {
- if (peer_hash_count[i] == 0)
- continue;
-
- for (peer = peer_hash[i]; peer != 0; peer =
- peer->next) {
- if (peer->cast_flags & MDF_ACAST) {
- NTOHL_FP(&pkt->org, &p_org);
- if (L_ISEQU(&peer->xmt, &p_org))
- return (peer);
- }
+ for (peer = peer_list; peer != NULL; peer = peer->p_link)
+ if (MDF_SOLICIT_MASK & peer->cast_flags) {
+ NTOHL_FP(&pkt->org, &p_org);
+ if (L_ISEQU(&p_org, &peer->aorg))
+ break;
}
- }
- return (NULL);
+
+ return peer;
+}
+
+/* peer_cleanup - clean peer list prior to shutdown */
+void peer_cleanup(void)
+{
+ struct peer *peer;
+ associd_t assoc;
+
+ for (assoc = initial_association_ID; assoc != current_association_ID; assoc++) {
+ if (assoc != 0U) {
+ peer = findpeerbyassoc(assoc);
+ if (peer != NULL)
+ unpeer(peer);
+ }
+ }
+ peer = findpeerbyassoc(current_association_ID);
+ if (peer != NULL)
+ unpeer(peer);
}
diff --git a/contrib/ntp/ntpd/ntp_prio_q.c b/contrib/ntp/ntpd/ntp_prio_q.c
new file mode 100644
index 0000000..703673b
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_prio_q.c
@@ -0,0 +1,238 @@
+/* ntp_prio_q.c
+ *
+ * This file contains the priority queue implementation used by the
+ * discrete event simulator.
+ *
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
+ * Copyright (c) 2006
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ntp_stdlib.h>
+#include <ntp_prio_q.h>
+
+/* Priority Queue
+ * --------------
+ * Define a priority queue in which the relative priority of the elements
+ * is determined by a function 'get_order' which is supplied to the
+ * priority_queue
+ */
+queue *debug_create_priority_queue(
+ q_order_func get_order
+#ifdef _CRTDBG_MAP_ALLOC
+ , const char * sourcefile
+ , int line_num
+#endif
+ )
+{
+ queue *my_queue;
+
+#ifndef _CRTDBG_MAP_ALLOC
+ my_queue = emalloc(sizeof(queue));
+#else
+ /* preserve original callsite __FILE__ and __LINE__ for leak report */
+ my_queue = debug_erealloc(NULL, sizeof(queue), sourcefile, line_num);
+#endif
+ my_queue->get_order = get_order;
+ my_queue->front = NULL;
+ my_queue->no_of_elements = 0;
+
+ return my_queue;
+}
+
+
+/* Define a function to "destroy" a priority queue, freeing-up
+ * all the allocated resources in the process
+ */
+
+void destroy_queue(
+ queue *my_queue
+ )
+{
+ node *temp = NULL;
+
+ /* Empty out the queue elements if they are not already empty */
+ while (my_queue->front != NULL) {
+ temp = my_queue->front;
+ my_queue->front = my_queue->front->node_next;
+ free(temp);
+ }
+
+ /* Now free the queue */
+ free(my_queue);
+}
+
+
+/* Define a function to allocate memory for one element
+ * of the queue. The allocated memory consists of size
+ * bytes plus the number of bytes needed for bookkeeping
+ */
+
+void *debug_get_node(
+ size_t size
+#ifdef _CRTDBG_MAP_ALLOC
+ , const char * sourcefile
+ , int line_num
+#endif
+ )
+{
+ node *new_node;
+
+#ifndef _CRTDBG_MAP_ALLOC
+ new_node = emalloc(sizeof(*new_node) + size);
+#else
+ new_node = debug_erealloc(NULL, sizeof(*new_node) + size,
+ sourcefile, line_num);
+#endif
+ new_node->node_next = NULL;
+
+ return new_node + 1;
+}
+
+/* Define a function to free the allocated memory for a queue node */
+void free_node(
+ void *my_node
+ )
+{
+ node *old_node = my_node;
+
+ free(old_node - 1);
+}
+
+
+void *
+next_node(
+ void *pv
+ )
+{
+ node *pn;
+
+ pn = pv;
+ pn--;
+
+ if (pn->node_next == NULL)
+ return NULL;
+
+ return pn->node_next + 1;
+}
+
+
+/* Define a function to check if the queue is empty. */
+int empty(
+ queue *my_queue
+ )
+{
+ return (!my_queue || !my_queue->front);
+}
+
+
+void *
+queue_head(
+ queue *q
+ )
+{
+ if (NULL == q || NULL == q->front)
+ return NULL;
+
+ return q->front + 1;
+}
+
+
+/* Define a function to add an element to the priority queue.
+ * The element is added according to its priority -
+ * relative priority is given by the get_order function
+ */
+queue *enqueue(
+ queue * my_queue,
+ void * my_node
+ )
+{
+ node *new_node = (node *)my_node - 1;
+ node *i = NULL;
+ node *j = my_queue->front;
+
+ while (j != NULL &&
+ (*my_queue->get_order)(new_node + 1, j + 1) > 0) {
+ i = j;
+ j = j->node_next;
+ }
+
+ if (i == NULL) { /* Insert at beginning of the queue */
+ new_node->node_next = my_queue->front;
+ my_queue->front = new_node;
+ } else { /* Insert Elsewhere, including the end */
+ new_node->node_next = i->node_next;
+ i->node_next = new_node;
+ }
+
+ ++my_queue->no_of_elements;
+ return my_queue;
+}
+
+
+/* Define a function to dequeue the first element from the priority
+ * queue and return it
+ */
+void *dequeue(
+ queue *my_queue
+ )
+{
+ node *my_node = my_queue->front;
+
+ if (my_node != NULL) {
+ my_queue->front = my_node->node_next;
+ --my_queue->no_of_elements;
+ return my_node + 1;
+ } else
+ return NULL;
+}
+
+
+/* Define a function that returns the number of elements in the
+ * priority queue
+ */
+int get_no_of_elements(
+ queue *my_queue
+ )
+{
+ return my_queue->no_of_elements;
+}
+
+
+/* Define a function to append a queue onto another.
+ * Note: there is a faster way (O(1) as opposed to O(n))
+ * to do this for simple (FIFO) queues, but we can't rely on
+ * that for priority queues. (Given the current representation)
+ *
+ * I don't anticipate this to be a problem. If it does turn
+ * out to be a bottleneck, I will consider replacing the
+ * current implementation with a binomial or fibonacci heap.
+ */
+void append_queue(
+ queue *q1,
+ queue *q2
+ )
+{
+ while (!empty(q2))
+ enqueue(q1, dequeue(q2));
+ destroy_queue(q2);
+}
+
+
+/* FIFO Queue
+ * ----------
+ * Use the priority queue to create a traditional FIFO queue.
+ * The only extra function needed is the create_queue
+ */
+
+/* C is not Lisp and does not allow anonymous lambda functions :-(.
+ * So define a get_fifo_order function here
+ */
+int get_fifo_order(const void *el1, const void *el2)
+{
+ return 1;
+}
diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c
index 12619b0..4062406 100644
--- a/contrib/ntp/ntpd/ntp_proto.c
+++ b/contrib/ntp/ntpd/ntp_proto.c
@@ -13,15 +13,15 @@
#include "ntp_unixtime.h"
#include "ntp_control.h"
#include "ntp_string.h"
+#include "ntp_leapsec.h"
+#include "refidsmear.h"
#include <stdio.h>
-
-#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/
-#include "ntp_refclock.h"
+#ifdef HAVE_LIBSCF_H
+#include <libscf.h>
#endif
-
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-#include <sys/sysctl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
/*
@@ -31,99 +31,170 @@
#define AUTH(x, y) ((x) ? (y) == AUTH_OK : (y) == AUTH_OK || \
(y) == AUTH_NONE)
+#define AUTH_NONE 0 /* authentication not required */
+#define AUTH_OK 1 /* authentication OK */
+#define AUTH_ERROR 2 /* authentication error */
+#define AUTH_CRYPTO 3 /* crypto_NAK */
+
+/*
+ * traffic shaping parameters
+ */
+#define NTP_IBURST 6 /* packets in iburst */
+#define RESP_DELAY 1 /* refclock burst delay (s) */
+
+/*
+ * pool soliciting restriction duration (s)
+ */
+#define POOL_SOLICIT_WINDOW 8
+
+/*
+ * peer_select groups statistics for a peer used by clock_select() and
+ * clock_cluster().
+ */
+typedef struct peer_select_tag {
+ struct peer * peer;
+ double synch; /* sync distance */
+ double error; /* jitter */
+ double seljit; /* selection jitter */
+} peer_select;
+
/*
- * System variables are declared here. See Section 3.2 of the
- * specification.
+ * System variables are declared here. Unless specified otherwise, all
+ * times are in seconds.
*/
-u_char sys_leap; /* system leap indicator */
-u_char sys_stratum; /* stratum of system */
+u_char sys_leap; /* system leap indicator, use set_sys_leap() to change this */
+u_char xmt_leap; /* leap indicator sent in client requests, set up by set_sys_leap() */
+u_char sys_stratum; /* system stratum */
s_char sys_precision; /* local clock precision (log2 s) */
double sys_rootdelay; /* roundtrip delay to primary source */
-double sys_rootdispersion; /* dispersion to primary source */
-u_int32 sys_refid; /* source/loop in network byte order */
-static double sys_offset; /* current local clock offset */
-l_fp sys_reftime; /* time we were last updated */
-struct peer *sys_peer; /* our current peer */
-struct peer *sys_pps; /* our PPS peer */
-struct peer *sys_prefer; /* our cherished peer */
-int sys_kod; /* kod credit */
-int sys_kod_rate = 2; /* max kod packets per second */
-#ifdef OPENSSL
-u_long sys_automax; /* maximum session key lifetime */
-#endif /* OPENSSL */
+double sys_rootdisp; /* dispersion to primary source */
+u_int32 sys_refid; /* reference id (network byte order) */
+l_fp sys_reftime; /* last update time */
+struct peer *sys_peer; /* current peer */
+#ifdef LEAP_SMEAR
+struct leap_smear_info leap_smear;
+#endif
+int leap_sec_in_progress;
+
+/*
+ * Rate controls. Leaky buckets are used to throttle the packet
+ * transmission rates in order to protect busy servers such as at NIST
+ * and USNO. There is a counter for each association and another for KoD
+ * packets. The association counter decrements each second, but not
+ * below zero. Each time a packet is sent the counter is incremented by
+ * a configurable value representing the average interval between
+ * packets. A packet is delayed as long as the counter is greater than
+ * zero. Note this does not affect the time value computations.
+ */
/*
- * Nonspecified system state variables.
+ * Nonspecified system state variables
*/
int sys_bclient; /* broadcast client enable */
double sys_bdelay; /* broadcast client default delay */
-int sys_calldelay; /* modem callup delay (s) */
int sys_authenticate; /* requre authentication for config */
l_fp sys_authdelay; /* authentication delay */
-static u_long sys_authdly[2]; /* authentication delay shift reg */
-static double sys_mindisp = MINDISPERSE; /* min disp increment (s) */
-static double sys_maxdist = MAXDISTANCE; /* selection threshold (s) */
-double sys_jitter; /* system jitter (s) */
-static int sys_hopper; /* anticlockhop counter */
-static int sys_maxhop = MAXHOP; /* anticlockhop counter threshold */
-int leap_next; /* leap consensus */
+double sys_offset; /* current local clock offset */
+double sys_mindisp = MINDISPERSE; /* minimum distance (s) */
+double sys_maxdist = MAXDISTANCE; /* selection threshold */
+double sys_jitter; /* system jitter */
+u_long sys_epoch; /* last clock update time */
+static double sys_clockhop; /* clockhop threshold */
+static int leap_vote_ins; /* leap consensus for insert */
+static int leap_vote_del; /* leap consensus for delete */
keyid_t sys_private; /* private value for session seed */
int sys_manycastserver; /* respond to manycast client pkts */
+int ntp_mode7; /* respond to ntpdc (mode7) */
int peer_ntpdate; /* active peers in ntpdate mode */
int sys_survivors; /* truest of the truechimers */
-#ifdef OPENSSL
-char *sys_hostname; /* gethostname() name */
-#endif /* OPENSSL */
+char *sys_ident = NULL; /* identity scheme */
/*
* TOS and multicast mapping stuff
*/
int sys_floor = 0; /* cluster stratum floor */
-int sys_ceiling = STRATUM_UNSPEC; /* cluster stratum ceiling */
+int sys_ceiling = STRATUM_UNSPEC - 1; /* cluster stratum ceiling */
int sys_minsane = 1; /* minimum candidates */
-int sys_minclock = NTP_MINCLOCK; /* minimum survivors */
+int sys_minclock = NTP_MINCLOCK; /* minimum candidates */
int sys_maxclock = NTP_MAXCLOCK; /* maximum candidates */
int sys_cohort = 0; /* cohort switch */
int sys_orphan = STRATUM_UNSPEC + 1; /* orphan stratum */
-double sys_orphandelay = 0; /* orphan root delay */
+int sys_orphwait = NTP_ORPHWAIT; /* orphan wait */
int sys_beacon = BEACON; /* manycast beacon interval */
int sys_ttlmax; /* max ttl mapping vector index */
u_char sys_ttl[MAX_TTL]; /* ttl mapping vector */
/*
- * Statistics counters
+ * Statistics counters - first the good, then the bad
*/
-u_long sys_stattime; /* time since reset */
+u_long sys_stattime; /* elapsed time */
u_long sys_received; /* packets received */
-u_long sys_processed; /* packets processed */
-u_long sys_newversionpkt; /* current version */
-u_long sys_oldversionpkt; /* recent version */
-u_long sys_unknownversion; /* invalid version */
+u_long sys_processed; /* packets for this host */
+u_long sys_newversion; /* current version */
+u_long sys_oldversion; /* old version */
u_long sys_restricted; /* access denied */
u_long sys_badlength; /* bad length or format */
u_long sys_badauth; /* bad authentication */
+u_long sys_declined; /* declined */
u_long sys_limitrejected; /* rate exceeded */
+u_long sys_kodsent; /* KoD sent */
+
+static double root_distance (struct peer *);
+static void clock_combine (peer_select *, int, int);
+static void peer_xmit (struct peer *);
+static void fast_xmit (struct recvbuf *, int, keyid_t, int);
+static void pool_xmit (struct peer *);
+static void clock_update (struct peer *);
+static void measure_precision(void);
+static double measure_tick_fuzz(void);
+static int local_refid (struct peer *);
+static int peer_unfit (struct peer *);
+#ifdef AUTOKEY
+static int group_test (char *, char *);
+#endif /* AUTOKEY */
+#ifdef WORKER
+void pool_name_resolved (int, int, void *, const char *,
+ const char *, const struct addrinfo *,
+ const struct addrinfo *);
+#endif /* WORKER */
-static double root_distance P((struct peer *));
-static void clock_combine P((struct peer **, int));
-static void peer_xmit P((struct peer *));
-static void fast_xmit P((struct recvbuf *, int, keyid_t,
- int));
-static void clock_update P((void));
-static int default_get_precision P((void));
-static int peer_unfit P((struct peer *));
+void
+set_sys_leap(u_char new_sys_leap) {
+ sys_leap = new_sys_leap;
+ xmt_leap = sys_leap;
+
+ /*
+ * Under certain conditions we send faked leap bits to clients, so
+ * eventually change xmt_leap below, but never change LEAP_NOTINSYNC.
+ */
+ if (xmt_leap != LEAP_NOTINSYNC) {
+ if (leap_sec_in_progress) {
+ /* always send "not sync" */
+ xmt_leap = LEAP_NOTINSYNC;
+ }
+#ifdef LEAP_SMEAR
+ else {
+ /*
+ * If leap smear is enabled in general we must never send a leap second warning
+ * to clients, so make sure we only send "in sync".
+ */
+ if (leap_smear.enabled)
+ xmt_leap = LEAP_NOWARNING;
+ }
+#endif /* LEAP_SMEAR */
+ }
+}
/*
- * transmit - Transmit Procedure. See Section 3.4.2 of the
- * specification.
+ * transmit - transmit procedure called by poll timeout
*/
void
transmit(
struct peer *peer /* peer structure pointer */
)
{
- int hpoll;
+ u_char hpoll;
/*
* The polling state machine. There are two kinds of machines,
@@ -131,24 +202,7 @@ transmit(
* server modes) and those that do (all other modes). The dance
* is intricate...
*/
- /*
- * Orphan mode is active when enabled and when no servers less
- * than the orphan statum are available. In this mode packets
- * are sent at the orphan stratum. An orphan with no other
- * synchronization source is an orphan parent. It assumes root
- * delay zero and reference ID the loopback address. All others
- * are orphan children with root delay randomized over a 1-s
- * range. The root delay is used by the election algorithm to
- * select the order of synchronization.
- */
hpoll = peer->hpoll;
- if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) {
- sys_leap = LEAP_NOWARNING;
- sys_stratum = sys_orphan;
- sys_refid = htonl(LOOPBACKADR);
- sys_rootdelay = 0;
- sys_rootdispersion = 0;
- }
/*
* In broadcast mode the poll interval is never changed from
@@ -156,7 +210,8 @@ transmit(
*/
if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) {
peer->outdate = current_time;
- peer_xmit(peer);
+ if (sys_leap != LEAP_NOTINSYNC)
+ peer_xmit(peer);
poll_update(peer, hpoll);
return;
}
@@ -166,9 +221,13 @@ transmit(
* increased by one for each poll until either sys_maxclock
* servers have been found or the maximum ttl is reached. When
* sys_maxclock servers are found we stop polling until one or
- * more servers have timed out or until less than minpoll
+ * more servers have timed out or until less than sys_minclock
* associations turn up. In this case additional better servers
- * are dragged in and preempt the existing ones.
+ * are dragged in and preempt the existing ones. Once every
+ * sys_beacon seconds we are to transmit unconditionally, but
+ * this code is not quite right -- peer->unreach counts polls
+ * and is being compared with sys_beacon, so the beacons happen
+ * every sys_beacon polls.
*/
if (peer->cast_flags & MDF_ACAST) {
peer->outdate = current_time;
@@ -177,8 +236,8 @@ transmit(
peer->ttl = 0;
peer_xmit(peer);
} else if (sys_survivors < sys_minclock ||
- peer_preempt < sys_maxclock) {
- if (peer->ttl < sys_ttlmax)
+ peer_associations < sys_maxclock) {
+ if (peer->ttl < (u_int32)sys_ttlmax)
peer->ttl++;
peer_xmit(peer);
}
@@ -188,8 +247,30 @@ transmit(
}
/*
+ * Pool associations transmit unicast solicitations when there
+ * are less than a hard limit of 2 * sys_maxclock associations,
+ * and either less than sys_minclock survivors or less than
+ * sys_maxclock associations. The hard limit prevents unbounded
+ * growth in associations if the system clock or network quality
+ * result in survivor count dipping below sys_minclock often.
+ * This was observed testing with pool, where sys_maxclock == 12
+ * resulted in 60 associations without the hard limit. A
+ * similar hard limit on manycastclient ephemeral associations
+ * may be appropriate.
+ */
+ if (peer->cast_flags & MDF_POOL) {
+ peer->outdate = current_time;
+ if ((peer_associations <= 2 * sys_maxclock) &&
+ (peer_associations < sys_maxclock ||
+ sys_survivors < sys_minclock))
+ pool_xmit(peer);
+ poll_update(peer, hpoll);
+ return;
+ }
+
+ /*
* In unicast modes the dance is much more intricate. It is
- * desigmed to back off whenever possible to minimize network
+ * designed to back off whenever possible to minimize network
* traffic.
*/
if (peer->burst == 0) {
@@ -198,100 +279,73 @@ transmit(
/*
* Update the reachability status. If not heard for
* three consecutive polls, stuff infinity in the clock
- * filter.
+ * filter.
*/
oreach = peer->reach;
peer->outdate = current_time;
- if (peer == sys_peer)
- sys_hopper++;
+ peer->unreach++;
peer->reach <<= 1;
- if (!(peer->reach & 0x07))
- clock_filter(peer, 0., 0., MAXDISPERSE);
if (!peer->reach) {
/*
* Here the peer is unreachable. If it was
- * previously reachable, raise a trap.
+ * previously reachable raise a trap. Send a
+ * burst if enabled.
*/
+ clock_filter(peer, 0., 0., MAXDISPERSE);
if (oreach) {
- report_event(EVNT_UNREACH, peer);
- peer->timereachable = current_time;
- }
-
- /*
- * Send a burst if enabled, but only once after
- * a peer becomes unreachable. If the prempt
- * flag is dim, bump the unreach counter by one;
- * otherwise, bump it by three.
- */
- if (peer->flags & FLAG_IBURST &&
- peer->unreach == 0) {
- peer->burst = NTP_BURST;
+ peer_unfit(peer);
+ report_event(PEVNT_UNREACH, peer, NULL);
}
- if (!(peer->flags & FLAG_PREEMPT))
- peer->unreach++;
- else
- peer->unreach += 3;
+ if ((peer->flags & FLAG_IBURST) &&
+ peer->retry == 0)
+ peer->retry = NTP_RETRY;
} else {
/*
- * Here the peer is reachable. Set the poll
- * interval to the system poll interval. Send a
- * burst only if enabled and the peer is fit.
- *
- * Respond to the peer evaluation produced by
- * the selection algorithm. If less than the
- * outlyer level, up the unreach by three. If
- * there are excess associations, up the unreach
- * by two if not a candidate and by one if so.
+ * Here the peer is reachable. Send a burst if
+ * enabled and the peer is fit. Reset unreach
+ * for persistent and ephemeral associations.
+ * Unreach is also reset for survivors in
+ * clock_select().
*/
- if (!(peer->flags & FLAG_PREEMPT)) {
- peer->unreach = 0;
- } else if (peer->status < CTL_PST_SEL_SELCAND) {
- peer->unreach += 3;
- } else if (peer_preempt > sys_maxclock) {
- if (peer->status < CTL_PST_SEL_SYNCCAND)
- peer->unreach += 2;
- else
- peer->unreach++;
- } else {
- peer->unreach = 0;
- }
hpoll = sys_poll;
- if (peer->flags & FLAG_BURST &&
- !peer_unfit(peer))
- peer->burst = NTP_BURST;
+ if (!(peer->flags & FLAG_PREEMPT))
+ peer->unreach = 0;
+ if ((peer->flags & FLAG_BURST) && peer->retry ==
+ 0 && !peer_unfit(peer))
+ peer->retry = NTP_RETRY;
}
/*
- * Watch for timeout. If ephemeral or preemptable, toss
- * the rascal; otherwise, bump the poll interval.
- */
+ * Watch for timeout. If ephemeral, toss the rascal;
+ * otherwise, bump the poll interval. Note the
+ * poll_update() routine will clamp it to maxpoll.
+ * If preemptible and we have more peers than maxclock,
+ * and this peer has the minimum score of preemptibles,
+ * demobilize.
+ */
if (peer->unreach >= NTP_UNREACH) {
- if (peer->flags & FLAG_PREEMPT ||
- !(peer->flags & FLAG_CONFIG)) {
+ hpoll++;
+ /* ephemeral: no FLAG_CONFIG nor FLAG_PREEMPT */
+ if (!(peer->flags & (FLAG_CONFIG | FLAG_PREEMPT))) {
+ report_event(PEVNT_RESTART, peer, "timeout");
+ peer_clear(peer, "TIME");
+ unpeer(peer);
+ return;
+ }
+ if ((peer->flags & FLAG_PREEMPT) &&
+ (peer_associations > sys_maxclock) &&
+ score_all(peer)) {
+ report_event(PEVNT_RESTART, peer, "timeout");
peer_clear(peer, "TIME");
unpeer(peer);
return;
- } else {
- hpoll++;
}
}
} else {
peer->burst--;
-
- /*
- * If a broadcast client at this point, the burst has
- * concluded, so we switch to client mode and purge the
- * keylist, since no further transmissions will be made.
- */
if (peer->burst == 0) {
- if (peer->cast_flags & MDF_BCLNT) {
- peer->hmode = MODE_BCLIENT;
-#ifdef OPENSSL
- key_expire(peer);
-#endif /* OPENSSL */
- }
/*
* If ntpdate mode and the clock has not been
@@ -302,15 +356,20 @@ transmit(
peer_ntpdate--;
if (peer_ntpdate == 0) {
msyslog(LOG_NOTICE,
- "no reply; clock not set");
+ "ntpd: no servers found");
+ if (!msyslog_term)
+ printf(
+ "ntpd: no servers found\n");
exit (0);
}
}
}
}
+ if (peer->retry > 0)
+ peer->retry--;
/*
- * Do not transmit if in broadcast client mode.
+ * Do not transmit if in broadcast client mode.
*/
if (peer->hmode != MODE_BCLIENT)
peer_xmit(peer);
@@ -319,7 +378,7 @@ transmit(
/*
- * receive - Receive Procedure. See section 3.4.3 in the specification.
+ * receive - receive procedure called for each packet received
*/
void
receive(
@@ -328,68 +387,65 @@ receive(
{
register struct peer *peer; /* peer structure pointer */
register struct pkt *pkt; /* receive packet pointer */
- int hisversion; /* packet version */
- int hisleap; /* packet leap indicator */
- int hismode; /* packet mode */
- int hisstratum; /* packet stratum */
- int restrict_mask; /* restrict bits */
+ u_char hisversion; /* packet version */
+ u_char hisleap; /* packet leap indicator */
+ u_char hismode; /* packet mode */
+ u_char hisstratum; /* packet stratum */
+ u_short restrict_mask; /* restrict bits */
int has_mac; /* length of MAC field */
int authlen; /* offset of MAC field */
int is_authentic = 0; /* cryptosum ok */
- keyid_t skeyid = 0; /* key ID */
- struct sockaddr_storage *dstadr_sin; /* active runway */
+ int retcode = AM_NOMATCH; /* match code */
+ keyid_t skeyid = 0; /* key IDs */
+ u_int32 opcode = 0; /* extension field opcode */
+ sockaddr_u *dstadr_sin; /* active runway */
struct peer *peer2; /* aux peer structure pointer */
+ endpt * match_ep; /* newpeer() local address */
l_fp p_org; /* origin timestamp */
l_fp p_rec; /* receive timestamp */
l_fp p_xmt; /* transmit timestamp */
-#ifdef OPENSSL
- keyid_t tkeyid = 0; /* temporary key ID */
- keyid_t pkeyid = 0; /* previous key ID */
+#ifdef AUTOKEY
+ char hostname[NTP_MAXSTRLEN + 1];
+ char *groupname = NULL;
struct autokey *ap; /* autokey structure pointer */
int rval; /* cookie snatcher */
-#endif /* OPENSSL */
- int retcode = AM_NOMATCH;
- int at_listhead;
+ keyid_t pkeyid = 0, tkeyid = 0; /* key IDs */
+#endif /* AUTOKEY */
+#ifdef HAVE_NTP_SIGND
+ static unsigned char zero_key[16];
+#endif /* HAVE_NTP_SIGND */
/*
* Monitor the packet and get restrictions. Note that the packet
* length for control and private mode packets must be checked
- * by the service routines. Note that no statistics counters are
- * recorded for restrict violations, since these counters are in
- * the restriction routine. Note the careful distinctions here
- * between a packet with a format error and a packet that is
- * simply discarded without prejudice. Some restrictions have to
- * be handled later in order to generate a kiss-of-death packet.
+ * by the service routines. Some restrictions have to be handled
+ * later in order to generate a kiss-o'-death packet.
*/
/*
* Bogus port check is before anything, since it probably
* reveals a clogging attack.
*/
sys_received++;
- if (SRCPORT(&rbufp->recv_srcadr) == 0) {
+ if (0 == SRCPORT(&rbufp->recv_srcadr)) {
sys_badlength++;
return; /* bogus port */
}
- at_listhead = ntp_monitor(rbufp);
- restrict_mask = restrictions(&rbufp->recv_srcadr, at_listhead);
-#ifdef DEBUG
- if (debug > 1)
- printf("receive: at %ld %s<-%s flags %x restrict %03x\n",
+ restrict_mask = restrictions(&rbufp->recv_srcadr);
+ DPRINTF(2, ("receive: at %ld %s<-%s flags %x restrict %03x\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr),
- rbufp->dstadr->flags, restrict_mask);
-#endif
- if (restrict_mask & RES_IGNORE) {
- sys_restricted++;
- return; /* ignore everything */
- }
+ rbufp->dstadr->flags, restrict_mask));
pkt = &rbufp->recv_pkt;
hisversion = PKT_VERSION(pkt->li_vn_mode);
hisleap = PKT_LEAP(pkt->li_vn_mode);
hismode = (int)PKT_MODE(pkt->li_vn_mode);
hisstratum = PKT_TO_STRATUM(pkt->stratum);
+ if (restrict_mask & RES_IGNORE) {
+ sys_restricted++;
+ return; /* ignore everything */
+ }
if (hismode == MODE_PRIVATE) {
- if (restrict_mask & RES_NOQUERY) {
+ if (!ntp_mode7 || (restrict_mask & RES_NOQUERY)) {
sys_restricted++;
return; /* no query private */
}
@@ -407,24 +463,31 @@ receive(
}
if (restrict_mask & RES_DONTSERVE) {
sys_restricted++;
- return; /* no time */
+ return; /* no time serve */
}
- if (rbufp->recv_length < LEN_PKT_NOMAC) {
- sys_badlength++;
- return; /* runt packet */
+
+ /*
+ * This is for testing. If restricted drop ten percent of
+ * surviving packets.
+ */
+ if (restrict_mask & RES_FLAKE) {
+ if ((double)ntp_random() / 0x7fffffff < .1) {
+ sys_restricted++;
+ return; /* no flakeway */
+ }
}
-
+
/*
* Version check must be after the query packets, since they
- * intentionally use early version.
+ * intentionally use an early version.
*/
if (hisversion == NTP_VERSION) {
- sys_newversionpkt++; /* new version */
+ sys_newversion++; /* new version */
} else if (!(restrict_mask & RES_VERSION) && hisversion >=
NTP_OLDVERSION) {
- sys_oldversionpkt++; /* previous version */
+ sys_oldversion++; /* previous version */
} else {
- sys_unknownversion++;
+ sys_badlength++;
return; /* old version */
}
@@ -449,40 +512,68 @@ receive(
* the number of words following the packet header is 0, no MAC
* is present and the packet is not authenticated. If 1, the
* packet is a crypto-NAK; if 3, the packet is authenticated
- * with DES; if 5, the packet is authenticated with MD5. If 2 or
- * 4, the packet is a runt and discarded forthwith. If greater
- * than 5, an extension field is present, so we subtract the
- * length of the field and go around again.
+ * with DES; if 5, the packet is authenticated with MD5; if 6,
+ * the packet is authenticated with SHA. If 2 or * 4, the packet
+ * is a runt and discarded forthwith. If greater than 6, an
+ * extension field is present, so we subtract the length of the
+ * field and go around again.
*/
authlen = LEN_PKT_NOMAC;
has_mac = rbufp->recv_length - authlen;
while (has_mac > 0) {
- int temp;
+ u_int32 len;
+#ifdef AUTOKEY
+ u_int32 hostlen;
+ struct exten *ep;
+#endif /*AUTOKEY */
- if (has_mac % 4 != 0 || has_mac < MIN_MAC_LEN) {
+ if (has_mac % 4 != 0 || has_mac < (int)MIN_MAC_LEN) {
sys_badlength++;
- return; /* bad MAC length */
+ return; /* bad length */
}
- if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac ==
- MAX_MAC_LEN) {
+ if (has_mac <= (int)MAX_MAC_LEN) {
skeyid = ntohl(((u_int32 *)pkt)[authlen / 4]);
break;
- } else if (has_mac > MAX_MAC_LEN) {
- temp = ntohl(((u_int32 *)pkt)[authlen / 4]) &
- 0xffff;
- if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4
- != 0) {
+ } else {
+ opcode = ntohl(((u_int32 *)pkt)[authlen / 4]);
+ len = opcode & 0xffff;
+ if (len % 4 != 0 || len < 4 || (int)len +
+ authlen > rbufp->recv_length) {
sys_badlength++;
- return; /* bad MAC length */
+ return; /* bad length */
}
- authlen += temp;
- has_mac -= temp;
- } else {
- sys_badlength++;
- return; /* bad MAC length */
+#ifdef AUTOKEY
+ /*
+ * Extract calling group name for later. If
+ * sys_groupname is non-NULL, there must be
+ * a group name provided to elicit a response.
+ */
+ if ((opcode & 0x3fff0000) == CRYPTO_ASSOC &&
+ sys_groupname != NULL) {
+ ep = (struct exten *)&((u_int32 *)pkt)[authlen / 4];
+ hostlen = ntohl(ep->vallen);
+ if (hostlen >= sizeof(hostname) ||
+ hostlen > len -
+ offsetof(struct exten, pkt)) {
+ sys_badlength++;
+ return; /* bad length */
+ }
+ memcpy(hostname, &ep->pkt, hostlen);
+ hostname[hostlen] = '\0';
+ groupname = strchr(hostname, '@');
+ if (groupname == NULL) {
+ sys_declined++;
+ return;
+ }
+ groupname++;
+ }
+#endif /* AUTOKEY */
+ authlen += len;
+ has_mac -= len;
}
}
+
/*
* If has_mac is < 0 we had a malformed packet.
*/
@@ -490,16 +581,47 @@ receive(
sys_badlength++;
return; /* bad length */
}
-#ifdef OPENSSL
- pkeyid = tkeyid = 0;
-#endif /* OPENSSL */
+
+ /*
+ * If authentication required, a MAC must be present.
+ */
+ if (restrict_mask & RES_DONTTRUST && has_mac == 0) {
+ sys_restricted++;
+ return; /* access denied */
+ }
+
+ /*
+ * Update the MRU list and finger the cloggers. It can be a
+ * little expensive, so turn it off for production use.
+ * RES_LIMITED and RES_KOD will be cleared in the returned
+ * restrict_mask unless one or both actions are warranted.
+ */
+ restrict_mask = ntp_monitor(rbufp, restrict_mask);
+ if (restrict_mask & RES_LIMITED) {
+ sys_limitrejected++;
+ if (!(restrict_mask & RES_KOD) || MODE_BROADCAST ==
+ hismode || MODE_SERVER == hismode) {
+ if (MODE_SERVER == hismode)
+ DPRINTF(1, ("Possibly self-induced rate limiting of MODE_SERVER from %s\n",
+ stoa(&rbufp->recv_srcadr)));
+ return; /* rate exceeded */
+ }
+ if (hismode == MODE_CLIENT)
+ fast_xmit(rbufp, MODE_SERVER, skeyid,
+ restrict_mask);
+ else
+ fast_xmit(rbufp, MODE_ACTIVE, skeyid,
+ restrict_mask);
+ return; /* rate exceeded */
+ }
+ restrict_mask &= ~RES_KOD;
/*
* We have tossed out as many buggy packets as possible early in
* the game to reduce the exposure to a clogging attack. Now we
* have to burn some cycles to find the association and
* authenticate the packet if required. Note that we burn only
- * MD5 cycles, again to reduce exposure. There may be no
+ * digest cycles, again to reduce exposure. There may be no
* matching association and that's okay.
*
* More on the autokey mambo. Normally the local interface is
@@ -509,12 +631,11 @@ receive(
* address used to construct the autokey is the unicast address
* of the interface. However, if the sender is a broadcaster,
* the interface broadcast address is used instead.
- & Notwithstanding this technobabble, if the sender is a
+ * Notwithstanding this technobabble, if the sender is a
* multicaster, the broadcast address is null, so we use the
* unicast address anyway. Don't ask.
*/
- peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, hismode,
- &retcode);
+ peer = findpeer(rbufp, hismode, &retcode);
dstadr_sin = &rbufp->dstadr->sin;
NTOHL_FP(&pkt->org, &p_org);
NTOHL_FP(&pkt->rec, &p_rec);
@@ -543,34 +664,57 @@ receive(
* is zero, acceptable outcomes of y are NONE and OK. If x is
* one, the only acceptable outcome of y is OK.
*/
+
if (has_mac == 0) {
+ restrict_mask &= ~RES_MSSNTP;
is_authentic = AUTH_NONE; /* not required */
#ifdef DEBUG
if (debug)
- printf("receive: at %ld %s<-%s mode %d code %d auth %d\n",
+ printf(
+ "receive: at %ld %s<-%s mode %d len %d\n",
current_time, stoa(dstadr_sin),
- stoa(&rbufp->recv_srcadr), hismode, retcode,
- is_authentic);
+ stoa(&rbufp->recv_srcadr), hismode,
+ authlen);
#endif
} else if (has_mac == 4) {
- is_authentic = AUTH_CRYPTO; /* crypto-NAK */
+ restrict_mask &= ~RES_MSSNTP;
+ is_authentic = AUTH_CRYPTO; /* crypto-NAK */
#ifdef DEBUG
if (debug)
printf(
- "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n",
+ "receive: at %ld %s<-%s mode %d keyid %08x len %d auth %d\n",
current_time, stoa(dstadr_sin),
- stoa(&rbufp->recv_srcadr), hismode, retcode,
- skeyid, authlen, has_mac, is_authentic);
+ stoa(&rbufp->recv_srcadr), hismode, skeyid,
+ authlen + has_mac, is_authentic);
#endif
+
+#ifdef HAVE_NTP_SIGND
+ /*
+ * If the signature is 20 bytes long, the last 16 of
+ * which are zero, then this is a Microsoft client
+ * wanting AD-style authentication of the server's
+ * reply.
+ *
+ * This is described in Microsoft's WSPP docs, in MS-SNTP:
+ * http://msdn.microsoft.com/en-us/library/cc212930.aspx
+ */
+ } else if (has_mac == MAX_MD5_LEN && (restrict_mask & RES_MSSNTP) &&
+ (retcode == AM_FXMIT || retcode == AM_NEWPASS) &&
+ (memcmp(zero_key, (char *)pkt + authlen + 4, MAX_MD5_LEN - 4) ==
+ 0)) {
+ is_authentic = AUTH_NONE;
+#endif /* HAVE_NTP_SIGND */
+
} else {
-#ifdef OPENSSL
+ restrict_mask &= ~RES_MSSNTP;
+#ifdef AUTOKEY
/*
* For autokey modes, generate the session key
* and install in the key cache. Use the socket
* broadcast or unicast address as appropriate.
*/
- if (skeyid > NTP_MAXKEY) {
-
+ if (crypto_flags && skeyid > NTP_MAXKEY) {
+
/*
* More on the autokey dance (AKD). A cookie is
* constructed from public and private values.
@@ -596,6 +740,10 @@ receive(
* # if unsync, 0
* % can't happen
*/
+ if (has_mac < (int)MAX_MD5_LEN) {
+ sys_badauth++;
+ return;
+ }
if (hismode == MODE_BROADCAST) {
/*
@@ -607,12 +755,12 @@ receive(
* the wildcard interface, game over.
*/
if (crypto_flags && rbufp->dstadr ==
- any_interface) {
+ ANY_INTERFACE_CHOOSE(&rbufp->recv_srcadr)) {
sys_restricted++;
return; /* no wildcard */
}
pkeyid = 0;
- if (!SOCKNUL(&rbufp->dstadr->bcast))
+ if (!SOCK_UNSPEC(&rbufp->dstadr->bcast))
dstadr_sin =
&rbufp->dstadr->bcast;
} else if (peer == NULL) {
@@ -630,7 +778,7 @@ receive(
* purposes is zero. Note the hash is saved for
* use later in the autokey mambo.
*/
- if (authlen > LEN_PKT_NOMAC && pkeyid != 0) {
+ if (authlen > (int)LEN_PKT_NOMAC && pkeyid != 0) {
session_key(&rbufp->recv_srcadr,
dstadr_sin, skeyid, 0, 2);
tkeyid = session_key(
@@ -643,7 +791,7 @@ receive(
}
}
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
/*
* Compute the cryptosum. Note a clogging attack may
@@ -653,24 +801,21 @@ receive(
* association. Note that there is no key zero.
*/
if (!authdecrypt(skeyid, (u_int32 *)pkt, authlen,
- has_mac)) {
+ has_mac))
is_authentic = AUTH_ERROR;
- sys_badauth++;
- return;
- } else {
+ else
is_authentic = AUTH_OK;
- }
-#ifdef OPENSSL
- if (skeyid > NTP_MAXKEY)
+#ifdef AUTOKEY
+ if (crypto_flags && skeyid > NTP_MAXKEY)
authtrust(skeyid, 0);
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
#ifdef DEBUG
if (debug)
printf(
- "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n",
+ "receive: at %ld %s<-%s mode %d keyid %08x len %d auth %d\n",
current_time, stoa(dstadr_sin),
- stoa(&rbufp->recv_srcadr), hismode, retcode,
- skeyid, authlen, has_mac, is_authentic);
+ stoa(&rbufp->recv_srcadr), hismode, skeyid,
+ authlen + has_mac, is_authentic);
#endif
}
@@ -695,19 +840,21 @@ receive(
case AM_FXMIT:
/*
- * The vanilla case is when this is not a multicast
- * interface. If authentication succeeds, return a
- * server mode packet; if not and the key ID is nonzero,
- * return a crypto-NAK.
+ * If authentication OK, send a server reply; otherwise,
+ * send a crypto-NAK.
*/
if (!(rbufp->dstadr->flags & INT_MCASTOPEN)) {
if (AUTH(restrict_mask & RES_DONTTRUST,
- is_authentic))
+ is_authentic)) {
fast_xmit(rbufp, MODE_SERVER, skeyid,
restrict_mask);
- else if (is_authentic == AUTH_ERROR)
+ } else if (is_authentic == AUTH_ERROR) {
fast_xmit(rbufp, MODE_SERVER, 0,
restrict_mask);
+ sys_badauth++;
+ } else {
+ sys_restricted++;
+ }
return; /* hooray */
}
@@ -720,22 +867,28 @@ receive(
return; /* not enabled */
}
+#ifdef AUTOKEY
/*
- * Do not respond if unsynchronized or stratum is below
- * the floor or at or above the ceiling.
+ * Do not respond if not the same group.
*/
- if (sys_leap == LEAP_NOTINSYNC || sys_stratum <
- sys_floor || sys_stratum >= sys_ceiling)
- return; /* bad stratum */
+ if (group_test(groupname, NULL)) {
+ sys_declined++;
+ return;
+ }
+#endif /* AUTOKEY */
/*
- * Do not respond if our stratum is greater than the
- * manycaster or it has already synchronized to us.
+ * Do not respond if we are not synchronized or our
+ * stratum is greater than the manycaster or the
+ * manycaster has already synchronized to us.
*/
- if (sys_peer == NULL || hisstratum < sys_stratum ||
- (sys_cohort && hisstratum == sys_stratum) ||
- rbufp->dstadr->addr_refid == pkt->refid)
+ if (sys_leap == LEAP_NOTINSYNC || sys_stratum >=
+ hisstratum || (!sys_cohort && sys_stratum ==
+ hisstratum + 1) || rbufp->dstadr->addr_refid ==
+ pkt->refid) {
+ sys_declined++;
return; /* no help */
+ }
/*
* Respond only if authentication succeeds. Don't do a
@@ -744,47 +897,84 @@ receive(
if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic))
fast_xmit(rbufp, MODE_SERVER, skeyid,
restrict_mask);
-
return; /* hooray */
/*
* This is a server mode packet returned in response to a client
- * mode packet sent to a multicast group address. The origin
- * timestamp is a good nonce to reliably associate the reply
- * with what was sent. If there is no match, that's curious and
- * could be an intruder attempting to clog, so we just ignore
- * it.
+ * mode packet sent to a multicast group address (for
+ * manycastclient) or to a unicast address (for pool). The
+ * origin timestamp is a good nonce to reliably associate the
+ * reply with what was sent. If there is no match, that's
+ * curious and could be an intruder attempting to clog, so we
+ * just ignore it.
*
- * If the packet is authentic and the manycast association is
- * found, we mobilize a client association and copy pertinent
- * variables from the manycast association to the new client
- * association. If not, just ignore the packet.
+ * If the packet is authentic and the manycastclient or pool
+ * association is found, we mobilize a client association and
+ * copy pertinent variables from the manycastclient or pool
+ * association to the new client association. If not, just
+ * ignore the packet.
*
* There is an implosion hazard at the manycast client, since
* the manycast servers send the server packet immediately. If
* the guy is already here, don't fire up a duplicate.
*/
case AM_MANYCAST:
- if (!AUTH(sys_authenticate | (restrict_mask &
- (RES_NOPEER | RES_DONTTRUST)), is_authentic))
- return; /* bad auth */
+#ifdef AUTOKEY
+ /*
+ * Do not respond if not the same group.
+ */
+ if (group_test(groupname, NULL)) {
+ sys_declined++;
+ return;
+ }
+#endif /* AUTOKEY */
if ((peer2 = findmanycastpeer(rbufp)) == NULL) {
sys_restricted++;
return; /* not enabled */
}
- if ((peer = newpeer(&rbufp->recv_srcadr,
- rbufp->dstadr, MODE_CLIENT,
- hisversion, NTP_MINDPOLL, NTP_MAXDPOLL,
- FLAG_IBURST | FLAG_PREEMPT, MDF_UCAST | MDF_ACLNT,
- 0, skeyid)) == NULL)
- return; /* system error */
+ if (!AUTH((!(peer2->cast_flags & MDF_POOL) &&
+ sys_authenticate) | (restrict_mask & (RES_NOPEER |
+ RES_DONTTRUST)), is_authentic)) {
+ sys_restricted++;
+ return; /* access denied */
+ }
/*
- * We don't need these, but it warms the billboards.
+ * Do not respond if unsynchronized or stratum is below
+ * the floor or at or above the ceiling.
*/
- peer->ttl = peer2->ttl;
- break;
+ if (hisleap == LEAP_NOTINSYNC || hisstratum <
+ sys_floor || hisstratum >= sys_ceiling) {
+ sys_declined++;
+ return; /* no help */
+ }
+ peer = newpeer(&rbufp->recv_srcadr, NULL, rbufp->dstadr,
+ MODE_CLIENT, hisversion, peer2->minpoll,
+ peer2->maxpoll, FLAG_PREEMPT |
+ (FLAG_IBURST & peer2->flags), MDF_UCAST |
+ MDF_UCLNT, 0, skeyid, sys_ident);
+ if (NULL == peer) {
+ sys_declined++;
+ return; /* ignore duplicate */
+ }
+
+ /*
+ * After each ephemeral pool association is spun,
+ * accelerate the next poll for the pool solicitor so
+ * the pool will fill promptly.
+ */
+ if (peer2->cast_flags & MDF_POOL)
+ peer2->nextdate = current_time + 1;
+
+ /*
+ * Further processing of the solicitation response would
+ * simply detect its origin timestamp as bogus for the
+ * brand-new association (it matches the prototype
+ * association) and tinker with peer->nextdate delaying
+ * first sync.
+ */
+ return; /* solicitation response handled */
/*
* This is the first packet received from a broadcast server. If
@@ -793,68 +983,117 @@ receive(
* kiss any frogs here.
*/
case AM_NEWBCL:
+
+#ifdef AUTOKEY
+ /*
+ * Do not respond if not the same group.
+ */
+ if (group_test(groupname, sys_ident)) {
+ sys_declined++;
+ return;
+ }
+#endif /* AUTOKEY */
+ if (sys_bclient == 0) {
+ sys_restricted++;
+ return; /* not enabled */
+ }
if (!AUTH(sys_authenticate | (restrict_mask &
- (RES_NOPEER | RES_DONTTRUST)), is_authentic))
- return; /* bad auth */
+ (RES_NOPEER | RES_DONTTRUST)), is_authentic)) {
+ sys_restricted++;
+ return; /* access denied */
+ }
/*
* Do not respond if unsynchronized or stratum is below
* the floor or at or above the ceiling.
*/
if (hisleap == LEAP_NOTINSYNC || hisstratum <
- sys_floor || hisstratum >= sys_ceiling)
- return; /* bad stratum */
-
- switch (sys_bclient) {
+ sys_floor || hisstratum >= sys_ceiling) {
+ sys_declined++;
+ return; /* no help */
+ }
+#ifdef AUTOKEY
/*
- * If not enabled, just skedaddle.
+ * Do not respond if Autokey and the opcode is not a
+ * CRYPTO_ASSOC response with association ID.
*/
- case 0:
- sys_restricted++;
- return; /* not enabled */
+ if (crypto_flags && skeyid > NTP_MAXKEY && (opcode &
+ 0xffff0000) != (CRYPTO_ASSOC | CRYPTO_RESP)) {
+ sys_declined++;
+ return; /* protocol error */
+ }
+#endif /* AUTOKEY */
/*
- * Execute the initial volley in order to calibrate the
- * propagation delay and run the Autokey protocol, if
- * enabled.
+ * Broadcasts received via a multicast address may
+ * arrive after a unicast volley has begun
+ * with the same remote address. newpeer() will not
+ * find duplicate associations on other local endpoints
+ * if a non-NULL endpoint is supplied. multicastclient
+ * ephemeral associations are unique across all local
+ * endpoints.
*/
- case 1:
- if ((peer = newpeer(&rbufp->recv_srcadr,
- rbufp->dstadr, MODE_CLIENT, hisversion,
- NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST |
- FLAG_IBURST, MDF_BCLNT, 0, skeyid)) ==
- NULL)
- return; /* system error */
-#ifdef OPENSSL
- if (skeyid > NTP_MAXKEY)
- crypto_recv(peer, rbufp);
-#endif /* OPENSSL */
- return; /* hooray */
-
+ if (!(INT_MCASTOPEN & rbufp->dstadr->flags))
+ match_ep = rbufp->dstadr;
+ else
+ match_ep = NULL;
/*
- * Do not execute the initial volley.
+ * Determine whether to execute the initial volley.
*/
- case 2:
-#ifdef OPENSSL
+ if (sys_bdelay != 0) {
+#ifdef AUTOKEY
/*
* If a two-way exchange is not possible,
* neither is Autokey.
*/
- if (skeyid > NTP_MAXKEY) {
- msyslog(LOG_INFO,
- "receive: autokey requires two-way communication");
+ if (crypto_flags && skeyid > NTP_MAXKEY) {
+ sys_restricted++;
return; /* no autokey */
}
-#endif /* OPENSSL */
- if ((peer = newpeer(&rbufp->recv_srcadr,
- rbufp->dstadr, MODE_BCLIENT, hisversion,
- NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_BCLNT, 0,
- skeyid)) == NULL)
- return; /* system error */
+#endif /* AUTOKEY */
+
+ /*
+ * Do not execute the volley. Start out in
+ * broadcast client mode.
+ */
+ peer = newpeer(&rbufp->recv_srcadr, NULL,
+ match_ep, MODE_BCLIENT, hisversion,
+ pkt->ppoll, pkt->ppoll, FLAG_PREEMPT,
+ MDF_BCLNT, 0, skeyid, sys_ident);
+ if (NULL == peer) {
+ sys_restricted++;
+ return; /* ignore duplicate */
+
+ } else {
+ peer->delay = sys_bdelay;
+ }
+ break;
}
- break;
+
+ /*
+ * Execute the initial volley in order to calibrate the
+ * propagation delay and run the Autokey protocol.
+ *
+ * Note that the minpoll is taken from the broadcast
+ * packet, normally 6 (64 s) and that the poll interval
+ * is fixed at this value.
+ */
+ peer = newpeer(&rbufp->recv_srcadr, NULL, match_ep,
+ MODE_CLIENT, hisversion, pkt->ppoll, pkt->ppoll,
+ FLAG_BC_VOL | FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT,
+ 0, skeyid, sys_ident);
+ if (NULL == peer) {
+ sys_restricted++;
+ return; /* ignore duplicate */
+ }
+#ifdef AUTOKEY
+ if (skeyid > NTP_MAXKEY)
+ crypto_recv(peer, rbufp);
+#endif /* AUTOKEY */
+
+ return; /* hooray */
/*
* This is the first packet received from a symmetric active
@@ -863,150 +1102,280 @@ receive(
*/
case AM_NEWPASS:
+#ifdef AUTOKEY
/*
- * If the inbound packet is correctly authenticated and
- * enabled, a symmetric passive association is
- * mobilized. If not but correctly authenticated, a
- * symmetric active response is sent. If authentication
- * fails, send a crypto-NAK packet.
+ * Do not respond if not the same group.
*/
- if (!AUTH(restrict_mask & RES_DONTTRUST, is_authentic))
- {
- if (is_authentic == AUTH_ERROR)
+ if (group_test(groupname, sys_ident)) {
+ sys_declined++;
+ return;
+ }
+#endif /* AUTOKEY */
+ if (!AUTH(sys_authenticate | (restrict_mask &
+ (RES_NOPEER | RES_DONTTRUST)), is_authentic)) {
+
+ /*
+ * If authenticated but cannot mobilize an
+ * association, send a symmetric passive
+ * response without mobilizing an association.
+ * This is for drat broken Windows clients. See
+ * Microsoft KB 875424 for preferred workaround.
+ */
+ if (AUTH(restrict_mask & RES_DONTTRUST,
+ is_authentic)) {
+ fast_xmit(rbufp, MODE_PASSIVE, skeyid,
+ restrict_mask);
+ return; /* hooray */
+ }
+ if (is_authentic == AUTH_ERROR) {
fast_xmit(rbufp, MODE_ACTIVE, 0,
restrict_mask);
- return; /* bad auth */
+ sys_restricted++;
+ return;
+ }
}
- if (!AUTH(sys_authenticate | (restrict_mask &
- RES_NOPEER), is_authentic)) {
- fast_xmit(rbufp, MODE_ACTIVE, skeyid,
- restrict_mask);
- return; /* hooray */
+
+ /*
+ * Do not respond if synchronized and if stratum is
+ * below the floor or at or above the ceiling. Note,
+ * this allows an unsynchronized peer to synchronize to
+ * us. It would be very strange if he did and then was
+ * nipped, but that could only happen if we were
+ * operating at the top end of the range. It also means
+ * we will spin an ephemeral association in response to
+ * MODE_ACTIVE KoDs, which will time out eventually.
+ */
+ if (hisleap != LEAP_NOTINSYNC && (hisstratum <
+ sys_floor || hisstratum >= sys_ceiling)) {
+ sys_declined++;
+ return; /* no help */
}
/*
- * Do not respond if stratum is below the floor.
+ * The message is correctly authenticated and allowed.
+ * Mobilize a symmetric passive association.
*/
- if (hisstratum < sys_floor)
- return; /* bad stratum */
-
- if ((peer = newpeer(&rbufp->recv_srcadr,
- rbufp->dstadr, MODE_PASSIVE, hisversion,
- NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0,
- skeyid)) == NULL)
- return; /* system error */
+ if ((peer = newpeer(&rbufp->recv_srcadr, NULL,
+ rbufp->dstadr, MODE_PASSIVE, hisversion, pkt->ppoll,
+ NTP_MAXDPOLL, 0, MDF_UCAST, 0, skeyid,
+ sys_ident)) == NULL) {
+ sys_declined++;
+ return; /* ignore duplicate */
+ }
break;
+
/*
* Process regular packet. Nothing special.
*/
case AM_PROCPKT:
+
+#ifdef AUTOKEY
+ /*
+ * Do not respond if not the same group.
+ */
+ if (group_test(groupname, peer->ident)) {
+ sys_declined++;
+ return;
+ }
+#endif /* AUTOKEY */
break;
/*
* A passive packet matches a passive association. This is
* usually the result of reconfiguring a client on the fly. As
- * this association might be legitamate and this packet an
+ * this association might be legitimate and this packet an
* attempt to deny service, just ignore it.
*/
case AM_ERR:
+ sys_declined++;
return;
/*
* For everything else there is the bit bucket.
*/
default:
+ sys_declined++;
+ return;
+ }
+
+#ifdef AUTOKEY
+ /*
+ * If the association is configured for Autokey, the packet must
+ * have a public key ID; if not, the packet must have a
+ * symmetric key ID.
+ */
+ if (is_authentic != AUTH_CRYPTO && (((peer->flags &
+ FLAG_SKEY) && skeyid <= NTP_MAXKEY) || (!(peer->flags &
+ FLAG_SKEY) && skeyid > NTP_MAXKEY))) {
+ sys_badauth++;
return;
}
+#endif /* AUTOKEY */
+ peer->received++;
peer->flash &= ~PKT_TEST_MASK;
+ if (peer->flags & FLAG_XBOGUS) {
+ peer->flags &= ~FLAG_XBOGUS;
+ peer->flash |= TEST3;
+ }
/*
* Next comes a rigorous schedule of timestamp checking. If the
- * transmit timestamp is zero, the server is horribly broken.
+ * transmit timestamp is zero, the server has not initialized in
+ * interleaved modes or is horribly broken.
*/
if (L_ISZERO(&p_xmt)) {
- return; /* read rfc1305 */
+ peer->flash |= TEST3; /* unsynch */
/*
* If the transmit timestamp duplicates a previous one, the
* packet is a replay. This prevents the bad guys from replaying
* the most recent packet, authenticated or not.
*/
- } else if (L_ISEQU(&peer->org, &p_xmt)) {
- peer->flash |= TEST1;
+ } else if (L_ISEQU(&peer->xmt, &p_xmt)) {
+ peer->flash |= TEST1; /* duplicate */
peer->oldpkt++;
- return; /* duplicate packet */
-
+ return;
/*
- * If this is a broadcast mode packet, skip further checking.
+ * If this is a broadcast mode packet, skip further checking. If
+ * an initial volley, bail out now and let the client do its
+ * stuff. If the origin timestamp is nonzero, this is an
+ * interleaved broadcast. so restart the protocol.
*/
- } else if (hismode != MODE_BROADCAST) {
- if (L_ISZERO(&p_org))
- peer->flash |= TEST3; /* protocol unsynch */
- else if (!L_ISEQU(&p_org, &peer->xmt))
- peer->flash |= TEST2; /* bogus packet */
- }
+ } else if (hismode == MODE_BROADCAST) {
+ if (!L_ISZERO(&p_org) && !(peer->flags & FLAG_XB)) {
+ peer->flags |= FLAG_XB;
+ peer->aorg = p_xmt;
+ peer->borg = rbufp->recv_time;
+ report_event(PEVNT_XLEAVE, peer, NULL);
+ return;
+ }
/*
- * If unsynchronized or bogus abandon ship. If the crypto machine
- * breaks, light the crypto bit and plaint the log.
+ * Check for bogus packet in basic mode. If found, switch to
+ * interleaved mode and resynchronize, but only after confirming
+ * the packet is not bogus in symmetric interleaved mode.
*/
- if (peer->flash & PKT_TEST_MASK) {
-#ifdef OPENSSL
- if (crypto_flags && (peer->flags & FLAG_SKEY)) {
- rval = crypto_recv(peer, rbufp);
- if (rval != XEVNT_OK) {
- peer_clear(peer, "CRYP");
- peer->flash |= TEST9; /* crypto error */
+ } else if (peer->flip == 0) {
+ if (!L_ISEQU(&p_org, &peer->aorg)) {
+ peer->bogusorg++;
+ peer->flash |= TEST2; /* bogus */
+ if (!L_ISZERO(&peer->dst) && L_ISEQU(&p_org,
+ &peer->dst)) {
+ peer->flip = 1;
+ report_event(PEVNT_XLEAVE, peer, NULL);
}
+ } else {
+ L_CLR(&peer->aorg);
}
-#endif /* OPENSSL */
- return; /* unsynch */
+
+ /*
+ * Check for valid nonzero timestamp fields.
+ */
+ } else if (L_ISZERO(&p_org) || L_ISZERO(&p_rec) ||
+ L_ISZERO(&peer->dst)) {
+ peer->flash |= TEST3; /* unsynch */
+
+ /*
+ * Check for bogus packet in interleaved symmetric mode. This
+ * can happen if a packet is lost, duplicated or crossed. If
+ * found, flip and resynchronize.
+ */
+ } else if (!L_ISZERO(&peer->dst) && !L_ISEQU(&p_org,
+ &peer->dst)) {
+ peer->bogusorg++;
+ peer->flags |= FLAG_XBOGUS;
+ peer->flash |= TEST2; /* bogus */
}
/*
- * The timestamps are valid and the receive packet matches the
- * last one sent. If the packet is a crypto-NAK, the server
- * might have just changed keys. We reset the association
- * and restart the protocol.
+ * If this is a crypto_NAK, the server cannot authenticate a
+ * client packet. The server might have just changed keys. Clear
+ * the association and restart the protocol.
*/
if (is_authentic == AUTH_CRYPTO) {
- peer_clear(peer, "AUTH");
- return; /* crypto-NAK */
+ report_event(PEVNT_AUTH, peer, "crypto_NAK");
+ peer->flash |= TEST5; /* bad auth */
+ peer->badauth++;
+ if (peer->flags & FLAG_PREEMPT) {
+ unpeer(peer);
+ return;
+ }
+#ifdef AUTOKEY
+ if (peer->crypto)
+ peer_clear(peer, "AUTH");
+#endif /* AUTOKEY */
+ return;
- /*
- * If the association is authenticated, the key ID is nonzero
- * and received packets must be authenticated. This is designed
- * to avoid a bait-and-switch attack, which was possible in past
- * versions. If symmetric modes, return a crypto-NAK. The peer
- * should restart the protocol.
+ /*
+ * If the digest fails or it's missing for authenticated
+ * associations, the client cannot authenticate a server
+ * reply to a client packet previously sent. The loopback check
+ * is designed to avoid a bait-and-switch attack, which was
+ * possible in past versions. If symmetric modes, return a
+ * crypto-NAK. The peer should restart the protocol.
*/
} else if (!AUTH(peer->keyid || has_mac ||
- (restrict_mask & RES_DONTTRUST), is_authentic)) {
- peer->flash |= TEST5;
+ (restrict_mask & RES_DONTTRUST), is_authentic)) {
+ report_event(PEVNT_AUTH, peer, "digest");
+ peer->flash |= TEST5; /* bad auth */
+ peer->badauth++;
if (has_mac &&
(hismode == MODE_ACTIVE || hismode == MODE_PASSIVE))
fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask);
- return; /* bad auth */
+ if (peer->flags & FLAG_PREEMPT) {
+ unpeer(peer);
+ return;
+ }
+#ifdef AUTOKEY
+ if (peer->crypto)
+ peer_clear(peer, "AUTH");
+#endif /* AUTOKEY */
+ return;
+ }
+
+ /*
+ * Update the state variables.
+ */
+ if (peer->flip == 0) {
+ if (hismode != MODE_BROADCAST)
+ peer->rec = p_xmt;
+ peer->dst = rbufp->recv_time;
+ }
+ peer->xmt = p_xmt;
+
+ /*
+ * Set the peer ppoll to the maximum of the packet ppoll and the
+ * peer minpoll. If a kiss-o'-death, set the peer minpoll to
+ * this maximum and advance the headway to give the sender some
+ * headroom. Very intricate.
+ */
+ peer->ppoll = max(peer->minpoll, pkt->ppoll);
+ if (hismode == MODE_SERVER && hisleap == LEAP_NOTINSYNC &&
+ hisstratum == STRATUM_UNSPEC && memcmp(&pkt->refid,
+ "RATE", 4) == 0) {
+ peer->selbroken++;
+ report_event(PEVNT_RATE, peer, NULL);
+ if (pkt->ppoll > peer->minpoll)
+ peer->minpoll = peer->ppoll;
+ peer->burst = peer->retry = 0;
+ peer->throttle = (NTP_SHIFT + 1) * (1 << peer->minpoll);
+ poll_update(peer, pkt->ppoll);
+ return; /* kiss-o'-death */
}
/*
* That was hard and I am sweaty, but the packet is squeaky
* clean. Get on with real work.
- *
- * Update the origin and destination timestamps.
*/
- peer->org = p_xmt;
- peer->rec = rbufp->recv_time;
-
- peer->received++;
peer->timereceived = current_time;
if (is_authentic == AUTH_OK)
peer->flags |= FLAG_AUTHENTIC;
else
peer->flags &= ~FLAG_AUTHENTIC;
-#ifdef OPENSSL
+
+#ifdef AUTOKEY
/*
* More autokey dance. The rules of the cha-cha are as follows:
*
@@ -1025,31 +1394,64 @@ receive(
* 5. Check to see that one or more hashes of the current key ID
* matches the previous key ID or ultimate original key ID
* obtained from the broadcaster or symmetric peer. If no
- * match, sit the dance and wait for timeout.
+ * match, sit the dance and call for new autokey values.
*
- * In case of crypto error, fire the orchestra and stop dancing.
- * This is considered a permanant error, so light the crypto bit
- * to suppress further requests. If preemptable or ephemeral,
- * scuttle the ship.
+ * In case of crypto error, fire the orchestra, stop dancing and
+ * restart the protocol.
*/
- if (crypto_flags && (peer->flags & FLAG_SKEY)) {
+ if (peer->flags & FLAG_SKEY) {
+ /*
+ * Decrement remaining autokey hashes. This isn't
+ * perfect if a packet is lost, but results in no harm.
+ */
+ ap = (struct autokey *)peer->recval.ptr;
+ if (ap != NULL) {
+ if (ap->seq > 0)
+ ap->seq--;
+ }
peer->flash |= TEST8;
rval = crypto_recv(peer, rbufp);
- if (rval != XEVNT_OK) {
- peer_clear(peer, "CRYP");
- peer->flash |= TEST9; /* crypto error */
- if (peer->flags & FLAG_PREEMPT ||
- !(peer->flags & FLAG_CONFIG))
- unpeer(peer);
+ if (rval == XEVNT_OK) {
+ peer->unreach = 0;
+ } else {
+ if (rval == XEVNT_ERR) {
+ report_event(PEVNT_RESTART, peer,
+ "crypto error");
+ peer_clear(peer, "CRYP");
+ peer->flash |= TEST9; /* bad crypt */
+ if (peer->flags & FLAG_PREEMPT)
+ unpeer(peer);
+ }
return;
+ }
- } else if (hismode == MODE_SERVER) {
+ /*
+ * If server mode, verify the receive key ID matches
+ * the transmit key ID.
+ */
+ if (hismode == MODE_SERVER) {
if (skeyid == peer->keyid)
peer->flash &= ~TEST8;
+
+ /*
+ * If an extension field is present, verify only that it
+ * has been correctly signed. We don't need a sequence
+ * check here, but the sequence continues.
+ */
} else if (!(peer->flash & TEST8)) {
peer->pkeyid = skeyid;
- } else if ((ap = (struct autokey *)peer->recval.ptr) !=
- NULL) {
+
+ /*
+ * Now the fun part. Here, skeyid is the current ID in
+ * the packet, pkeyid is the ID in the last packet and
+ * tkeyid is the hash of skeyid. If the autokey values
+ * have not been received, this is an automatic error.
+ * If so, check that the tkeyid matches pkeyid. If not,
+ * hash tkeyid and try again. If the number of hashes
+ * exceeds the number remaining in the sequence, declare
+ * a successful failure and refresh the autokey values.
+ */
+ } else if (ap != NULL) {
int i;
for (i = 0; ; i++) {
@@ -1057,45 +1459,57 @@ receive(
tkeyid == ap->key) {
peer->flash &= ~TEST8;
peer->pkeyid = skeyid;
+ ap->seq -= i;
break;
}
- if (i > ap->seq)
+ if (i > ap->seq) {
+ peer->crypto &=
+ ~CRYPTO_FLAG_AUTO;
break;
+ }
tkeyid = session_key(
&rbufp->recv_srcadr, dstadr_sin,
tkeyid, pkeyid, 0);
}
+ if (peer->flash & TEST8)
+ report_event(PEVNT_AUTH, peer, "keylist");
}
if (!(peer->crypto & CRYPTO_FLAG_PROV)) /* test 9 */
- peer->flash |= TEST8; /* not proventic */
+ peer->flash |= TEST8; /* bad autokey */
/*
- * If the transmit queue is nonempty, clamp the host
- * poll interval to the packet poll interval.
+ * The maximum lifetime of the protocol is about one
+ * week before restarting the Autokey protocol to
+ * refresh certificates and leapseconds values.
*/
- if (peer->cmmd != 0) {
- peer->ppoll = pkt->ppoll;
- poll_update(peer, peer->hpoll);
+ if (current_time > peer->refresh) {
+ report_event(PEVNT_RESTART, peer,
+ "crypto refresh");
+ peer_clear(peer, "TIME");
+ return;
}
}
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
/*
* The dance is complete and the flash bits have been lit. Toss
* the packet over the fence for processing, which may light up
* more flashers.
*/
- process_packet(peer, pkt);
+ process_packet(peer, pkt, rbufp->recv_length);
/*
- * Well, that was nice. If TEST4 is lit, either the crypto
- * machine jammed or a kiss-o'-death packet flew in, either of
- * which is fatal.
+ * In interleaved mode update the state variables. Also adjust the
+ * transmit phase to avoid crossover.
*/
- if (peer->flash & TEST4) {
- msyslog(LOG_INFO, "receive: fatal error %04x for %s",
- peer->flash, stoa(&peer->srcadr));
- return;
+ if (peer->flip != 0) {
+ peer->rec = p_rec;
+ peer->dst = rbufp->recv_time;
+ if (peer->nextdate - current_time < (1U << min(peer->ppoll,
+ peer->hpoll)) / 2)
+ peer->nextdate++;
+ else
+ peer->nextdate--;
}
}
@@ -1109,66 +1523,76 @@ receive(
void
process_packet(
register struct peer *peer,
- register struct pkt *pkt
+ register struct pkt *pkt,
+ u_int len
)
{
double t34, t21;
double p_offset, p_del, p_disp;
- l_fp p_rec, p_xmt, p_org, p_reftime;
- l_fp ci;
- u_char pmode, pleap, pstratum;
+ l_fp p_rec, p_xmt, p_org, p_reftime, ci;
+ u_char pmode, pleap, pversion, pstratum;
+ char statstr[NTP_MAXSTRLEN];
+#ifdef ASSYM
+ int itemp;
+ double etemp, ftemp, td;
+#endif /* ASSYM */
sys_processed++;
peer->processed++;
p_del = FPTOD(NTOHS_FP(pkt->rootdelay));
- p_disp = FPTOD(NTOHS_FP(pkt->rootdispersion));
+ p_offset = 0;
+ p_disp = FPTOD(NTOHS_FP(pkt->rootdisp));
NTOHL_FP(&pkt->reftime, &p_reftime);
+ NTOHL_FP(&pkt->org, &p_org);
NTOHL_FP(&pkt->rec, &p_rec);
NTOHL_FP(&pkt->xmt, &p_xmt);
pmode = PKT_MODE(pkt->li_vn_mode);
pleap = PKT_LEAP(pkt->li_vn_mode);
- if (pmode != MODE_BROADCAST)
- NTOHL_FP(&pkt->org, &p_org);
- else
- p_org = peer->rec;
+ pversion = PKT_VERSION(pkt->li_vn_mode);
pstratum = PKT_TO_STRATUM(pkt->stratum);
/*
- * Test for kiss-o'death packet)
+ * Capture the header values in the client/peer association..
*/
- if (pleap == LEAP_NOTINSYNC && pstratum == STRATUM_UNSPEC) {
- if (memcmp(&pkt->refid, "DENY", 4) == 0) {
- peer_clear(peer, "DENY");
- peer->flash |= TEST4; /* access denied */
- }
- }
-
- /*
- * Capture the header values.
- */
- record_raw_stats(&peer->srcadr, peer->dstadr ? &peer->dstadr->sin : NULL, &p_org,
- &p_rec, &p_xmt, &peer->rec);
+ record_raw_stats(&peer->srcadr, peer->dstadr ?
+ &peer->dstadr->sin : NULL,
+ &p_org, &p_rec, &p_xmt, &peer->dst,
+ pleap, pversion, pmode, pstratum, pkt->ppoll, pkt->precision,
+ p_del, p_disp, pkt->refid);
peer->leap = pleap;
peer->stratum = min(pstratum, STRATUM_UNSPEC);
peer->pmode = pmode;
- peer->ppoll = pkt->ppoll;
peer->precision = pkt->precision;
peer->rootdelay = p_del;
- peer->rootdispersion = p_disp;
+ peer->rootdisp = p_disp;
peer->refid = pkt->refid; /* network byte order */
peer->reftime = p_reftime;
/*
- * Verify the server is synchronized; that is, the leap bits and
- * stratum are valid, the root delay and root dispersion are
- * valid and the reference timestamp is not later than the
- * transmit timestamp.
+ * First, if either burst mode is armed, enable the burst.
+ * Compute the headway for the next packet and delay if
+ * necessary to avoid exceeding the threshold.
+ */
+ if (peer->retry > 0) {
+ peer->retry = 0;
+ if (peer->reach)
+ peer->burst = min(1 << (peer->hpoll -
+ peer->minpoll), NTP_SHIFT) - 1;
+ else
+ peer->burst = NTP_IBURST - 1;
+ if (peer->burst > 0)
+ peer->nextdate = current_time;
+ }
+ poll_update(peer, peer->hpoll);
+
+ /*
+ * Verify the server is synchronized; that is, the leap bits,
+ * stratum and root distance are valid.
*/
if (pleap == LEAP_NOTINSYNC || /* test 6 */
pstratum < sys_floor || pstratum >= sys_ceiling)
- peer->flash |= TEST6; /* peer not synch */
- if (p_del < 0 || p_disp < 0 || p_del / /* test 7 */
- 2 + p_disp >= MAXDISPERSE || !L_ISHIS(&p_xmt, &p_reftime))
+ peer->flash |= TEST6; /* bad synch or strat */
+ if (p_del / 2 + p_disp >= MAXDISPERSE) /* test 7 */
peer->flash |= TEST7; /* bad header */
/*
@@ -1177,6 +1601,7 @@ process_packet(
* receive() routine.
*/
if (peer->flash & PKT_TEST_MASK) {
+ peer->seldisptoolarge++;
#ifdef DEBUG
if (debug)
printf("packet: flash header %04x\n",
@@ -1184,11 +1609,15 @@ process_packet(
#endif
return;
}
- if (!(peer->reach)) {
- report_event(EVNT_REACH, peer);
+
+ /*
+ * If the peer was previously unreachable, raise a trap. In any
+ * case, mark it reachable.
+ */
+ if (!peer->reach) {
+ report_event(PEVNT_REACH, peer, NULL);
peer->timereachable = current_time;
}
- poll_update(peer, peer->hpoll);
peer->reach |= 1;
/*
@@ -1196,8 +1625,7 @@ process_packet(
* roundtrip delay and dispersion. The equations are reordered
* from the spec for more efficient use of temporaries. For a
* broadcast association, offset the last measurement by the
- * computed delay during the client/server volley. Note that
- * org has been set to the time of last reception. Note the
+ * computed delay during the client/server volley. Note the
* computation of dispersion includes the system precision plus
* that due to the frequency error since the origin time.
*
@@ -1212,52 +1640,202 @@ process_packet(
* only half that span. Since the typical first-order
* differences are usually very small, they are converted to 64-
* bit doubles and all remaining calculations done in floating-
- * point arithmetic. This preserves the accuracy while retaining
- * the 68-year span.
+ * double arithmetic. This preserves the accuracy while
+ * retaining the 68-year span.
*
- * Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec:
- */
- ci = p_xmt; /* t3 - t4 */
- L_SUB(&ci, &peer->rec);
- LFPTOD(&ci, t34);
- ci = p_rec; /* t2 - t1 */
- L_SUB(&ci, &p_org);
- LFPTOD(&ci, t21);
- ci = peer->rec; /* t4 - t1 */
- L_SUB(&ci, &p_org);
-
- /*
- * If running in a broadcast association, the clock offset is
- * (t1 - t0) corrected by the one-way delay, but we can't
- * measure that directly. Therefore, we start up in MODE_CLIENT
- * mode, set FLAG_MCAST and exchange eight messages to determine
- * the clock offset. When the last message is sent, we switch to
- * MODE_BCLIENT mode. The next broadcast message after that
- * computes the broadcast offset and clears FLAG_MCAST.
- */
- if (pmode == MODE_BROADCAST) {
- p_offset = t34;
- if (peer->flags & FLAG_MCAST) {
- peer->estbdelay = peer->offset - p_offset;
- if (peer->hmode == MODE_CLIENT)
+ * There are three interleaving schemes, basic, interleaved
+ * symmetric and interleaved broadcast. The timestamps are
+ * idioscyncratically different. See the onwire briefing/white
+ * paper at www.eecis.udel.edu/~mills for details.
+ *
+ * Interleaved symmetric mode
+ * t1 = peer->aorg/borg, t2 = peer->rec, t3 = p_xmt,
+ * t4 = peer->dst
+ */
+ if (peer->flip != 0) {
+ ci = p_xmt; /* t3 - t4 */
+ L_SUB(&ci, &peer->dst);
+ LFPTOD(&ci, t34);
+ ci = p_rec; /* t2 - t1 */
+ if (peer->flip > 0)
+ L_SUB(&ci, &peer->borg);
+ else
+ L_SUB(&ci, &peer->aorg);
+ LFPTOD(&ci, t21);
+ p_del = t21 - t34;
+ p_offset = (t21 + t34) / 2.;
+ if (p_del < 0 || p_del > 1.) {
+ snprintf(statstr, sizeof(statstr),
+ "t21 %.6f t34 %.6f", t21, t34);
+ report_event(PEVNT_XERR, peer, statstr);
+ return;
+ }
+
+ /*
+ * Broadcast modes
+ */
+ } else if (peer->pmode == MODE_BROADCAST) {
+
+ /*
+ * Interleaved broadcast mode. Use interleaved timestamps.
+ * t1 = peer->borg, t2 = p_org, t3 = p_org, t4 = aorg
+ */
+ if (peer->flags & FLAG_XB) {
+ ci = p_org; /* delay */
+ L_SUB(&ci, &peer->aorg);
+ LFPTOD(&ci, t34);
+ ci = p_org; /* t2 - t1 */
+ L_SUB(&ci, &peer->borg);
+ LFPTOD(&ci, t21);
+ peer->aorg = p_xmt;
+ peer->borg = peer->dst;
+ if (t34 < 0 || t34 > 1.) {
+ snprintf(statstr, sizeof(statstr),
+ "offset %.6f delay %.6f", t21, t34);
+ report_event(PEVNT_XERR, peer, statstr);
return;
+ }
+ p_offset = t21;
+ peer->xleave = t34;
- peer->flags &= ~(FLAG_MCAST | FLAG_BURST);
+ /*
+ * Basic broadcast - use direct timestamps.
+ * t3 = p_xmt, t4 = peer->dst
+ */
+ } else {
+ ci = p_xmt; /* t3 - t4 */
+ L_SUB(&ci, &peer->dst);
+ LFPTOD(&ci, t34);
+ p_offset = t34;
+ }
+
+ /*
+ * When calibration is complete and the clock is
+ * synchronized, the bias is calculated as the difference
+ * between the unicast timestamp and the broadcast
+ * timestamp. This works for both basic and interleaved
+ * modes.
+ */
+ if (FLAG_BC_VOL & peer->flags) {
+ peer->flags &= ~FLAG_BC_VOL;
+ peer->delay = fabs(peer->offset - p_offset) * 2;
}
- p_offset += peer->estbdelay;
p_del = peer->delay;
- p_disp = 0;
+ p_offset += p_del / 2;
+
+
+ /*
+ * Basic mode, otherwise known as the old fashioned way.
+ *
+ * t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->dst
+ */
} else {
+ ci = p_xmt; /* t3 - t4 */
+ L_SUB(&ci, &peer->dst);
+ LFPTOD(&ci, t34);
+ ci = p_rec; /* t2 - t1 */
+ L_SUB(&ci, &p_org);
+ LFPTOD(&ci, t21);
+ p_del = fabs(t21 - t34);
p_offset = (t21 + t34) / 2.;
- p_del = t21 - t34;
- LFPTOD(&ci, p_disp);
- p_disp = LOGTOD(sys_precision) +
- LOGTOD(peer->precision) + clock_phi * p_disp;
}
p_del = max(p_del, LOGTOD(sys_precision));
- clock_filter(peer, p_offset, p_del, p_disp);
- record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
- peer->offset, peer->delay, peer->disp, peer->jitter);
+ p_disp = LOGTOD(sys_precision) + LOGTOD(peer->precision) +
+ clock_phi * p_del;
+
+#if ASSYM
+ /*
+ * This code calculates the outbound and inbound data rates by
+ * measuring the differences between timestamps at different
+ * packet lengths. This is helpful in cases of large asymmetric
+ * delays commonly experienced on deep space communication
+ * links.
+ */
+ if (peer->t21_last > 0 && peer->t34_bytes > 0) {
+ itemp = peer->t21_bytes - peer->t21_last;
+ if (itemp > 25) {
+ etemp = t21 - peer->t21;
+ if (fabs(etemp) > 1e-6) {
+ ftemp = itemp / etemp;
+ if (ftemp > 1000.)
+ peer->r21 = ftemp;
+ }
+ }
+ itemp = len - peer->t34_bytes;
+ if (itemp > 25) {
+ etemp = -t34 - peer->t34;
+ if (fabs(etemp) > 1e-6) {
+ ftemp = itemp / etemp;
+ if (ftemp > 1000.)
+ peer->r34 = ftemp;
+ }
+ }
+ }
+
+ /*
+ * The following section compensates for different data rates on
+ * the outbound (d21) and inbound (t34) directions. To do this,
+ * it finds t such that r21 * t - r34 * (d - t) = 0, where d is
+ * the roundtrip delay. Then it calculates the correction as a
+ * fraction of d.
+ */
+ peer->t21 = t21;
+ peer->t21_last = peer->t21_bytes;
+ peer->t34 = -t34;
+ peer->t34_bytes = len;
+#ifdef DEBUG
+ if (debug > 1)
+ printf("packet: t21 %.9lf %d t34 %.9lf %d\n", peer->t21,
+ peer->t21_bytes, peer->t34, peer->t34_bytes);
+#endif
+ if (peer->r21 > 0 && peer->r34 > 0 && p_del > 0) {
+ if (peer->pmode != MODE_BROADCAST)
+ td = (peer->r34 / (peer->r21 + peer->r34) -
+ .5) * p_del;
+ else
+ td = 0;
+
+ /*
+ * Unfortunately, in many cases the errors are
+ * unacceptable, so for the present the rates are not
+ * used. In future, we might find conditions where the
+ * calculations are useful, so this should be considered
+ * a work in progress.
+ */
+ t21 -= td;
+ t34 -= td;
+#ifdef DEBUG
+ if (debug > 1)
+ printf("packet: del %.6lf r21 %.1lf r34 %.1lf %.6lf\n",
+ p_del, peer->r21 / 1e3, peer->r34 / 1e3,
+ td);
+#endif
+ }
+#endif /* ASSYM */
+
+ /*
+ * That was awesome. Now hand off to the clock filter.
+ */
+ clock_filter(peer, p_offset + peer->bias, p_del, p_disp);
+
+ /*
+ * If we are in broadcast calibrate mode, return to broadcast
+ * client mode when the client is fit and the autokey dance is
+ * complete.
+ */
+ if ((FLAG_BC_VOL & peer->flags) && MODE_CLIENT == peer->hmode &&
+ !(TEST11 & peer_unfit(peer))) { /* distance exceeded */
+#ifdef AUTOKEY
+ if (peer->flags & FLAG_SKEY) {
+ if (!(~peer->crypto & CRYPTO_FLAG_ALL))
+ peer->hmode = MODE_BCLIENT;
+ } else {
+ peer->hmode = MODE_BCLIENT;
+ }
+#else /* !AUTOKEY follows */
+ peer->hmode = MODE_BCLIENT;
+#endif /* !AUTOKEY */
+ }
}
@@ -1265,39 +1843,98 @@ process_packet(
* clock_update - Called at system process update intervals.
*/
static void
-clock_update(void)
+clock_update(
+ struct peer *peer /* peer structure pointer */
+ )
{
- u_char oleap;
- u_char ostratum;
double dtemp;
+ l_fp now;
+#ifdef HAVE_LIBSCF_H
+ char *fmri;
+#endif /* HAVE_LIBSCF_H */
/*
- * There must be a system peer at this point. If we just changed
- * the system peer, but have a newer sample from the old one,
- * wait until newer data are available.
+ * Update the system state variables. We do this very carefully,
+ * as the poll interval might need to be clamped differently.
*/
- if (sys_poll < sys_peer->minpoll)
- sys_poll = sys_peer->minpoll;
- if (sys_poll > sys_peer->maxpoll)
- sys_poll = sys_peer->maxpoll;
- poll_update(sys_peer, sys_poll);
- if (sys_peer->epoch <= sys_clocktime)
- return;
+ sys_peer = peer;
+ sys_epoch = peer->epoch;
+ if (sys_poll < peer->minpoll)
+ sys_poll = peer->minpoll;
+ if (sys_poll > peer->maxpoll)
+ sys_poll = peer->maxpoll;
+ poll_update(peer, sys_poll);
+ sys_stratum = min(peer->stratum + 1, STRATUM_UNSPEC);
+ if (peer->stratum == STRATUM_REFCLOCK ||
+ peer->stratum == STRATUM_UNSPEC)
+ sys_refid = peer->refid;
+ else
+ sys_refid = addr2refid(&peer->srcadr);
+ /*
+ * Root Dispersion (E) is defined (in RFC 5905) as:
+ *
+ * E = p.epsilon_r + p.epsilon + p.psi + PHI*(s.t - p.t) + |THETA|
+ *
+ * where:
+ * p.epsilon_r is the PollProc's root dispersion
+ * p.epsilon is the PollProc's dispersion
+ * p.psi is the PollProc's jitter
+ * THETA is the combined offset
+ *
+ * NB: Think Hard about where these numbers come from and
+ * what they mean. When did peer->update happen? Has anything
+ * interesting happened since then? What values are the most
+ * defensible? Why?
+ *
+ * DLM thinks this equation is probably the best of all worse choices.
+ */
+ dtemp = peer->rootdisp
+ + peer->disp
+ + sys_jitter
+ + clock_phi * (current_time - peer->update)
+ + fabs(sys_offset);
+
+ if (dtemp > sys_mindisp)
+ sys_rootdisp = dtemp;
+ else
+ sys_rootdisp = sys_mindisp;
+ sys_rootdelay = peer->delay + peer->rootdelay;
+ sys_reftime = peer->dst;
#ifdef DEBUG
if (debug)
- printf("clock_update: at %ld assoc %d \n", current_time,
- peer_associations);
+ printf(
+ "clock_update: at %lu sample %lu associd %d\n",
+ current_time, peer->epoch, peer->associd);
#endif
- oleap = sys_leap;
- ostratum = sys_stratum;
- switch (local_clock(sys_peer, sys_offset)) {
+
+ /*
+ * Comes now the moment of truth. Crank the clock discipline and
+ * see what comes out.
+ */
+ switch (local_clock(peer, sys_offset)) {
/*
* Clock exceeds panic threshold. Life as we know it ends.
*/
case -1:
- report_event(EVNT_SYSFAULT, NULL);
+#ifdef HAVE_LIBSCF_H
+ /*
+ * For Solaris enter the maintenance mode.
+ */
+ if ((fmri = getenv("SMF_FMRI")) != NULL) {
+ if (smf_maintain_instance(fmri, 0) < 0) {
+ printf("smf_maintain_instance: %s\n",
+ scf_strerror(scf_error()));
+ exit(1);
+ }
+ /*
+ * Sleep until SMF kills us.
+ */
+ for (;;)
+ pause();
+ }
+#endif /* HAVE_LIBSCF_H */
exit (-1);
/* not reached */
@@ -1306,64 +1943,68 @@ clock_update(void)
*/
case 2:
clear_all();
- sys_leap = LEAP_NOTINSYNC;
+ set_sys_leap(LEAP_NOTINSYNC);
sys_stratum = STRATUM_UNSPEC;
- sys_peer = NULL;
- sys_rootdelay = 0;
- sys_rootdispersion = 0;
memcpy(&sys_refid, "STEP", 4);
- report_event(EVNT_CLOCKRESET, NULL);
+ sys_rootdelay = 0;
+ sys_rootdisp = 0;
+ L_CLR(&sys_reftime);
+ sys_jitter = LOGTOD(sys_precision);
+ leapsec_reset_frame();
break;
/*
- * Clock was slewed. Update the system stratum, leap bits, root
- * delay, root dispersion, reference ID and reference time. If
- * the leap changes, we gotta reroll the keys. Except for
- * reference clocks, the minimum dispersion increment is not
- * less than sys_mindisp.
+ * Clock was slewed. Handle the leapsecond stuff.
*/
case 1:
- sys_leap = leap_next;
- sys_stratum = min(sys_peer->stratum + 1,
- STRATUM_UNSPEC);
- sys_reftime = sys_peer->rec;
/*
- * In orphan mode the stratum defaults to the orphan
- * stratum. The root delay is set to a random value
- * generated at startup. The root dispersion is set from
- * the peer dispersion; the peer root dispersion is
- * ignored.
+ * If this is the first time the clock is set, reset the
+ * leap bits. If crypto, the timer will goose the setup
+ * process.
*/
- dtemp = sys_peer->disp + clock_phi * (current_time -
- sys_peer->update) + sys_jitter +
- fabs(sys_peer->offset);
-#ifdef REFCLOCK
- if (!(sys_peer->flags & FLAG_REFCLOCK) && dtemp <
- sys_mindisp)
- dtemp = sys_mindisp;
-#else
- if (dtemp < sys_mindisp)
- dtemp = sys_mindisp;
-#endif /* REFCLOCK */
- if (sys_stratum >= sys_orphan) {
- sys_stratum = sys_orphan;
- sys_rootdelay = sys_peer->delay;
- sys_rootdispersion = dtemp;
- } else {
- sys_rootdelay = sys_peer->delay +
- sys_peer->rootdelay;
- sys_rootdispersion = dtemp +
- sys_peer->rootdispersion;
- }
- if (oleap == LEAP_NOTINSYNC) {
- report_event(EVNT_SYNCCHG, NULL);
-#ifdef OPENSSL
- expire_all();
- crypto_update();
-#endif /* OPENSSL */
+ if (sys_leap == LEAP_NOTINSYNC) {
+ set_sys_leap(LEAP_NOWARNING);
+#ifdef AUTOKEY
+ if (crypto_flags)
+ crypto_update();
+#endif /* AUTOKEY */
+ /*
+ * If our parent process is waiting for the
+ * first clock sync, send them home satisfied.
+ */
+#ifdef HAVE_WORKING_FORK
+ if (waitsync_fd_to_close != -1) {
+ close(waitsync_fd_to_close);
+ waitsync_fd_to_close = -1;
+ DPRINTF(1, ("notified parent --wait-sync is done\n"));
+ }
+#endif /* HAVE_WORKING_FORK */
+
+ }
+
+ /*
+ * If there is no leap second pending and the number of
+ * survivor leap bits is greater than half the number of
+ * survivors, try to schedule a leap for the end of the
+ * current month. (This only works if no leap second for
+ * that range is in the table, so doing this more than
+ * once is mostly harmless.)
+ */
+ if (leapsec == LSPROX_NOWARN) {
+ if (leap_vote_ins > leap_vote_del
+ && leap_vote_ins > sys_survivors / 2) {
+ get_systime(&now);
+ leapsec_add_dyn(TRUE, now.l_ui, NULL);
+ }
+ if (leap_vote_del > leap_vote_ins
+ && leap_vote_del > sys_survivors / 2) {
+ get_systime(&now);
+ leapsec_add_dyn(FALSE, now.l_ui, NULL);
+ }
}
break;
+
/*
* Popcorn spike or step threshold exceeded. Pretend it never
* happened.
@@ -1371,8 +2012,6 @@ clock_update(void)
default:
break;
}
- if (ostratum != sys_stratum)
- report_event(EVNT_PEERSTCHG, NULL);
}
@@ -1381,115 +2020,129 @@ clock_update(void)
*/
void
poll_update(
- struct peer *peer,
- int mpoll
+ struct peer *peer, /* peer structure pointer */
+ u_char mpoll
)
{
- int hpoll;
+ u_long next, utemp;
+ u_char hpoll;
/*
* This routine figures out when the next poll should be sent.
- * That turns out to be wickedly complicated. The big problem is
- * that sometimes the time for the next poll is in the past.
- * Watch out for races here between the receive process and the
- * poll process. The key assertion is that, if nextdate equals
- * current_time, the call is from the poll process; otherwise,
- * it is from the receive process.
+ * That turns out to be wickedly complicated. One problem is
+ * that sometimes the time for the next poll is in the past when
+ * the poll interval is reduced. We watch out for races here
+ * between the receive process and the poll process.
*
- * First, bracket the poll interval according to the type of
- * association and options. If a fixed interval is configured,
- * use minpoll. This primarily is for reference clocks, but
- * works for any association.
+ * Clamp the poll interval between minpoll and maxpoll.
*/
- if (peer->flags & FLAG_FIXPOLL) {
- hpoll = peer->minpoll;
+ hpoll = max(min(peer->maxpoll, mpoll), peer->minpoll);
+#ifdef AUTOKEY
/*
- * The ordinary case; clamp the poll interval between minpoll
- * and maxpoll.
- */
- } else {
- hpoll = max(min(peer->maxpoll, mpoll), peer->minpoll);
- }
-#ifdef OPENSSL
- /*
- * Bit of crass arrogance at this point. If the poll interval
- * has changed and we have a keylist, the lifetimes in the
- * keylist are probably bogus. In this case purge the keylist
- * and regenerate it later.
+ * If during the crypto protocol the poll interval has changed,
+ * the lifetimes in the key list are probably bogus. Purge the
+ * the key list and regenerate it later.
*/
- if (hpoll != peer->hpoll)
+ if ((peer->flags & FLAG_SKEY) && hpoll != peer->hpoll)
key_expire(peer);
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
peer->hpoll = hpoll;
/*
- * Now we figure out if there is an override. If during the
- * crypto protocol and a message is pending, make it wait not
- * more than two seconds.
- */
-#ifdef OPENSSL
- if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC ||
- peer->crypto)) {
- peer->nextdate = current_time + RESP_DELAY;
-
- /*
- * If we get called from the receive routine while a burst is
- * pending, just slink away. If from the poll routine and a
- * reference clock or a pending crypto response, delay for one
- * second. If this is the first sent in a burst, wait for the
- * modem to come up. For others in the burst, delay two seconds.
+ * There are three variables important for poll scheduling, the
+ * current time (current_time), next scheduled time (nextdate)
+ * and the earliest time (utemp). The earliest time is 2 s
+ * seconds, but could be more due to rate management. When
+ * sending in a burst, use the earliest time. When not in a
+ * burst but with a reply pending, send at the earliest time
+ * unless the next scheduled time has not advanced. This can
+ * only happen if multiple replies are pending in the same
+ * response interval. Otherwise, send at the later of the next
+ * scheduled time and the earliest time.
+ *
+ * Now we figure out if there is an override. If a burst is in
+ * progress and we get called from the receive process, just
+ * slink away. If called from the poll process, delay 1 s for a
+ * reference clock, otherwise 2 s.
*/
- } else if (peer->burst > 0) {
-#else /* OPENSSL */
+ utemp = current_time + max(peer->throttle - (NTP_SHIFT - 1) *
+ (1 << peer->minpoll), ntp_minpkt);
if (peer->burst > 0) {
-#endif /* OPENSSL */
- if (peer->nextdate != current_time)
+ if (peer->nextdate > current_time)
return;
#ifdef REFCLOCK
else if (peer->flags & FLAG_REFCLOCK)
- peer->nextdate += RESP_DELAY;
+ peer->nextdate = current_time + RESP_DELAY;
#endif /* REFCLOCK */
- else if (peer->flags & (FLAG_IBURST | FLAG_BURST) &&
- peer->burst == NTP_BURST)
- peer->nextdate += sys_calldelay;
else
- peer->nextdate += BURST_DELAY;
+ peer->nextdate = utemp;
+
+#ifdef AUTOKEY
/*
- * The ordinary case; use the minimum of the host and peer
- * intervals, but not less than minpoll. In other words,
- * oversampling is okay but understampling is evil.
+ * If a burst is not in progress and a crypto response message
+ * is pending, delay 2 s, but only if this is a new interval.
*/
- } else {
- peer->nextdate = peer->outdate +
- RANDPOLL(max(min(peer->ppoll, hpoll),
- peer->minpoll));
- }
+ } else if (peer->cmmd != NULL) {
+ if (peer->nextdate > current_time) {
+ if (peer->nextdate + ntp_minpkt != utemp)
+ peer->nextdate = utemp;
+ } else {
+ peer->nextdate = utemp;
+ }
+#endif /* AUTOKEY */
/*
- * If the time for the next poll has already happened, bring it
- * up to the next second after this one. This way the only way
- * to get nexdate == current time is from the poll routine.
+ * The ordinary case. If a retry, use minpoll; if unreachable,
+ * use host poll; otherwise, use the minimum of host and peer
+ * polls; In other words, oversampling is okay but
+ * understampling is evil. Use the maximum of this value and the
+ * headway. If the average headway is greater than the headway
+ * threshold, increase the headway by the minimum interval.
*/
- if (peer->nextdate <= current_time)
- peer->nextdate = current_time + 1;
-#ifdef DEBUG
- if (debug > 1)
- printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n",
- current_time, ntoa(&peer->srcadr), peer->flags,
- peer->hpoll, peer->burst, peer->outdate,
- peer->nextdate);
-#endif
+ } else {
+ if (peer->retry > 0)
+ hpoll = peer->minpoll;
+ else if (!(peer->reach))
+ hpoll = peer->hpoll;
+ else
+ hpoll = min(peer->ppoll, peer->hpoll);
+#ifdef REFCLOCK
+ if (peer->flags & FLAG_REFCLOCK)
+ next = 1 << hpoll;
+ else
+#endif /* REFCLOCK */
+ next = ((0x1000UL | (ntp_random() & 0x0ff)) <<
+ hpoll) >> 12;
+ next += peer->outdate;
+ if (next > utemp)
+ peer->nextdate = next;
+ else
+ peer->nextdate = utemp;
+ if (peer->throttle > (1 << peer->minpoll))
+ peer->nextdate += ntp_minpkt;
+ }
+ DPRINTF(2, ("poll_update: at %lu %s poll %d burst %d retry %d head %d early %lu next %lu\n",
+ current_time, ntoa(&peer->srcadr), peer->hpoll,
+ peer->burst, peer->retry, peer->throttle,
+ utemp - current_time, peer->nextdate -
+ current_time));
}
+
/*
- * peer_crypto_clear - discard crypto information
+ * peer_clear - clear peer filter registers. See Section 3.4.8 of the
+ * spec.
*/
void
-peer_crypto_clear(
- struct peer *peer
- )
+peer_clear(
+ struct peer *peer, /* peer structure */
+ const char *ident /* tally lights */
+ )
{
+ u_char u;
+
+#ifdef AUTOKEY
/*
* If cryptographic credentials have been acquired, toss them to
* Valhalla. Note that autokeys are ephemeral, in that they are
@@ -1499,117 +2152,76 @@ peer_crypto_clear(
* purged, too. This makes it much harder to sneak in some
* unauthenticated data in the clock filter.
*/
- DPRINTF(1, ("peer_crypto_clear: at %ld next %ld assoc ID %d\n",
- current_time, peer->nextdate, peer->associd));
-
-#ifdef OPENSSL
- peer->assoc = 0;
- peer->crypto = 0;
-
- if (peer->pkey != NULL)
- EVP_PKEY_free(peer->pkey);
- peer->pkey = NULL;
-
- peer->digest = NULL; /* XXX MEMLEAK? check whether this needs to be freed in any way - never was freed */
-
- if (peer->subject != NULL)
- free(peer->subject);
- peer->subject = NULL;
-
- if (peer->issuer != NULL)
- free(peer->issuer);
- peer->issuer = NULL;
-
- peer->pkeyid = 0;
-
- peer->pcookie = 0;
-
- if (peer->ident_pkey != NULL)
- EVP_PKEY_free(peer->ident_pkey);
- peer->ident_pkey = NULL;
-
- memset(&peer->fstamp, 0, sizeof(peer->fstamp));
-
+ key_expire(peer);
if (peer->iffval != NULL)
BN_free(peer->iffval);
- peer->iffval = NULL;
-
- if (peer->grpkey != NULL)
- BN_free(peer->grpkey);
- peer->grpkey = NULL;
-
value_free(&peer->cookval);
value_free(&peer->recval);
-
- if (peer->cmmd != NULL) {
- free(peer->cmmd);
- peer->cmmd = NULL;
- }
-
- key_expire(peer);
-
value_free(&peer->encrypt);
-#endif /* OPENSSL */
-}
-
-/*
- * peer_clear - clear peer filter registers. See Section 3.4.8 of the spec.
- */
-void
-peer_clear(
- struct peer *peer, /* peer structure */
- char *ident /* tally lights */
- )
-{
- int i;
-
- peer_crypto_clear(peer);
-
- if (peer == sys_peer)
- sys_peer = NULL;
+ value_free(&peer->sndval);
+ if (peer->cmmd != NULL)
+ free(peer->cmmd);
+ if (peer->subject != NULL)
+ free(peer->subject);
+ if (peer->issuer != NULL)
+ free(peer->issuer);
+#endif /* AUTOKEY */
/*
- * Wipe the association clean and initialize the nonzero values.
+ * Clear all values, including the optional crypto values above.
*/
- memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
- peer->estbdelay = sys_bdelay;
+ memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO(peer));
peer->ppoll = peer->maxpoll;
peer->hpoll = peer->minpoll;
peer->disp = MAXDISPERSE;
+ peer->flash = peer_unfit(peer);
peer->jitter = LOGTOD(sys_precision);
- for (i = 0; i < NTP_SHIFT; i++) {
- peer->filter_order[i] = i;
- peer->filter_disp[i] = MAXDISPERSE;
+
+ /*
+ * If interleave mode, initialize the alternate origin switch.
+ */
+ if (peer->flags & FLAG_XLEAVE)
+ peer->flip = 1;
+ for (u = 0; u < NTP_SHIFT; u++) {
+ peer->filter_order[u] = u;
+ peer->filter_disp[u] = MAXDISPERSE;
}
#ifdef REFCLOCK
if (!(peer->flags & FLAG_REFCLOCK)) {
+#endif
peer->leap = LEAP_NOTINSYNC;
peer->stratum = STRATUM_UNSPEC;
memcpy(&peer->refid, ident, 4);
+#ifdef REFCLOCK
}
-#else
- peer->leap = LEAP_NOTINSYNC;
- peer->stratum = STRATUM_UNSPEC;
- memcpy(&peer->refid, ident, 4);
-#endif /* REFCLOCK */
+#endif
/*
* During initialization use the association count to spread out
- * the polls at one-second intervals. Othersie, randomize over
- * the minimum poll interval in order to avoid broadcast
- * implosion.
+ * the polls at one-second intervals. Passive associations'
+ * first poll is delayed by the "discard minimum" to avoid rate
+ * limiting. Other post-startup new or cleared associations
+ * randomize the first poll over the minimum poll interval to
+ * avoid implosion.
*/
peer->nextdate = peer->update = peer->outdate = current_time;
- if (initializing)
+ if (initializing) {
peer->nextdate += peer_associations;
- else if (peer->hmode == MODE_PASSIVE)
- peer->nextdate += RESP_DELAY;
- else
- peer->nextdate += (ntp_random() & ((1 << NTP_MINDPOLL) -
- 1));
-
- DPRINTF(1, ("peer_clear: at %ld next %ld assoc ID %d refid %s\n",
- current_time, peer->nextdate, peer->associd, ident));
+ } else if (MODE_PASSIVE == peer->hmode) {
+ peer->nextdate += ntp_minpkt;
+ } else {
+ peer->nextdate += ntp_random() % peer->minpoll;
+ }
+#ifdef AUTOKEY
+ peer->refresh = current_time + (1 << NTP_REFRESH);
+#endif /* AUTOKEY */
+#ifdef DEBUG
+ if (debug)
+ printf(
+ "peer_clear: at %ld next %ld associd %d refid %s\n",
+ current_time, peer->nextdate, peer->associd,
+ ident);
+#endif
}
@@ -1629,19 +2241,20 @@ clock_filter(
int ord[NTP_SHIFT]; /* index vector */
int i, j, k, m;
double dtemp, etemp;
+ char tbuf[80];
/*
- * Shift the new sample into the register and discard the oldest
- * one. The new offset and delay come directly from the
- * timestamp calculations. The dispersion grows from the last
- * outbound packet or reference clock update to the present time
- * and increased by the sum of the peer precision and the system
- * precision. The delay can sometimes swing negative due to
- * frequency skew, so it is clamped non-negative.
+ * A sample consists of the offset, delay, dispersion and epoch
+ * of arrival. The offset and delay are determined by the on-
+ * wire protocol. The dispersion grows from the last outbound
+ * packet to the arrival of this one increased by the sum of the
+ * peer precision and the system precision as required by the
+ * error budget. First, shift the new arrival into the shift
+ * register discarding the oldest one.
*/
j = peer->filter_nextpt;
peer->filter_offset[j] = sample_offset;
- peer->filter_delay[j] = max(0, sample_delay);
+ peer->filter_delay[j] = sample_delay;
peer->filter_disp[j] = sample_disp;
peer->filter_epoch[j] = current_time;
j = (j + 1) % NTP_SHIFT;
@@ -1649,40 +2262,41 @@ clock_filter(
/*
* Update dispersions since the last update and at the same
- * time initialize the distance and index lists. The distance
- * list uses a compound metric. If the sample is valid and
- * younger than the minimum Allan intercept, use delay;
- * otherwise, use biased dispersion.
+ * time initialize the distance and index lists. Since samples
+ * become increasingly uncorrelated beyond the Allan intercept,
+ * only under exceptional cases will an older sample be used.
+ * Therefore, the distance list uses a compound metric. If the
+ * dispersion is greater than the maximum dispersion, clamp the
+ * distance at that value. If the time since the last update is
+ * less than the Allan intercept use the delay; otherwise, use
+ * the sum of the delay and dispersion.
*/
dtemp = clock_phi * (current_time - peer->update);
peer->update = current_time;
for (i = NTP_SHIFT - 1; i >= 0; i--) {
if (i != 0)
peer->filter_disp[j] += dtemp;
- if (peer->filter_disp[j] >= MAXDISPERSE)
+ if (peer->filter_disp[j] >= MAXDISPERSE) {
peer->filter_disp[j] = MAXDISPERSE;
- if (peer->filter_disp[j] >= MAXDISPERSE)
dst[i] = MAXDISPERSE;
- else if (peer->update - peer->filter_epoch[j] >
- allan_xpt)
- dst[i] = sys_maxdist + peer->filter_disp[j];
- else
+ } else if (peer->update - peer->filter_epoch[j] >
+ (u_long)ULOGTOD(allan_xpt)) {
+ dst[i] = peer->filter_delay[j] +
+ peer->filter_disp[j];
+ } else {
dst[i] = peer->filter_delay[j];
+ }
ord[i] = j;
- j++; j %= NTP_SHIFT;
+ j = (j + 1) % NTP_SHIFT;
}
- /*
- * If the clock discipline has stabilized, sort the samples in
- * both lists by distance. Note, we do not displace a higher
- * distance sample by a lower distance one unless lower by at
- * least the precision.
+ /*
+ * If the clock has stabilized, sort the samples by distance.
*/
- if (state == 4) {
+ if (freq_cnt == 0) {
for (i = 1; i < NTP_SHIFT; i++) {
for (j = 0; j < i; j++) {
- if (dst[j] > dst[i] +
- LOGTOD(sys_precision)) {
+ if (dst[j] > dst[i]) {
k = ord[j];
ord[j] = ord[i];
ord[i] = k;
@@ -1696,9 +2310,12 @@ clock_filter(
/*
* Copy the index list to the association structure so ntpq
- * can see it later. Prune the distance list to samples less
- * than max distance, but keep at least two valid samples for
- * jitter calculation.
+ * can see it later. Prune the distance list to leave only
+ * samples less than the maximum dispersion, which disfavors
+ * uncorrelated samples older than the Allan intercept. To
+ * further improve the jitter estimate, of the remainder leave
+ * only samples less than the maximum distance, but keep at
+ * least two samples for jitter calculation.
*/
m = 0;
for (i = 0; i < NTP_SHIFT; i++) {
@@ -1708,14 +2325,12 @@ clock_filter(
continue;
m++;
}
-
+
/*
* Compute the dispersion and jitter. The dispersion is weighted
* exponentially by NTP_FWEIGHT (0.5) so it is normalized close
* to 1.0. The jitter is the RMS differences relative to the
- * lowest delay sample. If no acceptable samples remain in the
- * shift register, quietly tiptoe home leaving only the
- * dispersion.
+ * lowest delay sample.
*/
peer->disp = peer->jitter = 0;
k = ord[0];
@@ -1734,9 +2349,10 @@ clock_filter(
* save the offset, delay and jitter. Note the jitter must not
* be less than the precision.
*/
- if (m == 0)
+ if (m == 0) {
+ clock_select();
return;
-
+ }
etemp = fabs(peer->offset - peer->filter_offset[k]);
peer->offset = peer->filter_offset[k];
peer->delay = peer->filter_delay[k];
@@ -1745,47 +2361,51 @@ clock_filter(
peer->jitter = max(SQRT(peer->jitter), LOGTOD(sys_precision));
/*
- * A new sample is useful only if it is younger than the last
- * one used. Note the order is FIFO if the clock discipline has
- * not stabilized.
+ * If the the new sample and the current sample are both valid
+ * and the difference between their offsets exceeds CLOCK_SGATE
+ * (3) times the jitter and the interval between them is less
+ * than twice the host poll interval, consider the new sample
+ * a popcorn spike and ignore it.
*/
- if (peer->filter_epoch[k] <= peer->epoch) {
-#ifdef DEBUG
- if (debug)
- printf("clock_filter: discard %lu\n",
- peer->epoch - peer->filter_epoch[k]);
-#endif
+ if (peer->disp < sys_maxdist && peer->filter_disp[k] <
+ sys_maxdist && etemp > CLOCK_SGATE * peer->jitter &&
+ peer->filter_epoch[k] - peer->epoch < 2. *
+ ULOGTOD(peer->hpoll)) {
+ snprintf(tbuf, sizeof(tbuf), "%.6f s", etemp);
+ report_event(PEVNT_POPCORN, peer, tbuf);
return;
}
/*
- * If the difference between the last offset and the current one
- * exceeds the jitter by CLOCK_SGATE and the interval since the
- * last update is less than twice the system poll interval,
- * consider the update a popcorn spike and ignore it.
+ * A new minimum sample is useful only if it is later than the
+ * last one used. In this design the maximum lifetime of any
+ * sample is not greater than eight times the poll interval, so
+ * the maximum interval between minimum samples is eight
+ * packets.
*/
- if (etemp > CLOCK_SGATE * peer->jitter && m > 1 &&
- peer->filter_epoch[k] - peer->epoch < 2. *
- ULOGTOD(sys_poll)) {
-#ifdef DEBUG
- if (debug)
- printf("clock_filter: popcorn %.6f %.6f\n",
- etemp, dtemp);
+ if (peer->filter_epoch[k] <= peer->epoch) {
+#if DEBUG
+ if (debug > 1)
+ printf("clock_filter: old sample %lu\n", current_time -
+ peer->filter_epoch[k]);
#endif
return;
}
+ peer->epoch = peer->filter_epoch[k];
/*
* The mitigated sample statistics are saved for later
- * processing. If not in a burst, tickle the select.
+ * processing. If not synchronized or not in a burst, tickle the
+ * clock select algorithm.
*/
- peer->epoch = peer->filter_epoch[k];
+ record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
+ peer->offset, peer->delay, peer->disp, peer->jitter);
#ifdef DEBUG
if (debug)
printf(
- "clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f, age %lu\n",
+ "clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f\n",
m, peer->offset, peer->delay, peer->disp,
- peer->jitter, current_time - peer->epoch);
+ peer->jitter);
#endif
if (peer->burst == 0 || sys_leap == LEAP_NOTINSYNC)
clock_select();
@@ -1795,69 +2415,68 @@ clock_filter(
/*
* clock_select - find the pick-of-the-litter clock
*
- * LOCKCLOCK: If the local clock is the prefer peer, it will always be
- * enabled, even if declared falseticker, (2) only the prefer peer can
- * be selected as the system peer, (3) if the external source is down,
- * the system leap bits are set to 11 and the stratum set to infinity.
+ * LOCKCLOCK: (1) If the local clock is the prefer peer, it will always
+ * be enabled, even if declared falseticker, (2) only the prefer peer
+ * can be selected as the system peer, (3) if the external source is
+ * down, the system leap bits are set to 11 and the stratum set to
+ * infinity.
*/
void
clock_select(void)
{
struct peer *peer;
int i, j, k, n;
- int nlist, nl3;
-
- int allow, osurv;
+ int nlist, nl2;
+ int allow;
+ int speer;
double d, e, f, g;
double high, low;
- double synch[NTP_MAXASSOC], error[NTP_MAXASSOC];
+ double speermet;
+ double orphmet = 2.0 * U_INT32_MAX; /* 2x is greater than */
+ struct endpoint endp;
struct peer *osys_peer;
+ struct peer *sys_prefer = NULL; /* prefer peer */
+ struct peer *typesystem = NULL;
+ struct peer *typeorphan = NULL;
+#ifdef REFCLOCK
struct peer *typeacts = NULL;
struct peer *typelocal = NULL;
- struct peer *typesystem = NULL;
-
- static int list_alloc = 0;
+ struct peer *typepps = NULL;
+#endif /* REFCLOCK */
static struct endpoint *endpoint = NULL;
static int *indx = NULL;
- static struct peer **peer_list = NULL;
+ static peer_select *peers = NULL;
static u_int endpoint_size = 0;
+ static u_int peers_size = 0;
static u_int indx_size = 0;
- static u_int peer_list_size = 0;
+ size_t octets;
/*
* Initialize and create endpoint, index and peer lists big
* enough to handle all associations.
*/
osys_peer = sys_peer;
- sys_peer = NULL;
- sys_pps = NULL;
- sys_prefer = NULL;
- osurv = sys_survivors;
sys_survivors = 0;
#ifdef LOCKCLOCK
- sys_leap = LEAP_NOTINSYNC;
+ set_sys_leap(LEAP_NOTINSYNC);
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "DOWN", 4);
#endif /* LOCKCLOCK */
- nlist = 0;
- for (n = 0; n < NTP_HASH_SIZE; n++)
- nlist += peer_hash_count[n];
- if (nlist > list_alloc) {
- if (list_alloc > 0) {
- free(endpoint);
- free(indx);
- free(peer_list);
- }
- while (list_alloc < nlist) {
- list_alloc += 5;
- endpoint_size += 5 * 3 * sizeof(*endpoint);
- indx_size += 5 * 3 * sizeof(*indx);
- peer_list_size += 5 * sizeof(*peer_list);
- }
- endpoint = (struct endpoint *)emalloc(endpoint_size);
- indx = (int *)emalloc(indx_size);
- peer_list = (struct peer **)emalloc(peer_list_size);
- }
+
+ /*
+ * Allocate dynamic space depending on the number of
+ * associations.
+ */
+ nlist = 1;
+ for (peer = peer_list; peer != NULL; peer = peer->p_link)
+ nlist++;
+ endpoint_size = ALIGNED_SIZE(nlist * 2 * sizeof(*endpoint));
+ peers_size = ALIGNED_SIZE(nlist * sizeof(*peers));
+ indx_size = ALIGNED_SIZE(nlist * 2 * sizeof(*indx));
+ octets = endpoint_size + peers_size + indx_size;
+ endpoint = erealloc(endpoint, octets);
+ peers = INC_ALIGNED_PTR(endpoint, endpoint_size);
+ indx = INC_ALIGNED_PTR(peers, peers_size);
/*
* Initially, we populate the island with all the rifraff peers
@@ -1869,103 +2488,130 @@ clock_select(void)
* has dwindled to sys_minclock, the survivors split a million
* bucks and collectively crank the chimes.
*/
- nlist = nl3 = 0; /* none yet */
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != NULL; peer =
- peer->next) {
- peer->flags &= ~FLAG_SYSPEER;
- peer->status = CTL_PST_SEL_REJECT;
-
- /*
- * Leave the island immediately if the peer is
- * unfit to synchronize.
- */
- if (peer_unfit(peer))
- continue;
-
- /*
- * Don't allow the local clock or modem drivers
- * in the kitchen at this point, unless the
- * prefer peer. Do that later, but only if
- * nobody else is around. These guys are all
- * configured, so we never throw them away.
- */
-#ifdef REFCLOCK
- if (peer->refclktype == REFCLK_LOCALCLOCK
-#if defined(VMS) && defined(VMS_LOCALUNIT)
- /* wjm: VMS_LOCALUNIT taken seriously */
- && REFCLOCKUNIT(&peer->srcadr) !=
- VMS_LOCALUNIT
-#endif /* VMS && VMS_LOCALUNIT */
- ) {
- typelocal = peer;
-#ifndef LOCKCLOCK
- if (!(peer->flags & FLAG_PREFER))
- continue; /* no local clock */
-#endif /* LOCKCLOCK */
- }
- if (peer->sstclktype == CTL_SST_TS_TELEPHONE) {
- typeacts = peer;
- if (!(peer->flags & FLAG_PREFER))
- continue; /* no acts */
- }
-#endif /* REFCLOCK */
+ nlist = nl2 = 0; /* none yet */
+ for (peer = peer_list; peer != NULL; peer = peer->p_link) {
+ peer->new_status = CTL_PST_SEL_REJECT;
- /*
- * If we get this far, the peer can stay on the
- * island, but does not yet have the immunity
- * idol.
- */
- peer->status = CTL_PST_SEL_SANE;
- peer_list[nlist++] = peer;
+ /*
+ * Leave the island immediately if the peer is
+ * unfit to synchronize.
+ */
+ if (peer_unfit(peer))
+ continue;
- /*
- * Insert each interval endpoint on the sorted
- * list.
- */
- e = peer->offset; /* Upper end */
- f = root_distance(peer);
- e = e + f;
- for (i = nl3 - 1; i >= 0; i--) {
- if (e >= endpoint[indx[i]].val)
- break;
+ /*
+ * If this peer is an orphan parent, elect the
+ * one with the lowest metric defined as the
+ * IPv4 address or the first 64 bits of the
+ * hashed IPv6 address. To ensure convergence
+ * on the same selected orphan, consider as
+ * well that this system may have the lowest
+ * metric and be the orphan parent. If this
+ * system wins, sys_peer will be NULL to trigger
+ * orphan mode in timer().
+ */
+ if (peer->stratum == sys_orphan) {
+ u_int32 localmet;
+ u_int32 peermet;
- indx[i + 3] = indx[i];
+ if (peer->dstadr != NULL)
+ localmet = ntohl(peer->dstadr->addr_refid);
+ else
+ localmet = U_INT32_MAX;
+ peermet = ntohl(addr2refid(&peer->srcadr));
+ if (peermet < localmet && peermet < orphmet) {
+ typeorphan = peer;
+ orphmet = peermet;
}
- indx[i + 3] = nl3;
- endpoint[nl3].type = 1;
- endpoint[nl3++].val = e;
+ continue;
+ }
- e = e - f; /* Center point */
- for (; i >= 0; i--) {
- if (e >= endpoint[indx[i]].val)
- break;
+ /*
+ * If this peer could have the orphan parent
+ * as a synchronization ancestor, exclude it
+ * from selection to avoid forming a
+ * synchronization loop within the orphan mesh,
+ * triggering stratum climb to infinity
+ * instability. Peers at stratum higher than
+ * the orphan stratum could have the orphan
+ * parent in ancestry so are excluded.
+ * See http://bugs.ntp.org/2050
+ */
+ if (peer->stratum > sys_orphan)
+ continue;
+#ifdef REFCLOCK
+ /*
+ * The following are special cases. We deal
+ * with them later.
+ */
+ if (!(peer->flags & FLAG_PREFER)) {
+ switch (peer->refclktype) {
+ case REFCLK_LOCALCLOCK:
+ if (current_time > orphwait &&
+ typelocal == NULL)
+ typelocal = peer;
+ continue;
- indx[i + 2] = indx[i];
+ case REFCLK_ACTS:
+ if (current_time > orphwait &&
+ typeacts == NULL)
+ typeacts = peer;
+ continue;
}
- indx[i + 2] = nl3;
- endpoint[nl3].type = 0;
- endpoint[nl3++].val = e;
+ }
+#endif /* REFCLOCK */
- e = e - f; /* Lower end */
- for (; i >= 0; i--) {
- if (e >= endpoint[indx[i]].val)
- break;
+ /*
+ * If we get this far, the peer can stay on the
+ * island, but does not yet have the immunity
+ * idol.
+ */
+ peer->new_status = CTL_PST_SEL_SANE;
+ f = root_distance(peer);
+ peers[nlist].peer = peer;
+ peers[nlist].error = peer->jitter;
+ peers[nlist].synch = f;
+ nlist++;
- indx[i + 1] = indx[i];
+ /*
+ * Insert each interval endpoint on the unsorted
+ * endpoint[] list.
+ */
+ e = peer->offset;
+ endpoint[nl2].type = -1; /* lower end */
+ endpoint[nl2].val = e - f;
+ nl2++;
+ endpoint[nl2].type = 1; /* upper end */
+ endpoint[nl2].val = e + f;
+ nl2++;
+ }
+ /*
+ * Construct sorted indx[] of endpoint[] indexes ordered by
+ * offset.
+ */
+ for (i = 0; i < nl2; i++)
+ indx[i] = i;
+ for (i = 0; i < nl2; i++) {
+ endp = endpoint[indx[i]];
+ e = endp.val;
+ k = i;
+ for (j = i + 1; j < nl2; j++) {
+ endp = endpoint[indx[j]];
+ if (endp.val < e) {
+ e = endp.val;
+ k = j;
}
- indx[i + 1] = nl3;
- endpoint[nl3].type = -1;
- endpoint[nl3++].val = e;
+ }
+ if (k != i) {
+ j = indx[k];
+ indx[k] = indx[i];
+ indx[i] = j;
}
}
-#ifdef DEBUG
- if (debug > 2)
- for (i = 0; i < nl3; i++)
- printf("select: endpoint %2d %.6f\n",
- endpoint[indx[i]].type,
- endpoint[indx[i]].val);
-#endif
+ for (i = 0; i < nl2; i++)
+ DPRINTF(3, ("select: endpoint %2d %.6f\n",
+ endpoint[indx[i]].type, endpoint[indx[i]].val));
+
/*
* This is the actual algorithm that cleaves the truechimers
* from the falsetickers. The original algorithm was described
@@ -1985,49 +2631,33 @@ clock_select(void)
*
* Here, nlist is the number of candidates and allow is the
* number of falsetickers. Upon exit, the truechimers are the
- * susvivors with offsets not less than low and not greater than
+ * survivors with offsets not less than low and not greater than
* high. There may be none of them.
*/
low = 1e9;
high = -1e9;
for (allow = 0; 2 * allow < nlist; allow++) {
- int found;
/*
- * Bound the interval (low, high) as the largest
- * interval containing points from presumed truechimers.
+ * Bound the interval (low, high) as the smallest
+ * interval containing points from the most sources.
*/
- found = 0;
n = 0;
- for (i = 0; i < nl3; i++) {
+ for (i = 0; i < nl2; i++) {
low = endpoint[indx[i]].val;
n -= endpoint[indx[i]].type;
if (n >= nlist - allow)
break;
- if (endpoint[indx[i]].type == 0)
- found++;
}
n = 0;
- for (j = nl3 - 1; j >= 0; j--) {
+ for (j = nl2 - 1; j >= 0; j--) {
high = endpoint[indx[j]].val;
n += endpoint[indx[j]].type;
if (n >= nlist - allow)
break;
- if (endpoint[indx[j]].type == 0)
- found++;
}
/*
- * If the number of candidates found outside the
- * interval is greater than the number of falsetickers,
- * then at least one truechimer is outside the interval,
- * so go around again. This is what makes this algorithm
- * different than Marzullo's.
- */
- if (found > allow)
- continue;
-
- /*
* If an interval containing truechimers is found, stop.
* If not, increase the number of falsetickers and go
* around again.
@@ -2037,302 +2667,291 @@ clock_select(void)
}
/*
- * Clustering algorithm. Construct candidate list in order first
- * by stratum then by root distance, but keep only the best
- * NTP_MAXASSOC of them. Scan the list to find falsetickers, who
- * leave the island immediately. The TRUE peer is always a
+ * Clustering algorithm. Whittle candidate list of falsetickers,
+ * who leave the island immediately. The TRUE peer is always a
* truechimer. We must leave at least one peer to collect the
- * million bucks. If in orphan mode, rascals found with lower
- * stratum are guaranteed a seat on the bus.
+ * million bucks.
+ *
+ * We assert the correct time is contained in the interval, but
+ * the best offset estimate for the interval might not be
+ * contained in the interval. For this purpose, a truechimer is
+ * defined as the midpoint of an interval that overlaps the
+ * intersection interval.
*/
j = 0;
for (i = 0; i < nlist; i++) {
- peer = peer_list[i];
- if (nlist > 1 && (peer->offset <= low || peer->offset >=
- high) && !(peer->flags & FLAG_TRUE) &&
- !(sys_stratum >= sys_orphan && peer->stratum <
- sys_orphan))
- continue;
+ double h;
- peer->status = CTL_PST_SEL_DISTSYSPEER;
+ peer = peers[i].peer;
+ h = peers[i].synch;
+ if ((high <= low || peer->offset + h < low ||
+ peer->offset - h > high) && !(peer->flags & FLAG_TRUE))
+ continue;
+#ifdef REFCLOCK
/*
- * The order metric is formed from the stratum times
- * max distance (1.) plus the root distance. It strongly
- * favors the lowest stratum, but a higher stratum peer
- * can capture the clock if the low stratum dominant
- * hasn't been heard for awhile.
+ * Eligible PPS peers must survive the intersection
+ * algorithm. Use the first one found, but don't
+ * include any of them in the cluster population.
*/
- d = root_distance(peer) + peer->stratum * sys_maxdist;
- if (j >= NTP_MAXASSOC) {
- if (d >= synch[j - 1])
+ if (peer->flags & FLAG_PPS) {
+ if (typepps == NULL)
+ typepps = peer;
+ if (!(peer->flags & FLAG_TSTAMP_PPS))
continue;
- else
- j--;
}
- for (k = j; k > 0; k--) {
- if (d >= synch[k - 1])
- break;
+#endif /* REFCLOCK */
- peer_list[k] = peer_list[k - 1];
- error[k] = error[k - 1];
- synch[k] = synch[k - 1];
- }
- peer_list[k] = peer;
- error[k] = peer->jitter;
- synch[k] = d;
+ if (j != i)
+ peers[j] = peers[i];
j++;
}
nlist = j;
/*
- * If no survivors remain at this point, check if the local
- * clock or modem drivers have been found. If so, nominate one
- * of them as the only survivor. Otherwise, give up and leave
- * the island to the rats.
+ * If no survivors remain at this point, check if the modem
+ * driver, local driver or orphan parent in that order. If so,
+ * nominate the first one found as the only survivor.
+ * Otherwise, give up and leave the island to the rats.
*/
if (nlist == 0) {
- if (typeacts != 0) {
- typeacts->status = CTL_PST_SEL_DISTSYSPEER;
- peer_list[0] = typeacts;
+ peers[0].error = 0;
+ peers[0].synch = sys_mindisp;
+#ifdef REFCLOCK
+ if (typeacts != NULL) {
+ peers[0].peer = typeacts;
nlist = 1;
- } else if (typelocal != 0) {
- typelocal->status = CTL_PST_SEL_DISTSYSPEER;
- peer_list[0] = typelocal;
+ } else if (typelocal != NULL) {
+ peers[0].peer = typelocal;
+ nlist = 1;
+ } else
+#endif /* REFCLOCK */
+ if (typeorphan != NULL) {
+ peers[0].peer = typeorphan;
nlist = 1;
- } else {
- if (osys_peer != NULL) {
- NLOG(NLOG_SYNCSTATUS)
- msyslog(LOG_INFO,
- "no servers reachable");
- report_event(EVNT_PEERSTCHG, NULL);
- }
}
}
/*
- * We can only trust the survivors if the number of candidates
- * sys_minsane is at least the number required to detect and
- * cast out one falsticker. For the Byzantine agreement
- * algorithm used here, that number is 4; however, the default
- * sys_minsane is 1 to speed initial synchronization. Careful
- * operators will tinker a higher value and use at least that
- * number of synchronization sources.
+ * Mark the candidates at this point as truechimers.
*/
- if (nlist < sys_minsane)
- return;
-
- for (i = 0; i < nlist; i++)
- peer_list[i]->status = CTL_PST_SEL_SELCAND;
+ for (i = 0; i < nlist; i++) {
+ peers[i].peer->new_status = CTL_PST_SEL_SELCAND;
+ DPRINTF(2, ("select: survivor %s %f\n",
+ stoa(&peers[i].peer->srcadr), peers[i].synch));
+ }
/*
* Now, vote outlyers off the island by select jitter weighted
* by root distance. Continue voting as long as there are more
- * than sys_minclock survivors and the minimum select jitter is
- * greater than the maximum peer jitter. Stop if we are about to
- * discard a TRUE or PREFER peer, who of course has the
- * immunity idol.
+ * than sys_minclock survivors and the select jitter of the peer
+ * with the worst metric is greater than the minimum peer
+ * jitter. Stop if we are about to discard a TRUE or PREFER
+ * peer, who of course have the immunity idol.
*/
while (1) {
d = 1e9;
e = -1e9;
- f = g = 0;
+ g = 0;
k = 0;
for (i = 0; i < nlist; i++) {
- if (error[i] < d)
- d = error[i];
- f = 0;
+ if (peers[i].error < d)
+ d = peers[i].error;
+ peers[i].seljit = 0;
if (nlist > 1) {
+ f = 0;
for (j = 0; j < nlist; j++)
- f += DIFF(peer_list[j]->offset,
- peer_list[i]->offset);
- f = SQRT(f / (nlist - 1));
+ f += DIFF(peers[j].peer->offset,
+ peers[i].peer->offset);
+ peers[i].seljit = SQRT(f / (nlist - 1));
}
- if (f * synch[i] > e) {
- g = f;
- e = f * synch[i];
+ if (peers[i].seljit * peers[i].synch > e) {
+ g = peers[i].seljit;
+ e = peers[i].seljit * peers[i].synch;
k = i;
}
}
- f = max(f, LOGTOD(sys_precision));
- if (nlist <= sys_minclock || f <= d ||
- peer_list[k]->flags & (FLAG_TRUE | FLAG_PREFER))
+ g = max(g, LOGTOD(sys_precision));
+ if (nlist <= max(1, sys_minclock) || g <= d ||
+ ((FLAG_TRUE | FLAG_PREFER) & peers[k].peer->flags))
break;
-#ifdef DEBUG
- if (debug > 2)
- printf(
- "select: drop %s select %.6f jitter %.6f\n",
- ntoa(&peer_list[k]->srcadr), g, d);
-#endif
- for (j = k + 1; j < nlist; j++) {
- peer_list[j - 1] = peer_list[j];
- error[j - 1] = error[j];
- }
+
+ DPRINTF(3, ("select: drop %s seljit %.6f jit %.6f\n",
+ ntoa(&peers[k].peer->srcadr), g, d));
+ if (nlist > sys_maxclock)
+ peers[k].peer->new_status = CTL_PST_SEL_EXCESS;
+ for (j = k + 1; j < nlist; j++)
+ peers[j - 1] = peers[j];
nlist--;
}
/*
* What remains is a list usually not greater than sys_minclock
- * peers. We want only a peer at the lowest stratum to become
- * the system peer, although all survivors are eligible for the
- * combining algorithm. Consider each peer in turn and OR the
- * leap bits on the assumption that, if some of them honk
- * nonzero bits, they must know what they are doing. Check for
- * prefer and pps peers at any stratum. Note that the head of
- * the list is at the lowest stratum and that unsynchronized
- * peers cannot survive this far.
- */
- leap_next = 0;
+ * peers. Note that unsynchronized peers cannot survive this
+ * far. Count and mark these survivors.
+ *
+ * While at it, count the number of leap warning bits found.
+ * This will be used later to vote the system leap warning bit.
+ * If a leap warning bit is found on a reference clock, the vote
+ * is always won.
+ *
+ * Choose the system peer using a hybrid metric composed of the
+ * selection jitter scaled by the root distance augmented by
+ * stratum scaled by sys_mindisp (.001 by default). The goal of
+ * the small stratum factor is to avoid clockhop between a
+ * reference clock and a network peer which has a refclock and
+ * is using an older ntpd, which does not floor sys_rootdisp at
+ * sys_mindisp.
+ *
+ * In contrast, ntpd 4.2.6 and earlier used stratum primarily
+ * in selecting the system peer, using a weight of 1 second of
+ * additional root distance per stratum. This heavy bias is no
+ * longer appropriate, as the scaled root distance provides a
+ * more rational metric carrying the cumulative error budget.
+ */
+ e = 1e9;
+ speer = 0;
+ leap_vote_ins = 0;
+ leap_vote_del = 0;
for (i = 0; i < nlist; i++) {
- peer = peer_list[i];
+ peer = peers[i].peer;
+ peer->unreach = 0;
+ peer->new_status = CTL_PST_SEL_SYNCCAND;
sys_survivors++;
- leap_next |= peer->leap;
- peer->status = CTL_PST_SEL_SYNCCAND;
+ if (peer->leap == LEAP_ADDSECOND) {
+ if (peer->flags & FLAG_REFCLOCK)
+ leap_vote_ins = nlist;
+ else if (leap_vote_ins < nlist)
+ leap_vote_ins++;
+ }
+ if (peer->leap == LEAP_DELSECOND) {
+ if (peer->flags & FLAG_REFCLOCK)
+ leap_vote_del = nlist;
+ else if (leap_vote_del < nlist)
+ leap_vote_del++;
+ }
if (peer->flags & FLAG_PREFER)
sys_prefer = peer;
- if (peer == osys_peer)
- typesystem = peer;
-#ifdef REFCLOCK
- if (peer->refclktype == REFCLK_ATOM_PPS)
- sys_pps = peer;
-#endif /* REFCLOCK */
-#if DEBUG
- if (debug > 1)
- printf("cluster: survivor %s metric %.6f\n",
- ntoa(&peer_list[i]->srcadr), synch[i]);
-#endif
+ speermet = peers[i].seljit * peers[i].synch +
+ peer->stratum * sys_mindisp;
+ if (speermet < e) {
+ e = speermet;
+ speer = i;
+ }
}
/*
- * Anticlockhop provision. Keep the current system peer if it is
- * a survivor but not first in the list. But do that only HOPPER
- * times.
+ * Unless there are at least sys_misane survivors, leave the
+ * building dark. Otherwise, do a clockhop dance. Ordinarily,
+ * use the selected survivor speer. However, if the current
+ * system peer is not speer, stay with the current system peer
+ * as long as it doesn't get too old or too ugly.
*/
- if (osys_peer == NULL || typesystem == NULL || typesystem ==
- peer_list[0] || sys_hopper > sys_maxhop) {
- typesystem = peer_list[0];
- sys_hopper = 0;
- } else {
- peer->selbroken++;
+ if (nlist > 0 && nlist >= sys_minsane) {
+ double x;
+
+ typesystem = peers[speer].peer;
+ if (osys_peer == NULL || osys_peer == typesystem) {
+ sys_clockhop = 0;
+ } else if ((x = fabs(typesystem->offset -
+ osys_peer->offset)) < sys_mindisp) {
+ if (sys_clockhop == 0)
+ sys_clockhop = sys_mindisp;
+ else
+ sys_clockhop *= .5;
+ DPRINTF(1, ("select: clockhop %d %.6f %.6f\n",
+ j, x, sys_clockhop));
+ if (fabs(x) < sys_clockhop)
+ typesystem = osys_peer;
+ else
+ sys_clockhop = 0;
+ } else {
+ sys_clockhop = 0;
+ }
}
/*
- * Mitigation rules of the game. There are several types of
- * peers that can be selected here: (1) orphan, (2) prefer peer
- * (flag FLAG_PREFER) (3) pps peers (type REFCLK_ATOM_PPS), (4)
- * the existing system peer, if any, and (5) the head of the
- * survivor list.
+ * Mitigation rules of the game. We have the pick of the
+ * litter in typesystem if any survivors are left. If
+ * there is a prefer peer, use its offset and jitter.
+ * Otherwise, use the combined offset and jitter of all kitters.
*/
- if (typesystem->stratum >= sys_orphan) {
-
- /*
- * If in orphan mode, choose the system peer. If the
- * lowest distance, we are the orphan parent and the
- * offset is zero.
- */
- sys_peer = typesystem;
- sys_peer->status = CTL_PST_SEL_SYSPEER;
- if (sys_orphandelay < sys_peer->rootdelay) {
- sys_offset = 0;
- sys_refid = htonl(LOOPBACKADR);
+ if (typesystem != NULL) {
+ if (sys_prefer == NULL) {
+ typesystem->new_status = CTL_PST_SEL_SYSPEER;
+ clock_combine(peers, sys_survivors, speer);
} else {
- sys_offset = sys_peer->offset;
- sys_refid = addr2refid(&sys_peer->srcadr);
+ typesystem = sys_prefer;
+ sys_clockhop = 0;
+ typesystem->new_status = CTL_PST_SEL_SYSPEER;
+ sys_offset = typesystem->offset;
+ sys_jitter = typesystem->jitter;
}
- sys_jitter = LOGTOD(sys_precision);
-#ifdef DEBUG
- if (debug > 1)
- printf("select: orphan offset %.6f\n",
- sys_offset);
-#endif
- } else if (sys_prefer) {
+ DPRINTF(1, ("select: combine offset %.9f jitter %.9f\n",
+ sys_offset, sys_jitter));
+ }
+#ifdef REFCLOCK
+ /*
+ * If a PPS driver is lit and the combined offset is less than
+ * 0.4 s, select the driver as the PPS peer and use its offset
+ * and jitter. However, if this is the atom driver, use it only
+ * if there is a prefer peer or there are no survivors and none
+ * are required.
+ */
+ if (typepps != NULL && fabs(sys_offset) < 0.4 &&
+ (typepps->refclktype != REFCLK_ATOM_PPS ||
+ (typepps->refclktype == REFCLK_ATOM_PPS && (sys_prefer !=
+ NULL || (typesystem == NULL && sys_minsane == 0))))) {
+ typesystem = typepps;
+ sys_clockhop = 0;
+ typesystem->new_status = CTL_PST_SEL_PPS;
+ sys_offset = typesystem->offset;
+ sys_jitter = typesystem->jitter;
+ DPRINTF(1, ("select: pps offset %.9f jitter %.9f\n",
+ sys_offset, sys_jitter));
+ }
+#endif /* REFCLOCK */
- /*
- * If a pps peer is present, choose it; otherwise,
- * choose the prefer peer.
- */
- if (sys_pps) {
- sys_peer = sys_pps;
- sys_peer->status = CTL_PST_SEL_PPS;
- sys_offset = sys_peer->offset;
- if (!pps_control)
- NLOG(NLOG_SYSEVENT)
- msyslog(LOG_INFO,
- "pps sync enabled");
- pps_control = current_time;
-#ifdef DEBUG
- if (debug > 1)
- printf("select: pps offset %.6f\n",
- sys_offset);
-#endif
- } else {
- sys_peer = sys_prefer;
- sys_peer->status = CTL_PST_SEL_SYSPEER;
- sys_offset = sys_peer->offset;
-#ifdef DEBUG
- if (debug > 1)
- printf("select: prefer offset %.6f\n",
- sys_offset);
-#endif
+ /*
+ * If there are no survivors at this point, there is no
+ * system peer. If so and this is an old update, keep the
+ * current statistics, but do not update the clock.
+ */
+ if (typesystem == NULL) {
+ if (osys_peer != NULL) {
+ if (sys_orphwait > 0)
+ orphwait = current_time + sys_orphwait;
+ report_event(EVNT_NOPEER, NULL, NULL);
}
- if (sys_peer->stratum == STRATUM_REFCLOCK ||
- sys_peer->stratum == STRATUM_UNSPEC)
- sys_refid = sys_peer->refid;
- else
- sys_refid = addr2refid(&sys_peer->srcadr);
- sys_jitter = sys_peer->jitter;
- } else {
-
- /*
- * Otherwise, choose the anticlockhopper.
- */
- sys_peer = typesystem;
- sys_peer->status = CTL_PST_SEL_SYSPEER;
- clock_combine(peer_list, nlist);
- if (sys_peer->stratum == STRATUM_REFCLOCK ||
- sys_peer->stratum == STRATUM_UNSPEC)
- sys_refid = sys_peer->refid;
- else
- sys_refid = addr2refid(&sys_peer->srcadr);
- sys_jitter = SQRT(SQUARE(sys_peer->jitter) +
- SQUARE(sys_jitter));
-#ifdef DEBUG
- if (debug > 1)
- printf("select: combine offset %.6f\n",
- sys_offset);
-#endif
+ sys_peer = NULL;
+ for (peer = peer_list; peer != NULL; peer = peer->p_link)
+ peer->status = peer->new_status;
+ return;
}
/*
- * We have found the alpha male.
+ * Do not use old data, as this may mess up the clock discipline
+ * stability.
*/
- sys_peer->flags |= FLAG_SYSPEER;
- if (osys_peer != sys_peer) {
- char *src;
-
- report_event(EVNT_PEERSTCHG, NULL);
+ if (typesystem->epoch <= sys_epoch)
+ return;
-#ifdef REFCLOCK
- if (sys_peer->flags & FLAG_REFCLOCK)
- src = refnumtoa(&sys_peer->srcadr);
- else
-#endif /* REFCLOCK */
- src = ntoa(&sys_peer->srcadr);
- NLOG(NLOG_SYNCSTATUS)
- msyslog(LOG_INFO, "synchronized to %s, stratum %d",
- src, sys_peer->stratum);
- }
- clock_update();
+ /*
+ * We have found the alpha male. Wind the clock.
+ */
+ if (osys_peer != typesystem)
+ report_event(PEVNT_NEWPEER, typesystem, NULL);
+ for (peer = peer_list; peer != NULL; peer = peer->p_link)
+ peer->status = peer->new_status;
+ clock_update(typesystem);
}
-/*
- * clock_combine - compute system offset and jitter from selected peers
- */
static void
clock_combine(
- struct peer **peers, /* survivor list */
- int npeers /* number of survivors */
+ peer_select * peers, /* survivor list */
+ int npeers, /* number of survivors */
+ int syspeer /* index of sys.peer */
)
{
int i;
@@ -2340,41 +2959,64 @@ clock_combine(
y = z = w = 0;
for (i = 0; i < npeers; i++) {
- x = root_distance(peers[i]);
- y += 1. / x;
- z += peers[i]->offset / x;
- w += SQUARE(peers[i]->offset - peers[0]->offset) / x;
+ x = 1. / peers[i].synch;
+ y += x;
+ z += x * peers[i].peer->offset;
+ w += x * DIFF(peers[i].peer->offset,
+ peers[syspeer].peer->offset);
}
sys_offset = z / y;
- sys_jitter = SQRT(w / y);
+ sys_jitter = SQRT(w / y + SQUARE(peers[syspeer].seljit));
}
+
/*
* root_distance - compute synchronization distance from peer to root
*/
static double
root_distance(
- struct peer *peer
+ struct peer *peer /* peer structure pointer */
)
{
- double dist;
+ double dtemp;
/*
+ * Root Distance (LAMBDA) is defined as:
+ * (delta + DELTA)/2 + epsilon + EPSILON + phi
+ *
+ * where:
+ * delta is the round-trip delay
+ * DELTA is the root delay
+ * epsilon is the remote server precision + local precision
+ * + (15 usec each second)
+ * EPSILON is the root dispersion
+ * phi is the peer jitter statistic
+ *
+ * NB: Think hard about why we are using these values, and what
+ * the alternatives are, and the various pros/cons.
+ *
+ * DLM thinks these are probably the best choices from any of the
+ * other worse choices.
+ */
+ dtemp = (peer->delay + peer->rootdelay) / 2
+ + LOGTOD(peer->precision)
+ + LOGTOD(sys_precision)
+ + clock_phi * (current_time - peer->update)
+ + peer->rootdisp
+ + peer->jitter;
+ /*
* Careful squeak here. The value returned must be greater than
* the minimum root dispersion in order to avoid clockhop with
- * highly precise reference clocks. In orphan mode lose the peer
- * root delay, as that is used by the election algorithm.
+ * highly precise reference clocks. Note that the root distance
+ * cannot exceed the sys_maxdist, as this is the cutoff by the
+ * selection algorithm.
*/
- if (peer->stratum >= sys_orphan)
- dist = 0;
- else
- dist = peer->rootdelay;
- dist += max(sys_mindisp, dist + peer->delay) / 2 +
- peer->rootdispersion + peer->disp + clock_phi *
- (current_time - peer->update) + peer->jitter;
- return (dist);
+ if (dtemp < sys_mindisp)
+ dtemp = sys_mindisp;
+ return (dtemp);
}
+
/*
* peer_xmit - send packet for persistent association.
*/
@@ -2384,66 +3026,24 @@ peer_xmit(
)
{
struct pkt xpkt; /* transmit packet */
- int sendlen, authlen;
+ size_t sendlen, authlen;
keyid_t xkeyid = 0; /* transmit key ID */
- l_fp xmt_tx;
+ l_fp xmt_tx, xmt_ty;
- if (!peer->dstadr) /* don't bother with peers without interface */
+ if (!peer->dstadr) /* drop peers without interface */
return;
- /*
- * This is deliciously complicated. There are three cases.
- *
- * case leap stratum refid delay dispersion
- *
- * normal system system system system system
- * orphan child 00 orphan system orphan system
- * orphan parent 00 orphan loopbk 0 0
- */
- /*
- * This is a normal packet. Use the system variables.
- */
- if (sys_stratum < sys_orphan) {
- xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap,
- peer->version, peer->hmode);
- xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
- xpkt.refid = sys_refid;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
- xpkt.rootdispersion =
- HTONS_FP(DTOUFP(sys_rootdispersion));
-
- /*
- * This is a orphan child packet. The host is synchronized to an
- * orphan parent. Show leap synchronized, orphan stratum, system
- * reference ID, orphan root delay and system root dispersion.
- */
- } else if (sys_peer != NULL) {
- xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING,
- peer->version, peer->hmode);
- xpkt.stratum = STRATUM_TO_PKT(sys_orphan);
- xpkt.refid = htonl(LOOPBACKADR);
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay));
- xpkt.rootdispersion =
- HTONS_FP(DTOUFP(sys_rootdispersion));
-
- /*
- * This is an orphan parent. Show leap synchronized, orphan
- * stratum, loopack reference ID and zero root delay and root
- * dispersion.
- */
- } else {
- xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING,
- peer->version, peer->hmode);
- xpkt.stratum = STRATUM_TO_PKT(sys_orphan);
- xpkt.refid = sys_refid;
- xpkt.rootdelay = 0;
- xpkt.rootdispersion = 0;
- }
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, peer->version,
+ peer->hmode);
+ xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
xpkt.ppoll = peer->hpoll;
xpkt.precision = sys_precision;
+ xpkt.refid = sys_refid;
+ xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
HTONL_FP(&sys_reftime, &xpkt.reftime);
- HTONL_FP(&peer->org, &xpkt.org);
- HTONL_FP(&peer->rec, &xpkt.rec);
+ HTONL_FP(&peer->rec, &xpkt.org);
+ HTONL_FP(&peer->dst, &xpkt.rec);
/*
* If the received packet contains a MAC, the transmitted packet
@@ -2458,28 +3058,73 @@ peer_xmit(
* might not be usable.
*/
sendlen = LEN_PKT_NOMAC;
- if (!(peer->flags & FLAG_AUTHENABLE)) {
- get_systime(&peer->xmt);
- HTONL_FP(&peer->xmt, &xpkt.xmt);
+#ifdef AUTOKEY
+ if (!(peer->flags & FLAG_SKEY) && peer->keyid == 0) {
+#else /* !AUTOKEY follows */
+ if (peer->keyid == 0) {
+#endif /* !AUTOKEY */
+
+ /*
+ * Transmit a-priori timestamps
+ */
+ get_systime(&xmt_tx);
+ if (peer->flip == 0) { /* basic mode */
+ peer->aorg = xmt_tx;
+ HTONL_FP(&xmt_tx, &xpkt.xmt);
+ } else { /* interleaved modes */
+ if (peer->hmode == MODE_BROADCAST) { /* bcst */
+ HTONL_FP(&xmt_tx, &xpkt.xmt);
+ if (peer->flip > 0)
+ HTONL_FP(&peer->borg,
+ &xpkt.org);
+ else
+ HTONL_FP(&peer->aorg,
+ &xpkt.org);
+ } else { /* symmetric */
+ if (peer->flip > 0)
+ HTONL_FP(&peer->borg,
+ &xpkt.xmt);
+ else
+ HTONL_FP(&peer->aorg,
+ &xpkt.xmt);
+ }
+ }
+ peer->t21_bytes = sendlen;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl],
- &xpkt, sendlen);
+ &xpkt, sendlen);
peer->sent++;
+ peer->throttle += (1 << peer->minpoll) - 2;
+
+ /*
+ * Capture a-posteriori timestamps
+ */
+ get_systime(&xmt_ty);
+ if (peer->flip != 0) { /* interleaved modes */
+ if (peer->flip > 0)
+ peer->aorg = xmt_ty;
+ else
+ peer->borg = xmt_ty;
+ peer->flip = -peer->flip;
+ }
+ L_SUB(&xmt_ty, &xmt_tx);
+ LFPTOD(&xmt_ty, peer->xleave);
#ifdef DEBUG
if (debug)
- printf("transmit: at %ld %s->%s mode %d\n",
- current_time, peer->dstadr ? stoa(&peer->dstadr->sin) : "-",
- stoa(&peer->srcadr), peer->hmode);
+ printf("transmit: at %ld %s->%s mode %d len %zu\n",
+ current_time, peer->dstadr ?
+ stoa(&peer->dstadr->sin) : "-",
+ stoa(&peer->srcadr), peer->hmode, sendlen);
#endif
return;
}
/*
- * The received packet contains a MAC, so the transmitted packet
- * must be authenticated. If autokey is enabled, fuss with the
- * various modes; otherwise, symmetric key cryptography is used.
+ * Authentication is enabled, so the transmitted packet must be
+ * authenticated. If autokey is enabled, fuss with the various
+ * modes; otherwise, symmetric key cryptography is used.
*/
-#ifdef OPENSSL
- if (crypto_flags && (peer->flags & FLAG_SKEY)) {
+#ifdef AUTOKEY
+ if (peer->flags & FLAG_SKEY) {
struct exten *exten; /* extension field */
/*
@@ -2495,7 +3140,7 @@ peer_xmit(
* messages have the same code as the request, but have
* a response bit and possibly an error bit set. In this
* implementation, a message may contain no more than
- * one command and no more than one response.
+ * one command and one or more responses.
*
* Cryptographic session keys include both a public and
* a private componet. Request and response messages
@@ -2505,7 +3150,7 @@ peer_xmit(
* the session key is generated.
*/
while (1) {
-
+
/*
* Allocate and initialize a keylist if not
* already done. Then, use the list in inverse
@@ -2521,10 +3166,10 @@ peer_xmit(
* identifier to verify authenticity.
*
* If for some reason a key is no longer in the
- * key cache, a birthday has happened and the
- * pseudo-random sequence is probably broken. In
- * that case, purge the keylist and regenerate
- * it.
+ * key cache, a birthday has happened or the key
+ * has expired, so the pseudo-random sequence is
+ * broken. In that case, purge the keylist and
+ * regenerate it.
*/
if (peer->keynumber == 0)
make_keylist(peer, peer->dstadr);
@@ -2540,273 +3185,272 @@ peer_xmit(
exten = NULL;
switch (peer->hmode) {
- /*
- * In broadcast server mode the autokey values are
- * required by the broadcast clients. Push them when a
- * new keylist is generated; otherwise, push the
- * association message so the client can request them at
- * other times.
- */
+ /*
+ * In broadcast server mode the autokey values are
+ * required by the broadcast clients. Push them when a
+ * new keylist is generated; otherwise, push the
+ * association message so the client can request them at
+ * other times.
+ */
case MODE_BROADCAST:
if (peer->flags & FLAG_ASSOC)
exten = crypto_args(peer, CRYPTO_AUTO |
- CRYPTO_RESP, NULL);
+ CRYPTO_RESP, peer->associd, NULL);
else
exten = crypto_args(peer, CRYPTO_ASSOC |
- CRYPTO_RESP, NULL);
+ CRYPTO_RESP, peer->associd, NULL);
break;
/*
- * In symmetric modes the digest, certificate, agreement
- * parameters, cookie and autokey values are required.
- * The leapsecond table is optional. But, a passive peer
- * will not believe the active peer until the latter has
- * synchronized, so the agreement must be postponed
- * until then. In any case, if a new keylist is
- * generated, the autokey values are pushed.
- *
- * If the crypto bit is lit, don't send requests.
+ * In symmetric modes the parameter, certificate,
+ * identity, cookie and autokey exchanges are
+ * required. The leapsecond exchange is optional. But, a
+ * peer will not believe the other peer until the other
+ * peer has synchronized, so the certificate exchange
+ * might loop until then. If a peer finds a broken
+ * autokey sequence, it uses the autokey exchange to
+ * retrieve the autokey values. In any case, if a new
+ * keylist is generated, the autokey values are pushed.
*/
case MODE_ACTIVE:
case MODE_PASSIVE:
- if (peer->flash & TEST9)
- break;
+
/*
- * Parameter and certificate.
+ * Parameter, certificate and identity.
*/
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
- sys_hostname);
- else if (!(peer->crypto & CRYPTO_FLAG_VALID))
+ peer->associd, hostval.ptr);
+ else if (!(peer->crypto & CRYPTO_FLAG_CERT))
exten = crypto_args(peer, CRYPTO_CERT,
- peer->issuer);
-
- /*
- * Identity. Note we have to sign the
- * certificate before the cookie to avoid a
- * deadlock when the passive peer is walking the
- * certificate trail. Awesome.
- */
+ peer->associd, peer->issuer);
else if (!(peer->crypto & CRYPTO_FLAG_VRFY))
exten = crypto_args(peer,
- crypto_ident(peer), NULL);
- else if (sys_leap != LEAP_NOTINSYNC &&
- !(peer->crypto & CRYPTO_FLAG_SIGN))
- exten = crypto_args(peer, CRYPTO_SIGN,
- sys_hostname);
+ crypto_ident(peer), peer->associd,
+ NULL);
/*
- * Autokey. We request the cookie only when the
- * server and client are synchronized and
- * signatures work both ways. On the other hand,
- * the active peer needs the autokey values
- * before then and when the passive peer is
- * waiting for the active peer to synchronize.
- * Any time we regenerate the key list, we offer
- * the autokey values without being asked.
+ * Cookie and autokey. We request the cookie
+ * only when the this peer and the other peer
+ * are synchronized. But, this peer needs the
+ * autokey values when the cookie is zero. Any
+ * time we regenerate the key list, we offer the
+ * autokey values without being asked. If for
+ * some reason either peer finds a broken
+ * autokey sequence, the autokey exchange is
+ * used to retrieve the autokey values.
*/
else if (sys_leap != LEAP_NOTINSYNC &&
- peer->leap != LEAP_NOTINSYNC &&
- !(peer->crypto & CRYPTO_FLAG_AGREE))
+ peer->leap != LEAP_NOTINSYNC &&
+ !(peer->crypto & CRYPTO_FLAG_COOK))
exten = crypto_args(peer, CRYPTO_COOK,
- NULL);
- else if (peer->flags & FLAG_ASSOC)
- exten = crypto_args(peer, CRYPTO_AUTO |
- CRYPTO_RESP, NULL);
+ peer->associd, NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO))
exten = crypto_args(peer, CRYPTO_AUTO,
- NULL);
+ peer->associd, NULL);
+ else if (peer->flags & FLAG_ASSOC &&
+ peer->crypto & CRYPTO_FLAG_SIGN)
+ exten = crypto_args(peer, CRYPTO_AUTO |
+ CRYPTO_RESP, peer->assoc, NULL);
/*
- * Postamble. We trade leapseconds only when the
- * server and client are synchronized.
+ * Wait for clock sync, then sign the
+ * certificate and retrieve the leapsecond
+ * values.
*/
- else if (sys_leap != LEAP_NOTINSYNC &&
- peer->leap != LEAP_NOTINSYNC &&
- peer->crypto & CRYPTO_FLAG_TAI &&
- !(peer->crypto & CRYPTO_FLAG_LEAP))
- exten = crypto_args(peer, CRYPTO_TAI,
- NULL);
+ else if (sys_leap == LEAP_NOTINSYNC)
+ break;
+
+ else if (!(peer->crypto & CRYPTO_FLAG_SIGN))
+ exten = crypto_args(peer, CRYPTO_SIGN,
+ peer->associd, hostval.ptr);
+ else if (!(peer->crypto & CRYPTO_FLAG_LEAP))
+ exten = crypto_args(peer, CRYPTO_LEAP,
+ peer->associd, NULL);
break;
/*
- * In client mode the digest, certificate, agreement
- * parameters and cookie are required. The leapsecond
- * table is optional. If broadcast client mode, the
- * autokey values are required as well. In broadcast
- * client mode, these values must be acquired during the
- * client/server exchange to avoid having to wait until
- * the next key list regeneration. Otherwise, the poor
- * dude may die a lingering death until becoming
- * unreachable and attempting rebirth.
- *
- * If neither the server or client have the agreement
- * parameters, the protocol transmits the cookie in the
- * clear. If the server has the parameters, the client
- * requests them and the protocol blinds it using the
- * agreed key. It is a protocol error if the client has
- * the parameters but the server does not.
- *
- * If the crypto bit is lit, don't send requests.
+ * In client mode the parameter, certificate, identity,
+ * cookie and sign exchanges are required. The
+ * leapsecond exchange is optional. If broadcast client
+ * mode the same exchanges are required, except that the
+ * autokey exchange is substitutes for the cookie
+ * exchange, since the cookie is always zero. If the
+ * broadcast client finds a broken autokey sequence, it
+ * uses the autokey exchange to retrieve the autokey
+ * values.
*/
case MODE_CLIENT:
- if (peer->flash & TEST9)
- break;
+
/*
- * Parameter and certificate.
+ * Parameter, certificate and identity.
*/
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
- sys_hostname);
- else if (!(peer->crypto & CRYPTO_FLAG_VALID))
+ peer->associd, hostval.ptr);
+ else if (!(peer->crypto & CRYPTO_FLAG_CERT))
exten = crypto_args(peer, CRYPTO_CERT,
- peer->issuer);
-
- /*
- * Identity
- */
+ peer->associd, peer->issuer);
else if (!(peer->crypto & CRYPTO_FLAG_VRFY))
exten = crypto_args(peer,
- crypto_ident(peer), NULL);
+ crypto_ident(peer), peer->associd,
+ NULL);
/*
- * Autokey
+ * Cookie and autokey. These are requests, but
+ * we use the peer association ID with autokey
+ * rather than our own.
*/
- else if (!(peer->crypto & CRYPTO_FLAG_AGREE))
+ else if (!(peer->crypto & CRYPTO_FLAG_COOK))
exten = crypto_args(peer, CRYPTO_COOK,
- NULL);
- else if (!(peer->crypto & CRYPTO_FLAG_AUTO) &&
- (peer->cast_flags & MDF_BCLNT))
+ peer->associd, NULL);
+ else if (!(peer->crypto & CRYPTO_FLAG_AUTO))
exten = crypto_args(peer, CRYPTO_AUTO,
- NULL);
+ peer->assoc, NULL);
/*
- * Postamble. We can sign the certificate here,
- * since there is no chance of deadlock.
+ * Wait for clock sync, then sign the
+ * certificate and retrieve the leapsecond
+ * values.
*/
- else if (sys_leap != LEAP_NOTINSYNC &&
- !(peer->crypto & CRYPTO_FLAG_SIGN))
+ else if (sys_leap == LEAP_NOTINSYNC)
+ break;
+
+ else if (!(peer->crypto & CRYPTO_FLAG_SIGN))
exten = crypto_args(peer, CRYPTO_SIGN,
- sys_hostname);
- else if (sys_leap != LEAP_NOTINSYNC &&
- peer->crypto & CRYPTO_FLAG_TAI &&
- !(peer->crypto & CRYPTO_FLAG_LEAP))
- exten = crypto_args(peer, CRYPTO_TAI,
- NULL);
+ peer->associd, hostval.ptr);
+ else if (!(peer->crypto & CRYPTO_FLAG_LEAP))
+ exten = crypto_args(peer, CRYPTO_LEAP,
+ peer->associd, NULL);
break;
}
/*
- * Build the extension fields as directed. A response to
- * a request is always sent, even if an error. If an
- * error occurs when sending a request, the crypto
- * machinery broke or was misconfigured. In that case
- * light the crypto bit to suppress further requests.
+ * Add a queued extension field if present. This is
+ * always a request message, so the reply ID is already
+ * in the message. If an error occurs, the error bit is
+ * lit in the response.
*/
if (peer->cmmd != NULL) {
- peer->cmmd->associd = htonl(peer->associd);
- sendlen += crypto_xmit(&xpkt, &peer->srcadr,
- sendlen, peer->cmmd, 0);
+ u_int32 temp32;
+
+ temp32 = CRYPTO_RESP;
+ peer->cmmd->opcode |= htonl(temp32);
+ sendlen += crypto_xmit(peer, &xpkt, NULL,
+ sendlen, peer->cmmd, 0);
free(peer->cmmd);
peer->cmmd = NULL;
}
+
+ /*
+ * Add an extension field created above. All but the
+ * autokey response message are request messages.
+ */
if (exten != NULL) {
- int ltemp = 0;
-
- if (exten->opcode != 0) {
- ltemp = crypto_xmit(&xpkt,
- &peer->srcadr, sendlen, exten, 0);
- if (ltemp == 0) {
- peer->flash |= TEST9; /* crypto error */
- free(exten);
- return;
- }
- }
- sendlen += ltemp;
+ if (exten->opcode != 0)
+ sendlen += crypto_xmit(peer, &xpkt,
+ NULL, sendlen, exten, 0);
free(exten);
}
/*
- * If extension fields are present, we must use a
- * private cookie value of zero. Don't send if the
- * crypto bit is set and no extension field is present,
- * but in that case give back the key. Most intricate.
+ * Calculate the next session key. Since extension
+ * fields are present, the cookie value is zero.
*/
- if (sendlen > LEN_PKT_NOMAC) {
+ if (sendlen > (int)LEN_PKT_NOMAC) {
session_key(&peer->dstadr->sin, &peer->srcadr,
xkeyid, 0, 2);
- } else if (peer->flash & TEST9) {
- authtrust(xkeyid, 0);
- return;
}
- }
-#endif /* OPENSSL */
+ }
+#endif /* AUTOKEY */
/*
- * Stash the transmit timestamp corrected for the encryption
- * delay. If autokey, give back the key, as we use keys only
- * once. Check for errors such as missing keys, buffer overflow,
- * etc.
+ * Transmit a-priori timestamps
*/
+ get_systime(&xmt_tx);
+ if (peer->flip == 0) { /* basic mode */
+ peer->aorg = xmt_tx;
+ HTONL_FP(&xmt_tx, &xpkt.xmt);
+ } else { /* interleaved modes */
+ if (peer->hmode == MODE_BROADCAST) { /* bcst */
+ HTONL_FP(&xmt_tx, &xpkt.xmt);
+ if (peer->flip > 0)
+ HTONL_FP(&peer->borg, &xpkt.org);
+ else
+ HTONL_FP(&peer->aorg, &xpkt.org);
+ } else { /* symmetric */
+ if (peer->flip > 0)
+ HTONL_FP(&peer->borg, &xpkt.xmt);
+ else
+ HTONL_FP(&peer->aorg, &xpkt.xmt);
+ }
+ }
xkeyid = peer->keyid;
- get_systime(&peer->xmt);
- L_ADD(&peer->xmt, &sys_authdelay);
- HTONL_FP(&peer->xmt, &xpkt.xmt);
authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
if (authlen == 0) {
- msyslog(LOG_INFO, "transmit: %s key %u not found",
- stoa(&peer->srcadr), xkeyid);
- peer->flash |= TEST9; /* no key found */
+ report_event(PEVNT_AUTH, peer, "no key");
+ peer->flash |= TEST5; /* auth error */
+ peer->badauth++;
return;
}
sendlen += authlen;
-#ifdef OPENSSL
+#ifdef AUTOKEY
if (xkeyid > NTP_MAXKEY)
authtrust(xkeyid, 0);
-#endif /* OPENSSL */
- get_systime(&xmt_tx);
+#endif /* AUTOKEY */
if (sendlen > sizeof(xpkt)) {
- msyslog(LOG_ERR, "buffer overflow %u", sendlen);
+ msyslog(LOG_ERR, "proto: buffer overflow %zu", sendlen);
exit (-1);
}
+ peer->t21_bytes = sendlen;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt,
- sendlen);
+ sendlen);
+ peer->sent++;
+ peer->throttle += (1 << peer->minpoll) - 2;
/*
- * Calculate the encryption delay. Keep the minimum over
- * the latest two samples.
+ * Capture a-posteriori timestamps
*/
- L_SUB(&xmt_tx, &peer->xmt);
- L_ADD(&xmt_tx, &sys_authdelay);
- sys_authdly[1] = sys_authdly[0];
- sys_authdly[0] = xmt_tx.l_uf;
- if (sys_authdly[0] < sys_authdly[1])
- sys_authdelay.l_uf = sys_authdly[0];
- else
- sys_authdelay.l_uf = sys_authdly[1];
- peer->sent++;
-#ifdef OPENSSL
+ get_systime(&xmt_ty);
+ if (peer->flip != 0) { /* interleaved modes */
+ if (peer->flip > 0)
+ peer->aorg = xmt_ty;
+ else
+ peer->borg = xmt_ty;
+ peer->flip = -peer->flip;
+ }
+ L_SUB(&xmt_ty, &xmt_tx);
+ LFPTOD(&xmt_ty, peer->xleave);
+#ifdef AUTOKEY
#ifdef DEBUG
if (debug)
- printf(
- "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n",
- current_time, peer->dstadr ? ntoa(&peer->dstadr->sin) : "-",
- ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen -
- authlen, authlen, peer->keynumber);
+ printf("transmit: at %ld %s->%s mode %d keyid %08x len %zu index %d\n",
+ current_time, latoa(peer->dstadr),
+ ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen,
+ peer->keynumber);
#endif
-#else
+#else /* !AUTOKEY follows */
#ifdef DEBUG
if (debug)
- printf(
- "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n",
- current_time, peer->dstadr ? ntoa(&peer->dstadr->sin) : "-",
- ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen -
- authlen, authlen);
+ printf("transmit: at %ld %s->%s mode %d keyid %08x len %d\n",
+ current_time, peer->dstadr ?
+ ntoa(&peer->dstadr->sin) : "-",
+ ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen);
#endif
-#endif /* OPENSSL */
+#endif /* !AUTOKEY */
}
+#ifdef LEAP_SMEAR
+
+static void
+leap_smear_add_offs(l_fp *t, l_fp *t_recv) {
+ L_ADD(t, &leap_smear.offset);
+}
+
+#endif /* LEAP_SMEAR */
+
+
/*
* fast_xmit - Send packet for nonpersistent association. Note that
* neither the source or destination can be a broadcast address.
@@ -2814,111 +3458,123 @@ peer_xmit(
static void
fast_xmit(
struct recvbuf *rbufp, /* receive packet pointer */
- int xmode, /* transmit mode */
+ int xmode, /* receive mode */
keyid_t xkeyid, /* transmit key ID */
- int mask /* restrict mask */
+ int flags /* restrict mask */
)
{
- struct pkt xpkt; /* transmit packet structure */
- struct pkt *rpkt; /* receive packet structure */
- l_fp xmt_ts; /* timestamp */
- l_fp xmt_tx; /* timestamp after authent */
- int sendlen, authlen;
-#ifdef OPENSSL
+ struct pkt xpkt; /* transmit packet structure */
+ struct pkt *rpkt; /* receive packet structure */
+ l_fp xmt_tx, xmt_ty;
+ int sendlen;
+#ifdef AUTOKEY
u_int32 temp32;
#endif
/*
* Initialize transmit packet header fields from the receive
- * buffer provided. We leave some fields intact as received. If
- * the gazinta was from a multicast address, the gazoutta must
- * go out another way.
+ * buffer provided. We leave the fields intact as received, but
+ * set the peer poll at the maximum of the receive peer poll and
+ * the system minimum poll (ntp_minpoll). This is for KoD rate
+ * control and not strictly specification compliant, but doesn't
+ * break anything.
*
- * The root delay field is special. If the system stratum is
- * less than the orphan stratum, send the real root delay.
- * Otherwise, if there is no system peer, send the orphan delay.
- * Otherwise, we must be an orphan parent, so send zero.
+ * If the gazinta was from a multicast address, the gazoutta
+ * must go out another way.
*/
rpkt = &rbufp->recv_pkt;
if (rbufp->dstadr->flags & INT_MCASTOPEN)
rbufp->dstadr = findinterface(&rbufp->recv_srcadr);
/*
- * This is deliciously complicated. There are four cases.
- *
- * case leap stratum refid delay dispersion
- *
- * KoD 11 16 KISS system system
- * normal system system system system system
- * orphan child 00 orphan system orphan system
- * orphan parent 00 orphan loopbk 0 0
- */
- /*
- * This is a kiss-of-death (KoD) packet. Show leap
+ * If this is a kiss-o'-death (KoD) packet, show leap
* unsynchronized, stratum zero, reference ID the four-character
- * kiss code and system root delay. Note the rate limit on these
- * packets. Once a second initialize a bucket counter. Every
- * packet sent decrements the counter until reaching zero. If
- * the counter is zero, drop the kiss.
+ * kiss code and system root delay. Note we don't reveal the
+ * local time, so these packets can't be used for
+ * synchronization.
*/
- if (mask & RES_LIMITED) {
- sys_limitrejected++;
- if (sys_kod == 0 || !(mask & RES_DEMOBILIZE))
- return;
-
- sys_kod--;
+ if (flags & RES_KOD) {
+ sys_kodsent++;
xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
PKT_VERSION(rpkt->li_vn_mode), xmode);
- xpkt.stratum = STRATUM_UNSPEC;
+ xpkt.stratum = STRATUM_PKT_UNSPEC;
+ xpkt.ppoll = max(rpkt->ppoll, ntp_minpoll);
+ xpkt.precision = rpkt->precision;
memcpy(&xpkt.refid, "RATE", 4);
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
- xpkt.rootdispersion =
- HTONS_FP(DTOUFP(sys_rootdispersion));
+ xpkt.rootdelay = rpkt->rootdelay;
+ xpkt.rootdisp = rpkt->rootdisp;
+ xpkt.reftime = rpkt->reftime;
+ xpkt.org = rpkt->xmt;
+ xpkt.rec = rpkt->xmt;
+ xpkt.xmt = rpkt->xmt;
/*
* This is a normal packet. Use the system variables.
*/
- } else if (sys_stratum < sys_orphan) {
- xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap,
+ } else {
+#ifdef LEAP_SMEAR
+ /*
+ * Make copies of the variables which can be affected by smearing.
+ */
+ l_fp this_ref_time;
+ l_fp this_recv_time;
+#endif
+
+ /*
+ * If we are inside the leap smear interval we add the current smear offset to
+ * the packet receive time, to the packet transmit time, and eventually to the
+ * reftime to make sure the reftime isn't later than the transmit/receive times.
+ */
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(xmt_leap,
PKT_VERSION(rpkt->li_vn_mode), xmode);
+
xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
+ xpkt.ppoll = max(rpkt->ppoll, ntp_minpoll);
+ xpkt.precision = sys_precision;
xpkt.refid = sys_refid;
xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
- xpkt.rootdispersion =
- HTONS_FP(DTOUFP(sys_rootdispersion));
+ xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
+
+#ifdef LEAP_SMEAR
+ this_ref_time = sys_reftime;
+ if (leap_smear.in_progress) {
+ leap_smear_add_offs(&this_ref_time, NULL);
+ xpkt.refid = convertLFPToRefID(leap_smear.offset);
+ DPRINTF(2, ("fast_xmit: leap_smear.in_progress: refid %8x, smear %s\n",
+ ntohl(xpkt.refid),
+ lfptoa(&leap_smear.offset, 8)
+ ));
+ }
+ HTONL_FP(&this_ref_time, &xpkt.reftime);
+#else
+ HTONL_FP(&sys_reftime, &xpkt.reftime);
+#endif
- /*
- * This is a orphan child packet. The host is synchronized to an
- * orphan parent. Show leap synchronized, orphan stratum, system
- * reference ID and orphan root delay.
- */
- } else if (sys_peer != NULL) {
- xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING,
- PKT_VERSION(rpkt->li_vn_mode), xmode);
- xpkt.stratum = STRATUM_TO_PKT(sys_orphan);
- xpkt.refid = sys_refid;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay));
- xpkt.rootdispersion =
- HTONS_FP(DTOUFP(sys_rootdispersion));
+ xpkt.org = rpkt->xmt;
- /*
- * This is an orphan parent. Show leap synchronized, orphan
- * stratum, loopack reference ID and zero root delay.
- */
- } else {
- xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING,
- PKT_VERSION(rpkt->li_vn_mode), xmode);
- xpkt.stratum = STRATUM_TO_PKT(sys_orphan);
- xpkt.refid = htonl(LOOPBACKADR);
- xpkt.rootdelay = HTONS_FP(DTOFP(0));
- xpkt.rootdispersion = HTONS_FP(DTOFP(0));
+#ifdef LEAP_SMEAR
+ this_recv_time = rbufp->recv_time;
+ if (leap_smear.in_progress)
+ leap_smear_add_offs(&this_recv_time, NULL);
+ HTONL_FP(&this_recv_time, &xpkt.rec);
+#else
+ HTONL_FP(&rbufp->recv_time, &xpkt.rec);
+#endif
+
+ get_systime(&xmt_tx);
+#ifdef LEAP_SMEAR
+ if (leap_smear.in_progress)
+ leap_smear_add_offs(&xmt_tx, &this_recv_time);
+#endif
+ HTONL_FP(&xmt_tx, &xpkt.xmt);
}
- xpkt.ppoll = rpkt->ppoll;
- xpkt.precision = sys_precision;
- xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion));
- HTONL_FP(&sys_reftime, &xpkt.reftime);
- xpkt.org = rpkt->xmt;
- HTONL_FP(&rbufp->recv_time, &xpkt.rec);
+
+#ifdef HAVE_NTP_SIGND
+ if (flags & RES_MSSNTP) {
+ send_via_ntp_signd(rbufp, xmode, xkeyid, flags, &xpkt);
+ return;
+ }
+#endif /* HAVE_NTP_SIGND */
/*
* If the received packet contains a MAC, the transmitted packet
@@ -2927,15 +3583,14 @@ fast_xmit(
*/
sendlen = LEN_PKT_NOMAC;
if (rbufp->recv_length == sendlen) {
- get_systime(&xmt_ts);
- HTONL_FP(&xmt_ts, &xpkt.xmt);
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt,
sendlen);
#ifdef DEBUG
if (debug)
- printf("transmit: at %ld %s->%s mode %d\n",
+ printf(
+ "transmit: at %ld %s->%s mode %d len %d\n",
current_time, stoa(&rbufp->dstadr->sin),
- stoa(&rbufp->recv_srcadr), xmode);
+ stoa(&rbufp->recv_srcadr), xmode, sendlen);
#endif
return;
}
@@ -2948,7 +3603,7 @@ fast_xmit(
* value to generate the cookie, which is unique for every
* source-destination-key ID combination.
*/
-#ifdef OPENSSL
+#ifdef AUTOKEY
if (xkeyid > NTP_MAXKEY) {
keyid_t cookie;
@@ -2963,61 +3618,199 @@ fast_xmit(
*/
cookie = session_key(&rbufp->recv_srcadr,
&rbufp->dstadr->sin, 0, sys_private, 0);
- if (rbufp->recv_length >= (int)(sendlen + MAX_MAC_LEN +
- 2 * sizeof(u_int32))) {
+ if (rbufp->recv_length > sendlen + (int)MAX_MAC_LEN) {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, 0, 2);
temp32 = CRYPTO_RESP;
rpkt->exten[0] |= htonl(temp32);
- sendlen += crypto_xmit(&xpkt,
- &rbufp->recv_srcadr, sendlen,
- (struct exten *)rpkt->exten, cookie);
+ sendlen += crypto_xmit(NULL, &xpkt, rbufp,
+ sendlen, (struct exten *)rpkt->exten,
+ cookie);
} else {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, cookie, 2);
}
}
-#endif /* OPENSSL */
- get_systime(&xmt_ts);
- L_ADD(&xmt_ts, &sys_authdelay);
- HTONL_FP(&xmt_ts, &xpkt.xmt);
- authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
- sendlen += authlen;
-#ifdef OPENSSL
+#endif /* AUTOKEY */
+ get_systime(&xmt_tx);
+ sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
+#ifdef AUTOKEY
if (xkeyid > NTP_MAXKEY)
authtrust(xkeyid, 0);
-#endif /* OPENSSL */
- get_systime(&xmt_tx);
- if (sendlen > sizeof(xpkt)) {
- msyslog(LOG_ERR, "buffer overflow %u", sendlen);
- exit (-1);
- }
+#endif /* AUTOKEY */
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen);
-
- /*
- * Calculate the encryption delay. Keep the minimum over the
- * latest two samples.
- */
- L_SUB(&xmt_tx, &xmt_ts);
- L_ADD(&xmt_tx, &sys_authdelay);
- sys_authdly[1] = sys_authdly[0];
- sys_authdly[0] = xmt_tx.l_uf;
- if (sys_authdly[0] < sys_authdly[1])
- sys_authdelay.l_uf = sys_authdly[0];
- else
- sys_authdelay.l_uf = sys_authdly[1];
+ get_systime(&xmt_ty);
+ L_SUB(&xmt_ty, &xmt_tx);
+ sys_authdelay = xmt_ty;
#ifdef DEBUG
if (debug)
printf(
- "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n",
+ "transmit: at %ld %s->%s mode %d keyid %08x len %d\n",
current_time, ntoa(&rbufp->dstadr->sin),
- ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen -
- authlen, authlen);
+ ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
#endif
}
-#ifdef OPENSSL
+/*
+ * pool_xmit - resolve hostname or send unicast solicitation for pool.
+ */
+static void
+pool_xmit(
+ struct peer *pool /* pool solicitor association */
+ )
+{
+#ifdef WORKER
+ struct pkt xpkt; /* transmit packet structure */
+ struct addrinfo hints;
+ int rc;
+ struct interface * lcladr;
+ sockaddr_u * rmtadr;
+ int restrict_mask;
+ struct peer * p;
+ l_fp xmt_tx;
+
+ if (NULL == pool->ai) {
+ if (pool->addrs != NULL) {
+ /* free() is used with copy_addrinfo_list() */
+ free(pool->addrs);
+ pool->addrs = NULL;
+ }
+ ZERO(hints);
+ hints.ai_family = AF(&pool->srcadr);
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ /* ignore getaddrinfo_sometime() errors, we will retry */
+ rc = getaddrinfo_sometime(
+ pool->hostname,
+ "ntp",
+ &hints,
+ 0, /* no retry */
+ &pool_name_resolved,
+ (void *)(intptr_t)pool->associd);
+ if (!rc)
+ DPRINTF(1, ("pool DNS lookup %s started\n",
+ pool->hostname));
+ else
+ msyslog(LOG_ERR,
+ "unable to start pool DNS %s %m",
+ pool->hostname);
+ return;
+ }
+
+ do {
+ /* copy_addrinfo_list ai_addr points to a sockaddr_u */
+ rmtadr = (sockaddr_u *)(void *)pool->ai->ai_addr;
+ pool->ai = pool->ai->ai_next;
+ p = findexistingpeer(rmtadr, NULL, NULL, MODE_CLIENT, 0);
+ } while (p != NULL && pool->ai != NULL);
+ if (p != NULL)
+ return; /* out of addresses, re-query DNS next poll */
+ restrict_mask = restrictions(rmtadr);
+ if (RES_FLAGS & restrict_mask)
+ restrict_source(rmtadr, 0,
+ current_time + POOL_SOLICIT_WINDOW + 1);
+ lcladr = findinterface(rmtadr);
+ memset(&xpkt, 0, sizeof(xpkt));
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, pool->version,
+ MODE_CLIENT);
+ xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
+ xpkt.ppoll = pool->hpoll;
+ xpkt.precision = sys_precision;
+ xpkt.refid = sys_refid;
+ xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
+ HTONL_FP(&sys_reftime, &xpkt.reftime);
+ get_systime(&xmt_tx);
+ pool->aorg = xmt_tx;
+ HTONL_FP(&xmt_tx, &xpkt.xmt);
+ sendpkt(rmtadr, lcladr, sys_ttl[pool->ttl], &xpkt,
+ LEN_PKT_NOMAC);
+ pool->sent++;
+ pool->throttle += (1 << pool->minpoll) - 2;
+#ifdef DEBUG
+ if (debug)
+ printf("transmit: at %ld %s->%s pool\n",
+ current_time, latoa(lcladr), stoa(rmtadr));
+#endif
+ msyslog(LOG_INFO, "Soliciting pool server %s", stoa(rmtadr));
+#endif /* WORKER */
+}
+
+
+#ifdef AUTOKEY
+ /*
+ * group_test - test if this is the same group
+ *
+ * host assoc return action
+ * none none 0 mobilize *
+ * none group 0 mobilize *
+ * group none 0 mobilize *
+ * group group 1 mobilize
+ * group different 1 ignore
+ * * ignore if notrust
+ */
+int group_test(
+ char *grp,
+ char *ident
+ )
+{
+ if (grp == NULL)
+ return (0);
+
+ if (strcmp(grp, sys_groupname) == 0)
+ return (0);
+
+ if (ident == NULL)
+ return (1);
+
+ if (strcmp(grp, ident) == 0)
+ return (0);
+
+ return (1);
+}
+#endif /* AUTOKEY */
+
+#ifdef WORKER
+void
+pool_name_resolved(
+ int rescode,
+ int gai_errno,
+ void * context,
+ const char * name,
+ const char * service,
+ const struct addrinfo * hints,
+ const struct addrinfo * res
+ )
+{
+ struct peer * pool; /* pool solicitor association */
+ associd_t assoc;
+
+ if (rescode) {
+ msyslog(LOG_ERR,
+ "error resolving pool %s: %s (%d)",
+ name, gai_strerror(rescode), rescode);
+ return;
+ }
+
+ assoc = (associd_t)(intptr_t)context;
+ pool = findpeerbyassoc(assoc);
+ if (NULL == pool) {
+ msyslog(LOG_ERR,
+ "Could not find assoc %u for pool DNS %s",
+ assoc, name);
+ return;
+ }
+ DPRINTF(1, ("pool DNS %s completed\n", name));
+ pool->addrs = copy_addrinfo_list(res);
+ pool->ai = pool->addrs;
+ pool_xmit(pool);
+
+}
+#endif /* WORKER */
+
+
+#ifdef AUTOKEY
/*
* key_expire - purge the key list
*/
@@ -3036,12 +3829,37 @@ key_expire(
}
value_free(&peer->sndval);
peer->keynumber = 0;
+ peer->flags &= ~FLAG_ASSOC;
#ifdef DEBUG
if (debug)
- printf("key_expire: at %lu\n", current_time);
+ printf("key_expire: at %lu associd %d\n", current_time,
+ peer->associd);
#endif
}
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
+
+
+/*
+ * local_refid(peer) - check peer refid to avoid selecting peers
+ * currently synced to this ntpd.
+ */
+static int
+local_refid(
+ struct peer * p
+ )
+{
+ endpt * unicast_ep;
+
+ if (p->dstadr != NULL && !(INT_MCASTIF & p->dstadr->flags))
+ unicast_ep = p->dstadr;
+ else
+ unicast_ep = findinterface(&p->srcadr);
+
+ if (unicast_ep != NULL && p->refid == unicast_ep->addr_refid)
+ return TRUE;
+ else
+ return FALSE;
+}
/*
@@ -3049,7 +3867,7 @@ key_expire(
*
* A peer is unfit for synchronization if
* > TEST10 bad leap or stratum below floor or at or above ceiling
- * > TEST11 root distance exceeded
+ * > TEST11 root distance exceeded for remote peer
* > TEST12 a direct or indirect synchronization loop would form
* > TEST13 unreachable or noselect
*/
@@ -3063,40 +3881,35 @@ peer_unfit(
/*
* A stratum error occurs if (1) the server has never been
* synchronized, (2) the server stratum is below the floor or
- * greater than or equal to the ceiling, (3) the system stratum
- * is below the orphan stratum and the server stratum is greater
- * than or equal to the orphan stratum.
+ * greater than or equal to the ceiling.
*/
if (peer->leap == LEAP_NOTINSYNC || peer->stratum < sys_floor ||
- peer->stratum >= sys_ceiling || (sys_stratum < sys_orphan &&
- peer->stratum >= sys_orphan))
- rval |= TEST10; /* stratum out of bounds */
+ peer->stratum >= sys_ceiling)
+ rval |= TEST10; /* bad synch or stratum */
/*
- * A distance error occurs if the root distance is greater than
- * or equal to the distance threshold plus the increment due to
- * one poll interval.
+ * A distance error for a remote peer occurs if the root
+ * distance is greater than or equal to the distance threshold
+ * plus the increment due to one host poll interval.
*/
- if (root_distance(peer) >= sys_maxdist + clock_phi *
- ULOGTOD(sys_poll))
+ if (!(peer->flags & FLAG_REFCLOCK) && root_distance(peer) >=
+ sys_maxdist + clock_phi * ULOGTOD(peer->hpoll))
rval |= TEST11; /* distance exceeded */
/*
* A loop error occurs if the remote peer is synchronized to the
- * local peer of if the remote peer is synchronized to the same
- * server as the local peer, but only if the remote peer is not
- * the orphan parent.
+ * local peer or if the remote peer is synchronized to the same
+ * server as the local peer but only if the remote peer is
+ * neither a reference clock nor an orphan.
*/
- if (peer->stratum > 1 && peer->refid != htonl(LOOPBACKADR) &&
- ((!peer->dstadr || peer->refid == peer->dstadr->addr_refid) ||
- peer->refid == sys_refid))
- rval |= TEST12; /* synch loop */
+ if (peer->stratum > 1 && local_refid(peer))
+ rval |= TEST12; /* synchronization loop */
/*
* An unreachable error occurs if the server is unreachable or
* the noselect bit is set.
*/
- if (!peer->reach || peer->flags & FLAG_NOSELECT)
+ if (!peer->reach || (peer->flags & FLAG_NOSELECT))
rval |= TEST13; /* unreachable */
peer->flash &= ~PEER_TEST_MASK;
@@ -3108,74 +3921,143 @@ peer_unfit(
/*
* Find the precision of this particular machine
*/
-#define MINSTEP 100e-9 /* minimum clock increment (s) */
-#define MAXSTEP 20e-3 /* maximum clock increment (s) */
-#define MINLOOPS 5 /* minimum number of step samples */
+#define MINSTEP 20e-9 /* minimum clock increment (s) */
+#define MAXSTEP 1 /* maximum clock increment (s) */
+#define MINCHANGES 12 /* minimum number of step samples */
+#define MAXLOOPS ((int)(1. / MINSTEP)) /* avoid infinite loop */
/*
- * This routine calculates the system precision, defined as the minimum
- * of a sequence of differences between successive readings of the
- * system clock. However, if the system clock can be read more than once
- * during a tick interval, the difference can be zero or one LSB unit,
- * where the LSB corresponds to one nanosecond or one microsecond.
- * Conceivably, if some other process preempts this one and reads the
- * clock, the difference can be more than one LSB unit.
+ * This routine measures the system precision defined as the minimum of
+ * a sequence of differences between successive readings of the system
+ * clock. However, if a difference is less than MINSTEP, the clock has
+ * been read more than once during a clock tick and the difference is
+ * ignored. We set MINSTEP greater than zero in case something happens
+ * like a cache miss, and to tolerate underlying system clocks which
+ * ensure each reading is strictly greater than prior readings while
+ * using an underlying stepping (not interpolated) clock.
*
- * For hardware clock frequencies of 10 MHz or less, we assume the
- * logical clock advances only at the hardware clock tick. For higher
- * frequencies, we assume the logical clock can advance no more than 100
- * nanoseconds between ticks.
+ * sys_tick and sys_precision represent the time to read the clock for
+ * systems with high-precision clocks, and the tick interval or step
+ * size for lower-precision stepping clocks.
+ *
+ * This routine also measures the time to read the clock on stepping
+ * system clocks by counting the number of readings between changes of
+ * the underlying clock. With either type of clock, the minimum time
+ * to read the clock is saved as sys_fuzz, and used to ensure the
+ * get_systime() readings always increase and are fuzzed below sys_fuzz.
*/
-int
-default_get_precision(void)
+void
+measure_precision(void)
{
+ /*
+ * With sys_fuzz set to zero, get_systime() fuzzing of low bits
+ * is effectively disabled. trunc_os_clock is FALSE to disable
+ * get_ostime() simulation of a low-precision system clock.
+ */
+ set_sys_fuzz(0.);
+ trunc_os_clock = FALSE;
+ measured_tick = measure_tick_fuzz();
+ set_sys_tick_precision(measured_tick);
+ msyslog(LOG_INFO, "proto: precision = %.3f usec (%d)",
+ sys_tick * 1e6, sys_precision);
+ if (sys_fuzz < sys_tick) {
+ msyslog(LOG_NOTICE, "proto: fuzz beneath %.3f usec",
+ sys_fuzz * 1e6);
+ }
+}
+
+
+/*
+ * measure_tick_fuzz()
+ *
+ * measures the minimum time to read the clock (stored in sys_fuzz)
+ * and returns the tick, the larger of the minimum increment observed
+ * between successive clock readings and the time to read the clock.
+ */
+double
+measure_tick_fuzz(void)
+{
+ l_fp minstep; /* MINSTEP as l_fp */
l_fp val; /* current seconds fraction */
l_fp last; /* last seconds fraction */
- l_fp diff; /* difference */
+ l_fp ldiff; /* val - last */
double tick; /* computed tick value */
- double dtemp; /* scratch */
+ double diff;
+ long repeats;
+ long max_repeats;
+ int changes;
int i; /* log2 precision */
- /*
- * Loop to find tick value in nanoseconds. Toss out outlyer
- * values less than the minimun tick value. In wacky cases, use
- * the default maximum value.
- */
- get_systime(&last);
tick = MAXSTEP;
- for (i = 0; i < MINLOOPS;) {
+ max_repeats = 0;
+ repeats = 0;
+ changes = 0;
+ DTOLFP(MINSTEP, &minstep);
+ get_systime(&last);
+ for (i = 0; i < MAXLOOPS && changes < MINCHANGES; i++) {
get_systime(&val);
- diff = val;
- L_SUB(&diff, &last);
+ ldiff = val;
+ L_SUB(&ldiff, &last);
last = val;
- LFPTOD(&diff, dtemp);
- if (dtemp < MINSTEP)
- continue;
- i++;
- if (dtemp < tick)
- tick = dtemp;
+ if (L_ISGT(&ldiff, &minstep)) {
+ max_repeats = max(repeats, max_repeats);
+ repeats = 0;
+ changes++;
+ LFPTOD(&ldiff, diff);
+ tick = min(diff, tick);
+ } else {
+ repeats++;
+ }
+ }
+ if (changes < MINCHANGES) {
+ msyslog(LOG_ERR, "Fatal error: precision could not be measured (MINSTEP too large?)");
+ exit(1);
}
- /*
- * Find the nearest power of two.
- */
- NLOG(NLOG_SYSEVENT)
- msyslog(LOG_INFO, "precision = %.3f usec", tick * 1e6);
- for (i = 0; tick <= 1; i++)
- tick *= 2;
- if (tick - 1. > 1. - tick / 2)
- i--;
- return (-i);
+ if (0 == max_repeats) {
+ set_sys_fuzz(tick);
+ } else {
+ set_sys_fuzz(tick / max_repeats);
+ }
+
+ return tick;
}
-/*
- * kod_proto - called once per second to limit kiss-of-death packets
- */
void
-kod_proto(void)
+set_sys_tick_precision(
+ double tick
+ )
{
- sys_kod = sys_kod_rate;
+ int i;
+
+ if (tick > 1.) {
+ msyslog(LOG_ERR,
+ "unsupported tick %.3f > 1s ignored", tick);
+ return;
+ }
+ if (tick < measured_tick) {
+ msyslog(LOG_ERR,
+ "proto: tick %.3f less than measured tick %.3f, ignored",
+ tick, measured_tick);
+ return;
+ } else if (tick > measured_tick) {
+ trunc_os_clock = TRUE;
+ msyslog(LOG_NOTICE,
+ "proto: truncating system clock to multiples of %.9f",
+ tick);
+ }
+ sys_tick = tick;
+
+ /*
+ * Find the nearest power of two.
+ */
+ for (i = 0; tick <= 1; i--)
+ tick *= 2;
+ if (tick - 1 > 1 - tick / 2)
+ i++;
+
+ sys_precision = (s_char)i;
}
@@ -3190,46 +4072,31 @@ init_proto(void)
/*
* Fill in the sys_* stuff. Default is don't listen to
- * broadcasting, authenticate.
+ * broadcasting, require authentication.
*/
- sys_leap = LEAP_NOTINSYNC;
+ set_sys_leap(LEAP_NOTINSYNC);
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "INIT", 4);
- sys_precision = (s_char)default_get_precision();
- sys_jitter = LOGTOD(sys_precision);
+ sys_peer = NULL;
sys_rootdelay = 0;
- sys_orphandelay = (double)(ntp_random() & 0xffff) / 65536. *
- sys_maxdist;
- sys_rootdispersion = 0;
+ sys_rootdisp = 0;
L_CLR(&sys_reftime);
- sys_peer = NULL;
- sys_survivors = 0;
+ sys_jitter = 0;
+ measure_precision();
get_systime(&dummy);
+ sys_survivors = 0;
sys_manycastserver = 0;
sys_bclient = 0;
- sys_bdelay = DEFBROADDELAY;
- sys_calldelay = BURST_DELAY;
+ sys_bdelay = 0;
sys_authenticate = 1;
- L_CLR(&sys_authdelay);
- sys_authdly[0] = sys_authdly[1] = 0;
- sys_stattime = 0;
+ sys_stattime = current_time;
+ orphwait = current_time + sys_orphwait;
proto_clr_stats();
for (i = 0; i < MAX_TTL; i++) {
sys_ttl[i] = (u_char)((i * 256) / MAX_TTL);
sys_ttlmax = i;
}
-#ifdef OPENSSL
- sys_automax = 1 << NTP_AUTOMAX;
-#endif /* OPENSSL */
-
- /*
- * Default these to enable
- */
- ntp_enable = 1;
-#ifndef KERNEL_FLL_BUG
- kern_enable = 1;
-#endif
- pps_enable = 0;
+ hardpps_enable = 0;
stats_control = 1;
}
@@ -3242,49 +4109,25 @@ proto_config(
int item,
u_long value,
double dvalue,
- struct sockaddr_storage* svalue
+ sockaddr_u *svalue
)
{
/*
* Figure out what he wants to change, then do it
*/
- switch (item) {
-
- /*
- * Turn on/off kernel discipline.
- */
- case PROTO_KERNEL:
- kern_enable = (int)value;
- break;
-
- /*
- * Turn on/off clock discipline.
- */
- case PROTO_NTP:
- ntp_enable = (int)value;
- break;
+ DPRINTF(2, ("proto_config: code %d value %lu dvalue %lf\n",
+ item, value, dvalue));
- /*
- * Turn on/off monitoring.
- */
- case PROTO_MONITOR:
- if (value)
- mon_start(MON_ON);
- else
- mon_stop(MON_ON);
- break;
+ switch (item) {
/*
- * Turn on/off statistics.
+ * enable and disable commands - arguments are Boolean.
*/
- case PROTO_FILEGEN:
- stats_control = (int)value;
+ case PROTO_AUTHENTICATE: /* authentication (auth) */
+ sys_authenticate = value;
break;
- /*
- * Turn on/off enable broadcasts.
- */
- case PROTO_BROADCLIENT:
+ case PROTO_BROADCLIENT: /* broadcast client (bclient) */
sys_bclient = (int)value;
if (sys_bclient == 0)
io_unsetbclient();
@@ -3292,152 +4135,116 @@ proto_config(
io_setbclient();
break;
- /*
- * Turn on/off PPS discipline.
- */
- case PROTO_PPS:
- pps_enable = (int)value;
+#ifdef REFCLOCK
+ case PROTO_CAL: /* refclock calibrate (calibrate) */
+ cal_enable = value;
break;
+#endif /* REFCLOCK */
- /*
- * Add muliticast group address.
- */
- case PROTO_MULTICAST_ADD:
- if (svalue)
- io_multicast_add(*svalue);
- sys_bclient = 1;
+ case PROTO_KERNEL: /* kernel discipline (kernel) */
+ select_loop(value);
break;
- /*
- * Delete multicast group address.
- */
- case PROTO_MULTICAST_DEL:
- if (svalue)
- io_multicast_del(*svalue);
+ case PROTO_MONITOR: /* monitoring (monitor) */
+ if (value)
+ mon_start(MON_ON);
+ else {
+ mon_stop(MON_ON);
+ if (mon_enabled)
+ msyslog(LOG_WARNING,
+ "restrict: 'monitor' cannot be disabled while 'limited' is enabled");
+ }
break;
- /*
- * Set default broadcast delay.
- */
- case PROTO_BROADDELAY:
- sys_bdelay = dvalue;
+ case PROTO_NTP: /* NTP discipline (ntp) */
+ ntp_enable = value;
break;
- /*
- * Set modem call delay.
- */
- case PROTO_CALLDELAY:
- sys_calldelay = (int)value;
+ case PROTO_MODE7: /* mode7 management (ntpdc) */
+ ntp_mode7 = value;
break;
- /*
- * Turn on/off authentication to mobilize ephemeral
- * associations.
- */
- case PROTO_AUTHENTICATE:
- sys_authenticate = (int)value;
+ case PROTO_PPS: /* PPS discipline (pps) */
+ hardpps_enable = value;
break;
- /*
- * Set minimum number of survivors.
- */
- case PROTO_MINCLOCK:
- sys_minclock = (int)dvalue;
+ case PROTO_FILEGEN: /* statistics (stats) */
+ stats_control = value;
break;
/*
- * Set maximum number of preemptable associations.
+ * tos command - arguments are double, sometimes cast to int
*/
- case PROTO_MAXCLOCK:
- sys_maxclock = (int)dvalue;
+ case PROTO_BEACON: /* manycast beacon (beacon) */
+ sys_beacon = (int)dvalue;
break;
- /*
- * Set minimum number of survivors.
- */
- case PROTO_MINSANE:
- sys_minsane = (int)dvalue;
+ case PROTO_BROADDELAY: /* default broadcast delay (bdelay) */
+ sys_bdelay = dvalue;
break;
- /*
- * Set stratum floor.
- */
- case PROTO_FLOOR:
+ case PROTO_CEILING: /* stratum ceiling (ceiling) */
+ sys_ceiling = (int)dvalue;
+ break;
+
+ case PROTO_COHORT: /* cohort switch (cohort) */
+ sys_cohort = (int)dvalue;
+ break;
+
+ case PROTO_FLOOR: /* stratum floor (floor) */
sys_floor = (int)dvalue;
break;
- /*
- * Set stratum ceiling.
- */
- case PROTO_CEILING:
- sys_ceiling = (int)dvalue;
+ case PROTO_MAXCLOCK: /* maximum candidates (maxclock) */
+ sys_maxclock = (int)dvalue;
break;
- /*
- * Set orphan stratum.
- */
- case PROTO_ORPHAN:
- sys_orphan = (int)dvalue;
+ case PROTO_MAXDIST: /* select threshold (maxdist) */
+ sys_maxdist = dvalue;
break;
- /*
- * Set cohort switch.
- */
- case PROTO_COHORT:
- sys_cohort = (int)dvalue;
+ case PROTO_CALLDELAY: /* modem call delay (mdelay) */
+ break; /* NOT USED */
+
+ case PROTO_MINCLOCK: /* minimum candidates (minclock) */
+ sys_minclock = (int)dvalue;
break;
- /*
- * Set minimum dispersion increment.
- */
- case PROTO_MINDISP:
+ case PROTO_MINDISP: /* minimum distance (mindist) */
sys_mindisp = dvalue;
break;
- /*
- * Set maximum distance (select threshold).
- */
- case PROTO_MAXDIST:
- sys_maxdist = dvalue;
+ case PROTO_MINSANE: /* minimum survivors (minsane) */
+ sys_minsane = (int)dvalue;
break;
- /*
- * Set anticlockhop threshold.
- */
- case PROTO_MAXHOP:
- sys_maxhop = (int)dvalue;
+ case PROTO_ORPHAN: /* orphan stratum (orphan) */
+ sys_orphan = (int)dvalue;
break;
- /*
- * Set adjtime() resolution (s).
- */
- case PROTO_ADJ:
- sys_tick = dvalue;
+ case PROTO_ORPHWAIT: /* orphan wait (orphwait) */
+ orphwait -= sys_orphwait;
+ sys_orphwait = (int)dvalue;
+ orphwait += sys_orphwait;
break;
/*
- * Set manycast beacon interval.
+ * Miscellaneous commands
*/
- case PROTO_BEACON:
- sys_beacon = (int)dvalue;
+ case PROTO_MULTICAST_ADD: /* add group address */
+ if (svalue != NULL)
+ io_multicast_add(svalue);
+ sys_bclient = 1;
break;
-#ifdef REFCLOCK
- /*
- * Turn on/off refclock calibrate
- */
- case PROTO_CAL:
- cal_enable = (int)value;
+ case PROTO_MULTICAST_DEL: /* delete group address */
+ if (svalue != NULL)
+ io_multicast_del(svalue);
break;
-#endif /* REFCLOCK */
- default:
- /*
- * Log this error.
- */
- msyslog(LOG_INFO,
- "proto_config: illegal item %d, value %ld", item,
- value);
+ default:
+ msyslog(LOG_NOTICE,
+ "proto: unsupported option %d", item);
}
}
@@ -3451,11 +4258,12 @@ proto_clr_stats(void)
sys_stattime = current_time;
sys_received = 0;
sys_processed = 0;
- sys_newversionpkt = 0;
- sys_oldversionpkt = 0;
- sys_unknownversion = 0;
+ sys_newversion = 0;
+ sys_oldversion = 0;
+ sys_declined = 0;
sys_restricted = 0;
sys_badlength = 0;
sys_badauth = 0;
sys_limitrejected = 0;
+ sys_kodsent = 0;
}
diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c
index a29ef08..f0e9b9e 100644
--- a/contrib/ntp/ntpd/ntp_refclock.c
+++ b/contrib/ntp/ntpd/ntp_refclock.c
@@ -11,6 +11,7 @@
#include "ntp_tty.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
#include <stdio.h>
@@ -20,77 +21,54 @@
#ifdef REFCLOCK
-#ifdef TTYCLK
-# ifdef HAVE_SYS_CLKDEFS_H
-# include <sys/clkdefs.h>
-# include <stropts.h>
-# endif
-# ifdef HAVE_SYS_SIO_H
-# include <sys/sio.h>
-# endif
-#endif /* TTYCLK */
-
#ifdef KERNEL_PLL
#include "ntp_syscall.h"
#endif /* KERNEL_PLL */
+#ifdef HAVE_PPSAPI
+#include "ppsapi_timepps.h"
+#include "refclock_atom.h"
+#endif /* HAVE_PPSAPI */
+
/*
* Reference clock support is provided here by maintaining the fiction
- * that the clock is actually a peer. As no packets are exchanged with a
- * reference clock, however, we replace the transmit, receive and packet
- * procedures with separate code to simulate them. Routines
+ * that the clock is actually a peer. As no packets are exchanged with
+ * a reference clock, however, we replace the transmit, receive and
+ * packet procedures with separate code to simulate them. Routines
* refclock_transmit() and refclock_receive() maintain the peer
* variables in a state analogous to an actual peer and pass reference
- * clock data on through the filters. Routines refclock_peer() and
+ * clock data on through the filters. Routines refclock_peer() and
* refclock_unpeer() are called to initialize and terminate reference
- * clock associations. A set of utility routines is included to open
- * serial devices, process sample data, edit input lines to extract
- * embedded timestamps and to peform various debugging functions.
+ * clock associations. A set of utility routines is included to open
+ * serial devices, process sample data, and to perform various debugging
+ * functions.
*
* The main interface used by these routines is the refclockproc
- * structure, which contains for most drivers the decimal equivalants of
- * the year, day, month, hour, second and millisecond/microsecond
- * decoded from the ASCII timecode. Additional information includes the
- * receive timestamp, exception report, statistics tallies, etc. In
- * addition, there may be a driver-specific unit structure used for
+ * structure, which contains for most drivers the decimal equivalants
+ * of the year, day, month, hour, second and millisecond/microsecond
+ * decoded from the ASCII timecode. Additional information includes
+ * the receive timestamp, exception report, statistics tallies, etc.
+ * In addition, there may be a driver-specific unit structure used for
* local control of the device.
*
* The support routines are passed a pointer to the peer structure,
- * which is used for all peer-specific processing and contains a pointer
- * to the refclockproc structure, which in turn containes a pointer to
- * the unit structure, if used. The peer structure is identified by an
- * interface address in the dotted quad form 127.127.t.u (for now only
- * IPv4 addresses are used, so we need to be sure the address is it),
- * where t is the clock type and u the unit. Some legacy drivers derive
- * the refclockproc structure pointer from the table
- * typeunit[type][unit]. This interface is strongly discouraged and may
- * be abandoned in future.
+ * which is used for all peer-specific processing and contains a
+ * pointer to the refclockproc structure, which in turn contains a
+ * pointer to the unit structure, if used. The peer structure is
+ * identified by an interface address in the dotted quad form
+ * 127.127.t.u, where t is the clock type and u the unit.
*/
-#define MAXUNIT 4 /* max units */
#define FUDGEFAC .1 /* fudge correction factor */
#define LF 0x0a /* ASCII LF */
-#ifdef PPS
-int fdpps; /* ppsclock legacy */
-#endif /* PPS */
int cal_enable; /* enable refclock calibrate */
/*
- * Type/unit peer index. Used to find the peer structure for control and
- * debugging. When all clock drivers have been converted to new style,
- * this dissapears.
- */
-static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
-
-/*
* Forward declarations
*/
-#ifdef QSORT_USES_VOID_P
-static int refclock_cmpl_fp P((const void *, const void *));
-#else
-static int refclock_cmpl_fp P((const double *, const double *));
-#endif /* QSORT_USES_VOID_P */
-static int refclock_sample P((struct refclockproc *));
+static int refclock_cmpl_fp (const void *, const void *);
+static int refclock_sample (struct refclockproc *);
+static int refclock_ioctl(int, u_int);
/*
@@ -113,58 +91,36 @@ refclock_report(
return;
switch (code) {
- case CEVNT_NOMINAL:
- break;
-
- case CEVNT_TIMEOUT:
- pp->noreply++;
- break;
- case CEVNT_BADREPLY:
- pp->badformat++;
- break;
+ case CEVNT_TIMEOUT:
+ pp->noreply++;
+ break;
- case CEVNT_FAULT:
- break;
+ case CEVNT_BADREPLY:
+ pp->badformat++;
+ break;
- case CEVNT_PROP:
- break;
+ case CEVNT_FAULT:
+ break;
- case CEVNT_BADDATE:
- case CEVNT_BADTIME:
- pp->baddata++;
- break;
+ case CEVNT_BADDATE:
+ case CEVNT_BADTIME:
+ pp->baddata++;
+ break;
- default:
- /* shouldn't happen */
- break;
+ default:
+ /* ignore others */
+ break;
}
-
+ if (pp->lastevent < 15)
+ pp->lastevent++;
if (pp->currentstatus != code) {
pp->currentstatus = (u_char)code;
-
- /* RFC1305: copy only iff not CEVNT_NOMINAL */
- if (code != CEVNT_NOMINAL)
- pp->lastevent = (u_char)code;
-
- if (code == CEVNT_FAULT)
- msyslog(LOG_ERR,
- "clock %s event '%s' (0x%02x)",
- refnumtoa(&peer->srcadr),
- ceventstr(code), code);
- else {
- NLOG(NLOG_CLOCKEVENT)
- msyslog(LOG_INFO,
- "clock %s event '%s' (0x%02x)",
- refnumtoa(&peer->srcadr),
- ceventstr(code), code);
- }
-
- /* RFC1305: post peer clock event */
- report_event(EVNT_PEERCLOCK, peer);
+ report_event(PEVNT_CLOCK, peer, ceventstr(code));
}
}
+
/*
* init_refclock - initialize the reference clock drivers
*
@@ -175,14 +131,11 @@ refclock_report(
void
init_refclock(void)
{
- int i, j;
+ int i;
- for (i = 0; i < (int)num_refclock_conf; i++) {
+ for (i = 0; i < (int)num_refclock_conf; i++)
if (refclock_conf[i]->clock_init != noentry)
(refclock_conf[i]->clock_init)();
- for (j = 0; j < MAXUNIT; j++)
- typeunit[i][j] = 0;
- }
}
@@ -211,12 +164,6 @@ refclock_newpeer(
* Check for valid clock address. If already running, shut it
* down first.
*/
- if (peer->srcadr.ss_family != AF_INET) {
- msyslog(LOG_ERR,
- "refclock_newpeer: clock address %s invalid, address family not implemented for refclock",
- stoa(&peer->srcadr));
- return (0);
- }
if (!ISREFCLOCKADR(&peer->srcadr)) {
msyslog(LOG_ERR,
"refclock_newpeer: clock address %s invalid",
@@ -225,7 +172,7 @@ refclock_newpeer(
}
clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
unit = REFCLOCKUNIT(&peer->srcadr);
- if (clktype >= num_refclock_conf || unit >= MAXUNIT ||
+ if (clktype >= num_refclock_conf ||
refclock_conf[clktype]->clock_start == noentry) {
msyslog(LOG_ERR,
"refclock_newpeer: clock type %d invalid\n",
@@ -236,12 +183,7 @@ refclock_newpeer(
/*
* Allocate and initialize interface structure
*/
- pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc));
- if (pp == NULL)
- return (0);
-
- memset((char *)pp, 0, sizeof(struct refclockproc));
- typeunit[clktype][unit] = peer;
+ pp = emalloc_zero(sizeof(*pp));
peer->procptr = pp;
/*
@@ -249,12 +191,14 @@ refclock_newpeer(
*/
peer->refclktype = clktype;
peer->refclkunit = (u_char)unit;
- peer->flags |= FLAG_REFCLOCK | FLAG_FIXPOLL;
+ peer->flags |= FLAG_REFCLOCK;
peer->leap = LEAP_NOTINSYNC;
peer->stratum = STRATUM_REFCLOCK;
peer->ppoll = peer->maxpoll;
pp->type = clktype;
+ pp->conf = refclock_conf[clktype];
pp->timestarted = current_time;
+ pp->io.fd = -1;
/*
* Set peer.pmode based on the hmode. For appearances only.
@@ -297,7 +241,7 @@ refclock_unpeer(
* Wiggle the driver to release its resources, then give back
* the interface structure.
*/
- if (!peer->procptr)
+ if (NULL == peer->procptr)
return;
clktype = peer->refclktype;
@@ -305,7 +249,7 @@ refclock_unpeer(
if (refclock_conf[clktype]->clock_shutdown != noentry)
(refclock_conf[clktype]->clock_shutdown)(unit, peer);
free(peer->procptr);
- peer->procptr = 0;
+ peer->procptr = NULL;
}
@@ -314,16 +258,18 @@ refclock_unpeer(
*/
void
refclock_timer(
- struct peer *peer /* peer structure pointer */
+ struct peer *p
)
{
- u_char clktype;
- int unit;
-
- clktype = peer->refclktype;
- unit = peer->refclkunit;
- if (refclock_conf[clktype]->clock_timer != noentry)
- (refclock_conf[clktype]->clock_timer)(unit, peer);
+ struct refclockproc * pp;
+ int unit;
+
+ unit = p->refclkunit;
+ pp = p->procptr;
+ if (pp->conf->clock_timer != noentry)
+ (*pp->conf->clock_timer)(unit, p);
+ if (pp->action != NULL && pp->nextaction <= current_time)
+ (*pp->action)(p);
}
@@ -365,19 +311,17 @@ refclock_transmit(
* Update reachability and poll variables like the
* network code.
*/
- oreach = peer->reach;
+ oreach = peer->reach & 0xfe;
peer->reach <<= 1;
+ if (!(peer->reach & 0x0f))
+ clock_filter(peer, 0., 0., MAXDISPERSE);
peer->outdate = current_time;
if (!peer->reach) {
if (oreach) {
- report_event(EVNT_UNREACH, peer);
+ report_event(PEVNT_UNREACH, peer, NULL);
peer->timereachable = current_time;
}
} else {
- if (!(oreach & 0x07)) {
- clock_filter(peer, 0., 0., MAXDISPERSE);
- clock_select();
- }
if (peer->flags & FLAG_BURST)
peer->burst = NSTAGE;
}
@@ -393,7 +337,6 @@ refclock_transmit(
/*
* Compare two doubles - used with qsort()
*/
-#ifdef QSORT_USES_VOID_P
static int
refclock_cmpl_fp(
const void *p1,
@@ -404,30 +347,11 @@ refclock_cmpl_fp(
const double *dp2 = (const double *)p2;
if (*dp1 < *dp2)
- return (-1);
-
- if (*dp1 > *dp2)
- return (1);
-
- return (0);
-}
-
-#else
-static int
-refclock_cmpl_fp(
- const double *dp1,
- const double *dp2
- )
-{
- if (*dp1 < *dp2)
- return (-1);
-
+ return -1;
if (*dp1 > *dp2)
- return (1);
-
- return (0);
+ return 1;
+ return 0;
}
-#endif /* QSORT_USES_VOID_P */
/*
@@ -458,6 +382,7 @@ refclock_process_offset(
/*
* refclock_process - process a sample from the clock
+ * refclock_process_f - refclock_process with other than time1 fudge
*
* This routine converts the timecode in the form days, hours, minutes,
* seconds and milliseconds/microseconds to internal timestamp format,
@@ -472,8 +397,9 @@ refclock_process_offset(
* zero and the fraction for pp->lastrec is set to the PPS offset.
*/
int
-refclock_process(
- struct refclockproc *pp /* refclock structure pointer */
+refclock_process_f(
+ struct refclockproc *pp, /* refclock structure pointer */
+ double fudge
)
{
l_fp offset, ltemp;
@@ -493,12 +419,20 @@ refclock_process(
offset.l_uf = 0;
DTOLFP(pp->nsec / 1e9, &ltemp);
L_ADD(&offset, &ltemp);
- refclock_process_offset(pp, offset, pp->lastrec,
- pp->fudgetime1);
+ refclock_process_offset(pp, offset, pp->lastrec, fudge);
return (1);
}
+int
+refclock_process(
+ struct refclockproc *pp /* refclock structure pointer */
+)
+{
+ return refclock_process_f(pp, pp->fudgetime1);
+}
+
+
/*
* refclock_sample - process a pile of samples from the clock
*
@@ -514,7 +448,7 @@ refclock_sample(
struct refclockproc *pp /* refclock structure pointer */
)
{
- int i, j, k, m, n;
+ size_t i, j, k, m, n;
double off[MAXSTAGE];
double offset;
@@ -532,13 +466,7 @@ refclock_sample(
return (0);
if (n > 1)
- qsort(
-#ifdef QSORT_USES_VOID_P
- (void *)
-#else
- (char *)
-#endif
- off, (size_t)n, sizeof(double), refclock_cmpl_fp);
+ qsort(off, n, sizeof(off[0]), refclock_cmpl_fp);
/*
* Reject the furthest from the median of the samples until
@@ -570,9 +498,9 @@ refclock_sample(
if (debug)
printf(
"refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
- n, pp->offset, pp->disp, pp->jitter);
+ (int)n, pp->offset, pp->disp, pp->jitter);
#endif
- return (n);
+ return (int)n;
}
@@ -611,30 +539,23 @@ refclock_receive(
peer->received++;
peer->timereceived = current_time;
if (!peer->reach) {
- report_event(EVNT_REACH, peer);
+ report_event(PEVNT_REACH, peer, NULL);
peer->timereachable = current_time;
}
peer->reach |= 1;
peer->reftime = pp->lastref;
- peer->org = pp->lastrec;
- peer->rootdispersion = pp->disp;
- get_systime(&peer->rec);
+ peer->aorg = pp->lastrec;
+ peer->rootdisp = pp->disp;
+ get_systime(&peer->dst);
if (!refclock_sample(pp))
return;
clock_filter(peer, pp->offset, 0., pp->jitter);
- record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
- peer->offset, peer->delay, clock_phi * (current_time -
- peer->epoch), peer->jitter);
- if (cal_enable && last_offset < MINDISPERSE) {
-#ifdef KERNEL_PLL
- if (peer != sys_peer || pll_status & STA_PPSTIME)
-#else
- if (peer != sys_peer)
-#endif /* KERNEL_PLL */
+ if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer !=
+ NULL) {
+ if (sys_peer->refclktype == REFCLK_ATOM_PPS &&
+ peer->refclktype != REFCLK_ATOM_PPS)
pp->fudgetime1 -= pp->offset * FUDGEFAC;
- else
- pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC;
}
}
@@ -656,25 +577,39 @@ refclock_gtlin(
l_fp *tsptr /* pointer to timestamp returned */
)
{
- char s[BMAX];
- char *dpt, *dpend, *dp;
+ const char *sp, *spend;
+ char *dp, *dpend;
+ int dlen;
- dpt = s;
- dpend = s + refclock_gtraw(rbufp, s, BMAX - 1, tsptr);
- if (dpend - dpt > bmax - 1)
- dpend = dpt + bmax - 1;
- for (dp = lineptr; dpt < dpend; dpt++) {
- char c;
+ if (bmax <= 0)
+ return (0);
- c = *dpt & 0x7f;
+ dp = lineptr;
+ dpend = dp + bmax - 1; /* leave room for NUL pad */
+ sp = (const char *)rbufp->recv_buffer;
+ spend = sp + rbufp->recv_length;
+
+ while (sp != spend && dp != dpend) {
+ char c;
+
+ c = *sp++ & 0x7f;
if (c >= 0x20 && c < 0x7f)
*dp++ = c;
}
- if (dp == lineptr)
- return (0);
-
- *dp = '\0';
- return (dp - lineptr);
+ /* Get length of data written to the destination buffer. If
+ * zero, do *not* place a NUL byte to preserve the previous
+ * buffer content.
+ */
+ dlen = dp - lineptr;
+ if (dlen)
+ *dp = '\0';
+ *tsptr = rbufp->recv_time;
+ DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n",
+ rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen,
+ (dlen != 0)
+ ? lineptr
+ : ""));
+ return (dlen);
}
@@ -691,9 +626,7 @@ refclock_gtlin(
* followed by a NULL character ('\0'), which is not included in the
* count.
*
- * If a timestamp is present in the timecode, as produced by the tty_clk
- * STREAMS module, it returns that as the timestamp; otherwise, it
- * returns the buffer timestamp.
+ * *tsptr receives a copy of the buffer timestamp.
*/
int
refclock_gtraw(
@@ -703,74 +636,99 @@ refclock_gtraw(
l_fp *tsptr /* pointer to timestamp returned */
)
{
- char *dpt, *dpend, *dp;
- l_fp trtmp, tstmp;
- int i;
+ if (bmax <= 0)
+ return (0);
+ bmax -= 1; /* leave room for trailing NUL */
+ if (bmax > rbufp->recv_length)
+ bmax = rbufp->recv_length;
+ memcpy(lineptr, rbufp->recv_buffer, bmax);
+ lineptr[bmax] = '\0';
+
+ *tsptr = rbufp->recv_time;
+ DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n",
+ rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax,
+ lineptr));
+ return (bmax);
+}
- /*
- * Check for the presence of a timestamp left by the tty_clock
- * module and, if present, use that instead of the buffer
- * timestamp captured by the I/O routines. We recognize a
- * timestamp by noting its value is earlier than the buffer
- * timestamp, but not more than one second earlier.
- */
- dpt = (char *)rbufp->recv_buffer;
- dpend = dpt + rbufp->recv_length;
- trtmp = rbufp->recv_time;
- if (dpend >= dpt + 8) {
- if (buftvtots(dpend - 8, &tstmp)) {
- L_SUB(&trtmp, &tstmp);
- if (trtmp.l_ui == 0) {
-#ifdef DEBUG
- if (debug > 1) {
- printf(
- "refclock_gtlin: fd %d ldisc %s",
- rbufp->fd, lfptoa(&trtmp,
- 6));
- get_systime(&trtmp);
- L_SUB(&trtmp, &tstmp);
- printf(" sigio %s\n",
- lfptoa(&trtmp, 6));
- }
-#endif
- dpend -= 8;
- trtmp = tstmp;
- } else
- trtmp = rbufp->recv_time;
- }
+
+/*
+ * indicate_refclock_packet()
+ *
+ * Passes a fragment of refclock input read from the device to the
+ * driver direct input routine, which may consume it (batch it for
+ * queuing once a logical unit is assembled). If it is not so
+ * consumed, queue it for the driver's receive entrypoint.
+ *
+ * The return value is TRUE if the data has been consumed as a fragment
+ * and should not be counted as a received packet.
+ */
+int
+indicate_refclock_packet(
+ struct refclockio * rio,
+ struct recvbuf * rb
+ )
+{
+ /* Does this refclock use direct input routine? */
+ if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) {
+ /*
+ * data was consumed - nothing to pass up
+ * into block input machine
+ */
+ freerecvbuf(rb);
+
+ return TRUE;
}
+ add_full_recv_buffer(rb);
- /*
- * Copy the raw buffer to the user string. The string is padded
- * with a NULL, which is not included in the character count.
+ return FALSE;
+}
+
+
+/*
+ * process_refclock_packet()
+ *
+ * Used for deferred processing of 'io_input' on systems where threading
+ * is used (notably Windows). This is acting as a trampoline to make the
+ * real calls to the refclock functions.
+ */
+#ifdef HAVE_IO_COMPLETION_PORT
+void
+process_refclock_packet(
+ struct recvbuf * rb
+ )
+{
+ struct refclockio * rio;
+
+ /* get the refclockio structure from the receive buffer */
+ rio = &rb->recv_peer->procptr->io;
+
+ /* call 'clock_recv' if either there is no input function or the
+ * raw input function tells us to feed the packet to the
+ * receiver.
*/
- if (dpend - dpt > bmax - 1)
- dpend = dpt + bmax - 1;
- for (dp = lineptr; dpt < dpend; dpt++)
- *dp++ = *dpt;
- *dp = '\0';
- i = dp - lineptr;
-#ifdef DEBUG
- if (debug > 1)
- printf("refclock_gtraw: fd %d time %s timecode %d %s\n",
- rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
-#endif
- *tsptr = trtmp;
- return (i);
+ if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) {
+ rio->recvcount++;
+ packets_received++;
+ handler_pkts++;
+ (*rio->clock_recv)(rb);
+ }
}
+#endif /* HAVE_IO_COMPLETION_PORT */
/*
* The following code does not apply to WINNT & VMS ...
*/
-#if !defined SYS_VXWORKS && !defined SYS_WINNT
+#if !defined(SYS_VXWORKS) && !defined(SYS_WINNT)
#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
/*
* refclock_open - open serial port for reference clock
*
* This routine opens a serial port for I/O and sets default options. It
- * returns the file descriptor if success and zero if failure.
+ * returns the file descriptor if successful, or logs an error and
+ * returns -1.
*/
int
refclock_open(
@@ -781,6 +739,9 @@ refclock_open(
{
int fd;
int omode;
+#ifdef O_NONBLOCK
+ char trash[128]; /* litter bin for old input data */
+#endif
/*
* Open serial port and set default options
@@ -794,21 +755,41 @@ refclock_open(
#endif
fd = open(dev, omode, 0777);
+ /* refclock_open() long returned 0 on failure, avoid it. */
+ if (0 == fd) {
+ fd = dup(0);
+ SAVE_ERRNO(
+ close(0);
+ )
+ }
if (fd < 0) {
- msyslog(LOG_ERR, "refclock_open %s: %m", dev);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR, "refclock_open %s: %m", dev);
+ )
+ return -1;
}
if (!refclock_setup(fd, speed, lflags)) {
close(fd);
- return (0);
+ return -1;
}
if (!refclock_ioctl(fd, lflags)) {
close(fd);
- return (0);
+ return -1;
}
- return (fd);
+#ifdef O_NONBLOCK
+ /*
+ * We want to make sure there is no pending trash in the input
+ * buffer. Since we have non-blocking IO available, this is a
+ * good moment to read and dump all available outdated stuff
+ * that might have become toxic for the driver.
+ */
+ while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR)
+ /*NOP*/;
+#endif
+ return fd;
}
+
/*
* refclock_setup - initialize terminal interface structure
*/
@@ -821,9 +802,6 @@ refclock_setup(
{
int i;
TTY ttyb, *ttyp;
-#ifdef PPS
- fdpps = fd; /* ppsclock legacy */
-#endif /* PPS */
/*
* By default, the serial line port is initialized in canonical
@@ -840,9 +818,12 @@ refclock_setup(
* POSIX serial line parameters (termios interface)
*/
if (tcgetattr(fd, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d tcgetattr: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d tcgetattr: %m",
+ fd);
+ )
+ return FALSE;
}
/*
@@ -857,7 +838,7 @@ refclock_setup(
ttyp->c_cflag = CS8 | CLOCAL | CREAD;
if (lflags & LDISC_7O1) {
/* HP Z3801A needs 7-bit, odd parity */
- ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
+ ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
}
cfsetispeed(&ttyb, speed);
cfsetospeed(&ttyb, speed);
@@ -896,10 +877,22 @@ refclock_setup(
if (lflags & LDISC_ECHO)
ttyp->c_lflag |= ECHO;
if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TCSANOW: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TCSANOW: %m",
+ fd);
+ )
+ return FALSE;
}
+
+ /*
+ * flush input and output buffers to discard any outdated stuff
+ * that might have become toxic for the driver. Failing to do so
+ * is logged, but we keep our fingers crossed otherwise.
+ */
+ if (tcflush(fd, TCIOFLUSH) < 0)
+ msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m",
+ fd);
#endif /* HAVE_TERMIOS */
#ifdef HAVE_SYSV_TTYS
@@ -909,9 +902,12 @@ refclock_setup(
*
*/
if (ioctl(fd, TCGETA, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TCGETA: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TCGETA: %m",
+ fd);
+ )
+ return FALSE;
}
/*
@@ -957,9 +953,11 @@ refclock_setup(
ttyp->c_cc[VMIN] = 1;
}
if (ioctl(fd, TCSETA, ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TCSETA: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TCSETA: %m", fd);
+ )
+ return FALSE;
}
#endif /* HAVE_SYSV_TTYS */
@@ -969,23 +967,26 @@ refclock_setup(
* 4.3bsd serial line parameters (sgttyb interface)
*/
if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup fd %d TIOCGETP: %m", fd);
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR,
+ "refclock_setup fd %d TIOCGETP: %m",
+ fd);
+ )
+ return FALSE;
}
if (speed)
ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
ttyp->sg_flags = EVENP | ODDP | CRMOD;
if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
- msyslog(LOG_ERR,
- "refclock_setup TIOCSETP: %m");
- return (0);
+ SAVE_ERRNO(
+ msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m");
+ )
+ return FALSE;
}
#endif /* HAVE_BSD_TTYS */
return(1);
}
#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
-#endif /* SYS_VXWORKS SYS_WINNT */
/*
@@ -994,8 +995,8 @@ refclock_setup(
* This routine attempts to hide the internal, system-specific details
* of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
* (sgtty) interfaces with varying degrees of success. The routine sets
- * up optional features such as tty_clk. The routine returns 1 if
- * success and 0 if failure.
+ * up optional features such as tty_clk. The routine returns TRUE if
+ * successful.
*/
int
refclock_ioctl(
@@ -1004,53 +1005,13 @@ refclock_ioctl(
)
{
/*
- * simply return 1 if no UNIX line discipline is supported
- */
-#if !defined SYS_VXWORKS && !defined SYS_WINNT
-#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
-
-#ifdef DEBUG
- if (debug)
- printf("refclock_ioctl: fd %d flags 0x%x\n", fd,
- lflags);
-#endif
-#ifdef TTYCLK
-
- /*
- * The TTYCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module and System V STREAMS
- * support. If not available, don't complain.
+ * simply return TRUE if no UNIX line discipline is supported
*/
- if (lflags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
- int rval = 0;
+ DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags));
- if (ioctl(fd, I_PUSH, "clk") < 0) {
- msyslog(LOG_NOTICE,
- "refclock_ioctl fd %d I_PUSH: %m", fd);
- return (0);
-#ifdef CLK_SETSTR
- } else {
- char *str;
-
- if (lflags & LDISC_CLKPPS)
- str = "\377";
- else if (lflags & LDISC_ACTS)
- str = "*";
- else
- str = "\n";
- if (ioctl(fd, CLK_SETSTR, str) < 0) {
- msyslog(LOG_ERR,
- "refclock_ioctl fd %d CLK_SETSTR: %m", fd);
- return (0);
- }
-#endif /*CLK_SETSTR */
- }
- }
-#endif /* TTYCLK */
-#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
-#endif /* SYS_VXWORKS SYS_WINNT */
- return (1);
+ return TRUE;
}
+#endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */
/*
@@ -1064,8 +1025,8 @@ refclock_ioctl(
*/
void
refclock_control(
- struct sockaddr_storage *srcadr,
- struct refclockstat *in,
+ sockaddr_u *srcadr,
+ const struct refclockstat *in,
struct refclockstat *out
)
{
@@ -1077,30 +1038,24 @@ refclock_control(
/*
* Check for valid address and running peer
*/
- if (srcadr->ss_family != AF_INET)
- return;
-
if (!ISREFCLOCKADR(srcadr))
return;
clktype = (u_char)REFCLOCKTYPE(srcadr);
unit = REFCLOCKUNIT(srcadr);
- if (clktype >= num_refclock_conf || unit >= MAXUNIT)
- return;
- peer = typeunit[clktype][unit];
- if (peer == NULL)
- return;
+ peer = findexistingpeer(srcadr, NULL, NULL, -1, 0);
- if (peer->procptr == NULL)
+ if (NULL == peer)
return;
+ NTP_INSIST(peer->procptr != NULL);
pp = peer->procptr;
/*
* Initialize requested data
*/
- if (in != 0) {
+ if (in != NULL) {
if (in->haveflags & CLK_HAVETIME1)
pp->fudgetime1 = in->fudgetime1;
if (in->haveflags & CLK_HAVETIME2)
@@ -1130,14 +1085,25 @@ refclock_control(
/*
* Readback requested data
*/
- if (out != 0) {
- out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
- CLK_HAVEVAL2 | CLK_HAVEFLAG4;
- out->fudgetime1 = pp->fudgetime1;
- out->fudgetime2 = pp->fudgetime2;
+ if (out != NULL) {
out->fudgeval1 = pp->stratum;
out->fudgeval2 = pp->refid;
+ out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
+ out->fudgetime1 = pp->fudgetime1;
+ if (0.0 != out->fudgetime1)
+ out->haveflags |= CLK_HAVETIME1;
+ out->fudgetime2 = pp->fudgetime2;
+ if (0.0 != out->fudgetime2)
+ out->haveflags |= CLK_HAVETIME2;
out->flags = (u_char) pp->sloppyclockflag;
+ if (CLK_FLAG1 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG1;
+ if (CLK_FLAG2 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG2;
+ if (CLK_FLAG3 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG3;
+ if (CLK_FLAG4 & out->flags)
+ out->haveflags |= CLK_HAVEFLAG4;
out->timereset = current_time - pp->timestarted;
out->polls = pp->polls;
@@ -1149,7 +1115,7 @@ refclock_control(
out->currentstatus = pp->currentstatus;
out->type = pp->type;
out->clockdesc = pp->clockdesc;
- out->lencode = pp->lencode;
+ out->lencode = (u_short)pp->lencode;
out->p_lastcode = pp->a_lastcode;
}
@@ -1170,32 +1136,28 @@ refclock_control(
*/
void
refclock_buginfo(
- struct sockaddr_storage *srcadr, /* clock address */
+ sockaddr_u *srcadr, /* clock address */
struct refclockbug *bug /* output structure */
)
{
struct peer *peer;
struct refclockproc *pp;
- u_char clktype;
+ int clktype;
int unit;
- int i;
+ unsigned u;
/*
* Check for valid address and peer structure
*/
- if (srcadr->ss_family != AF_INET)
- return;
-
if (!ISREFCLOCKADR(srcadr))
return;
clktype = (u_char) REFCLOCKTYPE(srcadr);
unit = REFCLOCKUNIT(srcadr);
- if (clktype >= num_refclock_conf || unit >= MAXUNIT)
- return;
- peer = typeunit[clktype][unit];
- if (peer == NULL)
+ peer = findexistingpeer(srcadr, NULL, NULL, -1, 0);
+
+ if (NULL == peer || NULL == peer->procptr)
return;
pp = peer->procptr;
@@ -1216,8 +1178,8 @@ refclock_buginfo(
bug->stimes = 0xfffffffc;
bug->times[0] = pp->lastref;
bug->times[1] = pp->lastrec;
- for (i = 2; i < (int)bug->ntimes; i++)
- DTOLFP(pp->filter[i - 2], &bug->times[i]);
+ for (u = 2; u < bug->ntimes; u++)
+ DTOLFP(pp->filter[u - 2], &bug->times[u]);
/*
* Give the stuff to the clock
@@ -1226,4 +1188,145 @@ refclock_buginfo(
(refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
}
+
+#ifdef HAVE_PPSAPI
+/*
+ * refclock_ppsapi - initialize/update ppsapi
+ *
+ * This routine is called after the fudge command to open the PPSAPI
+ * interface for later parameter setting after the fudge command.
+ */
+int
+refclock_ppsapi(
+ int fddev, /* fd device */
+ struct refclock_atom *ap /* atom structure pointer */
+ )
+{
+ if (ap->handle == 0) {
+ if (time_pps_create(fddev, &ap->handle) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_ppsapi: time_pps_create: %m");
+ return (0);
+ }
+ }
+ return (1);
+}
+
+
+/*
+ * refclock_params - set ppsapi parameters
+ *
+ * This routine is called to set the PPSAPI parameters after the fudge
+ * command.
+ */
+int
+refclock_params(
+ int mode, /* mode bits */
+ struct refclock_atom *ap /* atom structure pointer */
+ )
+{
+ ZERO(ap->pps_params);
+ ap->pps_params.api_version = PPS_API_VERS_1;
+
+ /*
+ * Solaris serial ports provide PPS pulse capture only on the
+ * assert edge. FreeBSD serial ports provide capture on the
+ * clear edge, while FreeBSD parallel ports provide capture
+ * on the assert edge. Your mileage may vary.
+ */
+ if (mode & CLK_FLAG2)
+ ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR;
+ else
+ ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT;
+ if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_params: time_pps_setparams: %m");
+ return (0);
+ }
+
+ /*
+ * If flag3 is lit, select the kernel PPS if we can.
+ */
+ if (mode & CLK_FLAG3) {
+ if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS,
+ ap->pps_params.mode & ~PPS_TSFMT_TSPEC,
+ PPS_TSFMT_TSPEC) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_params: time_pps_kcbind: %m");
+ return (0);
+ }
+ hardpps_enable = 1;
+ }
+ return (1);
+}
+
+
+/*
+ * refclock_pps - called once per second
+ *
+ * This routine is called once per second. It snatches the PPS
+ * timestamp from the kernel and saves the sign-extended fraction in
+ * a circular buffer for processing at the next poll event.
+ */
+int
+refclock_pps(
+ struct peer *peer, /* peer structure pointer */
+ struct refclock_atom *ap, /* atom structure pointer */
+ int mode /* mode bits */
+ )
+{
+ struct refclockproc *pp;
+ pps_info_t pps_info;
+ struct timespec timeout;
+ double dtemp;
+
+ /*
+ * We require the clock to be synchronized before setting the
+ * parameters. When the parameters have been set, fetch the
+ * most recent PPS timestamp.
+ */
+ pp = peer->procptr;
+ if (ap->handle == 0)
+ return (0);
+
+ if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) {
+ if (refclock_params(pp->sloppyclockflag, ap) < 1)
+ return (0);
+ }
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+ ZERO(pps_info);
+ if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info,
+ &timeout) < 0) {
+ refclock_report(peer, CEVNT_FAULT);
+ return (0);
+ }
+ timeout = ap->ts;
+ if (ap->pps_params.mode & PPS_CAPTUREASSERT)
+ ap->ts = pps_info.assert_timestamp;
+ else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
+ ap->ts = pps_info.clear_timestamp;
+ else
+ return (0);
+
+ if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout)))
+ return (0);
+
+ /*
+ * Convert to signed fraction offset and stuff in median filter.
+ */
+ pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970;
+ dtemp = ap->ts.tv_nsec / 1e9;
+ pp->lastrec.l_uf = (u_int32)(dtemp * FRAC);
+ if (dtemp > .5)
+ dtemp -= 1.;
+ SAMPLE(-dtemp + pp->fudgetime1);
+#ifdef DEBUG
+ if (debug > 1)
+ printf("refclock_pps: %lu %f %f\n", current_time,
+ dtemp, pp->fudgetime1);
+#endif
+ return (1);
+}
+#endif /* HAVE_PPSAPI */
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c
index 6d47956..8ffebad 100644
--- a/contrib/ntp/ntpd/ntp_request.c
+++ b/contrib/ntp/ntpd/ntp_request.c
@@ -13,11 +13,14 @@
#include "ntp_refclock.h"
#include "ntp_if.h"
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
#include <stdio.h>
#include <stddef.h>
#include <signal.h>
+#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
+#endif
#include <arpa/inet.h>
#include "recvbuff.h"
@@ -47,77 +50,78 @@ struct req_proc {
short needs_auth; /* true when authentication needed */
short sizeofitem; /* size of request data item (older size)*/
short v6_sizeofitem; /* size of request data item (new size)*/
- void (*handler) P((struct sockaddr_storage *, struct interface *,
- struct req_pkt *)); /* routine to handle request */
+ void (*handler) (sockaddr_u *, endpt *,
+ struct req_pkt *); /* routine to handle request */
};
/*
* Universal request codes
*/
-static struct req_proc univ_codes[] = {
- { NO_REQUEST, NOAUTH, 0, 0 }
+static const struct req_proc univ_codes[] = {
+ { NO_REQUEST, NOAUTH, 0, 0, NULL }
};
-static void req_ack P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));
-static char * prepare_pkt P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_int));
-static char * more_pkt P((void));
-static void flush_pkt P((void));
-static void peer_list P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void peer_list_sum P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void peer_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void peer_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void sys_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void sys_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void mem_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void io_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void timer_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void loop_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_conf P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_unconf P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void set_sys_flag P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void clr_sys_flag P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void setclr_flags P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long));
-static void list_restrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_resaddflags P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_ressubflags P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_unrestrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_restrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));
-static void mon_getlist_0 P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void mon_getlist_1 P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void reset_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void reset_peer P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_key_reread P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void trust_key P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void untrust_key P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_trustkey P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long));
-static void get_auth_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void reset_auth_stats P((void));
-static void req_get_traps P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void req_set_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void req_clr_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_setclr_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));
-static void set_request_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void set_control_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void get_ctl_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void get_if_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void do_if_reload P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
+static void req_ack (sockaddr_u *, endpt *, struct req_pkt *, int);
+static void * prepare_pkt (sockaddr_u *, endpt *,
+ struct req_pkt *, size_t);
+static void * more_pkt (void);
+static void flush_pkt (void);
+static void list_peers (sockaddr_u *, endpt *, struct req_pkt *);
+static void list_peers_sum (sockaddr_u *, endpt *, struct req_pkt *);
+static void peer_info (sockaddr_u *, endpt *, struct req_pkt *);
+static void peer_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void sys_info (sockaddr_u *, endpt *, struct req_pkt *);
+static void sys_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void mem_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void io_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void timer_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void loop_info (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_conf (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_unconf (sockaddr_u *, endpt *, struct req_pkt *);
+static void set_sys_flag (sockaddr_u *, endpt *, struct req_pkt *);
+static void clr_sys_flag (sockaddr_u *, endpt *, struct req_pkt *);
+static void setclr_flags (sockaddr_u *, endpt *, struct req_pkt *, u_long);
+static void list_restrict4 (restrict_u *, struct info_restrict **);
+static void list_restrict6 (restrict_u *, struct info_restrict **);
+static void list_restrict (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_resaddflags (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_ressubflags (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_unrestrict (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_restrict (sockaddr_u *, endpt *, struct req_pkt *, int);
+static void mon_getlist (sockaddr_u *, endpt *, struct req_pkt *);
+static void reset_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void reset_peer (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_key_reread (sockaddr_u *, endpt *, struct req_pkt *);
+static void trust_key (sockaddr_u *, endpt *, struct req_pkt *);
+static void untrust_key (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_trustkey (sockaddr_u *, endpt *, struct req_pkt *, u_long);
+static void get_auth_info (sockaddr_u *, endpt *, struct req_pkt *);
+static void req_get_traps (sockaddr_u *, endpt *, struct req_pkt *);
+static void req_set_trap (sockaddr_u *, endpt *, struct req_pkt *);
+static void req_clr_trap (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_setclr_trap (sockaddr_u *, endpt *, struct req_pkt *, int);
+static void set_request_keyid (sockaddr_u *, endpt *, struct req_pkt *);
+static void set_control_keyid (sockaddr_u *, endpt *, struct req_pkt *);
+static void get_ctl_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void get_if_stats (sockaddr_u *, endpt *, struct req_pkt *);
+static void do_if_reload (sockaddr_u *, endpt *, struct req_pkt *);
#ifdef KERNEL_PLL
-static void get_kernel_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
+static void get_kernel_info (sockaddr_u *, endpt *, struct req_pkt *);
#endif /* KERNEL_PLL */
#ifdef REFCLOCK
-static void get_clock_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
-static void set_clock_fudge P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
+static void get_clock_info (sockaddr_u *, endpt *, struct req_pkt *);
+static void set_clock_fudge (sockaddr_u *, endpt *, struct req_pkt *);
#endif /* REFCLOCK */
#ifdef REFCLOCK
-static void get_clkbug_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
+static void get_clkbug_info (sockaddr_u *, endpt *, struct req_pkt *);
#endif /* REFCLOCK */
/*
* ntpd request codes
*/
-static struct req_proc ntp_codes[] = {
- { REQ_PEER_LIST, NOAUTH, 0, 0, peer_list },
- { REQ_PEER_LIST_SUM, NOAUTH, 0, 0, peer_list_sum },
+static const struct req_proc ntp_codes[] = {
+ { REQ_PEER_LIST, NOAUTH, 0, 0, list_peers },
+ { REQ_PEER_LIST_SUM, NOAUTH, 0, 0, list_peers_sum },
{ REQ_PEER_INFO, NOAUTH, v4sizeof(struct info_peer_list),
sizeof(struct info_peer_list), peer_info},
{ REQ_PEER_STATS, NOAUTH, v4sizeof(struct info_peer_list),
@@ -143,8 +147,8 @@ static struct req_proc ntp_codes[] = {
sizeof(struct conf_restrict), do_ressubflags },
{ REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict),
sizeof(struct conf_restrict), do_unrestrict },
- { REQ_MON_GETLIST, NOAUTH, 0, 0, mon_getlist_0 },
- { REQ_MON_GETLIST_1, NOAUTH, 0, 0, mon_getlist_1 },
+ { REQ_MON_GETLIST, NOAUTH, 0, 0, mon_getlist },
+ { REQ_MON_GETLIST_1, NOAUTH, 0, 0, mon_getlist },
{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats },
{ REQ_RESET_PEER, AUTH, v4sizeof(struct conf_unpeer),
sizeof(struct conf_unpeer), reset_peer },
@@ -174,7 +178,7 @@ static struct req_proc ntp_codes[] = {
get_clkbug_info },
#endif
{ REQ_IF_STATS, AUTH, 0, 0, get_if_stats },
- { REQ_IF_RELOAD, AUTH, 0, 0, do_if_reload },
+ { REQ_IF_RELOAD, AUTH, 0, 0, do_if_reload },
{ NO_REQUEST, NOAUTH, 0, 0, 0 }
};
@@ -192,14 +196,16 @@ keyid_t info_auth_keyid;
u_long numrequests; /* number of requests we've received */
u_long numresppkts; /* number of resp packets sent with data */
-u_long errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */
-/* by the error code */
+/*
+ * lazy way to count errors, indexed by the error code
+ */
+u_long errorcounter[MAX_INFO_ERR + 1];
/*
* A hack. To keep the authentication module clear of ntp-ism's, we
* include a time reset variable for its stats here.
*/
-static u_long auth_timereset;
+u_long auth_timereset;
/*
* Response packet used by these routines. Also some state information
@@ -216,8 +222,8 @@ static int itemsize;
static int databytes;
static char exbuf[RESP_DATA_SIZE];
static int usingexbuf;
-static struct sockaddr_storage *toaddr;
-static struct interface *frominter;
+static sockaddr_u *toaddr;
+static endpt *frominter;
/*
* init_request - initialize request data
@@ -225,7 +231,7 @@ static struct interface *frominter;
void
init_request (void)
{
- int i;
+ size_t i;
numrequests = 0;
numresppkts = 0;
@@ -242,8 +248,8 @@ init_request (void)
*/
static void
req_ack(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt,
int errcode
)
@@ -255,7 +261,7 @@ req_ack(
rpkt.auth_seq = AUTH_SEQ(0, 0);
rpkt.implementation = inpkt->implementation;
rpkt.request = inpkt->request;
- rpkt.err_nitems = ERR_NITEMS(errcode, 0);
+ rpkt.err_nitems = ERR_NITEMS(errcode, 0);
rpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
/*
@@ -270,18 +276,15 @@ req_ack(
* prepare_pkt - prepare response packet for transmission, return pointer
* to storage for data item.
*/
-static char *
+static void *
prepare_pkt(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *pkt,
- u_int structsize
+ size_t structsize
)
{
-#ifdef DEBUG
- if (debug > 3)
- printf("request: preparing pkt\n");
-#endif
+ DPRINTF(4, ("request: preparing pkt\n"));
/*
* Fill in the implementation, request and itemsize fields
@@ -305,35 +308,32 @@ prepare_pkt(
/*
* return the beginning of the packet buffer.
*/
- return &rpkt.data[0];
+ return &rpkt.u;
}
/*
* more_pkt - return a data pointer for a new item.
*/
-static char *
+static void *
more_pkt(void)
{
/*
* If we were using the extra buffer, send the packet.
*/
if (usingexbuf) {
-#ifdef DEBUG
- if (debug > 2)
- printf("request: sending pkt\n");
-#endif
+ DPRINTF(3, ("request: sending pkt\n"));
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
rpkt.err_nitems = htons((u_short)nitems);
sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
- RESP_HEADER_SIZE+databytes);
+ RESP_HEADER_SIZE + databytes);
numresppkts++;
/*
* Copy data out of exbuf into the packet.
*/
- memmove(&rpkt.data[0], exbuf, (unsigned)itemsize);
+ memcpy(&rpkt.u.data[0], exbuf, (unsigned)itemsize);
seqno++;
databytes = 0;
nitems = 0;
@@ -343,26 +343,20 @@ more_pkt(void)
databytes += itemsize;
nitems++;
if (databytes + itemsize <= RESP_DATA_SIZE) {
-#ifdef DEBUG
- if (debug > 3)
- printf("request: giving him more data\n");
-#endif
+ DPRINTF(4, ("request: giving him more data\n"));
/*
* More room in packet. Give him the
* next address.
*/
- return &rpkt.data[databytes];
+ return &rpkt.u.data[databytes];
} else {
/*
* No room in packet. Give him the extra
* buffer unless this was the last in the sequence.
*/
-#ifdef DEBUG
- if (debug > 3)
- printf("request: into extra buffer\n");
-#endif
+ DPRINTF(4, ("request: into extra buffer\n"));
if (seqno == MAXSEQ)
- return (char *)0;
+ return NULL;
else {
usingexbuf = 1;
return exbuf;
@@ -377,17 +371,14 @@ more_pkt(void)
static void
flush_pkt(void)
{
-#ifdef DEBUG
- if (debug > 2)
- printf("request: flushing packet, %d items\n", nitems);
-#endif
+ DPRINTF(3, ("request: flushing packet, %d items\n", nitems));
/*
* Must send the last packet. If nothing in here and nothing
* has been sent, send an error saying no data to be found.
*/
if (seqno == 0 && nitems == 0)
- req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
- INFO_ERR_NODATA);
+ req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
+ INFO_ERR_NODATA);
else {
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
@@ -401,6 +392,17 @@ flush_pkt(void)
/*
+ * Given a buffer, return the packet mode
+ */
+int
+get_packet_mode(struct recvbuf *rbufp)
+{
+ struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt;
+ return (INFO_MODE(inpkt->rm_vn_mode));
+}
+
+
+/*
* process_private - process private mode (7) packets
*/
void
@@ -412,24 +414,27 @@ process_private(
static u_long quiet_until;
struct req_pkt *inpkt;
struct req_pkt_tail *tailinpkt;
- struct sockaddr_storage *srcadr;
- struct interface *inter;
- struct req_proc *proc;
+ sockaddr_u *srcadr;
+ endpt *inter;
+ const struct req_proc *proc;
int ec;
short temp_size;
+ l_fp ftmp;
+ double dtemp;
+ size_t recv_len;
+ size_t noslop_len;
+ size_t mac_len;
/*
* Initialize pointers, for convenience
*/
+ recv_len = rbufp->recv_length;
inpkt = (struct req_pkt *)&rbufp->recv_pkt;
srcadr = &rbufp->recv_srcadr;
inter = rbufp->dstadr;
-#ifdef DEBUG
- if (debug > 2)
- printf("process_private: impl %d req %d\n",
- inpkt->implementation, inpkt->request);
-#endif
+ DPRINTF(3, ("process_private: impl %d req %d\n",
+ inpkt->implementation, inpkt->request));
/*
* Do some sanity checks on the packet. Return a format
@@ -443,7 +448,7 @@ process_private(
|| (++ec, INFO_SEQ(inpkt->auth_seq) != 0)
|| (++ec, INFO_ERR(inpkt->err_nitems) != 0)
|| (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0)
- || (++ec, rbufp->recv_length < REQ_LEN_HDR)
+ || (++ec, rbufp->recv_length < (int)REQ_LEN_HDR)
) {
NLOG(NLOG_SYSEVENT)
if (current_time >= quiet_until) {
@@ -462,10 +467,10 @@ process_private(
* Get the appropriate procedure list to search.
*/
if (inpkt->implementation == IMPL_UNIV)
- proc = univ_codes;
+ proc = univ_codes;
else if ((inpkt->implementation == IMPL_XNTPD) ||
(inpkt->implementation == IMPL_XNTPD_OLD))
- proc = ntp_codes;
+ proc = ntp_codes;
else {
req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
return;
@@ -477,7 +482,7 @@ process_private(
*/
while (proc->request_code != NO_REQUEST) {
if (proc->request_code == (short) inpkt->request)
- break;
+ break;
proc++;
}
if (proc->request_code == NO_REQUEST) {
@@ -485,10 +490,7 @@ process_private(
return;
}
-#ifdef DEBUG
- if (debug > 3)
- printf("found request in tables\n");
-#endif
+ DPRINTF(4, ("found request in tables\n"));
/*
* If we need data, check to see if we have some. If we
@@ -507,21 +509,15 @@ process_private(
!(inpkt->implementation == IMPL_XNTPD &&
inpkt->request == REQ_CONFIG &&
temp_size == sizeof(struct old_conf_peer))) {
-#ifdef DEBUG
- if (debug > 2)
- printf("process_private: wrong item size, received %d, should be %d or %d\n",
- temp_size, proc->sizeofitem, proc->v6_sizeofitem);
-#endif
+ DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n",
+ temp_size, proc->sizeofitem, proc->v6_sizeofitem));
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if ((proc->sizeofitem != 0) &&
- ((temp_size * INFO_NITEMS(inpkt->err_nitems)) >
- (rbufp->recv_length - REQ_LEN_HDR))) {
-#ifdef DEBUG
- if (debug > 2)
- printf("process_private: not enough data\n");
-#endif
+ ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) >
+ (recv_len - REQ_LEN_HDR))) {
+ DPRINTF(3, ("process_private: not enough data\n"));
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
@@ -547,58 +543,80 @@ process_private(
* time stamp.
*/
if (proc->needs_auth && sys_authenticate) {
- l_fp ftmp;
- double dtemp;
-
- if (rbufp->recv_length < (int)((REQ_LEN_HDR +
+
+ if (recv_len < (REQ_LEN_HDR +
(INFO_ITEMSIZE(inpkt->mbz_itemsize) *
- INFO_NITEMS(inpkt->err_nitems))
- + sizeof(struct req_pkt_tail)))) {
+ INFO_NITEMS(inpkt->err_nitems)) +
+ REQ_TAIL_MIN)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
+ return;
}
- tailinpkt = (struct req_pkt_tail *)((char *)&rbufp->recv_pkt +
- rbufp->recv_length - sizeof(struct req_pkt_tail));
/*
- * If this guy is restricted from doing this, don't let him
- * If wrong key was used, or packet doesn't have mac, return.
+ * For 16-octet digests, regardless of itemsize and
+ * nitems, authenticated requests are a fixed size
+ * with the timestamp, key ID, and digest located
+ * at the end of the packet. Because the key ID
+ * determining the digest size precedes the digest,
+ * for larger digests the fixed size request scheme
+ * is abandoned and the timestamp, key ID, and digest
+ * are located relative to the start of the packet,
+ * with the digest size determined by the packet size.
*/
- if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0
+ noslop_len = REQ_LEN_HDR
+ + INFO_ITEMSIZE(inpkt->mbz_itemsize) *
+ INFO_NITEMS(inpkt->err_nitems)
+ + sizeof(inpkt->tstamp);
+ /* 32-bit alignment */
+ noslop_len = (noslop_len + 3) & ~3;
+ if (recv_len > (noslop_len + MAX_MAC_LEN))
+ mac_len = 20;
+ else
+ mac_len = recv_len - noslop_len;
+
+ tailinpkt = (void *)((char *)inpkt + recv_len -
+ (mac_len + sizeof(inpkt->tstamp)));
+
+ /*
+ * If this guy is restricted from doing this, don't let
+ * him. If the wrong key was used, or packet doesn't
+ * have mac, return.
+ */
+ if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid
|| ntohl(tailinpkt->keyid) != info_auth_keyid) {
+ DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
+ INFO_IS_AUTH(inpkt->auth_seq),
+ info_auth_keyid,
+ ntohl(tailinpkt->keyid), (u_long)mac_len));
#ifdef DEBUG
- if (debug > 4)
- printf("failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
- INFO_IS_AUTH(inpkt->auth_seq),
- (u_long)info_auth_keyid,
- (u_long)ntohl(tailinpkt->keyid));
msyslog(LOG_DEBUG,
- "process_private: failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
+ "process_private: failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
INFO_IS_AUTH(inpkt->auth_seq),
- (u_long)info_auth_keyid,
- (u_long)ntohl(tailinpkt->keyid));
+ info_auth_keyid,
+ ntohl(tailinpkt->keyid), (u_long)mac_len);
#endif
req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
return;
}
- if (rbufp->recv_length > REQ_LEN_MAC) {
-#ifdef DEBUG
- if (debug > 4)
- printf("bad pkt length %d\n",
- rbufp->recv_length);
-#endif
- msyslog(LOG_ERR, "process_private: bad pkt length %d",
- rbufp->recv_length);
+ if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) {
+ DPRINTF(5, ("bad pkt length %zu\n", recv_len));
+ msyslog(LOG_ERR,
+ "process_private: bad pkt length %zu",
+ recv_len);
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if (!mod_okay || !authhavekey(info_auth_keyid)) {
+ DPRINTF(5, ("failed auth mod_okay %d\n",
+ mod_okay));
#ifdef DEBUG
- if (debug > 4)
- printf("failed auth mod_okay %d\n", mod_okay);
msyslog(LOG_DEBUG,
"process_private: failed auth mod_okay %d\n",
mod_okay);
#endif
+ if (!mod_okay) {
+ sys_restricted++;
+ }
req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
return;
}
@@ -610,14 +628,12 @@ process_private(
NTOHL_FP(&tailinpkt->tstamp, &ftmp);
L_SUB(&ftmp, &rbufp->recv_time);
LFPTOD(&ftmp, dtemp);
- if (fabs(dtemp) >= INFO_TS_MAXSKEW) {
+ if (fabs(dtemp) > INFO_TS_MAXSKEW) {
/*
* He's a loser. Tell him.
*/
-#ifdef DEBUG
- if (debug > 4)
- printf("xmit/rcv timestamp delta > INFO_TS_MAXSKEW\n");
-#endif
+ DPRINTF(5, ("xmit/rcv timestamp delta %g > INFO_TS_MAXSKEW %g\n",
+ dtemp, INFO_TS_MAXSKEW));
req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
return;
}
@@ -626,22 +642,14 @@ process_private(
* So far so good. See if decryption works out okay.
*/
if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
- rbufp->recv_length - sizeof(struct req_pkt_tail) +
- REQ_LEN_HDR, sizeof(struct req_pkt_tail) - REQ_LEN_HDR)) {
-#ifdef DEBUG
- if (debug > 4)
- printf("authdecrypt failed\n");
-#endif
+ recv_len - mac_len, mac_len)) {
+ DPRINTF(5, ("authdecrypt failed\n"));
req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
return;
}
}
-#ifdef DEBUG
- if (debug > 3)
- printf("process_private: all okay, into handler\n");
-#endif
-
+ DPRINTF(3, ("process_private: all okay, into handler\n"));
/*
* Packet is okay. Call the handler to send him data.
*/
@@ -650,162 +658,149 @@ process_private(
/*
- * peer_list - send a list of the peers
+ * list_peers - send a list of the peers
*/
static void
-peer_list(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+list_peers(
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_peer_list *ip;
- register struct peer *pp;
- register int i;
- register int skip = 0;
+ struct info_peer_list *ip;
+ struct peer *pp;
+ int skip = 0;
ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
v6sizeof(struct info_peer_list));
- for (i = 0; i < NTP_HASH_SIZE && ip != 0; i++) {
- pp = peer_hash[i];
- while (pp != 0 && ip != 0) {
- if (pp->srcadr.ss_family == AF_INET6) {
- if (client_v6_capable) {
- ip->addr6 = GET_INADDR6(pp->srcadr);
- ip->v6_flag = 1;
- skip = 0;
- } else {
- skip = 1;
- break;
- }
- } else {
- ip->addr = GET_INADDR(pp->srcadr);
- if (client_v6_capable)
- ip->v6_flag = 0;
+ for (pp = peer_list; pp != NULL && ip != NULL; pp = pp->p_link) {
+ if (IS_IPV6(&pp->srcadr)) {
+ if (client_v6_capable) {
+ ip->addr6 = SOCK_ADDR6(&pp->srcadr);
+ ip->v6_flag = 1;
skip = 0;
+ } else {
+ skip = 1;
+ break;
}
+ } else {
+ ip->addr = NSRCADR(&pp->srcadr);
+ if (client_v6_capable)
+ ip->v6_flag = 0;
+ skip = 0;
+ }
- if(!skip) {
- ip->port = NSRCPORT(&pp->srcadr);
- ip->hmode = pp->hmode;
- ip->flags = 0;
- if (pp->flags & FLAG_CONFIG)
- ip->flags |= INFO_FLAG_CONFIG;
- if (pp == sys_peer)
- ip->flags |= INFO_FLAG_SYSPEER;
- if (pp->status == CTL_PST_SEL_SYNCCAND)
- ip->flags |= INFO_FLAG_SEL_CANDIDATE;
- if (pp->status >= CTL_PST_SEL_SYSPEER)
- ip->flags |= INFO_FLAG_SHORTLIST;
- ip = (struct info_peer_list *)more_pkt();
- }
- pp = pp->next;
+ if (!skip) {
+ ip->port = NSRCPORT(&pp->srcadr);
+ ip->hmode = pp->hmode;
+ ip->flags = 0;
+ if (pp->flags & FLAG_CONFIG)
+ ip->flags |= INFO_FLAG_CONFIG;
+ if (pp == sys_peer)
+ ip->flags |= INFO_FLAG_SYSPEER;
+ if (pp->status == CTL_PST_SEL_SYNCCAND)
+ ip->flags |= INFO_FLAG_SEL_CANDIDATE;
+ if (pp->status >= CTL_PST_SEL_SYSPEER)
+ ip->flags |= INFO_FLAG_SHORTLIST;
+ ip = (struct info_peer_list *)more_pkt();
}
- }
+ } /* for pp */
+
flush_pkt();
}
/*
- * peer_list_sum - return extended peer list
+ * list_peers_sum - return extended peer list
*/
static void
-peer_list_sum(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+list_peers_sum(
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
register struct info_peer_summary *ips;
register struct peer *pp;
- register int i;
l_fp ltmp;
register int skip;
-#ifdef DEBUG
- if (debug > 2)
- printf("wants peer list summary\n");
-#endif
+ DPRINTF(3, ("wants peer list summary\n"));
+
ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt,
v6sizeof(struct info_peer_summary));
- for (i = 0; i < NTP_HASH_SIZE && ips != 0; i++) {
- pp = peer_hash[i];
- while (pp != 0 && ips != 0) {
-#ifdef DEBUG
- if (debug > 3)
- printf("sum: got one\n");
-#endif
- /*
- * Be careful here not to return v6 peers when we
- * want only v4.
- */
- if (pp->srcadr.ss_family == AF_INET6) {
- if (client_v6_capable) {
- ips->srcadr6 = GET_INADDR6(pp->srcadr);
- ips->v6_flag = 1;
- if (pp->dstadr)
- ips->dstadr6 = GET_INADDR6(pp->dstadr->sin);
- else
- memset(&ips->dstadr6, 0, sizeof(ips->dstadr6));
- skip = 0;
- } else {
- skip = 1;
- break;
- }
- } else {
- ips->srcadr = GET_INADDR(pp->srcadr);
- if (client_v6_capable)
- ips->v6_flag = 0;
-/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */
-
+ for (pp = peer_list; pp != NULL && ips != NULL; pp = pp->p_link) {
+ DPRINTF(4, ("sum: got one\n"));
+ /*
+ * Be careful here not to return v6 peers when we
+ * want only v4.
+ */
+ if (IS_IPV6(&pp->srcadr)) {
+ if (client_v6_capable) {
+ ips->srcadr6 = SOCK_ADDR6(&pp->srcadr);
+ ips->v6_flag = 1;
if (pp->dstadr)
- ips->dstadr = (pp->processed) ?
- pp->cast_flags == MDF_BCAST ?
- GET_INADDR(pp->dstadr->bcast):
- pp->cast_flags ?
- GET_INADDR(pp->dstadr->sin) ?
- GET_INADDR(pp->dstadr->sin):
- GET_INADDR(pp->dstadr->bcast):
- 1 : GET_INADDR(pp->dstadr->sin);
+ ips->dstadr6 = SOCK_ADDR6(&pp->dstadr->sin);
else
- memset(&ips->dstadr, 0, sizeof(ips->dstadr));
-
+ ZERO(ips->dstadr6);
skip = 0;
+ } else {
+ skip = 1;
+ break;
}
+ } else {
+ ips->srcadr = NSRCADR(&pp->srcadr);
+ if (client_v6_capable)
+ ips->v6_flag = 0;
- if (!skip){
- ips->srcport = NSRCPORT(&pp->srcadr);
- ips->stratum = pp->stratum;
- ips->hpoll = pp->hpoll;
- ips->ppoll = pp->ppoll;
- ips->reach = pp->reach;
- ips->flags = 0;
- if (pp == sys_peer)
- ips->flags |= INFO_FLAG_SYSPEER;
- if (pp->flags & FLAG_CONFIG)
- ips->flags |= INFO_FLAG_CONFIG;
- if (pp->flags & FLAG_REFCLOCK)
- ips->flags |= INFO_FLAG_REFCLOCK;
- if (pp->flags & FLAG_AUTHENABLE)
- ips->flags |= INFO_FLAG_AUTHENABLE;
- if (pp->flags & FLAG_PREFER)
- ips->flags |= INFO_FLAG_PREFER;
- if (pp->flags & FLAG_BURST)
- ips->flags |= INFO_FLAG_BURST;
- if (pp->status == CTL_PST_SEL_SYNCCAND)
- ips->flags |= INFO_FLAG_SEL_CANDIDATE;
- if (pp->status >= CTL_PST_SEL_SYSPEER)
- ips->flags |= INFO_FLAG_SHORTLIST;
- ips->hmode = pp->hmode;
- ips->delay = HTONS_FP(DTOFP(pp->delay));
- DTOLFP(pp->offset, &ltmp);
- HTONL_FP(&ltmp, &ips->offset);
- ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
- }
- pp = pp->next;
- ips = (struct info_peer_summary *)more_pkt();
+ if (pp->dstadr) {
+ if (!pp->processed)
+ ips->dstadr = NSRCADR(&pp->dstadr->sin);
+ else {
+ if (MDF_BCAST == pp->cast_flags)
+ ips->dstadr = NSRCADR(&pp->dstadr->bcast);
+ else if (pp->cast_flags) {
+ ips->dstadr = NSRCADR(&pp->dstadr->sin);
+ if (!ips->dstadr)
+ ips->dstadr = NSRCADR(&pp->dstadr->bcast);
+ }
+ }
+ } else
+ ips->dstadr = 0;
+
+ skip = 0;
}
- }
+
+ if (!skip) {
+ ips->srcport = NSRCPORT(&pp->srcadr);
+ ips->stratum = pp->stratum;
+ ips->hpoll = pp->hpoll;
+ ips->ppoll = pp->ppoll;
+ ips->reach = pp->reach;
+ ips->flags = 0;
+ if (pp == sys_peer)
+ ips->flags |= INFO_FLAG_SYSPEER;
+ if (pp->flags & FLAG_CONFIG)
+ ips->flags |= INFO_FLAG_CONFIG;
+ if (pp->flags & FLAG_REFCLOCK)
+ ips->flags |= INFO_FLAG_REFCLOCK;
+ if (pp->flags & FLAG_PREFER)
+ ips->flags |= INFO_FLAG_PREFER;
+ if (pp->flags & FLAG_BURST)
+ ips->flags |= INFO_FLAG_BURST;
+ if (pp->status == CTL_PST_SEL_SYNCCAND)
+ ips->flags |= INFO_FLAG_SEL_CANDIDATE;
+ if (pp->status >= CTL_PST_SEL_SYSPEER)
+ ips->flags |= INFO_FLAG_SHORTLIST;
+ ips->hmode = pp->hmode;
+ ips->delay = HTONS_FP(DTOFP(pp->delay));
+ DTOLFP(pp->offset, &ltmp);
+ HTONL_FP(&ltmp, &ips->offset);
+ ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
+ }
+ ips = (struct info_peer_summary *)more_pkt();
+ } /* for pp */
+
flush_pkt();
}
@@ -815,88 +810,98 @@ peer_list_sum(
*/
static void
peer_info (
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_peer_list *ipl;
- register struct peer *pp;
- register struct info_peer *ip;
- register int items;
- register int i, j;
- struct sockaddr_storage addr;
- extern struct peer *sys_peer;
- l_fp ltmp;
+ u_short items;
+ size_t item_sz;
+ char * datap;
+ struct info_peer_list ipl;
+ struct peer * pp;
+ struct info_peer * ip;
+ int i;
+ int j;
+ sockaddr_u addr;
+ l_fp ltmp;
- memset((char *)&addr, 0, sizeof addr);
items = INFO_NITEMS(inpkt->err_nitems);
- ipl = (struct info_peer_list *) inpkt->data;
-
- ip = (struct info_peer *)prepare_pkt(srcadr, inter, inpkt,
- v6sizeof(struct info_peer));
- while (items-- > 0 && ip != 0) {
- memset((char *)&addr, 0, sizeof(addr));
- NSRCPORT(&addr) = ipl->port;
- if (client_v6_capable && ipl->v6_flag != 0) {
- addr.ss_family = AF_INET6;
- GET_INADDR6(addr) = ipl->addr6;
+ item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
+ datap = inpkt->u.data;
+ if (item_sz != sizeof(ipl)) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
+ return;
+ }
+ ip = prepare_pkt(srcadr, inter, inpkt,
+ v6sizeof(struct info_peer));
+ while (items-- > 0 && ip != NULL) {
+ ZERO(ipl);
+ memcpy(&ipl, datap, item_sz);
+ ZERO_SOCK(&addr);
+ NSRCPORT(&addr) = ipl.port;
+ if (client_v6_capable && ipl.v6_flag) {
+ AF(&addr) = AF_INET6;
+ SOCK_ADDR6(&addr) = ipl.addr6;
} else {
- addr.ss_family = AF_INET;
- GET_INADDR(addr) = ipl->addr;
+ AF(&addr) = AF_INET;
+ NSRCADR(&addr) = ipl.addr;
}
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- addr.ss_len = SOCKLEN(&addr);
+#ifdef ISC_PLATFORM_HAVESALEN
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
- ipl++;
- if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0)
- continue;
- if (pp->srcadr.ss_family == AF_INET6) {
+ datap += item_sz;
+
+ pp = findexistingpeer(&addr, NULL, NULL, -1, 0);
+ if (NULL == pp)
+ continue;
+ if (IS_IPV6(srcadr)) {
if (pp->dstadr)
- ip->dstadr6 = pp->cast_flags == MDF_BCAST ?
- GET_INADDR6(pp->dstadr->bcast) :
- GET_INADDR6(pp->dstadr->sin);
+ ip->dstadr6 =
+ (MDF_BCAST == pp->cast_flags)
+ ? SOCK_ADDR6(&pp->dstadr->bcast)
+ : SOCK_ADDR6(&pp->dstadr->sin);
else
- memset(&ip->dstadr6, 0, sizeof(ip->dstadr6));
+ ZERO(ip->dstadr6);
- ip->srcadr6 = GET_INADDR6(pp->srcadr);
+ ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
ip->v6_flag = 1;
} else {
-/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */
- if (pp->dstadr)
- ip->dstadr = (pp->processed) ?
- pp->cast_flags == MDF_BCAST ?
- GET_INADDR(pp->dstadr->bcast):
- pp->cast_flags ?
- GET_INADDR(pp->dstadr->sin) ?
- GET_INADDR(pp->dstadr->sin):
- GET_INADDR(pp->dstadr->bcast):
- 2 : GET_INADDR(pp->dstadr->sin);
- else
- memset(&ip->dstadr, 0, sizeof(ip->dstadr));
+ if (pp->dstadr) {
+ if (!pp->processed)
+ ip->dstadr = NSRCADR(&pp->dstadr->sin);
+ else {
+ if (MDF_BCAST == pp->cast_flags)
+ ip->dstadr = NSRCADR(&pp->dstadr->bcast);
+ else if (pp->cast_flags) {
+ ip->dstadr = NSRCADR(&pp->dstadr->sin);
+ if (!ip->dstadr)
+ ip->dstadr = NSRCADR(&pp->dstadr->bcast);
+ }
+ }
+ } else
+ ip->dstadr = 0;
- ip->srcadr = GET_INADDR(pp->srcadr);
+ ip->srcadr = NSRCADR(&pp->srcadr);
if (client_v6_capable)
ip->v6_flag = 0;
}
ip->srcport = NSRCPORT(&pp->srcadr);
ip->flags = 0;
if (pp == sys_peer)
- ip->flags |= INFO_FLAG_SYSPEER;
+ ip->flags |= INFO_FLAG_SYSPEER;
if (pp->flags & FLAG_CONFIG)
- ip->flags |= INFO_FLAG_CONFIG;
+ ip->flags |= INFO_FLAG_CONFIG;
if (pp->flags & FLAG_REFCLOCK)
- ip->flags |= INFO_FLAG_REFCLOCK;
- if (pp->flags & FLAG_AUTHENABLE)
- ip->flags |= INFO_FLAG_AUTHENABLE;
+ ip->flags |= INFO_FLAG_REFCLOCK;
if (pp->flags & FLAG_PREFER)
- ip->flags |= INFO_FLAG_PREFER;
+ ip->flags |= INFO_FLAG_PREFER;
if (pp->flags & FLAG_BURST)
- ip->flags |= INFO_FLAG_BURST;
+ ip->flags |= INFO_FLAG_BURST;
if (pp->status == CTL_PST_SEL_SYNCCAND)
- ip->flags |= INFO_FLAG_SEL_CANDIDATE;
+ ip->flags |= INFO_FLAG_SEL_CANDIDATE;
if (pp->status >= CTL_PST_SEL_SYSPEER)
- ip->flags |= INFO_FLAG_SHORTLIST;
+ ip->flags |= INFO_FLAG_SHORTLIST;
ip->leap = pp->leap;
ip->hmode = pp->hmode;
ip->keyid = pp->keyid;
@@ -906,37 +911,38 @@ peer_info (
ip->precision = pp->precision;
ip->version = pp->version;
ip->reach = pp->reach;
- ip->unreach = (u_char) pp->unreach;
+ ip->unreach = (u_char)pp->unreach;
ip->flash = (u_char)pp->flash;
- ip->flash2 = (u_short) pp->flash;
- ip->estbdelay = HTONS_FP(DTOFP(pp->estbdelay));
- ip->ttl = pp->ttl;
+ ip->flash2 = (u_short)pp->flash;
+ ip->estbdelay = HTONS_FP(DTOFP(pp->delay));
+ ip->ttl = (u_char)pp->ttl;
ip->associd = htons(pp->associd);
ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay));
- ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdispersion));
+ ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdisp));
ip->refid = pp->refid;
HTONL_FP(&pp->reftime, &ip->reftime);
- HTONL_FP(&pp->org, &ip->org);
+ HTONL_FP(&pp->aorg, &ip->org);
HTONL_FP(&pp->rec, &ip->rec);
HTONL_FP(&pp->xmt, &ip->xmt);
j = pp->filter_nextpt - 1;
for (i = 0; i < NTP_SHIFT; i++, j--) {
if (j < 0)
- j = NTP_SHIFT-1;
+ j = NTP_SHIFT-1;
ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j]));
DTOLFP(pp->filter_offset[j], &ltmp);
HTONL_FP(&ltmp, &ip->filtoffset[i]);
- ip->order[i] = (u_char)((pp->filter_nextpt+NTP_SHIFT-1)
- - pp->filter_order[i]);
+ ip->order[i] = (u_char)((pp->filter_nextpt +
+ NTP_SHIFT - 1) -
+ pp->filter_order[i]);
if (ip->order[i] >= NTP_SHIFT)
- ip->order[i] -= NTP_SHIFT;
+ ip->order[i] -= NTP_SHIFT;
}
DTOLFP(pp->offset, &ltmp);
HTONL_FP(&ltmp, &ip->offset);
ip->delay = HTONS_FP(DTOFP(pp->delay));
ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter)));
- ip = (struct info_peer *)more_pkt();
+ ip = more_pkt();
}
flush_pkt();
}
@@ -947,78 +953,84 @@ peer_info (
*/
static void
peer_stats (
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_peer_list *ipl;
- register struct peer *pp;
- register struct info_peer_stats *ip;
- register int items;
- struct sockaddr_storage addr;
- extern struct peer *sys_peer;
-
-#ifdef DEBUG
- if (debug)
- printf("peer_stats: called\n");
-#endif
+ u_short items;
+ size_t item_sz;
+ char * datap;
+ struct info_peer_list ipl;
+ struct peer * pp;
+ struct info_peer_stats *ip;
+ sockaddr_u addr;
+
+ DPRINTF(1, ("peer_stats: called\n"));
items = INFO_NITEMS(inpkt->err_nitems);
- ipl = (struct info_peer_list *) inpkt->data;
- ip = (struct info_peer_stats *)prepare_pkt(srcadr, inter, inpkt,
- v6sizeof(struct info_peer_stats));
- while (items-- > 0 && ip != 0) {
- memset((char *)&addr, 0, sizeof(addr));
- NSRCPORT(&addr) = ipl->port;
- if (client_v6_capable && ipl->v6_flag) {
- addr.ss_family = AF_INET6;
- GET_INADDR6(addr) = ipl->addr6;
+ item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
+ datap = inpkt->u.data;
+ if (item_sz > sizeof(ipl)) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
+ return;
+ }
+ ip = prepare_pkt(srcadr, inter, inpkt,
+ v6sizeof(struct info_peer_stats));
+ while (items-- > 0 && ip != NULL) {
+ ZERO(ipl);
+ memcpy(&ipl, datap, item_sz);
+ ZERO(addr);
+ NSRCPORT(&addr) = ipl.port;
+ if (client_v6_capable && ipl.v6_flag) {
+ AF(&addr) = AF_INET6;
+ SOCK_ADDR6(&addr) = ipl.addr6;
} else {
- addr.ss_family = AF_INET;
- GET_INADDR(addr) = ipl->addr;
+ AF(&addr) = AF_INET;
+ NSRCADR(&addr) = ipl.addr;
}
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- addr.ss_len = SOCKLEN(&addr);
-#endif
-#ifdef DEBUG
- if (debug)
- printf("peer_stats: looking for %s, %d, %d\n", stoa(&addr),
- ipl->port, ((struct sockaddr_in6 *)&addr)->sin6_port);
+#ifdef ISC_PLATFORM_HAVESALEN
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
- ipl = (struct info_peer_list *)((char *)ipl +
- INFO_ITEMSIZE(inpkt->mbz_itemsize));
-
- if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0)
- continue;
-#ifdef DEBUG
- if (debug)
- printf("peer_stats: found %s\n", stoa(&addr));
-#endif
- if (pp->srcadr.ss_family == AF_INET) {
- if (pp->dstadr)
- ip->dstadr = (pp->processed) ?
- pp->cast_flags == MDF_BCAST ?
- GET_INADDR(pp->dstadr->bcast):
- pp->cast_flags ?
- GET_INADDR(pp->dstadr->sin) ?
- GET_INADDR(pp->dstadr->sin):
- GET_INADDR(pp->dstadr->bcast):
- 3 : 7;
- else
- memset(&ip->dstadr, 0, sizeof(ip->dstadr));
+ DPRINTF(1, ("peer_stats: looking for %s, %d, %d\n",
+ stoa(&addr), ipl.port, NSRCPORT(&addr)));
+
+ datap += item_sz;
+
+ pp = findexistingpeer(&addr, NULL, NULL, -1, 0);
+ if (NULL == pp)
+ continue;
+
+ DPRINTF(1, ("peer_stats: found %s\n", stoa(&addr)));
+
+ if (IS_IPV4(&pp->srcadr)) {
+ if (pp->dstadr) {
+ if (!pp->processed)
+ ip->dstadr = NSRCADR(&pp->dstadr->sin);
+ else {
+ if (MDF_BCAST == pp->cast_flags)
+ ip->dstadr = NSRCADR(&pp->dstadr->bcast);
+ else if (pp->cast_flags) {
+ ip->dstadr = NSRCADR(&pp->dstadr->sin);
+ if (!ip->dstadr)
+ ip->dstadr = NSRCADR(&pp->dstadr->bcast);
+ }
+ }
+ } else
+ ip->dstadr = 0;
- ip->srcadr = GET_INADDR(pp->srcadr);
+ ip->srcadr = NSRCADR(&pp->srcadr);
if (client_v6_capable)
ip->v6_flag = 0;
} else {
if (pp->dstadr)
- ip->dstadr6 = pp->cast_flags == MDF_BCAST ?
- GET_INADDR6(pp->dstadr->bcast):
- GET_INADDR6(pp->dstadr->sin);
+ ip->dstadr6 =
+ (MDF_BCAST == pp->cast_flags)
+ ? SOCK_ADDR6(&pp->dstadr->bcast)
+ : SOCK_ADDR6(&pp->dstadr->sin);
else
- memset(&ip->dstadr6, 0, sizeof(ip->dstadr6));
-
- ip->srcadr6 = GET_INADDR6(pp->srcadr);
+ ZERO(ip->dstadr6);
+
+ ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
ip->v6_flag = 1;
}
ip->srcport = NSRCPORT(&pp->srcadr);
@@ -1029,8 +1041,6 @@ peer_stats (
ip->flags |= INFO_FLAG_CONFIG;
if (pp->flags & FLAG_REFCLOCK)
ip->flags |= INFO_FLAG_REFCLOCK;
- if (pp->flags & FLAG_AUTHENABLE)
- ip->flags |= INFO_FLAG_AUTHENABLE;
if (pp->flags & FLAG_PREFER)
ip->flags |= INFO_FLAG_PREFER;
if (pp->flags & FLAG_BURST)
@@ -1064,8 +1074,8 @@ peer_stats (
*/
static void
sys_info(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -1074,13 +1084,13 @@ sys_info(
is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
v6sizeof(struct info_sys));
- if (sys_peer != 0) {
- if (sys_peer->srcadr.ss_family == AF_INET) {
- is->peer = GET_INADDR(sys_peer->srcadr);
+ if (sys_peer) {
+ if (IS_IPV4(&sys_peer->srcadr)) {
+ is->peer = NSRCADR(&sys_peer->srcadr);
if (client_v6_capable)
is->v6_flag = 0;
} else if (client_v6_capable) {
- is->peer6 = GET_INADDR6(sys_peer->srcadr);
+ is->peer6 = SOCK_ADDR6(&sys_peer->srcadr);
is->v6_flag = 1;
}
is->peer_mode = sys_peer->hmode;
@@ -1096,9 +1106,9 @@ sys_info(
is->stratum = sys_stratum;
is->precision = sys_precision;
is->rootdelay = htonl(DTOFP(sys_rootdelay));
- is->rootdispersion = htonl(DTOUFP(sys_rootdispersion));
+ is->rootdispersion = htonl(DTOUFP(sys_rootdisp));
is->frequency = htonl(DTOFP(sys_jitter));
- is->stability = htonl(DTOUFP(clock_stability));
+ is->stability = htonl(DTOUFP(clock_stability * 1e6));
is->refid = sys_refid;
HTONL_FP(&sys_reftime, &is->reftime);
@@ -1119,13 +1129,12 @@ sys_info(
is->flags |= INFO_FLAG_MONITOR;
if (ntp_enable)
is->flags |= INFO_FLAG_NTP;
- if (pps_enable)
+ if (hardpps_enable)
is->flags |= INFO_FLAG_PPS_SYNC;
if (stats_control)
is->flags |= INFO_FLAG_FILEGEN;
is->bdelay = HTONS_FP(DTOFP(sys_bdelay));
- HTONL_UF(sys_authdelay.l_f, &is->authdelay);
-
+ HTONL_UF(sys_authdelay.l_uf, &is->authdelay);
(void) more_pkt();
flush_pkt();
}
@@ -1136,24 +1145,21 @@ sys_info(
*/
static void
sys_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
register struct info_sys_stats *ss;
- /*
- * Importations from the protocol module
- */
ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_sys_stats));
ss->timeup = htonl((u_int32)current_time);
ss->timereset = htonl((u_int32)(current_time - sys_stattime));
ss->denied = htonl((u_int32)sys_restricted);
- ss->oldversionpkt = htonl((u_int32)sys_oldversionpkt);
- ss->newversionpkt = htonl((u_int32)sys_newversionpkt);
- ss->unknownversion = htonl((u_int32)sys_unknownversion);
+ ss->oldversionpkt = htonl((u_int32)sys_oldversion);
+ ss->newversionpkt = htonl((u_int32)sys_newversion);
+ ss->unknownversion = htonl((u_int32)sys_declined);
ss->badlength = htonl((u_int32)sys_badlength);
ss->processed = htonl((u_int32)sys_processed);
ss->badauth = htonl((u_int32)sys_badauth);
@@ -1169,25 +1175,14 @@ sys_stats(
*/
static void
mem_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
register struct info_mem_stats *ms;
register int i;
- /*
- * Importations from the peer module
- */
- extern int peer_hash_count[NTP_HASH_SIZE];
- extern int peer_free_count;
- extern u_long peer_timereset;
- extern u_long findpeer_calls;
- extern u_long peer_allocations;
- extern u_long peer_demobilizations;
- extern int total_peer_structs;
-
ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_mem_stats));
@@ -1198,14 +1193,11 @@ mem_stats(
ms->allocations = htonl((u_int32)peer_allocations);
ms->demobilizations = htonl((u_int32)peer_demobilizations);
- for (i = 0; i < NTP_HASH_SIZE; i++) {
- if (peer_hash_count[i] > 255)
- ms->hashcount[i] = 255;
- else
- ms->hashcount[i] = (u_char)peer_hash_count[i];
- }
+ for (i = 0; i < NTP_HASH_SIZE; i++)
+ ms->hashcount[i] = (u_char)
+ max((u_int)peer_hash_count[i], UCHAR_MAX);
- (void) more_pkt();
+ more_pkt();
flush_pkt();
}
@@ -1215,18 +1207,13 @@ mem_stats(
*/
static void
io_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_io_stats *io;
+ struct info_io_stats *io;
- /*
- * Importations from the io module
- */
- extern u_long io_timereset;
-
io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_io_stats));
@@ -1253,26 +1240,21 @@ io_stats(
*/
static void
timer_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
- struct req_pkt *inpkt
+ sockaddr_u * srcadr,
+ endpt * inter,
+ struct req_pkt * inpkt
)
{
- register struct info_timer_stats *ts;
-
- /*
- * Importations from the timer module
- */
- extern u_long timer_timereset;
- extern u_long timer_overflows;
- extern u_long timer_xmtcalls;
+ struct info_timer_stats * ts;
+ u_long sincereset;
- ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, inpkt,
- sizeof(struct info_timer_stats));
+ ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter,
+ inpkt, sizeof(*ts));
- ts->timereset = htonl((u_int32)(current_time - timer_timereset));
- ts->alarms = htonl((u_int32)alarm_overflow);
- ts->overflows = htonl((u_int32)timer_overflows);
+ sincereset = current_time - timer_timereset;
+ ts->timereset = htonl((u_int32)sincereset);
+ ts->alarms = ts->timereset;
+ ts->overflows = htonl((u_int32)alarm_overflow);
ts->xmtcalls = htonl((u_int32)timer_xmtcalls);
(void) more_pkt();
@@ -1285,22 +1267,14 @@ timer_stats(
*/
static void
loop_info(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_loop *li;
+ struct info_loop *li;
l_fp ltmp;
- /*
- * Importations from the loop filter module
- */
- extern double last_offset;
- extern double drift_comp;
- extern int tc_counter;
- extern u_long sys_clocktime;
-
li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_loop));
@@ -1309,9 +1283,9 @@ loop_info(
DTOLFP(drift_comp * 1e6, &ltmp);
HTONL_FP(&ltmp, &li->drift_comp);
li->compliance = htonl((u_int32)(tc_counter));
- li->watchdog_timer = htonl((u_int32)(current_time - sys_clocktime));
+ li->watchdog_timer = htonl((u_int32)(current_time - sys_epoch));
- (void) more_pkt();
+ more_pkt();
flush_pkt();
}
@@ -1321,18 +1295,17 @@ loop_info(
*/
static void
do_conf(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- static u_long soonest_ifrescan_time = 0;
- int items;
- u_int fl;
- struct conf_peer *cp;
- struct conf_peer temp_cp;
- struct sockaddr_storage peeraddr;
- struct sockaddr_in tmp_clock;
+ u_short items;
+ size_t item_sz;
+ u_int fl;
+ char * datap;
+ struct conf_peer temp_cp;
+ sockaddr_u peeraddr;
/*
* Do a check of everything to see that it looks
@@ -1340,80 +1313,52 @@ do_conf(
* very picky here.
*/
items = INFO_NITEMS(inpkt->err_nitems);
- cp = (struct conf_peer *)inpkt->data;
- memset(&temp_cp, 0, sizeof(struct conf_peer));
- memcpy(&temp_cp, (char *)cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
- fl = 0;
- while (items-- > 0 && !fl) {
- if (((temp_cp.version) > NTP_VERSION)
- || ((temp_cp.version) < NTP_OLDVERSION))
- fl = 1;
- if (temp_cp.hmode != MODE_ACTIVE
- && temp_cp.hmode != MODE_CLIENT
- && temp_cp.hmode != MODE_BROADCAST)
- fl = 1;
- if (temp_cp.flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER
- | CONF_FLAG_BURST | CONF_FLAG_IBURST | CONF_FLAG_SKEY))
- fl = 1;
- cp = (struct conf_peer *)
- ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
- }
-
- if (fl) {
+ item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
+ datap = inpkt->u.data;
+ if (item_sz > sizeof(temp_cp)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
- /*
- * Looks okay, try it out
- */
- items = INFO_NITEMS(inpkt->err_nitems);
- cp = (struct conf_peer *)inpkt->data;
-
while (items-- > 0) {
- memset(&temp_cp, 0, sizeof(struct conf_peer));
- memcpy(&temp_cp, (char *)cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
- memset((char *)&peeraddr, 0, sizeof(struct sockaddr_storage));
+ ZERO(temp_cp);
+ memcpy(&temp_cp, datap, item_sz);
+ ZERO_SOCK(&peeraddr);
fl = 0;
- if (temp_cp.flags & CONF_FLAG_AUTHENABLE)
- fl |= FLAG_AUTHENABLE;
if (temp_cp.flags & CONF_FLAG_PREFER)
fl |= FLAG_PREFER;
if (temp_cp.flags & CONF_FLAG_BURST)
- fl |= FLAG_BURST;
+ fl |= FLAG_BURST;
if (temp_cp.flags & CONF_FLAG_IBURST)
- fl |= FLAG_IBURST;
+ fl |= FLAG_IBURST;
+#ifdef AUTOKEY
if (temp_cp.flags & CONF_FLAG_SKEY)
fl |= FLAG_SKEY;
-
- if (client_v6_capable && temp_cp.v6_flag != 0) {
- peeraddr.ss_family = AF_INET6;
- GET_INADDR6(peeraddr) = temp_cp.peeraddr6;
+#endif /* AUTOKEY */
+ if (client_v6_capable && temp_cp.v6_flag) {
+ AF(&peeraddr) = AF_INET6;
+ SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
} else {
- peeraddr.ss_family = AF_INET;
- GET_INADDR(peeraddr) = temp_cp.peeraddr;
+ AF(&peeraddr) = AF_INET;
+ NSRCADR(&peeraddr) = temp_cp.peeraddr;
/*
* Make sure the address is valid
*/
- tmp_clock = *CAST_V4(peeraddr);
- if (
-#ifdef REFCLOCK
- !ISREFCLOCKADR(&tmp_clock) &&
-#endif
- ISBADADR(&tmp_clock)) {
+ if (!ISREFCLOCKADR(&peeraddr) &&
+ ISBADADR(&peeraddr)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
}
NSRCPORT(&peeraddr) = htons(NTP_PORT);
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- peeraddr.ss_len = SOCKLEN(&peeraddr);
+#ifdef ISC_PLATFORM_HAVESALEN
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
/* XXX W2DO? minpoll/maxpoll arguments ??? */
- if (peer_config(&peeraddr, (struct interface *)0,
+ if (peer_config(&peeraddr, NULL, NULL,
temp_cp.hmode, temp_cp.version, temp_cp.minpoll,
temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid,
NULL) == 0) {
@@ -1421,142 +1366,30 @@ do_conf(
return;
}
- /*
- * ntp_intres.c uses REQ_CONFIG/doconf() to add each
- * server after its name is resolved. If we have been
- * disconnected from the network, it may notice the
- * network has returned and add the first server while
- * the relevant interface is still disabled, awaiting
- * the next interface rescan. To get things moving
- * more quickly, trigger an interface scan now, except
- * if we have done so in the last half minute.
- */
- if (soonest_ifrescan_time < current_time) {
- soonest_ifrescan_time = current_time + 30;
- timer_interfacetimeout(current_time);
- DPRINTF(1, ("do_conf triggering interface rescan\n"));
- }
-
- cp = (struct conf_peer *)
- ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
+ datap += item_sz;
}
-
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
-#if 0
-/* XXX */
-/*
- * dns_a - Snarf DNS info for an association ID
- */
-static void
-dns_a(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
- struct req_pkt *inpkt
- )
-{
- register struct info_dns_assoc *dp;
- register int items;
- struct sockaddr_in peeraddr;
-
- /*
- * Do a check of everything to see that it looks
- * okay. If not, complain about it. Note we are
- * very picky here.
- */
- items = INFO_NITEMS(inpkt->err_nitems);
- dp = (struct info_dns_assoc *)inpkt->data;
-
- /*
- * Looks okay, try it out
- */
- items = INFO_NITEMS(inpkt->err_nitems);
- dp = (struct info_dns_assoc *)inpkt->data;
- memset((char *)&peeraddr, 0, sizeof(struct sockaddr_in));
- peeraddr.sin_family = AF_INET;
- peeraddr.sin_port = htons(NTP_PORT);
-
- /*
- * Make sure the address is valid
- */
- if (
-#ifdef REFCLOCK
- !ISREFCLOCKADR(&peeraddr) &&
-#endif
- ISBADADR(&peeraddr)) {
-#ifdef REFCLOCK
- msyslog(LOG_ERR, "dns_a: !ISREFCLOCK && ISBADADR");
-#else
- msyslog(LOG_ERR, "dns_a: ISBADADR");
-#endif
- req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
- return;
- }
-
- while (items-- > 0) {
- associd_t associd;
- size_t hnl;
- struct peer *peer;
- int bogon = 0;
-
- associd = dp->associd;
- peer = findpeerbyassoc(associd);
- if (peer == 0 || peer->flags & FLAG_REFCLOCK) {
- msyslog(LOG_ERR, "dns_a: %s",
- (peer == 0)
- ? "peer == 0"
- : "peer->flags & FLAG_REFCLOCK");
- ++bogon;
- }
- peeraddr.sin_addr.s_addr = dp->peeraddr;
- for (hnl = 0; dp->hostname[hnl] && hnl < sizeof dp->hostname; ++hnl) ;
- if (hnl >= sizeof dp->hostname) {
- msyslog(LOG_ERR, "dns_a: hnl (%ld) >= %ld",
- (long)hnl, (long)sizeof dp->hostname);
- ++bogon;
- }
-
- msyslog(LOG_INFO, "dns_a: <%s> for %s, AssocID %d, bogon %d",
- dp->hostname,
- stoa((struct sockaddr_storage *)&peeraddr), associd,
- bogon);
-
- if (bogon) {
- /* If it didn't work */
- req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
- return;
- } else {
-#if 0
-#ifdef PUBKEY
- crypto_public(peer, dp->hostname);
-#endif /* PUBKEY */
-#endif
- }
-
- dp++;
- }
-
- req_ack(srcadr, inter, inpkt, INFO_OKAY);
-}
-#endif /* 0 */
/*
* do_unconf - remove a peer from the configuration list
*/
static void
do_unconf(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u * srcadr,
+ endpt * inter,
struct req_pkt *inpkt
)
{
- register struct conf_unpeer *cp;
- struct conf_unpeer temp_cp;
- register int items;
- register struct peer *peer;
- struct sockaddr_storage peeraddr;
- int bad, found;
+ u_short items;
+ size_t item_sz;
+ char * datap;
+ struct conf_unpeer temp_cp;
+ struct peer * p;
+ sockaddr_u peeraddr;
+ int bad;
+ int found;
/*
* This is a bit unstructured, but I like to be careful.
@@ -1565,41 +1398,45 @@ do_unconf(
* an error.
*/
items = INFO_NITEMS(inpkt->err_nitems);
- cp = (struct conf_unpeer *)inpkt->data;
+ item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
+ datap = inpkt->u.data;
+ if (item_sz > sizeof(temp_cp)) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
+ return;
+ }
- bad = 0;
+ bad = FALSE;
while (items-- > 0 && !bad) {
- memset(&temp_cp, 0, sizeof(temp_cp));
- memset(&peeraddr, 0, sizeof(peeraddr));
- memcpy(&temp_cp, cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
- if (client_v6_capable && temp_cp.v6_flag != 0) {
- peeraddr.ss_family = AF_INET6;
- GET_INADDR6(peeraddr) = temp_cp.peeraddr6;
+ ZERO(temp_cp);
+ memcpy(&temp_cp, datap, item_sz);
+ ZERO_SOCK(&peeraddr);
+ if (client_v6_capable && temp_cp.v6_flag) {
+ AF(&peeraddr) = AF_INET6;
+ SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
} else {
- peeraddr.ss_family = AF_INET;
- GET_INADDR(peeraddr) = temp_cp.peeraddr;
+ AF(&peeraddr) = AF_INET;
+ NSRCADR(&peeraddr) = temp_cp.peeraddr;
}
- NSRCPORT(&peeraddr) = htons(NTP_PORT);
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- peeraddr.ss_len = SOCKLEN(&peeraddr);
-#endif
- found = 0;
- peer = (struct peer *)0;
-#ifdef DEBUG
- if (debug)
- printf("searching for %s\n", stoa(&peeraddr));
+ SET_PORT(&peeraddr, NTP_PORT);
+#ifdef ISC_PLATFORM_HAVESALEN
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
+ found = FALSE;
+ p = NULL;
+
+ DPRINTF(1, ("searching for %s\n", stoa(&peeraddr)));
+
while (!found) {
- peer = findexistingpeer(&peeraddr, peer, -1);
- if (peer == (struct peer *)0)
- break;
- if (peer->flags & FLAG_CONFIG)
- found = 1;
+ p = findexistingpeer(&peeraddr, NULL, p, -1, 0);
+ if (NULL == p)
+ break;
+ if (FLAG_CONFIG & p->flags)
+ found = TRUE;
}
if (!found)
- bad = 1;
- cp = (struct conf_unpeer *)
- ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
+ bad = TRUE;
+
+ datap += item_sz;
}
if (bad) {
@@ -1612,25 +1449,40 @@ do_unconf(
*/
items = INFO_NITEMS(inpkt->err_nitems);
- cp = (struct conf_unpeer *)inpkt->data;
+ datap = inpkt->u.data;
+
while (items-- > 0) {
- memset(&temp_cp, 0, sizeof(temp_cp));
- memset(&peeraddr, 0, sizeof(peeraddr));
- memcpy(&temp_cp, cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
- if (client_v6_capable && temp_cp.v6_flag != 0) {
- peeraddr.ss_family = AF_INET6;
- GET_INADDR6(peeraddr) = temp_cp.peeraddr6;
+ ZERO(temp_cp);
+ memcpy(&temp_cp, datap, item_sz);
+ ZERO(peeraddr);
+ if (client_v6_capable && temp_cp.v6_flag) {
+ AF(&peeraddr) = AF_INET6;
+ SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
} else {
- peeraddr.ss_family = AF_INET;
- GET_INADDR(peeraddr) = temp_cp.peeraddr;
+ AF(&peeraddr) = AF_INET;
+ NSRCADR(&peeraddr) = temp_cp.peeraddr;
}
- NSRCPORT(&peeraddr) = htons(NTP_PORT);
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- peeraddr.ss_len = SOCKLEN(&peeraddr);
+ SET_PORT(&peeraddr, NTP_PORT);
+#ifdef ISC_PLATFORM_HAVESALEN
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
- peer_unconfig(&peeraddr, (struct interface *)0, -1);
- cp = (struct conf_unpeer *)
- ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
+ found = FALSE;
+ p = NULL;
+
+ while (!found) {
+ p = findexistingpeer(&peeraddr, NULL, p, -1, 0);
+ if (NULL == p)
+ break;
+ if (FLAG_CONFIG & p->flags)
+ found = TRUE;
+ }
+ INSIST(found);
+ INSIST(NULL != p);
+
+ peer_clear(p, "GONE");
+ unpeer(p);
+
+ datap += item_sz;
}
req_ack(srcadr, inter, inpkt, INFO_OKAY);
@@ -1642,8 +1494,8 @@ do_unconf(
*/
static void
set_sys_flag(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -1656,8 +1508,8 @@ set_sys_flag(
*/
static void
clr_sys_flag(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -1670,24 +1522,23 @@ clr_sys_flag(
*/
static void
setclr_flags(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt,
u_long set
)
{
- register u_int flags;
- int prev_kern_enable;
+ struct conf_sys_flags *sf;
+ u_int32 flags;
- prev_kern_enable = kern_enable;
if (INFO_NITEMS(inpkt->err_nitems) > 1) {
msyslog(LOG_ERR, "setclr_flags: err_nitems > 1");
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
- flags = ((struct conf_sys_flags *)inpkt->data)->flags;
- flags = ntohl(flags);
+ sf = (struct conf_sys_flags *)&inpkt->u;
+ flags = ntohl(sf->flags);
if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR |
@@ -1718,12 +1569,58 @@ setclr_flags(
if (flags & SYS_FLAG_CAL)
proto_config(PROTO_CAL, set, 0., NULL);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
+}
- /* Reset the kernel ntp parameters if the kernel flag changed. */
- if (prev_kern_enable && !kern_enable)
- loop_config(LOOP_KERN_CLEAR, 0.0);
- if (!prev_kern_enable && kern_enable)
- loop_config(LOOP_DRIFTCOMP, drift_comp);
+/*
+ * list_restrict4 - recursive helper for list_restrict dumps IPv4
+ * restriction list in reverse order.
+ */
+static void
+list_restrict4(
+ restrict_u * res,
+ struct info_restrict ** ppir
+ )
+{
+ struct info_restrict * pir;
+
+ if (res->link != NULL)
+ list_restrict4(res->link, ppir);
+
+ pir = *ppir;
+ pir->addr = htonl(res->u.v4.addr);
+ if (client_v6_capable)
+ pir->v6_flag = 0;
+ pir->mask = htonl(res->u.v4.mask);
+ pir->count = htonl(res->count);
+ pir->flags = htons(res->flags);
+ pir->mflags = htons(res->mflags);
+ *ppir = (struct info_restrict *)more_pkt();
+}
+
+
+/*
+ * list_restrict6 - recursive helper for list_restrict dumps IPv6
+ * restriction list in reverse order.
+ */
+static void
+list_restrict6(
+ restrict_u * res,
+ struct info_restrict ** ppir
+ )
+{
+ struct info_restrict * pir;
+
+ if (res->link != NULL)
+ list_restrict6(res->link, ppir);
+
+ pir = *ppir;
+ pir->addr6 = res->u.v6.addr;
+ pir->mask6 = res->u.v6.mask;
+ pir->v6_flag = 1;
+ pir->count = htonl(res->count);
+ pir->flags = htons(res->flags);
+ pir->mflags = htons(res->mflags);
+ *ppir = (struct info_restrict *)more_pkt();
}
@@ -1732,55 +1629,38 @@ setclr_flags(
*/
static void
list_restrict(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_restrict *ir;
- register struct restrictlist *rl;
- register struct restrictlist6 *rl6;
+ struct info_restrict *ir;
-#ifdef DEBUG
- if (debug > 2)
- printf("wants restrict list summary\n");
-#endif
+ DPRINTF(3, ("wants restrict list summary\n"));
ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
v6sizeof(struct info_restrict));
- for (rl = restrictlist; rl != 0 && ir != 0; rl = rl->next) {
- ir->addr = htonl(rl->addr);
- if (client_v6_capable)
- ir->v6_flag = 0;
- ir->mask = htonl(rl->mask);
- ir->count = htonl((u_int32)rl->count);
- ir->flags = htons(rl->flags);
- ir->mflags = htons(rl->mflags);
- ir = (struct info_restrict *)more_pkt();
- }
+ /*
+ * The restriction lists are kept sorted in the reverse order
+ * than they were originally. To preserve the output semantics,
+ * dump each list in reverse order. A recursive helper function
+ * achieves that.
+ */
+ list_restrict4(restrictlist4, &ir);
if (client_v6_capable)
- for (rl6 = restrictlist6; rl6 != 0 && ir != 0; rl6 = rl6->next) {
- ir->addr6 = rl6->addr6;
- ir->mask6 = rl6->mask6;
- ir->v6_flag = 1;
- ir->count = htonl((u_int32)rl6->count);
- ir->flags = htons(rl6->flags);
- ir->mflags = htons(rl6->mflags);
- ir = (struct info_restrict *)more_pkt();
- }
+ list_restrict6(restrictlist6, &ir);
flush_pkt();
}
-
/*
* do_resaddflags - add flags to a restrict entry (or create one)
*/
static void
do_resaddflags(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -1794,8 +1674,8 @@ do_resaddflags(
*/
static void
do_ressubflags(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -1808,8 +1688,8 @@ do_ressubflags(
*/
static void
do_unrestrict(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -1817,25 +1697,24 @@ do_unrestrict(
}
-
-
-
/*
* do_restrict - do the dirty stuff of dealing with restrictions
*/
static void
do_restrict(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt,
int op
)
{
- register struct conf_restrict *cr;
- register int items;
- struct sockaddr_storage matchaddr;
- struct sockaddr_storage matchmask;
- int bad;
+ char * datap;
+ struct conf_restrict cr;
+ u_short items;
+ size_t item_sz;
+ sockaddr_u matchaddr;
+ sockaddr_u matchmask;
+ int bad;
/*
* Do a check of the flags to make sure that only
@@ -1843,26 +1722,32 @@ do_restrict(
* about it. Note we are very picky here.
*/
items = INFO_NITEMS(inpkt->err_nitems);
- cr = (struct conf_restrict *)inpkt->data;
+ item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
+ datap = inpkt->u.data;
+ if (item_sz > sizeof(cr)) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
+ return;
+ }
- bad = 0;
- cr->flags = ntohs(cr->flags);
- cr->mflags = ntohs(cr->mflags);
+ bad = FALSE;
while (items-- > 0 && !bad) {
- if (cr->mflags & ~(RESM_NTPONLY))
- bad |= 1;
- if (cr->flags & ~(RES_ALLFLAGS))
- bad |= 2;
- if (cr->mask != htonl(INADDR_ANY)) {
- if (client_v6_capable && cr->v6_flag != 0) {
- if (IN6_IS_ADDR_UNSPECIFIED(&cr->addr6))
+ memcpy(&cr, datap, item_sz);
+ cr.flags = ntohs(cr.flags);
+ cr.mflags = ntohs(cr.mflags);
+ if (~RESM_NTPONLY & cr.mflags)
+ bad |= 1;
+ if (~RES_ALLFLAGS & cr.flags)
+ bad |= 2;
+ if (INADDR_ANY != cr.mask) {
+ if (client_v6_capable && cr.v6_flag) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&cr.addr6))
bad |= 4;
- } else
- if (cr->addr == htonl(INADDR_ANY))
+ } else {
+ if (INADDR_ANY == cr.addr)
bad |= 8;
+ }
}
- cr = (struct conf_restrict *)((char *)cr +
- INFO_ITEMSIZE(inpkt->mbz_itemsize));
+ datap += item_sz;
}
if (bad) {
@@ -1874,26 +1759,28 @@ do_restrict(
/*
* Looks okay, try it out
*/
- items = INFO_NITEMS(inpkt->err_nitems);
- cr = (struct conf_restrict *)inpkt->data;
- memset((char *)&matchaddr, 0, sizeof(struct sockaddr_storage));
- memset((char *)&matchmask, 0, sizeof(struct sockaddr_storage));
+ ZERO_SOCK(&matchaddr);
+ ZERO_SOCK(&matchmask);
+ datap = inpkt->u.data;
while (items-- > 0) {
- if (client_v6_capable && cr->v6_flag != 0) {
- GET_INADDR6(matchaddr) = cr->addr6;
- GET_INADDR6(matchmask) = cr->mask6;
- matchaddr.ss_family = AF_INET6;
- matchmask.ss_family = AF_INET6;
+ memcpy(&cr, datap, item_sz);
+ cr.flags = ntohs(cr.flags);
+ cr.mflags = ntohs(cr.mflags);
+ if (client_v6_capable && cr.v6_flag) {
+ AF(&matchaddr) = AF_INET6;
+ AF(&matchmask) = AF_INET6;
+ SOCK_ADDR6(&matchaddr) = cr.addr6;
+ SOCK_ADDR6(&matchmask) = cr.mask6;
} else {
- GET_INADDR(matchaddr) = cr->addr;
- GET_INADDR(matchmask) = cr->mask;
- matchaddr.ss_family = AF_INET;
- matchmask.ss_family = AF_INET;
+ AF(&matchaddr) = AF_INET;
+ AF(&matchmask) = AF_INET;
+ NSRCADR(&matchaddr) = cr.addr;
+ NSRCADR(&matchmask) = cr.mask;
}
- hack_restrict(op, &matchaddr, &matchmask, cr->mflags,
- cr->flags);
- cr++;
+ hack_restrict(op, &matchaddr, &matchmask, cr.mflags,
+ cr.flags, 0);
+ datap += item_sz;
}
req_ack(srcadr, inter, inpkt, INFO_OKAY);
@@ -1904,109 +1791,22 @@ do_restrict(
* mon_getlist - return monitor data
*/
static void
-mon_getlist_0(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+mon_getlist(
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_monitor *im;
- register struct mon_data *md;
- extern struct mon_data mon_mru_list;
- extern int mon_enabled;
-
-#ifdef DEBUG
- if (debug > 2)
- printf("wants monitor 0 list\n");
-#endif
- if (!mon_enabled) {
- return;
- }
- im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt,
- v6sizeof(struct info_monitor));
- for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0;
- md = md->mru_next) {
- im->lasttime = htonl((u_int32)md->avg_interval);
- im->firsttime = htonl((u_int32)(current_time - md->lasttime));
- im->lastdrop = htonl((u_int32)md->drop_count);
- im->count = htonl((u_int32)(md->count));
- if (md->rmtadr.ss_family == AF_INET6) {
- if (!client_v6_capable)
- continue;
- im->addr6 = GET_INADDR6(md->rmtadr);
- im->v6_flag = 1;
- } else {
- im->addr = GET_INADDR(md->rmtadr);
- if (client_v6_capable)
- im->v6_flag = 0;
- }
- im->port = md->rmtport;
- im->mode = md->mode;
- im->version = md->version;
- im = (struct info_monitor *)more_pkt();
- }
- flush_pkt();
+ req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
}
-/*
- * mon_getlist - return monitor data
- */
-static void
-mon_getlist_1(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
- struct req_pkt *inpkt
- )
-{
- register struct info_monitor_1 *im;
- register struct mon_data *md;
- extern struct mon_data mon_mru_list;
- extern int mon_enabled;
-
- if (!mon_enabled) {
- return;
- }
- im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt,
- v6sizeof(struct info_monitor_1));
- for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0;
- md = md->mru_next) {
- im->lasttime = htonl((u_int32)md->avg_interval);
- im->firsttime = htonl((u_int32)(current_time - md->lasttime));
- im->lastdrop = htonl((u_int32)md->drop_count);
- im->count = htonl((u_int32)md->count);
- if (md->rmtadr.ss_family == AF_INET6) {
- if (!client_v6_capable)
- continue;
- im->addr6 = GET_INADDR6(md->rmtadr);
- im->v6_flag = 1;
- im->daddr6 = GET_INADDR6(md->interface->sin);
- } else {
- im->addr = GET_INADDR(md->rmtadr);
- if (client_v6_capable)
- im->v6_flag = 0;
- im->daddr = (md->cast_flags == MDF_BCAST)
- ? GET_INADDR(md->interface->bcast)
- : (md->cast_flags
- ? (GET_INADDR(md->interface->sin)
- ? GET_INADDR(md->interface->sin)
- : GET_INADDR(md->interface->bcast))
- : 4);
- }
- im->flags = htonl(md->cast_flags);
- im->port = md->rmtport;
- im->mode = md->mode;
- im->version = md->version;
- im = (struct info_monitor_1 *)more_pkt();
- }
- flush_pkt();
-}
/*
* Module entry points and the flags they correspond with
*/
struct reset_entry {
int flag; /* flag this corresponds to */
- void (*handler) P((void)); /* routine to handle request */
+ void (*handler)(void); /* routine to handle request */
};
struct reset_entry reset_entries[] = {
@@ -2025,11 +1825,12 @@ struct reset_entry reset_entries[] = {
*/
static void
reset_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
+ struct reset_flags *rflags;
u_long flags;
struct reset_entry *rent;
@@ -2039,9 +1840,9 @@ reset_stats(
return;
}
- flags = ((struct reset_flags *)inpkt->data)->flags;
- flags = ntohl(flags);
-
+ rflags = (struct reset_flags *)&inpkt->u;
+ flags = ntohl(rflags->flags);
+
if (flags & ~RESET_ALLFLAGS) {
msyslog(LOG_ERR, "reset_stats: reset leaves %#lx",
flags & ~RESET_ALLFLAGS);
@@ -2051,7 +1852,7 @@ reset_stats(
for (rent = reset_entries; rent->flag != 0; rent++) {
if (flags & rent->flag)
- (rent->handler)();
+ (*rent->handler)();
}
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -2062,16 +1863,18 @@ reset_stats(
*/
static void
reset_peer(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct conf_unpeer *cp;
- register int items;
- register struct peer *peer;
- struct sockaddr_storage peeraddr;
- int bad;
+ u_short items;
+ size_t item_sz;
+ char * datap;
+ struct conf_unpeer cp;
+ struct peer * p;
+ sockaddr_u peeraddr;
+ int bad;
/*
* We check first to see that every peer exists. If not,
@@ -2079,27 +1882,33 @@ reset_peer(
*/
items = INFO_NITEMS(inpkt->err_nitems);
- cp = (struct conf_unpeer *)inpkt->data;
+ item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
+ datap = inpkt->u.data;
+ if (item_sz > sizeof(cp)) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
+ return;
+ }
- bad = 0;
+ bad = FALSE;
while (items-- > 0 && !bad) {
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- if (client_v6_capable && cp->v6_flag != 0) {
- GET_INADDR6(peeraddr) = cp->peeraddr6;
- peeraddr.ss_family = AF_INET6;
+ ZERO(cp);
+ memcpy(&cp, datap, item_sz);
+ ZERO_SOCK(&peeraddr);
+ if (client_v6_capable && cp.v6_flag) {
+ AF(&peeraddr) = AF_INET6;
+ SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
} else {
- GET_INADDR(peeraddr) = cp->peeraddr;
- peeraddr.ss_family = AF_INET;
+ AF(&peeraddr) = AF_INET;
+ NSRCADR(&peeraddr) = cp.peeraddr;
}
- NSRCPORT(&peeraddr) = htons(NTP_PORT);
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- peeraddr.ss_len = SOCKLEN(&peeraddr);
+
+#ifdef ISC_PLATFORM_HAVESALEN
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
- peer = findexistingpeer(&peeraddr, (struct peer *)0, -1);
- if (peer == (struct peer *)0)
- bad++;
- cp = (struct conf_unpeer *)((char *)cp +
- INFO_ITEMSIZE(inpkt->mbz_itemsize));
+ p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
+ if (NULL == p)
+ bad++;
+ datap += item_sz;
}
if (bad) {
@@ -2111,27 +1920,28 @@ reset_peer(
* Now do it in earnest.
*/
- items = INFO_NITEMS(inpkt->err_nitems);
- cp = (struct conf_unpeer *)inpkt->data;
+ datap = inpkt->u.data;
while (items-- > 0) {
- memset((char *)&peeraddr, 0, sizeof(peeraddr));
- if (client_v6_capable && cp->v6_flag != 0) {
- GET_INADDR6(peeraddr) = cp->peeraddr6;
- peeraddr.ss_family = AF_INET6;
+ ZERO(cp);
+ memcpy(&cp, datap, item_sz);
+ ZERO_SOCK(&peeraddr);
+ if (client_v6_capable && cp.v6_flag) {
+ AF(&peeraddr) = AF_INET6;
+ SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
} else {
- GET_INADDR(peeraddr) = cp->peeraddr;
- peeraddr.ss_family = AF_INET;
+ AF(&peeraddr) = AF_INET;
+ NSRCADR(&peeraddr) = cp.peeraddr;
}
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- peeraddr.ss_len = SOCKLEN(&peeraddr);
+ SET_PORT(&peeraddr, 123);
+#ifdef ISC_PLATFORM_HAVESALEN
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
- peer = findexistingpeer(&peeraddr, (struct peer *)0, -1);
- while (peer != 0) {
- peer_reset(peer);
- peer = findexistingpeer(&peeraddr, (struct peer *)peer, -1);
+ p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
+ while (p != NULL) {
+ peer_reset(p);
+ p = findexistingpeer(&peeraddr, NULL, p, -1, 0);
}
- cp = (struct conf_unpeer *)((char *)cp +
- INFO_ITEMSIZE(inpkt->mbz_itemsize));
+ datap += item_sz;
}
req_ack(srcadr, inter, inpkt, INFO_OKAY);
@@ -2143,8 +1953,8 @@ reset_peer(
*/
static void
do_key_reread(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2158,8 +1968,8 @@ do_key_reread(
*/
static void
trust_key(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2172,8 +1982,8 @@ trust_key(
*/
static void
untrust_key(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2186,8 +1996,8 @@ untrust_key(
*/
static void
do_trustkey(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt,
u_long trust
)
@@ -2196,7 +2006,7 @@ do_trustkey(
register int items;
items = INFO_NITEMS(inpkt->err_nitems);
- kp = (u_long *)inpkt->data;
+ kp = (u_long *)&inpkt->u;
while (items-- > 0) {
authtrust(*kp, trust);
kp++;
@@ -2211,25 +2021,13 @@ do_trustkey(
*/
static void
get_auth_info(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
register struct info_auth *ia;
- /*
- * Importations from the authentication module
- */
- extern u_long authnumkeys;
- extern int authnumfreekeys;
- extern u_long authkeylookups;
- extern u_long authkeynotfound;
- extern u_long authencryptions;
- extern u_long authdecryptions;
- extern u_long authkeyuncached;
- extern u_long authkeyexpired;
-
ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_auth));
@@ -2253,18 +2051,9 @@ get_auth_info(
* reset_auth_stats - reset the authentication stat counters. Done here
* to keep ntp-isms out of the authentication module
*/
-static void
+void
reset_auth_stats(void)
{
- /*
- * Importations from the authentication module
- */
- extern u_long authkeylookups;
- extern u_long authkeynotfound;
- extern u_long authencryptions;
- extern u_long authdecryptions;
- extern u_long authkeyuncached;
-
authkeylookups = 0;
authkeynotfound = 0;
authencryptions = 0;
@@ -2279,20 +2068,14 @@ reset_auth_stats(void)
*/
static void
req_get_traps(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- register struct info_trap *it;
- register struct ctl_trap *tr;
- register int i;
-
- /*
- * Imported from the control module
- */
- extern struct ctl_trap ctl_trap[];
- extern int num_ctl_traps;
+ struct info_trap *it;
+ struct ctl_trap *tr;
+ size_t i;
if (num_ctl_traps == 0) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
@@ -2302,23 +2085,23 @@ req_get_traps(
it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt,
v6sizeof(struct info_trap));
- for (i = 0, tr = ctl_trap; i < CTL_MAXTRAPS; i++, tr++) {
+ for (i = 0, tr = ctl_traps; i < COUNTOF(ctl_traps); i++, tr++) {
if (tr->tr_flags & TRAP_INUSE) {
- if (tr->tr_addr.ss_family == AF_INET) {
+ if (IS_IPV4(&tr->tr_addr)) {
if (tr->tr_localaddr == any_interface)
it->local_address = 0;
else
it->local_address
- = GET_INADDR(tr->tr_localaddr->sin);
- it->trap_address = GET_INADDR(tr->tr_addr);
+ = NSRCADR(&tr->tr_localaddr->sin);
+ it->trap_address = NSRCADR(&tr->tr_addr);
if (client_v6_capable)
it->v6_flag = 0;
} else {
if (!client_v6_capable)
continue;
it->local_address6
- = GET_INADDR6(tr->tr_localaddr->sin);
- it->trap_address6 = GET_INADDR6(tr->tr_addr);
+ = SOCK_ADDR6(&tr->tr_localaddr->sin);
+ it->trap_address6 = SOCK_ADDR6(&tr->tr_addr);
it->v6_flag = 1;
}
it->trap_port = NSRCPORT(&tr->tr_addr);
@@ -2339,8 +2122,8 @@ req_get_traps(
*/
static void
req_set_trap(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2354,8 +2137,8 @@ req_set_trap(
*/
static void
req_clr_trap(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2369,23 +2152,23 @@ req_clr_trap(
*/
static void
do_setclr_trap(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt,
int set
)
{
register struct conf_trap *ct;
- register struct interface *linter;
+ register endpt *linter;
int res;
- struct sockaddr_storage laddr;
+ sockaddr_u laddr;
/*
- * Prepare sockaddr_storage structure
+ * Prepare sockaddr
*/
- memset((char *)&laddr, 0, sizeof laddr);
- laddr.ss_family = srcadr->ss_family;
- NSRCPORT(&laddr) = ntohs(NTP_PORT);
+ ZERO_SOCK(&laddr);
+ AF(&laddr) = AF(srcadr);
+ SET_PORT(&laddr, NTP_PORT);
/*
* Restrict ourselves to one item only. This eliminates
@@ -2396,7 +2179,7 @@ do_setclr_trap(
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
- ct = (struct conf_trap *)inpkt->data;
+ ct = (struct conf_trap *)&inpkt->u;
/*
* Look for the local interface. If none, use the default.
@@ -2404,25 +2187,25 @@ do_setclr_trap(
if (ct->local_address == 0) {
linter = any_interface;
} else {
- if (laddr.ss_family == AF_INET)
- GET_INADDR(laddr) = ct->local_address;
+ if (IS_IPV4(&laddr))
+ NSRCADR(&laddr) = ct->local_address;
else
- GET_INADDR6(laddr) = ct->local_address6;
+ SOCK_ADDR6(&laddr) = ct->local_address6;
linter = findinterface(&laddr);
- if (linter == NULL) {
+ if (NULL == linter) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
return;
}
}
- if (laddr.ss_family == AF_INET)
- GET_INADDR(laddr) = ct->trap_address;
+ if (IS_IPV4(&laddr))
+ NSRCADR(&laddr) = ct->trap_address;
else
- GET_INADDR6(laddr) = ct->trap_address6;
- if (ct->trap_port != 0)
- NSRCPORT(&laddr) = ct->trap_port;
+ SOCK_ADDR6(&laddr) = ct->trap_address6;
+ if (ct->trap_port)
+ NSRCPORT(&laddr) = ct->trap_port;
else
- NSRCPORT(&laddr) = htons(TRAPPORT);
+ SET_PORT(&laddr, TRAPPORT);
if (set) {
res = ctlsettrap(&laddr, linter, 0,
@@ -2446,12 +2229,12 @@ do_setclr_trap(
*/
static void
set_request_keyid(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- keyid_t keyid;
+ keyid_t *pkeyid;
/*
* Restrict ourselves to one item only.
@@ -2462,8 +2245,8 @@ set_request_keyid(
return;
}
- keyid = ntohl(*((u_int32 *)(inpkt->data)));
- info_auth_keyid = keyid;
+ pkeyid = (keyid_t *)&inpkt->u;
+ info_auth_keyid = ntohl(*pkeyid);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -2474,13 +2257,12 @@ set_request_keyid(
*/
static void
set_control_keyid(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
- keyid_t keyid;
- extern keyid_t ctl_auth_keyid;
+ keyid_t *pkeyid;
/*
* Restrict ourselves to one item only.
@@ -2491,8 +2273,8 @@ set_control_keyid(
return;
}
- keyid = ntohl(*((u_int32 *)(inpkt->data)));
- ctl_auth_keyid = keyid;
+ pkeyid = (keyid_t *)&inpkt->u;
+ ctl_auth_keyid = ntohl(*pkeyid);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -2503,32 +2285,13 @@ set_control_keyid(
*/
static void
get_ctl_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
register struct info_control *ic;
- /*
- * Importations from the control module
- */
- extern u_long ctltimereset;
- extern u_long numctlreq;
- extern u_long numctlbadpkts;
- extern u_long numctlresponses;
- extern u_long numctlfrags;
- extern u_long numctlerrors;
- extern u_long numctltooshort;
- extern u_long numctlinputresp;
- extern u_long numctlinputfrag;
- extern u_long numctlinputerr;
- extern u_long numctlbadoffset;
- extern u_long numctlbadversion;
- extern u_long numctldatatooshort;
- extern u_long numctlbadop;
- extern u_long numasyncmsgs;
-
ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_control));
@@ -2559,8 +2322,8 @@ get_ctl_stats(
*/
static void
get_kernel_info(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2572,7 +2335,7 @@ get_kernel_info(
return;
}
- memset((char *)&ntx, 0, sizeof(ntx));
+ ZERO(ntx);
if (ntp_adjtime(&ntx) < 0)
msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m");
ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt,
@@ -2614,8 +2377,8 @@ get_kernel_info(
*/
static void
get_clock_info(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2623,36 +2386,34 @@ get_clock_info(
register u_int32 *clkaddr;
register int items;
struct refclockstat clock_stat;
- struct sockaddr_storage addr;
- struct sockaddr_in tmp_clock;
+ sockaddr_u addr;
l_fp ltmp;
- memset((char *)&addr, 0, sizeof addr);
- addr.ss_family = AF_INET;
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- addr.ss_len = SOCKLEN(&addr);
+ ZERO_SOCK(&addr);
+ AF(&addr) = AF_INET;
+#ifdef ISC_PLATFORM_HAVESALEN
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
- NSRCPORT(&addr) = htons(NTP_PORT);
+ SET_PORT(&addr, NTP_PORT);
items = INFO_NITEMS(inpkt->err_nitems);
- clkaddr = (u_int32 *) inpkt->data;
+ clkaddr = &inpkt->u.u32[0];
ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_clock));
while (items-- > 0) {
- tmp_clock.sin_addr.s_addr = *clkaddr++;
- CAST_V4(addr)->sin_addr = tmp_clock.sin_addr;
- if (!ISREFCLOCKADR(&tmp_clock) ||
- findexistingpeer(&addr, (struct peer *)0, -1) == 0) {
+ NSRCADR(&addr) = *clkaddr++;
+ if (!ISREFCLOCKADR(&addr) || NULL ==
+ findexistingpeer(&addr, NULL, NULL, -1, 0)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
return;
}
clock_stat.kv_list = (struct ctl_var *)0;
- refclock_control(&addr, (struct refclockstat *)0, &clock_stat);
+ refclock_control(&addr, NULL, &clock_stat);
- ic->clockadr = tmp_clock.sin_addr.s_addr;
+ ic->clockadr = NSRCADR(&addr);
ic->type = clock_stat.type;
ic->flags = clock_stat.flags;
ic->lastevent = clock_stat.lastevent;
@@ -2667,7 +2428,7 @@ get_clock_info(
DTOLFP(clock_stat.fudgetime2, &ltmp);
HTONL_FP(&ltmp, &ic->fudgetime2);
ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1);
- ic->fudgeval2 = htonl((u_int32)clock_stat.fudgeval2);
+ ic->fudgeval2 = htonl(clock_stat.fudgeval2);
free_varlist(clock_stat.kv_list);
@@ -2683,33 +2444,31 @@ get_clock_info(
*/
static void
set_clock_fudge(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
register struct conf_fudge *cf;
register int items;
struct refclockstat clock_stat;
- struct sockaddr_storage addr;
- struct sockaddr_in tmp_clock;
+ sockaddr_u addr;
l_fp ltmp;
- memset((char *)&addr, 0, sizeof addr);
- memset((char *)&clock_stat, 0, sizeof clock_stat);
+ ZERO(addr);
+ ZERO(clock_stat);
items = INFO_NITEMS(inpkt->err_nitems);
- cf = (struct conf_fudge *) inpkt->data;
+ cf = (struct conf_fudge *)&inpkt->u;
while (items-- > 0) {
- tmp_clock.sin_addr.s_addr = cf->clockadr;
- *CAST_V4(addr) = tmp_clock;
- addr.ss_family = AF_INET;
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- addr.ss_len = SOCKLEN(&addr);
+ AF(&addr) = AF_INET;
+ NSRCADR(&addr) = cf->clockadr;
+#ifdef ISC_PLATFORM_HAVESALEN
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
- NSRCPORT(&addr) = htons(NTP_PORT);
- if (!ISREFCLOCKADR(&tmp_clock) ||
- findexistingpeer(&addr, (struct peer *)0, -1) == 0) {
+ SET_PORT(&addr, NTP_PORT);
+ if (!ISREFCLOCKADR(&addr) || NULL ==
+ findexistingpeer(&addr, NULL, NULL, -1, 0)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
return;
}
@@ -2757,8 +2516,8 @@ set_clock_fudge(
*/
static void
get_clkbug_info(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2767,38 +2526,36 @@ get_clkbug_info(
register u_int32 *clkaddr;
register int items;
struct refclockbug bug;
- struct sockaddr_storage addr;
- struct sockaddr_in tmp_clock;
+ sockaddr_u addr;
- memset((char *)&addr, 0, sizeof addr);
- addr.ss_family = AF_INET;
-#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
- addr.ss_len = SOCKLEN(&addr);
+ ZERO_SOCK(&addr);
+ AF(&addr) = AF_INET;
+#ifdef ISC_PLATFORM_HAVESALEN
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
- NSRCPORT(&addr) = htons(NTP_PORT);
+ SET_PORT(&addr, NTP_PORT);
items = INFO_NITEMS(inpkt->err_nitems);
- clkaddr = (u_int32 *) inpkt->data;
+ clkaddr = (u_int32 *)&inpkt->u;
ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_clkbug));
while (items-- > 0) {
- tmp_clock.sin_addr.s_addr = *clkaddr++;
- GET_INADDR(addr) = tmp_clock.sin_addr.s_addr;
- if (!ISREFCLOCKADR(&tmp_clock) ||
- findexistingpeer(&addr, (struct peer *)0, -1) == 0) {
+ NSRCADR(&addr) = *clkaddr++;
+ if (!ISREFCLOCKADR(&addr) || NULL ==
+ findexistingpeer(&addr, NULL, NULL, -1, 0)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
return;
}
- memset((char *)&bug, 0, sizeof bug);
+ ZERO(bug);
refclock_buginfo(&addr, &bug);
if (bug.nvalues == 0 && bug.ntimes == 0) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
return;
}
- ic->clockadr = tmp_clock.sin_addr.s_addr;
+ ic->clockadr = NSRCADR(&addr);
i = bug.nvalues;
if (i > NUMCBUGVALUES)
i = NUMCBUGVALUES;
@@ -2830,39 +2587,40 @@ fill_info_if_stats(void *data, interface_info_t *interface_info)
{
struct info_if_stats **ifsp = (struct info_if_stats **)data;
struct info_if_stats *ifs = *ifsp;
- struct interface *interface = interface_info->interface;
+ endpt *ep = interface_info->ep;
- memset((char*)ifs, 0, sizeof(*ifs));
+ ZERO(*ifs);
- if (interface->sin.ss_family == AF_INET6) {
+ if (IS_IPV6(&ep->sin)) {
if (!client_v6_capable) {
return;
}
ifs->v6_flag = 1;
- memcpy((char *)&ifs->unaddr.addr6, (char *)&CAST_V6(interface->sin)->sin6_addr, sizeof(struct in6_addr));
- memcpy((char *)&ifs->unbcast.addr6, (char *)&CAST_V6(interface->bcast)->sin6_addr, sizeof(struct in6_addr));
- memcpy((char *)&ifs->unmask.addr6, (char *)&CAST_V6(interface->mask)->sin6_addr, sizeof(struct in6_addr));
+ ifs->unaddr.addr6 = SOCK_ADDR6(&ep->sin);
+ ifs->unbcast.addr6 = SOCK_ADDR6(&ep->bcast);
+ ifs->unmask.addr6 = SOCK_ADDR6(&ep->mask);
} else {
ifs->v6_flag = 0;
- memcpy((char *)&ifs->unaddr.addr, (char *)&CAST_V4(interface->sin)->sin_addr, sizeof(struct in_addr));
- memcpy((char *)&ifs->unbcast.addr, (char *)&CAST_V4(interface->bcast)->sin_addr, sizeof(struct in_addr));
- memcpy((char *)&ifs->unmask.addr, (char *)&CAST_V4(interface->mask)->sin_addr, sizeof(struct in_addr));
+ ifs->unaddr.addr = SOCK_ADDR4(&ep->sin);
+ ifs->unbcast.addr = SOCK_ADDR4(&ep->bcast);
+ ifs->unmask.addr = SOCK_ADDR4(&ep->mask);
}
ifs->v6_flag = htonl(ifs->v6_flag);
- strcpy(ifs->name, interface->name);
- ifs->family = htons(interface->family);
- ifs->flags = htonl(interface->flags);
- ifs->last_ttl = htonl(interface->last_ttl);
- ifs->num_mcast = htonl(interface->num_mcast);
- ifs->received = htonl(interface->received);
- ifs->sent = htonl(interface->sent);
- ifs->notsent = htonl(interface->notsent);
- ifs->scopeid = htonl(interface->scopeid);
- ifs->ifindex = htonl(interface->ifindex);
- ifs->ifnum = htonl(interface->ifnum);
- ifs->uptime = htonl(current_time - interface->starttime);
- ifs->ignore_packets = interface->ignore_packets;
- ifs->peercnt = htonl(interface->peercnt);
+ strlcpy(ifs->name, ep->name, sizeof(ifs->name));
+ ifs->family = htons(ep->family);
+ ifs->flags = htonl(ep->flags);
+ ifs->last_ttl = htonl(ep->last_ttl);
+ ifs->num_mcast = htonl(ep->num_mcast);
+ ifs->received = htonl(ep->received);
+ ifs->sent = htonl(ep->sent);
+ ifs->notsent = htonl(ep->notsent);
+ ifs->ifindex = htonl(ep->ifindex);
+ /* scope no longer in endpt, in in6_addr typically */
+ ifs->scopeid = ifs->ifindex;
+ ifs->ifnum = htonl(ep->ifnum);
+ ifs->uptime = htonl(current_time - ep->starttime);
+ ifs->ignore_packets = ep->ignore_packets;
+ ifs->peercnt = htonl(ep->peercnt);
ifs->action = interface_info->action;
*ifsp = (struct info_if_stats *)more_pkt();
@@ -2873,8 +2631,8 @@ fill_info_if_stats(void *data, interface_info_t *interface_info)
*/
static void
get_if_stats(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
@@ -2892,8 +2650,8 @@ get_if_stats(
static void
do_if_reload(
- struct sockaddr_storage *srcadr,
- struct interface *inter,
+ sockaddr_u *srcadr,
+ endpt *inter,
struct req_pkt *inpkt
)
{
diff --git a/contrib/ntp/ntpd/ntp_restrict.c b/contrib/ntp/ntpd/ntp_restrict.c
index 473e2ce..9948d54 100644
--- a/contrib/ntp/ntpd/ntp_restrict.c
+++ b/contrib/ntp/ntpd/ntp_restrict.c
@@ -10,7 +10,9 @@
#include "ntpd.h"
#include "ntp_if.h"
+#include "ntp_lists.h"
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
/*
* This code keeps a simple address-and-mask list of hosts we want
@@ -41,65 +43,75 @@
* addresses. This is not protocol-independant but for now I can't
* find a way to respect this. We'll check this later... JFB 07/2001
*/
-#define SET_IPV6_ADDR_MASK(dst, src, msk) \
- do { \
- int idx; \
- for (idx = 0; idx < 16; idx++) { \
- (dst)->s6_addr[idx] = \
- (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
- } \
+#define MASK_IPV6_ADDR(dst, src, msk) \
+ do { \
+ int idx; \
+ for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \
+ (dst)->s6_addr[idx] = (src)->s6_addr[idx] \
+ & (msk)->s6_addr[idx]; \
+ } \
} while (0)
/*
- * Memory allocation parameters. We allocate INITRESLIST entries
- * initially, and add INCRESLIST entries to the free list whenever
- * we run out.
+ * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
+ * Auto-tune these to be just less than 1KB (leaving at least 16 bytes
+ * for allocator overhead).
*/
-#define INITRESLIST 10
-#define INCRESLIST 5
-
-#define RES_AVG 8. /* interpacket averaging factor */
+#define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U)
+#define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U)
/*
* The restriction list
*/
-struct restrictlist *restrictlist;
-struct restrictlist6 *restrictlist6;
-static int restrictcount; /* count of entries in the res list */
-static int restrictcount6; /* count of entries in the res list 2*/
+restrict_u *restrictlist4;
+restrict_u *restrictlist6;
+static int restrictcount; /* count in the restrict lists */
/*
* The free list and associated counters. Also some uninteresting
* stat counters.
*/
-static struct restrictlist *resfree;
-static struct restrictlist6 *resfree6;
-static int numresfree; /* number of structures on free list */
-static int numresfree6; /* number of structures on free list 2 */
+static restrict_u *resfree4; /* available entries (free list) */
+static restrict_u *resfree6;
-static u_long res_calls;
-static u_long res_found;
-static u_long res_not_found;
+static u_long res_calls;
+static u_long res_found;
+static u_long res_not_found;
/*
- * Parameters of the RES_LIMITED restriction option.
+ * Count number of restriction entries referring to RES_LIMITED, to
+ * control implicit activation/deactivation of the MRU monlist.
*/
-u_long res_avg_interval = 5; /* min average interpacket interval */
-u_long res_min_interval = 1; /* min interpacket interval */
+static u_long res_limited_refcnt;
/*
- * Count number of restriction entries referring to RES_LIMITED controls
- * activation/deactivation of monitoring (with respect to RES_LIMITED
- * control)
+ * Our default entries.
*/
-static u_long res_limited_refcnt;
-static u_long res_limited_refcnt6;
+static restrict_u restrict_def4;
+static restrict_u restrict_def6;
+
+/*
+ * "restrict source ..." enabled knob and restriction bits.
+ */
+static int restrict_source_enabled;
+static u_short restrict_source_flags;
+static u_short restrict_source_mflags;
/*
- * Our initial allocation of lists entries.
+ * private functions
*/
-static struct restrictlist resinit[INITRESLIST];
-static struct restrictlist6 resinit6[INITRESLIST];
+static restrict_u * alloc_res4(void);
+static restrict_u * alloc_res6(void);
+static void free_res(restrict_u *, int);
+static void inc_res_limited(void);
+static void dec_res_limited(void);
+static restrict_u * match_restrict4_addr(u_int32, u_short);
+static restrict_u * match_restrict6_addr(const struct in6_addr *,
+ u_short);
+static restrict_u * match_restrict_entry(const restrict_u *, int);
+static int res_sorts_before4(restrict_u *, restrict_u *);
+static int res_sorts_before6(restrict_u *, restrict_u *);
+
/*
* init_restrict - initialize the restriction data structures
@@ -107,103 +119,329 @@ static struct restrictlist6 resinit6[INITRESLIST];
void
init_restrict(void)
{
- register int i;
-
/*
- * Zero the list and put all but one on the free list
+ * The restriction lists begin with a default entry with address
+ * and mask 0, which will match any entry. The lists are kept
+ * sorted by descending address followed by descending mask:
+ *
+ * address mask
+ * 192.168.0.0 255.255.255.0 kod limited noquery nopeer
+ * 192.168.0.0 255.255.0.0 kod limited
+ * 0.0.0.0 0.0.0.0 kod limited noquery
+ *
+ * The first entry which matches an address is used. With the
+ * example restrictions above, 192.168.0.0/24 matches the first
+ * entry, the rest of 192.168.0.0/16 matches the second, and
+ * everything else matches the third (default).
+ *
+ * Note this achieves the same result a little more efficiently
+ * than the documented behavior, which is to keep the lists
+ * sorted by ascending address followed by ascending mask, with
+ * the _last_ matching entry used.
+ *
+ * An additional wrinkle is we may have multiple entries with
+ * the same address and mask but differing match flags (mflags).
+ * At present there is only one, RESM_NTPONLY. Entries with
+ * RESM_NTPONLY are sorted earlier so they take precedence over
+ * any otherwise similar entry without. Again, this is the same
+ * behavior as but reversed implementation compared to the docs.
+ *
*/
- resfree = NULL;
- memset((char *)resinit, 0, sizeof resinit);
- resfree6 = NULL;
- memset((char *)resinit6, 0, sizeof resinit6);
- for (i = 1; i < INITRESLIST; i++) {
- resinit[i].next = resfree;
- resinit6[i].next = resfree6;
- resfree = &resinit[i];
- resfree6 = &resinit6[i];
+ LINK_SLIST(restrictlist4, &restrict_def4, link);
+ LINK_SLIST(restrictlist6, &restrict_def6, link);
+ restrictcount = 2;
+}
+
+
+static restrict_u *
+alloc_res4(void)
+{
+ const size_t cb = V4_SIZEOF_RESTRICT_U;
+ const size_t count = INC_RESLIST4;
+ restrict_u * rl;
+ restrict_u * res;
+ int i;
+
+ UNLINK_HEAD_SLIST(res, resfree4, link);
+ if (res != NULL)
+ return res;
+
+ rl = emalloc_zero(count * cb);
+ /* link all but the first onto free list */
+ res = (void *)((char *)rl + (count - 1) * cb);
+ for (i = count - 1; i > 0; i--) {
+ LINK_SLIST(resfree4, res, link);
+ res = (void *)((char *)res - cb);
}
- numresfree = INITRESLIST-1;
- numresfree6 = INITRESLIST-1;
+ NTP_INSIST(rl == res);
+ /* allocate the first */
+ return res;
+}
- /*
- * Put the remaining item at the head of the list as our default
- * entry. Everything in here should be zero for now.
- */
- resinit[0].addr = htonl(INADDR_ANY);
- resinit[0].mask = 0;
- memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr));
- memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr));
- restrictlist = &resinit[0];
- restrictlist6 = &resinit6[0];
- restrictcount = 1;
- restrictcount = 2;
- /*
- * fix up stat counters
- */
- res_calls = 0;
- res_found = 0;
- res_not_found = 0;
+static restrict_u *
+alloc_res6(void)
+{
+ const size_t cb = V6_SIZEOF_RESTRICT_U;
+ const size_t count = INC_RESLIST6;
+ restrict_u * rl;
+ restrict_u * res;
+ int i;
+
+ UNLINK_HEAD_SLIST(res, resfree6, link);
+ if (res != NULL)
+ return res;
+
+ rl = emalloc_zero(count * cb);
+ /* link all but the first onto free list */
+ res = (void *)((char *)rl + (count - 1) * cb);
+ for (i = count - 1; i > 0; i--) {
+ LINK_SLIST(resfree6, res, link);
+ res = (void *)((char *)res - cb);
+ }
+ NTP_INSIST(rl == res);
+ /* allocate the first */
+ return res;
+}
- /*
- * set default values for RES_LIMIT functionality
- */
- res_limited_refcnt = 0;
- res_limited_refcnt6 = 0;
+
+static void
+free_res(
+ restrict_u * res,
+ int v6
+ )
+{
+ restrict_u ** plisthead;
+ restrict_u * unlinked;
+
+ restrictcount--;
+ if (RES_LIMITED & res->flags)
+ dec_res_limited();
+
+ if (v6)
+ plisthead = &restrictlist6;
+ else
+ plisthead = &restrictlist4;
+ UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u);
+ NTP_INSIST(unlinked == res);
+
+ if (v6) {
+ zero_mem(res, V6_SIZEOF_RESTRICT_U);
+ plisthead = &resfree6;
+ } else {
+ zero_mem(res, V4_SIZEOF_RESTRICT_U);
+ plisthead = &resfree4;
+ }
+ LINK_SLIST(*plisthead, res, link);
+}
+
+
+static void
+inc_res_limited(void)
+{
+ if (!res_limited_refcnt)
+ mon_start(MON_RES);
+ res_limited_refcnt++;
+}
+
+
+static void
+dec_res_limited(void)
+{
+ res_limited_refcnt--;
+ if (!res_limited_refcnt)
+ mon_stop(MON_RES);
+}
+
+
+static restrict_u *
+match_restrict4_addr(
+ u_int32 addr,
+ u_short port
+ )
+{
+ const int v6 = 0;
+ restrict_u * res;
+ restrict_u * next;
+
+ for (res = restrictlist4; res != NULL; res = next) {
+ next = res->link;
+ if (res->expire &&
+ res->expire <= current_time)
+ free_res(res, v6);
+ if (res->u.v4.addr == (addr & res->u.v4.mask)
+ && (!(RESM_NTPONLY & res->mflags)
+ || NTP_PORT == port))
+ break;
+ }
+ return res;
+}
+
+
+static restrict_u *
+match_restrict6_addr(
+ const struct in6_addr * addr,
+ u_short port
+ )
+{
+ const int v6 = 1;
+ restrict_u * res;
+ restrict_u * next;
+ struct in6_addr masked;
+
+ for (res = restrictlist6; res != NULL; res = next) {
+ next = res->link;
+ NTP_INSIST(next != res);
+ if (res->expire &&
+ res->expire <= current_time)
+ free_res(res, v6);
+ MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
+ if (ADDR6_EQ(&masked, &res->u.v6.addr)
+ && (!(RESM_NTPONLY & res->mflags)
+ || NTP_PORT == (int)port))
+ break;
+ }
+ return res;
+}
+
+
+/*
+ * match_restrict_entry - find an exact match on a restrict list.
+ *
+ * Exact match is addr, mask, and mflags all equal.
+ * In order to use more common code for IPv4 and IPv6, this routine
+ * requires the caller to populate a restrict_u with mflags and either
+ * the v4 or v6 address and mask as appropriate. Other fields in the
+ * input restrict_u are ignored.
+ */
+static restrict_u *
+match_restrict_entry(
+ const restrict_u * pmatch,
+ int v6
+ )
+{
+ restrict_u *res;
+ restrict_u *rlist;
+ size_t cb;
+
+ if (v6) {
+ rlist = restrictlist6;
+ cb = sizeof(pmatch->u.v6);
+ } else {
+ rlist = restrictlist4;
+ cb = sizeof(pmatch->u.v4);
+ }
+
+ for (res = rlist; res != NULL; res = res->link)
+ if (res->mflags == pmatch->mflags &&
+ !memcmp(&res->u, &pmatch->u, cb))
+ break;
+ return res;
+}
+
+
+/*
+ * res_sorts_before4 - compare two restrict4 entries
+ *
+ * Returns nonzero if r1 sorts before r2. We sort by descending
+ * address, then descending mask, then descending mflags, so sorting
+ * before means having a higher value.
+ */
+static int
+res_sorts_before4(
+ restrict_u *r1,
+ restrict_u *r2
+ )
+{
+ int r1_before_r2;
+
+ if (r1->u.v4.addr > r2->u.v4.addr)
+ r1_before_r2 = 1;
+ else if (r1->u.v4.addr < r2->u.v4.addr)
+ r1_before_r2 = 0;
+ else if (r1->u.v4.mask > r2->u.v4.mask)
+ r1_before_r2 = 1;
+ else if (r1->u.v4.mask < r2->u.v4.mask)
+ r1_before_r2 = 0;
+ else if (r1->mflags > r2->mflags)
+ r1_before_r2 = 1;
+ else
+ r1_before_r2 = 0;
+
+ return r1_before_r2;
+}
+
+
+/*
+ * res_sorts_before6 - compare two restrict6 entries
+ *
+ * Returns nonzero if r1 sorts before r2. We sort by descending
+ * address, then descending mask, then descending mflags, so sorting
+ * before means having a higher value.
+ */
+static int
+res_sorts_before6(
+ restrict_u *r1,
+ restrict_u *r2
+ )
+{
+ int r1_before_r2;
+ int cmp;
+
+ cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr);
+ if (cmp > 0) /* r1->addr > r2->addr */
+ r1_before_r2 = 1;
+ else if (cmp < 0) /* r2->addr > r1->addr */
+ r1_before_r2 = 0;
+ else {
+ cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask);
+ if (cmp > 0) /* r1->mask > r2->mask*/
+ r1_before_r2 = 1;
+ else if (cmp < 0) /* r2->mask > r1->mask */
+ r1_before_r2 = 0;
+ else if (r1->mflags > r2->mflags)
+ r1_before_r2 = 1;
+ else
+ r1_before_r2 = 0;
+ }
+
+ return r1_before_r2;
}
/*
* restrictions - return restrictions for this host
*/
-int
+u_short
restrictions(
- struct sockaddr_storage *srcadr,
- int at_listhead
+ sockaddr_u *srcadr
)
{
- struct restrictlist *rl;
- struct restrictlist *match = NULL;
- struct restrictlist6 *rl6;
- struct restrictlist6 *match6 = NULL;
- struct in6_addr hostaddr6;
- struct in6_addr hostservaddr6;
- u_int32 hostaddr;
- int flags = 0;
- int isntpport;
+ restrict_u *match;
+ struct in6_addr *pin6;
+ u_short flags;
res_calls++;
- if (srcadr->ss_family == AF_INET) {
- /*
- * We need the host address in host order. Also need to
- * know whether this is from the ntp port or not.
- */
- hostaddr = SRCADR(srcadr);
- isntpport = (SRCPORT(srcadr) == NTP_PORT);
-
+ flags = 0;
+ /* IPv4 source address */
+ if (IS_IPV4(srcadr)) {
/*
* Ignore any packets with a multicast source address
* (this should be done early in the receive process,
- * later!)
+ * not later!)
*/
if (IN_CLASSD(SRCADR(srcadr)))
return (int)RES_IGNORE;
+ match = match_restrict4_addr(SRCADR(srcadr),
+ SRCPORT(srcadr));
+ match->count++;
/*
- * Set match to first entry, which is default entry.
- * Work our way down from there.
+ * res_not_found counts only use of the final default
+ * entry, not any "restrict default ntpport ...", which
+ * would be just before the final default.
*/
- match = restrictlist;
- for (rl = match->next; rl != NULL && rl->addr <= hostaddr;
- rl = rl->next)
- if ((hostaddr & rl->mask) == rl->addr) {
- if ((rl->mflags & RESM_NTPONLY) &&
- !isntpport)
- continue;
- match = rl;
- }
- match->count++;
- if (match == restrictlist)
+ if (&restrict_def4 == match)
res_not_found++;
else
res_found++;
@@ -211,77 +449,24 @@ restrictions(
}
/* IPv6 source address */
- if (srcadr->ss_family == AF_INET6) {
- /*
- * Need to know whether this is from the ntp port or
- * not.
- */
- hostaddr6 = GET_INADDR6(*srcadr);
- isntpport = (ntohs((
- (struct sockaddr_in6 *)srcadr)->sin6_port) ==
- NTP_PORT);
+ if (IS_IPV6(srcadr)) {
+ pin6 = PSOCK_ADDR6(srcadr);
/*
* Ignore any packets with a multicast source address
* (this should be done early in the receive process,
- * later!)
+ * not later!)
*/
- if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
+ if (IN6_IS_ADDR_MULTICAST(pin6))
return (int)RES_IGNORE;
- /*
- * Set match to first entry, which is default entry.
- * Work our way down from there.
- */
- match6 = restrictlist6;
- for (rl6 = match6->next; rl6 != NULL &&
- (memcmp(&(rl6->addr6), &hostaddr6,
- sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
- SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
- &rl6->mask6);
- if (memcmp(&hostservaddr6, &(rl6->addr6),
- sizeof(hostservaddr6)) == 0) {
- if ((rl6->mflags & RESM_NTPONLY) &&
- !isntpport)
- continue;
- match6 = rl6;
- }
- }
- match6->count++;
- if (match6 == restrictlist6)
+ match = match_restrict6_addr(pin6, SRCPORT(srcadr));
+ match->count++;
+ if (&restrict_def6 == match)
res_not_found++;
else
res_found++;
- flags = match6->flags;
- }
-
- /*
- * The following implements a generalized call gap facility.
- * Douse the RES_LIMITED bit only if the interval since the last
- * packet is greater than res_min_interval and the average is
- * greater thatn res_avg_interval.
- */
- if (!at_listhead || mon_enabled == MON_OFF) {
- flags &= ~RES_LIMITED;
- } else {
- struct mon_data *md;
-
- /*
- * At this poin the most recent arrival is first in the
- * MRU list. Let the first 10 packets in for free until
- * the average stabilizes.
- */
- md = mon_mru_list.mru_next;
- if (md->avg_interval == 0)
- md->avg_interval = md->drop_count;
- else
- md->avg_interval += (md->drop_count -
- md->avg_interval) / RES_AVG;
- if (md->count < 10 || (md->drop_count >
- res_min_interval && md->avg_interval >
- res_avg_interval))
- flags &= ~RES_LIMITED;
- md->drop_count = flags;
+ flags = match->flags;
}
return (flags);
}
@@ -292,316 +477,193 @@ restrictions(
*/
void
hack_restrict(
- int op,
- struct sockaddr_storage *resaddr,
- struct sockaddr_storage *resmask,
- int mflags,
- int flags
+ int op,
+ sockaddr_u * resaddr,
+ sockaddr_u * resmask,
+ u_short mflags,
+ u_short flags,
+ u_long expire
)
{
- register u_int32 addr = 0;
- register u_int32 mask = 0;
- struct in6_addr addr6;
- struct in6_addr mask6;
- register struct restrictlist *rl = NULL;
- register struct restrictlist *rlprev = NULL;
- register struct restrictlist6 *rl6 = NULL;
- register struct restrictlist6 *rlprev6 = NULL;
- int i, addr_cmp, mask_cmp;
- memset(&addr6, 0, sizeof(struct in6_addr));
- memset(&mask6, 0, sizeof(struct in6_addr));
-
- if (resaddr->ss_family == AF_INET) {
+ int v6;
+ restrict_u match;
+ restrict_u * res;
+ restrict_u ** plisthead;
+
+ DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n",
+ op, stoa(resaddr), stoa(resmask), mflags, flags));
+
+ if (NULL == resaddr) {
+ NTP_REQUIRE(NULL == resmask);
+ NTP_REQUIRE(RESTRICT_FLAGS == op);
+ restrict_source_flags = flags;
+ restrict_source_mflags = mflags;
+ restrict_source_enabled = 1;
+ return;
+ }
+
+ ZERO(match);
+ /* silence VC9 potentially uninit warnings */
+ res = NULL;
+ v6 = 0;
+
+ if (IS_IPV4(resaddr)) {
+ v6 = 0;
/*
- * Get address and mask in host byte order
+ * Get address and mask in host byte order for easy
+ * comparison as u_int32
*/
- addr = SRCADR(resaddr);
- mask = SRCADR(resmask);
- addr &= mask; /* make sure low bits zero */
+ match.u.v4.addr = SRCADR(resaddr);
+ match.u.v4.mask = SRCADR(resmask);
+ match.u.v4.addr &= match.u.v4.mask;
+ } else if (IS_IPV6(resaddr)) {
+ v6 = 1;
/*
- * If this is the default address, point at first on
- * list. Else go searching for it.
+ * Get address and mask in network byte order for easy
+ * comparison as byte sequences (e.g. memcmp())
*/
- if (addr == 0) {
- rlprev = NULL;
- rl = restrictlist;
- } else {
- rlprev = restrictlist;
- rl = rlprev->next;
- while (rl != NULL) {
- if (rl->addr > addr) {
- rl = NULL;
- break;
- } else if (rl->addr == addr) {
- if (rl->mask == mask) {
- if ((mflags &
- RESM_NTPONLY) ==
- (rl->mflags &
- RESM_NTPONLY))
- break;
-
- if (!(mflags &
- RESM_NTPONLY)) {
- rl = NULL;
- break;
- }
- } else if (rl->mask > mask) {
- rl = NULL;
- break;
- }
- }
- rlprev = rl;
- rl = rl->next;
- }
- }
- }
+ match.u.v6.mask = SOCK_ADDR6(resmask);
+ MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
+ &match.u.v6.mask);
- if (resaddr->ss_family == AF_INET6) {
- mask6 = GET_INADDR6(*resmask);
- SET_IPV6_ADDR_MASK(&addr6,
- &GET_INADDR6(*resaddr), &mask6);
- if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
- rlprev6 = NULL;
- rl6 = restrictlist6;
- } else {
- rlprev6 = restrictlist6;
- rl6 = rlprev6->next;
- while (rl6 != NULL) {
- addr_cmp = memcmp(&rl6->addr6, &addr6,
- sizeof(addr6));
- if (addr_cmp > 0) {
- rl6 = NULL;
- break;
- } else if (addr_cmp == 0) {
- mask_cmp = memcmp(&rl6->mask6,
- &mask6, sizeof(mask6));
- if (mask_cmp == 0) {
- if ((mflags &
- RESM_NTPONLY) ==
- (rl6->mflags &
- RESM_NTPONLY))
- break;
-
- if (!(mflags &
- RESM_NTPONLY)) {
- rl6 = NULL;
- break;
- }
- } else if (mask_cmp > 0) {
- rl6 = NULL;
- break;
- }
- }
- rlprev6 = rl6;
- rl6 = rl6->next;
- }
- }
- }
+ } else /* not IPv4 nor IPv6 */
+ NTP_REQUIRE(0);
- /*
- * In case the above wasn't clear :-), either rl now points
- * at the entry this call refers to, or rl is zero and rlprev
- * points to the entry prior to where this one should go in
- * the sort.
- */
+ match.flags = flags;
+ match.mflags = mflags;
+ match.expire = expire;
+ res = match_restrict_entry(&match, v6);
- /*
- * Switch based on operation
- */
- if (resaddr->ss_family == AF_INET) {
- switch (op) {
- case RESTRICT_FLAGS:
- /*
- * Here we add bits to the flags. If this is a
- * new restriction add it.
- */
- if (rl == NULL) {
- if (resfree == NULL) {
- rl = (struct restrictlist *)
- emalloc(INCRESLIST *
- sizeof(struct
- restrictlist));
- memset((char *)rl, 0,
- INCRESLIST * sizeof(struct
- restrictlist));
- for (i = 0; i < INCRESLIST; i++) {
- rl->next = resfree;
- resfree = rl;
- rl++;
- }
- numresfree = INCRESLIST;
- }
-
- rl = resfree;
- resfree = rl->next;
- numresfree--;
-
- rl->addr = addr;
- rl->mask = mask;
- rl->mflags = (u_short)mflags;
-
- if (rlprev == NULL) {
- rl->next = restrictlist;
- restrictlist = rl;
- } else {
- rl->next = rlprev->next;
- rlprev->next = rl;
- }
- restrictcount++;
- }
- if ((rl->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt++;
- mon_start(MON_RES);
- }
- rl->flags |= (u_short)flags;
- break;
+ switch (op) {
- case RESTRICT_UNFLAG:
- /*
- * Remove some bits from the flags. If we didn't
- * find this one, just return.
- */
- if (rl != NULL) {
- if ((rl->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt--;
- if (res_limited_refcnt == 0)
- mon_stop(MON_RES);
- }
- rl->flags &= (u_short)~flags;
- }
- break;
-
- case RESTRICT_REMOVE:
- case RESTRICT_REMOVEIF:
- /*
- * Remove an entry from the table entirely if we
- * found one. Don't remove the default entry and
- * don't remove an interface entry.
- */
- if (rl != NULL
- && rl->addr != htonl(INADDR_ANY)
- && !(rl->mflags & RESM_INTERFACE && op != RESTRICT_REMOVEIF)) {
- if (rlprev != NULL) {
- rlprev->next = rl->next;
- } else {
- restrictlist = rl->next;
- }
- restrictcount--;
- if (rl->flags & RES_LIMITED) {
- res_limited_refcnt--;
- if (res_limited_refcnt == 0)
- mon_stop(MON_RES);
- }
- memset((char *)rl, 0,
- sizeof(struct restrictlist));
-
- rl->next = resfree;
- resfree = rl;
- numresfree++;
+ case RESTRICT_FLAGS:
+ /*
+ * Here we add bits to the flags. If this is a
+ * new restriction add it.
+ */
+ if (NULL == res) {
+ if (v6) {
+ res = alloc_res6();
+ memcpy(res, &match,
+ V6_SIZEOF_RESTRICT_U);
+ plisthead = &restrictlist6;
+ } else {
+ res = alloc_res4();
+ memcpy(res, &match,
+ V4_SIZEOF_RESTRICT_U);
+ plisthead = &restrictlist4;
}
- break;
+ LINK_SORT_SLIST(
+ *plisthead, res,
+ (v6)
+ ? res_sorts_before6(res, L_S_S_CUR())
+ : res_sorts_before4(res, L_S_S_CUR()),
+ link, restrict_u);
+ restrictcount++;
+ if (RES_LIMITED & flags)
+ inc_res_limited();
+ } else {
+ if ((RES_LIMITED & flags) &&
+ !(RES_LIMITED & res->flags))
+ inc_res_limited();
+ res->flags |= flags;
+ }
+ break;
- default:
- break;
+ case RESTRICT_UNFLAG:
+ /*
+ * Remove some bits from the flags. If we didn't
+ * find this one, just return.
+ */
+ if (res != NULL) {
+ if ((RES_LIMITED & res->flags)
+ && (RES_LIMITED & flags))
+ dec_res_limited();
+ res->flags &= ~flags;
}
- } else if (resaddr->ss_family == AF_INET6) {
- switch (op) {
- case RESTRICT_FLAGS:
- /*
- * Here we add bits to the flags. If this is a
- * new restriction add it.
- */
- if (rl6 == NULL) {
- if (resfree6 == NULL) {
- rl6 = (struct
- restrictlist6 *)emalloc(
- INCRESLIST * sizeof(struct
- restrictlist6));
- memset((char *)rl6, 0,
- INCRESLIST * sizeof(struct
- restrictlist6));
-
- for (i = 0; i < INCRESLIST;
- i++) {
- rl6->next = resfree6;
- resfree6 = rl6;
- rl6++;
- }
- numresfree6 = INCRESLIST;
- }
- rl6 = resfree6;
- resfree6 = rl6->next;
- numresfree6--;
- rl6->addr6 = addr6;
- rl6->mask6 = mask6;
- rl6->mflags = (u_short)mflags;
- if (rlprev6 != NULL) {
- rl6->next = rlprev6->next;
- rlprev6->next = rl6;
- } else {
- rl6->next = restrictlist6;
- restrictlist6 = rl6;
- }
- restrictcount6++;
- }
- if ((rl6->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt6++;
- mon_start(MON_RES);
- }
- rl6->flags |= (u_short)flags;
- break;
+ break;
- case RESTRICT_UNFLAG:
- /*
- * Remove some bits from the flags. If we didn't
- * find this one, just return.
- */
- if (rl6 != NULL) {
- if ((rl6->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt6--;
- if (res_limited_refcnt6 == 0)
- mon_stop(MON_RES);
- }
- rl6->flags &= (u_short)~flags;
- }
- break;
+ case RESTRICT_REMOVE:
+ case RESTRICT_REMOVEIF:
+ /*
+ * Remove an entry from the table entirely if we
+ * found one. Don't remove the default entry and
+ * don't remove an interface entry.
+ */
+ if (res != NULL
+ && (RESTRICT_REMOVEIF == op
+ || !(RESM_INTERFACE & res->mflags))
+ && res != &restrict_def4
+ && res != &restrict_def6)
+ free_res(res, v6);
+ break;
+
+ default: /* unknown op */
+ NTP_INSIST(0);
+ break;
+ }
- case RESTRICT_REMOVE:
- case RESTRICT_REMOVEIF:
- /*
- * Remove an entry from the table entirely if we
- * found one. Don't remove the default entry and
- * don't remove an interface entry.
- */
- if (rl6 != NULL &&
- !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
- && !(rl6->mflags & RESM_INTERFACE && op != RESTRICT_REMOVEIF)) {
- if (rlprev6 != NULL) {
- rlprev6->next = rl6->next;
- } else {
- restrictlist6 = rl6->next;
- }
- restrictcount6--;
- if (rl6->flags & RES_LIMITED) {
- res_limited_refcnt6--;
- if (res_limited_refcnt6 == 0)
- mon_stop(MON_RES);
- }
- memset((char *)rl6, 0,
- sizeof(struct restrictlist6));
- rl6->next = resfree6;
- resfree6 = rl6;
- numresfree6++;
- }
- break;
+}
- default:
- break;
- }
+
+/*
+ * restrict_source - maintains dynamic "restrict source ..." entries as
+ * peers come and go.
+ */
+void
+restrict_source(
+ sockaddr_u * addr,
+ int farewell, /* 0 to add, 1 to remove */
+ u_long expire /* 0 is infinite, valid until */
+ )
+{
+ sockaddr_u onesmask;
+ restrict_u * res;
+ int found_specific;
+
+ if (!restrict_source_enabled || SOCK_UNSPEC(addr) ||
+ IS_MCAST(addr) || ISREFCLOCKADR(addr))
+ return;
+
+ NTP_REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));
+
+ SET_HOSTMASK(&onesmask, AF(addr));
+ if (farewell) {
+ hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
+ 0, 0, 0);
+ DPRINTF(1, ("restrict_source: %s removed", stoa(addr)));
+ return;
+ }
+
+ /*
+ * If there is a specific entry for this address, hands
+ * off, as it is condidered more specific than "restrict
+ * server ...".
+ * However, if the specific entry found is a fleeting one
+ * added by pool_xmit() before soliciting, replace it
+ * immediately regardless of the expire value to make way
+ * for the more persistent entry.
+ */
+ if (IS_IPV4(addr)) {
+ res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr));
+ found_specific = (SRCADR(&onesmask) == res->u.v4.mask);
+ } else {
+ res = match_restrict6_addr(&SOCK_ADDR6(addr),
+ SRCPORT(addr));
+ found_specific = ADDR6_EQ(&res->u.v6.mask,
+ &SOCK_ADDR6(&onesmask));
+ }
+ if (!expire && found_specific && res->expire) {
+ found_specific = 0;
+ free_res(res, IS_IPV6(addr));
}
+ if (found_specific)
+ return;
+
+ hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
+ restrict_source_mflags, restrict_source_flags,
+ expire);
+ DPRINTF(1, ("restrict_source: %s host restriction added\n",
+ stoa(addr)));
}
diff --git a/contrib/ntp/ntpd/ntp_scanner.c b/contrib/ntp/ntpd/ntp_scanner.c
new file mode 100644
index 0000000..49adf6b
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_scanner.c
@@ -0,0 +1,935 @@
+
+/* ntp_scanner.c
+ *
+ * The source code for a simple lexical analyzer.
+ *
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
+ * Copyright (c) 2006
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ntpd.h"
+#include "ntp_config.h"
+#include "ntpsim.h"
+#include "ntp_scanner.h"
+#include "ntp_parser.h"
+
+/* ntp_keyword.h declares finite state machine and token text */
+#include "ntp_keyword.h"
+
+
+
+/* SCANNER GLOBAL VARIABLES
+ * ------------------------
+ */
+
+#define MAX_LEXEME (1024 + 1) /* The maximum size of a lexeme */
+char yytext[MAX_LEXEME]; /* Buffer for storing the input text/lexeme */
+u_int32 conf_file_sum; /* Simple sum of characters read */
+
+static struct FILE_INFO * lex_stack = NULL;
+
+
+
+/* CONSTANTS
+ * ---------
+ */
+
+
+/* SCANNER GLOBAL VARIABLES
+ * ------------------------
+ */
+const char special_chars[] = "{}(),;|=";
+
+
+/* FUNCTIONS
+ * ---------
+ */
+
+static int is_keyword(char *lexeme, follby *pfollowedby);
+
+
+/*
+ * keyword() - Return the keyword associated with token T_ identifier.
+ * See also token_name() for the string-ized T_ identifier.
+ * Example: keyword(T_Server) returns "server"
+ * token_name(T_Server) returns "T_Server"
+ */
+const char *
+keyword(
+ int token
+ )
+{
+ size_t i;
+ const char *text;
+
+ i = token - LOWEST_KEYWORD_ID;
+
+ if (i < COUNTOF(keyword_text))
+ text = keyword_text[i];
+ else
+ text = NULL;
+
+ return (text != NULL)
+ ? text
+ : "(keyword not found)";
+}
+
+
+/* FILE & STRING BUFFER INTERFACE
+ * ------------------------------
+ *
+ * This set out as a couple of wrapper functions around the standard C
+ * fgetc and ungetc functions in order to include positional
+ * bookkeeping. Alas, this is no longer a good solution with nested
+ * input files and the possibility to send configuration commands via
+ * 'ntpdc' and 'ntpq'.
+ *
+ * Now there are a few functions to maintain a stack of nested input
+ * sources (though nesting is only allowd for disk files) and from the
+ * scanner / parser point of view there's no difference between both
+ * types of sources.
+ *
+ * The 'fgetc()' / 'ungetc()' replacements now operate on a FILE_INFO
+ * structure. Instead of trying different 'ungetc()' strategies for file
+ * and buffer based parsing, we keep the backup char in our own
+ * FILE_INFO structure. This is sufficient, as the parser does *not*
+ * jump around via 'seek' or the like, and there's no need to
+ * check/clear the backup store in other places than 'lex_getch()'.
+ */
+
+/*
+ * Allocate an info structure and attach it to a file.
+ *
+ * Note: When 'mode' is NULL, then the INFO block will be set up to
+ * contain a NULL file pointer, as suited for remote config command
+ * parsing. Otherwise having a NULL file pointer is considered an error,
+ * and a NULL info block pointer is returned to indicate failure!
+ *
+ * Note: We use a variable-sized structure to hold a copy of the file
+ * name (or, more proper, the input source description). This is more
+ * secure than keeping a reference to some other storage that might go
+ * out of scope.
+ */
+static struct FILE_INFO *
+lex_open(
+ const char *path,
+ const char *mode
+ )
+{
+ struct FILE_INFO *stream;
+ size_t nnambuf;
+
+ nnambuf = strlen(path);
+ stream = emalloc_zero(sizeof(*stream) + nnambuf);
+ stream->curpos.nline = 1;
+ stream->backch = EOF;
+ /* copy name with memcpy -- trailing NUL already there! */
+ memcpy(stream->fname, path, nnambuf);
+
+ if (NULL != mode) {
+ stream->fpi = fopen(path, mode);
+ if (NULL == stream->fpi) {
+ free(stream);
+ stream = NULL;
+ }
+ }
+ return stream;
+}
+
+/* get next character from buffer or file. This will return any putback
+ * character first; it will also make sure the last line is at least
+ * virtually terminated with a '\n'.
+ */
+static int
+lex_getch(
+ struct FILE_INFO *stream
+ )
+{
+ int ch;
+
+ if (NULL == stream || stream->force_eof)
+ return EOF;
+
+ if (EOF != stream->backch) {
+ ch = stream->backch;
+ stream->backch = EOF;
+ if (stream->fpi)
+ conf_file_sum += ch;
+ } else if (stream->fpi) {
+ /* fetch next 7-bit ASCII char (or EOF) from file */
+ while ((ch = fgetc(stream->fpi)) != EOF && ch > SCHAR_MAX)
+ stream->curpos.ncol++;
+ if (EOF != ch) {
+ conf_file_sum += ch;
+ stream->curpos.ncol++;
+ }
+ } else {
+ /* fetch next 7-bit ASCII char from buffer */
+ const char * scan;
+ scan = &remote_config.buffer[remote_config.pos];
+ while ((ch = (u_char)*scan) > SCHAR_MAX) {
+ scan++;
+ stream->curpos.ncol++;
+ }
+ if ('\0' != ch) {
+ scan++;
+ stream->curpos.ncol++;
+ } else {
+ ch = EOF;
+ }
+ remote_config.pos = (int)(scan - remote_config.buffer);
+ }
+
+ /* If the last line ends without '\n', generate one. This
+ * happens most likely on Windows, where editors often have a
+ * sloppy concept of a line.
+ */
+ if (EOF == ch && stream->curpos.ncol != 0)
+ ch = '\n';
+
+ /* update scan position tallies */
+ if (ch == '\n') {
+ stream->bakpos = stream->curpos;
+ stream->curpos.nline++;
+ stream->curpos.ncol = 0;
+ }
+
+ return ch;
+}
+
+/* Note: lex_ungetch will fail to track more than one line of push
+ * back. But since it guarantees only one char of back storage anyway,
+ * this should not be a problem.
+ */
+static int
+lex_ungetch(
+ int ch,
+ struct FILE_INFO *stream
+ )
+{
+ /* check preconditions */
+ if (NULL == stream || stream->force_eof)
+ return EOF;
+ if (EOF != stream->backch || EOF == ch)
+ return EOF;
+
+ /* keep for later reference and update checksum */
+ stream->backch = (u_char)ch;
+ if (stream->fpi)
+ conf_file_sum -= stream->backch;
+
+ /* update position */
+ if (stream->backch == '\n') {
+ stream->curpos = stream->bakpos;
+ stream->bakpos.ncol = -1;
+ }
+ stream->curpos.ncol--;
+ return stream->backch;
+}
+
+/* dispose of an input structure. If the file pointer is not NULL, close
+ * the file. This function does not check the result of 'fclose()'.
+ */
+static void
+lex_close(
+ struct FILE_INFO *stream
+ )
+{
+ if (NULL != stream) {
+ if (NULL != stream->fpi)
+ fclose(stream->fpi);
+ free(stream);
+ }
+}
+
+/* INPUT STACK
+ * -----------
+ *
+ * Nested input sources are a bit tricky at first glance. We deal with
+ * this problem using a stack of input sources, that is, a forward
+ * linked list of FILE_INFO structs.
+ *
+ * This stack is never empty during parsing; while an encounter with EOF
+ * can and will remove nested input sources, removing the last element
+ * in the stack will not work during parsing, and the EOF condition of
+ * the outermost input file remains until the parser folds up.
+ */
+
+static struct FILE_INFO *
+_drop_stack_do(
+ struct FILE_INFO * head
+ )
+{
+ struct FILE_INFO * tail;
+ while (NULL != head) {
+ tail = head->st_next;
+ lex_close(head);
+ head = tail;
+ }
+ return head;
+}
+
+
+
+/* Create a singleton input source on an empty lexer stack. This will
+ * fail if there is already an input source, or if the underlying disk
+ * file cannot be opened.
+ *
+ * Returns TRUE if a new input object was successfully created.
+ */
+int/*BOOL*/
+lex_init_stack(
+ const char * path,
+ const char * mode
+ )
+{
+ if (NULL != lex_stack || NULL == path)
+ return FALSE;
+
+ lex_stack = lex_open(path, mode);
+ return (NULL != lex_stack);
+}
+
+/* This removes *all* input sources from the stack, leaving the head
+ * pointer as NULL. Any attempt to parse in that state is likely to bomb
+ * with segmentation faults or the like.
+ *
+ * In other words: Use this to clean up after parsing, and do not parse
+ * anything until the next 'lex_init_stack()' succeeded.
+ */
+void
+lex_drop_stack()
+{
+ lex_stack = _drop_stack_do(lex_stack);
+}
+
+/* Flush the lexer input stack: This will nip all input objects on the
+ * stack (but keeps the current top-of-stack) and marks the top-of-stack
+ * as inactive. Any further calls to lex_getch yield only EOF, and it's
+ * no longer possible to push something back.
+ *
+ * Returns TRUE if there is a head element (top-of-stack) that was not
+ * in the force-eof mode before this call.
+ */
+int/*BOOL*/
+lex_flush_stack()
+{
+ int retv = FALSE;
+
+ if (NULL != lex_stack) {
+ retv = !lex_stack->force_eof;
+ lex_stack->force_eof = TRUE;
+ lex_stack->st_next = _drop_stack_do(
+ lex_stack->st_next);
+ }
+ return retv;
+}
+
+/* Push another file on the parsing stack. If the mode is NULL, create a
+ * FILE_INFO suitable for in-memory parsing; otherwise, create a
+ * FILE_INFO that is bound to a local/disc file. Note that 'path' must
+ * not be NULL, or the function will fail.
+ *
+ * Returns TRUE if a new info record was pushed onto the stack.
+ */
+int/*BOOL*/ lex_push_file(
+ const char * path,
+ const char * mode
+ )
+{
+ struct FILE_INFO * next = NULL;
+
+ if (NULL != path) {
+ next = lex_open(path, mode);
+ if (NULL != next) {
+ next->st_next = lex_stack;
+ lex_stack = next;
+ }
+ }
+ return (NULL != next);
+}
+
+/* Pop, close & free the top of the include stack, unless the stack
+ * contains only a singleton input object. In that case the function
+ * fails, because the parser does not expect the input stack to be
+ * empty.
+ *
+ * Returns TRUE if an object was successfuly popped from the stack.
+ */
+int/*BOOL*/
+lex_pop_file(void)
+{
+ struct FILE_INFO * head = lex_stack;
+ struct FILE_INFO * tail = NULL;
+
+ if (NULL != head) {
+ tail = head->st_next;
+ if (NULL != tail) {
+ lex_stack = tail;
+ lex_close(head);
+ }
+ }
+ return (NULL != tail);
+}
+
+/* Get include nesting level. This currently loops over the stack and
+ * counts elements; but since this is of concern only with an include
+ * statement and the nesting depth has a small limit, there's no
+ * bottleneck expected here.
+ *
+ * Returns the nesting level of includes, that is, the current depth of
+ * the lexer input stack.
+ *
+ * Note:
+ */
+size_t
+lex_level(void)
+{
+ size_t cnt = 0;
+ struct FILE_INFO *ipf = lex_stack;
+
+ while (NULL != ipf) {
+ cnt++;
+ ipf = ipf->st_next;
+ }
+ return cnt;
+}
+
+/* check if the current input is from a file */
+int/*BOOL*/
+lex_from_file(void)
+{
+ return (NULL != lex_stack) && (NULL != lex_stack->fpi);
+}
+
+struct FILE_INFO *
+lex_current()
+{
+ /* this became so simple, it could be a macro. But then,
+ * lex_stack needed to be global...
+ */
+ return lex_stack;
+}
+
+
+/* STATE MACHINES
+ * --------------
+ */
+
+/* Keywords */
+static int
+is_keyword(
+ char *lexeme,
+ follby *pfollowedby
+ )
+{
+ follby fb;
+ int curr_s; /* current state index */
+ int token;
+ int i;
+
+ curr_s = SCANNER_INIT_S;
+ token = 0;
+
+ for (i = 0; lexeme[i]; i++) {
+ while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
+ curr_s = SS_OTHER_N(sst[curr_s]);
+
+ if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
+ if ('\0' == lexeme[i + 1]
+ && FOLLBY_NON_ACCEPTING
+ != SS_FB(sst[curr_s])) {
+ fb = SS_FB(sst[curr_s]);
+ *pfollowedby = fb;
+ token = curr_s;
+ break;
+ }
+ curr_s = SS_MATCH_N(sst[curr_s]);
+ } else
+ break;
+ }
+
+ return token;
+}
+
+
+/* Integer */
+static int
+is_integer(
+ char *lexeme
+ )
+{
+ int i;
+ int is_neg;
+ u_int u_val;
+
+ i = 0;
+
+ /* Allow a leading minus sign */
+ if (lexeme[i] == '-') {
+ i++;
+ is_neg = TRUE;
+ } else {
+ is_neg = FALSE;
+ }
+
+ /* Check that all the remaining characters are digits */
+ for (; lexeme[i] != '\0'; i++) {
+ if (!isdigit((u_char)lexeme[i]))
+ return FALSE;
+ }
+
+ if (is_neg)
+ return TRUE;
+
+ /* Reject numbers that fit in unsigned but not in signed int */
+ if (1 == sscanf(lexeme, "%u", &u_val))
+ return (u_val <= INT_MAX);
+ else
+ return FALSE;
+}
+
+
+/* U_int -- assumes is_integer() has returned FALSE */
+static int
+is_u_int(
+ char *lexeme
+ )
+{
+ int i;
+ int is_hex;
+
+ i = 0;
+ if ('0' == lexeme[i] && 'x' == tolower((u_char)lexeme[i + 1])) {
+ i += 2;
+ is_hex = TRUE;
+ } else {
+ is_hex = FALSE;
+ }
+
+ /* Check that all the remaining characters are digits */
+ for (; lexeme[i] != '\0'; i++) {
+ if (is_hex && !isxdigit((u_char)lexeme[i]))
+ return FALSE;
+ if (!is_hex && !isdigit((u_char)lexeme[i]))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Double */
+static int
+is_double(
+ char *lexeme
+ )
+{
+ u_int num_digits = 0; /* Number of digits read */
+ u_int i;
+
+ i = 0;
+
+ /* Check for an optional '+' or '-' */
+ if ('+' == lexeme[i] || '-' == lexeme[i])
+ i++;
+
+ /* Read the integer part */
+ for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
+ num_digits++;
+
+ /* Check for the optional decimal point */
+ if ('.' == lexeme[i]) {
+ i++;
+ /* Check for any digits after the decimal point */
+ for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
+ num_digits++;
+ }
+
+ /*
+ * The number of digits in both the decimal part and the
+ * fraction part must not be zero at this point
+ */
+ if (!num_digits)
+ return 0;
+
+ /* Check if we are done */
+ if (!lexeme[i])
+ return 1;
+
+ /* There is still more input, read the exponent */
+ if ('e' == tolower((u_char)lexeme[i]))
+ i++;
+ else
+ return 0;
+
+ /* Read an optional Sign */
+ if ('+' == lexeme[i] || '-' == lexeme[i])
+ i++;
+
+ /* Now read the exponent part */
+ while (lexeme[i] && isdigit((u_char)lexeme[i]))
+ i++;
+
+ /* Check if we are done */
+ if (!lexeme[i])
+ return 1;
+ else
+ return 0;
+}
+
+
+/* is_special() - Test whether a character is a token */
+static inline int
+is_special(
+ int ch
+ )
+{
+ return strchr(special_chars, ch) != NULL;
+}
+
+
+static int
+is_EOC(
+ int ch
+ )
+{
+ if ((old_config_style && (ch == '\n')) ||
+ (!old_config_style && (ch == ';')))
+ return 1;
+ return 0;
+}
+
+
+char *
+quote_if_needed(char *str)
+{
+ char *ret;
+ size_t len;
+ size_t octets;
+
+ len = strlen(str);
+ octets = len + 2 + 1;
+ ret = emalloc(octets);
+ if ('"' != str[0]
+ && (strcspn(str, special_chars) < len
+ || strchr(str, ' ') != NULL)) {
+ snprintf(ret, octets, "\"%s\"", str);
+ } else
+ strlcpy(ret, str, octets);
+
+ return ret;
+}
+
+
+static int
+create_string_token(
+ char *lexeme
+ )
+{
+ char *pch;
+
+ /*
+ * ignore end of line whitespace
+ */
+ pch = lexeme;
+ while (*pch && isspace((u_char)*pch))
+ pch++;
+
+ if (!*pch) {
+ yylval.Integer = T_EOC;
+ return yylval.Integer;
+ }
+
+ yylval.String = estrdup(lexeme);
+ return T_String;
+}
+
+
+/*
+ * yylex() - function that does the actual scanning.
+ * Bison expects this function to be called yylex and for it to take no
+ * input and return an int.
+ * Conceptually yylex "returns" yylval as well as the actual return
+ * value representing the token or type.
+ */
+int
+yylex(void)
+{
+ static follby followedby = FOLLBY_TOKEN;
+ int i;
+ int instring;
+ int yylval_was_set;
+ int converted;
+ int token; /* The return value */
+ int ch;
+
+ instring = FALSE;
+ yylval_was_set = FALSE;
+
+ do {
+ /* Ignore whitespace at the beginning */
+ while (EOF != (ch = lex_getch(lex_stack)) &&
+ isspace(ch) &&
+ !is_EOC(ch))
+
+ ; /* Null Statement */
+
+ if (EOF == ch) {
+
+ if ( ! lex_pop_file())
+ return 0;
+ token = T_EOC;
+ goto normal_return;
+
+ } else if (is_EOC(ch)) {
+
+ /* end FOLLBY_STRINGS_TO_EOC effect */
+ followedby = FOLLBY_TOKEN;
+ token = T_EOC;
+ goto normal_return;
+
+ } else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
+ /* special chars are their own token values */
+ token = ch;
+ /*
+ * '=' outside simulator configuration implies
+ * a single string following as in:
+ * setvar Owner = "The Boss" default
+ */
+ if ('=' == ch && old_config_style)
+ followedby = FOLLBY_STRING;
+ yytext[0] = (char)ch;
+ yytext[1] = '\0';
+ goto normal_return;
+ } else
+ lex_ungetch(ch, lex_stack);
+
+ /* save the position of start of the token */
+ lex_stack->tokpos = lex_stack->curpos;
+
+ /* Read in the lexeme */
+ i = 0;
+ while (EOF != (ch = lex_getch(lex_stack))) {
+
+ yytext[i] = (char)ch;
+
+ /* Break on whitespace or a special character */
+ if (isspace(ch) || is_EOC(ch)
+ || '"' == ch
+ || (FOLLBY_TOKEN == followedby
+ && is_special(ch)))
+ break;
+
+ /* Read the rest of the line on reading a start
+ of comment character */
+ if ('#' == ch) {
+ while (EOF != (ch = lex_getch(lex_stack))
+ && '\n' != ch)
+ ; /* Null Statement */
+ break;
+ }
+
+ i++;
+ if (i >= COUNTOF(yytext))
+ goto lex_too_long;
+ }
+ /* Pick up all of the string inside between " marks, to
+ * end of line. If we make it to EOL without a
+ * terminating " assume it for them.
+ *
+ * XXX - HMS: I'm not sure we want to assume the closing "
+ */
+ if ('"' == ch) {
+ instring = TRUE;
+ while (EOF != (ch = lex_getch(lex_stack)) &&
+ ch != '"' && ch != '\n') {
+ yytext[i++] = (char)ch;
+ if (i >= COUNTOF(yytext))
+ goto lex_too_long;
+ }
+ /*
+ * yytext[i] will be pushed back as not part of
+ * this lexeme, but any closing quote should
+ * not be pushed back, so we read another char.
+ */
+ if ('"' == ch)
+ ch = lex_getch(lex_stack);
+ }
+ /* Pushback the last character read that is not a part
+ * of this lexeme. This fails silently if ch is EOF,
+ * but then the EOF condition persists and is handled on
+ * the next turn by the include stack mechanism.
+ */
+ lex_ungetch(ch, lex_stack);
+
+ yytext[i] = '\0';
+ } while (i == 0);
+
+ /* Now return the desired token */
+
+ /* First make sure that the parser is *not* expecting a string
+ * as the next token (based on the previous token that was
+ * returned) and that we haven't read a string.
+ */
+
+ if (followedby == FOLLBY_TOKEN && !instring) {
+ token = is_keyword(yytext, &followedby);
+ if (token) {
+ /*
+ * T_Server is exceptional as it forces the
+ * following token to be a string in the
+ * non-simulator parts of the configuration,
+ * but in the simulator configuration section,
+ * "server" is followed by "=" which must be
+ * recognized as a token not a string.
+ */
+ if (T_Server == token && !old_config_style)
+ followedby = FOLLBY_TOKEN;
+ goto normal_return;
+ } else if (is_integer(yytext)) {
+ yylval_was_set = TRUE;
+ errno = 0;
+ if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
+ && ((errno == EINVAL) || (errno == ERANGE))) {
+ msyslog(LOG_ERR,
+ "Integer cannot be represented: %s",
+ yytext);
+ if (lex_from_file()) {
+ exit(1);
+ } else {
+ /* force end of parsing */
+ yylval.Integer = 0;
+ return 0;
+ }
+ }
+ token = T_Integer;
+ goto normal_return;
+ } else if (is_u_int(yytext)) {
+ yylval_was_set = TRUE;
+ if ('0' == yytext[0] &&
+ 'x' == tolower((unsigned long)yytext[1]))
+ converted = sscanf(&yytext[2], "%x",
+ &yylval.U_int);
+ else
+ converted = sscanf(yytext, "%u",
+ &yylval.U_int);
+ if (1 != converted) {
+ msyslog(LOG_ERR,
+ "U_int cannot be represented: %s",
+ yytext);
+ if (lex_from_file()) {
+ exit(1);
+ } else {
+ /* force end of parsing */
+ yylval.Integer = 0;
+ return 0;
+ }
+ }
+ token = T_U_int;
+ goto normal_return;
+ } else if (is_double(yytext)) {
+ yylval_was_set = TRUE;
+ errno = 0;
+ if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
+ msyslog(LOG_ERR,
+ "Double too large to represent: %s",
+ yytext);
+ exit(1);
+ } else {
+ token = T_Double;
+ goto normal_return;
+ }
+ } else {
+ /* Default: Everything is a string */
+ yylval_was_set = TRUE;
+ token = create_string_token(yytext);
+ goto normal_return;
+ }
+ }
+
+ /*
+ * Either followedby is not FOLLBY_TOKEN or this lexeme is part
+ * of a string. Hence, we need to return T_String.
+ *
+ * _Except_ we might have a -4 or -6 flag on a an association
+ * configuration line (server, peer, pool, etc.).
+ *
+ * This is a terrible hack, but the grammar is ambiguous so we
+ * don't have a choice. [SK]
+ *
+ * The ambiguity is in the keyword scanner, not ntp_parser.y.
+ * We do not require server addresses be quoted in ntp.conf,
+ * complicating the scanner's job. To avoid trying (and
+ * failing) to match an IP address or DNS name to a keyword,
+ * the association keywords use FOLLBY_STRING in the keyword
+ * table, which tells the scanner to force the next token to be
+ * a T_String, so it does not try to match a keyword but rather
+ * expects a string when -4/-6 modifiers to server, peer, etc.
+ * are encountered.
+ * restrict -4 and restrict -6 parsing works correctly without
+ * this hack, as restrict uses FOLLBY_TOKEN. [DH]
+ */
+ if ('-' == yytext[0]) {
+ if ('4' == yytext[1]) {
+ token = T_Ipv4_flag;
+ goto normal_return;
+ } else if ('6' == yytext[1]) {
+ token = T_Ipv6_flag;
+ goto normal_return;
+ }
+ }
+
+ instring = FALSE;
+ if (FOLLBY_STRING == followedby)
+ followedby = FOLLBY_TOKEN;
+
+ yylval_was_set = TRUE;
+ token = create_string_token(yytext);
+
+normal_return:
+ if (T_EOC == token)
+ DPRINTF(4,("\t<end of command>\n"));
+ else
+ DPRINTF(4, ("yylex: lexeme '%s' -> %s\n", yytext,
+ token_name(token)));
+
+ if (!yylval_was_set)
+ yylval.Integer = token;
+
+ return token;
+
+lex_too_long:
+ yytext[min(sizeof(yytext) - 1, 50)] = 0;
+ msyslog(LOG_ERR,
+ "configuration item on line %d longer than limit of %lu, began with '%s'",
+ lex_stack->curpos.nline, (u_long)min(sizeof(yytext) - 1, 50),
+ yytext);
+
+ /*
+ * If we hit the length limit reading the startup configuration
+ * file, abort.
+ */
+ if (lex_from_file())
+ exit(sizeof(yytext) - 1);
+
+ /*
+ * If it's runtime configuration via ntpq :config treat it as
+ * if the configuration text ended before the too-long lexeme,
+ * hostname, or string.
+ */
+ yylval.Integer = 0;
+ return 0;
+}
diff --git a/contrib/ntp/ntpd/ntp_scanner.h b/contrib/ntp/ntpd/ntp_scanner.h
new file mode 100644
index 0000000..11bbfe9
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_scanner.h
@@ -0,0 +1,142 @@
+/* ntp_scanner.h
+ *
+ * The header file for a simple lexical analyzer.
+ *
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
+ * Copyright (c) 2006
+ */
+
+#ifndef NTP_SCANNER_H
+#define NTP_SCANNER_H
+
+#include "ntp_config.h"
+
+/*
+ * ntp.conf syntax is slightly irregular in that some tokens such as
+ * hostnames do not require quoting even if they might otherwise be
+ * recognized as T_ terminal tokens. This hand-crafted lexical scanner
+ * uses a "followed by" value associated with each keyword to indicate
+ * normal scanning of the next token, forced scanning of the next token
+ * alone as a T_String, or forced scanning of all tokens to the end of
+ * the command as T_String.
+ * In the past the identifiers for this functionality ended in _ARG:
+ *
+ * NO_ARG -> FOLLBY_TOKEN
+ * SINGLE_ARG -> FOLLBY_STRING
+ * MULTIPLE_ARG -> FOLLBY_STRINGS_TO_EOC
+ *
+ * Note that some tokens use FOLLBY_TOKEN even though they sometimes
+ * are followed by strings. FOLLBY_STRING is used only when needed to
+ * avoid the keyword scanner matching a token where a string is needed.
+ *
+ * FOLLBY_NON_ACCEPT is an overloading of this field to distinguish
+ * non-accepting states (where the state number does not match a T_
+ * value).
+ */
+typedef enum {
+ FOLLBY_TOKEN = 0,
+ FOLLBY_STRING,
+ FOLLBY_STRINGS_TO_EOC,
+ FOLLBY_NON_ACCEPTING
+} follby;
+
+#define MAXLINE 1024 /* maximum length of line */
+#define MAXINCLUDELEVEL 5 /* maximum include file levels */
+
+/* STRUCTURES
+ * ----------
+ */
+
+/*
+ * Define a structure to hold the FSA for the keywords.
+ * The structure is actually a trie.
+ *
+ * To save space, a single u_int32 encodes four fields, and a fifth
+ * (the token completed for terminal states) is implied by the index of
+ * the rule within the scan state array, taking advantage of the fact
+ * there are more scan states than the highest T_ token number.
+ *
+ * The lowest 8 bits hold the character the state matches on.
+ * Bits 8 and 9 hold the followedby value (0 - 3). For non-accepting
+ * states (which do not match a completed token) the followedby
+ * value 3 (FOLLBY_NONACCEPTING) denotes that fact. For accepting
+ * states, values 0 - 2 control whether the scanner forces the
+ * following token(s) to strings.
+ * Bits 10 through 20 hold the next state to check not matching
+ * this state's character.
+ * Bits 21 through 31 hold the next state to check matching the char.
+ */
+
+#define S_ST(ch, fb, match_n, other_n) ( \
+ (u_char)((ch) & 0xff) | \
+ ((u_int32)(fb) << 8) | \
+ ((u_int32)(match_n) << 10) | \
+ ((u_int32)(other_n) << 21) \
+)
+
+#define SS_CH(ss) ((char)(u_char)((ss) & 0xff))
+#define SS_FB(ss) (((u_int)(ss) >> 8) & 0x3)
+#define SS_MATCH_N(ss) (((u_int)(ss) >> 10) & 0x7ff)
+#define SS_OTHER_N(ss) (((u_int)(ss) >> 21) & 0x7ff)
+
+typedef u_int32 scan_state;
+
+struct LCPOS {
+ int nline;
+ int ncol;
+};
+
+/* Structure to hold a filename, file pointer and positional info.
+ * Instances are dynamically allocated, and the file name is copied by
+ * value into a dynamic extension of the 'fname' array. (Which *must* be
+ * the last field for that reason!)
+ */
+struct FILE_INFO {
+ struct FILE_INFO * st_next; /* next on stack */
+ FILE * fpi; /* File Descriptor */
+ int force_eof; /* locked or not */
+ int backch; /* ungetch buffer */
+
+ struct LCPOS curpos; /* current scan position */
+ struct LCPOS bakpos; /* last line end for ungetc */
+ struct LCPOS tokpos; /* current token position */
+ struct LCPOS errpos; /* error position */
+
+ char fname[1]; /* (formal only) buffered name */
+};
+
+
+/* SCANNER GLOBAL VARIABLES
+ * ------------------------
+ */
+extern config_tree cfgt; /* Parser output stored here */
+
+/* VARIOUS EXTERNAL DECLARATIONS
+ * -----------------------------
+ */
+extern int old_config_style;
+
+/* VARIOUS SUBROUTINE DECLARATIONS
+ * -------------------------------
+ */
+extern const char *keyword(int token);
+extern char *quote_if_needed(char *str);
+int yylex(void);
+
+/* managing the input source stack itself */
+extern int/*BOOL*/ lex_init_stack(const char * path, const char * mode);
+extern void lex_drop_stack(void);
+extern int/*BOOL*/ lex_flush_stack(void);
+
+/* add/remove a nested input source */
+extern int/*BOOL*/ lex_push_file(const char * path, const char * mode);
+extern int/*BOOL*/ lex_pop_file(void);
+
+/* input stack state query functions */
+extern size_t lex_level(void);
+extern int/*BOOL*/ lex_from_file(void);
+extern struct FILE_INFO * lex_current(void);
+
+#endif /* NTP_SCANNER_H */
diff --git a/contrib/ntp/ntpd/ntp_signd.c b/contrib/ntp/ntpd/ntp_signd.c
new file mode 100644
index 0000000..2ba11d0
--- /dev/null
+++ b/contrib/ntp/ntpd/ntp_signd.c
@@ -0,0 +1,239 @@
+/* Copyright 2008, Red Hat, Inc.
+ Copyright 2008, Andrew Tridgell.
+ Licenced under the same terms as NTP itself.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_NTP_SIGND
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_stdlib.h"
+#include "ntp_unixtime.h"
+#include "ntp_control.h"
+#include "ntp_string.h"
+
+#include <stdio.h>
+#include <stddef.h>
+#ifdef HAVE_LIBSCF_H
+#include <libscf.h>
+#include <unistd.h>
+#endif /* HAVE_LIBSCF_H */
+
+#include <sys/un.h>
+
+/* socket routines by tridge - from junkcode.samba.org */
+
+/*
+ connect to a unix domain socket
+*/
+static int
+ux_socket_connect(const char *name)
+{
+ int fd;
+ struct sockaddr_un addr;
+ if (!name) {
+ return -1;
+ }
+
+ ZERO(addr);
+ addr.sun_family = AF_UNIX;
+ strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ return -1;
+ }
+
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+
+/*
+ keep writing until its all sent
+*/
+static int
+write_all(int fd, const void *buf, size_t len)
+{
+ size_t total = 0;
+ while (len) {
+ int n = write(fd, buf, len);
+ if (n <= 0) return total;
+ buf = n + (char *)buf;
+ len -= n;
+ total += n;
+ }
+ return total;
+}
+
+/*
+ keep reading until its all read
+*/
+static int
+read_all(int fd, void *buf, size_t len)
+{
+ size_t total = 0;
+ while (len) {
+ int n = read(fd, buf, len);
+ if (n <= 0) return total;
+ buf = n + (char *)buf;
+ len -= n;
+ total += n;
+ }
+ return total;
+}
+
+/*
+ send a packet in length prefix format
+*/
+static int
+send_packet(int fd, const char *buf, uint32_t len)
+{
+ uint32_t net_len = htonl(len);
+ if (write_all(fd, &net_len, sizeof(net_len)) != sizeof(net_len)) return -1;
+ if (write_all(fd, buf, len) != len) return -1;
+ return 0;
+}
+
+/*
+ receive a packet in length prefix format
+*/
+static int
+recv_packet(int fd, char **buf, uint32_t *len)
+{
+ if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
+ *len = ntohl(*len);
+ (*buf) = emalloc(*len);
+ if (read_all(fd, *buf, *len) != *len) {
+ free(*buf);
+ return -1;
+ }
+ return 0;
+}
+
+void
+send_via_ntp_signd(
+ struct recvbuf *rbufp, /* receive packet pointer */
+ int xmode,
+ keyid_t xkeyid,
+ int flags,
+ struct pkt *xpkt
+ )
+{
+
+ /* We are here because it was detected that the client
+ * sent an all-zero signature, and we therefore know
+ * it's windows trying to talk to an AD server
+ *
+ * Because we don't want to dive into Samba's secrets
+ * database just to find the long-term kerberos key
+ * that is re-used as the NTP key, we instead hand the
+ * packet over to Samba to sign, and return to us.
+ *
+ * The signing method Samba will use is described by
+ * Microsoft in MS-SNTP, found here:
+ * http://msdn.microsoft.com/en-us/library/cc212930.aspx
+ */
+
+ int fd, sendlen;
+ struct samba_key_in {
+ uint32_t version;
+ uint32_t op;
+ uint32_t packet_id;
+ uint32_t key_id_le;
+ struct pkt pkt;
+ } samba_pkt;
+
+ struct samba_key_out {
+ uint32_t version;
+ uint32_t op;
+ uint32_t packet_id;
+ struct pkt pkt;
+ } samba_reply;
+
+ char full_socket[256];
+
+ char *reply = NULL;
+ uint32_t reply_len;
+
+ ZERO(samba_pkt);
+ samba_pkt.op = 0; /* Sign message */
+ /* This will be echoed into the reply - a different
+ * impelementation might want multiple packets
+ * awaiting signing */
+
+ samba_pkt.packet_id = 1;
+
+ /* Swap the byte order back - it's actually little
+ * endian on the wire, but it was read above as
+ * network byte order */
+ samba_pkt.key_id_le = htonl(xkeyid);
+ samba_pkt.pkt = *xpkt;
+
+ snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
+
+ fd = ux_socket_connect(full_socket);
+ /* Only continue with this if we can talk to Samba */
+ if (fd != -1) {
+ /* Send old packet to Samba, expect response */
+ /* Packet to Samba is quite simple:
+ All values BIG endian except key ID as noted
+ [packet size as BE] - 4 bytes
+ [protocol version (0)] - 4 bytes
+ [packet ID] - 4 bytes
+ [operation (sign message=0)] - 4 bytes
+ [key id] - LITTLE endian (as on wire) - 4 bytes
+ [message to sign] - as marshalled, without signature
+ */
+
+ if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) {
+ /* Huh? could not talk to Samba... */
+ close(fd);
+ return;
+ }
+
+ if (recv_packet(fd, &reply, &reply_len) != 0) {
+ if (reply) {
+ free(reply);
+ }
+ close(fd);
+ return;
+ }
+ /* Return packet is also simple:
+ [packet size] - network byte order - 4 bytes
+ [protocol version (0)] network byte order - - 4 bytes
+ [operation (signed success=3, failure=4)] network byte order - - 4 byte
+ (optional) [signed message] - as provided before, with signature appended
+ */
+
+ if (reply_len <= sizeof(samba_reply)) {
+ memcpy(&samba_reply, reply, reply_len);
+ if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) {
+ sendlen = reply_len - offsetof(struct samba_key_out, pkt);
+ xpkt = &samba_reply.pkt;
+ sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
+#ifdef DEBUG
+ if (debug)
+ printf(
+ "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
+ current_time, ntoa(&rbufp->dstadr->sin),
+ ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
+#endif
+ }
+ }
+
+ if (reply) {
+ free(reply);
+ }
+ close(fd);
+
+ }
+}
+#endif
diff --git a/contrib/ntp/ntpd/ntp_timer.c b/contrib/ntp/ntpd/ntp_timer.c
index 812206a..5cbb892 100644
--- a/contrib/ntp/ntpd/ntp_timer.c
+++ b/contrib/ntp/ntpd/ntp_timer.c
@@ -8,6 +8,13 @@
#include "ntp_machine.h"
#include "ntpd.h"
#include "ntp_stdlib.h"
+#include "ntp_calendar.h"
+#include "ntp_leapsec.h"
+
+#if defined(HAVE_IO_COMPLETION_PORT)
+# include "ntp_iocompletionport.h"
+# include "ntp_timer.h"
+#endif
#include <stdio.h>
#include <signal.h>
@@ -18,51 +25,67 @@
# include <unistd.h>
#endif
-#if defined(HAVE_IO_COMPLETION_PORT)
-# include "ntp_iocompletionport.h"
-# include "ntp_timer.h"
+#ifdef KERNEL_PLL
+#include "ntp_syscall.h"
+#endif /* KERNEL_PLL */
+
+#ifdef AUTOKEY
+#include <openssl/rand.h>
+#endif /* AUTOKEY */
+
+
+/* TC_ERR represents the timer_create() error return value. */
+#ifdef SYS_VXWORKS
+#define TC_ERR ERROR
+#else
+#define TC_ERR (-1)
#endif
+
+static void check_leapsec(u_int32, const time_t*, int/*BOOL*/);
+
/*
- * These routines provide support for the event timer. The timer is
+ * These routines provide support for the event timer. The timer is
* implemented by an interrupt routine which sets a flag once every
- * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
- * is called when the mainline code gets around to seeing the flag.
- * The timer routine dispatches the clock adjustment code if its time
- * has come, then searches the timer queue for expiries which are
- * dispatched to the transmit procedure. Finally, we call the hourly
- * procedure to do cleanup and print a message.
+ * second, and a timer routine which is called when the mainline code
+ * gets around to seeing the flag. The timer routine dispatches the
+ * clock adjustment code if its time has come, then searches the timer
+ * queue for expiries which are dispatched to the transmit procedure.
+ * Finally, we call the hourly procedure to do cleanup and print a
+ * message.
*/
+volatile int interface_interval; /* init_io() sets def. 300s */
-volatile int interface_interval = 300; /* update interface every 5 minutes as default */
-
/*
- * Alarm flag. The mainline code imports this.
+ * Alarm flag. The mainline code imports this.
*/
volatile int alarm_flag;
/*
- * The counters
+ * The counters and timeouts
*/
-static u_long adjust_timer; /* second timer */
-static u_long keys_timer; /* minute timer */
-static u_long stats_timer; /* stats timer */
-static u_long huffpuff_timer; /* huff-n'-puff timer */
-static u_long interface_timer; /* interface update timer */
-#ifdef OPENSSL
-static u_long revoke_timer; /* keys revoke timer */
-u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
-#endif /* OPENSSL */
+static u_long interface_timer; /* interface update timer */
+static u_long adjust_timer; /* second timer */
+static u_long stats_timer; /* stats timer */
+static u_long leapf_timer; /* Report leapfile problems once/day */
+static u_long huffpuff_timer; /* huff-n'-puff timer */
+static u_long worker_idle_timer;/* next check for idle intres */
+u_long leapsec; /* seconds to next leap (proximity class) */
+int leapdif; /* TAI difference step at next leap second*/
+u_long orphwait; /* orphan wait time */
+#ifdef AUTOKEY
+static u_long revoke_timer; /* keys revoke timer */
+static u_long keys_timer; /* session key timer */
+u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
+u_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
+#endif /* AUTOKEY */
/*
* Statistics counter for the interested.
*/
volatile u_long alarm_overflow;
-#define MINUTE 60
-#define HOUR (60*60)
-
-u_long current_time;
+u_long current_time; /* seconds since startup */
/*
* Stats. Number of overflows and number of calls to transmit().
@@ -76,82 +99,98 @@ static int vmstimer[2]; /* time for next timer AST */
static int vmsinc[2]; /* timer increment */
#endif /* VMS */
-#if defined SYS_WINNT
-static HANDLE WaitableTimerHandle = NULL;
+#ifdef SYS_WINNT
+HANDLE WaitableTimerHandle;
#else
-static RETSIGTYPE alarming P((int));
+static RETSIGTYPE alarming (int);
#endif /* SYS_WINNT */
#if !defined(VMS)
# if !defined SYS_WINNT || defined(SYS_CYGWIN32)
-# ifndef HAVE_TIMER_SETTIME
- struct itimerval itimer;
-# else
- static timer_t ntpd_timerid;
- struct itimerspec itimer;
-# endif /* HAVE_TIMER_SETTIME */
-# endif /* SYS_WINNT */
-#endif /* VMS */
+# ifdef HAVE_TIMER_CREATE
+static timer_t timer_id;
+typedef struct itimerspec intervaltimer;
+# define itv_frac tv_nsec
+# else
+typedef struct itimerval intervaltimer;
+# define itv_frac tv_usec
+# endif
+intervaltimer itimer;
+# endif
+#endif
+
+#if !defined(SYS_WINNT) && !defined(VMS)
+void set_timer_or_die(const intervaltimer *);
+#endif
+
+
+#if !defined(SYS_WINNT) && !defined(VMS)
+void
+set_timer_or_die(
+ const intervaltimer * ptimer
+ )
+{
+ const char * setfunc;
+ int rc;
+
+# ifdef HAVE_TIMER_CREATE
+ setfunc = "timer_settime";
+ rc = timer_settime(timer_id, 0, &itimer, NULL);
+# else
+ setfunc = "setitimer";
+ rc = setitimer(ITIMER_REAL, &itimer, NULL);
+# endif
+ if (-1 == rc) {
+ msyslog(LOG_ERR, "interval timer %s failed, %m",
+ setfunc);
+ exit(1);
+ }
+}
+#endif /* !SYS_WINNT && !VMS */
+
/*
- * reinit_timer - reinitialize interval timer.
+ * reinit_timer - reinitialize interval timer after a clock step.
*/
-void
+void
reinit_timer(void)
{
#if !defined(SYS_WINNT) && !defined(VMS)
-# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- timer_gettime(ntpd_timerid, &itimer);
- if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- }
- if (itimer.it_value.tv_nsec < 0 ) {
- itimer.it_value.tv_nsec = 0;
- }
- if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_value.tv_nsec = 0;
- }
- itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_nsec = 0;
- timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
-# else
+ ZERO(itimer);
+# ifdef HAVE_TIMER_CREATE
+ timer_gettime(timer_id, &itimer);
+# else
getitimer(ITIMER_REAL, &itimer);
- if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- }
- if (itimer.it_value.tv_usec < 0 ) {
- itimer.it_value.tv_usec = 0;
- }
- if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_value.tv_usec = 0;
- }
- itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_usec = 0;
- setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
-# endif
+# endif
+ if (itimer.it_value.tv_sec < 0 ||
+ itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT))
+ itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
+ if (itimer.it_value.itv_frac < 0)
+ itimer.it_value.itv_frac = 0;
+ if (0 == itimer.it_value.tv_sec &&
+ 0 == itimer.it_value.itv_frac)
+ itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
+ itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT);
+ itimer.it_interval.itv_frac = 0;
+ set_timer_or_die(&itimer);
# endif /* VMS */
}
+
/*
* init_timer - initialize the timer data structures
*/
void
init_timer(void)
{
-# if defined SYS_WINNT & !defined(SYS_CYGWIN32)
- HANDLE hToken = INVALID_HANDLE_VALUE;
- TOKEN_PRIVILEGES tkp;
-# endif /* SYS_WINNT */
-
/*
* Initialize...
*/
- alarm_flag = 0;
+ alarm_flag = FALSE;
alarm_overflow = 0;
adjust_timer = 1;
- stats_timer = 0;
+ stats_timer = SECSPERHR;
+ leapf_timer = SECSPERDAY;
huffpuff_timer = 0;
interface_timer = 0;
current_time = 0;
@@ -159,36 +198,25 @@ init_timer(void)
timer_xmtcalls = 0;
timer_timereset = 0;
-#if !defined(SYS_WINNT)
+#ifndef SYS_WINNT
/*
* Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
* seconds from now and they continue on every 2**EVENT_TIMEOUT
* seconds.
*/
-# if !defined(VMS)
-# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
-# ifdef SYS_VXWORKS
- ERROR
-# else
- -1
-# endif
- )
- {
- fprintf (stderr, "timer create FAILED\n");
- exit (0);
+# ifndef VMS
+# ifdef HAVE_TIMER_CREATE
+ if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) {
+ msyslog(LOG_ERR, "timer_create failed, %m");
+ exit(1);
}
- (void) signal_no_reset(SIGALRM, alarming);
- itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
- timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
-# else
- (void) signal_no_reset(SIGALRM, alarming);
- itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
# endif
-# else /* VMS */
+ signal_no_reset(SIGALRM, alarming);
+ itimer.it_interval.tv_sec =
+ itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
+ itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0;
+ set_timer_or_die(&itimer);
+# else /* VMS follows */
vmsinc[0] = 10000000; /* 1 sec */
vmsinc[1] = 0;
lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
@@ -197,33 +225,11 @@ init_timer(void)
lib$addx(&vmsinc, &vmstimer, &vmstimer);
sys$setimr(0, &vmstimer, alarming, alarming, 0);
-# endif /* VMS */
-#else /* SYS_WINNT */
- _tzset();
-
- /*
- * Get privileges needed for fiddling with the clock
- */
-
- /* get the current process token handle */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
- msyslog(LOG_ERR, "OpenProcessToken failed: %m");
- exit(1);
- }
- /* get the LUID for system-time privilege. */
- LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
- tkp.PrivilegeCount = 1; /* one privilege to set */
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- /* get set-time privilege for this process. */
- AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
- /* cannot test return value of AdjustTokenPrivileges. */
- if (GetLastError() != ERROR_SUCCESS) {
- msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
- }
-
+# endif /* VMS */
+#else /* SYS_WINNT follows */
/*
* Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
- * Under Windows/NT,
+ * Under Windows/NT,
*/
WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
@@ -232,130 +238,200 @@ init_timer(void)
exit(1);
}
else {
- DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
- LARGE_INTEGER DueTime;
+ DWORD Period;
+ LARGE_INTEGER DueTime;
+ BOOL rc;
+
+ Period = (1 << EVENT_TIMEOUT) * 1000;
DueTime.QuadPart = Period * 10000i64;
- if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
+ rc = SetWaitableTimer(WaitableTimerHandle, &DueTime,
+ Period, NULL, NULL, FALSE);
+ if (!rc) {
msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
exit(1);
}
}
-#endif /* SYS_WINNT */
+#endif /* SYS_WINNT */
}
-#if defined(SYS_WINNT)
-extern HANDLE
-get_timer_handle(void)
+
+/*
+ * intres_timeout_req(s) is invoked in the parent to schedule an idle
+ * timeout to fire in s seconds, if not reset earlier by a call to
+ * intres_timeout_req(0), which clears any pending timeout. When the
+ * timeout expires, worker_idle_timer_fired() is invoked (again, in the
+ * parent).
+ *
+ * sntp and ntpd each provide implementations adapted to their timers.
+ */
+void
+intres_timeout_req(
+ u_int seconds /* 0 cancels */
+ )
{
- return WaitableTimerHandle;
+ if (0 == seconds) {
+ worker_idle_timer = 0;
+ return;
+ }
+ worker_idle_timer = current_time + seconds;
}
-#endif
+
/*
- * timer - dispatch anyone who needs to be
+ * timer - event timer
*/
void
timer(void)
{
- register struct peer *peer, *next_peer;
-#ifdef OPENSSL
- char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
-#endif /* OPENSSL */
- u_int n;
-
- current_time += (1<<EVENT_TIMEOUT);
+ struct peer * p;
+ struct peer * next_peer;
+ l_fp now;
+ time_t tnow;
/*
- * Adjustment timeout first.
+ * The basic timerevent is one second. This is used to adjust the
+ * system clock in time and frequency, implement the kiss-o'-death
+ * function and the association polling function.
*/
+ current_time++;
if (adjust_timer <= current_time) {
adjust_timer += 1;
adj_host_clock();
- kod_proto();
#ifdef REFCLOCK
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- if (peer->flags & FLAG_REFCLOCK)
- refclock_timer(peer);
- }
+ for (p = peer_list; p != NULL; p = next_peer) {
+ next_peer = p->p_link;
+ if (FLAG_REFCLOCK & p->flags)
+ refclock_timer(p);
}
#endif /* REFCLOCK */
}
/*
- * Now dispatch any peers whose event timer has expired. Be careful
- * here, since the peer structure might go away as the result of
- * the call.
+ * Now dispatch any peers whose event timer has expired. Be
+ * careful here, since the peer structure might go away as the
+ * result of the call.
*/
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- if (peer->action && peer->nextaction <= current_time)
- peer->action(peer);
- if (peer->nextdate <= current_time) {
+ for (p = peer_list; p != NULL; p = next_peer) {
+ next_peer = p->p_link;
+
+ /*
+ * Restrain the non-burst packet rate not more
+ * than one packet every 16 seconds. This is
+ * usually tripped using iburst and minpoll of
+ * 128 s or less.
+ */
+ if (p->throttle > 0)
+ p->throttle--;
+ if (p->nextdate <= current_time) {
#ifdef REFCLOCK
- if (peer->flags & FLAG_REFCLOCK)
- refclock_transmit(peer);
- else
- transmit(peer);
-#else /* REFCLOCK */
- transmit(peer);
-#endif /* REFCLOCK */
- }
+ if (FLAG_REFCLOCK & p->flags)
+ refclock_transmit(p);
+ else
+#endif /* REFCLOCK */
+ transmit(p);
}
}
/*
- * Garbage collect expired keys.
+ * Orphan mode is active when enabled and when no servers less
+ * than the orphan stratum are available. A server with no other
+ * synchronization source is an orphan. It shows offset zero and
+ * reference ID the loopback address.
*/
- if (keys_timer <= current_time) {
- keys_timer += MINUTE;
- auth_agekeys();
+ if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL &&
+ current_time > orphwait) {
+ if (sys_leap == LEAP_NOTINSYNC) {
+ set_sys_leap(LEAP_NOWARNING);
+#ifdef AUTOKEY
+ if (crypto_flags)
+ crypto_update();
+#endif /* AUTOKEY */
+ }
+ sys_stratum = (u_char)sys_orphan;
+ if (sys_stratum > 1)
+ sys_refid = htonl(LOOPBACKADR);
+ else
+ memcpy(&sys_refid, "LOOP", 4);
+ sys_offset = 0;
+ sys_rootdelay = 0;
+ sys_rootdisp = 0;
+ }
+
+ get_systime(&now);
+ time(&tnow);
+
+ /*
+ * Leapseconds. Get time and defer to worker if either something
+ * is imminent or every 8th second.
+ */
+ if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7))
+ check_leapsec(now.l_ui, &tnow,
+ (sys_leap == LEAP_NOTINSYNC));
+ if (sys_leap != LEAP_NOTINSYNC) {
+ if (leapsec >= LSPROX_ANNOUNCE && leapdif) {
+ if (leapdif > 0)
+ set_sys_leap(LEAP_ADDSECOND);
+ else
+ set_sys_leap(LEAP_DELSECOND);
+ } else {
+ set_sys_leap(LEAP_NOWARNING);
+ }
}
/*
- * Huff-n'-puff filter
+ * Update huff-n'-puff filter.
*/
if (huffpuff_timer <= current_time) {
huffpuff_timer += HUFFPUFF;
huffpuff();
}
-#ifdef OPENSSL
+#ifdef AUTOKEY
/*
- * Garbage collect old keys and generate new private value
+ * Garbage collect expired keys.
*/
- if (revoke_timer <= current_time) {
- revoke_timer += RANDPOLL(sys_revoke);
- expire_all();
- sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
- record_crypto_stats(NULL, statstr);
-#ifdef DEBUG
- if (debug)
- printf("timer: %s\n", statstr);
-#endif
+ if (keys_timer <= current_time) {
+ keys_timer += 1 << sys_automax;
+ auth_agekeys();
}
-#endif /* OPENSSL */
/*
- * interface update timer
+ * Generate new private value. This causes all associations
+ * to regenerate cookies.
*/
- if (interface_interval && interface_timer <= current_time) {
+ if (revoke_timer && revoke_timer <= current_time) {
+ revoke_timer += 1 << sys_revoke;
+ RAND_bytes((u_char *)&sys_private, 4);
+ }
+#endif /* AUTOKEY */
- timer_interfacetimeout(current_time + interface_interval);
- DPRINTF(1, ("timer: interface update\n"));
+ /*
+ * Interface update timer
+ */
+ if (interface_interval && interface_timer <= current_time) {
+ timer_interfacetimeout(current_time +
+ interface_interval);
+ DPRINTF(2, ("timer: interface update\n"));
interface_update(NULL, NULL);
}
-
+
+ if (worker_idle_timer && worker_idle_timer <= current_time)
+ worker_idle_timer_fired();
+
/*
- * Finally, periodically write stats.
+ * Finally, write hourly stats and do the hourly
+ * and daily leapfile checks.
*/
if (stats_timer <= current_time) {
- if (stats_timer != 0)
- write_stats();
- stats_timer += stats_write_period;
+ stats_timer += SECSPERHR;
+ write_stats();
+ if (leapf_timer <= current_time) {
+ leapf_timer += SECSPERDAY;
+ check_leap_file(TRUE, now.l_ui, &tnow);
+ } else {
+ check_leap_file(FALSE, now.l_ui, &tnow);
+ }
}
}
@@ -369,24 +445,40 @@ alarming(
int sig
)
{
-#if !defined(VMS)
- if (initializing)
- return;
- if (alarm_flag)
- alarm_overflow++;
- else
- alarm_flag++;
-#else /* VMS AST routine */
+# ifdef DEBUG
+ const char *msg = "alarming: initializing TRUE\n";
+# endif
+
if (!initializing) {
- if (alarm_flag) alarm_overflow++;
- else alarm_flag = 1; /* increment is no good */
+ if (alarm_flag) {
+ alarm_overflow++;
+# ifdef DEBUG
+ msg = "alarming: overflow\n";
+# endif
+ } else {
+# ifndef VMS
+ alarm_flag++;
+# else
+ /* VMS AST routine, increment is no good */
+ alarm_flag = 1;
+# endif
+# ifdef DEBUG
+ msg = "alarming: normal\n";
+# endif
+ }
}
- lib$addx(&vmsinc,&vmstimer,&vmstimer);
- sys$setimr(0,&vmstimer,alarming,alarming,0);
-#endif /* VMS */
+# ifdef VMS
+ lib$addx(&vmsinc, &vmstimer, &vmstimer);
+ sys$setimr(0, &vmstimer, alarming, alarming, 0);
+# endif
+# ifdef DEBUG
+ if (debug >= 4)
+ (void)(-1 == write(1, msg, strlen(msg)));
+# endif
}
#endif /* SYS_WINNT */
+
void
timer_interfacetimeout(u_long timeout)
{
@@ -405,3 +497,200 @@ timer_clr_stats(void)
timer_timereset = current_time;
}
+
+static void
+check_leap_sec_in_progress( const leap_result_t *lsdata ) {
+ int prv_leap_sec_in_progress = leap_sec_in_progress;
+ leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3);
+
+ /* if changed we may have to update the leap status sent to clients */
+ if (leap_sec_in_progress != prv_leap_sec_in_progress)
+ set_sys_leap(sys_leap);
+}
+
+
+static void
+check_leapsec(
+ u_int32 now ,
+ const time_t * tpiv ,
+ int/*BOOL*/ reset)
+{
+ static const char leapmsg_p_step[] =
+ "Positive leap second, stepped backward.";
+ static const char leapmsg_p_slew[] =
+ "Positive leap second, no step correction. "
+ "System clock will be inaccurate for a long time.";
+
+ static const char leapmsg_n_step[] =
+ "Negative leap second, stepped forward.";
+ static const char leapmsg_n_slew[] =
+ "Negative leap second, no step correction. "
+ "System clock will be inaccurate for a long time.";
+
+ leap_result_t lsdata;
+ u_int32 lsprox;
+#ifdef AUTOKEY
+ int/*BOOL*/ update_autokey = FALSE;
+#endif
+
+#ifndef SYS_WINNT /* WinNT port has its own leap second handling */
+# ifdef KERNEL_PLL
+ leapsec_electric(pll_control && kern_enable);
+# else
+ leapsec_electric(0);
+# endif
+#endif
+#ifdef LEAP_SMEAR
+ leap_smear.enabled = leap_smear_intv != 0;
+#endif
+ if (reset) {
+ lsprox = LSPROX_NOWARN;
+ leapsec_reset_frame();
+ memset(&lsdata, 0, sizeof(lsdata));
+ } else {
+ int fired = leapsec_query(&lsdata, now, tpiv);
+
+ DPRINTF(1, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n",
+ fired, now, now, lsdata.tai_diff, lsdata.ddist));
+
+#ifdef LEAP_SMEAR
+ leap_smear.in_progress = 0;
+ leap_smear.doffset = 0.0;
+
+ if (leap_smear.enabled) {
+ if (lsdata.tai_diff) {
+ if (leap_smear.interval == 0) {
+ leap_smear.interval = leap_smear_intv;
+ leap_smear.intv_end = lsdata.ttime.Q_s;
+ leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval;
+ DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n",
+ leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end));
+ }
+ }
+ else {
+ if (leap_smear.interval)
+ DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n"));
+ leap_smear.interval = 0;
+ }
+
+ if (leap_smear.interval) {
+ double dtemp = now;
+ if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) {
+ double leap_smear_time = dtemp - leap_smear.intv_start;
+ /*
+ * For now we just do a linear interpolation over the smear interval
+ */
+#if 0
+ // linear interpolation
+ leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval);
+#else
+ // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0
+ leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0;
+#endif
+ /*
+ * TODO see if we're inside an inserted leap second, so we need to compute
+ * leap_smear.doffset = 1.0 - leap_smear.doffset
+ */
+ leap_smear.in_progress = 1;
+#if 0 && defined( DEBUG )
+ msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n",
+ leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
+ now, leap_smear_time, leap_smear.doffset);
+#else
+ DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n",
+ leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
+ now, leap_smear_time, leap_smear.doffset));
+#endif
+
+ }
+ }
+ }
+ else
+ leap_smear.interval = 0;
+
+ /*
+ * Update the current leap smear offset, eventually 0.0 if outside smear interval.
+ */
+ DTOLFP(leap_smear.doffset, &leap_smear.offset);
+
+#endif /* LEAP_SMEAR */
+
+ if (fired) {
+ /* Full hit. Eventually step the clock, but always
+ * announce the leap event has happened.
+ */
+ const char *leapmsg = NULL;
+ if (lsdata.warped < 0) {
+ if (clock_max_back > 0.0 &&
+ clock_max_back < fabs(lsdata.warped)) {
+ step_systime(lsdata.warped);
+ leapmsg = leapmsg_p_step;
+ } else {
+ leapmsg = leapmsg_p_slew;
+ }
+ } else if (lsdata.warped > 0) {
+ if (clock_max_fwd > 0.0 &&
+ clock_max_fwd < fabs(lsdata.warped)) {
+ step_systime(lsdata.warped);
+ leapmsg = leapmsg_n_step;
+ } else {
+ leapmsg = leapmsg_n_slew;
+ }
+ }
+ if (leapmsg)
+ msyslog(LOG_NOTICE, "%s", leapmsg);
+ report_event(EVNT_LEAP, NULL, NULL);
+#ifdef AUTOKEY
+ update_autokey = TRUE;
+#endif
+ lsprox = LSPROX_NOWARN;
+ leapsec = LSPROX_NOWARN;
+ sys_tai = lsdata.tai_offs;
+ } else {
+#ifdef AUTOKEY
+ update_autokey = (sys_tai != lsdata.tai_offs);
+#endif
+ lsprox = lsdata.proximity;
+ sys_tai = lsdata.tai_offs;
+ }
+ }
+
+ /* We guard against panic alarming during the red alert phase.
+ * Strange and evil things might happen if we go from stone cold
+ * to piping hot in one step. If things are already that wobbly,
+ * we let the normal clock correction take over, even if a jump
+ * is involved.
+ * Also make sure the alarming events are edge-triggered, that is,
+ * ceated only when the threshold is crossed.
+ */
+ if ( (leapsec > 0 || lsprox < LSPROX_ALERT)
+ && leapsec < lsprox ) {
+ if ( leapsec < LSPROX_SCHEDULE
+ && lsprox >= LSPROX_SCHEDULE) {
+ if (lsdata.dynamic)
+ report_event(PEVNT_ARMED, sys_peer, NULL);
+ else
+ report_event(EVNT_ARMED, NULL, NULL);
+ }
+ leapsec = lsprox;
+ }
+ if (leapsec > lsprox) {
+ if ( leapsec >= LSPROX_SCHEDULE
+ && lsprox < LSPROX_SCHEDULE) {
+ report_event(EVNT_DISARMED, NULL, NULL);
+ }
+ leapsec = lsprox;
+ }
+
+ if (leapsec >= LSPROX_SCHEDULE)
+ leapdif = lsdata.tai_diff;
+ else
+ leapdif = 0;
+
+ check_leap_sec_in_progress(&lsdata);
+
+#ifdef AUTOKEY
+ if (update_autokey)
+ crypto_update_taichange();
+#endif
+}
diff --git a/contrib/ntp/ntpd/ntp_util.c b/contrib/ntp/ntpd/ntp_util.c
index 91ff8a6..c4bc901 100644
--- a/contrib/ntp/ntpd/ntp_util.c
+++ b/contrib/ntp/ntpd/ntp_util.c
@@ -1,17 +1,19 @@
/*
* ntp_util.c - stuff I didn't have any other place for
*/
-
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ntpd.h"
-#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_filegen.h"
#include "ntp_if.h"
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
+#include "ntp_calendar.h"
+#include "ntp_leapsec.h"
+#include "lib_strbuf.h"
#include <stdio.h>
#include <ctype.h>
@@ -19,6 +21,10 @@
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <sys/stat.h>
#ifdef HAVE_IEEEFP_H
# include <ieeefp.h>
@@ -27,35 +33,35 @@
# include <math.h>
#endif
-#ifdef DOSYNCTODR
-# if !defined(VMS)
-# include <sys/resource.h>
-# endif /* VMS */
-#endif
-
#if defined(VMS)
# include <descrip.h>
#endif /* VMS */
/*
- * This contains odds and ends. Right now the only thing you'll find
- * in here is the hourly stats printer and some code to support
- * rereading the keys file, but I may eventually put other things in
- * here such as code to do something with the leap bits.
+ * Defines used by the leapseconds stuff
*/
+#define MAX_TAI 100 /* max TAI offset (s) */
+#define L_DAY 86400UL /* seconds per day */
+#define L_YEAR (L_DAY * 365) /* days per year */
+#define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */
+#define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */
+#define L_CENT (L_4YEAR * 25) /* days per century */
+
/*
- * Name of the keys file
+ * This contains odds and ends, including the hourly stats, various
+ * configuration items, leapseconds stuff, etc.
*/
-static char *key_file_name;
-
/*
- * The name of the drift_comp file and the temporary.
+ * File names
*/
-static char *stats_drift_file;
-static char *stats_temp_file;
-int stats_write_period = 3600; /* # of seconds between writes. */
-double stats_write_tolerance = 0;
-static double prev_drift_comp = 99999.;
+static char *key_file_name; /* keys file name */
+static char *leapfile_name; /* leapseconds file name */
+static struct stat leapfile_stat; /* leapseconds file stat() buffer */
+static int /*BOOL*/have_leapfile = FALSE;
+char *stats_drift_file; /* frequency file name */
+static char *stats_temp_file; /* temp frequency file name */
+static double wander_resid; /* last frequency update */
+double wander_threshold = 1e-7; /* initial frequency threshold */
/*
* Statistics file stuff
@@ -64,27 +70,20 @@ static double prev_drift_comp = 99999.;
# ifndef SYS_WINNT
# define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */
# else
-# define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
+# define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
# endif /* SYS_WINNT */
#endif
-#ifndef MAXPATHLEN
-# define MAXPATHLEN 256
-#endif
-
-static char statsdir[MAXPATHLEN] = NTP_VAR;
+char statsdir[MAXFILENAME] = NTP_VAR;
static FILEGEN peerstats;
static FILEGEN loopstats;
static FILEGEN clockstats;
static FILEGEN rawstats;
static FILEGEN sysstats;
-#ifdef DEBUG_TIMING
-static FILEGEN timingstats;
-#endif
-#ifdef OPENSSL
+static FILEGEN protostats;
static FILEGEN cryptostats;
-#endif /* OPENSSL */
+static FILEGEN timingstats;
/*
* This controls whether stats are written to the fileset. Provided
@@ -93,37 +92,86 @@ static FILEGEN cryptostats;
int stats_control;
/*
- * Initial frequency offset later passed to the loopfilter.
+ * Last frequency written to file.
*/
-double old_drift;
+static double prev_drift_comp; /* last frequency update */
/*
- * init_util - initialize the utilities
+ * Function prototypes
*/
-void
-init_util(void)
-{
- stats_drift_file = 0;
- stats_temp_file = 0;
- key_file_name = 0;
-
- filegen_register(&statsdir[0], "peerstats", &peerstats);
+static void record_sys_stats(void);
+ void ntpd_time_stepped(void);
+static void check_leap_expiration(int, uint32_t, const time_t*);
- filegen_register(&statsdir[0], "loopstats", &loopstats);
-
- filegen_register(&statsdir[0], "clockstats", &clockstats);
+/*
+ * Prototypes
+ */
+#ifdef DEBUG
+void uninit_util(void);
+#endif
- filegen_register(&statsdir[0], "rawstats", &rawstats);
+/*
+ * uninit_util - free memory allocated by init_util
+ */
+#ifdef DEBUG
+void
+uninit_util(void)
+{
+#if defined(_MSC_VER) && defined (_DEBUG)
+ _CrtCheckMemory();
+#endif
+ if (stats_drift_file) {
+ free(stats_drift_file);
+ free(stats_temp_file);
+ stats_drift_file = NULL;
+ stats_temp_file = NULL;
+ }
+ if (key_file_name) {
+ free(key_file_name);
+ key_file_name = NULL;
+ }
+ filegen_unregister("peerstats");
+ filegen_unregister("loopstats");
+ filegen_unregister("clockstats");
+ filegen_unregister("rawstats");
+ filegen_unregister("sysstats");
+ filegen_unregister("protostats");
+#ifdef AUTOKEY
+ filegen_unregister("cryptostats");
+#endif /* AUTOKEY */
+#ifdef DEBUG_TIMING
+ filegen_unregister("timingstats");
+#endif /* DEBUG_TIMING */
- filegen_register(&statsdir[0], "sysstats", &sysstats);
+#if defined(_MSC_VER) && defined (_DEBUG)
+ _CrtCheckMemory();
+#endif
+}
+#endif /* DEBUG */
-#ifdef OPENSSL
- filegen_register(&statsdir[0], "cryptostats", &cryptostats);
-#endif /* OPENSSL */
-#ifdef DEBUG_TIMING
- filegen_register(&statsdir[0], "timingstats", &timingstats);
-#endif
+/*
+ * init_util - initialize the util module of ntpd
+ */
+void
+init_util(void)
+{
+ filegen_register(statsdir, "peerstats", &peerstats);
+ filegen_register(statsdir, "loopstats", &loopstats);
+ filegen_register(statsdir, "clockstats", &clockstats);
+ filegen_register(statsdir, "rawstats", &rawstats);
+ filegen_register(statsdir, "sysstats", &sysstats);
+ filegen_register(statsdir, "protostats", &protostats);
+ filegen_register(statsdir, "cryptostats", &cryptostats);
+ filegen_register(statsdir, "timingstats", &timingstats);
+ /*
+ * register with libntp ntp_set_tod() to call us back
+ * when time is stepped.
+ */
+ step_callback = &ntpd_time_stepped;
+#ifdef DEBUG
+ atexit(&uninit_util);
+#endif /* DEBUG */
}
@@ -133,17 +181,16 @@ init_util(void)
void
write_stats(void)
{
- FILE *fp;
-
+ FILE *fp;
#ifdef DOSYNCTODR
struct timeval tv;
#if !defined(VMS)
- int prio_set;
+ int prio_set;
#endif
#ifdef HAVE_GETCLOCK
- struct timespec ts;
+ struct timespec ts;
#endif
- int o_prio;
+ int o_prio;
/*
* Sometimes having a Sun can be a drag.
@@ -163,12 +210,13 @@ write_stats(void)
* thing to do.
*
* CAVEAT: settimeofday() steps the sun clock by about 800 us,
- * so setting DOSYNCTODR seems a bad idea in the
- * case of us resolution
+ * so setting DOSYNCTODR seems a bad idea in the
+ * case of us resolution
*/
#if !defined(VMS)
- /* (prr) getpriority returns -1 on error, but -1 is also a valid
+ /*
+ * (prr) getpriority returns -1 on error, but -1 is also a valid
* return value (!), so instead we have to zero errno before the
* call and check it for non-zero afterwards.
*/
@@ -192,37 +240,45 @@ write_stats(void)
prio_set = 1; /* overdrive */
#endif /* VMS */
#ifdef HAVE_GETCLOCK
- (void) getclock(TIMEOFDAY, &ts);
- tv.tv_sec = ts.tv_sec;
- tv.tv_usec = ts.tv_nsec / 1000;
+ (void) getclock(TIMEOFDAY, &ts);
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
#else /* not HAVE_GETCLOCK */
GETTIMEOFDAY(&tv,(struct timezone *)NULL);
#endif /* not HAVE_GETCLOCK */
- if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) {
+ if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0)
msyslog(LOG_ERR, "can't sync battery time: %m");
- }
#if !defined(VMS)
if (prio_set)
setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
#endif /* VMS */
#endif /* DOSYNCTODR */
-
- NLOG(NLOG_SYSSTATIST)
- msyslog(LOG_INFO,
- "offset %.6f sec freq %.3f ppm error %.6f poll %d",
- last_offset, drift_comp * 1e6, sys_jitter,
- sys_poll);
-
-
record_sys_stats();
- if ((u_long)(fabs(prev_drift_comp - drift_comp) * 1e9) <=
- (u_long)(fabs(stats_write_tolerance * drift_comp) * 1e9)) {
- return;
- }
- prev_drift_comp = drift_comp;
if (stats_drift_file != 0) {
+
+ /*
+ * When the frequency file is written, initialize the
+ * prev_drift_comp and wander_resid. Thereafter,
+ * reduce the wander_resid by half each hour. When
+ * the difference between the prev_drift_comp and
+ * drift_comp is less than the wander_resid, update
+ * the frequncy file. This minimizes the file writes to
+ * nonvolaile storage.
+ */
+#ifdef DEBUG
+ if (debug)
+ printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n",
+ (prev_drift_comp - drift_comp) * 1e6, wander_resid *
+ 1e6, drift_comp * 1e6);
+#endif
+ if (fabs(prev_drift_comp - drift_comp) < wander_resid) {
+ wander_resid *= 0.5;
+ return;
+ }
+ prev_drift_comp = drift_comp;
+ wander_resid = wander_threshold;
if ((fp = fopen(stats_temp_file, "w")) == NULL) {
- msyslog(LOG_ERR, "can't open %s: %m",
+ msyslog(LOG_ERR, "frequency file %s: %m",
stats_temp_file);
return;
}
@@ -230,19 +286,26 @@ write_stats(void)
(void)fclose(fp);
/* atomic */
#ifdef SYS_WINNT
- (void) _unlink(stats_drift_file); /* rename semantics differ under NT */
+ if (_unlink(stats_drift_file)) /* rename semantics differ under NT */
+ msyslog(LOG_WARNING,
+ "Unable to remove prior drift file %s, %m",
+ stats_drift_file);
#endif /* SYS_WINNT */
#ifndef NO_RENAME
- (void) rename(stats_temp_file, stats_drift_file);
+ if (rename(stats_temp_file, stats_drift_file))
+ msyslog(LOG_WARNING,
+ "Unable to rename temp drift file %s to %s, %m",
+ stats_temp_file, stats_drift_file);
#else
/* we have no rename NFS of ftp in use */
- if ((fp = fopen(stats_drift_file, "w")) == NULL) {
- msyslog(LOG_ERR, "can't open %s: %m",
+ if ((fp = fopen(stats_drift_file, "w")) ==
+ NULL) {
+ msyslog(LOG_ERR,
+ "frequency file %s: %m",
stats_drift_file);
return;
}
-
#endif
#if defined(VMS)
@@ -250,9 +313,10 @@ write_stats(void)
{
$DESCRIPTOR(oldvers,";-1");
struct dsc$descriptor driftdsc = {
- strlen(stats_drift_file),0,0,stats_drift_file };
-
- while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
+ strlen(stats_drift_file), 0, 0,
+ stats_drift_file };
+ while(lib$delete_file(&oldvers,
+ &driftdsc) & 1);
}
#endif
}
@@ -268,9 +332,17 @@ stats_config(
const char *invalue /* only one type so far */
)
{
- FILE *fp;
+ FILE *fp;
const char *value;
- int len;
+ int len;
+ double old_drift;
+ l_fp now;
+ time_t ttnow;
+#ifndef VMS
+ const char temp_ext[] = ".TEMP";
+#else
+ const char temp_ext[] = "-TEMP";
+#endif
/*
* Expand environment strings under Windows NT, since the
@@ -280,170 +352,192 @@ stats_config(
char newvalue[MAX_PATH], parameter[MAX_PATH];
if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
- switch(item) {
- case STATS_FREQ_FILE:
- strcpy(parameter,"STATS_FREQ_FILE");
+ switch (item) {
+ case STATS_FREQ_FILE:
+ strlcpy(parameter, "STATS_FREQ_FILE",
+ sizeof(parameter));
break;
- case STATS_STATSDIR:
- strcpy(parameter,"STATS_STATSDIR");
+
+ case STATS_LEAP_FILE:
+ strlcpy(parameter, "STATS_LEAP_FILE",
+ sizeof(parameter));
+ break;
+
+ case STATS_STATSDIR:
+ strlcpy(parameter, "STATS_STATSDIR",
+ sizeof(parameter));
break;
- case STATS_PID_FILE:
- strcpy(parameter,"STATS_PID_FILE");
+
+ case STATS_PID_FILE:
+ strlcpy(parameter, "STATS_PID_FILE",
+ sizeof(parameter));
break;
- default:
- strcpy(parameter,"UNKNOWN");
+
+ default:
+ strlcpy(parameter, "UNKNOWN",
+ sizeof(parameter));
break;
}
value = invalue;
-
msyslog(LOG_ERR,
- "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
+ "ExpandEnvironmentStrings(%s) failed: %m\n",
+ parameter);
} else {
value = newvalue;
}
-#else
+#else
value = invalue;
#endif /* SYS_WINNT */
- switch(item) {
- case STATS_FREQ_FILE:
- if (stats_drift_file != 0) {
- (void) free(stats_drift_file);
- (void) free(stats_temp_file);
- stats_drift_file = 0;
- stats_temp_file = 0;
- }
+ switch (item) {
- if (value == 0 || (len = strlen(value)) == 0)
- break;
+ /*
+ * Open and read frequency file.
+ */
+ case STATS_FREQ_FILE:
+ if (!value || (len = strlen(value)) == 0)
+ break;
- stats_drift_file = (char*)emalloc((u_int)(len + 1));
-#if !defined(VMS)
- stats_temp_file = (char*)emalloc((u_int)(len +
- sizeof(".TEMP")));
-#else
- stats_temp_file = (char*)emalloc((u_int)(len +
- sizeof("-TEMP")));
-#endif /* VMS */
- memmove(stats_drift_file, value, (unsigned)(len+1));
- memmove(stats_temp_file, value, (unsigned)len);
-#if !defined(VMS)
- memmove(stats_temp_file + len, ".TEMP",
- sizeof(".TEMP"));
-#else
- memmove(stats_temp_file + len, "-TEMP",
- sizeof("-TEMP"));
-#endif /* VMS */
+ stats_drift_file = erealloc(stats_drift_file, len + 1);
+ stats_temp_file = erealloc(stats_temp_file,
+ len + sizeof(".TEMP"));
+ memcpy(stats_drift_file, value, (size_t)(len+1));
+ memcpy(stats_temp_file, value, (size_t)len);
+ memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext));
/*
* Open drift file and read frequency. If the file is
* missing or contains errors, tell the loop to reset.
*/
- if ((fp = fopen(stats_drift_file, "r")) == NULL) {
- old_drift = 1e9;
+ if ((fp = fopen(stats_drift_file, "r")) == NULL)
break;
- }
+
if (fscanf(fp, "%lf", &old_drift) != 1) {
- msyslog(LOG_ERR, "Frequency format error in %s",
- stats_drift_file);
- old_drift = 1e9;
+ msyslog(LOG_ERR,
+ "format error frequency file %s",
+ stats_drift_file);
fclose(fp);
break;
+
}
fclose(fp);
- prev_drift_comp = old_drift / 1e6;
- msyslog(LOG_INFO,
- "frequency initialized %.3f PPM from %s",
- old_drift, stats_drift_file);
+ loop_config(LOOP_FREQ, old_drift);
+ prev_drift_comp = drift_comp;
break;
-
- case STATS_STATSDIR:
- if (strlen(value) >= sizeof(statsdir)) {
+
+ /*
+ * Specify statistics directory.
+ */
+ case STATS_STATSDIR:
+
+ /* - 1 since value may be missing the DIR_SEP. */
+ if (strlen(value) >= sizeof(statsdir) - 1) {
msyslog(LOG_ERR,
- "value for statsdir too long (>%d, sigh)",
- (int)sizeof(statsdir)-1);
+ "statsdir too long (>%d, sigh)",
+ (int)sizeof(statsdir) - 2);
} else {
- l_fp now;
-
- get_systime(&now);
- strcpy(statsdir,value);
- if(peerstats.prefix == &statsdir[0] &&
- peerstats.fp != NULL) {
- fclose(peerstats.fp);
- peerstats.fp = NULL;
- filegen_setup(&peerstats, now.l_ui);
- }
- if(loopstats.prefix == &statsdir[0] &&
- loopstats.fp != NULL) {
- fclose(loopstats.fp);
- loopstats.fp = NULL;
- filegen_setup(&loopstats, now.l_ui);
- }
- if(clockstats.prefix == &statsdir[0] &&
- clockstats.fp != NULL) {
- fclose(clockstats.fp);
- clockstats.fp = NULL;
- filegen_setup(&clockstats, now.l_ui);
- }
- if(rawstats.prefix == &statsdir[0] &&
- rawstats.fp != NULL) {
- fclose(rawstats.fp);
- rawstats.fp = NULL;
- filegen_setup(&rawstats, now.l_ui);
- }
- if(sysstats.prefix == &statsdir[0] &&
- sysstats.fp != NULL) {
- fclose(sysstats.fp);
- sysstats.fp = NULL;
- filegen_setup(&sysstats, now.l_ui);
- }
-#ifdef OPENSSL
- if(cryptostats.prefix == &statsdir[0] &&
- cryptostats.fp != NULL) {
- fclose(cryptostats.fp);
- cryptostats.fp = NULL;
- filegen_setup(&cryptostats, now.l_ui);
- }
-#endif /* OPENSSL */
+ int add_dir_sep;
+ int value_l;
+
+ /* Add a DIR_SEP unless we already have one. */
+ value_l = strlen(value);
+ if (0 == value_l)
+ add_dir_sep = FALSE;
+ else
+ add_dir_sep = (DIR_SEP !=
+ value[value_l - 1]);
+
+ if (add_dir_sep)
+ snprintf(statsdir, sizeof(statsdir),
+ "%s%c", value, DIR_SEP);
+ else
+ snprintf(statsdir, sizeof(statsdir),
+ "%s", value);
+ filegen_statsdir();
}
break;
- case STATS_PID_FILE:
+ /*
+ * Open pid file.
+ */
+ case STATS_PID_FILE:
if ((fp = fopen(value, "w")) == NULL) {
- msyslog(LOG_ERR, "Can't open %s: %m", value);
+ msyslog(LOG_ERR, "pid file %s: %m",
+ value);
+ break;
+ }
+ fprintf(fp, "%d", (int)getpid());
+ fclose(fp);
+ break;
+
+ /*
+ * Read leapseconds file.
+ *
+ * Note: Currently a leap file without SHA1 signature is
+ * accepted, but if there is a signature line, the signature
+ * must be valid or the file is rejected.
+ */
+ case STATS_LEAP_FILE:
+ if (!value || (len = strlen(value)) == 0)
break;
+
+ leapfile_name = erealloc(leapfile_name, len + 1);
+ memcpy(leapfile_name, value, len + 1);
+
+ if (leapsec_load_file(
+ leapfile_name, &leapfile_stat, TRUE, TRUE))
+ {
+ leap_signature_t lsig;
+
+ get_systime(&now);
+ time(&ttnow);
+ leapsec_getsig(&lsig);
+ mprintf_event(EVNT_TAI, NULL,
+ "%d leap %s %s %s",
+ lsig.taiof,
+ fstostr(lsig.ttime),
+ leapsec_expired(now.l_ui, NULL)
+ ? "expired"
+ : "expires",
+ fstostr(lsig.etime));
+
+ have_leapfile = TRUE;
+
+ /* force an immediate daily expiration check of
+ * the leap seconds table
+ */
+ check_leap_expiration(TRUE, now.l_ui, &ttnow);
}
- fprintf(fp, "%d", (int) getpid());
- fclose(fp);;
break;
- default:
+ default:
/* oh well */
break;
}
}
+
/*
* record_peer_stats - write peer statistics to file
*
* file format:
- * day (mjd)
+ * day (MJD)
* time (s past UTC midnight)
- * peer (ip address)
- * peer status word (hex)
- * peer offset (s)
- * peer delay (s)
- * peer error bound (s)
- * peer error (s)
+ * IP address
+ * status word (hex)
+ * offset
+ * delay
+ * dispersion
+ * jitter
*/
void
record_peer_stats(
- struct sockaddr_storage *addr,
+ sockaddr_u *addr,
int status,
- double offset,
- double delay,
- double dispersion,
- double skew
+ double offset, /* offset */
+ double delay, /* delay */
+ double dispersion, /* dispersion */
+ double jitter /* jitter */
)
{
l_fp now;
@@ -458,29 +552,32 @@ record_peer_stats(
now.l_ui %= 86400;
if (peerstats.fp != NULL) {
fprintf(peerstats.fp,
- "%lu %s %s %x %.9f %.9f %.9f %.9f\n",
- day, ulfptoa(&now, 3), stoa(addr), status, offset,
- delay, dispersion, skew);
+ "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day,
+ ulfptoa(&now, 3), stoa(addr), status, offset,
+ delay, dispersion, jitter);
fflush(peerstats.fp);
}
}
+
/*
* record_loop_stats - write loop filter statistics to file
*
* file format:
- * day (mjd)
+ * day (MJD)
* time (s past midnight)
- * offset (s)
- * frequency (approx ppm)
- * time constant (log base 2)
+ * offset
+ * frequency (PPM)
+ * jitter
+ * wnder (PPM)
+ * time constant (log2)
*/
void
record_loop_stats(
- double offset,
- double freq,
- double jitter,
- double stability,
+ double offset, /* offset */
+ double freq, /* frequency (PPM) */
+ double jitter, /* jitter */
+ double wander, /* wander (PPM) */
int spoll
)
{
@@ -497,24 +594,25 @@ record_loop_stats(
if (loopstats.fp != NULL) {
fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
- stability * 1e6, spoll);
+ wander * 1e6, spoll);
fflush(loopstats.fp);
}
}
+
/*
* record_clock_stats - write clock statistics to file
*
* file format:
- * day (mjd)
+ * day (MJD)
* time (s past midnight)
- * peer (ip address)
+ * IP address
* text message
*/
void
record_clock_stats(
- struct sockaddr_storage *addr,
- const char *text
+ sockaddr_u *addr,
+ const char *text /* timecode string */
)
{
l_fp now;
@@ -528,30 +626,64 @@ record_clock_stats(
day = now.l_ui / 86400 + MJD_1900;
now.l_ui %= 86400;
if (clockstats.fp != NULL) {
- fprintf(clockstats.fp, "%lu %s %s %s\n",
- day, ulfptoa(&now, 3), stoa(addr), text);
+ fprintf(clockstats.fp, "%lu %s %s %s\n", day,
+ ulfptoa(&now, 3), stoa(addr), text);
fflush(clockstats.fp);
}
}
+
+/*
+ * mprintf_clock_stats - write clock statistics to file with
+ * msnprintf-style formatting.
+ */
+int
+mprintf_clock_stats(
+ sockaddr_u *addr,
+ const char *fmt,
+ ...
+ )
+{
+ va_list ap;
+ int rc;
+ char msg[512];
+
+ va_start(ap, fmt);
+ rc = mvsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ if (stats_control)
+ record_clock_stats(addr, msg);
+
+ return rc;
+}
+
/*
* record_raw_stats - write raw timestamps to file
*
- *
* file format
+ * day (MJD)
* time (s past midnight)
* peer ip address
- * local ip address
+ * IP address
* t1 t2 t3 t4 timestamps
*/
void
record_raw_stats(
- struct sockaddr_storage *srcadr,
- struct sockaddr_storage *dstadr,
- l_fp *t1,
- l_fp *t2,
- l_fp *t3,
- l_fp *t4
+ sockaddr_u *srcadr,
+ sockaddr_u *dstadr,
+ l_fp *t1, /* originate timestamp */
+ l_fp *t2, /* receive timestamp */
+ l_fp *t3, /* transmit timestamp */
+ l_fp *t4, /* destination timestamp */
+ int leap,
+ int version,
+ int mode,
+ int stratum,
+ int ppoll,
+ int precision,
+ double root_delay, /* seconds */
+ double root_dispersion,/* seconds */
+ u_int32 refid
)
{
l_fp now;
@@ -565,10 +697,13 @@ record_raw_stats(
day = now.l_ui / 86400 + MJD_1900;
now.l_ui %= 86400;
if (rawstats.fp != NULL) {
- fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n",
- day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-",
- ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
- ulfptoa(t4, 9));
+ fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s\n",
+ day, ulfptoa(&now, 3),
+ stoa(srcadr), dstadr ? stoa(dstadr) : "-",
+ ulfptoa(t1, 9), ulfptoa(t2, 9),
+ ulfptoa(t3, 9), ulfptoa(t4, 9),
+ leap, version, mode, stratum, ppoll, precision,
+ root_delay, root_dispersion, refid_str(refid, stratum));
fflush(rawstats.fp);
}
}
@@ -578,17 +713,19 @@ record_raw_stats(
* record_sys_stats - write system statistics to file
*
* file format
+ * day (MJD)
* time (s past midnight)
- * time since startup (hr)
+ * time since reset
* packets recieved
- * packets processed
+ * packets for this host
* current version
- * previous version
- * bad version
+ * old version
* access denied
* bad length or format
* bad authentication
+ * declined
* rate exceeded
+ * KoD sent
*/
void
record_sys_stats(void)
@@ -604,33 +741,64 @@ record_sys_stats(void)
day = now.l_ui / 86400 + MJD_1900;
now.l_ui %= 86400;
if (sysstats.fp != NULL) {
- fprintf(sysstats.fp,
- "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
- day, ulfptoa(&now, 3), sys_stattime / 3600,
- sys_received, sys_processed, sys_newversionpkt,
- sys_oldversionpkt, sys_unknownversion,
- sys_restricted, sys_badlength, sys_badauth,
- sys_limitrejected);
+ fprintf(sysstats.fp,
+ "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+ day, ulfptoa(&now, 3), current_time - sys_stattime,
+ sys_received, sys_processed, sys_newversion,
+ sys_oldversion, sys_restricted, sys_badlength,
+ sys_badauth, sys_declined, sys_limitrejected,
+ sys_kodsent);
fflush(sysstats.fp);
proto_clr_stats();
}
}
-#ifdef OPENSSL
+/*
+ * record_proto_stats - write system statistics to file
+ *
+ * file format
+ * day (MJD)
+ * time (s past midnight)
+ * text message
+ */
+void
+record_proto_stats(
+ char *str /* text string */
+ )
+{
+ l_fp now;
+ u_long day;
+
+ if (!stats_control)
+ return;
+
+ get_systime(&now);
+ filegen_setup(&protostats, now.l_ui);
+ day = now.l_ui / 86400 + MJD_1900;
+ now.l_ui %= 86400;
+ if (protostats.fp != NULL) {
+ fprintf(protostats.fp, "%lu %s %s\n", day,
+ ulfptoa(&now, 3), str);
+ fflush(protostats.fp);
+ }
+}
+
+
+#ifdef AUTOKEY
/*
* record_crypto_stats - write crypto statistics to file
*
* file format:
* day (mjd)
* time (s past midnight)
- * peer (ip address)
+ * peer ip address
* text message
*/
void
record_crypto_stats(
- struct sockaddr_storage *addr,
- const char *text
+ sockaddr_u *addr,
+ const char *text /* text message */
)
{
l_fp now;
@@ -645,7 +813,7 @@ record_crypto_stats(
now.l_ui %= 86400;
if (cryptostats.fp != NULL) {
if (addr == NULL)
- fprintf(cryptostats.fp, "%lu %s %s\n",
+ fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n",
day, ulfptoa(&now, 3), text);
else
fprintf(cryptostats.fp, "%lu %s %s %s\n",
@@ -653,11 +821,12 @@ record_crypto_stats(
fflush(cryptostats.fp);
}
}
-#endif /* OPENSSL */
+#endif /* AUTOKEY */
+
#ifdef DEBUG_TIMING
/*
- * record_crypto_stats - write crypto statistics to file
+ * record_timing_stats - write timing statistics to file
*
* file format:
* day (mjd)
@@ -666,7 +835,7 @@ record_crypto_stats(
*/
void
record_timing_stats(
- const char *text
+ const char *text /* text message */
)
{
static unsigned int flshcnt;
@@ -681,13 +850,81 @@ record_timing_stats(
day = now.l_ui / 86400 + MJD_1900;
now.l_ui %= 86400;
if (timingstats.fp != NULL) {
- fprintf(timingstats.fp, "%lu %s %s\n",
- day, lfptoa(&now, 3), text);
+ fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now,
+ 3), text);
if (++flshcnt % 100 == 0)
fflush(timingstats.fp);
}
}
#endif
+
+
+/*
+ * check_leap_file - See if the leapseconds file has been updated.
+ *
+ * Returns: n/a
+ *
+ * Note: This loads a new leapfile on the fly. Currently a leap file
+ * without SHA1 signature is accepted, but if there is a signature line,
+ * the signature must be valid or the file is rejected.
+ */
+void
+check_leap_file(
+ int is_daily_check,
+ uint32_t ntptime ,
+ const time_t *systime
+ )
+{
+ /* just do nothing if there is no leap file */
+ if ( ! (leapfile_name && *leapfile_name))
+ return;
+
+ /* try to load leapfile, force it if no leapfile loaded yet */
+ if (leapsec_load_file(
+ leapfile_name, &leapfile_stat,
+ !have_leapfile, is_daily_check))
+ have_leapfile = TRUE;
+ else if (!have_leapfile)
+ return;
+
+ check_leap_expiration(is_daily_check, ntptime, systime);
+}
+
+/*
+ * check expiration of a loaded leap table
+ */
+static void
+check_leap_expiration(
+ int is_daily_check,
+ uint32_t ntptime ,
+ const time_t *systime
+ )
+{
+ static const char * const logPrefix = "leapsecond file";
+ int rc;
+
+ /* test the expiration of the leap data and log with proper
+ * level and frequency (once/hour or once/day, depending on the
+ * state.
+ */
+ rc = leapsec_daystolive(ntptime, systime);
+ if (rc == 0) {
+ msyslog(LOG_WARNING,
+ "%s ('%s'): will expire in less than one day",
+ logPrefix, leapfile_name);
+ } else if (is_daily_check && rc < 28) {
+ if (rc < 0)
+ msyslog(LOG_ERR,
+ "%s ('%s'): expired less than %d day%s ago",
+ logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s"));
+ else
+ msyslog(LOG_WARNING,
+ "%s ('%s'): will expire in less than %d days",
+ logPrefix, leapfile_name, 1+rc);
+ }
+}
+
+
/*
* getauthkeys - read the authentication keys from the specified file
*/
@@ -699,31 +936,24 @@ getauthkeys(
int len;
len = strlen(keyfile);
- if (len == 0)
+ if (!len)
return;
- if (key_file_name != 0) {
- if (len > (int)strlen(key_file_name)) {
- (void) free(key_file_name);
- key_file_name = 0;
- }
- }
-
- if (key_file_name == 0) {
#ifndef SYS_WINNT
- key_file_name = (char*)emalloc((u_int) (len + 1));
+ key_file_name = erealloc(key_file_name, len + 1);
+ memcpy(key_file_name, keyfile, len + 1);
#else
- key_file_name = (char*)emalloc((u_int) (MAXPATHLEN));
-#endif
- }
-#ifndef SYS_WINNT
- memmove(key_file_name, keyfile, (unsigned)(len+1));
-#else
- if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN))
- {
+ key_file_name = erealloc(key_file_name, _MAX_PATH);
+ if (len + 1 > _MAX_PATH)
+ return;
+ if (!ExpandEnvironmentStrings(keyfile, key_file_name,
+ _MAX_PATH)) {
msyslog(LOG_ERR,
- "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
+ "ExpandEnvironmentStrings(KEY_FILE) failed: %m");
+ strlcpy(key_file_name, keyfile, _MAX_PATH);
}
+ key_file_name = erealloc(key_file_name,
+ 1 + strlen(key_file_name));
#endif /* SYS_WINNT */
authreadkeys(key_file_name);
@@ -736,66 +966,66 @@ getauthkeys(
void
rereadkeys(void)
{
- if (key_file_name != 0)
- authreadkeys(key_file_name);
+ if (NULL != key_file_name)
+ authreadkeys(key_file_name);
}
+
+#if notyet
/*
- * sock_hash - hash an sockaddr_storage structure
+ * ntp_exit - document explicitly that ntpd has exited
*/
-int
-sock_hash(
- struct sockaddr_storage *addr
- )
+void
+ntp_exit(int retval)
{
- int hashVal;
- int i;
- int len;
- char *ch;
-
- hashVal = 0;
- len = 0;
- /*
- * We can't just hash the whole thing because there are hidden
- * fields in sockaddr_in6 that might be filled in by recvfrom(),
- * so just use the family, port and address.
- */
- ch = (char *)&addr->ss_family;
- hashVal = 37 * hashVal + (int)*ch;
- if (sizeof(addr->ss_family) > 1) {
- ch++;
- hashVal = 37 * hashVal + (int)*ch;
- }
- switch(addr->ss_family) {
- case AF_INET:
- ch = (char *)&((struct sockaddr_in *)addr)->sin_addr;
- len = sizeof(struct in_addr);
- break;
- case AF_INET6:
- ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr;
- len = sizeof(struct in6_addr);
- break;
- }
-
- for (i = 0; i < len ; i++)
- hashVal = 37 * hashVal + (int)*(ch + i);
-
- hashVal = hashVal % 128; /* % MON_HASH_SIZE hardcoded */
-
- if (hashVal < 0)
- hashVal += 128;
+ msyslog(LOG_ERR, "EXITING with return code %d", retval);
+ exit(retval);
+}
+#endif
- return hashVal;
+/*
+ * fstostr - prettyprint NTP seconds
+ */
+char * fstostr(
+ time_t ntp_stamp
+ )
+{
+ char * buf;
+ struct calendar tm;
+
+ LIB_GETBUF(buf);
+ if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0)
+ snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error",
+ (long)ntp_stamp);
+ else
+ snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d",
+ tm.year, tm.month, tm.monthday,
+ tm.hour, tm.minute);
+ return buf;
}
-#if notyet
+
/*
- * ntp_exit - document explicitly that ntpd has exited
+ * ntpd_time_stepped is called back by step_systime(), allowing ntpd
+ * to do any one-time processing necessitated by the step.
*/
void
-ntp_exit(int retval)
+ntpd_time_stepped(void)
{
- msyslog(LOG_ERR, "EXITING with return code %d", retval);
- exit(retval);
-}
+ u_int saved_mon_enabled;
+
+ /*
+ * flush the monitor MRU list which contains l_fp timestamps
+ * which should not be compared across the step.
+ */
+ if (MON_OFF != mon_enabled) {
+ saved_mon_enabled = mon_enabled;
+ mon_stop(MON_OFF);
+ mon_start(saved_mon_enabled);
+ }
+
+ /* inform interpolating Windows code to allow time to go back */
+#ifdef SYS_WINNT
+ win_time_stepped();
#endif
+}
diff --git a/contrib/ntp/ntpd/ntpd-opts.c b/contrib/ntp/ntpd/ntpd-opts.c
index 4d23d66..2d547a1 100644
--- a/contrib/ntp/ntpd/ntpd-opts.c
+++ b/contrib/ntp/ntpd/ntpd-opts.c
@@ -1,50 +1,67 @@
-/*
+/*
* EDIT THIS FILE WITH CAUTION (ntpd-opts.c)
- *
- * It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:10 AM EST
+ *
+ * It has been AutoGen-ed June 29, 2015 at 04:28:19 PM by AutoGen 5.18.5
* From the definitions ntpd-opts.def
* and the template file options
*
- * Generated from AutoOpts 29:0:4 templates.
- */
-
-/*
- * This file was produced by an AutoOpts template. AutoOpts is a
- * copyrighted work. This source file is not encumbered by AutoOpts
- * licensing, but is provided under the licensing terms chosen by the
- * ntpd author or copyright holder. AutoOpts is licensed under
- * the terms of the LGPL. The redistributable library (``libopts'') is
- * licensed under the terms of either the LGPL or, at the users discretion,
- * the BSD license. See the AutoOpts and/or libopts sources for details.
+ * Generated from AutoOpts 41:0:16 templates.
*
- * This source file is copyrighted and licensed under the following terms:
+ * AutoOpts is a copyrighted work. This source file is not encumbered
+ * by AutoOpts licensing, but is provided under the licensing terms chosen
+ * by the ntpd author or copyright holder. AutoOpts is
+ * licensed under the terms of the LGPL. The redistributable library
+ * (``libopts'') is licensed under the terms of either the LGPL or, at the
+ * users discretion, the BSD license. See the AutoOpts and/or libopts sources
+ * for details.
*
- * ntpd copyright 1970-2009 David L. Mills and/or others - all rights reserved
+ * The ntpd program is copyrighted and licensed
+ * under the following terms:
*
- * see html/copyright.html
+ * Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation, all rights reserved.
+ * This is free software. It is licensed for use, modification and
+ * redistribution under the terms of the NTP License, copies of which
+ * can be seen at:
+ * <http://ntp.org/license>
+ * <http://opensource.org/licenses/ntp-license.php>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and that
+ * both the copyright notice and this permission notice appear in
+ * supporting documentation, and that the name The University of Delaware not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The University of Delaware and Network Time Foundation makes no
+ * representations about the suitability this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
*/
-
-#include <limits.h>
-
+#ifndef __doxygen__
#define OPTION_CODE_COMPILE 1
#include "ntpd-opts.h"
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
-tSCC zCopyright[] =
- "ntpd copyright (c) 1970-2009 David L. Mills and/or others, all rights reserved";
-tSCC zCopyrightNotice[] =
-
-/* extracted from ../include/copyright.def near line 8 */
-"see html/copyright.html";
-extern tUsageProc optionUsage;
+extern FILE * option_usage_fp;
+#define zCopyright (ntpd_opt_strs+0)
+#define zLicenseDescrip (ntpd_opt_strs+340)
/*
* global included definitions
*/
#ifdef __windows
+ extern int atoi(const char *);
+#else
+# include <stdlib.h>
+#endif
+
+#ifdef __windows
extern int atoi(const char*);
#else
# include <stdlib.h>
@@ -53,409 +70,754 @@ extern tUsageProc optionUsage;
#ifndef NULL
# define NULL 0
#endif
-#ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
-#endif
-#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
-#endif
-/*
- * Ipv4 option description:
- */
-tSCC zIpv4Text[] =
- "Force IPv4 DNS name resolution";
-tSCC zIpv4_NAME[] = "IPV4";
-tSCC zIpv4_Name[] = "ipv4";
-#define IPV4_FLAGS (OPTST_DISABLED)
-/*
- * Ipv6 option description:
+/**
+ * static const strings for ntpd options
*/
-tSCC zIpv6Text[] =
- "Force IPv6 DNS name resolution";
-tSCC zIpv6_NAME[] = "IPV6";
-tSCC zIpv6_Name[] = "ipv6";
-#define IPV6_FLAGS (OPTST_DISABLED)
-
-/*
- * Authreq option description with
+static char const ntpd_opt_strs[3129] =
+/* 0 */ "ntpd 4.2.8p3\n"
+ "Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation, all rights reserved.\n"
+ "This is free software. It is licensed for use, modification and\n"
+ "redistribution under the terms of the NTP License, copies of which\n"
+ "can be seen at:\n"
+ " <http://ntp.org/license>\n"
+ " <http://opensource.org/licenses/ntp-license.php>\n\0"
+/* 340 */ "Permission to use, copy, modify, and distribute this software and its\n"
+ "documentation for any purpose with or without fee is hereby granted,\n"
+ "provided that the above copyright notice appears in all copies and that\n"
+ "both the copyright notice and this permission notice appear in supporting\n"
+ "documentation, and that the name The University of Delaware not be used in\n"
+ "advertising or publicity pertaining to distribution of the software without\n"
+ "specific, written prior permission. The University of Delaware and Network\n"
+ "Time Foundation makes no representations about the suitability this\n"
+ "software for any purpose. It is provided \"as is\" without express or\n"
+ "implied warranty.\n\0"
+/* 1008 */ "Force IPv4 DNS name resolution\0"
+/* 1039 */ "IPV4\0"
+/* 1044 */ "ipv4\0"
+/* 1049 */ "Force IPv6 DNS name resolution\0"
+/* 1080 */ "IPV6\0"
+/* 1085 */ "ipv6\0"
+/* 1090 */ "Require crypto authentication\0"
+/* 1120 */ "AUTHREQ\0"
+/* 1128 */ "authreq\0"
+/* 1136 */ "Do not require crypto authentication\0"
+/* 1173 */ "AUTHNOREQ\0"
+/* 1183 */ "authnoreq\0"
+/* 1193 */ "Allow us to sync to broadcast servers\0"
+/* 1231 */ "BCASTSYNC\0"
+/* 1241 */ "bcastsync\0"
+/* 1251 */ "configuration file name\0"
+/* 1275 */ "CONFIGFILE\0"
+/* 1286 */ "configfile\0"
+/* 1297 */ "Increase debug verbosity level\0"
+/* 1328 */ "DEBUG_LEVEL\0"
+/* 1340 */ "debug-level\0"
+/* 1352 */ "Set the debug verbosity level\0"
+/* 1382 */ "SET_DEBUG_LEVEL\0"
+/* 1398 */ "set-debug-level\0"
+/* 1414 */ "frequency drift file name\0"
+/* 1440 */ "DRIFTFILE\0"
+/* 1450 */ "driftfile\0"
+/* 1460 */ "Allow the first adjustment to be Big\0"
+/* 1497 */ "PANICGATE\0"
+/* 1507 */ "panicgate\0"
+/* 1517 */ "Step any initial offset correction.\0"
+/* 1553 */ "FORCE_STEP_ONCE\0"
+/* 1569 */ "force-step-once\0"
+/* 1585 */ "Jail directory\0"
+/* 1600 */ "JAILDIR\0"
+/* 1608 */ "jaildir\0"
+/* 1616 */ "built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs\0"
+/* 1695 */ "Listen on an interface name or address\0"
+/* 1734 */ "INTERFACE\0"
+/* 1744 */ "interface\0"
+/* 1754 */ "path to symmetric keys\0"
+/* 1777 */ "KEYFILE\0"
+/* 1785 */ "keyfile\0"
+/* 1793 */ "path to the log file\0"
+/* 1814 */ "LOGFILE\0"
+/* 1822 */ "logfile\0"
+/* 1830 */ "Do not listen to virtual interfaces\0"
+/* 1866 */ "NOVIRTUALIPS\0"
+/* 1879 */ "novirtualips\0"
+/* 1892 */ "Modify Multimedia Timer (Windows only)\0"
+/* 1931 */ "MODIFYMMTIMER\0"
+/* 1945 */ "modifymmtimer\0"
+/* 1959 */ "Do not fork\0"
+/* 1971 */ "NOFORK\0"
+/* 1978 */ "nofork\0"
+/* 1985 */ "Run at high priority\0"
+/* 2006 */ "NICE\0"
+/* 2011 */ "nice\0"
+/* 2016 */ "path to the PID file\0"
+/* 2037 */ "PIDFILE\0"
+/* 2045 */ "pidfile\0"
+/* 2053 */ "Process priority\0"
+/* 2070 */ "PRIORITY\0"
+/* 2079 */ "priority\0"
+/* 2088 */ "Set the time and quit\0"
+/* 2110 */ "QUIT\0"
+/* 2115 */ "quit\0"
+/* 2120 */ "Broadcast/propagation delay\0"
+/* 2148 */ "PROPAGATIONDELAY\0"
+/* 2165 */ "propagationdelay\0"
+/* 2182 */ "Save parsed configuration and quit\0"
+/* 2217 */ "SAVECONFIGQUIT\0"
+/* 2232 */ "saveconfigquit\0"
+/* 2247 */ "Statistics file location\0"
+/* 2272 */ "STATSDIR\0"
+/* 2281 */ "statsdir\0"
+/* 2290 */ "Trusted key number\0"
+/* 2309 */ "TRUSTEDKEY\0"
+/* 2320 */ "trustedkey\0"
+/* 2331 */ "Run as userid (or userid:groupid)\0"
+/* 2365 */ "USER\0"
+/* 2370 */ "user\0"
+/* 2375 */ "interval in seconds between scans for new or dropped interfaces\0"
+/* 2439 */ "UPDATEINTERVAL\0"
+/* 2454 */ "updateinterval\0"
+/* 2469 */ "make ARG an ntp variable (RW)\0"
+/* 2499 */ "VAR\0"
+/* 2503 */ "var\0"
+/* 2507 */ "make ARG an ntp variable (RW|DEF)\0"
+/* 2541 */ "DVAR\0"
+/* 2546 */ "dvar\0"
+/* 2551 */ "Seconds to wait for first clock sync\0"
+/* 2588 */ "WAIT_SYNC\0"
+/* 2598 */ "wait-sync\0"
+/* 2608 */ "Slew up to 600 seconds\0"
+/* 2631 */ "SLEW\0"
+/* 2636 */ "slew\0"
+/* 2641 */ "Use CPU cycle counter (Windows only)\0"
+/* 2678 */ "USEPCC\0"
+/* 2685 */ "usepcc\0"
+/* 2692 */ "Force CPU cycle counter use (Windows only)\0"
+/* 2735 */ "PCCFREQ\0"
+/* 2743 */ "pccfreq\0"
+/* 2751 */ "Register with mDNS as a NTP server\0"
+/* 2786 */ "MDNS\0"
+/* 2791 */ "mdns\0"
+/* 2796 */ "display extended usage information and exit\0"
+/* 2840 */ "help\0"
+/* 2845 */ "extended usage information passed thru pager\0"
+/* 2890 */ "more-help\0"
+/* 2900 */ "output version information and exit\0"
+/* 2936 */ "version\0"
+/* 2944 */ "NTPD\0"
+/* 2949 */ "ntpd - NTP daemon program - Ver. 4.2.8p3\n"
+ "Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n"
+ "\t\t[ <server1> ... <serverN> ]\n\0"
+/* 3080 */ "http://bugs.ntp.org, bugs@ntp.org\0"
+/* 3114 */ "\n\0"
+/* 3116 */ "ntpd 4.2.8p3";
+
+/**
+ * ipv4 option description with
+ * "Must also have options" and "Incompatible options":
+ */
+/** Descriptive text for the ipv4 option */
+#define IPV4_DESC (ntpd_opt_strs+1008)
+/** Upper-cased name for the ipv4 option */
+#define IPV4_NAME (ntpd_opt_strs+1039)
+/** Name string for the ipv4 option */
+#define IPV4_name (ntpd_opt_strs+1044)
+/** Other options that appear in conjunction with the ipv4 option */
+static int const aIpv4CantList[] = {
+ INDEX_OPT_IPV6, NO_EQUIVALENT };
+/** Compiled in flag settings for the ipv4 option */
+#define IPV4_FLAGS (OPTST_DISABLED)
+
+/**
+ * ipv6 option description with
* "Must also have options" and "Incompatible options":
*/
-tSCC zAuthreqText[] =
- "Require crypto authentication";
-tSCC zAuthreq_NAME[] = "AUTHREQ";
-tSCC zAuthreq_Name[] = "authreq";
-static const int
- aAuthreqCantList[] = {
+/** Descriptive text for the ipv6 option */
+#define IPV6_DESC (ntpd_opt_strs+1049)
+/** Upper-cased name for the ipv6 option */
+#define IPV6_NAME (ntpd_opt_strs+1080)
+/** Name string for the ipv6 option */
+#define IPV6_name (ntpd_opt_strs+1085)
+/** Other options that appear in conjunction with the ipv6 option */
+static int const aIpv6CantList[] = {
+ INDEX_OPT_IPV4, NO_EQUIVALENT };
+/** Compiled in flag settings for the ipv6 option */
+#define IPV6_FLAGS (OPTST_DISABLED)
+
+/**
+ * authreq option description with
+ * "Must also have options" and "Incompatible options":
+ */
+/** Descriptive text for the authreq option */
+#define AUTHREQ_DESC (ntpd_opt_strs+1090)
+/** Upper-cased name for the authreq option */
+#define AUTHREQ_NAME (ntpd_opt_strs+1120)
+/** Name string for the authreq option */
+#define AUTHREQ_name (ntpd_opt_strs+1128)
+/** Other options that appear in conjunction with the authreq option */
+static int const aAuthreqCantList[] = {
INDEX_OPT_AUTHNOREQ, NO_EQUIVALENT };
-#define AUTHREQ_FLAGS (OPTST_DISABLED)
+/** Compiled in flag settings for the authreq option */
+#define AUTHREQ_FLAGS (OPTST_DISABLED)
-/*
- * Authnoreq option description with
+/**
+ * authnoreq option description with
* "Must also have options" and "Incompatible options":
*/
-tSCC zAuthnoreqText[] =
- "Do not require crypto authentication";
-tSCC zAuthnoreq_NAME[] = "AUTHNOREQ";
-tSCC zAuthnoreq_Name[] = "authnoreq";
-static const int
- aAuthnoreqCantList[] = {
+/** Descriptive text for the authnoreq option */
+#define AUTHNOREQ_DESC (ntpd_opt_strs+1136)
+/** Upper-cased name for the authnoreq option */
+#define AUTHNOREQ_NAME (ntpd_opt_strs+1173)
+/** Name string for the authnoreq option */
+#define AUTHNOREQ_name (ntpd_opt_strs+1183)
+/** Other options that appear in conjunction with the authnoreq option */
+static int const aAuthnoreqCantList[] = {
INDEX_OPT_AUTHREQ, NO_EQUIVALENT };
-#define AUTHNOREQ_FLAGS (OPTST_DISABLED)
+/** Compiled in flag settings for the authnoreq option */
+#define AUTHNOREQ_FLAGS (OPTST_DISABLED)
-/*
- * Bcastsync option description:
+/**
+ * bcastsync option description:
*/
-tSCC zBcastsyncText[] =
- "Allow us to sync to broadcast servers";
-tSCC zBcastsync_NAME[] = "BCASTSYNC";
-tSCC zBcastsync_Name[] = "bcastsync";
-#define BCASTSYNC_FLAGS (OPTST_DISABLED)
-
-/*
- * Configfile option description:
+/** Descriptive text for the bcastsync option */
+#define BCASTSYNC_DESC (ntpd_opt_strs+1193)
+/** Upper-cased name for the bcastsync option */
+#define BCASTSYNC_NAME (ntpd_opt_strs+1231)
+/** Name string for the bcastsync option */
+#define BCASTSYNC_name (ntpd_opt_strs+1241)
+/** Compiled in flag settings for the bcastsync option */
+#define BCASTSYNC_FLAGS (OPTST_DISABLED)
+
+/**
+ * configfile option description:
*/
-tSCC zConfigfileText[] =
- "configuration file name";
-tSCC zConfigfile_NAME[] = "CONFIGFILE";
-tSCC zConfigfile_Name[] = "configfile";
-#define CONFIGFILE_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the configfile option */
+#define CONFIGFILE_DESC (ntpd_opt_strs+1251)
+/** Upper-cased name for the configfile option */
+#define CONFIGFILE_NAME (ntpd_opt_strs+1275)
+/** Name string for the configfile option */
+#define CONFIGFILE_name (ntpd_opt_strs+1286)
+/** Compiled in flag settings for the configfile option */
+#define CONFIGFILE_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Debug_Level option description:
- */
-#ifdef DEBUG
-tSCC zDebug_LevelText[] =
- "Increase output debug message level";
-tSCC zDebug_Level_NAME[] = "DEBUG_LEVEL";
-tSCC zDebug_Level_Name[] = "debug-level";
-#define DEBUG_LEVEL_FLAGS (OPTST_DISABLED)
-
-#else /* disable Debug_Level */
-#define VALUE_OPT_DEBUG_LEVEL NO_EQUIVALENT
-#define DEBUG_LEVEL_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
-#define zDebug_LevelText NULL
-#define zDebug_Level_NAME NULL
-#define zDebug_Level_Name NULL
-#endif /* DEBUG */
-
-/*
- * Set_Debug_Level option description:
- */
-#ifdef DEBUG
-tSCC zSet_Debug_LevelText[] =
- "Set the output debug message level";
-tSCC zSet_Debug_Level_NAME[] = "SET_DEBUG_LEVEL";
-tSCC zSet_Debug_Level_Name[] = "set-debug-level";
-#define SET_DEBUG_LEVEL_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-#else /* disable Set_Debug_Level */
-#define VALUE_OPT_SET_DEBUG_LEVEL NO_EQUIVALENT
-#define SET_DEBUG_LEVEL_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
-#define zSet_Debug_LevelText NULL
-#define zSet_Debug_Level_NAME NULL
-#define zSet_Debug_Level_Name NULL
-#endif /* DEBUG */
+/**
+ * debug-level option description:
+ */
+/** Descriptive text for the debug-level option */
+#define DEBUG_LEVEL_DESC (ntpd_opt_strs+1297)
+/** Upper-cased name for the debug-level option */
+#define DEBUG_LEVEL_NAME (ntpd_opt_strs+1328)
+/** Name string for the debug-level option */
+#define DEBUG_LEVEL_name (ntpd_opt_strs+1340)
+/** Compiled in flag settings for the debug-level option */
+#define DEBUG_LEVEL_FLAGS (OPTST_DISABLED)
+
+/**
+ * set-debug-level option description:
+ */
+/** Descriptive text for the set-debug-level option */
+#define SET_DEBUG_LEVEL_DESC (ntpd_opt_strs+1352)
+/** Upper-cased name for the set-debug-level option */
+#define SET_DEBUG_LEVEL_NAME (ntpd_opt_strs+1382)
+/** Name string for the set-debug-level option */
+#define SET_DEBUG_LEVEL_name (ntpd_opt_strs+1398)
+/** Compiled in flag settings for the set-debug-level option */
+#define SET_DEBUG_LEVEL_FLAGS (OPTST_DISABLED \
+ | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
-/*
- * Driftfile option description:
+/**
+ * driftfile option description:
*/
-tSCC zDriftfileText[] =
- "frequency drift file name";
-tSCC zDriftfile_NAME[] = "DRIFTFILE";
-tSCC zDriftfile_Name[] = "driftfile";
-#define DRIFTFILE_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the driftfile option */
+#define DRIFTFILE_DESC (ntpd_opt_strs+1414)
+/** Upper-cased name for the driftfile option */
+#define DRIFTFILE_NAME (ntpd_opt_strs+1440)
+/** Name string for the driftfile option */
+#define DRIFTFILE_name (ntpd_opt_strs+1450)
+/** Compiled in flag settings for the driftfile option */
+#define DRIFTFILE_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Panicgate option description:
+/**
+ * panicgate option description:
*/
-tSCC zPanicgateText[] =
- "Allow the first adjustment to be Big";
-tSCC zPanicgate_NAME[] = "PANICGATE";
-tSCC zPanicgate_Name[] = "panicgate";
-#define PANICGATE_FLAGS (OPTST_DISABLED)
-
-/*
- * Jaildir option description:
+/** Descriptive text for the panicgate option */
+#define PANICGATE_DESC (ntpd_opt_strs+1460)
+/** Upper-cased name for the panicgate option */
+#define PANICGATE_NAME (ntpd_opt_strs+1497)
+/** Name string for the panicgate option */
+#define PANICGATE_name (ntpd_opt_strs+1507)
+/** Compiled in flag settings for the panicgate option */
+#define PANICGATE_FLAGS (OPTST_DISABLED)
+
+/**
+ * force_step_once option description:
*/
-tSCC zJaildirText[] =
- "Jail directory";
-tSCC zJaildir_NAME[] = "JAILDIR";
-tSCC zJaildir_Name[] = "jaildir";
-#define JAILDIR_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the force_step_once option */
+#define FORCE_STEP_ONCE_DESC (ntpd_opt_strs+1517)
+/** Upper-cased name for the force_step_once option */
+#define FORCE_STEP_ONCE_NAME (ntpd_opt_strs+1553)
+/** Name string for the force_step_once option */
+#define FORCE_STEP_ONCE_name (ntpd_opt_strs+1569)
+/** Compiled in flag settings for the force_step_once option */
+#define FORCE_STEP_ONCE_FLAGS (OPTST_DISABLED)
+
+/**
+ * jaildir option description:
+ */
+#ifdef HAVE_DROPROOT
+/** Descriptive text for the jaildir option */
+#define JAILDIR_DESC (ntpd_opt_strs+1585)
+/** Upper-cased name for the jaildir option */
+#define JAILDIR_NAME (ntpd_opt_strs+1600)
+/** Name string for the jaildir option */
+#define JAILDIR_name (ntpd_opt_strs+1608)
+/** Compiled in flag settings for the jaildir option */
+#define JAILDIR_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Interface option description:
+#else /* disable jaildir */
+#define JAILDIR_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define JAILDIR_NAME NULL
+/** Descriptive text for the jaildir option */
+#define JAILDIR_DESC (ntpd_opt_strs+1616)
+#define JAILDIR_name (ntpd_opt_strs+1608)
+#endif /* HAVE_DROPROOT */
+
+/**
+ * interface option description:
*/
-tSCC zInterfaceText[] =
- "Listen on interface";
-tSCC zInterface_NAME[] = "INTERFACE";
-tSCC zInterface_Name[] = "interface";
-#define INTERFACE_FLAGS (OPTST_DISABLED | OPTST_STACKED \
+/** Descriptive text for the interface option */
+#define INTERFACE_DESC (ntpd_opt_strs+1695)
+/** Upper-cased name for the interface option */
+#define INTERFACE_NAME (ntpd_opt_strs+1734)
+/** Name string for the interface option */
+#define INTERFACE_name (ntpd_opt_strs+1744)
+/** Compiled in flag settings for the interface option */
+#define INTERFACE_FLAGS (OPTST_DISABLED | OPTST_STACKED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Keyfile option description:
+/**
+ * keyfile option description:
*/
-tSCC zKeyfileText[] =
- "path to symmetric keys";
-tSCC zKeyfile_NAME[] = "KEYFILE";
-tSCC zKeyfile_Name[] = "keyfile";
-#define KEYFILE_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the keyfile option */
+#define KEYFILE_DESC (ntpd_opt_strs+1754)
+/** Upper-cased name for the keyfile option */
+#define KEYFILE_NAME (ntpd_opt_strs+1777)
+/** Name string for the keyfile option */
+#define KEYFILE_name (ntpd_opt_strs+1785)
+/** Compiled in flag settings for the keyfile option */
+#define KEYFILE_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Logfile option description:
+/**
+ * logfile option description:
*/
-tSCC zLogfileText[] =
- "path to the log file";
-tSCC zLogfile_NAME[] = "LOGFILE";
-tSCC zLogfile_Name[] = "logfile";
-#define LOGFILE_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the logfile option */
+#define LOGFILE_DESC (ntpd_opt_strs+1793)
+/** Upper-cased name for the logfile option */
+#define LOGFILE_NAME (ntpd_opt_strs+1814)
+/** Name string for the logfile option */
+#define LOGFILE_name (ntpd_opt_strs+1822)
+/** Compiled in flag settings for the logfile option */
+#define LOGFILE_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Novirtualips option description:
+/**
+ * novirtualips option description:
*/
-tSCC zNovirtualipsText[] =
- "Do not listen to virtual IPs";
-tSCC zNovirtualips_NAME[] = "NOVIRTUALIPS";
-tSCC zNovirtualips_Name[] = "novirtualips";
-#define NOVIRTUALIPS_FLAGS (OPTST_DISABLED)
-
-/*
- * Modifymmtimer option description:
+/** Descriptive text for the novirtualips option */
+#define NOVIRTUALIPS_DESC (ntpd_opt_strs+1830)
+/** Upper-cased name for the novirtualips option */
+#define NOVIRTUALIPS_NAME (ntpd_opt_strs+1866)
+/** Name string for the novirtualips option */
+#define NOVIRTUALIPS_name (ntpd_opt_strs+1879)
+/** Compiled in flag settings for the novirtualips option */
+#define NOVIRTUALIPS_FLAGS (OPTST_DISABLED)
+
+/**
+ * modifymmtimer option description:
*/
#ifdef SYS_WINNT
-tSCC zModifymmtimerText[] =
- "Modify Multimedia Timer (Windows only)";
-tSCC zModifymmtimer_NAME[] = "MODIFYMMTIMER";
-tSCC zModifymmtimer_Name[] = "modifymmtimer";
-#define MODIFYMMTIMER_FLAGS (OPTST_DISABLED)
-
-#else /* disable Modifymmtimer */
-#define VALUE_OPT_MODIFYMMTIMER NO_EQUIVALENT
-#define MODIFYMMTIMER_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
-#define zModifymmtimerText NULL
-#define zModifymmtimer_NAME NULL
-#define zModifymmtimer_Name NULL
+/** Descriptive text for the modifymmtimer option */
+#define MODIFYMMTIMER_DESC (ntpd_opt_strs+1892)
+/** Upper-cased name for the modifymmtimer option */
+#define MODIFYMMTIMER_NAME (ntpd_opt_strs+1931)
+/** Name string for the modifymmtimer option */
+#define MODIFYMMTIMER_name (ntpd_opt_strs+1945)
+/** Compiled in flag settings for the modifymmtimer option */
+#define MODIFYMMTIMER_FLAGS (OPTST_DISABLED)
+
+#else /* disable modifymmtimer */
+#define MODIFYMMTIMER_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define MODIFYMMTIMER_NAME NULL
+#define MODIFYMMTIMER_DESC NULL
+#define MODIFYMMTIMER_name NULL
#endif /* SYS_WINNT */
-/*
- * Nofork option description:
+/**
+ * nofork option description with
+ * "Must also have options" and "Incompatible options":
*/
-tSCC zNoforkText[] =
- "Do not fork";
-tSCC zNofork_NAME[] = "NOFORK";
-tSCC zNofork_Name[] = "nofork";
-#define NOFORK_FLAGS (OPTST_DISABLED)
-
-/*
- * Nice option description:
+/** Descriptive text for the nofork option */
+#define NOFORK_DESC (ntpd_opt_strs+1959)
+/** Upper-cased name for the nofork option */
+#define NOFORK_NAME (ntpd_opt_strs+1971)
+/** Name string for the nofork option */
+#define NOFORK_name (ntpd_opt_strs+1978)
+/** Other options that appear in conjunction with the nofork option */
+static int const aNoforkCantList[] = {
+ INDEX_OPT_WAIT_SYNC, NO_EQUIVALENT };
+/** Compiled in flag settings for the nofork option */
+#define NOFORK_FLAGS (OPTST_DISABLED)
+
+/**
+ * nice option description:
*/
-tSCC zNiceText[] =
- "Run at high priority";
-tSCC zNice_NAME[] = "NICE";
-tSCC zNice_Name[] = "nice";
-#define NICE_FLAGS (OPTST_DISABLED)
-
-/*
- * Pidfile option description:
+/** Descriptive text for the nice option */
+#define NICE_DESC (ntpd_opt_strs+1985)
+/** Upper-cased name for the nice option */
+#define NICE_NAME (ntpd_opt_strs+2006)
+/** Name string for the nice option */
+#define NICE_name (ntpd_opt_strs+2011)
+/** Compiled in flag settings for the nice option */
+#define NICE_FLAGS (OPTST_DISABLED)
+
+/**
+ * pidfile option description:
*/
-tSCC zPidfileText[] =
- "path to the PID file";
-tSCC zPidfile_NAME[] = "PIDFILE";
-tSCC zPidfile_Name[] = "pidfile";
-#define PIDFILE_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the pidfile option */
+#define PIDFILE_DESC (ntpd_opt_strs+2016)
+/** Upper-cased name for the pidfile option */
+#define PIDFILE_NAME (ntpd_opt_strs+2037)
+/** Name string for the pidfile option */
+#define PIDFILE_name (ntpd_opt_strs+2045)
+/** Compiled in flag settings for the pidfile option */
+#define PIDFILE_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Priority option description:
+/**
+ * priority option description:
*/
-tSCC zPriorityText[] =
- "Process priority";
-tSCC zPriority_NAME[] = "PRIORITY";
-tSCC zPriority_Name[] = "priority";
-#define PRIORITY_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the priority option */
+#define PRIORITY_DESC (ntpd_opt_strs+2053)
+/** Upper-cased name for the priority option */
+#define PRIORITY_NAME (ntpd_opt_strs+2070)
+/** Name string for the priority option */
+#define PRIORITY_name (ntpd_opt_strs+2079)
+/** Compiled in flag settings for the priority option */
+#define PRIORITY_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
-/*
- * Quit option description:
+/**
+ * quit option description with
+ * "Must also have options" and "Incompatible options":
*/
-tSCC zQuitText[] =
- "Set the time and quit";
-tSCC zQuit_NAME[] = "QUIT";
-tSCC zQuit_Name[] = "quit";
-#define QUIT_FLAGS (OPTST_DISABLED)
-
-/*
- * Propagationdelay option description:
+/** Descriptive text for the quit option */
+#define QUIT_DESC (ntpd_opt_strs+2088)
+/** Upper-cased name for the quit option */
+#define QUIT_NAME (ntpd_opt_strs+2110)
+/** Name string for the quit option */
+#define QUIT_name (ntpd_opt_strs+2115)
+/** Other options that appear in conjunction with the quit option */
+static int const aQuitCantList[] = {
+ INDEX_OPT_SAVECONFIGQUIT,
+ INDEX_OPT_WAIT_SYNC, NO_EQUIVALENT };
+/** Compiled in flag settings for the quit option */
+#define QUIT_FLAGS (OPTST_DISABLED)
+
+/**
+ * propagationdelay option description:
*/
-tSCC zPropagationdelayText[] =
- "Broadcast/propagation delay";
-tSCC zPropagationdelay_NAME[] = "PROPAGATIONDELAY";
-tSCC zPropagationdelay_Name[] = "propagationdelay";
-#define PROPAGATIONDELAY_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the propagationdelay option */
+#define PROPAGATIONDELAY_DESC (ntpd_opt_strs+2120)
+/** Upper-cased name for the propagationdelay option */
+#define PROPAGATIONDELAY_NAME (ntpd_opt_strs+2148)
+/** Name string for the propagationdelay option */
+#define PROPAGATIONDELAY_name (ntpd_opt_strs+2165)
+/** Compiled in flag settings for the propagationdelay option */
+#define PROPAGATIONDELAY_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Updateinterval option description:
+/**
+ * saveconfigquit option description with
+ * "Must also have options" and "Incompatible options":
*/
-tSCC zUpdateintervalText[] =
- "interval in seconds between scans for new or dropped interfaces";
-tSCC zUpdateinterval_NAME[] = "UPDATEINTERVAL";
-tSCC zUpdateinterval_Name[] = "updateinterval";
-#define UPDATEINTERVAL_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
+#ifdef SAVECONFIG
+/** Descriptive text for the saveconfigquit option */
+#define SAVECONFIGQUIT_DESC (ntpd_opt_strs+2182)
+/** Upper-cased name for the saveconfigquit option */
+#define SAVECONFIGQUIT_NAME (ntpd_opt_strs+2217)
+/** Name string for the saveconfigquit option */
+#define SAVECONFIGQUIT_name (ntpd_opt_strs+2232)
+/** Other options that appear in conjunction with the saveconfigquit option */
+static int const aSaveconfigquitCantList[] = {
+ INDEX_OPT_QUIT,
+ INDEX_OPT_WAIT_SYNC, NO_EQUIVALENT };
+/** Compiled in flag settings for the saveconfigquit option */
+#define SAVECONFIGQUIT_FLAGS (OPTST_DISABLED \
+ | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Statsdir option description:
+#else /* disable saveconfigquit */
+#define SAVECONFIGQUIT_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define aSaveconfigquitCantList NULL
+#define SAVECONFIGQUIT_NAME NULL
+#define SAVECONFIGQUIT_DESC NULL
+#define SAVECONFIGQUIT_name NULL
+#endif /* SAVECONFIG */
+
+/**
+ * statsdir option description:
*/
-tSCC zStatsdirText[] =
- "Statistics file location";
-tSCC zStatsdir_NAME[] = "STATSDIR";
-tSCC zStatsdir_Name[] = "statsdir";
-#define STATSDIR_FLAGS (OPTST_DISABLED \
+/** Descriptive text for the statsdir option */
+#define STATSDIR_DESC (ntpd_opt_strs+2247)
+/** Upper-cased name for the statsdir option */
+#define STATSDIR_NAME (ntpd_opt_strs+2272)
+/** Name string for the statsdir option */
+#define STATSDIR_name (ntpd_opt_strs+2281)
+/** Compiled in flag settings for the statsdir option */
+#define STATSDIR_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Trustedkey option description:
+/**
+ * trustedkey option description:
*/
-tSCC zTrustedkeyText[] =
- "Trusted key number";
-tSCC zTrustedkey_NAME[] = "TRUSTEDKEY";
-tSCC zTrustedkey_Name[] = "trustedkey";
-#define TRUSTEDKEY_FLAGS (OPTST_DISABLED | OPTST_STACKED \
+/** Descriptive text for the trustedkey option */
+#define TRUSTEDKEY_DESC (ntpd_opt_strs+2290)
+/** Upper-cased name for the trustedkey option */
+#define TRUSTEDKEY_NAME (ntpd_opt_strs+2309)
+/** Name string for the trustedkey option */
+#define TRUSTEDKEY_name (ntpd_opt_strs+2320)
+/** Compiled in flag settings for the trustedkey option */
+#define TRUSTEDKEY_FLAGS (OPTST_DISABLED | OPTST_STACKED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * User option description:
+/**
+ * user option description:
*/
-tSCC zUserText[] =
- "Run as userid (or userid:groupid)";
-tSCC zUser_NAME[] = "USER";
-tSCC zUser_Name[] = "user";
-#define USER_FLAGS (OPTST_DISABLED \
+#ifdef HAVE_DROPROOT
+/** Descriptive text for the user option */
+#define USER_DESC (ntpd_opt_strs+2331)
+/** Upper-cased name for the user option */
+#define USER_NAME (ntpd_opt_strs+2365)
+/** Name string for the user option */
+#define USER_name (ntpd_opt_strs+2370)
+/** Compiled in flag settings for the user option */
+#define USER_FLAGS (OPTST_DISABLED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Var option description:
+#else /* disable user */
+#define USER_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define USER_NAME NULL
+/** Descriptive text for the user option */
+#define USER_DESC (ntpd_opt_strs+1616)
+#define USER_name (ntpd_opt_strs+2370)
+#endif /* HAVE_DROPROOT */
+
+/**
+ * updateinterval option description:
*/
-tSCC zVarText[] =
- "make ARG an ntp variable (RW)";
-tSCC zVar_NAME[] = "VAR";
-tSCC zVar_Name[] = "var";
-#define VAR_FLAGS (OPTST_DISABLED | OPTST_STACKED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+/** Descriptive text for the updateinterval option */
+#define UPDATEINTERVAL_DESC (ntpd_opt_strs+2375)
+/** Upper-cased name for the updateinterval option */
+#define UPDATEINTERVAL_NAME (ntpd_opt_strs+2439)
+/** Name string for the updateinterval option */
+#define UPDATEINTERVAL_name (ntpd_opt_strs+2454)
+/** Compiled in flag settings for the updateinterval option */
+#define UPDATEINTERVAL_FLAGS (OPTST_DISABLED \
+ | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
-/*
- * Dvar option description:
+/**
+ * var option description:
*/
-tSCC zDvarText[] =
- "make ARG an ntp variable (RW|DEF)";
-tSCC zDvar_NAME[] = "DVAR";
-tSCC zDvar_Name[] = "dvar";
-#define DVAR_FLAGS (OPTST_DISABLED | OPTST_STACKED \
+/** Descriptive text for the var option */
+#define VAR_DESC (ntpd_opt_strs+2469)
+/** Upper-cased name for the var option */
+#define VAR_NAME (ntpd_opt_strs+2499)
+/** Name string for the var option */
+#define VAR_name (ntpd_opt_strs+2503)
+/** Compiled in flag settings for the var option */
+#define VAR_FLAGS (OPTST_DISABLED | OPTST_STACKED \
| OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Slew option description:
+/**
+ * dvar option description:
*/
-tSCC zSlewText[] =
- "Slew up to 600 seconds";
-tSCC zSlew_NAME[] = "SLEW";
-tSCC zSlew_Name[] = "slew";
-#define SLEW_FLAGS (OPTST_DISABLED)
+/** Descriptive text for the dvar option */
+#define DVAR_DESC (ntpd_opt_strs+2507)
+/** Upper-cased name for the dvar option */
+#define DVAR_NAME (ntpd_opt_strs+2541)
+/** Name string for the dvar option */
+#define DVAR_name (ntpd_opt_strs+2546)
+/** Compiled in flag settings for the dvar option */
+#define DVAR_FLAGS (OPTST_DISABLED | OPTST_STACKED \
+ | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-/*
- * Help/More_Help/Version option descriptions:
+/**
+ * wait-sync option description with
+ * "Must also have options" and "Incompatible options":
*/
-tSCC zHelpText[] = "Display usage information and exit";
-tSCC zHelp_Name[] = "help";
+#ifdef HAVE_WORKING_FORK
+/** Descriptive text for the wait-sync option */
+#define WAIT_SYNC_DESC (ntpd_opt_strs+2551)
+/** Upper-cased name for the wait-sync option */
+#define WAIT_SYNC_NAME (ntpd_opt_strs+2588)
+/** Name string for the wait-sync option */
+#define WAIT_SYNC_name (ntpd_opt_strs+2598)
+/** Other options that appear in conjunction with the wait-sync option */
+static int const aWait_SyncCantList[] = {
+ INDEX_OPT_NOFORK,
+ INDEX_OPT_QUIT,
+ INDEX_OPT_SAVECONFIGQUIT, NO_EQUIVALENT };
+/** Compiled in flag settings for the wait-sync option */
+#define WAIT_SYNC_FLAGS (OPTST_DISABLED \
+ | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
-tSCC zMore_HelpText[] = "Extended usage information passed thru pager";
-tSCC zMore_Help_Name[] = "more-help";
+#else /* disable wait-sync */
+#define WAIT_SYNC_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define aWait_SyncCantList NULL
+#define WAIT_SYNC_NAME NULL
+#define WAIT_SYNC_DESC NULL
+#define WAIT_SYNC_name NULL
+#endif /* HAVE_WORKING_FORK */
-tSCC zVersionText[] = "Output version information and exit";
-tSCC zVersion_Name[] = "version";
-/*
- * Declare option callback procedures
+/**
+ * slew option description:
*/
-#ifdef DEBUG
- static tOptProc doOptSet_Debug_Level;
-#else /* not DEBUG */
-# define doOptSet_Debug_Level NULL
-#endif /* def/not DEBUG */
-#if defined(TEST_NTPD_OPTS)
-/*
- * Under test, omit argument processing, or call optionStackArg,
- * if multiple copies are allowed.
+/** Descriptive text for the slew option */
+#define SLEW_DESC (ntpd_opt_strs+2608)
+/** Upper-cased name for the slew option */
+#define SLEW_NAME (ntpd_opt_strs+2631)
+/** Name string for the slew option */
+#define SLEW_name (ntpd_opt_strs+2636)
+/** Compiled in flag settings for the slew option */
+#define SLEW_FLAGS (OPTST_DISABLED)
+
+/**
+ * usepcc option description:
*/
-extern tOptProc
- optionNumericVal, optionPagedUsage, optionStackArg,
- optionVersionStderr;
-static tOptProc
- doUsageOpt;
+#ifdef SYS_WINNT
+/** Descriptive text for the usepcc option */
+#define USEPCC_DESC (ntpd_opt_strs+2641)
+/** Upper-cased name for the usepcc option */
+#define USEPCC_NAME (ntpd_opt_strs+2678)
+/** Name string for the usepcc option */
+#define USEPCC_name (ntpd_opt_strs+2685)
+/** Compiled in flag settings for the usepcc option */
+#define USEPCC_FLAGS (OPTST_DISABLED)
+
+#else /* disable usepcc */
+#define USEPCC_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define USEPCC_NAME NULL
+#define USEPCC_DESC NULL
+#define USEPCC_name NULL
+#endif /* SYS_WINNT */
-/*
- * #define map the "normal" callout procs to the test ones...
+/**
+ * pccfreq option description:
*/
-#define SET_DEBUG_LEVEL_OPT_PROC optionStackArg
+#ifdef SYS_WINNT
+/** Descriptive text for the pccfreq option */
+#define PCCFREQ_DESC (ntpd_opt_strs+2692)
+/** Upper-cased name for the pccfreq option */
+#define PCCFREQ_NAME (ntpd_opt_strs+2735)
+/** Name string for the pccfreq option */
+#define PCCFREQ_name (ntpd_opt_strs+2743)
+/** Compiled in flag settings for the pccfreq option */
+#define PCCFREQ_FLAGS (OPTST_DISABLED \
+ | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+#else /* disable pccfreq */
+#define PCCFREQ_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define PCCFREQ_NAME NULL
+#define PCCFREQ_DESC NULL
+#define PCCFREQ_name NULL
+#endif /* SYS_WINNT */
-#else /* NOT defined TEST_NTPD_OPTS */
-/*
- * When not under test, there are different procs to use
+/**
+ * mdns option description:
*/
-extern tOptProc
- optionNumericVal, optionPagedUsage, optionPrintVersion, optionStackArg;
-static tOptProc
- doUsageOpt;
+#ifdef HAVE_DNSREGISTRATION
+/** Descriptive text for the mdns option */
+#define MDNS_DESC (ntpd_opt_strs+2751)
+/** Upper-cased name for the mdns option */
+#define MDNS_NAME (ntpd_opt_strs+2786)
+/** Name string for the mdns option */
+#define MDNS_name (ntpd_opt_strs+2791)
+/** Compiled in flag settings for the mdns option */
+#define MDNS_FLAGS (OPTST_DISABLED)
+
+#else /* disable mdns */
+#define MDNS_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#define MDNS_NAME NULL
+#define MDNS_DESC NULL
+#define MDNS_name NULL
+#endif /* HAVE_DNSREGISTRATION */
/*
- * #define map the "normal" callout procs
+ * Help/More_Help/Version option descriptions:
*/
-#define SET_DEBUG_LEVEL_OPT_PROC doOptSet_Debug_Level
-
-#define SET_DEBUG_LEVEL_OPT_PROC doOptSet_Debug_Level
-#endif /* defined(TEST_NTPD_OPTS) */
-#ifdef TEST_NTPD_OPTS
-# define DOVERPROC optionVersionStderr
+#define HELP_DESC (ntpd_opt_strs+2796)
+#define HELP_name (ntpd_opt_strs+2840)
+#ifdef HAVE_WORKING_FORK
+#define MORE_HELP_DESC (ntpd_opt_strs+2845)
+#define MORE_HELP_name (ntpd_opt_strs+2890)
+#define MORE_HELP_FLAGS (OPTST_IMM | OPTST_NO_INIT)
#else
-# define DOVERPROC optionPrintVersion
-#endif /* TEST_NTPD_OPTS */
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Define the Ntpd Option Descriptions.
+#define MORE_HELP_DESC HELP_DESC
+#define MORE_HELP_name HELP_name
+#define MORE_HELP_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#endif
+#ifdef NO_OPTIONAL_OPT_ARGS
+# define VER_FLAGS (OPTST_IMM | OPTST_NO_INIT)
+#else
+# define VER_FLAGS (OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \
+ OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT)
+#endif
+#define VER_DESC (ntpd_opt_strs+2900)
+#define VER_name (ntpd_opt_strs+2936)
+/**
+ * Declare option callback procedures
*/
-static tOptDesc optDesc[ OPTION_CT ] = {
+extern tOptProc
+ ntpOptionPrintVersion, optionBooleanVal, optionNestedVal,
+ optionNumericVal, optionPagedUsage, optionResetOpt,
+ optionStackArg, optionTimeDate, optionTimeVal,
+ optionUnstackArg, optionVendorOption;
+static tOptProc
+ doOptDebug_Level, doUsageOpt;
+#define VER_PROC ntpOptionPrintVersion
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * Define the ntpd Option Descriptions.
+ * This is an array of OPTION_CT entries, one for each
+ * option that the ntpd program responds to.
+ */
+static tOptDesc optDesc[OPTION_CT] = {
{ /* entry idx, value */ 0, VALUE_OPT_IPV4,
- /* equiv idx, value */ NO_EQUIVALENT, 0,
+ /* equiv idx, value */ 0, VALUE_OPT_IPV4,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ IPV4_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --ipv4 */
/* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
+ /* must/cannot opts */ NULL, aIpv4CantList,
/* option proc */ NULL,
- /* desc, NAME, name */ zIpv4Text, zIpv4_NAME, zIpv4_Name,
+ /* desc, NAME, name */ IPV4_DESC, IPV4_NAME, IPV4_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 1, VALUE_OPT_IPV6,
- /* equiv idx, value */ NOLIMIT, NOLIMIT,
- /* equivalenced to */ INDEX_OPT_IPV4,
+ /* equiv idx, value */ 1, VALUE_OPT_IPV6,
+ /* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ IPV6_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --ipv6 */
/* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
+ /* must/cannot opts */ NULL, aIpv6CantList,
/* option proc */ NULL,
- /* desc, NAME, name */ zIpv6Text, zIpv6_NAME, zIpv6_Name,
+ /* desc, NAME, name */ IPV6_DESC, IPV6_NAME, IPV6_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 2, VALUE_OPT_AUTHREQ,
@@ -463,11 +825,11 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ AUTHREQ_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --authreq */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, aAuthreqCantList,
/* option proc */ NULL,
- /* desc, NAME, name */ zAuthreqText, zAuthreq_NAME, zAuthreq_Name,
+ /* desc, NAME, name */ AUTHREQ_DESC, AUTHREQ_NAME, AUTHREQ_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 3, VALUE_OPT_AUTHNOREQ,
@@ -475,11 +837,11 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ AUTHNOREQ_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --authnoreq */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, aAuthnoreqCantList,
/* option proc */ NULL,
- /* desc, NAME, name */ zAuthnoreqText, zAuthnoreq_NAME, zAuthnoreq_Name,
+ /* desc, NAME, name */ AUTHNOREQ_DESC, AUTHNOREQ_NAME, AUTHNOREQ_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 4, VALUE_OPT_BCASTSYNC,
@@ -487,11 +849,11 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ BCASTSYNC_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --bcastsync */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zBcastsyncText, zBcastsync_NAME, zBcastsync_Name,
+ /* desc, NAME, name */ BCASTSYNC_DESC, BCASTSYNC_NAME, BCASTSYNC_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 5, VALUE_OPT_CONFIGFILE,
@@ -499,11 +861,11 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ CONFIGFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --configfile */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zConfigfileText, zConfigfile_NAME, zConfigfile_Name,
+ /* desc, NAME, name */ CONFIGFILE_DESC, CONFIGFILE_NAME, CONFIGFILE_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 6, VALUE_OPT_DEBUG_LEVEL,
@@ -511,11 +873,11 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ DEBUG_LEVEL_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --debug-level */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zDebug_LevelText, zDebug_Level_NAME, zDebug_Level_Name,
+ /* option proc */ doOptDebug_Level,
+ /* desc, NAME, name */ DEBUG_LEVEL_DESC, DEBUG_LEVEL_NAME, DEBUG_LEVEL_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 7, VALUE_OPT_SET_DEBUG_LEVEL,
@@ -523,11 +885,11 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ SET_DEBUG_LEVEL_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --set-debug-level */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
- /* option proc */ SET_DEBUG_LEVEL_OPT_PROC,
- /* desc, NAME, name */ zSet_Debug_LevelText, zSet_Debug_Level_NAME, zSet_Debug_Level_Name,
+ /* option proc */ optionNumericVal,
+ /* desc, NAME, name */ SET_DEBUG_LEVEL_DESC, SET_DEBUG_LEVEL_NAME, SET_DEBUG_LEVEL_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 8, VALUE_OPT_DRIFTFILE,
@@ -535,316 +897,383 @@ static tOptDesc optDesc[ OPTION_CT ] = {
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ DRIFTFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --driftfile */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zDriftfileText, zDriftfile_NAME, zDriftfile_Name,
+ /* desc, NAME, name */ DRIFTFILE_DESC, DRIFTFILE_NAME, DRIFTFILE_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ 9, VALUE_OPT_PANICGATE,
/* equiv idx, value */ 9, VALUE_OPT_PANICGATE,
/* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
+ /* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ PANICGATE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --panicgate */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zPanicgateText, zPanicgate_NAME, zPanicgate_Name,
+ /* desc, NAME, name */ PANICGATE_DESC, PANICGATE_NAME, PANICGATE_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 10, VALUE_OPT_JAILDIR,
- /* equiv idx, value */ 10, VALUE_OPT_JAILDIR,
+ { /* entry idx, value */ 10, VALUE_OPT_FORCE_STEP_ONCE,
+ /* equiv idx, value */ 10, VALUE_OPT_FORCE_STEP_ONCE,
+ /* equivalenced to */ NO_EQUIVALENT,
+ /* min, max, act ct */ 0, 1, 0,
+ /* opt state flags */ FORCE_STEP_ONCE_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --force_step_once */
+ /* arg list/cookie */ NULL,
+ /* must/cannot opts */ NULL, NULL,
+ /* option proc */ NULL,
+ /* desc, NAME, name */ FORCE_STEP_ONCE_DESC, FORCE_STEP_ONCE_NAME, FORCE_STEP_ONCE_name,
+ /* disablement strs */ NULL, NULL },
+
+ { /* entry idx, value */ 11, VALUE_OPT_JAILDIR,
+ /* equiv idx, value */ 11, VALUE_OPT_JAILDIR,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ JAILDIR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --jaildir */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zJaildirText, zJaildir_NAME, zJaildir_Name,
+ /* desc, NAME, name */ JAILDIR_DESC, JAILDIR_NAME, JAILDIR_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 11, VALUE_OPT_INTERFACE,
- /* equiv idx, value */ 11, VALUE_OPT_INTERFACE,
+ { /* entry idx, value */ 12, VALUE_OPT_INTERFACE,
+ /* equiv idx, value */ 12, VALUE_OPT_INTERFACE,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ INTERFACE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --interface */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ optionStackArg,
- /* desc, NAME, name */ zInterfaceText, zInterface_NAME, zInterface_Name,
+ /* desc, NAME, name */ INTERFACE_DESC, INTERFACE_NAME, INTERFACE_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 12, VALUE_OPT_KEYFILE,
- /* equiv idx, value */ 12, VALUE_OPT_KEYFILE,
+ { /* entry idx, value */ 13, VALUE_OPT_KEYFILE,
+ /* equiv idx, value */ 13, VALUE_OPT_KEYFILE,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ KEYFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --keyfile */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zKeyfileText, zKeyfile_NAME, zKeyfile_Name,
+ /* desc, NAME, name */ KEYFILE_DESC, KEYFILE_NAME, KEYFILE_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 13, VALUE_OPT_LOGFILE,
- /* equiv idx, value */ 13, VALUE_OPT_LOGFILE,
+ { /* entry idx, value */ 14, VALUE_OPT_LOGFILE,
+ /* equiv idx, value */ 14, VALUE_OPT_LOGFILE,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ LOGFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --logfile */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zLogfileText, zLogfile_NAME, zLogfile_Name,
+ /* desc, NAME, name */ LOGFILE_DESC, LOGFILE_NAME, LOGFILE_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 14, VALUE_OPT_NOVIRTUALIPS,
- /* equiv idx, value */ 14, VALUE_OPT_NOVIRTUALIPS,
+ { /* entry idx, value */ 15, VALUE_OPT_NOVIRTUALIPS,
+ /* equiv idx, value */ 15, VALUE_OPT_NOVIRTUALIPS,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ NOVIRTUALIPS_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --novirtualips */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zNovirtualipsText, zNovirtualips_NAME, zNovirtualips_Name,
+ /* desc, NAME, name */ NOVIRTUALIPS_DESC, NOVIRTUALIPS_NAME, NOVIRTUALIPS_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 15, VALUE_OPT_MODIFYMMTIMER,
- /* equiv idx, value */ 15, VALUE_OPT_MODIFYMMTIMER,
+ { /* entry idx, value */ 16, VALUE_OPT_MODIFYMMTIMER,
+ /* equiv idx, value */ 16, VALUE_OPT_MODIFYMMTIMER,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ MODIFYMMTIMER_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --modifymmtimer */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zModifymmtimerText, zModifymmtimer_NAME, zModifymmtimer_Name,
+ /* desc, NAME, name */ MODIFYMMTIMER_DESC, MODIFYMMTIMER_NAME, MODIFYMMTIMER_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 16, VALUE_OPT_NOFORK,
- /* equiv idx, value */ 16, VALUE_OPT_NOFORK,
+ { /* entry idx, value */ 17, VALUE_OPT_NOFORK,
+ /* equiv idx, value */ 17, VALUE_OPT_NOFORK,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ NOFORK_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --nofork */
/* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
+ /* must/cannot opts */ NULL, aNoforkCantList,
/* option proc */ NULL,
- /* desc, NAME, name */ zNoforkText, zNofork_NAME, zNofork_Name,
+ /* desc, NAME, name */ NOFORK_DESC, NOFORK_NAME, NOFORK_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 17, VALUE_OPT_NICE,
- /* equiv idx, value */ 17, VALUE_OPT_NICE,
+ { /* entry idx, value */ 18, VALUE_OPT_NICE,
+ /* equiv idx, value */ 18, VALUE_OPT_NICE,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ NICE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --nice */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zNiceText, zNice_NAME, zNice_Name,
+ /* desc, NAME, name */ NICE_DESC, NICE_NAME, NICE_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 18, VALUE_OPT_PIDFILE,
- /* equiv idx, value */ 18, VALUE_OPT_PIDFILE,
+ { /* entry idx, value */ 19, VALUE_OPT_PIDFILE,
+ /* equiv idx, value */ 19, VALUE_OPT_PIDFILE,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ PIDFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --pidfile */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zPidfileText, zPidfile_NAME, zPidfile_Name,
+ /* desc, NAME, name */ PIDFILE_DESC, PIDFILE_NAME, PIDFILE_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 19, VALUE_OPT_PRIORITY,
- /* equiv idx, value */ 19, VALUE_OPT_PRIORITY,
+ { /* entry idx, value */ 20, VALUE_OPT_PRIORITY,
+ /* equiv idx, value */ 20, VALUE_OPT_PRIORITY,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ PRIORITY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --priority */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ optionNumericVal,
- /* desc, NAME, name */ zPriorityText, zPriority_NAME, zPriority_Name,
+ /* desc, NAME, name */ PRIORITY_DESC, PRIORITY_NAME, PRIORITY_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 20, VALUE_OPT_QUIT,
- /* equiv idx, value */ 20, VALUE_OPT_QUIT,
+ { /* entry idx, value */ 21, VALUE_OPT_QUIT,
+ /* equiv idx, value */ 21, VALUE_OPT_QUIT,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ QUIT_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --quit */
/* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
+ /* must/cannot opts */ NULL, aQuitCantList,
/* option proc */ NULL,
- /* desc, NAME, name */ zQuitText, zQuit_NAME, zQuit_Name,
+ /* desc, NAME, name */ QUIT_DESC, QUIT_NAME, QUIT_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 21, VALUE_OPT_PROPAGATIONDELAY,
- /* equiv idx, value */ 21, VALUE_OPT_PROPAGATIONDELAY,
+ { /* entry idx, value */ 22, VALUE_OPT_PROPAGATIONDELAY,
+ /* equiv idx, value */ 22, VALUE_OPT_PROPAGATIONDELAY,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ PROPAGATIONDELAY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --propagationdelay */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zPropagationdelayText, zPropagationdelay_NAME, zPropagationdelay_Name,
+ /* desc, NAME, name */ PROPAGATIONDELAY_DESC, PROPAGATIONDELAY_NAME, PROPAGATIONDELAY_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 22, VALUE_OPT_UPDATEINTERVAL,
- /* equiv idx, value */ 22, VALUE_OPT_UPDATEINTERVAL,
+ { /* entry idx, value */ 23, VALUE_OPT_SAVECONFIGQUIT,
+ /* equiv idx, value */ 23, VALUE_OPT_SAVECONFIGQUIT,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ UPDATEINTERVAL_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* opt state flags */ SAVECONFIGQUIT_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --saveconfigquit */
/* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionNumericVal,
- /* desc, NAME, name */ zUpdateintervalText, zUpdateinterval_NAME, zUpdateinterval_Name,
+ /* must/cannot opts */ NULL, aSaveconfigquitCantList,
+ /* option proc */ NULL,
+ /* desc, NAME, name */ SAVECONFIGQUIT_DESC, SAVECONFIGQUIT_NAME, SAVECONFIGQUIT_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 23, VALUE_OPT_STATSDIR,
- /* equiv idx, value */ 23, VALUE_OPT_STATSDIR,
+ { /* entry idx, value */ 24, VALUE_OPT_STATSDIR,
+ /* equiv idx, value */ 24, VALUE_OPT_STATSDIR,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ STATSDIR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --statsdir */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zStatsdirText, zStatsdir_NAME, zStatsdir_Name,
+ /* desc, NAME, name */ STATSDIR_DESC, STATSDIR_NAME, STATSDIR_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 24, VALUE_OPT_TRUSTEDKEY,
- /* equiv idx, value */ 24, VALUE_OPT_TRUSTEDKEY,
+ { /* entry idx, value */ 25, VALUE_OPT_TRUSTEDKEY,
+ /* equiv idx, value */ 25, VALUE_OPT_TRUSTEDKEY,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ TRUSTEDKEY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --trustedkey */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ optionStackArg,
- /* desc, NAME, name */ zTrustedkeyText, zTrustedkey_NAME, zTrustedkey_Name,
+ /* desc, NAME, name */ TRUSTEDKEY_DESC, TRUSTEDKEY_NAME, TRUSTEDKEY_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 25, VALUE_OPT_USER,
- /* equiv idx, value */ 25, VALUE_OPT_USER,
+ { /* entry idx, value */ 26, VALUE_OPT_USER,
+ /* equiv idx, value */ 26, VALUE_OPT_USER,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ USER_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --user */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zUserText, zUser_NAME, zUser_Name,
+ /* desc, NAME, name */ USER_DESC, USER_NAME, USER_name,
+ /* disablement strs */ NULL, NULL },
+
+ { /* entry idx, value */ 27, VALUE_OPT_UPDATEINTERVAL,
+ /* equiv idx, value */ 27, VALUE_OPT_UPDATEINTERVAL,
+ /* equivalenced to */ NO_EQUIVALENT,
+ /* min, max, act ct */ 0, 1, 0,
+ /* opt state flags */ UPDATEINTERVAL_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --updateinterval */
+ /* arg list/cookie */ NULL,
+ /* must/cannot opts */ NULL, NULL,
+ /* option proc */ optionNumericVal,
+ /* desc, NAME, name */ UPDATEINTERVAL_DESC, UPDATEINTERVAL_NAME, UPDATEINTERVAL_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 26, VALUE_OPT_VAR,
- /* equiv idx, value */ 26, VALUE_OPT_VAR,
+ { /* entry idx, value */ 28, VALUE_OPT_VAR,
+ /* equiv idx, value */ 28, VALUE_OPT_VAR,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ VAR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --var */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ optionStackArg,
- /* desc, NAME, name */ zVarText, zVar_NAME, zVar_Name,
+ /* desc, NAME, name */ VAR_DESC, VAR_NAME, VAR_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 27, VALUE_OPT_DVAR,
- /* equiv idx, value */ 27, VALUE_OPT_DVAR,
+ { /* entry idx, value */ 29, VALUE_OPT_DVAR,
+ /* equiv idx, value */ 29, VALUE_OPT_DVAR,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, NOLIMIT, 0,
/* opt state flags */ DVAR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --dvar */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ optionStackArg,
- /* desc, NAME, name */ zDvarText, zDvar_NAME, zDvar_Name,
+ /* desc, NAME, name */ DVAR_DESC, DVAR_NAME, DVAR_name,
+ /* disablement strs */ NULL, NULL },
+
+ { /* entry idx, value */ 30, VALUE_OPT_WAIT_SYNC,
+ /* equiv idx, value */ 30, VALUE_OPT_WAIT_SYNC,
+ /* equivalenced to */ NO_EQUIVALENT,
+ /* min, max, act ct */ 0, 1, 0,
+ /* opt state flags */ WAIT_SYNC_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --wait-sync */
+ /* arg list/cookie */ NULL,
+ /* must/cannot opts */ NULL, aWait_SyncCantList,
+ /* option proc */ optionNumericVal,
+ /* desc, NAME, name */ WAIT_SYNC_DESC, WAIT_SYNC_NAME, WAIT_SYNC_name,
/* disablement strs */ NULL, NULL },
- { /* entry idx, value */ 28, VALUE_OPT_SLEW,
- /* equiv idx, value */ 28, VALUE_OPT_SLEW,
+ { /* entry idx, value */ 31, VALUE_OPT_SLEW,
+ /* equiv idx, value */ 31, VALUE_OPT_SLEW,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
/* opt state flags */ SLEW_FLAGS, 0,
- /* last opt argumnt */ { NULL },
+ /* last opt argumnt */ { NULL }, /* --slew */
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ NULL,
- /* desc, NAME, name */ zSlewText, zSlew_NAME, zSlew_Name,
+ /* desc, NAME, name */ SLEW_DESC, SLEW_NAME, SLEW_name,
/* disablement strs */ NULL, NULL },
-#ifdef NO_OPTIONAL_OPT_ARGS
-# define VERSION_OPT_FLAGS OPTST_IMM | OPTST_NO_INIT
-#else
-# define VERSION_OPT_FLAGS OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \
- OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT
-#endif
+ { /* entry idx, value */ 32, VALUE_OPT_USEPCC,
+ /* equiv idx, value */ 32, VALUE_OPT_USEPCC,
+ /* equivalenced to */ NO_EQUIVALENT,
+ /* min, max, act ct */ 0, 1, 0,
+ /* opt state flags */ USEPCC_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --usepcc */
+ /* arg list/cookie */ NULL,
+ /* must/cannot opts */ NULL, NULL,
+ /* option proc */ NULL,
+ /* desc, NAME, name */ USEPCC_DESC, USEPCC_NAME, USEPCC_name,
+ /* disablement strs */ NULL, NULL },
+
+ { /* entry idx, value */ 33, VALUE_OPT_PCCFREQ,
+ /* equiv idx, value */ 33, VALUE_OPT_PCCFREQ,
+ /* equivalenced to */ NO_EQUIVALENT,
+ /* min, max, act ct */ 0, 1, 0,
+ /* opt state flags */ PCCFREQ_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --pccfreq */
+ /* arg list/cookie */ NULL,
+ /* must/cannot opts */ NULL, NULL,
+ /* option proc */ NULL,
+ /* desc, NAME, name */ PCCFREQ_DESC, PCCFREQ_NAME, PCCFREQ_name,
+ /* disablement strs */ NULL, NULL },
+
+ { /* entry idx, value */ 34, VALUE_OPT_MDNS,
+ /* equiv idx, value */ 34, VALUE_OPT_MDNS,
+ /* equivalenced to */ NO_EQUIVALENT,
+ /* min, max, act ct */ 0, 1, 0,
+ /* opt state flags */ MDNS_FLAGS, 0,
+ /* last opt argumnt */ { NULL }, /* --mdns */
+ /* arg list/cookie */ NULL,
+ /* must/cannot opts */ NULL, NULL,
+ /* option proc */ NULL,
+ /* desc, NAME, name */ MDNS_DESC, MDNS_NAME, MDNS_name,
+ /* disablement strs */ NULL, NULL },
{ /* entry idx, value */ INDEX_OPT_VERSION, VALUE_OPT_VERSION,
- /* equiv idx value */ NO_EQUIVALENT, 0,
+ /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_VERSION,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ VERSION_OPT_FLAGS, 0,
+ /* opt state flags */ VER_FLAGS, AOUSE_VERSION,
/* last opt argumnt */ { NULL },
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
- /* option proc */ DOVERPROC,
- /* desc, NAME, name */ zVersionText, NULL, zVersion_Name,
+ /* option proc */ VER_PROC,
+ /* desc, NAME, name */ VER_DESC, NULL, VER_name,
/* disablement strs */ NULL, NULL },
-#undef VERSION_OPT_FLAGS
{ /* entry idx, value */ INDEX_OPT_HELP, VALUE_OPT_HELP,
- /* equiv idx value */ NO_EQUIVALENT, 0,
+ /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_HELP,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ OPTST_IMM | OPTST_NO_INIT, 0,
+ /* opt state flags */ OPTST_IMM | OPTST_NO_INIT, AOUSE_HELP,
/* last opt argumnt */ { NULL },
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ doUsageOpt,
- /* desc, NAME, name */ zHelpText, NULL, zHelp_Name,
+ /* desc, NAME, name */ HELP_DESC, NULL, HELP_name,
/* disablement strs */ NULL, NULL },
{ /* entry idx, value */ INDEX_OPT_MORE_HELP, VALUE_OPT_MORE_HELP,
- /* equiv idx value */ NO_EQUIVALENT, 0,
+ /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_MORE_HELP,
/* equivalenced to */ NO_EQUIVALENT,
/* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ OPTST_IMM | OPTST_NO_INIT, 0,
+ /* opt state flags */ MORE_HELP_FLAGS, AOUSE_MORE_HELP,
/* last opt argumnt */ { NULL },
/* arg list/cookie */ NULL,
/* must/cannot opts */ NULL, NULL,
/* option proc */ optionPagedUsage,
- /* desc, NAME, name */ zMore_HelpText, NULL, zMore_Help_Name,
+ /* desc, NAME, name */ MORE_HELP_DESC, NULL, MORE_HELP_name,
/* disablement strs */ NULL, NULL }
};
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Define the Ntpd Option Environment
- */
-tSCC zPROGNAME[] = "NTPD";
-tSCC zUsageTitle[] =
-"ntpd - NTP daemon program - Ver. 4.2.4p8\n\
-USAGE: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n";
-#define zRcName NULL
-#define apzHomeList NULL
-tSCC zBugsAddr[] = "http://bugs.ntp.org, bugs@ntp.org";
-#define zExplain NULL
-tSCC zDetail[] = "\n\n";
-tSCC zFullVersion[] = NTPD_FULL_VERSION;
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/optcode.tpl near line 408 */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** Reference to the upper cased version of ntpd. */
+#define zPROGNAME (ntpd_opt_strs+2944)
+/** Reference to the title line for ntpd usage. */
+#define zUsageTitle (ntpd_opt_strs+2949)
+/** There is no ntpd configuration file. */
+#define zRcName NULL
+/** There are no directories to search for ntpd config files. */
+#define apzHomeList NULL
+/** The ntpd program bug email address. */
+#define zBugsAddr (ntpd_opt_strs+3080)
+/** Clarification/explanation of what ntpd does. */
+#define zExplain (ntpd_opt_strs+3114)
+/** Extra detail explaining what ntpd does. */
+#define zDetail (NULL)
+/** The full version string for ntpd. */
+#define zFullVersion (ntpd_opt_strs+3116)
+/* extracted from optcode.tlib near line 364 */
#if defined(ENABLE_NLS)
# define OPTPROC_BASE OPTPROC_TRANSLATE
@@ -854,6 +1283,90 @@ tSCC zFullVersion[] = NTPD_FULL_VERSION;
# define translate_option_strings NULL
#endif /* ENABLE_NLS */
+#define ntpd_full_usage (NULL)
+#define ntpd_short_usage (NULL)
+
+#endif /* not defined __doxygen__ */
+
+/*
+ * Create the static procedure(s) declared above.
+ */
+/**
+ * The callout function that invokes the optionUsage function.
+ *
+ * @param[in] opts the AutoOpts option description structure
+ * @param[in] od the descriptor for the "help" (usage) option.
+ * @noreturn
+ */
+static void
+doUsageOpt(tOptions * opts, tOptDesc * od)
+{
+ int ex_code;
+ ex_code = NTPD_EXIT_SUCCESS;
+ optionUsage(&ntpdOptions, ex_code);
+ /* NOTREACHED */
+ exit(1);
+ (void)opts;
+ (void)od;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * Code to handle the debug-level option.
+ *
+ * @param[in] pOptions the ntpd options data structure
+ * @param[in,out] pOptDesc the option descriptor for this option.
+ */
+static void
+doOptDebug_Level(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+ /*
+ * Be sure the flag-code[0] handles special values for the options pointer
+ * viz. (poptions <= OPTPROC_EMIT_LIMIT) *and also* the special flag bit
+ * ((poptdesc->fOptState & OPTST_RESET) != 0) telling the option to
+ * reset its state.
+ */
+ /* extracted from debug-opt.def, line 15 */
+OPT_VALUE_SET_DEBUG_LEVEL++;
+ (void)pOptDesc;
+ (void)pOptions;
+}
+/* extracted from optmain.tlib near line 1250 */
+
+/**
+ * The directory containing the data associated with ntpd.
+ */
+#ifndef PKGDATADIR
+# define PKGDATADIR ""
+#endif
+
+/**
+ * Information about the person or institution that packaged ntpd
+ * for the current distribution.
+ */
+#ifndef WITH_PACKAGER
+# define ntpd_packager_info NULL
+#else
+/** Packager information for ntpd. */
+static char const ntpd_packager_info[] =
+ "Packaged by " WITH_PACKAGER
+
+# ifdef WITH_PACKAGER_VERSION
+ " ("WITH_PACKAGER_VERSION")"
+# endif
+
+# ifdef WITH_PACKAGER_BUG_REPORTS
+ "\nReport ntpd bugs to " WITH_PACKAGER_BUG_REPORTS
+# endif
+ "\n";
+#endif
+#ifndef __doxygen__
+
+#endif /* __doxygen__ */
+/**
+ * The option definitions for ntpd. The one structure that
+ * binds them all.
+ */
tOptions ntpdOptions = {
OPTIONS_STRUCT_VERSION,
0, NULL, /* original argc + argv */
@@ -863,158 +1376,608 @@ tOptions ntpdOptions = {
+ OPTPROC_LONGOPT
+ OPTPROC_NO_REQ_OPT
+ OPTPROC_ENVIRON
- + OPTPROC_NO_ARGS ),
+ + OPTPROC_MISUSE ),
0, NULL, /* current option index, current option */
NULL, NULL, zPROGNAME,
- zRcName, zCopyright, zCopyrightNotice,
+ zRcName, zCopyright, zLicenseDescrip,
zFullVersion, apzHomeList, zUsageTitle,
zExplain, zDetail, optDesc,
zBugsAddr, /* address to send bugs to */
NULL, NULL, /* extensions/saved state */
- optionUsage, /* usage procedure */
+ optionUsage, /* usage procedure */
translate_option_strings, /* translation procedure */
/*
* Indexes to special options
*/
- { INDEX_OPT_MORE_HELP,
- 0 /* no option state saving */,
- NO_EQUIVALENT /* index of '-#' option */,
+ { INDEX_OPT_MORE_HELP, /* more-help option index */
+ NO_EQUIVALENT, /* save option index */
+ NO_EQUIVALENT, /* '-#' option index */
NO_EQUIVALENT /* index of default opt */
},
- 32 /* full option count */, 29 /* user option count */
+ 38 /* full option count */, 35 /* user option count */,
+ ntpd_full_usage, ntpd_short_usage,
+ NULL, NULL,
+ PKGDATADIR, ntpd_packager_info
};
-/*
- * Create the static procedure(s) declared above.
- */
-static void
-doUsageOpt(
- tOptions* pOptions,
- tOptDesc* pOptDesc )
-{
- USAGE( EXIT_SUCCESS );
-}
-
-#if ! defined(TEST_NTPD_OPTS)
-
-/* * * * * * *
- *
- * For the set-debug-level option, when DEBUG is #define-d.
- */
-#ifdef DEBUG
-static void
-doOptSet_Debug_Level(
- tOptions* pOptions,
- tOptDesc* pOptDesc )
-{
- /* extracted from ../include/debug-opt.def, line 29 */
-DESC(DEBUG_LEVEL).optOccCt = atoi( pOptDesc->pzLastArg );
-}
-#endif /* defined DEBUG */
-
-#endif /* defined(TEST_NTPD_OPTS) */
-
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/optmain.tpl near line 92 */
-
-#if defined(TEST_NTPD_OPTS) /* TEST MAIN PROCEDURE: */
-
-int
-main( int argc, char** argv )
-{
- int res = EXIT_SUCCESS;
- (void)optionProcess( &ntpdOptions, argc, argv );
- {
- void optionPutShell( tOptions* );
- optionPutShell( &ntpdOptions );
- }
- return res;
-}
-#endif /* defined TEST_NTPD_OPTS */
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/optcode.tpl near line 514 */
-
#if ENABLE_NLS
+/**
+ * This code is designed to translate translatable option text for the
+ * ntpd program. These translations happen upon entry
+ * to optionProcess().
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_DCGETTEXT
+# include <gettext.h>
+#endif
#include <autoopts/usage-txt.h>
-static char* AO_gettext( char const* pz );
-static void coerce_it(void** s);
+static char * AO_gettext(char const * pz);
+static void coerce_it(void ** s);
-static char*
-AO_gettext( char const* pz )
+/**
+ * AutoGen specific wrapper function for gettext. It relies on the macro _()
+ * to convert from English to the target language, then strdup-duplicates the
+ * result string. It tries the "libopts" domain first, then whatever has been
+ * set via the \a textdomain(3) call.
+ *
+ * @param[in] pz the input text used as a lookup key.
+ * @returns the translated text (if there is one),
+ * or the original text (if not).
+ */
+static char *
+AO_gettext(char const * pz)
{
- char* pzRes;
+ char * res;
if (pz == NULL)
return NULL;
- pzRes = _(pz);
- if (pzRes == pz)
- return pzRes;
- pzRes = strdup( pzRes );
- if (pzRes == NULL) {
- fputs( _("No memory for duping translated strings\n"), stderr );
- exit( EXIT_FAILURE );
+#ifdef HAVE_DCGETTEXT
+ /*
+ * While processing the option_xlateable_txt data, try to use the
+ * "libopts" domain. Once we switch to the option descriptor data,
+ * do *not* use that domain.
+ */
+ if (option_xlateable_txt.field_ct != 0) {
+ res = dgettext("libopts", pz);
+ if (res == pz)
+ res = (char *)VOIDP(_(pz));
+ } else
+ res = (char *)VOIDP(_(pz));
+#else
+ res = (char *)VOIDP(_(pz));
+#endif
+ if (res == pz)
+ return res;
+ res = strdup(res);
+ if (res == NULL) {
+ fputs(_("No memory for duping translated strings\n"), stderr);
+ exit(NTPD_EXIT_FAILURE);
}
- return pzRes;
+ return res;
}
-static void coerce_it(void** s) { *s = AO_gettext(*s); }
-#define COERSION(_f) \
- coerce_it((void*)&(ntpdOptions._f))
+/**
+ * All the pointers we use are marked "* const", but they are stored in
+ * writable memory. Coerce the mutability and set the pointer.
+ */
+static void coerce_it(void ** s) { *s = AO_gettext(*s);
+}
-/*
- * This invokes the translation code (e.g. gettext(3)).
+/**
+ * Translate all the translatable strings in the ntpdOptions
+ * structure defined above. This is done only once.
*/
static void
-translate_option_strings( void )
+translate_option_strings(void)
{
+ tOptions * const opts = &ntpdOptions;
+
/*
* Guard against re-translation. It won't work. The strings will have
* been changed by the first pass through this code. One shot only.
*/
- if (option_usage_text.field_ct == 0)
- return;
- /*
- * Do the translations. The first pointer follows the field count field.
- * The field count field is the size of a pointer.
- */
- {
- char** ppz = (char**)(void*)&(option_usage_text);
- int ix = option_usage_text.field_ct;
+ if (option_xlateable_txt.field_ct != 0) {
+ /*
+ * Do the translations. The first pointer follows the field count
+ * field. The field count field is the size of a pointer.
+ */
+ char ** ppz = (char**)VOIDP(&(option_xlateable_txt));
+ int ix = option_xlateable_txt.field_ct;
do {
- ppz++;
+ ppz++; /* skip over field_ct */
*ppz = AO_gettext(*ppz);
} while (--ix > 0);
- }
- option_usage_text.field_ct = 0;
-
- {
- tOptDesc* pOD = ntpdOptions.pOptDesc;
- int ix = ntpdOptions.optCt;
-
- for (;;) {
- pOD->pzText = AO_gettext(pOD->pzText);
- pOD->pz_NAME = AO_gettext(pOD->pz_NAME);
- pOD->pz_Name = AO_gettext(pOD->pz_Name);
- pOD->pz_DisableName = AO_gettext(pOD->pz_DisableName);
- pOD->pz_DisablePfx = AO_gettext(pOD->pz_DisablePfx);
- if (--ix <= 0)
- break;
- pOD++;
+ /* prevent re-translation and disable "libopts" domain lookup */
+ option_xlateable_txt.field_ct = 0;
+
+ coerce_it(VOIDP(&(opts->pzCopyright)));
+ coerce_it(VOIDP(&(opts->pzCopyNotice)));
+ coerce_it(VOIDP(&(opts->pzFullVersion)));
+ coerce_it(VOIDP(&(opts->pzUsageTitle)));
+ coerce_it(VOIDP(&(opts->pzExplain)));
+ coerce_it(VOIDP(&(opts->pzDetail)));
+ {
+ tOptDesc * od = opts->pOptDesc;
+ for (ix = opts->optCt; ix > 0; ix--, od++)
+ coerce_it(VOIDP(&(od->pzText)));
}
}
- COERSION(pzCopyright);
- COERSION(pzCopyNotice);
- COERSION(pzFullVersion);
- COERSION(pzUsageTitle);
- COERSION(pzExplain);
- COERSION(pzDetail);
}
-
#endif /* ENABLE_NLS */
+#ifdef DO_NOT_COMPILE_THIS_CODE_IT_IS_FOR_GETTEXT
+/** I18N function strictly for xgettext. Do not compile. */
+static void bogus_function(void) {
+ /* TRANSLATORS:
+
+ The following dummy function was crated solely so that xgettext can
+ extract the correct strings. These strings are actually referenced
+ by a field name in the ntpdOptions structure noted in the
+ comments below. The literal text is defined in ntpd_opt_strs.
+
+ NOTE: the strings below are segmented with respect to the source string
+ ntpd_opt_strs. The strings above are handed off for translation
+ at run time a paragraph at a time. Consequently, they are presented here
+ for translation a paragraph at a time.
+
+ ALSO: often the description for an option will reference another option
+ by name. These are set off with apostrophe quotes (I hope). Do not
+ translate option names.
+ */
+ /* referenced via ntpdOptions.pzCopyright */
+ puts(_("ntpd 4.2.8p3\n\
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation, all rights reserved.\n\
+This is free software. It is licensed for use, modification and\n\
+redistribution under the terms of the NTP License, copies of which\n\
+can be seen at:\n"));
+ puts(_(" <http://ntp.org/license>\n\
+ <http://opensource.org/licenses/ntp-license.php>\n"));
+
+ /* referenced via ntpdOptions.pzCopyNotice */
+ puts(_("Permission to use, copy, modify, and distribute this software and its\n\
+documentation for any purpose with or without fee is hereby granted,\n\
+provided that the above copyright notice appears in all copies and that\n\
+both the copyright notice and this permission notice appear in supporting\n\
+documentation, and that the name The University of Delaware not be used in\n\
+advertising or publicity pertaining to distribution of the software without\n\
+specific, written prior permission. The University of Delaware and Network\n\
+Time Foundation makes no representations about the suitability this\n\
+software for any purpose. It is provided \"as is\" without express or\n\
+implied warranty.\n"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Force IPv4 DNS name resolution"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Force IPv6 DNS name resolution"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Require crypto authentication"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Do not require crypto authentication"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Allow us to sync to broadcast servers"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("configuration file name"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Increase debug verbosity level"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Set the debug verbosity level"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("frequency drift file name"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Allow the first adjustment to be Big"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Step any initial offset correction."));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Jail directory"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Listen on an interface name or address"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("path to symmetric keys"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("path to the log file"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Do not listen to virtual interfaces"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Modify Multimedia Timer (Windows only)"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Do not fork"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Run at high priority"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("path to the PID file"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Process priority"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Set the time and quit"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Broadcast/propagation delay"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Save parsed configuration and quit"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Statistics file location"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Trusted key number"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Run as userid (or userid:groupid)"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("interval in seconds between scans for new or dropped interfaces"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("make ARG an ntp variable (RW)"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("make ARG an ntp variable (RW|DEF)"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Seconds to wait for first clock sync"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Slew up to 600 seconds"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Use CPU cycle counter (Windows only)"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Force CPU cycle counter use (Windows only)"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("Register with mDNS as a NTP server"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("display extended usage information and exit"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("extended usage information passed thru pager"));
+
+ /* referenced via ntpdOptions.pOptDesc->pzText */
+ puts(_("output version information and exit"));
+
+ /* referenced via ntpdOptions.pzUsageTitle */
+ puts(_("ntpd - NTP daemon program - Ver. 4.2.8p3\n\
+Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n\
+\t\t[ <server1> ... <serverN> ]\n"));
+
+ /* referenced via ntpdOptions.pzExplain */
+ puts(_("\n"));
+
+ /* referenced via ntpdOptions.pzFullVersion */
+ puts(_("ntpd 4.2.8p3"));
+
+ /* referenced via ntpdOptions.pzFullUsage */
+ puts(_("<<<NOT-FOUND>>>"));
+
+ /* referenced via ntpdOptions.pzShortUsage */
+ puts(_("<<<NOT-FOUND>>>"));
+ /* LIBOPTS-MESSAGES: */
+#line 67 "../autoopts.c"
+ puts(_("allocation of %d bytes failed\n"));
+#line 93 "../autoopts.c"
+ puts(_("allocation of %d bytes failed\n"));
+#line 53 "../init.c"
+ puts(_("AutoOpts function called without option descriptor\n"));
+#line 86 "../init.c"
+ puts(_("\tThis exceeds the compiled library version: "));
+#line 84 "../init.c"
+ puts(_("Automated Options Processing Error!\n"
+ "\t%s called AutoOpts function with structure version %d:%d:%d.\n"));
+#line 80 "../autoopts.c"
+ puts(_("realloc of %d bytes at 0x%p failed\n"));
+#line 88 "../init.c"
+ puts(_("\tThis is less than the minimum library version: "));
+#line 121 "../version.c"
+ puts(_("Automated Options version %s\n"
+ "\tCopyright (C) 1999-2014 by Bruce Korb - all rights reserved\n"));
+#line 87 "../makeshell.c"
+ puts(_("(AutoOpts bug): %s.\n"));
+#line 90 "../reset.c"
+ puts(_("optionResetOpt() called, but reset-option not configured"));
+#line 292 "../usage.c"
+ puts(_("could not locate the 'help' option"));
+#line 336 "../autoopts.c"
+ puts(_("optionProcess() was called with invalid data"));
+#line 748 "../usage.c"
+ puts(_("invalid argument type specified"));
+#line 598 "../find.c"
+ puts(_("defaulted to option with optional arg"));
+#line 76 "../alias.c"
+ puts(_("aliasing option is out of range."));
+#line 234 "../enum.c"
+ puts(_("%s error: the keyword '%s' is ambiguous for %s\n"));
+#line 108 "../find.c"
+ puts(_(" The following options match:\n"));
+#line 293 "../find.c"
+ puts(_("%s: ambiguous option name: %s (matches %d options)\n"));
+#line 161 "../check.c"
+ puts(_("%s: Command line arguments required\n"));
+#line 43 "../alias.c"
+ puts(_("%d %s%s options allowed\n"));
+#line 94 "../makeshell.c"
+ puts(_("%s error %d (%s) calling %s for '%s'\n"));
+#line 306 "../makeshell.c"
+ puts(_("interprocess pipe"));
+#line 168 "../version.c"
+ puts(_("error: version option argument '%c' invalid. Use:\n"
+ "\t'v' - version only\n"
+ "\t'c' - version and copyright\n"
+ "\t'n' - version and full copyright notice\n"));
+#line 58 "../check.c"
+ puts(_("%s error: the '%s' and '%s' options conflict\n"));
+#line 217 "../find.c"
+ puts(_("%s: The '%s' option has been disabled."));
+#line 430 "../find.c"
+ puts(_("%s: The '%s' option has been disabled."));
+#line 38 "../alias.c"
+ puts(_("-equivalence"));
+#line 469 "../find.c"
+ puts(_("%s: illegal option -- %c\n"));
+#line 110 "../reset.c"
+ puts(_("%s: illegal option -- %c\n"));
+#line 271 "../find.c"
+ puts(_("%s: illegal option -- %s\n"));
+#line 755 "../find.c"
+ puts(_("%s: illegal option -- %s\n"));
+#line 118 "../reset.c"
+ puts(_("%s: illegal option -- %s\n"));
+#line 335 "../find.c"
+ puts(_("%s: unknown vendor extension option -- %s\n"));
+#line 159 "../enum.c"
+ puts(_(" or an integer from %d through %d\n"));
+#line 169 "../enum.c"
+ puts(_(" or an integer from %d through %d\n"));
+#line 747 "../usage.c"
+ puts(_("%s error: invalid option descriptor for %s\n"));
+#line 1081 "../usage.c"
+ puts(_("%s error: invalid option descriptor for %s\n"));
+#line 385 "../find.c"
+ puts(_("%s: invalid option name: %s\n"));
+#line 527 "../find.c"
+ puts(_("%s: The '%s' option requires an argument.\n"));
+#line 156 "../autoopts.c"
+ puts(_("(AutoOpts bug): Equivalenced option '%s' was equivalenced to both\n"
+ "\t'%s' and '%s'."));
+#line 94 "../check.c"
+ puts(_("%s error: The %s option is required\n"));
+#line 632 "../find.c"
+ puts(_("%s: The '%s' option cannot have an argument.\n"));
+#line 151 "../check.c"
+ puts(_("%s: Command line arguments are not allowed.\n"));
+#line 535 "../save.c"
+ puts(_("error %d (%s) creating %s\n"));
+#line 234 "../enum.c"
+ puts(_("%s error: '%s' does not match any %s keywords.\n"));
+#line 93 "../reset.c"
+ puts(_("%s error: The '%s' option requires an argument.\n"));
+#line 184 "../save.c"
+ puts(_("error %d (%s) stat-ing %s\n"));
+#line 238 "../save.c"
+ puts(_("error %d (%s) stat-ing %s\n"));
+#line 143 "../restore.c"
+ puts(_("%s error: no saved option state\n"));
+#line 231 "../autoopts.c"
+ puts(_("'%s' is not a command line option.\n"));
+#line 111 "../time.c"
+ puts(_("%s error: '%s' is not a recognizable date/time.\n"));
+#line 132 "../save.c"
+ puts(_("'%s' not defined\n"));
+#line 50 "../time.c"
+ puts(_("%s error: '%s' is not a recognizable time duration.\n"));
+#line 92 "../check.c"
+ puts(_("%s error: The %s option must appear %d times.\n"));
+#line 164 "../numeric.c"
+ puts(_("%s error: '%s' is not a recognizable number.\n"));
+#line 200 "../enum.c"
+ puts(_("%s error: %s exceeds %s keyword count\n"));
+#line 330 "../usage.c"
+ puts(_("Try '%s %s' for more information.\n"));
+#line 45 "../alias.c"
+ puts(_("one %s%s option allowed\n"));
+#line 208 "../makeshell.c"
+ puts(_("standard output"));
+#line 943 "../makeshell.c"
+ puts(_("standard output"));
+#line 274 "../usage.c"
+ puts(_("standard output"));
+#line 415 "../usage.c"
+ puts(_("standard output"));
+#line 625 "../usage.c"
+ puts(_("standard output"));
+#line 175 "../version.c"
+ puts(_("standard output"));
+#line 274 "../usage.c"
+ puts(_("standard error"));
+#line 415 "../usage.c"
+ puts(_("standard error"));
+#line 625 "../usage.c"
+ puts(_("standard error"));
+#line 175 "../version.c"
+ puts(_("standard error"));
+#line 208 "../makeshell.c"
+ puts(_("write"));
+#line 943 "../makeshell.c"
+ puts(_("write"));
+#line 273 "../usage.c"
+ puts(_("write"));
+#line 414 "../usage.c"
+ puts(_("write"));
+#line 624 "../usage.c"
+ puts(_("write"));
+#line 174 "../version.c"
+ puts(_("write"));
+#line 60 "../numeric.c"
+ puts(_("%s error: %s option value %ld is out of range.\n"));
+#line 44 "../check.c"
+ puts(_("%s error: %s option requires the %s option\n"));
+#line 131 "../save.c"
+ puts(_("%s warning: cannot save options - %s not regular file\n"));
+#line 183 "../save.c"
+ puts(_("%s warning: cannot save options - %s not regular file\n"));
+#line 237 "../save.c"
+ puts(_("%s warning: cannot save options - %s not regular file\n"));
+#line 256 "../save.c"
+ puts(_("%s warning: cannot save options - %s not regular file\n"));
+#line 534 "../save.c"
+ puts(_("%s warning: cannot save options - %s not regular file\n"));
+ /* END-LIBOPTS-MESSAGES */
+
+ /* USAGE-TEXT: */
+#line 873 "../usage.c"
+ puts(_("\t\t\t\t- an alternate for '%s'\n"));
+#line 1148 "../usage.c"
+ puts(_("Version, usage and configuration options:"));
+#line 924 "../usage.c"
+ puts(_("\t\t\t\t- default option for unnamed options\n"));
+#line 837 "../usage.c"
+ puts(_("\t\t\t\t- disabled as '--%s'\n"));
+#line 1117 "../usage.c"
+ puts(_(" --- %-14s %s\n"));
+#line 1115 "../usage.c"
+ puts(_("This option has been disabled"));
+#line 864 "../usage.c"
+ puts(_("\t\t\t\t- enabled by default\n"));
+#line 40 "../alias.c"
+ puts(_("%s error: only "));
+#line 1194 "../usage.c"
+ puts(_(" - examining environment variables named %s_*\n"));
+#line 168 "../file.c"
+ puts(_("\t\t\t\t- file must not pre-exist\n"));
+#line 172 "../file.c"
+ puts(_("\t\t\t\t- file must pre-exist\n"));
+#line 380 "../usage.c"
+ puts(_("Options are specified by doubled hyphens and their name or by a single\n"
+ "hyphen and the flag character.\n"));
+#line 921 "../makeshell.c"
+ puts(_("\n"
+ "= = = = = = = =\n\n"
+ "This incarnation of genshell will produce\n"
+ "a shell script to parse the options for %s:\n\n"));
+#line 166 "../enum.c"
+ puts(_(" or an integer mask with any of the lower %d bits set\n"));
+#line 897 "../usage.c"
+ puts(_("\t\t\t\t- is a set membership option\n"));
+#line 918 "../usage.c"
+ puts(_("\t\t\t\t- must appear between %d and %d times\n"));
+#line 382 "../usage.c"
+ puts(_("Options are specified by single or double hyphens and their name.\n"));
+#line 904 "../usage.c"
+ puts(_("\t\t\t\t- may appear multiple times\n"));
+#line 891 "../usage.c"
+ puts(_("\t\t\t\t- may not be preset\n"));
+#line 1309 "../usage.c"
+ puts(_(" Arg Option-Name Description\n"));
+#line 1245 "../usage.c"
+ puts(_(" Flg Arg Option-Name Description\n"));
+#line 1303 "../usage.c"
+ puts(_(" Flg Arg Option-Name Description\n"));
+#line 1304 "../usage.c"
+ puts(_(" %3s %s"));
+#line 1310 "../usage.c"
+ puts(_(" %3s %s"));
+#line 387 "../usage.c"
+ puts(_("The '-#<number>' option may omit the hash char\n"));
+#line 383 "../usage.c"
+ puts(_("All arguments are named options.\n"));
+#line 971 "../usage.c"
+ puts(_(" - reading file %s"));
+#line 409 "../usage.c"
+ puts(_("\n"
+ "Please send bug reports to: <%s>\n"));
+#line 100 "../version.c"
+ puts(_("\n"
+ "Please send bug reports to: <%s>\n"));
+#line 129 "../version.c"
+ puts(_("\n"
+ "Please send bug reports to: <%s>\n"));
+#line 903 "../usage.c"
+ puts(_("\t\t\t\t- may NOT appear - preset only\n"));
+#line 944 "../usage.c"
+ puts(_("\n"
+ "The following option preset mechanisms are supported:\n"));
+#line 1192 "../usage.c"
+ puts(_("\n"
+ "The following option preset mechanisms are supported:\n"));
+#line 682 "../usage.c"
+ puts(_("prohibits these options:\n"));
+#line 677 "../usage.c"
+ puts(_("prohibits the option '%s'\n"));
+#line 81 "../numeric.c"
+ puts(_("%s%ld to %ld"));
+#line 79 "../numeric.c"
+ puts(_("%sgreater than or equal to %ld"));
+#line 75 "../numeric.c"
+ puts(_("%s%ld exactly"));
+#line 68 "../numeric.c"
+ puts(_("%sit must lie in one of the ranges:\n"));
+#line 68 "../numeric.c"
+ puts(_("%sit must be in the range:\n"));
+#line 88 "../numeric.c"
+ puts(_(", or\n"));
+#line 66 "../numeric.c"
+ puts(_("%sis scalable with a suffix: k/K/m/M/g/G/t/T\n"));
+#line 77 "../numeric.c"
+ puts(_("%sless than or equal to %ld"));
+#line 390 "../usage.c"
+ puts(_("Operands and options may be intermixed. They will be reordered.\n"));
+#line 652 "../usage.c"
+ puts(_("requires the option '%s'\n"));
+#line 655 "../usage.c"
+ puts(_("requires these options:\n"));
+#line 1321 "../usage.c"
+ puts(_(" Arg Option-Name Req? Description\n"));
+#line 1315 "../usage.c"
+ puts(_(" Flg Arg Option-Name Req? Description\n"));
+#line 167 "../enum.c"
+ puts(_("or you may use a numeric representation. Preceding these with a '!'\n"
+ "will clear the bits, specifying 'none' will clear all bits, and 'all'\n"
+ "will set them all. Multiple entries may be passed as an option\n"
+ "argument list.\n"));
+#line 910 "../usage.c"
+ puts(_("\t\t\t\t- may appear up to %d times\n"));
+#line 77 "../enum.c"
+ puts(_("The valid \"%s\" option keywords are:\n"));
+#line 1152 "../usage.c"
+ puts(_("The next option supports vendor supported extra options:"));
+#line 773 "../usage.c"
+ puts(_("These additional options are:"));
+ /* END-USAGE-TEXT */
+}
+#endif /* uncompilable code */
#ifdef __cplusplus
}
#endif
diff --git a/contrib/ntp/ntpd/ntpd-opts.def b/contrib/ntp/ntpd/ntpd-opts.def
index 7266e1b..dee484d 100644
--- a/contrib/ntp/ntpd/ntpd-opts.def
+++ b/contrib/ntp/ntpd/ntpd-opts.def
@@ -4,10 +4,608 @@ autogen definitions options;
#include copyright.def
-prog-name = "ntpd";
-prog-title = "NTP daemon program";
+prog-name = "ntpd";
+prog-title = "NTP daemon program";
+argument = "[ <server1> ... <serverN> ]";
#include ntpdbase-opts.def
-detail = <<- _END_DETAIL
- _END_DETAIL;
+/* explain: Additional information whenever the usage routine is invoked */
+explain = <<- _END_EXPLAIN
+ _END_EXPLAIN;
+
+doc-section = {
+ ds-type = 'DESCRIPTION';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_PROG_MDOC_DESCRIP
+The
+.Nm
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC-5905,
+but also retains compatibility with
+version 3, as defined by RFC-1305, and versions 1
+and 2, as defined by RFC-1059 and RFC-1119, respectively.
+.Pp
+The
+.Nm
+utility does most computations in 64-bit floating point
+arithmetic and does relatively clumsy 64-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+.Pp
+Ordinarily,
+.Nm
+reads the
+.Xr ntp.conf 5
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+.Pp
+If NetInfo support is built into
+.Nm ,
+then
+.Nm
+will attempt to read its configuration from the
+NetInfo if the default
+.Xr ntp.conf 5
+file cannot be read and no file is
+specified by the
+.Fl c
+option.
+.Pp
+Various internal
+.Nm
+variables can be displayed and
+configuration options altered while the
+.Nm
+is running
+using the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+utility programs.
+.Pp
+When
+.Nm
+starts it looks at the value of
+.Xr umask 2 ,
+and if zero
+.Nm
+will set the
+.Xr umask 2
+to 022.
+ _END_PROG_MDOC_DESCRIP;
+};
+
+doc-section = {
+ ds-type = 'USAGE';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_USAGE
+.Ss "How NTP Operates"
+The
+.Nm
+utility operates by exchanging messages with
+one or more configured servers over a range of designated poll intervals.
+When
+started, whether for the first or subsequent times, the program
+requires several exchanges from the majority of these servers so
+the signal processing and mitigation algorithms can accumulate and
+groom the data and set the clock.
+In order to protect the network
+from bursts, the initial poll interval for each server is delayed
+an interval randomized over a few seconds.
+At the default initial poll
+interval of 64s, several minutes can elapse before the clock is
+set.
+This initial delay to set the clock
+can be safely and dramatically reduced using the
+.Cm iburst
+keyword with the
+.Ic server
+configuration
+command, as described in
+.Xr ntp.conf 5 .
+.Pp
+Most operating systems and hardware of today incorporate a
+time-of-year (TOY) chip to maintain the time during periods when
+the power is off.
+When the machine is booted, the chip is used to
+initialize the operating system time.
+After the machine has
+synchronized to a NTP server, the operating system corrects the
+chip from time to time.
+In the default case, if
+.Nm
+detects that the time on the host
+is more than 1000s from the server time,
+.Nm
+assumes something must be terribly wrong and the only
+reliable action is for the operator to intervene and set the clock
+by hand.
+(Reasons for this include there is no TOY chip,
+or its battery is dead, or that the TOY chip is just of poor quality.)
+This causes
+.Nm
+to exit with a panic message to
+the system log.
+The
+.Fl g
+option overrides this check and the
+clock will be set to the server time regardless of the chip time
+(up to 68 years in the past or future \(em
+this is a limitation of the NTPv4 protocol).
+However, and to protect against broken hardware, such as when the
+CMOS battery fails or the clock counter becomes defective, once the
+clock has been set an error greater than 1000s will cause
+.Nm
+to exit anyway.
+.Pp
+Under ordinary conditions,
+.Nm
+adjusts the clock in
+small steps so that the timescale is effectively continuous and
+without discontinuities.
+Under conditions of extreme network
+congestion, the roundtrip delay jitter can exceed three seconds and
+the synchronization distance, which is equal to one-half the
+roundtrip delay plus error budget terms, can become very large.
+The
+.Nm
+algorithms discard sample offsets exceeding 128 ms,
+unless the interval during which no sample offset is less than 128
+ms exceeds 900s.
+The first sample after that, no matter what the
+offset, steps the clock to the indicated time.
+In practice this
+reduces the false alarm rate where the clock is stepped in error to
+a vanishingly low incidence.
+.Pp
+As the result of this behavior, once the clock has been set it
+very rarely strays more than 128 ms even under extreme cases of
+network path congestion and jitter.
+Sometimes, in particular when
+.Nm
+is first started without a valid drift file
+on a system with a large intrinsic drift
+the error might grow to exceed 128 ms,
+which would cause the clock to be set backwards
+if the local clock time is more than 128 s
+in the future relative to the server.
+In some applications, this behavior may be unacceptable.
+There are several solutions, however.
+If the
+.Fl x
+option is included on the command line, the clock will
+never be stepped and only slew corrections will be used.
+But this choice comes with a cost that
+should be carefully explored before deciding to use
+the
+.Fl x
+option.
+The maximum slew rate possible is limited
+to 500 parts-per-million (PPM) as a consequence of the correctness
+principles on which the NTP protocol and algorithm design are
+based.
+As a result, the local clock can take a long time to
+converge to an acceptable offset, about 2,000 s for each second the
+clock is outside the acceptable range.
+During this interval the
+local clock will not be consistent with any other network clock and
+the system cannot be used for distributed applications that require
+correctly synchronized network time.
+.Pp
+In spite of the above precautions, sometimes when large
+frequency errors are present the resulting time offsets stray
+outside the 128-ms range and an eventual step or slew time
+correction is required.
+If following such a correction the
+frequency error is so large that the first sample is outside the
+acceptable range,
+.Nm
+enters the same state as when the
+.Pa ntp.drift
+file is not present.
+The intent of this behavior
+is to quickly correct the frequency and restore operation to the
+normal tracking mode.
+In the most extreme cases
+(the host
+.Cm time.ien.it
+comes to mind), there may be occasional
+step/slew corrections and subsequent frequency corrections.
+It
+helps in these cases to use the
+.Cm burst
+keyword when
+configuring the server, but
+ONLY
+when you have permission to do so from the owner of the target host.
+.Pp
+Finally,
+in the past many startup scripts would run
+.Xr ntpdate 1ntpdatemdoc
+to get the system clock close to correct before starting
+.Xr ntpd 1ntpdmdoc ,
+but this was never more than a mediocre hack and is no longer needed.
+If you are following the instructions in
+.Sx "Starting NTP (Best Current Practice)"
+and you still need to set the system time before starting
+.Nm ,
+please open a bug report and document what is going on,
+and then look at using
+.Xr sntp 1sntpmdoc .
+.Pp
+There is a way to start
+.Xr ntpd 1ntpdmdoc
+that often addresses all of the problems mentioned above.
+.Ss "Starting NTP (Best Current Practice)"
+First, use the
+.Cm iburst
+option on your
+.Cm server
+entries.
+.Pp
+If you can also keep a good
+.Pa ntp.drift
+file then
+.Xr ntpd 1ntpdmdoc
+will effectively "warm-start" and your system's clock will
+be stable in under 11 seconds' time.
+.Pp
+As soon as possible in the startup sequence, start
+.Xr ntpd 1ntpdmdoc
+with at least the
+.Fl g
+and perhaps the
+.Fl N
+options.
+Then,
+start the rest of your "normal" processes.
+This will give
+.Xr ntpd 1ntpdmdoc
+as much time as possible to get the system's clock synchronized and stable.
+.Pp
+Finally,
+if you have processes like
+.Cm dovecot
+or database servers
+that require
+monotonically-increasing time,
+run
+.Xr ntp-wait 1ntp-waitmdoc
+as late as possible in the boot sequence
+(perhaps with the
+.Fl v
+flag)
+and after
+.Xr ntp-wait 1ntp-waitmdoc
+exits successfully
+it is as safe as it will ever be to start any process that require
+stable time.
+.Ss "Frequency Discipline"
+The
+.Nm
+behavior at startup depends on whether the
+frequency file, usually
+.Pa ntp.drift ,
+exists.
+This file
+contains the latest estimate of clock frequency error.
+When the
+.Nm
+is started and the file does not exist, the
+.Nm
+enters a special mode designed to quickly adapt to
+the particular system clock oscillator time and frequency error.
+This takes approximately 15 minutes, after which the time and
+frequency are set to nominal values and the
+.Nm
+enters
+normal mode, where the time and frequency are continuously tracked
+relative to the server.
+After one hour the frequency file is
+created and the current frequency offset written to it.
+When the
+.Nm
+is started and the file does exist, the
+.Nm
+frequency is initialized from the file and enters normal mode
+immediately.
+After that the current frequency offset is written to
+the file at hourly intervals.
+.Ss "Operating Modes"
+The
+.Nm
+utility can operate in any of several modes, including
+symmetric active/passive, client/server broadcast/multicast and
+manycast, as described in the
+.Qq Association Management
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+It normally operates continuously while
+monitoring for small changes in frequency and trimming the clock
+for the ultimate precision.
+However, it can operate in a one-time
+mode where the time is set from an external server and frequency is
+set from a previously recorded frequency file.
+A
+broadcast/multicast or manycast client can discover remote servers,
+compute server-client propagation delay correction factors and
+configure itself automatically.
+This makes it possible to deploy a
+fleet of workstations without specifying configuration details
+specific to the local environment.
+.Pp
+By default,
+.Nm
+runs in continuous mode where each of
+possibly several external servers is polled at intervals determined
+by an intricate state machine.
+The state machine measures the
+incidental roundtrip delay jitter and oscillator frequency wander
+and determines the best poll interval using a heuristic algorithm.
+Ordinarily, and in most operating environments, the state machine
+will start with 64s intervals and eventually increase in steps to
+1024s.
+A small amount of random variation is introduced in order to
+avoid bunching at the servers.
+In addition, should a server become
+unreachable for some time, the poll interval is increased in steps
+to 1024s in order to reduce network overhead.
+.Pp
+In some cases it may not be practical for
+.Nm
+to run continuously.
+A common workaround has been to run the
+.Xr ntpdate 1ntpdatemdoc
+or
+.Xr sntp 1sntpmdoc
+programs from a
+.Xr cron 8
+job at designated
+times.
+However, these programs do not have the crafted signal
+processing, error checking or mitigation algorithms of
+.Nm .
+The
+.Fl q
+option is intended for this purpose.
+Setting this option will cause
+.Nm
+to exit just after
+setting the clock for the first time.
+The procedure for initially
+setting the clock is the same as in continuous mode; most
+applications will probably want to specify the
+.Cm iburst
+keyword with the
+.Ic server
+configuration command.
+With this
+keyword a volley of messages are exchanged to groom the data and
+the clock is set in about 10 s.
+If nothing is heard after a
+couple of minutes, the daemon times out and exits.
+After a suitable
+period of mourning, the
+.Xr ntpdate 1ntpdatemdoc
+program will be
+retired.
+.Pp
+When kernel support is available to discipline the clock
+frequency, which is the case for stock Solaris, Tru64, Linux and
+.Fx ,
+a useful feature is available to discipline the clock
+frequency.
+First,
+.Nm
+is run in continuous mode with
+selected servers in order to measure and record the intrinsic clock
+frequency offset in the frequency file.
+It may take some hours for
+the frequency and offset to settle down.
+Then the
+.Nm
+is
+stopped and run in one-time mode as required.
+At each startup, the
+frequency is read from the file and initializes the kernel
+frequency.
+.Ss "Poll Interval Control"
+This version of NTP includes an intricate state machine to
+reduce the network load while maintaining a quality of
+synchronization consistent with the observed jitter and wander.
+There are a number of ways to tailor the operation in order enhance
+accuracy by reducing the interval or to reduce network overhead by
+increasing it.
+However, the user is advised to carefully consider
+the consequences of changing the poll adjustment range from the
+default minimum of 64 s to the default maximum of 1,024 s.
+The
+default minimum can be changed with the
+.Ic tinker
+.Cm minpoll
+command to a value not less than 16 s.
+This value is used for all
+configured associations, unless overridden by the
+.Cm minpoll
+option on the configuration command.
+Note that most device drivers
+will not operate properly if the poll interval is less than 64 s
+and that the broadcast server and manycast client associations will
+also use the default, unless overridden.
+.Pp
+In some cases involving dial up or toll services, it may be
+useful to increase the minimum interval to a few tens of minutes
+and maximum interval to a day or so.
+Under normal operation
+conditions, once the clock discipline loop has stabilized the
+interval will be increased in steps from the minimum to the
+maximum.
+However, this assumes the intrinsic clock frequency error
+is small enough for the discipline loop correct it.
+The capture
+range of the loop is 500 PPM at an interval of 64s decreasing by a
+factor of two for each doubling of interval.
+At a minimum of 1,024
+s, for example, the capture range is only 31 PPM.
+If the intrinsic
+error is greater than this, the drift file
+.Pa ntp.drift
+will
+have to be specially tailored to reduce the residual error below
+this limit.
+Once this is done, the drift file is automatically
+updated once per hour and is available to initialize the frequency
+on subsequent daemon restarts.
+.Ss "The huff-n'-puff Filter"
+In scenarios where a considerable amount of data are to be
+downloaded or uploaded over telephone modems, timekeeping quality
+can be seriously degraded.
+This occurs because the differential
+delays on the two directions of transmission can be quite large.
+In
+many cases the apparent time errors are so large as to exceed the
+step threshold and a step correction can occur during and after the
+data transfer is in progress.
+.Pp
+The huff-n'-puff filter is designed to correct the apparent time
+offset in these cases.
+It depends on knowledge of the propagation
+delay when no other traffic is present.
+In common scenarios this
+occurs during other than work hours.
+The filter maintains a shift
+register that remembers the minimum delay over the most recent
+interval measured usually in hours.
+Under conditions of severe
+delay, the filter corrects the apparent offset using the sign of
+the offset and the difference between the apparent delay and
+minimum delay.
+The name of the filter reflects the negative (huff)
+and positive (puff) correction, which depends on the sign of the
+offset.
+.Pp
+The filter is activated by the
+.Ic tinker
+command and
+.Cm huffpuff
+keyword, as described in
+.Xr ntp.conf 5 .
+ _END_MDOC_USAGE;
+};
+
+doc-section = {
+ ds-type = 'FILES';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_FILES
+.Bl -tag -width /etc/ntp.drift -compact
+.It Pa /etc/ntp.conf
+the default name of the configuration file
+.It Pa /etc/ntp.drift
+the default name of the drift file
+.It Pa /etc/ntp.keys
+the default name of the key file
+.El
+ _END_MDOC_FILES;
+};
+
+doc-section = {
+ ds-type = 'SEE ALSO';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_SEE_ALSO
+.Xr ntp.conf 5 ,
+.Xr ntpdate 1ntpdatemdoc ,
+.Xr ntpdc 1ntpdcmdoc ,
+.Xr ntpq 1ntpqmdoc ,
+.Xr sntp 1sntpmdoc
+.Pp
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+.Li http://www.ntp.org/ .
+A snapshot of this documentation is available in HTML format in
+.Pa /usr/share/doc/ntp .
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 1)
+.%O RFC1059
+.Re
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 2)
+.%O RFC1119
+.Re
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 3)
+.%O RFC1305
+.Re
+.Rs
+.%A David L. Mills
+.%A J. Martin, Ed.
+.%A J. Burbank
+.%A W. Kasch
+.%T Network Time Protocol Version 4: Protocol and Algorithms Specification
+.%O RFC5905
+.Re
+.Rs
+.%A David L. Mills
+.%A B. Haberman, Ed.
+.%T Network Time Protocol Version 4: Autokey Specification
+.%O RFC5906
+.Re
+.Rs
+.%A H. Gerstung
+.%A C. Elliott
+.%A B. Haberman, Ed.
+.%T Definitions of Managed Objects for Network Time Protocol Version 4: (NTPv4)
+.%O RFC5907
+.Re
+.Rs
+.%A R. Gayraud
+.%A B. Lourdelet
+.%T Network Time Protocol (NTP) Server Option for DHCPv6
+.%O RFC5908
+.Re
+ _END_MDOC_SEE_ALSO;
+};
+
+doc-section = {
+ ds-type = 'BUGS';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_BUGS
+The
+.Nm
+utility has gotten rather fat.
+While not huge, it has gotten
+larger than might be desirable for an elevated-priority
+.Nm
+running on a workstation, particularly since many of
+the fancy features which consume the space were designed more with
+a busy primary server, rather than a high stratum workstation in
+mind.
+ _END_MDOC_BUGS;
+};
+
+doc-section = {
+ ds-type = 'NOTES';
+ ds-format = 'mdoc';
+ ds-text = <<- _END_MDOC_NOTES
+Portions of this document came from FreeBSD.
+ _END_MDOC_NOTES;
+};
diff --git a/contrib/ntp/ntpd/ntpd-opts.h b/contrib/ntp/ntpd/ntpd-opts.h
index 0347f33..21142d8 100644
--- a/contrib/ntp/ntpd/ntpd-opts.h
+++ b/contrib/ntp/ntpd/ntpd-opts.h
@@ -1,117 +1,162 @@
-/*
+/*
* EDIT THIS FILE WITH CAUTION (ntpd-opts.h)
- *
- * It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:09 AM EST
+ *
+ * It has been AutoGen-ed June 29, 2015 at 04:28:18 PM by AutoGen 5.18.5
* From the definitions ntpd-opts.def
* and the template file options
*
- * Generated from AutoOpts 29:0:4 templates.
- */
-
-/*
- * This file was produced by an AutoOpts template. AutoOpts is a
- * copyrighted work. This header file is not encumbered by AutoOpts
- * licensing, but is provided under the licensing terms chosen by the
- * ntpd author or copyright holder. AutoOpts is licensed under
- * the terms of the LGPL. The redistributable library (``libopts'') is
- * licensed under the terms of either the LGPL or, at the users discretion,
- * the BSD license. See the AutoOpts and/or libopts sources for details.
+ * Generated from AutoOpts 41:0:16 templates.
+ *
+ * AutoOpts is a copyrighted work. This header file is not encumbered
+ * by AutoOpts licensing, but is provided under the licensing terms chosen
+ * by the ntpd author or copyright holder. AutoOpts is
+ * licensed under the terms of the LGPL. The redistributable library
+ * (``libopts'') is licensed under the terms of either the LGPL or, at the
+ * users discretion, the BSD license. See the AutoOpts and/or libopts sources
+ * for details.
*
- * This source file is copyrighted and licensed under the following terms:
+ * The ntpd program is copyrighted and licensed
+ * under the following terms:
*
- * ntpd copyright 1970-2009 David L. Mills and/or others - all rights reserved
+ * Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation, all rights reserved.
+ * This is free software. It is licensed for use, modification and
+ * redistribution under the terms of the NTP License, copies of which
+ * can be seen at:
+ * <http://ntp.org/license>
+ * <http://opensource.org/licenses/ntp-license.php>
*
- * see html/copyright.html
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and that
+ * both the copyright notice and this permission notice appear in
+ * supporting documentation, and that the name The University of Delaware not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The University of Delaware and Network Time Foundation makes no
+ * representations about the suitability this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
*/
-/*
+/**
* This file contains the programmatic interface to the Automated
* Options generated for the ntpd program.
* These macros are documented in the AutoGen info file in the
* "AutoOpts" chapter. Please refer to that doc for usage help.
*/
#ifndef AUTOOPTS_NTPD_OPTS_H_GUARD
-#define AUTOOPTS_NTPD_OPTS_H_GUARD
+#define AUTOOPTS_NTPD_OPTS_H_GUARD 1
#include "config.h"
#include <autoopts/options.h>
-/*
+/**
* Ensure that the library used for compiling this generated header is at
* least as new as the version current when the header template was released
* (not counting patch version increments). Also ensure that the oldest
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 118784
+#define AO_TEMPLATE_VERSION 167936
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
Choke Me.
#endif
-/*
- * Enumeration of each option:
+/**
+ * Enumeration of each option type for ntpd
*/
typedef enum {
- INDEX_OPT_IPV4 = 0,
- INDEX_OPT_IPV6 = 1,
- INDEX_OPT_AUTHREQ = 2,
- INDEX_OPT_AUTHNOREQ = 3,
- INDEX_OPT_BCASTSYNC = 4,
- INDEX_OPT_CONFIGFILE = 5,
- INDEX_OPT_DEBUG_LEVEL = 6,
- INDEX_OPT_SET_DEBUG_LEVEL = 7,
- INDEX_OPT_DRIFTFILE = 8,
- INDEX_OPT_PANICGATE = 9,
- INDEX_OPT_JAILDIR = 10,
- INDEX_OPT_INTERFACE = 11,
- INDEX_OPT_KEYFILE = 12,
- INDEX_OPT_LOGFILE = 13,
- INDEX_OPT_NOVIRTUALIPS = 14,
- INDEX_OPT_MODIFYMMTIMER = 15,
- INDEX_OPT_NOFORK = 16,
- INDEX_OPT_NICE = 17,
- INDEX_OPT_PIDFILE = 18,
- INDEX_OPT_PRIORITY = 19,
- INDEX_OPT_QUIT = 20,
- INDEX_OPT_PROPAGATIONDELAY = 21,
- INDEX_OPT_UPDATEINTERVAL = 22,
- INDEX_OPT_STATSDIR = 23,
- INDEX_OPT_TRUSTEDKEY = 24,
- INDEX_OPT_USER = 25,
- INDEX_OPT_VAR = 26,
- INDEX_OPT_DVAR = 27,
- INDEX_OPT_SLEW = 28,
- INDEX_OPT_VERSION = 29,
- INDEX_OPT_HELP = 30,
- INDEX_OPT_MORE_HELP = 31
+ INDEX_OPT_IPV4 = 0,
+ INDEX_OPT_IPV6 = 1,
+ INDEX_OPT_AUTHREQ = 2,
+ INDEX_OPT_AUTHNOREQ = 3,
+ INDEX_OPT_BCASTSYNC = 4,
+ INDEX_OPT_CONFIGFILE = 5,
+ INDEX_OPT_DEBUG_LEVEL = 6,
+ INDEX_OPT_SET_DEBUG_LEVEL = 7,
+ INDEX_OPT_DRIFTFILE = 8,
+ INDEX_OPT_PANICGATE = 9,
+ INDEX_OPT_FORCE_STEP_ONCE = 10,
+ INDEX_OPT_JAILDIR = 11,
+ INDEX_OPT_INTERFACE = 12,
+ INDEX_OPT_KEYFILE = 13,
+ INDEX_OPT_LOGFILE = 14,
+ INDEX_OPT_NOVIRTUALIPS = 15,
+ INDEX_OPT_MODIFYMMTIMER = 16,
+ INDEX_OPT_NOFORK = 17,
+ INDEX_OPT_NICE = 18,
+ INDEX_OPT_PIDFILE = 19,
+ INDEX_OPT_PRIORITY = 20,
+ INDEX_OPT_QUIT = 21,
+ INDEX_OPT_PROPAGATIONDELAY = 22,
+ INDEX_OPT_SAVECONFIGQUIT = 23,
+ INDEX_OPT_STATSDIR = 24,
+ INDEX_OPT_TRUSTEDKEY = 25,
+ INDEX_OPT_USER = 26,
+ INDEX_OPT_UPDATEINTERVAL = 27,
+ INDEX_OPT_VAR = 28,
+ INDEX_OPT_DVAR = 29,
+ INDEX_OPT_WAIT_SYNC = 30,
+ INDEX_OPT_SLEW = 31,
+ INDEX_OPT_USEPCC = 32,
+ INDEX_OPT_PCCFREQ = 33,
+ INDEX_OPT_MDNS = 34,
+ INDEX_OPT_VERSION = 35,
+ INDEX_OPT_HELP = 36,
+ INDEX_OPT_MORE_HELP = 37
} teOptIndex;
+/** count of all options for ntpd */
+#define OPTION_CT 38
+/** ntpd version */
+#define NTPD_VERSION "4.2.8p3"
+/** Full ntpd version text */
+#define NTPD_FULL_VERSION "ntpd 4.2.8p3"
-#define OPTION_CT 32
-#define NTPD_VERSION "4.2.4p8"
-#define NTPD_FULL_VERSION "ntpd - NTP daemon program - Ver. 4.2.4p8"
-
-/*
+/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
* option name (as in the teOptIndex enumeration above).
- * e.g. HAVE_OPT( IPV4 )
+ * e.g. HAVE_OPT(IPV4)
*/
#define DESC(n) (ntpdOptions.pOptDesc[INDEX_OPT_## n])
+/** 'true' if an option has been specified in any way */
#define HAVE_OPT(n) (! UNUSED_OPT(& DESC(n)))
+/** The string argument to an option. The argument type must be \"string\". */
#define OPT_ARG(n) (DESC(n).optArg.argString)
+/** Mask the option state revealing how an option was specified.
+ * It will be one and only one of \a OPTST_SET, \a OPTST_PRESET,
+ * \a OPTST_DEFINED, \a OPTST_RESET or zero.
+ */
#define STATE_OPT(n) (DESC(n).fOptState & OPTST_SET_MASK)
+/** Count of option's occurrances *on the command line*. */
#define COUNT_OPT(n) (DESC(n).optOccCt)
+/** mask of \a OPTST_SET and \a OPTST_DEFINED. */
#define ISSEL_OPT(n) (SELECTED_OPT(&DESC(n)))
+/** 'true' if \a HAVE_OPT would yield 'false'. */
#define ISUNUSED_OPT(n) (UNUSED_OPT(& DESC(n)))
+/** 'true' if OPTST_DISABLED bit not set. */
#define ENABLED_OPT(n) (! DISABLED_OPT(& DESC(n)))
+/** number of stacked option arguments.
+ * Valid only for stacked option arguments. */
#define STACKCT_OPT(n) (((tArgList*)(DESC(n).optCookie))->useCt)
+/** stacked argument vector.
+ * Valid only for stacked option arguments. */
#define STACKLST_OPT(n) (((tArgList*)(DESC(n).optCookie))->apzArgs)
+/** Reset an option. */
#define CLEAR_OPT(n) STMTS( \
DESC(n).fOptState &= OPTST_PERSISTENT_MASK; \
- if ( (DESC(n).fOptState & OPTST_INITENABLED) == 0) \
+ if ((DESC(n).fOptState & OPTST_INITENABLED) == 0) \
DESC(n).fOptState |= OPTST_DISABLED; \
DESC(n).optCookie = NULL )
-
-/*
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * Enumeration of ntpd exit codes
+ */
+typedef enum {
+ NTPD_EXIT_SUCCESS = 0,
+ NTPD_EXIT_FAILURE = 1,
+ NTPD_EXIT_USAGE_ERROR = 64,
+ NTPD_EXIT_LIBOPTS_FAILURE = 70
+} ntpd_exit_code_t;
+/** @} */
+/**
* Make sure there are no #define name conflicts with the option names
*/
#ifndef NO_OPTION_NAME_WARNINGS
@@ -155,6 +200,10 @@ typedef enum {
# warning undefining PANICGATE due to option name conflict
# undef PANICGATE
# endif
+# ifdef FORCE_STEP_ONCE
+# warning undefining FORCE_STEP_ONCE due to option name conflict
+# undef FORCE_STEP_ONCE
+# endif
# ifdef JAILDIR
# warning undefining JAILDIR due to option name conflict
# undef JAILDIR
@@ -203,9 +252,9 @@ typedef enum {
# warning undefining PROPAGATIONDELAY due to option name conflict
# undef PROPAGATIONDELAY
# endif
-# ifdef UPDATEINTERVAL
-# warning undefining UPDATEINTERVAL due to option name conflict
-# undef UPDATEINTERVAL
+# ifdef SAVECONFIGQUIT
+# warning undefining SAVECONFIGQUIT due to option name conflict
+# undef SAVECONFIGQUIT
# endif
# ifdef STATSDIR
# warning undefining STATSDIR due to option name conflict
@@ -219,6 +268,10 @@ typedef enum {
# warning undefining USER due to option name conflict
# undef USER
# endif
+# ifdef UPDATEINTERVAL
+# warning undefining UPDATEINTERVAL due to option name conflict
+# undef UPDATEINTERVAL
+# endif
# ifdef VAR
# warning undefining VAR due to option name conflict
# undef VAR
@@ -227,10 +280,26 @@ typedef enum {
# warning undefining DVAR due to option name conflict
# undef DVAR
# endif
+# ifdef WAIT_SYNC
+# warning undefining WAIT_SYNC due to option name conflict
+# undef WAIT_SYNC
+# endif
# ifdef SLEW
# warning undefining SLEW due to option name conflict
# undef SLEW
# endif
+# ifdef USEPCC
+# warning undefining USEPCC due to option name conflict
+# undef USEPCC
+# endif
+# ifdef PCCFREQ
+# warning undefining PCCFREQ due to option name conflict
+# undef PCCFREQ
+# endif
+# ifdef MDNS
+# warning undefining MDNS due to option name conflict
+# undef MDNS
+# endif
#else /* NO_OPTION_NAME_WARNINGS */
# undef IPV4
# undef IPV6
@@ -242,6 +311,7 @@ typedef enum {
# undef SET_DEBUG_LEVEL
# undef DRIFTFILE
# undef PANICGATE
+# undef FORCE_STEP_ONCE
# undef JAILDIR
# undef INTERFACE
# undef KEYFILE
@@ -254,98 +324,142 @@ typedef enum {
# undef PRIORITY
# undef QUIT
# undef PROPAGATIONDELAY
-# undef UPDATEINTERVAL
+# undef SAVECONFIGQUIT
# undef STATSDIR
# undef TRUSTEDKEY
# undef USER
+# undef UPDATEINTERVAL
# undef VAR
# undef DVAR
+# undef WAIT_SYNC
# undef SLEW
+# undef USEPCC
+# undef PCCFREQ
+# undef MDNS
#endif /* NO_OPTION_NAME_WARNINGS */
-/*
+/**
* Interface defines for specific options.
+ * @{
*/
#define VALUE_OPT_IPV4 '4'
-#define WHICH_OPT_IPV4 (DESC(IPV4).optActualValue)
-#define WHICH_IDX_IPV4 (DESC(IPV4).optActualIndex)
#define VALUE_OPT_IPV6 '6'
#define VALUE_OPT_AUTHREQ 'a'
#define VALUE_OPT_AUTHNOREQ 'A'
#define VALUE_OPT_BCASTSYNC 'b'
#define VALUE_OPT_CONFIGFILE 'c'
-#ifdef DEBUG
#define VALUE_OPT_DEBUG_LEVEL 'd'
-#endif /* DEBUG */
-#ifdef DEBUG
#define VALUE_OPT_SET_DEBUG_LEVEL 'D'
-#endif /* DEBUG */
+
+#define OPT_VALUE_SET_DEBUG_LEVEL (DESC(SET_DEBUG_LEVEL).optArg.argInt)
#define VALUE_OPT_DRIFTFILE 'f'
#define VALUE_OPT_PANICGATE 'g'
+#define VALUE_OPT_FORCE_STEP_ONCE 'G'
#define VALUE_OPT_JAILDIR 'i'
#define VALUE_OPT_INTERFACE 'I'
#define VALUE_OPT_KEYFILE 'k'
#define VALUE_OPT_LOGFILE 'l'
#define VALUE_OPT_NOVIRTUALIPS 'L'
-#ifdef SYS_WINNT
#define VALUE_OPT_MODIFYMMTIMER 'M'
-#endif /* SYS_WINNT */
#define VALUE_OPT_NOFORK 'n'
#define VALUE_OPT_NICE 'N'
#define VALUE_OPT_PIDFILE 'p'
#define VALUE_OPT_PRIORITY 'P'
+
#define OPT_VALUE_PRIORITY (DESC(PRIORITY).optArg.argInt)
#define VALUE_OPT_QUIT 'q'
#define VALUE_OPT_PROPAGATIONDELAY 'r'
-#define VALUE_OPT_UPDATEINTERVAL 'U'
-#define OPT_VALUE_UPDATEINTERVAL (DESC(UPDATEINTERVAL).optArg.argInt)
+#define VALUE_OPT_SAVECONFIGQUIT 0x1001
#define VALUE_OPT_STATSDIR 's'
#define VALUE_OPT_TRUSTEDKEY 't'
#define VALUE_OPT_USER 'u'
-#define VALUE_OPT_VAR 'v'
-#define VALUE_OPT_DVAR 'V'
-#define VALUE_OPT_SLEW 'x'
+#define VALUE_OPT_UPDATEINTERVAL 'U'
-#define VALUE_OPT_VERSION 'v'
+#define OPT_VALUE_UPDATEINTERVAL (DESC(UPDATEINTERVAL).optArg.argInt)
+#define VALUE_OPT_VAR 0x1002
+#define VALUE_OPT_DVAR 0x1003
+#define VALUE_OPT_WAIT_SYNC 'w'
+#ifdef HAVE_WORKING_FORK
+#define OPT_VALUE_WAIT_SYNC (DESC(WAIT_SYNC).optArg.argInt)
+#endif /* HAVE_WORKING_FORK */
+#define VALUE_OPT_SLEW 'x'
+#define VALUE_OPT_USEPCC 0x1004
+#define VALUE_OPT_PCCFREQ 0x1005
+#define VALUE_OPT_MDNS 'm'
+/** option flag (value) for help-value option */
#define VALUE_OPT_HELP '?'
+/** option flag (value) for more-help-value option */
#define VALUE_OPT_MORE_HELP '!'
+/** option flag (value) for version-value option */
+#define VALUE_OPT_VERSION 0x1006
/*
* Interface defines not associated with particular options
*/
-#define ERRSKIP_OPTERR STMTS( ntpdOptions.fOptSet &= ~OPTPROC_ERRSTOP )
-#define ERRSTOP_OPTERR STMTS( ntpdOptions.fOptSet |= OPTPROC_ERRSTOP )
+#define ERRSKIP_OPTERR STMTS(ntpdOptions.fOptSet &= ~OPTPROC_ERRSTOP)
+#define ERRSTOP_OPTERR STMTS(ntpdOptions.fOptSet |= OPTPROC_ERRSTOP)
#define RESTART_OPT(n) STMTS( \
ntpdOptions.curOptIdx = (n); \
ntpdOptions.pzCurOpt = NULL )
#define START_OPT RESTART_OPT(1)
-#define USAGE(c) (*ntpdOptions.pUsageProc)( &ntpdOptions, c )
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/opthead.tpl near line 360 */
+#define USAGE(c) (*ntpdOptions.pUsageProc)(&ntpdOptions, c)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* * * * * *
*
* Declare the ntpd option descriptor.
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
+extern tOptions ntpdOptions;
-extern tOptions ntpdOptions;
+#if defined(ENABLE_NLS)
+# ifndef _
+# include <stdio.h>
+# ifndef HAVE_GETTEXT
+ extern char * gettext(char const *);
+# else
+# include <libintl.h>
+# endif
-#ifndef _
-# if ENABLE_NLS
-# include <stdio.h>
- static inline char* aoGetsText( char const* pz ) {
- if (pz == NULL) return NULL;
- return (char*)gettext( pz );
- }
-# define _(s) aoGetsText(s)
-# else /* ENABLE_NLS */
-# define _(s) s
-# endif /* ENABLE_NLS */
-#endif
+# ifndef ATTRIBUTE_FORMAT_ARG
+# define ATTRIBUTE_FORMAT_ARG(_a)
+# endif
+
+static inline char* aoGetsText(char const* pz) ATTRIBUTE_FORMAT_ARG(1);
+static inline char* aoGetsText(char const* pz) {
+ if (pz == NULL) return NULL;
+ return (char*)gettext(pz);
+}
+# define _(s) aoGetsText(s)
+# endif /* _() */
+
+# define OPT_NO_XLAT_CFG_NAMES STMTS(ntpdOptions.fOptSet |= \
+ OPTPROC_NXLAT_OPT_CFG;)
+# define OPT_NO_XLAT_OPT_NAMES STMTS(ntpdOptions.fOptSet |= \
+ OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG;)
+
+# define OPT_XLAT_CFG_NAMES STMTS(ntpdOptions.fOptSet &= \
+ ~(OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG);)
+# define OPT_XLAT_OPT_NAMES STMTS(ntpdOptions.fOptSet &= \
+ ~OPTPROC_NXLAT_OPT;)
+
+#else /* ENABLE_NLS */
+# define OPT_NO_XLAT_CFG_NAMES
+# define OPT_NO_XLAT_OPT_NAMES
+
+# define OPT_XLAT_CFG_NAMES
+# define OPT_XLAT_OPT_NAMES
+
+# ifndef _
+# define _(_s) _s
+# endif
+#endif /* ENABLE_NLS */
#ifdef __cplusplus
}
#endif
#endif /* AUTOOPTS_NTPD_OPTS_H_GUARD */
+
/* ntpd-opts.h ends here */
diff --git a/contrib/ntp/ntpd/ntpd-opts.texi b/contrib/ntp/ntpd/ntpd-opts.texi
deleted file mode 100644
index 0491294..0000000
--- a/contrib/ntp/ntpd/ntpd-opts.texi
+++ /dev/null
@@ -1,496 +0,0 @@
-@node ntpd Invocation
-@section Invoking ntpd
-@pindex ntpd
-@cindex NTP daemon program
-@ignore
-#
-# EDIT THIS FILE WITH CAUTION (ntpd-opts.texi)
-#
-# It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:12 AM EST
-# From the definitions ntpd-opts.def
-# and the template file aginfo.tpl
-@end ignore
-This program has no explanation.
-
-
-
-This section was generated by @strong{AutoGen},
-the aginfo template and the option descriptions for the @command{ntpd} program. It documents the ntpd usage text and option meanings.
-
-This software is released under a specialized copyright license.
-
-@menu
-* ntpd usage:: ntpd usage help (-?)
-* ntpd authnoreq:: authnoreq option (-A)
-* ntpd authreq:: authreq option (-a)
-* ntpd bcastsync:: bcastsync option (-b)
-* ntpd configfile:: configfile option (-c)
-* ntpd debug-level:: debug-level option (-d)
-* ntpd driftfile:: driftfile option (-f)
-* ntpd dvar:: dvar option (-V)
-* ntpd interface:: interface option (-I)
-* ntpd ipv4:: ipv4 option (-4)
-* ntpd ipv6:: ipv6 option (-6)
-* ntpd jaildir:: jaildir option (-i)
-* ntpd keyfile:: keyfile option (-k)
-* ntpd logfile:: logfile option (-l)
-* ntpd modifymmtimer:: modifymmtimer option (-M)
-* ntpd nice:: nice option (-N)
-* ntpd nofork:: nofork option (-n)
-* ntpd novirtualips:: novirtualips option (-L)
-* ntpd panicgate:: panicgate option (-g)
-* ntpd pidfile:: pidfile option (-p)
-* ntpd priority:: priority option (-P)
-* ntpd propagationdelay:: propagationdelay option (-r)
-* ntpd quit:: quit option (-q)
-* ntpd set-debug-level:: set-debug-level option (-D)
-* ntpd slew:: slew option (-x)
-* ntpd statsdir:: statsdir option (-s)
-* ntpd trustedkey:: trustedkey option (-t)
-* ntpd updateinterval:: updateinterval option (-U)
-* ntpd user:: user option (-u)
-* ntpd var:: var option (-v)
-@end menu
-
-@node ntpd usage
-@subsection ntpd usage help (-?)
-@cindex ntpd usage
-
-This is the automatically generated usage text for ntpd:
-
-@exampleindent 0
-@example
-ntpd - NTP daemon program - Ver. 4.2.5p247-RC
-USAGE: ntpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
- Flg Arg Option-Name Description
- -4 no ipv4 Force IPv4 DNS name resolution
- - prohibits these options:
- ipv6
- -6 no ipv6 Force IPv6 DNS name resolution
- - prohibits these options:
- ipv4
- -a no authreq Require crypto authentication
- - prohibits these options:
- authnoreq
- -A no authnoreq Do not require crypto authentication
- - prohibits these options:
- authreq
- -b no bcastsync Allow us to sync to broadcast servers
- -c Str configfile configuration file name
- -d no debug-level Increase output debug message level
- - may appear multiple times
- -D Str set-debug-level Set the output debug message level
- - may appear multiple times
- -f Str driftfile frequency drift file name
- -g no panicgate Allow the first adjustment to be Big
- - may appear multiple times
- -i --- jaildir built without --enable-clockctl or --enable-linuxcaps
- -I Str interface Listen on an interface name or address
- - may appear multiple times
- -k Str keyfile path to symmetric keys
- -l Str logfile path to the log file
- -L no novirtualips Do not listen to virtual interfaces
- -n no nofork Do not fork
- -N no nice Run at high priority
- -p Str pidfile path to the PID file
- -P Num priority Process priority
- -q no quit Set the time and quit
- -r Str propagationdelay Broadcast/propagation delay
- Str saveconfigquit Save parsed configuration and quit
- -s Str statsdir Statistics file location
- -t Str trustedkey Trusted key number
- - may appear multiple times
- -u --- user built without --enable-clockctl or --enable-linuxcaps
- -U Num updateinterval interval in seconds between scans for new or dropped interfaces
- Str var make ARG an ntp variable (RW)
- - may appear multiple times
- Str dvar make ARG an ntp variable (RW|DEF)
- - may appear multiple times
- -x no slew Slew up to 600 seconds
- opt version Output version information and exit
- -? no help Display extended usage information and exit
- -! no more-help Extended usage information passed thru pager
-
-Options are specified by doubled hyphens and their name
-or by a single hyphen and the flag character.
-
-The following option preset mechanisms are supported:
- - examining environment variables named NTPD_*
-
-
-
-please send bug reports to: http://bugs.ntp.org, bugs@@ntp.org
-@end example
-@exampleindent 4
-
-@node ntpd ipv4
-@subsection ipv4 option (-4)
-@cindex ntpd-ipv4
-
-This is the ``force ipv4 dns name resolution'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-is a member of the ipv4 class of options.
-@end itemize
-
-Force DNS resolution of following host names on the command line
-to the IPv4 namespace.
-
-@node ntpd ipv6
-@subsection ipv6 option (-6)
-@cindex ntpd-ipv6
-
-This is the ``force ipv6 dns name resolution'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-is a member of the ipv4 class of options.
-@end itemize
-
-Force DNS resolution of following host names on the command line
-to the IPv6 namespace.
-
-@node ntpd authreq
-@subsection authreq option (-a)
-@cindex ntpd-authreq
-
-This is the ``require crypto authentication'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-must not appear in combination with any of the following options:
-authnoreq.
-@end itemize
-
-Require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is the default.
-
-@node ntpd authnoreq
-@subsection authnoreq option (-A)
-@cindex ntpd-authnoreq
-
-This is the ``do not require crypto authentication'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-must not appear in combination with any of the following options:
-authreq.
-@end itemize
-
-Do not require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is almost never a good idea.
-
-@node ntpd bcastsync
-@subsection bcastsync option (-b)
-@cindex ntpd-bcastsync
-
-This is the ``allow us to sync to broadcast servers'' option.
-
-
-@node ntpd configfile
-@subsection configfile option (-c)
-@cindex ntpd-configfile
-
-This is the ``configuration file name'' option.
-The name and path of the configuration file,
-/etc/ntp.conf
-by default.
-
-@node ntpd debug-level
-@subsection debug-level option (-d)
-@cindex ntpd-debug-level
-
-This is the ``increase output debug message level'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@item
-must be compiled in by defining @code{DEBUG} during the compilation.
-@end itemize
-
-Increase the debugging message output level.
-
-@node ntpd set-debug-level
-@subsection set-debug-level option (-D)
-@cindex ntpd-set-debug-level
-
-This is the ``set the output debug message level'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@item
-must be compiled in by defining @code{DEBUG} during the compilation.
-@end itemize
-
-Set the output debugging level. Can be supplied multiple times,
-but each overrides the previous value(s).
-
-@node ntpd driftfile
-@subsection driftfile option (-f)
-@cindex ntpd-driftfile
-
-This is the ``frequency drift file name'' option.
-The name and path of the frequency file,
-/etc/ntp.drift
-by default.
-This is the same operation as the
-driftfile driftfile
-configuration specification in the
-/etc/ntp.conf
-file.
-
-@node ntpd panicgate
-@subsection panicgate option (-g)
-@cindex ntpd-panicgate
-
-This is the ``allow the first adjustment to be big'' option.
-Normally,
-ntpd
-exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
-ntpd
-will exit with a message to the system log. This option can be used with the
--q
-and
--x
-options.
-See the
-tinker
-configuration file directive for other options.
-
-@node ntpd jaildir
-@subsection jaildir option (-i)
-@cindex ntpd-jaildir
-
-This is the ``jail directory'' option.
-Chroot the server to the directory
-jaildir
-.
-This option also implies that the server attempts to drop root privileges at startup (otherwise, chroot gives very little additional security), and it is only available if the OS supports to run the server without full root privileges.
-You may need to also specify a
--u
-option.
-
-@node ntpd interface
-@subsection interface option (-I)
-@cindex ntpd-interface
-
-This is the ``listen on interface'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-
-
-@node ntpd keyfile
-@subsection keyfile option (-k)
-@cindex ntpd-keyfile
-
-This is the ``path to symmetric keys'' option.
-Specify the name and path of the symmetric key file.
-/etc/ntp.keys
-is the default.
-This is the same operation as the
-keys keyfile
-configuration file directive.
-
-@node ntpd logfile
-@subsection logfile option (-l)
-@cindex ntpd-logfile
-
-This is the ``path to the log file'' option.
-Specify the name and path of the log file.
-The default is the system log file.
-This is the same operation as the
-logfile logfile
-configuration file directive.
-
-@node ntpd novirtualips
-@subsection novirtualips option (-L)
-@cindex ntpd-novirtualips
-
-This is the ``do not listen to virtual ips'' option.
-Do not listen to virtual IPs. The default is to listen.
-
-@node ntpd modifymmtimer
-@subsection modifymmtimer option (-M)
-@cindex ntpd-modifymmtimer
-
-This is the ``modify multimedia timer (windows only)'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-must be compiled in by defining @code{SYS_WINNT} during the compilation.
-@end itemize
-
-Set the Windows Multimedia Timer to highest resolution.
-
-@node ntpd nofork
-@subsection nofork option (-n)
-@cindex ntpd-nofork
-
-This is the ``do not fork'' option.
-
-
-@node ntpd nice
-@subsection nice option (-N)
-@cindex ntpd-nice
-
-This is the ``run at high priority'' option.
-To the extent permitted by the operating system, run
-ntpd
-at the highest priority.
-
-@node ntpd pidfile
-@subsection pidfile option (-p)
-@cindex ntpd-pidfile
-
-This is the ``path to the pid file'' option.
-Specify the name and path of the file used to record
-ntpd's
-process ID.
-This is the same operation as the
-pidfile pidfile
-configuration file directive.
-
-@node ntpd priority
-@subsection priority option (-P)
-@cindex ntpd-priority
-
-This is the ``process priority'' option.
-To the extent permitted by the operating system, run
-ntpd
-at the specified
-sched_setscheduler(SCHED_FIFO)
-priority.
-
-@node ntpd quit
-@subsection quit option (-q)
-@cindex ntpd-quit
-
-This is the ``set the time and quit'' option.
-ntpd
-will exit just after the first time the clock is set. This behavior mimics that of the
-ntpdate
-program, which is to be retired.
-The
--g
-and
--x
-options can be used with this option.
-Note: The kernel time discipline is disabled with this option.
-
-@node ntpd propagationdelay
-@subsection propagationdelay option (-r)
-@cindex ntpd-propagationdelay
-
-This is the ``broadcast/propagation delay'' option.
-Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
-
-@node ntpd updateinterval
-@subsection updateinterval option (-U)
-@cindex ntpd-updateinterval
-
-This is the ``interval in seconds between scans for new or dropped interfaces'' option.
-Give the time in seconds between two scans for new or dropped interfaces.
-For systems with routing socket support the scans will be performed shortly after the interface change
-has been detected by the system.
-Use 0 to disable scanning.
-
-@node ntpd statsdir
-@subsection statsdir option (-s)
-@cindex ntpd-statsdir
-
-This is the ``statistics file location'' option.
-Specify the directory path for files created by the statistics facility.
-This is the same operation as the
-statsdir statsdir
-configuration file directive.
-
-@node ntpd trustedkey
-@subsection trustedkey option (-t)
-@cindex ntpd-trustedkey
-
-This is the ``trusted key number'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-Add a key number to the trusted key list.
-
-@node ntpd user
-@subsection user option (-u)
-@cindex ntpd-user
-
-This is the ``run as userid (or userid:groupid)'' option.
-Specify a user, and optionally a group, to switch to.
-This option is only available if the OS supports to run the server without full root privileges.
-Currently, this option is supported under NetBSD (configure with
---enable-clockctl
-) and Linux (configure with
---enable-linuxcaps
-).
-
-@node ntpd var
-@subsection var option (-v)
-@cindex ntpd-var
-
-This is the ``make arg an ntp variable (rw)'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-
-
-@node ntpd dvar
-@subsection dvar option (-V)
-@cindex ntpd-dvar
-
-This is the ``make arg an ntp variable (rw|def)'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-
-
-@node ntpd slew
-@subsection slew option (-x)
-@cindex ntpd-slew
-
-This is the ``slew up to 600 seconds'' option.
-Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
-This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
-Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
-Thus, an adjustment as much as 600 s will take almost 14 days to complete.
-This option can be used with the
--g
-and
--q
-options.
-See the
-tinker
-configuration file directive for other options.
-Note: The kernel time discipline is disabled with this option.
diff --git a/contrib/ntp/ntpd/ntpd.1 b/contrib/ntp/ntpd/ntpd.1
deleted file mode 100644
index ec0a0ed..0000000
--- a/contrib/ntp/ntpd/ntpd.1
+++ /dev/null
@@ -1,296 +0,0 @@
-.TH NTPD 1 2009-12-08 "( 4.2.4p8)" "Programmer's Manual"
-.\" EDIT THIS FILE WITH CAUTION (ntpd.1)
-.\"
-.\" It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:11 AM EST
-.\" From the definitions ntpd-opts.def
-.\" and the template file agman1.tpl
-.\"
-.SH NAME
-ntpd \- NTP daemon program
-.SH SYNOPSIS
-.B ntpd
-.\" Mixture of short (flag) options and long options
-.RB [ \-\fIflag\fP " [\fIvalue\fP]]... [" \--\fIopt-name\fP " [[=| ]\fIvalue\fP]]..."
-.PP
-All arguments must be options.
-.SH "DESCRIPTION"
-This manual page documents, briefly, the \fBntpd\fP command.
-
-.SH OPTIONS
-.TP
-.BR \-4 ", " \--ipv4
-Force IPv4 DNS name resolution.
-This option is a member of the ipv4 class of options.
-.sp
-Force DNS resolution of following host names on the command line
-to the IPv4 namespace.
-.TP
-.BR \-6 ", " \--ipv6
-Force IPv6 DNS name resolution.
-This option is a member of the ipv4 class of options.
-.sp
-Force DNS resolution of following host names on the command line
-to the IPv6 namespace.
-.TP
-.BR \-a ", " \--authreq
-Require crypto authentication.
-This option must not appear in combination with any of the following options:
-authnoreq.
-.sp
-Require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is the default.
-.TP
-.BR \-A ", " \--authnoreq
-Do not require crypto authentication.
-This option must not appear in combination with any of the following options:
-authreq.
-.sp
-Do not require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is almost never a good idea.
-.TP
-.BR \-b ", " \--bcastsync
-Allow us to sync to broadcast servers.
-.sp
-
-.TP
-.BR \-c " \fIstring\fP, " \--configfile "=" \fIstring\fP
-configuration file name.
-.sp
-The name and path of the configuration file,
-/etc/ntp.conf
-by default.
-.TP
-.BR \-d ", " \--debug-level
-Increase output debug message level.
-This option may appear an unlimited number of times.
-.sp
-Increase the debugging message output level.
-.TP
-.BR \-D " \fIstring\fP, " \--set-debug-level "=" \fIstring\fP
-Set the output debug message level.
-This option may appear an unlimited number of times.
-.sp
-Set the output debugging level. Can be supplied multiple times,
-but each overrides the previous value(s).
-.TP
-.BR \-f " \fIstring\fP, " \--driftfile "=" \fIstring\fP
-frequency drift file name.
-.sp
-The name and path of the frequency file,
-/etc/ntp.drift
-by default.
-This is the same operation as the
-driftfile driftfile
-configuration specification in the
-/etc/ntp.conf
-file.
-.TP
-.BR \-g ", " \--panicgate
-Allow the first adjustment to be Big.
-.sp
-Normally,
-ntpd
-exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
-ntpd
-will exit with a message to the system log. This option can be used with the
--q
-and
--x
-options.
-See the
-tinker
-configuration file directive for other options.
-.TP
-.BR \-i " \fIstring\fP, " \--jaildir "=" \fIstring\fP
-Jail directory.
-.sp
-Chroot the server to the directory
-jaildir
-.
-This option also implies that the server attempts to drop root privileges at startup (otherwise, chroot gives very little additional security), and it is only available if the OS supports to run the server without full root privileges.
-You may need to also specify a
--u
-option.
-.TP
-.BR \-I " \fIiface\fP, " \--interface "=" \fIiface\fP
-Listen on interface.
-This option may appear an unlimited number of times.
-.sp
-
-.TP
-.BR \-k " \fIstring\fP, " \--keyfile "=" \fIstring\fP
-path to symmetric keys.
-.sp
-Specify the name and path of the symmetric key file.
-/etc/ntp.keys
-is the default.
-This is the same operation as the
-keys keyfile
-configuration file directive.
-.TP
-.BR \-l " \fIstring\fP, " \--logfile "=" \fIstring\fP
-path to the log file.
-.sp
-Specify the name and path of the log file.
-The default is the system log file.
-This is the same operation as the
-logfile logfile
-configuration file directive.
-.TP
-.BR \-L ", " \--novirtualips
-Do not listen to virtual IPs.
-.sp
-Do not listen to virtual IPs. The default is to listen.
-.TP
-.BR \-M ", " \--modifymmtimer
-Modify Multimedia Timer (Windows only).
-.sp
-Set the Windows Multimedia Timer to highest resolution.
-.TP
-.BR \-n ", " \--nofork
-Do not fork.
-.sp
-
-.TP
-.BR \-N ", " \--nice
-Run at high priority.
-.sp
-To the extent permitted by the operating system, run
-ntpd
-at the highest priority.
-.TP
-.BR \-p " \fIstring\fP, " \--pidfile "=" \fIstring\fP
-path to the PID file.
-.sp
-Specify the name and path of the file used to record
-ntpd's
-process ID.
-This is the same operation as the
-pidfile pidfile
-configuration file directive.
-.TP
-.BR \-P " \fInumber\fP, " \--priority "=" \fInumber\fP
-Process priority.
-This option takes an integer number as its argument.
-.sp
-To the extent permitted by the operating system, run
-ntpd
-at the specified
-sched_setscheduler(SCHED_FIFO)
-priority.
-.TP
-.BR \-q ", " \--quit
-Set the time and quit.
-.sp
-ntpd
-will exit just after the first time the clock is set. This behavior mimics that of the
-ntpdate
-program, which is to be retired.
-The
--g
-and
--x
-options can be used with this option.
-Note: The kernel time discipline is disabled with this option.
-.TP
-.BR \-r " \fIstring\fP, " \--propagationdelay "=" \fIstring\fP
-Broadcast/propagation delay.
-.sp
-Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
-.TP
-.BR \-U " \fInumber\fP, " \--updateinterval "=" \fInumber\fP
-interval in seconds between scans for new or dropped interfaces.
-This option takes an integer number as its argument.
-.sp
-Give the time in seconds between two scans for new or dropped interfaces.
-For systems with routing socket support the scans will be performed shortly after the interface change
-has been detected by the system.
-Use 0 to disable scanning.
-.TP
-.BR \-s " \fIstring\fP, " \--statsdir "=" \fIstring\fP
-Statistics file location.
-.sp
-Specify the directory path for files created by the statistics facility.
-This is the same operation as the
-statsdir statsdir
-configuration file directive.
-.TP
-.BR \-t " \fItkey\fP, " \--trustedkey "=" \fItkey\fP
-Trusted key number.
-This option may appear an unlimited number of times.
-.sp
-Add a key number to the trusted key list.
-.TP
-.BR \-u " \fIstring\fP, " \--user "=" \fIstring\fP
-Run as userid (or userid:groupid).
-.sp
-Specify a user, and optionally a group, to switch to.
-This option is only available if the OS supports to run the server without full root privileges.
-Currently, this option is supported under NetBSD (configure with
---enable-clockctl
-) and Linux (configure with
---enable-linuxcaps
-).
-.TP
-.BR \-v " \fInvar\fP, " \--var "=" \fInvar\fP
-make ARG an ntp variable (RW).
-This option may appear an unlimited number of times.
-.sp
-
-.TP
-.BR \-V " \fIndvar\fP, " \--dvar "=" \fIndvar\fP
-make ARG an ntp variable (RW|DEF).
-This option may appear an unlimited number of times.
-.sp
-
-.TP
-.BR \-x ", " \--slew
-Slew up to 600 seconds.
-.sp
-Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
-This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
-Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
-Thus, an adjustment as much as 600 s will take almost 14 days to complete.
-This option can be used with the
--g
-and
--q
-options.
-See the
-tinker
-configuration file directive for other options.
-Note: The kernel time discipline is disabled with this option.
-.TP
-.BR \-? , " \--help"
-Display usage information and exit.
-.TP
-.BR \-! , " \--more-help"
-Extended usage information passed thru pager.
-.TP
-.BR \-v " [{\fIv|c|n\fP}]," " \--version" "[=\fI{v|c|n}\fP]"
-Output version of program and exit. The default mode is `v', a simple
-version. The `c' mode will print copyright information and `n' will
-print the full copyright notice.
-.SH OPTION PRESETS
-Any option that is not marked as \fInot presettable\fP may be preset
-by loading values from environment variables named:
-.nf
- \fBNTPD_<option-name>\fP or \fBNTPD\fP
-.fi
-.aj
-.SH AUTHOR
-David L. Mills and/or others
-.br
-Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
-
-.PP
-.nf
-.na
-see html/copyright.html
-.fi
-.ad
-.PP
-This manual page was \fIAutoGen\fP-erated from the \fBntpd\fP
-option definitions.
diff --git a/contrib/ntp/ntpd/ntpd.1ntpdman b/contrib/ntp/ntpd/ntpd.1ntpdman
new file mode 100644
index 0000000..c231b7f
--- /dev/null
+++ b/contrib/ntp/ntpd/ntpd.1ntpdman
@@ -0,0 +1,1001 @@
+.de1 NOP
+. it 1 an-trap
+. if \\n[.$] \,\\$*\/
+..
+.ie t \
+.ds B-Font [CB]
+.ds I-Font [CI]
+.ds R-Font [CR]
+.el \
+.ds B-Font B
+.ds I-Font I
+.ds R-Font R
+.TH ntpd 1ntpdman "29 Jun 2015" "4.2.8p3" "User Commands"
+.\"
+.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-LZaapD/ag-XZa4nD)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:24 PM by AutoGen 5.18.5
+.\" From the definitions ntpd-opts.def
+.\" and the template file agman-cmd.tpl
+.SH NAME
+\f\*[B-Font]ntpd\fP
+\- NTP daemon program
+.SH SYNOPSIS
+\f\*[B-Font]ntpd\fP
+.\" Mixture of short (flag) options and long options
+[\f\*[B-Font]\-flags\f[]]
+[\f\*[B-Font]\-flag\f[] [\f\*[I-Font]value\f[]]]
+[\f\*[B-Font]\-\-option-name\f[][[=| ]\f\*[I-Font]value\f[]]]
+[ <server1> ... <serverN> ]
+.sp \n(Ppu
+.ne 2
+
+.SH DESCRIPTION
+The
+\f\*[B-Font]ntpd\fP
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC-5905,
+but also retains compatibility with
+version 3, as defined by RFC-1305, and versions 1
+and 2, as defined by RFC-1059 and RFC-1119, respectively.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]ntpd\fP
+utility does most computations in 64-bit floating point
+arithmetic and does relatively clumsy 64-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+.sp \n(Ppu
+.ne 2
+
+Ordinarily,
+\f\*[B-Font]ntpd\fP
+reads the
+\fCntp.conf\f[]\fR(5)\f[]
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+.sp \n(Ppu
+.ne 2
+
+If NetInfo support is built into
+\f\*[B-Font]ntpd\fP,
+then
+\f\*[B-Font]ntpd\fP
+will attempt to read its configuration from the
+NetInfo if the default
+\fCntp.conf\f[]\fR(5)\f[]
+file cannot be read and no file is
+specified by the
+\f\*[B-Font]\-c\f[]
+option.
+.sp \n(Ppu
+.ne 2
+
+Various internal
+\f\*[B-Font]ntpd\fP
+variables can be displayed and
+configuration options altered while the
+\f\*[B-Font]ntpd\fP
+is running
+using the
+\fCntpq\f[]\fR(1ntpqmdoc)\f[]
+and
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[]
+utility programs.
+.sp \n(Ppu
+.ne 2
+
+When
+\f\*[B-Font]ntpd\fP
+starts it looks at the value of
+\fCumask\f[]\fR(2)\f[],
+and if zero
+\f\*[B-Font]ntpd\fP
+will set the
+\fCumask\f[]\fR(2)\f[]
+to 022.
+.SH "OPTIONS"
+.TP
+.NOP \f\*[B-Font]\-4\f[], \f\*[B-Font]\-\-ipv4\f[]
+Force IPv4 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv6.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+.TP
+.NOP \f\*[B-Font]\-6\f[], \f\*[B-Font]\-\-ipv6\f[]
+Force IPv6 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv4.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+.TP
+.NOP \f\*[B-Font]\-a\f[], \f\*[B-Font]\-\-authreq\f[]
+Require crypto authentication.
+This option must not appear in combination with any of the following options:
+authnoreq.
+.sp
+Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+.TP
+.NOP \f\*[B-Font]\-A\f[], \f\*[B-Font]\-\-authnoreq\f[]
+Do not require crypto authentication.
+This option must not appear in combination with any of the following options:
+authreq.
+.sp
+Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+.TP
+.NOP \f\*[B-Font]\-b\f[], \f\*[B-Font]\-\-bcastsync\f[]
+Allow us to sync to broadcast servers.
+.sp
+.TP
+.NOP \f\*[B-Font]\-c\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-configfile\f[]=\f\*[I-Font]string\f[]
+configuration file name.
+.sp
+The name and path of the configuration file,
+\fI/etc/ntp.conf\fP
+by default.
+.TP
+.NOP \f\*[B-Font]\-d\f[], \f\*[B-Font]\-\-debug\-level\f[]
+Increase debug verbosity level.
+This option may appear an unlimited number of times.
+.sp
+.TP
+.NOP \f\*[B-Font]\-D\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-set\-debug\-level\f[]=\f\*[I-Font]number\f[]
+Set the debug verbosity level.
+This option may appear an unlimited number of times.
+This option takes an integer number as its argument.
+.sp
+.TP
+.NOP \f\*[B-Font]\-f\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-driftfile\f[]=\f\*[I-Font]string\f[]
+frequency drift file name.
+.sp
+The name and path of the frequency file,
+\fI/etc/ntp.drift\fP
+by default.
+This is the same operation as the
+\fBdriftfile\fP \fIdriftfile\fP
+configuration specification in the
+\fI/etc/ntp.conf\fP
+file.
+.TP
+.NOP \f\*[B-Font]\-g\f[], \f\*[B-Font]\-\-panicgate\f[]
+Allow the first adjustment to be Big.
+This option may appear an unlimited number of times.
+.sp
+Normally,
+\fBntpd\fP
+exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
+\fBntpd\fP
+will exit with a message to the system log. This option can be used with the
+\fB-q\fP
+and
+\fB-x\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+.TP
+.NOP \f\*[B-Font]\-G\f[], \f\*[B-Font]\-\-force\-step\-once\f[]
+Step any initial offset correction..
+.sp
+Normally,
+\fBntpd\fP
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the \fBtinker\fP configuration file directive for other options.
+.TP
+.NOP \f\*[B-Font]\-i\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-jaildir\f[]=\f\*[I-Font]string\f[]
+Jail directory.
+.sp
+Chroot the server to the directory
+\fIjaildir\fP
+.
+This option also implies that the server attempts to drop root privileges at startup.
+You may need to also specify a
+\fB-u\fP
+option.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB--enable-clockctl\fP) or Linux (configure with
+\fB--enable-linuxcaps\fP) or Solaris (configure with \fB--enable-solarisprivs\fP).
+.TP
+.NOP \f\*[B-Font]\-I\f[] \f\*[I-Font]iface\f[], \f\*[B-Font]\-\-interface\f[]=\f\*[I-Font]iface\f[]
+Listen on an interface name or address.
+This option may appear an unlimited number of times.
+.sp
+Open the network address given, or all the addresses associated with the
+given interface name. This option may appear multiple times. This option
+also implies not opening other addresses, except wildcard and localhost.
+This option is deprecated. Please consider using the configuration file
+\fBinterface\fP command, which is more versatile.
+.TP
+.NOP \f\*[B-Font]\-k\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-keyfile\f[]=\f\*[I-Font]string\f[]
+path to symmetric keys.
+.sp
+Specify the name and path of the symmetric key file.
+\fI/etc/ntp.keys\fP
+is the default.
+This is the same operation as the
+\fBkeys\fP \fIkeyfile\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-l\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-logfile\f[]=\f\*[I-Font]string\f[]
+path to the log file.
+.sp
+Specify the name and path of the log file.
+The default is the system log file.
+This is the same operation as the
+\fBlogfile\fP \fIlogfile\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-L\f[], \f\*[B-Font]\-\-novirtualips\f[]
+Do not listen to virtual interfaces.
+.sp
+Do not listen to virtual interfaces, defined as those with
+names containing a colon. This option is deprecated. Please
+consider using the configuration file \fBinterface\fP command, which
+is more versatile.
+.TP
+.NOP \f\*[B-Font]\-M\f[], \f\*[B-Font]\-\-modifymmtimer\f[]
+Modify Multimedia Timer (Windows only).
+.sp
+Set the Windows Multimedia Timer to highest resolution. This
+ensures the resolution does not change while ntpd is running,
+avoiding timekeeping glitches associated with changes.
+.TP
+.NOP \f\*[B-Font]\-n\f[], \f\*[B-Font]\-\-nofork\f[]
+Do not fork.
+This option must not appear in combination with any of the following options:
+wait-sync.
+.sp
+.TP
+.NOP \f\*[B-Font]\-N\f[], \f\*[B-Font]\-\-nice\f[]
+Run at high priority.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the highest priority.
+.TP
+.NOP \f\*[B-Font]\-p\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-pidfile\f[]=\f\*[I-Font]string\f[]
+path to the PID file.
+.sp
+Specify the name and path of the file used to record
+\fBntpd\fP's
+process ID.
+This is the same operation as the
+\fBpidfile\fP \fIpidfile\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-P\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-priority\f[]=\f\*[I-Font]number\f[]
+Process priority.
+This option takes an integer number as its argument.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the specified
+\fBsched_setscheduler(SCHED_FIFO)\fP
+priority.
+.TP
+.NOP \f\*[B-Font]\-q\f[], \f\*[B-Font]\-\-quit\f[]
+Set the time and quit.
+This option must not appear in combination with any of the following options:
+saveconfigquit, wait-sync.
+.sp
+\fBntpd\fP
+will not daemonize and will exit after the clock is first
+synchronized. This behavior mimics that of the
+\fBntpdate\fP
+program, which will soon be replaced with a shell script.
+The
+\fB-g\fP
+and
+\fB-x\fP
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+.TP
+.NOP \f\*[B-Font]\-r\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-propagationdelay\f[]=\f\*[I-Font]string\f[]
+Broadcast/propagation delay.
+.sp
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+.TP
+.NOP \f\*[B-Font]\-\-saveconfigquit\f[]=\f\*[I-Font]string\f[]
+Save parsed configuration and quit.
+This option must not appear in combination with any of the following options:
+quit, wait-sync.
+.sp
+Cause \fBntpd\fP to parse its startup configuration file and save an
+equivalent to the given filename and exit. This option was
+designed for automated testing.
+.TP
+.NOP \f\*[B-Font]\-s\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-statsdir\f[]=\f\*[I-Font]string\f[]
+Statistics file location.
+.sp
+Specify the directory path for files created by the statistics facility.
+This is the same operation as the
+\fBstatsdir\fP \fIstatsdir\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-t\f[] \f\*[I-Font]tkey\f[], \f\*[B-Font]\-\-trustedkey\f[]=\f\*[I-Font]tkey\f[]
+Trusted key number.
+This option may appear an unlimited number of times.
+.sp
+Add the specified key number to the trusted key list.
+.TP
+.NOP \f\*[B-Font]\-u\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-user\f[]=\f\*[I-Font]string\f[]
+Run as userid (or userid:groupid).
+.sp
+Specify a user, and optionally a group, to switch to.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB--enable-clockctl\fP) or Linux (configure with
+\fB--enable-linuxcaps\fP) or Solaris (configure with \fB--enable-solarisprivs\fP).
+.TP
+.NOP \f\*[B-Font]\-U\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-updateinterval\f[]=\f\*[I-Font]number\f[]
+interval in seconds between scans for new or dropped interfaces.
+This option takes an integer number as its argument.
+.sp
+Give the time in seconds between two scans for new or dropped interfaces.
+For systems with routing socket support the scans will be performed shortly after the interface change
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+.TP
+.NOP \f\*[B-Font]\-\-var\f[]=\f\*[I-Font]nvar\f[]
+make ARG an ntp variable (RW).
+This option may appear an unlimited number of times.
+.sp
+.TP
+.NOP \f\*[B-Font]\-\-dvar\f[]=\f\*[I-Font]ndvar\f[]
+make ARG an ntp variable (RW|DEF).
+This option may appear an unlimited number of times.
+.sp
+.TP
+.NOP \f\*[B-Font]\-w\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-wait\-sync\f[]=\f\*[I-Font]number\f[]
+Seconds to wait for first clock sync.
+This option must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+This option takes an integer number as its argument.
+.sp
+If greater than zero, alters \fBntpd\fP's behavior when forking to
+daemonize. Instead of exiting with status 0 immediately after
+the fork, the parent waits up to the specified number of
+seconds for the child to first synchronize the clock. The exit
+status is zero (success) if the clock was synchronized,
+otherwise it is \fBETIMEDOUT\fP.
+This provides the option for a script starting \fBntpd\fP to easily
+wait for the first set of the clock before proceeding.
+.TP
+.NOP \f\*[B-Font]\-x\f[], \f\*[B-Font]\-\-slew\f[]
+Slew up to 600 seconds.
+.sp
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+This option can be used with the
+\fB-g\fP
+and
+\fB-q\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+.TP
+.NOP \f\*[B-Font]\-\-usepcc\f[]
+Use CPU cycle counter (Windows only).
+.sp
+Attempt to substitute the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter and \fBQueryPerformanceCounter\fP are compared, and if
+they have the same frequency, the CPU counter (RDTSC on x86) is
+used directly, saving the overhead of a system call.
+.TP
+.NOP \f\*[B-Font]\-\-pccfreq\f[]=\f\*[I-Font]string\f[]
+Force CPU cycle counter use (Windows only).
+.sp
+Force substitution the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter (RDTSC on x86) is used unconditionally with the
+given frequency (in Hz).
+.TP
+.NOP \f\*[B-Font]\-m\f[], \f\*[B-Font]\-\-mdns\f[]
+Register with mDNS as a NTP server.
+.sp
+Registers as an NTP server with the local mDNS server which allows
+the server to be discovered via mDNS client lookup.
+.TP
+.NOP \f\*[B-Font]\-\&?\f[], \f\*[B-Font]\-\-help\f[]
+Display usage information and exit.
+.TP
+.NOP \f\*[B-Font]\-\&!\f[], \f\*[B-Font]\-\-more-help\f[]
+Pass the extended usage information through a pager.
+.TP
+.NOP \f\*[B-Font]\-\-version\f[] [{\f\*[I-Font]v|c|n\f[]}]
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.PP
+.SH "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTPD_<option-name>\fP or \fBNTPD\fP
+.fi
+.ad
+.SH USAGE
+.SS "How NTP Operates"
+The
+\f\*[B-Font]ntpd\fP
+utility operates by exchanging messages with
+one or more configured servers over a range of designated poll intervals.
+When
+started, whether for the first or subsequent times, the program
+requires several exchanges from the majority of these servers so
+the signal processing and mitigation algorithms can accumulate and
+groom the data and set the clock.
+In order to protect the network
+from bursts, the initial poll interval for each server is delayed
+an interval randomized over a few seconds.
+At the default initial poll
+interval of 64s, several minutes can elapse before the clock is
+set.
+This initial delay to set the clock
+can be safely and dramatically reduced using the
+\f\*[B-Font]iburst\f[]
+keyword with the
+\f\*[B-Font]server\f[]
+configuration
+command, as described in
+\fCntp.conf\f[]\fR(5)\f[].
+.sp \n(Ppu
+.ne 2
+
+Most operating systems and hardware of today incorporate a
+time-of-year (TOY) chip to maintain the time during periods when
+the power is off.
+When the machine is booted, the chip is used to
+initialize the operating system time.
+After the machine has
+synchronized to a NTP server, the operating system corrects the
+chip from time to time.
+In the default case, if
+\f\*[B-Font]ntpd\fP
+detects that the time on the host
+is more than 1000s from the server time,
+\f\*[B-Font]ntpd\fP
+assumes something must be terribly wrong and the only
+reliable action is for the operator to intervene and set the clock
+by hand.
+(Reasons for this include there is no TOY chip,
+or its battery is dead, or that the TOY chip is just of poor quality.)
+This causes
+\f\*[B-Font]ntpd\fP
+to exit with a panic message to
+the system log.
+The
+\f\*[B-Font]\-g\f[]
+option overrides this check and the
+clock will be set to the server time regardless of the chip time
+(up to 68 years in the past or future \(em
+this is a limitation of the NTPv4 protocol).
+However, and to protect against broken hardware, such as when the
+CMOS battery fails or the clock counter becomes defective, once the
+clock has been set an error greater than 1000s will cause
+\f\*[B-Font]ntpd\fP
+to exit anyway.
+.sp \n(Ppu
+.ne 2
+
+Under ordinary conditions,
+\f\*[B-Font]ntpd\fP
+adjusts the clock in
+small steps so that the timescale is effectively continuous and
+without discontinuities.
+Under conditions of extreme network
+congestion, the roundtrip delay jitter can exceed three seconds and
+the synchronization distance, which is equal to one-half the
+roundtrip delay plus error budget terms, can become very large.
+The
+\f\*[B-Font]ntpd\fP
+algorithms discard sample offsets exceeding 128 ms,
+unless the interval during which no sample offset is less than 128
+ms exceeds 900s.
+The first sample after that, no matter what the
+offset, steps the clock to the indicated time.
+In practice this
+reduces the false alarm rate where the clock is stepped in error to
+a vanishingly low incidence.
+.sp \n(Ppu
+.ne 2
+
+As the result of this behavior, once the clock has been set it
+very rarely strays more than 128 ms even under extreme cases of
+network path congestion and jitter.
+Sometimes, in particular when
+\f\*[B-Font]ntpd\fP
+is first started without a valid drift file
+on a system with a large intrinsic drift
+the error might grow to exceed 128 ms,
+which would cause the clock to be set backwards
+if the local clock time is more than 128 s
+in the future relative to the server.
+In some applications, this behavior may be unacceptable.
+There are several solutions, however.
+If the
+\f\*[B-Font]\-x\f[]
+option is included on the command line, the clock will
+never be stepped and only slew corrections will be used.
+But this choice comes with a cost that
+should be carefully explored before deciding to use
+the
+\f\*[B-Font]\-x\f[]
+option.
+The maximum slew rate possible is limited
+to 500 parts-per-million (PPM) as a consequence of the correctness
+principles on which the NTP protocol and algorithm design are
+based.
+As a result, the local clock can take a long time to
+converge to an acceptable offset, about 2,000 s for each second the
+clock is outside the acceptable range.
+During this interval the
+local clock will not be consistent with any other network clock and
+the system cannot be used for distributed applications that require
+correctly synchronized network time.
+.sp \n(Ppu
+.ne 2
+
+In spite of the above precautions, sometimes when large
+frequency errors are present the resulting time offsets stray
+outside the 128-ms range and an eventual step or slew time
+correction is required.
+If following such a correction the
+frequency error is so large that the first sample is outside the
+acceptable range,
+\f\*[B-Font]ntpd\fP
+enters the same state as when the
+\fIntp.drift\f[]
+file is not present.
+The intent of this behavior
+is to quickly correct the frequency and restore operation to the
+normal tracking mode.
+In the most extreme cases
+(the host
+\f\*[B-Font]time.ien.it\f[]
+comes to mind), there may be occasional
+step/slew corrections and subsequent frequency corrections.
+It
+helps in these cases to use the
+\f\*[B-Font]burst\f[]
+keyword when
+configuring the server, but
+ONLY
+when you have permission to do so from the owner of the target host.
+.sp \n(Ppu
+.ne 2
+
+Finally,
+in the past many startup scripts would run
+\fCntpdate\f[]\fR(1ntpdatemdoc)\f[]
+to get the system clock close to correct before starting
+\fCntpd\f[]\fR(1ntpdmdoc)\f[],
+but this was never more than a mediocre hack and is no longer needed.
+If you are following the instructions in
+\fIStarting NTP (Best Current Practice)\f[]
+and you still need to set the system time before starting
+\f\*[B-Font]ntpd\fP,
+please open a bug report and document what is going on,
+and then look at using
+\fCsntp\f[]\fR(1sntpmdoc)\f[].
+.sp \n(Ppu
+.ne 2
+
+There is a way to start
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+that often addresses all of the problems mentioned above.
+.SS "Starting NTP (Best Current Practice)"
+First, use the
+\f\*[B-Font]iburst\f[]
+option on your
+\f\*[B-Font]server\f[]
+entries.
+.sp \n(Ppu
+.ne 2
+
+If you can also keep a good
+\fIntp.drift\f[]
+file then
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+will effectively "warm-start" and your system's clock will
+be stable in under 11 seconds' time.
+.sp \n(Ppu
+.ne 2
+
+As soon as possible in the startup sequence, start
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+with at least the
+\f\*[B-Font]\-g\f[]
+and perhaps the
+\f\*[B-Font]\-N\f[]
+options.
+Then,
+start the rest of your "normal" processes.
+This will give
+\fCntpd\f[]\fR(1ntpdmdoc)\f[]
+as much time as possible to get the system's clock synchronized and stable.
+.sp \n(Ppu
+.ne 2
+
+Finally,
+if you have processes like
+\f\*[B-Font]dovecot\f[]
+or database servers
+that require
+monotonically-increasing time,
+run
+\fCntp-wait\f[]\fR(1ntp-waitmdoc)\f[]
+as late as possible in the boot sequence
+(perhaps with the
+\f\*[B-Font]\-v\f[]
+flag)
+and after
+\fCntp-wait\f[]\fR(1ntp-waitmdoc)\f[]
+exits successfully
+it is as safe as it will ever be to start any process that require
+stable time.
+.SS "Frequency Discipline"
+The
+\f\*[B-Font]ntpd\fP
+behavior at startup depends on whether the
+frequency file, usually
+\fIntp.drift\f[],
+exists.
+This file
+contains the latest estimate of clock frequency error.
+When the
+\f\*[B-Font]ntpd\fP
+is started and the file does not exist, the
+\f\*[B-Font]ntpd\fP
+enters a special mode designed to quickly adapt to
+the particular system clock oscillator time and frequency error.
+This takes approximately 15 minutes, after which the time and
+frequency are set to nominal values and the
+\f\*[B-Font]ntpd\fP
+enters
+normal mode, where the time and frequency are continuously tracked
+relative to the server.
+After one hour the frequency file is
+created and the current frequency offset written to it.
+When the
+\f\*[B-Font]ntpd\fP
+is started and the file does exist, the
+\f\*[B-Font]ntpd\fP
+frequency is initialized from the file and enters normal mode
+immediately.
+After that the current frequency offset is written to
+the file at hourly intervals.
+.SS "Operating Modes"
+The
+\f\*[B-Font]ntpd\fP
+utility can operate in any of several modes, including
+symmetric active/passive, client/server broadcast/multicast and
+manycast, as described in the
+"Association Management"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+It normally operates continuously while
+monitoring for small changes in frequency and trimming the clock
+for the ultimate precision.
+However, it can operate in a one-time
+mode where the time is set from an external server and frequency is
+set from a previously recorded frequency file.
+A
+broadcast/multicast or manycast client can discover remote servers,
+compute server-client propagation delay correction factors and
+configure itself automatically.
+This makes it possible to deploy a
+fleet of workstations without specifying configuration details
+specific to the local environment.
+.sp \n(Ppu
+.ne 2
+
+By default,
+\f\*[B-Font]ntpd\fP
+runs in continuous mode where each of
+possibly several external servers is polled at intervals determined
+by an intricate state machine.
+The state machine measures the
+incidental roundtrip delay jitter and oscillator frequency wander
+and determines the best poll interval using a heuristic algorithm.
+Ordinarily, and in most operating environments, the state machine
+will start with 64s intervals and eventually increase in steps to
+1024s.
+A small amount of random variation is introduced in order to
+avoid bunching at the servers.
+In addition, should a server become
+unreachable for some time, the poll interval is increased in steps
+to 1024s in order to reduce network overhead.
+.sp \n(Ppu
+.ne 2
+
+In some cases it may not be practical for
+\f\*[B-Font]ntpd\fP
+to run continuously.
+A common workaround has been to run the
+\fCntpdate\f[]\fR(1ntpdatemdoc)\f[]
+or
+\fCsntp\f[]\fR(1sntpmdoc)\f[]
+programs from a
+\fCcron\f[]\fR(8)\f[]
+job at designated
+times.
+However, these programs do not have the crafted signal
+processing, error checking or mitigation algorithms of
+\f\*[B-Font]ntpd\fP.
+The
+\f\*[B-Font]\-q\f[]
+option is intended for this purpose.
+Setting this option will cause
+\f\*[B-Font]ntpd\fP
+to exit just after
+setting the clock for the first time.
+The procedure for initially
+setting the clock is the same as in continuous mode; most
+applications will probably want to specify the
+\f\*[B-Font]iburst\f[]
+keyword with the
+\f\*[B-Font]server\f[]
+configuration command.
+With this
+keyword a volley of messages are exchanged to groom the data and
+the clock is set in about 10 s.
+If nothing is heard after a
+couple of minutes, the daemon times out and exits.
+After a suitable
+period of mourning, the
+\fCntpdate\f[]\fR(1ntpdatemdoc)\f[]
+program will be
+retired.
+.sp \n(Ppu
+.ne 2
+
+When kernel support is available to discipline the clock
+frequency, which is the case for stock Solaris, Tru64, Linux and
+FreeBSD,
+a useful feature is available to discipline the clock
+frequency.
+First,
+\f\*[B-Font]ntpd\fP
+is run in continuous mode with
+selected servers in order to measure and record the intrinsic clock
+frequency offset in the frequency file.
+It may take some hours for
+the frequency and offset to settle down.
+Then the
+\f\*[B-Font]ntpd\fP
+is
+stopped and run in one-time mode as required.
+At each startup, the
+frequency is read from the file and initializes the kernel
+frequency.
+.SS "Poll Interval Control"
+This version of NTP includes an intricate state machine to
+reduce the network load while maintaining a quality of
+synchronization consistent with the observed jitter and wander.
+There are a number of ways to tailor the operation in order enhance
+accuracy by reducing the interval or to reduce network overhead by
+increasing it.
+However, the user is advised to carefully consider
+the consequences of changing the poll adjustment range from the
+default minimum of 64 s to the default maximum of 1,024 s.
+The
+default minimum can be changed with the
+\f\*[B-Font]tinker\f[]
+\f\*[B-Font]minpoll\f[]
+command to a value not less than 16 s.
+This value is used for all
+configured associations, unless overridden by the
+\f\*[B-Font]minpoll\f[]
+option on the configuration command.
+Note that most device drivers
+will not operate properly if the poll interval is less than 64 s
+and that the broadcast server and manycast client associations will
+also use the default, unless overridden.
+.sp \n(Ppu
+.ne 2
+
+In some cases involving dial up or toll services, it may be
+useful to increase the minimum interval to a few tens of minutes
+and maximum interval to a day or so.
+Under normal operation
+conditions, once the clock discipline loop has stabilized the
+interval will be increased in steps from the minimum to the
+maximum.
+However, this assumes the intrinsic clock frequency error
+is small enough for the discipline loop correct it.
+The capture
+range of the loop is 500 PPM at an interval of 64s decreasing by a
+factor of two for each doubling of interval.
+At a minimum of 1,024
+s, for example, the capture range is only 31 PPM.
+If the intrinsic
+error is greater than this, the drift file
+\fIntp.drift\f[]
+will
+have to be specially tailored to reduce the residual error below
+this limit.
+Once this is done, the drift file is automatically
+updated once per hour and is available to initialize the frequency
+on subsequent daemon restarts.
+.SS "The huff-n'-puff Filter"
+In scenarios where a considerable amount of data are to be
+downloaded or uploaded over telephone modems, timekeeping quality
+can be seriously degraded.
+This occurs because the differential
+delays on the two directions of transmission can be quite large.
+In
+many cases the apparent time errors are so large as to exceed the
+step threshold and a step correction can occur during and after the
+data transfer is in progress.
+.sp \n(Ppu
+.ne 2
+
+The huff-n'-puff filter is designed to correct the apparent time
+offset in these cases.
+It depends on knowledge of the propagation
+delay when no other traffic is present.
+In common scenarios this
+occurs during other than work hours.
+The filter maintains a shift
+register that remembers the minimum delay over the most recent
+interval measured usually in hours.
+Under conditions of severe
+delay, the filter corrects the apparent offset using the sign of
+the offset and the difference between the apparent delay and
+minimum delay.
+The name of the filter reflects the negative (huff)
+and positive (puff) correction, which depends on the sign of the
+offset.
+.sp \n(Ppu
+.ne 2
+
+The filter is activated by the
+\f\*[B-Font]tinker\f[]
+command and
+\f\*[B-Font]huffpuff\f[]
+keyword, as described in
+\fCntp.conf\f[]\fR(5)\f[].
+.SH "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.SH FILES
+.TP 15
+.NOP \fI/etc/ntp.conf\f[]
+the default name of the configuration file
+.br
+.ns
+.TP 15
+.NOP \fI/etc/ntp.drift\f[]
+the default name of the drift file
+.br
+.ns
+.TP 15
+.NOP \fI/etc/ntp.keys\f[]
+the default name of the key file
+.PP
+.SH "EXIT STATUS"
+One of the following exit values will be returned:
+.TP
+.NOP 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.TP
+.NOP 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.TP
+.NOP 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+.PP
+.SH "SEE ALSO"
+\fCntp.conf\f[]\fR(5)\f[],
+\fCntpdate\f[]\fR(1ntpdatemdoc)\f[],
+\fCntpdc\f[]\fR(1ntpdcmdoc)\f[],
+\fCntpq\f[]\fR(1ntpqmdoc)\f[],
+\fCsntp\f[]\fR(1sntpmdoc)\f[]
+.sp \n(Ppu
+.ne 2
+
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+\f[C]http://www.ntp.org/\f[].
+A snapshot of this documentation is available in HTML format in
+\fI/usr/share/doc/ntp\f[].
+David L. Mills,
+\fINetwork Time Protocol (Version 1)\fR,
+RFC1059
+.PP
+
+David L. Mills,
+\fINetwork Time Protocol (Version 2)\fR,
+RFC1119
+.PP
+
+David L. Mills,
+\fINetwork Time Protocol (Version 3)\fR,
+RFC1305
+.PP
+
+David L. Mills and J. Martin, Ed. and J. Burbank and W. Kasch,
+\fINetwork Time Protocol Version 4: Protocol and Algorithms Specification\fR,
+RFC5905
+.PP
+
+David L. Mills and B. Haberman, Ed.,
+\fINetwork Time Protocol Version 4: Autokey Specification\fR,
+RFC5906
+.PP
+
+H. Gerstung and C. Elliott and B. Haberman, Ed.,
+\fIDefinitions of Managed Objects for Network Time Protocol Version 4: (NTPv4)\fR,
+RFC5907
+.PP
+
+R. Gayraud and B. Lourdelet,
+\fINetwork Time Protocol (NTP) Server Option for DHCPv6\fR,
+RFC5908
+.PP
+
+.SH "AUTHORS"
+The University of Delaware and Network Time Foundation
+.SH "COPYRIGHT"
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.SH BUGS
+The
+\f\*[B-Font]ntpd\fP
+utility has gotten rather fat.
+While not huge, it has gotten
+larger than might be desirable for an elevated-priority
+\f\*[B-Font]ntpd\fP
+running on a workstation, particularly since many of
+the fancy features which consume the space were designed more with
+a busy primary server, rather than a high stratum workstation in
+mind.
+.sp \n(Ppu
+.ne 2
+
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.SH NOTES
+Portions of this document came from FreeBSD.
+.sp \n(Ppu
+.ne 2
+
+This manual page was \fIAutoGen\fP-erated from the \fBntpd\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntpd.1ntpdmdoc b/contrib/ntp/ntpd/ntpd.1ntpdmdoc
new file mode 100644
index 0000000..08d7655
--- /dev/null
+++ b/contrib/ntp/ntpd/ntpd.1ntpdmdoc
@@ -0,0 +1,904 @@
+.Dd June 29 2015
+.Dt NTPD 1ntpdmdoc User Commands
+.Os
+.\" EDIT THIS FILE WITH CAUTION (ntpd-opts.mdoc)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:41 PM by AutoGen 5.18.5
+.\" From the definitions ntpd-opts.def
+.\" and the template file agmdoc-cmd.tpl
+.Sh NAME
+.Nm ntpd
+.Nd NTP daemon program
+.Sh SYNOPSIS
+.Nm
+.\" Mixture of short (flag) options and long options
+.Op Fl flags
+.Op Fl flag Op Ar value
+.Op Fl \-option\-name Ns Oo Oo Ns "=| " Oc Ns Ar value Oc
+[ <server1> ... <serverN> ]
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC\-5905,
+but also retains compatibility with
+version 3, as defined by RFC\-1305, and versions 1
+and 2, as defined by RFC\-1059 and RFC\-1119, respectively.
+.Pp
+The
+.Nm
+utility does most computations in 64\-bit floating point
+arithmetic and does relatively clumsy 64\-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+.Pp
+Ordinarily,
+.Nm
+reads the
+.Xr ntp.conf 5
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+.Pp
+If NetInfo support is built into
+.Nm ,
+then
+.Nm
+will attempt to read its configuration from the
+NetInfo if the default
+.Xr ntp.conf 5
+file cannot be read and no file is
+specified by the
+.Fl c
+option.
+.Pp
+Various internal
+.Nm
+variables can be displayed and
+configuration options altered while the
+.Nm
+is running
+using the
+.Xr ntpq 1ntpqmdoc
+and
+.Xr ntpdc 1ntpdcmdoc
+utility programs.
+.Pp
+When
+.Nm
+starts it looks at the value of
+.Xr umask 2 ,
+and if zero
+.Nm
+will set the
+.Xr umask 2
+to 022.
+.Sh "OPTIONS"
+.Bl -tag
+.It Fl 4 , Fl \-ipv4
+Force IPv4 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv6.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+.It Fl 6 , Fl \-ipv6
+Force IPv6 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv4.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+.It Fl a , Fl \-authreq
+Require crypto authentication.
+This option must not appear in combination with any of the following options:
+authnoreq.
+.sp
+Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+.It Fl A , Fl \-authnoreq
+Do not require crypto authentication.
+This option must not appear in combination with any of the following options:
+authreq.
+.sp
+Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+.It Fl b , Fl \-bcastsync
+Allow us to sync to broadcast servers.
+.sp
+.It Fl c Ar string , Fl \-configfile Ns = Ns Ar string
+configuration file name.
+.sp
+The name and path of the configuration file,
+\fI/etc/ntp.conf\fP
+by default.
+.It Fl d , Fl \-debug\-level
+Increase debug verbosity level.
+This option may appear an unlimited number of times.
+.sp
+.It Fl D Ar number , Fl \-set\-debug\-level Ns = Ns Ar number
+Set the debug verbosity level.
+This option may appear an unlimited number of times.
+This option takes an integer number as its argument.
+.sp
+.It Fl f Ar string , Fl \-driftfile Ns = Ns Ar string
+frequency drift file name.
+.sp
+The name and path of the frequency file,
+\fI/etc/ntp.drift\fP
+by default.
+This is the same operation as the
+\fBdriftfile\fP \fIdriftfile\fP
+configuration specification in the
+\fI/etc/ntp.conf\fP
+file.
+.It Fl g , Fl \-panicgate
+Allow the first adjustment to be Big.
+This option may appear an unlimited number of times.
+.sp
+Normally,
+\fBntpd\fP
+exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
+\fBntpd\fP
+will exit with a message to the system log. This option can be used with the
+\fB\-q\fP
+and
+\fB\-x\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+.It Fl G , Fl \-force\-step\-once
+Step any initial offset correction..
+.sp
+Normally,
+\fBntpd\fP
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the \fBtinker\fP configuration file directive for other options.
+.It Fl i Ar string , Fl \-jaildir Ns = Ns Ar string
+Jail directory.
+.sp
+Chroot the server to the directory
+\fIjaildir\fP
+.
+This option also implies that the server attempts to drop root privileges at startup.
+You may need to also specify a
+\fB\-u\fP
+option.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB\-\-enable\-clockctl\fP) or Linux (configure with
+\fB\-\-enable\-linuxcaps\fP) or Solaris (configure with \fB\-\-enable\-solarisprivs\fP).
+.It Fl I Ar iface , Fl \-interface Ns = Ns Ar iface
+Listen on an interface name or address.
+This option may appear an unlimited number of times.
+.sp
+Open the network address given, or all the addresses associated with the
+given interface name. This option may appear multiple times. This option
+also implies not opening other addresses, except wildcard and localhost.
+This option is deprecated. Please consider using the configuration file
+\fBinterface\fP command, which is more versatile.
+.It Fl k Ar string , Fl \-keyfile Ns = Ns Ar string
+path to symmetric keys.
+.sp
+Specify the name and path of the symmetric key file.
+\fI/etc/ntp.keys\fP
+is the default.
+This is the same operation as the
+\fBkeys\fP \fIkeyfile\fP
+configuration file directive.
+.It Fl l Ar string , Fl \-logfile Ns = Ns Ar string
+path to the log file.
+.sp
+Specify the name and path of the log file.
+The default is the system log file.
+This is the same operation as the
+\fBlogfile\fP \fIlogfile\fP
+configuration file directive.
+.It Fl L , Fl \-novirtualips
+Do not listen to virtual interfaces.
+.sp
+Do not listen to virtual interfaces, defined as those with
+names containing a colon. This option is deprecated. Please
+consider using the configuration file \fBinterface\fP command, which
+is more versatile.
+.It Fl M , Fl \-modifymmtimer
+Modify Multimedia Timer (Windows only).
+.sp
+Set the Windows Multimedia Timer to highest resolution. This
+ensures the resolution does not change while ntpd is running,
+avoiding timekeeping glitches associated with changes.
+.It Fl n , Fl \-nofork
+Do not fork.
+This option must not appear in combination with any of the following options:
+wait\-sync.
+.sp
+.It Fl N , Fl \-nice
+Run at high priority.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the highest priority.
+.It Fl p Ar string , Fl \-pidfile Ns = Ns Ar string
+path to the PID file.
+.sp
+Specify the name and path of the file used to record
+\fBntpd\fP's
+process ID.
+This is the same operation as the
+\fBpidfile\fP \fIpidfile\fP
+configuration file directive.
+.It Fl P Ar number , Fl \-priority Ns = Ns Ar number
+Process priority.
+This option takes an integer number as its argument.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the specified
+\fBsched_setscheduler(SCHED_FIFO)\fP
+priority.
+.It Fl q , Fl \-quit
+Set the time and quit.
+This option must not appear in combination with any of the following options:
+saveconfigquit, wait\-sync.
+.sp
+\fBntpd\fP
+will not daemonize and will exit after the clock is first
+synchronized. This behavior mimics that of the
+\fBntpdate\fP
+program, which will soon be replaced with a shell script.
+The
+\fB\-g\fP
+and
+\fB\-x\fP
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+.It Fl r Ar string , Fl \-propagationdelay Ns = Ns Ar string
+Broadcast/propagation delay.
+.sp
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+.It Fl \-saveconfigquit Ns = Ns Ar string
+Save parsed configuration and quit.
+This option must not appear in combination with any of the following options:
+quit, wait\-sync.
+.sp
+Cause \fBntpd\fP to parse its startup configuration file and save an
+equivalent to the given filename and exit. This option was
+designed for automated testing.
+.It Fl s Ar string , Fl \-statsdir Ns = Ns Ar string
+Statistics file location.
+.sp
+Specify the directory path for files created by the statistics facility.
+This is the same operation as the
+\fBstatsdir\fP \fIstatsdir\fP
+configuration file directive.
+.It Fl t Ar tkey , Fl \-trustedkey Ns = Ns Ar tkey
+Trusted key number.
+This option may appear an unlimited number of times.
+.sp
+Add the specified key number to the trusted key list.
+.It Fl u Ar string , Fl \-user Ns = Ns Ar string
+Run as userid (or userid:groupid).
+.sp
+Specify a user, and optionally a group, to switch to.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB\-\-enable\-clockctl\fP) or Linux (configure with
+\fB\-\-enable\-linuxcaps\fP) or Solaris (configure with \fB\-\-enable\-solarisprivs\fP).
+.It Fl U Ar number , Fl \-updateinterval Ns = Ns Ar number
+interval in seconds between scans for new or dropped interfaces.
+This option takes an integer number as its argument.
+.sp
+Give the time in seconds between two scans for new or dropped interfaces.
+For systems with routing socket support the scans will be performed shortly after the interface change
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+.It Fl \-var Ns = Ns Ar nvar
+make ARG an ntp variable (RW).
+This option may appear an unlimited number of times.
+.sp
+.It Fl \-dvar Ns = Ns Ar ndvar
+make ARG an ntp variable (RW|DEF).
+This option may appear an unlimited number of times.
+.sp
+.It Fl w Ar number , Fl \-wait\-sync Ns = Ns Ar number
+Seconds to wait for first clock sync.
+This option must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+This option takes an integer number as its argument.
+.sp
+If greater than zero, alters \fBntpd\fP's behavior when forking to
+daemonize. Instead of exiting with status 0 immediately after
+the fork, the parent waits up to the specified number of
+seconds for the child to first synchronize the clock. The exit
+status is zero (success) if the clock was synchronized,
+otherwise it is \fBETIMEDOUT\fP.
+This provides the option for a script starting \fBntpd\fP to easily
+wait for the first set of the clock before proceeding.
+.It Fl x , Fl \-slew
+Slew up to 600 seconds.
+.sp
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+This option can be used with the
+\fB\-g\fP
+and
+\fB\-q\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+.It Fl \-usepcc
+Use CPU cycle counter (Windows only).
+.sp
+Attempt to substitute the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter and \fBQueryPerformanceCounter\fP are compared, and if
+they have the same frequency, the CPU counter (RDTSC on x86) is
+used directly, saving the overhead of a system call.
+.It Fl \-pccfreq Ns = Ns Ar string
+Force CPU cycle counter use (Windows only).
+.sp
+Force substitution the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter (RDTSC on x86) is used unconditionally with the
+given frequency (in Hz).
+.It Fl m , Fl \-mdns
+Register with mDNS as a NTP server.
+.sp
+Registers as an NTP server with the local mDNS server which allows
+the server to be discovered via mDNS client lookup.
+.It Fl \&? , Fl \-help
+Display usage information and exit.
+.It Fl \&! , Fl \-more\-help
+Pass the extended usage information through a pager.
+.It Fl \-version Op Brq Ar v|c|n
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.El
+.Sh "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTPD_<option\-name>\fP or \fBNTPD\fP
+.fi
+.ad
+.Sh USAGE
+.Ss "How NTP Operates"
+The
+.Nm
+utility operates by exchanging messages with
+one or more configured servers over a range of designated poll intervals.
+When
+started, whether for the first or subsequent times, the program
+requires several exchanges from the majority of these servers so
+the signal processing and mitigation algorithms can accumulate and
+groom the data and set the clock.
+In order to protect the network
+from bursts, the initial poll interval for each server is delayed
+an interval randomized over a few seconds.
+At the default initial poll
+interval of 64s, several minutes can elapse before the clock is
+set.
+This initial delay to set the clock
+can be safely and dramatically reduced using the
+.Cm iburst
+keyword with the
+.Ic server
+configuration
+command, as described in
+.Xr ntp.conf 5 .
+.Pp
+Most operating systems and hardware of today incorporate a
+time\-of\-year (TOY) chip to maintain the time during periods when
+the power is off.
+When the machine is booted, the chip is used to
+initialize the operating system time.
+After the machine has
+synchronized to a NTP server, the operating system corrects the
+chip from time to time.
+In the default case, if
+.Nm
+detects that the time on the host
+is more than 1000s from the server time,
+.Nm
+assumes something must be terribly wrong and the only
+reliable action is for the operator to intervene and set the clock
+by hand.
+(Reasons for this include there is no TOY chip,
+or its battery is dead, or that the TOY chip is just of poor quality.)
+This causes
+.Nm
+to exit with a panic message to
+the system log.
+The
+.Fl g
+option overrides this check and the
+clock will be set to the server time regardless of the chip time
+(up to 68 years in the past or future \(em
+this is a limitation of the NTPv4 protocol).
+However, and to protect against broken hardware, such as when the
+CMOS battery fails or the clock counter becomes defective, once the
+clock has been set an error greater than 1000s will cause
+.Nm
+to exit anyway.
+.Pp
+Under ordinary conditions,
+.Nm
+adjusts the clock in
+small steps so that the timescale is effectively continuous and
+without discontinuities.
+Under conditions of extreme network
+congestion, the roundtrip delay jitter can exceed three seconds and
+the synchronization distance, which is equal to one\-half the
+roundtrip delay plus error budget terms, can become very large.
+The
+.Nm
+algorithms discard sample offsets exceeding 128 ms,
+unless the interval during which no sample offset is less than 128
+ms exceeds 900s.
+The first sample after that, no matter what the
+offset, steps the clock to the indicated time.
+In practice this
+reduces the false alarm rate where the clock is stepped in error to
+a vanishingly low incidence.
+.Pp
+As the result of this behavior, once the clock has been set it
+very rarely strays more than 128 ms even under extreme cases of
+network path congestion and jitter.
+Sometimes, in particular when
+.Nm
+is first started without a valid drift file
+on a system with a large intrinsic drift
+the error might grow to exceed 128 ms,
+which would cause the clock to be set backwards
+if the local clock time is more than 128 s
+in the future relative to the server.
+In some applications, this behavior may be unacceptable.
+There are several solutions, however.
+If the
+.Fl x
+option is included on the command line, the clock will
+never be stepped and only slew corrections will be used.
+But this choice comes with a cost that
+should be carefully explored before deciding to use
+the
+.Fl x
+option.
+The maximum slew rate possible is limited
+to 500 parts\-per\-million (PPM) as a consequence of the correctness
+principles on which the NTP protocol and algorithm design are
+based.
+As a result, the local clock can take a long time to
+converge to an acceptable offset, about 2,000 s for each second the
+clock is outside the acceptable range.
+During this interval the
+local clock will not be consistent with any other network clock and
+the system cannot be used for distributed applications that require
+correctly synchronized network time.
+.Pp
+In spite of the above precautions, sometimes when large
+frequency errors are present the resulting time offsets stray
+outside the 128\-ms range and an eventual step or slew time
+correction is required.
+If following such a correction the
+frequency error is so large that the first sample is outside the
+acceptable range,
+.Nm
+enters the same state as when the
+.Pa ntp.drift
+file is not present.
+The intent of this behavior
+is to quickly correct the frequency and restore operation to the
+normal tracking mode.
+In the most extreme cases
+(the host
+.Cm time.ien.it
+comes to mind), there may be occasional
+step/slew corrections and subsequent frequency corrections.
+It
+helps in these cases to use the
+.Cm burst
+keyword when
+configuring the server, but
+ONLY
+when you have permission to do so from the owner of the target host.
+.Pp
+Finally,
+in the past many startup scripts would run
+.Xr ntpdate 1ntpdatemdoc
+to get the system clock close to correct before starting
+.Xr ntpd 1ntpdmdoc ,
+but this was never more than a mediocre hack and is no longer needed.
+If you are following the instructions in
+.Sx "Starting NTP (Best Current Practice)"
+and you still need to set the system time before starting
+.Nm ,
+please open a bug report and document what is going on,
+and then look at using
+.Xr sntp 1sntpmdoc .
+.Pp
+There is a way to start
+.Xr ntpd 1ntpdmdoc
+that often addresses all of the problems mentioned above.
+.Ss "Starting NTP (Best Current Practice)"
+First, use the
+.Cm iburst
+option on your
+.Cm server
+entries.
+.Pp
+If you can also keep a good
+.Pa ntp.drift
+file then
+.Xr ntpd 1ntpdmdoc
+will effectively "warm\-start" and your system's clock will
+be stable in under 11 seconds' time.
+.Pp
+As soon as possible in the startup sequence, start
+.Xr ntpd 1ntpdmdoc
+with at least the
+.Fl g
+and perhaps the
+.Fl N
+options.
+Then,
+start the rest of your "normal" processes.
+This will give
+.Xr ntpd 1ntpdmdoc
+as much time as possible to get the system's clock synchronized and stable.
+.Pp
+Finally,
+if you have processes like
+.Cm dovecot
+or database servers
+that require
+monotonically\-increasing time,
+run
+.Xr ntp\-wait 1ntp\-waitmdoc
+as late as possible in the boot sequence
+(perhaps with the
+.Fl v
+flag)
+and after
+.Xr ntp\-wait 1ntp\-waitmdoc
+exits successfully
+it is as safe as it will ever be to start any process that require
+stable time.
+.Ss "Frequency Discipline"
+The
+.Nm
+behavior at startup depends on whether the
+frequency file, usually
+.Pa ntp.drift ,
+exists.
+This file
+contains the latest estimate of clock frequency error.
+When the
+.Nm
+is started and the file does not exist, the
+.Nm
+enters a special mode designed to quickly adapt to
+the particular system clock oscillator time and frequency error.
+This takes approximately 15 minutes, after which the time and
+frequency are set to nominal values and the
+.Nm
+enters
+normal mode, where the time and frequency are continuously tracked
+relative to the server.
+After one hour the frequency file is
+created and the current frequency offset written to it.
+When the
+.Nm
+is started and the file does exist, the
+.Nm
+frequency is initialized from the file and enters normal mode
+immediately.
+After that the current frequency offset is written to
+the file at hourly intervals.
+.Ss "Operating Modes"
+The
+.Nm
+utility can operate in any of several modes, including
+symmetric active/passive, client/server broadcast/multicast and
+manycast, as described in the
+.Qq Association Management
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+It normally operates continuously while
+monitoring for small changes in frequency and trimming the clock
+for the ultimate precision.
+However, it can operate in a one\-time
+mode where the time is set from an external server and frequency is
+set from a previously recorded frequency file.
+A
+broadcast/multicast or manycast client can discover remote servers,
+compute server\-client propagation delay correction factors and
+configure itself automatically.
+This makes it possible to deploy a
+fleet of workstations without specifying configuration details
+specific to the local environment.
+.Pp
+By default,
+.Nm
+runs in continuous mode where each of
+possibly several external servers is polled at intervals determined
+by an intricate state machine.
+The state machine measures the
+incidental roundtrip delay jitter and oscillator frequency wander
+and determines the best poll interval using a heuristic algorithm.
+Ordinarily, and in most operating environments, the state machine
+will start with 64s intervals and eventually increase in steps to
+1024s.
+A small amount of random variation is introduced in order to
+avoid bunching at the servers.
+In addition, should a server become
+unreachable for some time, the poll interval is increased in steps
+to 1024s in order to reduce network overhead.
+.Pp
+In some cases it may not be practical for
+.Nm
+to run continuously.
+A common workaround has been to run the
+.Xr ntpdate 1ntpdatemdoc
+or
+.Xr sntp 1sntpmdoc
+programs from a
+.Xr cron 8
+job at designated
+times.
+However, these programs do not have the crafted signal
+processing, error checking or mitigation algorithms of
+.Nm .
+The
+.Fl q
+option is intended for this purpose.
+Setting this option will cause
+.Nm
+to exit just after
+setting the clock for the first time.
+The procedure for initially
+setting the clock is the same as in continuous mode; most
+applications will probably want to specify the
+.Cm iburst
+keyword with the
+.Ic server
+configuration command.
+With this
+keyword a volley of messages are exchanged to groom the data and
+the clock is set in about 10 s.
+If nothing is heard after a
+couple of minutes, the daemon times out and exits.
+After a suitable
+period of mourning, the
+.Xr ntpdate 1ntpdatemdoc
+program will be
+retired.
+.Pp
+When kernel support is available to discipline the clock
+frequency, which is the case for stock Solaris, Tru64, Linux and
+.Fx ,
+a useful feature is available to discipline the clock
+frequency.
+First,
+.Nm
+is run in continuous mode with
+selected servers in order to measure and record the intrinsic clock
+frequency offset in the frequency file.
+It may take some hours for
+the frequency and offset to settle down.
+Then the
+.Nm
+is
+stopped and run in one\-time mode as required.
+At each startup, the
+frequency is read from the file and initializes the kernel
+frequency.
+.Ss "Poll Interval Control"
+This version of NTP includes an intricate state machine to
+reduce the network load while maintaining a quality of
+synchronization consistent with the observed jitter and wander.
+There are a number of ways to tailor the operation in order enhance
+accuracy by reducing the interval or to reduce network overhead by
+increasing it.
+However, the user is advised to carefully consider
+the consequences of changing the poll adjustment range from the
+default minimum of 64 s to the default maximum of 1,024 s.
+The
+default minimum can be changed with the
+.Ic tinker
+.Cm minpoll
+command to a value not less than 16 s.
+This value is used for all
+configured associations, unless overridden by the
+.Cm minpoll
+option on the configuration command.
+Note that most device drivers
+will not operate properly if the poll interval is less than 64 s
+and that the broadcast server and manycast client associations will
+also use the default, unless overridden.
+.Pp
+In some cases involving dial up or toll services, it may be
+useful to increase the minimum interval to a few tens of minutes
+and maximum interval to a day or so.
+Under normal operation
+conditions, once the clock discipline loop has stabilized the
+interval will be increased in steps from the minimum to the
+maximum.
+However, this assumes the intrinsic clock frequency error
+is small enough for the discipline loop correct it.
+The capture
+range of the loop is 500 PPM at an interval of 64s decreasing by a
+factor of two for each doubling of interval.
+At a minimum of 1,024
+s, for example, the capture range is only 31 PPM.
+If the intrinsic
+error is greater than this, the drift file
+.Pa ntp.drift
+will
+have to be specially tailored to reduce the residual error below
+this limit.
+Once this is done, the drift file is automatically
+updated once per hour and is available to initialize the frequency
+on subsequent daemon restarts.
+.Ss "The huff\-n'\-puff Filter"
+In scenarios where a considerable amount of data are to be
+downloaded or uploaded over telephone modems, timekeeping quality
+can be seriously degraded.
+This occurs because the differential
+delays on the two directions of transmission can be quite large.
+In
+many cases the apparent time errors are so large as to exceed the
+step threshold and a step correction can occur during and after the
+data transfer is in progress.
+.Pp
+The huff\-n'\-puff filter is designed to correct the apparent time
+offset in these cases.
+It depends on knowledge of the propagation
+delay when no other traffic is present.
+In common scenarios this
+occurs during other than work hours.
+The filter maintains a shift
+register that remembers the minimum delay over the most recent
+interval measured usually in hours.
+Under conditions of severe
+delay, the filter corrects the apparent offset using the sign of
+the offset and the difference between the apparent delay and
+minimum delay.
+The name of the filter reflects the negative (huff)
+and positive (puff) correction, which depends on the sign of the
+offset.
+.Pp
+The filter is activated by the
+.Ic tinker
+command and
+.Cm huffpuff
+keyword, as described in
+.Xr ntp.conf 5 .
+.Sh "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.Sh FILES
+.Bl -tag -width /etc/ntp.drift -compact
+.It Pa /etc/ntp.conf
+the default name of the configuration file
+.It Pa /etc/ntp.drift
+the default name of the drift file
+.It Pa /etc/ntp.keys
+the default name of the key file
+.El
+.Sh "EXIT STATUS"
+One of the following exit values will be returned:
+.Bl -tag
+.It 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.It 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.It 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen\-users@lists.sourceforge.net. Thank you.
+.El
+.Sh "SEE ALSO"
+.Xr ntp.conf 5 ,
+.Xr ntpdate 1ntpdatemdoc ,
+.Xr ntpdc 1ntpdcmdoc ,
+.Xr ntpq 1ntpqmdoc ,
+.Xr sntp 1sntpmdoc
+.Pp
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+.Li http://www.ntp.org/ .
+A snapshot of this documentation is available in HTML format in
+.Pa /usr/share/doc/ntp .
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 1)
+.%O RFC1059
+.Re
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 2)
+.%O RFC1119
+.Re
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 3)
+.%O RFC1305
+.Re
+.Rs
+.%A David L. Mills
+.%A J. Martin, Ed.
+.%A J. Burbank
+.%A W. Kasch
+.%T Network Time Protocol Version 4: Protocol and Algorithms Specification
+.%O RFC5905
+.Re
+.Rs
+.%A David L. Mills
+.%A B. Haberman, Ed.
+.%T Network Time Protocol Version 4: Autokey Specification
+.%O RFC5906
+.Re
+.Rs
+.%A H. Gerstung
+.%A C. Elliott
+.%A B. Haberman, Ed.
+.%T Definitions of Managed Objects for Network Time Protocol Version 4: (NTPv4)
+.%O RFC5907
+.Re
+.Rs
+.%A R. Gayraud
+.%A B. Lourdelet
+.%T Network Time Protocol (NTP) Server Option for DHCPv6
+.%O RFC5908
+.Re
+.Sh "AUTHORS"
+The University of Delaware and Network Time Foundation
+.Sh "COPYRIGHT"
+Copyright (C) 1992\-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.Sh BUGS
+The
+.Nm
+utility has gotten rather fat.
+While not huge, it has gotten
+larger than might be desirable for an elevated\-priority
+.Nm
+running on a workstation, particularly since many of
+the fancy features which consume the space were designed more with
+a busy primary server, rather than a high stratum workstation in
+mind.
+.Pp
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.Sh NOTES
+Portions of this document came from FreeBSD.
+.Pp
+This manual page was \fIAutoGen\fP\-erated from the \fBntpd\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c
index 02a5198..529e6ce 100644
--- a/contrib/ntp/ntpd/ntpd.c
+++ b/contrib/ntp/ntpd/ntpd.c
@@ -12,13 +12,21 @@
#include "ntp_stdlib.h"
#include <ntp_random.h>
+#include "ntp_config.h"
+#include "ntp_syslog.h"
+#include "ntp_assert.h"
+#include "isc/error.h"
+#include "isc/strerror.h"
+#include "isc/formatcheck.h"
+#include "iosignal.h"
+
#ifdef SIM
# include "ntpsim.h"
-# include "ntpdsim-opts.h"
-#else
-# include "ntpd-opts.h"
#endif
+#include "ntp_libopts.h"
+#include "ntpd-opts.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
@@ -26,11 +34,9 @@
# include <sys/stat.h>
#endif
#include <stdio.h>
-#if !defined(VMS) /*wjm*/
-# ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-#endif /* VMS */
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#else
@@ -39,13 +45,7 @@
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif /* HAVE_SYS_IOCTL_H */
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif /* HAVE_SYS_RESOURCE_H */
#if defined(HAVE_RTPRIO)
-# ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-# endif
# ifdef HAVE_SYS_LOCK_H
# include <sys/lock.h>
# endif
@@ -78,8 +78,9 @@
# include <apollo/base.h>
#endif /* SYS_DOMAINOS */
-#include "recvbuff.h"
-#include "ntp_cmdargs.h"
+
+#include "recvbuff.h"
+#include "ntp_cmdargs.h"
#if 0 /* HMS: I don't think we need this. 961223 */
#ifdef LOCK_PROCESS
@@ -106,30 +107,34 @@
#ifdef HAVE_LINUX_CAPABILITIES
# include <sys/capability.h>
# include <sys/prctl.h>
-#endif
-#endif
-
-/*
- * Signals we catch for debugging. If not debugging we ignore them.
- */
-#define MOREDEBUGSIG SIGUSR1
-#define LESSDEBUGSIG SIGUSR2
+#endif /* HAVE_LINUX_CAPABILITIES */
+#if defined(HAVE_PRIV_H) && defined(HAVE_SOLARIS_PRIVS)
+# include <priv.h>
+#endif /* HAVE_PRIV_H */
+#endif /* HAVE_DROPROOT */
-/*
- * Signals which terminate us gracefully.
- */
-#ifndef SYS_WINNT
-# define SIGDIE1 SIGHUP
-# define SIGDIE3 SIGQUIT
-# define SIGDIE2 SIGINT
-# define SIGDIE4 SIGTERM
-#endif /* SYS_WINNT */
+#if defined (LIBSECCOMP) && (KERN_SECCOMP)
+/* # include <sys/types.h> */
+# include <sys/resource.h>
+# include <seccomp.h>
+#endif /* LIBSECCOMP and KERN_SECCOMP */
#ifdef HAVE_DNSREGISTRATION
-#include <dns_sd.h>
+# include <dns_sd.h>
DNSServiceRef mdns;
#endif
+#ifdef HAVE_SETPGRP_0
+# define ntp_setpgrp(x, y) setpgrp()
+#else
+# define ntp_setpgrp(x, y) setpgrp(x, y)
+#endif
+
+#ifdef HAVE_SOLARIS_PRIVS
+# define LOWPRIVS "basic,sys_time,net_privaddr,proc_setid,!proc_info,!proc_session,!proc_exec"
+static priv_set_t *lowprivs = NULL;
+static priv_set_t *highprivs = NULL;
+#endif /* HAVE_SOLARIS_PRIVS */
/*
* Scheduling priority we run at
*/
@@ -140,33 +145,40 @@ int priority_done = 2; /* 0 - Set priority */
/* 2 - Don't set priority */
/* 1 and 2 are pretty much the same */
-#ifdef DEBUG
+int listen_to_virtual_ips = TRUE;
+
/*
- * Debugging flag
+ * No-fork flag. If set, we do not become a background daemon.
*/
-volatile int debug = 0; /* No debugging by default */
-#endif
-
-int listen_to_virtual_ips = 1;
-const char *specific_interface = NULL; /* interface name or IP address to bind to */
+int nofork; /* Fork by default */
+#ifdef HAVE_DNSREGISTRATION
/*
- * No-fork flag. If set, we do not become a background daemon.
+ * mDNS registration flag. If set, we attempt to register with the mDNS system, but only
+ * after we have synched the first time. If the attempt fails, then try again once per
+ * minute for up to 5 times. After all, we may be starting before mDNS.
*/
-int nofork = 0; /* Fork by default */
+int mdnsreg = FALSE;
+int mdnstries = 5;
+#endif /* HAVE_DNSREGISTRATION */
#ifdef HAVE_DROPROOT
-int droproot = 0;
-char *user = NULL; /* User to switch to */
-char *group = NULL; /* group to switch to */
-char *chrootdir = NULL; /* directory to chroot to */
-int sw_uid;
-int sw_gid;
-char *endp;
+int droproot;
+int root_dropped;
+char *user; /* User to switch to */
+char *group; /* group to switch to */
+const char *chrootdir; /* directory to chroot to */
+uid_t sw_uid;
+gid_t sw_gid;
+char *endp;
struct group *gr;
-struct passwd *pw;
+struct passwd *pw;
#endif /* HAVE_DROPROOT */
+#ifdef HAVE_WORKING_FORK
+int waitsync_fd_to_close = -1; /* -w/--wait-sync */
+#endif
+
/*
* Initializing flag. All async routines watch this and only do their
* thing when it is clear.
@@ -186,106 +198,67 @@ int was_alarmed;
/*
* We put this here, since the argument profile is syscall-specific
*/
-extern int syscall P((int, ...));
+extern int syscall (int, ...);
#endif /* DECL_SYSCALL */
-#ifdef SIGDIE2
-static RETSIGTYPE finish P((int));
-#endif /* SIGDIE2 */
-
-#ifdef DEBUG
-#ifndef SYS_WINNT
-static RETSIGTYPE moredebug P((int));
-static RETSIGTYPE lessdebug P((int));
+#if !defined(SIM) && defined(SIGDIE1)
+static RETSIGTYPE finish (int);
#endif
-#else /* not DEBUG */
-static RETSIGTYPE no_debug P((int));
-#endif /* not DEBUG */
-int ntpdmain P((int, char **));
-static void set_process_priority P((void));
-static void init_logging P((char const *));
-static void setup_logfile P((void));
-
-/*
- * Initialize the logging
- */
-void
-init_logging(char const *name)
-{
- const char *cp;
-
- /*
- * Logging. This may actually work on the gizmo board. Find a name
- * to log with by using the basename
- */
- cp = strrchr(name, '/');
- if (cp == 0)
- cp = name;
- else
- cp++;
+#if !defined(SIM) && defined(HAVE_WORKING_FORK)
+static int wait_child_sync_if (int, long);
+#endif
-#if !defined(VMS)
+#if !defined(SIM) && !defined(SYS_WINNT)
+# ifdef DEBUG
+static RETSIGTYPE moredebug (int);
+static RETSIGTYPE lessdebug (int);
+# else /* !DEBUG follows */
+static RETSIGTYPE no_debug (int);
+# endif /* !DEBUG */
+#endif /* !SIM && !SYS_WINNT */
-# ifndef LOG_DAEMON
- openlog(cp, LOG_PID);
-# else /* LOG_DAEMON */
+int saved_argc;
+char ** saved_argv;
-# ifndef LOG_NTP
-# define LOG_NTP LOG_DAEMON
-# endif
- openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
-# ifdef DEBUG
- if (debug)
- setlogmask(LOG_UPTO(LOG_DEBUG));
- else
-# endif /* DEBUG */
- setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
-# endif /* LOG_DAEMON */
-#endif /* !SYS_WINNT && !VMS */
+#ifndef SIM
+int ntpdmain (int, char **);
+static void set_process_priority (void);
+static void assertion_failed (const char *, int,
+ isc_assertiontype_t,
+ const char *)
+ __attribute__ ((__noreturn__));
+static void library_fatal_error (const char *, int,
+ const char *, va_list)
+ ISC_FORMAT_PRINTF(3, 0);
+static void library_unexpected_error(const char *, int,
+ const char *, va_list)
+ ISC_FORMAT_PRINTF(3, 0);
+#endif /* !SIM */
- NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
- msyslog(LOG_NOTICE, "%s", Version);
-}
-/*
- * See if we should redirect the logfile
- */
void
-setup_logfile(
- void
+parse_cmdline_opts(
+ int * pargc,
+ char ***pargv
)
{
- if (HAVE_OPT( LOGFILE )) {
- const char *my_optarg = OPT_ARG( LOGFILE );
- FILE *new_file;
-
- if(strcmp(my_optarg, "stderr") == 0)
- new_file = stderr;
- else if(strcmp(my_optarg, "stdout") == 0)
- new_file = stdout;
- else
- new_file = fopen(my_optarg, "a");
- if (new_file != NULL) {
- NLOG(NLOG_SYSINFO)
- msyslog(LOG_NOTICE, "logging to file %s", my_optarg);
- if (syslog_file != NULL &&
- fileno(syslog_file) != fileno(new_file))
- (void)fclose(syslog_file);
-
- syslog_file = new_file;
- syslogit = 0;
- }
- else
- msyslog(LOG_ERR,
- "Cannot open log file %s",
- my_optarg);
- }
+ static int parsed;
+ static int optct;
+
+ if (!parsed)
+ optct = ntpOptionProcess(&ntpdOptions, *pargc, *pargv);
+
+ parsed = 1;
+
+ *pargc -= optct;
+ *pargv += optct;
}
+
#ifdef SIM
int
main(
@@ -293,12 +266,19 @@ main(
char *argv[]
)
{
+ progname = argv[0];
+ parse_cmdline_opts(&argc, &argv);
+#ifdef DEBUG
+ debug = OPT_VALUE_SET_DEBUG_LEVEL;
+ DPRINTF(1, ("%s\n", Version));
+#endif
+
return ntpsim(argc, argv);
}
-#else /* SIM */
+#else /* !SIM follows */
#ifdef NO_MAIN_ALLOWED
CALL(ntpd,"ntpd",ntpdmain);
-#else
+#else /* !NO_MAIN_ALLOWED follows */
#ifndef SYS_WINNT
int
main(
@@ -308,18 +288,18 @@ main(
{
return ntpdmain(argc, argv);
}
-#endif /* SYS_WINNT */
-#endif /* NO_MAIN_ALLOWED */
-#endif /* SIM */
+#endif /* !SYS_WINNT */
+#endif /* !NO_MAIN_ALLOWED */
+#endif /* !SIM */
#ifdef _AIX
/*
* OK. AIX is different than solaris in how it implements plock().
* If you do NOT adjust the stack limit, you will get the MAXIMUM
- * stack size allocated and PINNED with you program. To check the
- * value, use ulimit -a.
+ * stack size allocated and PINNED with you program. To check the
+ * value, use ulimit -a.
*
- * To fix this, we create an automatic variable and set our stack limit
+ * To fix this, we create an automatic variable and set our stack limit
* to that PLUS 32KB of extra space (we need some headroom).
*
* This subroutine gets the stack address.
@@ -349,11 +329,12 @@ catch_danger(int signo)
/*
* Set the process priority
*/
+#ifndef SIM
static void
set_process_priority(void)
{
-#ifdef DEBUG
+# ifdef DEBUG
if (debug > 1)
msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>",
((priority_done)
@@ -361,13 +342,9 @@ set_process_priority(void)
: "Attempt to set priority"
),
priority_done);
-#endif /* DEBUG */
-
-#ifdef SYS_WINNT
- priority_done += NT_set_process_priority();
-#endif
+# endif /* DEBUG */
-#if defined(HAVE_SCHED_SETSCHEDULER)
+# if defined(HAVE_SCHED_SETSCHEDULER)
if (!priority_done) {
extern int config_priority_override, config_priority;
int pmax, pmin;
@@ -389,9 +366,9 @@ set_process_priority(void)
else
++priority_done;
}
-#endif /* HAVE_SCHED_SETSCHEDULER */
-#if defined(HAVE_RTPRIO)
-# ifdef RTP_SET
+# endif /* HAVE_SCHED_SETSCHEDULER */
+# ifdef HAVE_RTPRIO
+# ifdef RTP_SET
if (!priority_done) {
struct rtprio srtp;
@@ -403,17 +380,17 @@ set_process_priority(void)
else
++priority_done;
}
-# else /* not RTP_SET */
+# else /* !RTP_SET follows */
if (!priority_done) {
if (rtprio(0, 120) < 0)
msyslog(LOG_ERR, "rtprio() error: %m");
else
++priority_done;
}
-# endif /* not RTP_SET */
-#endif /* HAVE_RTPRIO */
-#if defined(NTPD_PRIO) && NTPD_PRIO != 0
-# ifdef HAVE_ATT_NICE
+# endif /* !RTP_SET */
+# endif /* HAVE_RTPRIO */
+# if defined(NTPD_PRIO) && NTPD_PRIO != 0
+# ifdef HAVE_ATT_NICE
if (!priority_done) {
errno = 0;
if (-1 == nice (NTPD_PRIO) && errno != 0)
@@ -421,148 +398,214 @@ set_process_priority(void)
else
++priority_done;
}
-# endif /* HAVE_ATT_NICE */
-# ifdef HAVE_BSD_NICE
+# endif /* HAVE_ATT_NICE */
+# ifdef HAVE_BSD_NICE
if (!priority_done) {
if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO))
msyslog(LOG_ERR, "setpriority() error: %m");
else
++priority_done;
}
-# endif /* HAVE_BSD_NICE */
-#endif /* NTPD_PRIO && NTPD_PRIO != 0 */
+# endif /* HAVE_BSD_NICE */
+# endif /* NTPD_PRIO && NTPD_PRIO != 0 */
if (!priority_done)
msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority");
}
+#endif /* !SIM */
/*
* Main program. Initialize us, disconnect us from the tty if necessary,
* and loop waiting for I/O and/or timer expiries.
*/
+#ifndef SIM
int
ntpdmain(
int argc,
char *argv[]
)
{
- l_fp now;
+ l_fp now;
struct recvbuf *rbuf;
-#ifdef _AIX /* HMS: ifdef SIGDANGER? */
+ const char * logfilename;
+# ifdef HAVE_UMASK
+ mode_t uv;
+# endif
+# if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */
+ uid_t uid;
+# endif
+# if defined(HAVE_WORKING_FORK)
+ long wait_sync = 0;
+ int pipe_fds[2];
+ int rc;
+ int exit_code;
+# ifdef _AIX
struct sigaction sa;
-#endif
+# endif
+# if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY)
+ int fid;
+# endif
+# endif /* HAVE_WORKING_FORK*/
+# ifdef SCO5_CLOCK
+ int fd;
+ int zero;
+# endif
+# ifdef HAVE_UMASK
+ uv = umask(0);
+ if (uv)
+ umask(uv);
+ else
+ umask(022);
+# endif
+ saved_argc = argc;
+ saved_argv = argv;
progname = argv[0];
+ initializing = TRUE; /* mark that we are initializing */
+ parse_cmdline_opts(&argc, &argv);
+# ifdef DEBUG
+ debug = OPT_VALUE_SET_DEBUG_LEVEL;
+# ifdef HAVE_SETLINEBUF
+ setlinebuf(stdout);
+# endif
+# endif
- initializing = 1; /* mark that we are initializing */
-
- {
- int optct = optionProcess(
-#ifdef SIM
- &ntpdsimOptions
-#else
- &ntpdOptions
-#endif
- , argc, argv);
- argc -= optct;
- argv += optct;
- }
-
- /* HMS: is this lame? Should we process -l first? */
-
- init_logging(progname); /* Open the log file */
-
-#ifdef HAVE_UMASK
- {
- mode_t uv;
-
- uv = umask(0);
- if(uv)
- (void) umask(uv);
- else
- (void) umask(022);
+ if (HAVE_OPT(NOFORK) || HAVE_OPT(QUIT)
+# ifdef DEBUG
+ || debug
+# endif
+ || HAVE_OPT(SAVECONFIGQUIT))
+ nofork = TRUE;
+
+ init_logging(progname, NLOG_SYNCMASK, TRUE);
+ /* honor -l/--logfile option to log to a file */
+ if (HAVE_OPT(LOGFILE)) {
+ logfilename = OPT_ARG(LOGFILE);
+ syslogit = FALSE;
+ change_logfile(logfilename, FALSE);
+ } else {
+ logfilename = NULL;
+ if (nofork)
+ msyslog_term = TRUE;
+ if (HAVE_OPT(SAVECONFIGQUIT))
+ syslogit = FALSE;
}
-#endif
+ msyslog(LOG_NOTICE, "%s: Starting", Version);
-#if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */
{
- uid_t uid;
-
- uid = getuid();
- if (uid)
- {
- msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid);
- printf("must be run as root, not uid %ld", (long)uid);
- exit(1);
+ int i;
+ char buf[1024]; /* Secret knowledge of msyslog buf length */
+ char *cp = buf;
+
+ /* Note that every arg has an initial space character */
+ snprintf(cp, sizeof(buf), "Command line:");
+ cp += strlen(cp);
+
+ for (i = 0; i < saved_argc ; ++i) {
+ snprintf(cp, sizeof(buf) - (cp - buf),
+ " %s", saved_argv[i]);
+ cp += strlen(cp);
}
+ msyslog(LOG_INFO, "%s", buf);
}
-#endif
-#ifdef OPENSSL
- if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
+ /*
+ * Install trap handlers to log errors and assertion failures.
+ * Default handlers print to stderr which doesn't work if detached.
+ */
+ isc_assertion_setcallback(assertion_failed);
+ isc_error_setfatal(library_fatal_error);
+ isc_error_setunexpected(library_unexpected_error);
+
+ /* MPE lacks the concept of root */
+# if defined(HAVE_GETUID) && !defined(MPE)
+ uid = getuid();
+ if (uid && !HAVE_OPT( SAVECONFIGQUIT )) {
+ msyslog_term = TRUE;
msyslog(LOG_ERR,
- "ntpd: OpenSSL version mismatch. Built against %lx, you have %lx\n",
- OPENSSL_VERSION_NUMBER, SSLeay());
+ "must be run as root, not uid %ld", (long)uid);
exit(1);
}
-#endif
-
- /* getstartup(argc, argv); / * startup configuration, may set debug */
-
-#ifdef DEBUG
- debug = DESC(DEBUG_LEVEL).optOccCt;
- if (debug)
- printf("%s\n", Version);
-#endif
+# endif
/*
* Enable the Multi-Media Timer for Windows?
*/
-#ifdef SYS_WINNT
+# ifdef SYS_WINNT
if (HAVE_OPT( MODIFYMMTIMER ))
set_mm_timer(MM_TIMER_HIRES);
-#endif
+# endif
- if (HAVE_OPT( NOFORK ) || HAVE_OPT( QUIT ))
- nofork = 1;
+#ifdef HAVE_DNSREGISTRATION
+/*
+ * Enable mDNS registrations?
+ */
+ if (HAVE_OPT( MDNS )) {
+ mdnsreg = TRUE;
+ }
+#endif /* HAVE_DNSREGISTRATION */
if (HAVE_OPT( NOVIRTUALIPS ))
listen_to_virtual_ips = 0;
+ /*
+ * --interface, listen on specified interfaces
+ */
if (HAVE_OPT( INTERFACE )) {
-#if 0
- int ifacect = STACKCT_OPT( INTERFACE );
- char** ifaces = STACKLST_OPT( INTERFACE );
+ int ifacect = STACKCT_OPT( INTERFACE );
+ const char** ifaces = STACKLST_OPT( INTERFACE );
+ sockaddr_u addr;
- /* malloc space for the array of names */
while (ifacect-- > 0) {
- next_iface = *ifaces++;
+ add_nic_rule(
+ is_ip_address(*ifaces, AF_UNSPEC, &addr)
+ ? MATCH_IFADDR
+ : MATCH_IFNAME,
+ *ifaces, -1, ACTION_LISTEN);
+ ifaces++;
}
-#else
- specific_interface = OPT_ARG( INTERFACE );
-#endif
}
if (HAVE_OPT( NICE ))
priority_done = 0;
-#if defined(HAVE_SCHED_SETSCHEDULER)
+# ifdef HAVE_SCHED_SETSCHEDULER
if (HAVE_OPT( PRIORITY )) {
config_priority = OPT_VALUE_PRIORITY;
config_priority_override = 1;
priority_done = 0;
}
-#endif
+# endif
+
+# ifdef HAVE_WORKING_FORK
+ do { /* 'loop' once */
+ if (!HAVE_OPT( WAIT_SYNC ))
+ break;
+ wait_sync = OPT_VALUE_WAIT_SYNC;
+ if (wait_sync <= 0) {
+ wait_sync = 0;
+ break;
+ }
+ /* -w requires a fork() even with debug > 0 */
+ nofork = FALSE;
+ if (pipe(pipe_fds)) {
+ exit_code = (errno) ? errno : -1;
+ msyslog(LOG_ERR,
+ "Pipe creation failed for --wait-sync: %m");
+ exit(exit_code);
+ }
+ waitsync_fd_to_close = pipe_fds[1];
+ } while (0); /* 'loop' once */
+# endif /* HAVE_WORKING_FORK */
-#ifdef SYS_WINNT
+ init_lib();
+# ifdef SYS_WINNT
/*
- * Initialize the time structures and variables
+ * Start interpolation thread, must occur before first
+ * get_systime()
*/
init_winnt_time();
-#endif
-
- setup_logfile();
-
+# endif
/*
* Initialize random generator and public key pair
*/
@@ -570,256 +613,171 @@ ntpdmain(
ntp_srandom((int)(now.l_i * now.l_uf));
-#ifdef HAVE_DNSREGISTRATION
- /* HMS: does this have to happen this early? */
- msyslog(LOG_INFO, "Attemping to register mDNS");
- if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL, htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) {
- msyslog(LOG_ERR, "Unable to register mDNS");
- }
-#endif
-
-#if !defined(VMS)
-# ifndef NODETACH
/*
* Detach us from the terminal. May need an #ifndef GIZMO.
*/
- if (
-# ifdef DEBUG
- !debug &&
-# endif /* DEBUG */
- !nofork)
- {
-# ifndef SYS_WINNT
-# ifdef HAVE_DAEMON
- daemon(0, 0);
-# else /* not HAVE_DAEMON */
- if (fork()) /* HMS: What about a -1? */
- exit(0);
-
- {
-#if !defined(F_CLOSEM)
- u_long s;
- int max_fd;
-#endif /* not F_CLOSEM */
+ if (!nofork) {
+
+# ifdef HAVE_WORKING_FORK
+ rc = fork();
+ if (-1 == rc) {
+ exit_code = (errno) ? errno : -1;
+ msyslog(LOG_ERR, "fork: %m");
+ exit(exit_code);
+ }
+ if (rc > 0) {
+ /* parent */
+ exit_code = wait_child_sync_if(pipe_fds[0],
+ wait_sync);
+ exit(exit_code);
+ }
+
+ /*
+ * child/daemon
+ * close all open files excepting waitsync_fd_to_close.
+ * msyslog() unreliable until after init_logging().
+ */
+ closelog();
+ if (syslog_file != NULL) {
+ fclose(syslog_file);
+ syslog_file = NULL;
+ syslogit = TRUE;
+ }
+ close_all_except(waitsync_fd_to_close);
+ INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \
+ && 2 == dup2(0, 2));
-#if defined(F_CLOSEM)
- /*
- * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
- * by Eric Agar (saves us from doing 32767 system
- * calls)
- */
- if (fcntl(0, F_CLOSEM, 0) == -1)
- msyslog(LOG_ERR, "ntpd: failed to close open files(): %m");
-#else /* not F_CLOSEM */
-
-# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
- max_fd = sysconf(_SC_OPEN_MAX);
-# else /* HAVE_SYSCONF && _SC_OPEN_MAX */
- max_fd = getdtablesize();
-# endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
- for (s = 0; s < max_fd; s++)
- (void) close((int)s);
-#endif /* not F_CLOSEM */
- (void) open("/", 0);
- (void) dup2(0, 1);
- (void) dup2(0, 2);
-#ifdef SYS_DOMAINOS
- {
- uid_$t puid;
- status_$t st;
+ init_logging(progname, 0, TRUE);
+ /* we lost our logfile (if any) daemonizing */
+ setup_logfile(logfilename);
- proc2_$who_am_i(&puid);
- proc2_$make_server(&puid, &st);
- }
-#endif /* SYS_DOMAINOS */
-#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
-# ifdef HAVE_SETSID
- if (setsid() == (pid_t)-1)
- msyslog(LOG_ERR, "ntpd: setsid(): %m");
-# else
- if (setpgid(0, 0) == -1)
- msyslog(LOG_ERR, "ntpd: setpgid(): %m");
-# endif
-#else /* HAVE_SETPGID || HAVE_SETSID */
- {
-# if defined(TIOCNOTTY)
- int fid;
-
- fid = open("/dev/tty", 2);
- if (fid >= 0)
- {
- (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
- (void) close(fid);
- }
-# endif /* defined(TIOCNOTTY) */
-# ifdef HAVE_SETPGRP_0
- (void) setpgrp();
-# else /* HAVE_SETPGRP_0 */
- (void) setpgrp(0, getpid());
-# endif /* HAVE_SETPGRP_0 */
- }
-#endif /* HAVE_SETPGID || HAVE_SETSID */
-#ifdef _AIX
- /* Don't get killed by low-on-memory signal. */
- sa.sa_handler = catch_danger;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
+# ifdef SYS_DOMAINOS
+ {
+ uid_$t puid;
+ status_$t st;
- (void) sigaction(SIGDANGER, &sa, NULL);
-#endif /* _AIX */
+ proc2_$who_am_i(&puid);
+ proc2_$make_server(&puid, &st);
}
-# endif /* not HAVE_DAEMON */
-# endif /* SYS_WINNT */
+# endif /* SYS_DOMAINOS */
+# ifdef HAVE_SETSID
+ if (setsid() == (pid_t)-1)
+ msyslog(LOG_ERR, "setsid(): %m");
+# elif defined(HAVE_SETPGID)
+ if (setpgid(0, 0) == -1)
+ msyslog(LOG_ERR, "setpgid(): %m");
+# else /* !HAVE_SETSID && !HAVE_SETPGID follows */
+# ifdef TIOCNOTTY
+ fid = open("/dev/tty", 2);
+ if (fid >= 0) {
+ ioctl(fid, (u_long)TIOCNOTTY, NULL);
+ close(fid);
+ }
+# endif /* TIOCNOTTY */
+ ntp_setpgrp(0, getpid());
+# endif /* !HAVE_SETSID && !HAVE_SETPGID */
+# ifdef _AIX
+ /* Don't get killed by low-on-memory signal. */
+ sa.sa_handler = catch_danger;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGDANGER, &sa, NULL);
+# endif /* _AIX */
+# endif /* HAVE_WORKING_FORK */
}
-# endif /* NODETACH */
-#endif /* VMS */
-
- setup_logfile(); /* We lost any redirect when we daemonized */
-#ifdef SCO5_CLOCK
+# ifdef SCO5_CLOCK
/*
* SCO OpenServer's system clock offers much more precise timekeeping
* on the base CPU than the other CPUs (for multiprocessor systems),
* so we must lock to the base CPU.
*/
- {
- int fd = open("/dev/at1", O_RDONLY);
- if (fd >= 0) {
- int zero = 0;
+ fd = open("/dev/at1", O_RDONLY);
+ if (fd >= 0) {
+ zero = 0;
if (ioctl(fd, ACPU_LOCK, &zero) < 0)
- msyslog(LOG_ERR, "cannot lock to base CPU: %m");
- close( fd );
- } /* else ...
- * If we can't open the device, this probably just isn't
- * a multiprocessor system, so we're A-OK.
- */
+ msyslog(LOG_ERR, "cannot lock to base CPU: %m");
+ close(fd);
}
-#endif
+# endif
-#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
-# ifdef HAVE_SETRLIMIT
+ /* Setup stack size in preparation for locking pages in memory. */
+# if defined(HAVE_MLOCKALL)
+# ifdef HAVE_SETRLIMIT
+ ntp_rlimit(RLIMIT_STACK, DFLT_RLIMIT_STACK * 4096, 4096, "4k");
+# ifdef RLIMIT_MEMLOCK
/*
- * Set the stack limit to something smaller, so that we don't lock a lot
- * of unused stack memory.
+ * The default RLIMIT_MEMLOCK is very low on Linux systems.
+ * Unless we increase this limit malloc calls are likely to
+ * fail if we drop root privilege. To be useful the value
+ * has to be larger than the largest ntpd resident set size.
*/
- {
- struct rlimit rl;
-
- /* HMS: must make the rlim_cur amount configurable */
- if (getrlimit(RLIMIT_STACK, &rl) != -1
- && (rl.rlim_cur = 50 * 4096) < rl.rlim_max)
- {
- if (setrlimit(RLIMIT_STACK, &rl) == -1)
- {
- msyslog(LOG_ERR,
- "Cannot adjust stack limit for mlockall: %m");
- }
- }
-# ifdef RLIMIT_MEMLOCK
- /*
- * The default RLIMIT_MEMLOCK is very low on Linux systems.
- * Unless we increase this limit malloc calls are likely to
- * fail if we drop root privlege. To be useful the value
- * has to be larger than the largest ntpd resident set size.
- */
- rl.rlim_cur = rl.rlim_max = 32*1024*1024;
- if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) {
- msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
- }
-# endif /* RLIMIT_MEMLOCK */
- }
-# endif /* HAVE_SETRLIMIT */
+ ntp_rlimit(RLIMIT_MEMLOCK, DFLT_RLIMIT_MEMLOCK * 1024 * 1024, 1024 * 1024, "MB");
+# endif /* RLIMIT_MEMLOCK */
+# endif /* HAVE_SETRLIMIT */
+# else /* !HAVE_MLOCKALL follows */
+# ifdef HAVE_PLOCK
+# ifdef PROCLOCK
+# ifdef _AIX
/*
- * lock the process into memory
- */
- if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
- msyslog(LOG_ERR, "mlockall(): %m");
-#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
-# ifdef HAVE_PLOCK
-# ifdef PROCLOCK
-# ifdef _AIX
- /*
* set the stack limit for AIX for plock().
* see get_aix_stack() for more info.
*/
- if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0)
- {
- msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m");
- }
-# endif /* _AIX */
- /*
- * lock the process into memory
- */
- if (plock(PROCLOCK) < 0)
- msyslog(LOG_ERR, "plock(PROCLOCK): %m");
-# else /* not PROCLOCK */
-# ifdef TXTLOCK
- /*
- * Lock text into ram
- */
- if (plock(TXTLOCK) < 0)
- msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
-# else /* not TXTLOCK */
- msyslog(LOG_ERR, "plock() - don't know what to lock!");
-# endif /* not TXTLOCK */
-# endif /* not PROCLOCK */
-# endif /* HAVE_PLOCK */
-#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
+ if (ulimit(SET_STACKLIM, (get_aix_stack() - 8 * 4096)) < 0)
+ msyslog(LOG_ERR,
+ "Cannot adjust stack limit for plock: %m");
+# endif /* _AIX */
+# endif /* PROCLOCK */
+# endif /* HAVE_PLOCK */
+# endif /* !HAVE_MLOCKALL */
/*
* Set up signals we pay attention to locally.
*/
-#ifdef SIGDIE1
- (void) signal_no_reset(SIGDIE1, finish);
-#endif /* SIGDIE1 */
-#ifdef SIGDIE2
- (void) signal_no_reset(SIGDIE2, finish);
-#endif /* SIGDIE2 */
-#ifdef SIGDIE3
- (void) signal_no_reset(SIGDIE3, finish);
-#endif /* SIGDIE3 */
-#ifdef SIGDIE4
- (void) signal_no_reset(SIGDIE4, finish);
-#endif /* SIGDIE4 */
-
-#ifdef SIGBUS
- (void) signal_no_reset(SIGBUS, finish);
-#endif /* SIGBUS */
-
-#if !defined(SYS_WINNT) && !defined(VMS)
-# ifdef DEBUG
+# ifdef SIGDIE1
+ signal_no_reset(SIGDIE1, finish);
+ signal_no_reset(SIGDIE2, finish);
+ signal_no_reset(SIGDIE3, finish);
+ signal_no_reset(SIGDIE4, finish);
+# endif
+# ifdef SIGBUS
+ signal_no_reset(SIGBUS, finish);
+# endif
+
+# if !defined(SYS_WINNT) && !defined(VMS)
+# ifdef DEBUG
(void) signal_no_reset(MOREDEBUGSIG, moredebug);
(void) signal_no_reset(LESSDEBUGSIG, lessdebug);
-# else
+# else
(void) signal_no_reset(MOREDEBUGSIG, no_debug);
(void) signal_no_reset(LESSDEBUGSIG, no_debug);
-# endif /* DEBUG */
-#endif /* !SYS_WINNT && !VMS */
+# endif /* DEBUG */
+# endif /* !SYS_WINNT && !VMS */
/*
* Set up signals we should never pay attention to.
*/
-#if defined SIGPIPE
- (void) signal_no_reset(SIGPIPE, SIG_IGN);
-#endif /* SIGPIPE */
+# ifdef SIGPIPE
+ signal_no_reset(SIGPIPE, SIG_IGN);
+# endif
/*
* Call the init_ routines to initialize the data structures.
*
* Exactly what command-line options are we expecting here?
*/
+ INIT_SSL();
init_auth();
init_util();
init_restrict();
init_mon();
init_timer();
- init_lib();
init_request();
init_control();
init_peer();
-#ifdef REFCLOCK
+# ifdef REFCLOCK
init_refclock();
-#endif
+# endif
set_process_priority();
init_proto(); /* Call at high priority */
init_io();
@@ -831,45 +789,90 @@ ntpdmain(
* Get the configuration. This is done in a separate module
* since this will definitely be different for the gizmo board.
*/
-
getconfig(argc, argv);
- loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
-#ifdef OPENSSL
- crypto_setup();
-#endif /* OPENSSL */
- initializing = 0;
+ if (do_memlock) {
+# if defined(HAVE_MLOCKALL)
+ /*
+ * lock the process into memory
+ */
+ if (!HAVE_OPT(SAVECONFIGQUIT) &&
+ 0 != mlockall(MCL_CURRENT|MCL_FUTURE))
+ msyslog(LOG_ERR, "mlockall(): %m");
+# else /* !HAVE_MLOCKALL follows */
+# ifdef HAVE_PLOCK
+# ifdef PROCLOCK
+ /*
+ * lock the process into memory
+ */
+ if (!HAVE_OPT(SAVECONFIGQUIT) && 0 != plock(PROCLOCK))
+ msyslog(LOG_ERR, "plock(PROCLOCK): %m");
+# else /* !PROCLOCK follows */
+# ifdef TXTLOCK
+ /*
+ * Lock text into ram
+ */
+ if (!HAVE_OPT(SAVECONFIGQUIT) && 0 != plock(TXTLOCK))
+ msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
+# else /* !TXTLOCK follows */
+ msyslog(LOG_ERR, "plock() - don't know what to lock!");
+# endif /* !TXTLOCK */
+# endif /* !PROCLOCK */
+# endif /* HAVE_PLOCK */
+# endif /* !HAVE_MLOCKALL */
+ }
-#ifdef HAVE_DROPROOT
- if( droproot ) {
+ loop_config(LOOP_DRIFTINIT, 0);
+ report_event(EVNT_SYSRESTART, NULL, NULL);
+ initializing = FALSE;
+
+# ifdef HAVE_DROPROOT
+ if (droproot) {
/* Drop super-user privileges and chroot now if the OS supports this */
-#ifdef HAVE_LINUX_CAPABILITIES
+# ifdef HAVE_LINUX_CAPABILITIES
/* set flag: keep privileges accross setuid() call (we only really need cap_sys_time): */
- if( prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1 ) {
+ if (prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1) {
msyslog( LOG_ERR, "prctl( PR_SET_KEEPCAPS, 1L ) failed: %m" );
exit(-1);
}
-#else
+# elif HAVE_SOLARIS_PRIVS
+ /* Nothing to do here */
+# else
/* we need a user to switch to */
- if( user == NULL ) {
+ if (user == NULL) {
msyslog(LOG_ERR, "Need user name to drop root privileges (see -u flag!)" );
exit(-1);
}
-#endif /* HAVE_LINUX_CAPABILITIES */
-
+# endif /* HAVE_LINUX_CAPABILITIES || HAVE_SOLARIS_PRIVS */
+
if (user != NULL) {
if (isdigit((unsigned char)*user)) {
sw_uid = (uid_t)strtoul(user, &endp, 0);
- if (*endp != '\0')
+ if (*endp != '\0')
goto getuser;
+
+ if ((pw = getpwuid(sw_uid)) != NULL) {
+ free(user);
+ user = estrdup(pw->pw_name);
+ sw_gid = pw->pw_gid;
+ } else {
+ errno = 0;
+ msyslog(LOG_ERR, "Cannot find user ID %s", user);
+ exit (-1);
+ }
+
} else {
-getuser:
+getuser:
+ errno = 0;
if ((pw = getpwnam(user)) != NULL) {
sw_uid = pw->pw_uid;
+ sw_gid = pw->pw_gid;
} else {
- errno = 0;
- msyslog(LOG_ERR, "Cannot find user `%s'", user);
+ if (errno)
+ msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user);
+ else
+ msyslog(LOG_ERR, "Cannot find user `%s'", user);
exit (-1);
}
}
@@ -877,10 +880,10 @@ getuser:
if (group != NULL) {
if (isdigit((unsigned char)*group)) {
sw_gid = (gid_t)strtoul(group, &endp, 0);
- if (*endp != '\0')
+ if (*endp != '\0')
goto getgroup;
} else {
-getgroup:
+getgroup:
if ((gr = getgrnam(group)) != NULL) {
sw_gid = gr->gr_gid;
} else {
@@ -890,17 +893,41 @@ getgroup:
}
}
}
-
- if( chrootdir ) {
+
+ if (chrootdir ) {
/* make sure cwd is inside the jail: */
- if( chdir(chrootdir) ) {
+ if (chdir(chrootdir)) {
msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir);
exit (-1);
}
- if( chroot(chrootdir) ) {
+ if (chroot(chrootdir)) {
msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir);
exit (-1);
}
+ if (chdir("/")) {
+ msyslog(LOG_ERR, "Cannot chdir() to`root after chroot(): %m");
+ exit (-1);
+ }
+ }
+# ifdef HAVE_SOLARIS_PRIVS
+ if ((lowprivs = priv_str_to_set(LOWPRIVS, ",", NULL)) == NULL) {
+ msyslog(LOG_ERR, "priv_str_to_set() failed:%m");
+ exit(-1);
+ }
+ if ((highprivs = priv_allocset()) == NULL) {
+ msyslog(LOG_ERR, "priv_allocset() failed:%m");
+ exit(-1);
+ }
+ (void) getppriv(PRIV_PERMITTED, highprivs);
+ (void) priv_intersect(highprivs, lowprivs);
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, lowprivs) == -1) {
+ msyslog(LOG_ERR, "setppriv() failed:%m");
+ exit(-1);
+ }
+# endif /* HAVE_SOLARIS_PRIVS */
+ if (user && initgroups(user, sw_gid)) {
+ msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user);
+ exit (-1);
}
if (group && setgid(sw_gid)) {
msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
@@ -910,6 +937,10 @@ getgroup:
msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
exit (-1);
}
+ if (group)
+ setgroups(1, &sw_gid);
+ else
+ initgroups(pw->pw_name, pw->pw_gid);
if (user && setuid(sw_uid)) {
msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
exit (-1);
@@ -918,192 +949,249 @@ getgroup:
msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
exit (-1);
}
-
-#ifndef HAVE_LINUX_CAPABILITIES
+
+# if !defined(HAVE_LINUX_CAPABILITIES) && !defined(HAVE_SOLARIS_PRIVS)
/*
* for now assume that the privilege to bind to privileged ports
* is associated with running with uid 0 - should be refined on
* ports that allow binding to NTP_PORT with uid != 0
*/
disable_dynamic_updates |= (sw_uid != 0); /* also notifies routing message listener */
-#endif
+# endif /* !HAVE_LINUX_CAPABILITIES && !HAVE_SOLARIS_PRIVS */
if (disable_dynamic_updates && interface_interval) {
interface_interval = 0;
- msyslog(LOG_INFO, "running in unprivileged mode disables dynamic interface tracking");
+ msyslog(LOG_INFO, "running as non-root disables dynamic interface tracking");
}
-#ifdef HAVE_LINUX_CAPABILITIES
- do {
+# ifdef HAVE_LINUX_CAPABILITIES
+ {
/*
* We may be running under non-root uid now, but we still hold full root privileges!
* We drop all of them, except for the crucial one or two: cap_sys_time and
* cap_net_bind_service if doing dynamic interface tracking.
*/
cap_t caps;
- char *captext = interface_interval ?
- "cap_sys_time,cap_net_bind_service=ipe" :
- "cap_sys_time=ipe";
- if( ! ( caps = cap_from_text( captext ) ) ) {
- msyslog( LOG_ERR, "cap_from_text() failed: %m" );
+ char *captext;
+
+ captext = (0 != interface_interval)
+ ? "cap_sys_time,cap_net_bind_service=pe"
+ : "cap_sys_time=pe";
+ caps = cap_from_text(captext);
+ if (!caps) {
+ msyslog(LOG_ERR,
+ "cap_from_text(%s) failed: %m",
+ captext);
exit(-1);
}
- if( cap_set_proc( caps ) == -1 ) {
- msyslog( LOG_ERR, "cap_set_proc() failed to drop root privileges: %m" );
+ if (-1 == cap_set_proc(caps)) {
+ msyslog(LOG_ERR,
+ "cap_set_proc() failed to drop root privs: %m");
exit(-1);
}
- cap_free( caps );
- } while(0);
-#endif /* HAVE_LINUX_CAPABILITIES */
+ cap_free(caps);
+ }
+# endif /* HAVE_LINUX_CAPABILITIES */
+# ifdef HAVE_SOLARIS_PRIVS
+ if (priv_delset(lowprivs, "proc_setid") == -1) {
+ msyslog(LOG_ERR, "priv_delset() failed:%m");
+ exit(-1);
+ }
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, lowprivs) == -1) {
+ msyslog(LOG_ERR, "setppriv() failed:%m");
+ exit(-1);
+ }
+ priv_freeset(lowprivs);
+ priv_freeset(highprivs);
+# endif /* HAVE_SOLARIS_PRIVS */
+ root_dropped = TRUE;
+ fork_deferred_worker();
+ } /* if (droproot) */
+# endif /* HAVE_DROPROOT */
+
+/* libssecomp sandboxing */
+#if defined (LIBSECCOMP) && (KERN_SECCOMP)
+ scmp_filter_ctx ctx;
+
+ if ((ctx = seccomp_init(SCMP_ACT_KILL)) < 0)
+ msyslog(LOG_ERR, "%s: seccomp_init(SCMP_ACT_KILL) failed: %m", __func__);
+ else {
+ msyslog(LOG_DEBUG, "%s: seccomp_init(SCMP_ACT_KILL) succeeded", __func__);
+ }
- } /* if( droproot ) */
-#endif /* HAVE_DROPROOT */
-
- /*
- * Report that we're up to any trappers
- */
- report_event(EVNT_SYSRESTART, (struct peer *)0);
+#ifdef __x86_64__
+int scmp_sc[] = {
+ SCMP_SYS(adjtimex),
+ SCMP_SYS(bind),
+ SCMP_SYS(brk),
+ SCMP_SYS(chdir),
+ SCMP_SYS(clock_gettime),
+ SCMP_SYS(clock_settime),
+ SCMP_SYS(close),
+ SCMP_SYS(connect),
+ SCMP_SYS(exit_group),
+ SCMP_SYS(fstat),
+ SCMP_SYS(fsync),
+ SCMP_SYS(futex),
+ SCMP_SYS(getitimer),
+ SCMP_SYS(getsockname),
+ SCMP_SYS(ioctl),
+ SCMP_SYS(lseek),
+ SCMP_SYS(madvise),
+ SCMP_SYS(mmap),
+ SCMP_SYS(munmap),
+ SCMP_SYS(open),
+ SCMP_SYS(poll),
+ SCMP_SYS(read),
+ SCMP_SYS(recvmsg),
+ SCMP_SYS(rename),
+ SCMP_SYS(rt_sigaction),
+ SCMP_SYS(rt_sigprocmask),
+ SCMP_SYS(rt_sigreturn),
+ SCMP_SYS(select),
+ SCMP_SYS(sendto),
+ SCMP_SYS(setitimer),
+ SCMP_SYS(setsid),
+ SCMP_SYS(socket),
+ SCMP_SYS(stat),
+ SCMP_SYS(time),
+ SCMP_SYS(write),
+};
+#endif
+#ifdef __i386__
+int scmp_sc[] = {
+ SCMP_SYS(_newselect),
+ SCMP_SYS(adjtimex),
+ SCMP_SYS(brk),
+ SCMP_SYS(chdir),
+ SCMP_SYS(clock_gettime),
+ SCMP_SYS(clock_settime),
+ SCMP_SYS(close),
+ SCMP_SYS(exit_group),
+ SCMP_SYS(fsync),
+ SCMP_SYS(futex),
+ SCMP_SYS(getitimer),
+ SCMP_SYS(madvise),
+ SCMP_SYS(mmap),
+ SCMP_SYS(mmap2),
+ SCMP_SYS(munmap),
+ SCMP_SYS(open),
+ SCMP_SYS(poll),
+ SCMP_SYS(read),
+ SCMP_SYS(rename),
+ SCMP_SYS(rt_sigaction),
+ SCMP_SYS(rt_sigprocmask),
+ SCMP_SYS(select),
+ SCMP_SYS(setitimer),
+ SCMP_SYS(setsid),
+ SCMP_SYS(sigprocmask),
+ SCMP_SYS(sigreturn),
+ SCMP_SYS(socketcall),
+ SCMP_SYS(stat64),
+ SCMP_SYS(time),
+ SCMP_SYS(write),
+};
+#endif
+ {
+ int i;
+
+ for (i = 0; i < COUNTOF(scmp_sc); i++) {
+ if (seccomp_rule_add(ctx,
+ SCMP_ACT_ALLOW, scmp_sc[i], 0) < 0) {
+ msyslog(LOG_ERR,
+ "%s: seccomp_rule_add() failed: %m",
+ __func__);
+ }
+ }
+ }
- /*
- * Use select() on all on all input fd's for unlimited
- * time. select() will terminate on SIGALARM or on the
- * reception of input. Using select() means we can't do
- * robust signal handling and we get a potential race
- * between checking for alarms and doing the select().
- * Mostly harmless, I think.
- */
- /* On VMS, I suspect that select() can't be interrupted
- * by a "signal" either, so I take the easy way out and
- * have select() time out after one second.
- * System clock updates really aren't time-critical,
- * and - lacking a hardware reference clock - I have
- * yet to learn about anything else that is.
- */
-#if defined(HAVE_IO_COMPLETION_PORT)
+ if (seccomp_load(ctx) < 0)
+ msyslog(LOG_ERR, "%s: seccomp_load() failed: %m",
+ __func__);
+ else {
+ msyslog(LOG_DEBUG, "%s: seccomp_load() succeeded", __func__);
+ }
+#endif /* LIBSECCOMP and KERN_SECCOMP */
+
+# ifdef HAVE_IO_COMPLETION_PORT
for (;;) {
GetReceivedBuffers();
-#else /* normal I/O */
+# else /* normal I/O */
BLOCK_IO_AND_ALARM();
- was_alarmed = 0;
- for (;;)
- {
-# if !defined(HAVE_SIGNALED_IO)
- extern fd_set activefds;
- extern int maxactivefd;
-
- fd_set rdfdes;
- int nfound;
-# endif
+ was_alarmed = FALSE;
- if (alarm_flag) /* alarmed? */
- {
- was_alarmed = 1;
- alarm_flag = 0;
+ for (;;) {
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = TRUE;
+ alarm_flag = FALSE;
}
- if (!was_alarmed && has_full_recv_buffer() == ISC_FALSE)
- {
+ if (!was_alarmed && !has_full_recv_buffer()) {
/*
* Nothing to do. Wait for something.
*/
-# ifndef HAVE_SIGNALED_IO
- rdfdes = activefds;
-# if defined(VMS) || defined(SYS_VXWORKS)
- /* make select() wake up after one second */
- {
- struct timeval t1;
-
- t1.tv_sec = 1; t1.tv_usec = 0;
- nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
- (fd_set *)0, &t1);
- }
-# else
- nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
- (fd_set *)0, (struct timeval *)0);
-# endif /* VMS */
- if (nfound > 0)
- {
- l_fp ts;
-
- get_systime(&ts);
+ io_handler();
+ }
- (void)input_handler(&ts);
- }
- else if (nfound == -1 && errno != EINTR)
- netsyslog(LOG_ERR, "select() error: %m");
-# ifdef DEBUG
- else if (debug > 5)
- netsyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
-# endif /* DEBUG */
-# else /* HAVE_SIGNALED_IO */
-
- wait_for_signal();
-# endif /* HAVE_SIGNALED_IO */
- if (alarm_flag) /* alarmed? */
- {
- was_alarmed = 1;
- alarm_flag = 0;
- }
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = TRUE;
+ alarm_flag = FALSE;
}
- if (was_alarmed)
- {
+ if (was_alarmed) {
UNBLOCK_IO_AND_ALARM();
/*
* Out here, signals are unblocked. Call timer routine
* to process expiry.
*/
timer();
- was_alarmed = 0;
- BLOCK_IO_AND_ALARM();
+ was_alarmed = FALSE;
+ BLOCK_IO_AND_ALARM();
}
-#endif /* HAVE_IO_COMPLETION_PORT */
+# endif /* !HAVE_IO_COMPLETION_PORT */
-#ifdef DEBUG_TIMING
+# ifdef DEBUG_TIMING
{
l_fp pts;
l_fp tsa, tsb;
int bufcount = 0;
-
+
get_systime(&pts);
tsa = pts;
-#endif
+# endif
rbuf = get_full_recv_buffer();
- while (rbuf != NULL)
- {
- if (alarm_flag)
- {
- was_alarmed = 1;
- alarm_flag = 0;
+ while (rbuf != NULL) {
+ if (alarm_flag) {
+ was_alarmed = TRUE;
+ alarm_flag = FALSE;
}
UNBLOCK_IO_AND_ALARM();
- if (was_alarmed)
- { /* avoid timer starvation during lengthy I/O handling */
+ if (was_alarmed) {
+ /* avoid timer starvation during lengthy I/O handling */
timer();
- was_alarmed = 0;
+ was_alarmed = FALSE;
}
/*
* Call the data procedure to handle each received
* packet.
*/
- if (rbuf->receiver != NULL) /* This should always be true */
- {
-#ifdef DEBUG_TIMING
+ if (rbuf->receiver != NULL) {
+# ifdef DEBUG_TIMING
l_fp dts = pts;
L_SUB(&dts, &rbuf->recv_time);
DPRINTF(2, ("processing timestamp delta %s (with prec. fuzz)\n", lfptoa(&dts, 9)));
collect_timing(rbuf, "buffer processing delay", 1, &dts);
bufcount++;
-#endif
- (rbuf->receiver)(rbuf);
+# endif
+ (*rbuf->receiver)(rbuf);
} else {
- msyslog(LOG_ERR, "receive buffer corruption - receiver found to be NULL - ABORTING");
+ msyslog(LOG_ERR, "fatal: receive buffer callback NULL");
abort();
}
@@ -1111,7 +1199,7 @@ getgroup:
freerecvbuf(rbuf);
rbuf = get_full_recv_buffer();
}
-#ifdef DEBUG_TIMING
+# ifdef DEBUG_TIMING
get_systime(&tsb);
L_SUB(&tsb, &tsa);
if (bufcount) {
@@ -1119,18 +1207,38 @@ getgroup:
DPRINTF(2, ("processing time for %d buffers %s\n", bufcount, lfptoa(&tsb, 9)));
}
}
-#endif
+# endif
/*
* Go around again
*/
+
+# ifdef HAVE_DNSREGISTRATION
+ if (mdnsreg && (current_time - mdnsreg ) > 60 && mdnstries && sys_leap != LEAP_NOTINSYNC) {
+ mdnsreg = current_time;
+ msyslog(LOG_INFO, "Attempting to register mDNS");
+ if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL,
+ htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) {
+ if (!--mdnstries) {
+ msyslog(LOG_ERR, "Unable to register mDNS, giving up.");
+ } else {
+ msyslog(LOG_INFO, "Unable to register mDNS, will try later.");
+ }
+ } else {
+ msyslog(LOG_INFO, "mDNS service registered.");
+ mdnsreg = FALSE;
+ }
+ }
+# endif /* HAVE_DNSREGISTRATION */
+
}
UNBLOCK_IO_AND_ALARM();
return 1;
}
+#endif /* !SIM */
-#ifdef SIGDIE2
+#if !defined(SIM) && defined(SIGDIE1)
/*
* finish - exit gracefully
*/
@@ -1139,32 +1247,185 @@ finish(
int sig
)
{
+ const char *sig_desc;
- msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig);
- write_stats();
-#ifdef HAVE_DNSREGISTRATION
+ sig_desc = NULL;
+#ifdef HAVE_STRSIGNAL
+ sig_desc = strsignal(sig);
+#endif
+ if (sig_desc == NULL)
+ sig_desc = "";
+ msyslog(LOG_NOTICE, "%s exiting on signal %d (%s)", progname,
+ sig, sig_desc);
+ /* See Bug 2513 and Bug 2522 re the unlink of PIDFILE */
+# ifdef HAVE_DNSREGISTRATION
if (mdns != NULL)
- DNSServiceRefDeallocate(mdns);
+ DNSServiceRefDeallocate(mdns);
+# endif
+ peer_cleanup();
+ exit(0);
+}
+#endif /* !SIM && SIGDIE1 */
+
+
+#ifndef SIM
+/*
+ * wait_child_sync_if - implements parent side of -w/--wait-sync
+ */
+# ifdef HAVE_WORKING_FORK
+static int
+wait_child_sync_if(
+ int pipe_read_fd,
+ long wait_sync
+ )
+{
+ int rc;
+ int exit_code;
+ time_t wait_end_time;
+ time_t cur_time;
+ time_t wait_rem;
+ fd_set readset;
+ struct timeval wtimeout;
+
+ if (0 == wait_sync)
+ return 0;
+
+ /* waitsync_fd_to_close used solely by child */
+ close(waitsync_fd_to_close);
+ wait_end_time = time(NULL) + wait_sync;
+ do {
+ cur_time = time(NULL);
+ wait_rem = (wait_end_time > cur_time)
+ ? (wait_end_time - cur_time)
+ : 0;
+ wtimeout.tv_sec = wait_rem;
+ wtimeout.tv_usec = 0;
+ FD_ZERO(&readset);
+ FD_SET(pipe_read_fd, &readset);
+ rc = select(pipe_read_fd + 1, &readset, NULL, NULL,
+ &wtimeout);
+ if (-1 == rc) {
+ if (EINTR == errno)
+ continue;
+ exit_code = (errno) ? errno : -1;
+ msyslog(LOG_ERR,
+ "--wait-sync select failed: %m");
+ return exit_code;
+ }
+ if (0 == rc) {
+ /*
+ * select() indicated a timeout, but in case
+ * its timeouts are affected by a step of the
+ * system clock, select() again with a zero
+ * timeout to confirm.
+ */
+ FD_ZERO(&readset);
+ FD_SET(pipe_read_fd, &readset);
+ wtimeout.tv_sec = 0;
+ wtimeout.tv_usec = 0;
+ rc = select(pipe_read_fd + 1, &readset, NULL,
+ NULL, &wtimeout);
+ if (0 == rc) /* select() timeout */
+ break;
+ else /* readable */
+ return 0;
+ } else /* readable */
+ return 0;
+ } while (wait_rem > 0);
+
+ fprintf(stderr, "%s: -w/--wait-sync %ld timed out.\n",
+ progname, wait_sync);
+ return ETIMEDOUT;
+}
+# endif /* HAVE_WORKING_FORK */
+
+
+/*
+ * assertion_failed - Redirect assertion failures to msyslog().
+ */
+static void
+assertion_failed(
+ const char *file,
+ int line,
+ isc_assertiontype_t type,
+ const char *cond
+ )
+{
+ isc_assertion_setcallback(NULL); /* Avoid recursion */
+
+ msyslog(LOG_ERR, "%s:%d: %s(%s) failed",
+ file, line, isc_assertion_typetotext(type), cond);
+ msyslog(LOG_ERR, "exiting (due to assertion failure)");
+
+#if defined(DEBUG) && defined(SYS_WINNT)
+ if (debug)
+ DebugBreak();
#endif
- switch (sig)
- {
-# ifdef SIGBUS
- case SIGBUS:
- printf("\nfinish(SIGBUS)\n");
- exit(0);
-# endif
- case 0: /* Should never happen... */
- return;
- default:
- exit(0);
- }
+ abort();
+}
+
+
+/*
+ * library_fatal_error - Handle fatal errors from our libraries.
+ */
+static void
+library_fatal_error(
+ const char *file,
+ int line,
+ const char *format,
+ va_list args
+ )
+{
+ char errbuf[256];
+
+ isc_error_setfatal(NULL); /* Avoid recursion */
+
+ msyslog(LOG_ERR, "%s:%d: fatal error:", file, line);
+ vsnprintf(errbuf, sizeof(errbuf), format, args);
+ msyslog(LOG_ERR, "%s", errbuf);
+ msyslog(LOG_ERR, "exiting (due to fatal error in library)");
+
+#if defined(DEBUG) && defined(SYS_WINNT)
+ if (debug)
+ DebugBreak();
+#endif
+
+ abort();
}
-#endif /* SIGDIE2 */
-#ifdef DEBUG
-#ifndef SYS_WINNT
+/*
+ * library_unexpected_error - Handle non fatal errors from our libraries.
+ */
+# define MAX_UNEXPECTED_ERRORS 100
+int unexpected_error_cnt = 0;
+static void
+library_unexpected_error(
+ const char *file,
+ int line,
+ const char *format,
+ va_list args
+ )
+{
+ char errbuf[256];
+
+ if (unexpected_error_cnt >= MAX_UNEXPECTED_ERRORS)
+ return; /* avoid clutter in log */
+
+ msyslog(LOG_ERR, "%s:%d: unexpected error:", file, line);
+ vsnprintf(errbuf, sizeof(errbuf), format, args);
+ msyslog(LOG_ERR, "%s", errbuf);
+
+ if (++unexpected_error_cnt == MAX_UNEXPECTED_ERRORS)
+ msyslog(LOG_ERR, "Too many errors. Shutting up.");
+
+}
+#endif /* !SIM */
+
+#if !defined(SIM) && !defined(SYS_WINNT)
+# ifdef DEBUG
+
/*
* moredebug - increase debugging verbosity
*/
@@ -1183,6 +1444,7 @@ moredebug(
errno = saved_errno;
}
+
/*
* lessdebug - decrease debugging verbosity
*/
@@ -1200,9 +1462,10 @@ lessdebug(
}
errno = saved_errno;
}
-#endif
-#else /* not DEBUG */
-#ifndef SYS_WINNT
+
+# else /* !DEBUG follows */
+
+
/*
* no_debug - We don't do the debug here.
*/
@@ -1216,5 +1479,5 @@ no_debug(
msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig);
errno = saved_errno;
}
-#endif /* not SYS_WINNT */
-#endif /* not DEBUG */
+# endif /* !DEBUG */
+#endif /* !SIM && !SYS_WINNT */
diff --git a/contrib/ntp/ntpd/ntpd.html b/contrib/ntp/ntpd/ntpd.html
new file mode 100644
index 0000000..7af6d98
--- /dev/null
+++ b/contrib/ntp/ntpd/ntpd.html
@@ -0,0 +1,1019 @@
+<html lang="en">
+<head>
+<title>ntpd: Network Time Protocol (NTP) Daemon User's Manual</title>
+<meta http-equiv="Content-Type" content="text/html">
+<meta name="description" content="ntpd: Network Time Protocol (NTP) Daemon User's Manual">
+<meta name="generator" content="makeinfo 4.7">
+<link title="Top" rel="top" href="#Top">
+<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
+<meta http-equiv="Content-Style-Type" content="text/css">
+<style type="text/css"><!--
+ pre.display { font-family:inherit }
+ pre.format { font-family:inherit }
+ pre.smalldisplay { font-family:inherit; font-size:smaller }
+ pre.smallformat { font-family:inherit; font-size:smaller }
+ pre.smallexample { font-size:smaller }
+ pre.smalllisp { font-size:smaller }
+ span.sc { font-variant:small-caps }
+ span.roman { font-family: serif; font-weight: normal; }
+--></style>
+</head>
+<body>
+<h1 class="settitle">ntpd: Network Time Protocol (NTP) Daemon User's Manual</h1>
+<div class="node">
+<p><hr>
+<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Description">ntpd Description</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
+<br>
+</div>
+
+<h2 class="unnumbered">ntpd: Network Time Protocol (NTP) Daemon User Manual</h2>
+
+<p>The <code>ntpd</code> program is an operating system daemon that synchronizes the
+system clock to remote NTP time servers or local reference clocks.
+It is a complete implementation of NTP version 4 defined by RFC-5905, but
+also retains compatible with version 3 defined by RFC-1305 and versions
+1 and 2, defined by RFC-1059 and RFC-1119, respectively.
+The program can operate in any of several modes, including client/server,
+symmetric and broadcast modes, and with both symmetric-key and public-key
+cryptography.
+
+ <p>This document applies to version 4.2.8p3 of <code>ntpd</code>.
+
+<ul class="menu">
+<li><a accesskey="1" href="#ntpd-Description">ntpd Description</a>: Description
+<li><a accesskey="2" href="#ntpd-Invocation">ntpd Invocation</a>: Invoking ntpd
+<li><a accesskey="3" href="#Usage">Usage</a>: Usage
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-Description"></a>
+<br>
+</div>
+
+<!-- node-name, next, previous, up -->
+<h3 class="section">Description</h3>
+
+<p>The <code>ntpd</code> program ordinarily requires
+a configuration file described at <a href="#ntp_002econf">ntp.conf</a>.
+This configuration file contains configuration commands described on
+the pages listed above.
+However a client can discover remote servers and configure them
+automatically.
+This makes it possible to deploy a fleet of workstations without
+specifying configuration details specific to the local environment.
+
+ <p>The <code>ntpd</code> program normally operates continuously while adjusting the
+system time and frequency, but in some cases this might not be
+practical.
+With the <code>-q</code> option <code>ntpd</code> operates as in continuous mode, but
+exits just after setting the clock for the first time.
+Most applications will probably want to specify the <code>iburst</code>
+option with the <code>server</code> command.
+With this option an initial volley of messages is exchanged to
+groom the data and set the clock in about ten seconds' time.
+If nothing is heard after a few minutes' time,
+the daemon times out and exits without setting the clock.
+
+<div class="node">
+<p><hr>
+<a name="ntpd-Invocation"></a>
+<br>
+</div>
+
+<h3 class="section">Invoking ntpd</h3>
+
+<p><a name="index-ntpd-1"></a><a name="index-NTP-daemon-program-2"></a>
+
+ <p>The
+<code>ntpd</code>
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC-5905,
+but also retains compatibility with
+version 3, as defined by RFC-1305, and versions 1
+and 2, as defined by RFC-1059 and RFC-1119, respectively.
+
+ <p>The
+<code>ntpd</code>
+utility does most computations in 64-bit floating point
+arithmetic and does relatively clumsy 64-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+
+ <p>Ordinarily,
+<code>ntpd</code>
+reads the
+<code>ntp.conf(5)</code>
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+
+ <p>If NetInfo support is built into
+<code>ntpd</code>
+then
+<code>ntpd</code>
+will attempt to read its configuration from the
+NetInfo if the default
+<code>ntp.conf(5)</code>
+file cannot be read and no file is
+specified by the
+<code>-c</code>
+option.
+
+ <p>Various internal
+<code>ntpd</code>
+variables can be displayed and
+configuration options altered while the
+<code>ntpd</code>
+is running
+using the
+<code>ntpq(1ntpqmdoc)</code>
+and
+<code>ntpdc(1ntpdcmdoc)</code>
+utility programs.
+
+ <p>When
+<code>ntpd</code>
+starts it looks at the value of
+<code>umask(2)</code>,
+and if zero
+<code>ntpd</code>
+will set the
+<code>umask(2)</code>
+to 022.
+
+ <p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpd</code> program.
+This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
+
+<ul class="menu">
+<li><a accesskey="1" href="#ntpd-usage">ntpd usage</a>: ntpd help/usage (<span class="option">--help</span>)
+<li><a accesskey="2" href="#ntpd-ipv4">ntpd ipv4</a>: ipv4 option (-4)
+<li><a accesskey="3" href="#ntpd-ipv6">ntpd ipv6</a>: ipv6 option (-6)
+<li><a accesskey="4" href="#ntpd-authreq">ntpd authreq</a>: authreq option (-a)
+<li><a accesskey="5" href="#ntpd-authnoreq">ntpd authnoreq</a>: authnoreq option (-A)
+<li><a accesskey="6" href="#ntpd-configfile">ntpd configfile</a>: configfile option (-c)
+<li><a accesskey="7" href="#ntpd-driftfile">ntpd driftfile</a>: driftfile option (-f)
+<li><a accesskey="8" href="#ntpd-panicgate">ntpd panicgate</a>: panicgate option (-g)
+<li><a accesskey="9" href="#ntpd-force_002dstep_002donce">ntpd force-step-once</a>: force-step-once option (-G)
+<li><a href="#ntpd-jaildir">ntpd jaildir</a>: jaildir option (-i)
+<li><a href="#ntpd-interface">ntpd interface</a>: interface option (-I)
+<li><a href="#ntpd-keyfile">ntpd keyfile</a>: keyfile option (-k)
+<li><a href="#ntpd-logfile">ntpd logfile</a>: logfile option (-l)
+<li><a href="#ntpd-novirtualips">ntpd novirtualips</a>: novirtualips option (-L)
+<li><a href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>: modifymmtimer option (-M)
+<li><a href="#ntpd-nice">ntpd nice</a>: nice option (-N)
+<li><a href="#ntpd-pidfile">ntpd pidfile</a>: pidfile option (-p)
+<li><a href="#ntpd-priority">ntpd priority</a>: priority option (-P)
+<li><a href="#ntpd-quit">ntpd quit</a>: quit option (-q)
+<li><a href="#ntpd-propagationdelay">ntpd propagationdelay</a>: propagationdelay option (-r)
+<li><a href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>: saveconfigquit option
+<li><a href="#ntpd-statsdir">ntpd statsdir</a>: statsdir option (-s)
+<li><a href="#ntpd-trustedkey">ntpd trustedkey</a>: trustedkey option (-t)
+<li><a href="#ntpd-user">ntpd user</a>: user option (-u)
+<li><a href="#ntpd-updateinterval">ntpd updateinterval</a>: updateinterval option (-U)
+<li><a href="#ntpd-wait_002dsync">ntpd wait-sync</a>: wait-sync option (-w)
+<li><a href="#ntpd-slew">ntpd slew</a>: slew option (-x)
+<li><a href="#ntpd-usepcc">ntpd usepcc</a>: usepcc option
+<li><a href="#ntpd-pccfreq">ntpd pccfreq</a>: pccfreq option
+<li><a href="#ntpd-mdns">ntpd mdns</a>: mdns option (-m)
+<li><a href="#ntpd-config">ntpd config</a>: presetting/configuring ntpd
+<li><a href="#ntpd-exit-status">ntpd exit status</a>: exit status
+<li><a href="#ntpd-Usage">ntpd Usage</a>: Usage
+<li><a href="#ntpd-Files">ntpd Files</a>: Files
+<li><a href="#ntpd-See-Also">ntpd See Also</a>: See Also
+<li><a href="#ntpd-Bugs">ntpd Bugs</a>: Bugs
+<li><a href="#ntpd-Notes">ntpd Notes</a>: Notes
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-ipv4">ntpd ipv4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd help/usage (<span class="option">--help</span>)</h4>
+
+<p><a name="index-ntpd-help-3"></a>
+This is the automatically generated usage text for ntpd.
+
+ <p>The text printed is the same whether selected with the <code>help</code> option
+(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
+<code>more-help</code> is disabled on platforms without a working
+<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
+used to select the program, defaulting to <span class="file">more</span>. Both will exit
+with a status code of 0.
+
+<pre class="example">ntpd - NTP daemon program - Ver. 4.2.8p3-RC3
+Usage: ntpd [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... \
+ [ &lt;server1&gt; ... &lt;serverN&gt; ]
+ Flg Arg Option-Name Description
+ -4 no ipv4 Force IPv4 DNS name resolution
+ - prohibits the option 'ipv6'
+ -6 no ipv6 Force IPv6 DNS name resolution
+ - prohibits the option 'ipv4'
+ -a no authreq Require crypto authentication
+ - prohibits the option 'authnoreq'
+ -A no authnoreq Do not require crypto authentication
+ - prohibits the option 'authreq'
+ -b no bcastsync Allow us to sync to broadcast servers
+ -c Str configfile configuration file name
+ -d no debug-level Increase debug verbosity level
+ - may appear multiple times
+ -D Num set-debug-level Set the debug verbosity level
+ - may appear multiple times
+ -f Str driftfile frequency drift file name
+ -g no panicgate Allow the first adjustment to be Big
+ - may appear multiple times
+ -G no force-step-once Step any initial offset correction.
+ -i Str jaildir Jail directory
+ -I Str interface Listen on an interface name or address
+ - may appear multiple times
+ -k Str keyfile path to symmetric keys
+ -l Str logfile path to the log file
+ -L no novirtualips Do not listen to virtual interfaces
+ -n no nofork Do not fork
+ - prohibits the option 'wait-sync'
+ -N no nice Run at high priority
+ -p Str pidfile path to the PID file
+ -P Num priority Process priority
+ -q no quit Set the time and quit
+ - prohibits these options:
+ saveconfigquit
+ wait-sync
+ -r Str propagationdelay Broadcast/propagation delay
+ Str saveconfigquit Save parsed configuration and quit
+ - prohibits these options:
+ quit
+ wait-sync
+ -s Str statsdir Statistics file location
+ -t Str trustedkey Trusted key number
+ - may appear multiple times
+ -u Str user Run as userid (or userid:groupid)
+ -U Num updateinterval interval in seconds between scans for new or dropped interfaces
+ Str var make ARG an ntp variable (RW)
+ - may appear multiple times
+ Str dvar make ARG an ntp variable (RW|DEF)
+ - may appear multiple times
+ -w Num wait-sync Seconds to wait for first clock sync
+ - prohibits these options:
+ nofork
+ quit
+ saveconfigquit
+ -x no slew Slew up to 600 seconds
+ opt version output version information and exit
+ -? no help display extended usage information and exit
+ -! no more-help extended usage information passed thru pager
+
+Options are specified by doubled hyphens and their name or by a single
+hyphen and the flag character.
+
+
+The following option preset mechanisms are supported:
+ - examining environment variables named NTPD_*
+
+Please send bug reports to: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
+</pre>
+ <div class="node">
+<p><hr>
+<a name="ntpd-ipv4"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-ipv6">ntpd ipv6</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-usage">ntpd usage</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ipv4 option (-4)</h4>
+
+<p><a name="index-ntpd_002dipv4-4"></a>
+This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must not appear in combination with any of the following options:
+ipv6.
+</ul>
+
+ <p>Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+<div class="node">
+<p><hr>
+<a name="ntpd-ipv6"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-authreq">ntpd authreq</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-ipv4">ntpd ipv4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ipv6 option (-6)</h4>
+
+<p><a name="index-ntpd_002dipv6-5"></a>
+This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must not appear in combination with any of the following options:
+ipv4.
+</ul>
+
+ <p>Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+<div class="node">
+<p><hr>
+<a name="ntpd-authreq"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-authnoreq">ntpd authnoreq</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-ipv6">ntpd ipv6</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">authreq option (-a)</h4>
+
+<p><a name="index-ntpd_002dauthreq-6"></a>
+This is the &ldquo;require crypto authentication&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must not appear in combination with any of the following options:
+authnoreq.
+</ul>
+
+ <p>Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+<div class="node">
+<p><hr>
+<a name="ntpd-authnoreq"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-configfile">ntpd configfile</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-authreq">ntpd authreq</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">authnoreq option (-A)</h4>
+
+<p><a name="index-ntpd_002dauthnoreq-7"></a>
+This is the &ldquo;do not require crypto authentication&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must not appear in combination with any of the following options:
+authreq.
+</ul>
+
+ <p>Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+<div class="node">
+<p><hr>
+<a name="ntpd-configfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-driftfile">ntpd driftfile</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-authnoreq">ntpd authnoreq</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">configfile option (-c)</h4>
+
+<p><a name="index-ntpd_002dconfigfile-8"></a>
+This is the &ldquo;configuration file name&rdquo; option.
+This option takes a string argument.
+The name and path of the configuration file,
+<span class="file">/etc/ntp.conf</span>
+by default.
+<div class="node">
+<p><hr>
+<a name="ntpd-driftfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-panicgate">ntpd panicgate</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-configfile">ntpd configfile</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">driftfile option (-f)</h4>
+
+<p><a name="index-ntpd_002ddriftfile-9"></a>
+This is the &ldquo;frequency drift file name&rdquo; option.
+This option takes a string argument.
+The name and path of the frequency file,
+<span class="file">/etc/ntp.drift</span>
+by default.
+This is the same operation as the
+<code>driftfile</code> <kbd>driftfile</kbd>
+configuration specification in the
+<span class="file">/etc/ntp.conf</span>
+file.
+<div class="node">
+<p><hr>
+<a name="ntpd-panicgate"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-force_002dstep_002donce">ntpd force-step-once</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-driftfile">ntpd driftfile</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">panicgate option (-g)</h4>
+
+<p><a name="index-ntpd_002dpanicgate-10"></a>
+This is the &ldquo;allow the first adjustment to be big&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>may appear an unlimited number of times.
+</ul>
+
+ <p>Normally,
+<code>ntpd</code>
+exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
+<code>ntpd</code>
+will exit with a message to the system log. This option can be used with the
+<code>-q</code>
+and
+<code>-x</code>
+options.
+See the
+<code>tinker</code>
+configuration file directive for other options.
+<div class="node">
+<p><hr>
+<a name="ntpd-force_002dstep_002donce"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-jaildir">ntpd jaildir</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-panicgate">ntpd panicgate</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">force-step-once option (-G)</h4>
+
+<p><a name="index-ntpd_002dforce_002dstep_002donce-11"></a>
+This is the &ldquo;step any initial offset correction.&rdquo; option.
+Normally,
+<code>ntpd</code>
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the <code>tinker</code> configuration file directive for other options.
+<div class="node">
+<p><hr>
+<a name="ntpd-jaildir"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-interface">ntpd interface</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-force_002dstep_002donce">ntpd force-step-once</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">jaildir option (-i)</h4>
+
+<p><a name="index-ntpd_002djaildir-12"></a>
+This is the &ldquo;jail directory&rdquo; option.
+This option takes a string argument.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>HAVE_DROPROOT</code> during the compilation.
+</ul>
+
+ <p>Chroot the server to the directory
+<kbd>jaildir</kbd>
+.
+This option also implies that the server attempts to drop root privileges at startup.
+You may need to also specify a
+<code>-u</code>
+option.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+<code>--enable-clockctl</code>) or Linux (configure with
+<code>--enable-linuxcaps</code>) or Solaris (configure with <code>--enable-solarisprivs</code>).
+<div class="node">
+<p><hr>
+<a name="ntpd-interface"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-keyfile">ntpd keyfile</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-jaildir">ntpd jaildir</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">interface option (-I)</h4>
+
+<p><a name="index-ntpd_002dinterface-13"></a>
+This is the &ldquo;listen on an interface name or address&rdquo; option.
+This option takes a string argument <span class="file">iface</span>.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>may appear an unlimited number of times.
+</ul>
+
+ <p>Open the network address given, or all the addresses associated with the
+given interface name. This option may appear multiple times. This option
+also implies not opening other addresses, except wildcard and localhost.
+This option is deprecated. Please consider using the configuration file
+<code>interface</code> command, which is more versatile.
+<div class="node">
+<p><hr>
+<a name="ntpd-keyfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-logfile">ntpd logfile</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-interface">ntpd interface</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">keyfile option (-k)</h4>
+
+<p><a name="index-ntpd_002dkeyfile-14"></a>
+This is the &ldquo;path to symmetric keys&rdquo; option.
+This option takes a string argument.
+Specify the name and path of the symmetric key file.
+<span class="file">/etc/ntp.keys</span>
+is the default.
+This is the same operation as the
+<code>keys</code> <kbd>keyfile</kbd>
+configuration file directive.
+<div class="node">
+<p><hr>
+<a name="ntpd-logfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-novirtualips">ntpd novirtualips</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-keyfile">ntpd keyfile</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">logfile option (-l)</h4>
+
+<p><a name="index-ntpd_002dlogfile-15"></a>
+This is the &ldquo;path to the log file&rdquo; option.
+This option takes a string argument.
+Specify the name and path of the log file.
+The default is the system log file.
+This is the same operation as the
+<code>logfile</code> <kbd>logfile</kbd>
+configuration file directive.
+<div class="node">
+<p><hr>
+<a name="ntpd-novirtualips"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-logfile">ntpd logfile</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">novirtualips option (-L)</h4>
+
+<p><a name="index-ntpd_002dnovirtualips-16"></a>
+This is the &ldquo;do not listen to virtual interfaces&rdquo; option.
+Do not listen to virtual interfaces, defined as those with
+names containing a colon. This option is deprecated. Please
+consider using the configuration file <code>interface</code> command, which
+is more versatile.
+<div class="node">
+<p><hr>
+<a name="ntpd-modifymmtimer"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-nice">ntpd nice</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-novirtualips">ntpd novirtualips</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">modifymmtimer option (-M)</h4>
+
+<p><a name="index-ntpd_002dmodifymmtimer-17"></a>
+This is the &ldquo;modify multimedia timer (windows only)&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
+</ul>
+
+ <p>Set the Windows Multimedia Timer to highest resolution. This
+ensures the resolution does not change while ntpd is running,
+avoiding timekeeping glitches associated with changes.
+<div class="node">
+<p><hr>
+<a name="ntpd-nice"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-pidfile">ntpd pidfile</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">nice option (-N)</h4>
+
+<p><a name="index-ntpd_002dnice-18"></a>
+This is the &ldquo;run at high priority&rdquo; option.
+To the extent permitted by the operating system, run
+<code>ntpd</code>
+at the highest priority.
+<div class="node">
+<p><hr>
+<a name="ntpd-pidfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-priority">ntpd priority</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-nice">ntpd nice</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">pidfile option (-p)</h4>
+
+<p><a name="index-ntpd_002dpidfile-19"></a>
+This is the &ldquo;path to the pid file&rdquo; option.
+This option takes a string argument.
+Specify the name and path of the file used to record
+<code>ntpd</code>'s
+process ID.
+This is the same operation as the
+<code>pidfile</code> <kbd>pidfile</kbd>
+configuration file directive.
+<div class="node">
+<p><hr>
+<a name="ntpd-priority"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-quit">ntpd quit</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-pidfile">ntpd pidfile</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">priority option (-P)</h4>
+
+<p><a name="index-ntpd_002dpriority-20"></a>
+This is the &ldquo;process priority&rdquo; option.
+This option takes a number argument.
+To the extent permitted by the operating system, run
+<code>ntpd</code>
+at the specified
+<code>sched_setscheduler(SCHED_FIFO)</code>
+priority.
+<div class="node">
+<p><hr>
+<a name="ntpd-quit"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-propagationdelay">ntpd propagationdelay</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-priority">ntpd priority</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">quit option (-q)</h4>
+
+<p><a name="index-ntpd_002dquit-21"></a>
+This is the &ldquo;set the time and quit&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must not appear in combination with any of the following options:
+saveconfigquit, wait-sync.
+</ul>
+
+ <p><code>ntpd</code>
+will not daemonize and will exit after the clock is first
+synchronized. This behavior mimics that of the
+<code>ntpdate</code>
+program, which will soon be replaced with a shell script.
+The
+<code>-g</code>
+and
+<code>-x</code>
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+<div class="node">
+<p><hr>
+<a name="ntpd-propagationdelay"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-quit">ntpd quit</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">propagationdelay option (-r)</h4>
+
+<p><a name="index-ntpd_002dpropagationdelay-22"></a>
+This is the &ldquo;broadcast/propagation delay&rdquo; option.
+This option takes a string argument.
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+<div class="node">
+<p><hr>
+<a name="ntpd-saveconfigquit"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-statsdir">ntpd statsdir</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-propagationdelay">ntpd propagationdelay</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">saveconfigquit option</h4>
+
+<p><a name="index-ntpd_002dsaveconfigquit-23"></a>
+This is the &ldquo;save parsed configuration and quit&rdquo; option.
+This option takes a string argument.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>SAVECONFIG</code> during the compilation.
+<li>must not appear in combination with any of the following options:
+quit, wait-sync.
+</ul>
+
+ <p>Cause <code>ntpd</code> to parse its startup configuration file and save an
+equivalent to the given filename and exit. This option was
+designed for automated testing.
+<div class="node">
+<p><hr>
+<a name="ntpd-statsdir"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-trustedkey">ntpd trustedkey</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">statsdir option (-s)</h4>
+
+<p><a name="index-ntpd_002dstatsdir-24"></a>
+This is the &ldquo;statistics file location&rdquo; option.
+This option takes a string argument.
+Specify the directory path for files created by the statistics facility.
+This is the same operation as the
+<code>statsdir</code> <kbd>statsdir</kbd>
+configuration file directive.
+<div class="node">
+<p><hr>
+<a name="ntpd-trustedkey"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-user">ntpd user</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-statsdir">ntpd statsdir</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">trustedkey option (-t)</h4>
+
+<p><a name="index-ntpd_002dtrustedkey-25"></a>
+This is the &ldquo;trusted key number&rdquo; option.
+This option takes a string argument <span class="file">tkey</span>.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>may appear an unlimited number of times.
+</ul>
+
+ <p>Add the specified key number to the trusted key list.
+<div class="node">
+<p><hr>
+<a name="ntpd-user"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-updateinterval">ntpd updateinterval</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-trustedkey">ntpd trustedkey</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">user option (-u)</h4>
+
+<p><a name="index-ntpd_002duser-26"></a>
+This is the &ldquo;run as userid (or userid:groupid)&rdquo; option.
+This option takes a string argument.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>HAVE_DROPROOT</code> during the compilation.
+</ul>
+
+ <p>Specify a user, and optionally a group, to switch to.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+<code>--enable-clockctl</code>) or Linux (configure with
+<code>--enable-linuxcaps</code>) or Solaris (configure with <code>--enable-solarisprivs</code>).
+<div class="node">
+<p><hr>
+<a name="ntpd-updateinterval"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-wait_002dsync">ntpd wait-sync</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-user">ntpd user</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">updateinterval option (-U)</h4>
+
+<p><a name="index-ntpd_002dupdateinterval-27"></a>
+This is the &ldquo;interval in seconds between scans for new or dropped interfaces&rdquo; option.
+This option takes a number argument.
+Give the time in seconds between two scans for new or dropped interfaces.
+For systems with routing socket support the scans will be performed shortly after the interface change
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+<div class="node">
+<p><hr>
+<a name="ntpd-wait_002dsync"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-slew">ntpd slew</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-updateinterval">ntpd updateinterval</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">wait-sync option (-w)</h4>
+
+<p><a name="index-ntpd_002dwait_002dsync-28"></a>
+This is the &ldquo;seconds to wait for first clock sync&rdquo; option.
+This option takes a number argument.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>HAVE_WORKING_FORK</code> during the compilation.
+<li>must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+</ul>
+
+ <p>If greater than zero, alters <code>ntpd</code>'s behavior when forking to
+daemonize. Instead of exiting with status 0 immediately after
+the fork, the parent waits up to the specified number of
+seconds for the child to first synchronize the clock. The exit
+status is zero (success) if the clock was synchronized,
+otherwise it is <code>ETIMEDOUT</code>.
+This provides the option for a script starting <code>ntpd</code> to easily
+wait for the first set of the clock before proceeding.
+<div class="node">
+<p><hr>
+<a name="ntpd-slew"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-usepcc">ntpd usepcc</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-wait_002dsync">ntpd wait-sync</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">slew option (-x)</h4>
+
+<p><a name="index-ntpd_002dslew-29"></a>
+This is the &ldquo;slew up to 600 seconds&rdquo; option.
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+This option can be used with the
+<code>-g</code>
+and
+<code>-q</code>
+options.
+See the
+<code>tinker</code>
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+<div class="node">
+<p><hr>
+<a name="ntpd-usepcc"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-pccfreq">ntpd pccfreq</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-slew">ntpd slew</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">usepcc option</h4>
+
+<p><a name="index-ntpd_002dusepcc-30"></a>
+This is the &ldquo;use cpu cycle counter (windows only)&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
+</ul>
+
+ <p>Attempt to substitute the CPU counter for <code>QueryPerformanceCounter</code>.
+The CPU counter and <code>QueryPerformanceCounter</code> are compared, and if
+they have the same frequency, the CPU counter (RDTSC on x86) is
+used directly, saving the overhead of a system call.
+<div class="node">
+<p><hr>
+<a name="ntpd-pccfreq"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-mdns">ntpd mdns</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-usepcc">ntpd usepcc</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">pccfreq option</h4>
+
+<p><a name="index-ntpd_002dpccfreq-31"></a>
+This is the &ldquo;force cpu cycle counter use (windows only)&rdquo; option.
+This option takes a string argument.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
+</ul>
+
+ <p>Force substitution the CPU counter for <code>QueryPerformanceCounter</code>.
+The CPU counter (RDTSC on x86) is used unconditionally with the
+given frequency (in Hz).
+<div class="node">
+<p><hr>
+<a name="ntpd-mdns"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-config">ntpd config</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-pccfreq">ntpd pccfreq</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">mdns option (-m)</h4>
+
+<p><a name="index-ntpd_002dmdns-32"></a>
+This is the &ldquo;register with mdns as a ntp server&rdquo; option.
+
+<p class="noindent">This option has some usage constraints. It:
+ <ul>
+<li>must be compiled in by defining <code>HAVE_DNSREGISTRATION</code> during the compilation.
+</ul>
+
+ <p>Registers as an NTP server with the local mDNS server which allows
+the server to be discovered via mDNS client lookup.
+
+<div class="node">
+<p><hr>
+<a name="ntpd-config"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-exit-status">ntpd exit status</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-mdns">ntpd mdns</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">presetting/configuring ntpd</h4>
+
+<p>Any option that is not marked as <i>not presettable</i> may be preset by
+loading values from environment variables named <code>NTPD</code> and <code>NTPD_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
+the options listed above in upper case and segmented with underscores.
+The <code>NTPD</code> variable will be tokenized and parsed like
+the command line. The remaining variables are tested for existence and their
+values are treated like option arguments.
+
+ <p>The command line options relating to configuration and/or usage help are:
+
+<h5 class="subsubheading">version (-)</h5>
+
+<p>Print the program version to standard out, optionally with licensing
+information, then exit 0. The optional argument specifies how much licensing
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+Only the first letter of the argument is examined:
+
+ <dl>
+<dt><span class="samp">version</span><dd>Only print the version. This is the default.
+<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms.
+<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms.
+</dl>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Usage">ntpd Usage</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-config">ntpd config</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd exit status</h4>
+
+<p>One of the following exit values will be returned:
+ <dl>
+<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
+<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</dl>
+ <div class="node">
+<p><hr>
+<a name="ntpd-Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Files">ntpd Files</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-exit-status">ntpd exit status</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd Usage</h4>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-Files"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-See-Also">ntpd See Also</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-Usage">ntpd Usage</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd Files</h4>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-See-Also"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Bugs">ntpd Bugs</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-Files">ntpd Files</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd See Also</h4>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-Bugs"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Notes">ntpd Notes</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-See-Also">ntpd See Also</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd Bugs</h4>
+
+<div class="node">
+<p><hr>
+<a name="ntpd-Notes"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-Bugs">ntpd Bugs</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
+<br>
+</div>
+
+<h4 class="subsection">ntpd Notes</h4>
+
+<div class="node">
+<p><hr>
+<a name="Usage"></a>
+<br>
+</div>
+
+<!-- node-name, next, previous, up -->
+<h3 class="section">Usage</h3>
+
diff --git a/contrib/ntp/ntpd/ntpd.man.in b/contrib/ntp/ntpd/ntpd.man.in
new file mode 100644
index 0000000..c7c4eec
--- /dev/null
+++ b/contrib/ntp/ntpd/ntpd.man.in
@@ -0,0 +1,1001 @@
+.de1 NOP
+. it 1 an-trap
+. if \\n[.$] \,\\$*\/
+..
+.ie t \
+.ds B-Font [CB]
+.ds I-Font [CI]
+.ds R-Font [CR]
+.el \
+.ds B-Font B
+.ds I-Font I
+.ds R-Font R
+.TH ntpd @NTPD_MS@ "29 Jun 2015" "4.2.8p3" "User Commands"
+.\"
+.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-LZaapD/ag-XZa4nD)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:24 PM by AutoGen 5.18.5
+.\" From the definitions ntpd-opts.def
+.\" and the template file agman-cmd.tpl
+.SH NAME
+\f\*[B-Font]ntpd\fP
+\- NTP daemon program
+.SH SYNOPSIS
+\f\*[B-Font]ntpd\fP
+.\" Mixture of short (flag) options and long options
+[\f\*[B-Font]\-flags\f[]]
+[\f\*[B-Font]\-flag\f[] [\f\*[I-Font]value\f[]]]
+[\f\*[B-Font]\-\-option-name\f[][[=| ]\f\*[I-Font]value\f[]]]
+[ <server1> ... <serverN> ]
+.sp \n(Ppu
+.ne 2
+
+.SH DESCRIPTION
+The
+\f\*[B-Font]ntpd\fP
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC-5905,
+but also retains compatibility with
+version 3, as defined by RFC-1305, and versions 1
+and 2, as defined by RFC-1059 and RFC-1119, respectively.
+.sp \n(Ppu
+.ne 2
+
+The
+\f\*[B-Font]ntpd\fP
+utility does most computations in 64-bit floating point
+arithmetic and does relatively clumsy 64-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+.sp \n(Ppu
+.ne 2
+
+Ordinarily,
+\f\*[B-Font]ntpd\fP
+reads the
+\fCntp.conf\f[]\fR(5)\f[]
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+.sp \n(Ppu
+.ne 2
+
+If NetInfo support is built into
+\f\*[B-Font]ntpd\fP,
+then
+\f\*[B-Font]ntpd\fP
+will attempt to read its configuration from the
+NetInfo if the default
+\fCntp.conf\f[]\fR(5)\f[]
+file cannot be read and no file is
+specified by the
+\f\*[B-Font]\-c\f[]
+option.
+.sp \n(Ppu
+.ne 2
+
+Various internal
+\f\*[B-Font]ntpd\fP
+variables can be displayed and
+configuration options altered while the
+\f\*[B-Font]ntpd\fP
+is running
+using the
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[]
+and
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[]
+utility programs.
+.sp \n(Ppu
+.ne 2
+
+When
+\f\*[B-Font]ntpd\fP
+starts it looks at the value of
+\fCumask\f[]\fR(2)\f[],
+and if zero
+\f\*[B-Font]ntpd\fP
+will set the
+\fCumask\f[]\fR(2)\f[]
+to 022.
+.SH "OPTIONS"
+.TP
+.NOP \f\*[B-Font]\-4\f[], \f\*[B-Font]\-\-ipv4\f[]
+Force IPv4 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv6.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+.TP
+.NOP \f\*[B-Font]\-6\f[], \f\*[B-Font]\-\-ipv6\f[]
+Force IPv6 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv4.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+.TP
+.NOP \f\*[B-Font]\-a\f[], \f\*[B-Font]\-\-authreq\f[]
+Require crypto authentication.
+This option must not appear in combination with any of the following options:
+authnoreq.
+.sp
+Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+.TP
+.NOP \f\*[B-Font]\-A\f[], \f\*[B-Font]\-\-authnoreq\f[]
+Do not require crypto authentication.
+This option must not appear in combination with any of the following options:
+authreq.
+.sp
+Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+.TP
+.NOP \f\*[B-Font]\-b\f[], \f\*[B-Font]\-\-bcastsync\f[]
+Allow us to sync to broadcast servers.
+.sp
+.TP
+.NOP \f\*[B-Font]\-c\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-configfile\f[]=\f\*[I-Font]string\f[]
+configuration file name.
+.sp
+The name and path of the configuration file,
+\fI/etc/ntp.conf\fP
+by default.
+.TP
+.NOP \f\*[B-Font]\-d\f[], \f\*[B-Font]\-\-debug\-level\f[]
+Increase debug verbosity level.
+This option may appear an unlimited number of times.
+.sp
+.TP
+.NOP \f\*[B-Font]\-D\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-set\-debug\-level\f[]=\f\*[I-Font]number\f[]
+Set the debug verbosity level.
+This option may appear an unlimited number of times.
+This option takes an integer number as its argument.
+.sp
+.TP
+.NOP \f\*[B-Font]\-f\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-driftfile\f[]=\f\*[I-Font]string\f[]
+frequency drift file name.
+.sp
+The name and path of the frequency file,
+\fI/etc/ntp.drift\fP
+by default.
+This is the same operation as the
+\fBdriftfile\fP \fIdriftfile\fP
+configuration specification in the
+\fI/etc/ntp.conf\fP
+file.
+.TP
+.NOP \f\*[B-Font]\-g\f[], \f\*[B-Font]\-\-panicgate\f[]
+Allow the first adjustment to be Big.
+This option may appear an unlimited number of times.
+.sp
+Normally,
+\fBntpd\fP
+exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
+\fBntpd\fP
+will exit with a message to the system log. This option can be used with the
+\fB-q\fP
+and
+\fB-x\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+.TP
+.NOP \f\*[B-Font]\-G\f[], \f\*[B-Font]\-\-force\-step\-once\f[]
+Step any initial offset correction..
+.sp
+Normally,
+\fBntpd\fP
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the \fBtinker\fP configuration file directive for other options.
+.TP
+.NOP \f\*[B-Font]\-i\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-jaildir\f[]=\f\*[I-Font]string\f[]
+Jail directory.
+.sp
+Chroot the server to the directory
+\fIjaildir\fP
+.
+This option also implies that the server attempts to drop root privileges at startup.
+You may need to also specify a
+\fB-u\fP
+option.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB--enable-clockctl\fP) or Linux (configure with
+\fB--enable-linuxcaps\fP) or Solaris (configure with \fB--enable-solarisprivs\fP).
+.TP
+.NOP \f\*[B-Font]\-I\f[] \f\*[I-Font]iface\f[], \f\*[B-Font]\-\-interface\f[]=\f\*[I-Font]iface\f[]
+Listen on an interface name or address.
+This option may appear an unlimited number of times.
+.sp
+Open the network address given, or all the addresses associated with the
+given interface name. This option may appear multiple times. This option
+also implies not opening other addresses, except wildcard and localhost.
+This option is deprecated. Please consider using the configuration file
+\fBinterface\fP command, which is more versatile.
+.TP
+.NOP \f\*[B-Font]\-k\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-keyfile\f[]=\f\*[I-Font]string\f[]
+path to symmetric keys.
+.sp
+Specify the name and path of the symmetric key file.
+\fI/etc/ntp.keys\fP
+is the default.
+This is the same operation as the
+\fBkeys\fP \fIkeyfile\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-l\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-logfile\f[]=\f\*[I-Font]string\f[]
+path to the log file.
+.sp
+Specify the name and path of the log file.
+The default is the system log file.
+This is the same operation as the
+\fBlogfile\fP \fIlogfile\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-L\f[], \f\*[B-Font]\-\-novirtualips\f[]
+Do not listen to virtual interfaces.
+.sp
+Do not listen to virtual interfaces, defined as those with
+names containing a colon. This option is deprecated. Please
+consider using the configuration file \fBinterface\fP command, which
+is more versatile.
+.TP
+.NOP \f\*[B-Font]\-M\f[], \f\*[B-Font]\-\-modifymmtimer\f[]
+Modify Multimedia Timer (Windows only).
+.sp
+Set the Windows Multimedia Timer to highest resolution. This
+ensures the resolution does not change while ntpd is running,
+avoiding timekeeping glitches associated with changes.
+.TP
+.NOP \f\*[B-Font]\-n\f[], \f\*[B-Font]\-\-nofork\f[]
+Do not fork.
+This option must not appear in combination with any of the following options:
+wait-sync.
+.sp
+.TP
+.NOP \f\*[B-Font]\-N\f[], \f\*[B-Font]\-\-nice\f[]
+Run at high priority.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the highest priority.
+.TP
+.NOP \f\*[B-Font]\-p\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-pidfile\f[]=\f\*[I-Font]string\f[]
+path to the PID file.
+.sp
+Specify the name and path of the file used to record
+\fBntpd\fP's
+process ID.
+This is the same operation as the
+\fBpidfile\fP \fIpidfile\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-P\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-priority\f[]=\f\*[I-Font]number\f[]
+Process priority.
+This option takes an integer number as its argument.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the specified
+\fBsched_setscheduler(SCHED_FIFO)\fP
+priority.
+.TP
+.NOP \f\*[B-Font]\-q\f[], \f\*[B-Font]\-\-quit\f[]
+Set the time and quit.
+This option must not appear in combination with any of the following options:
+saveconfigquit, wait-sync.
+.sp
+\fBntpd\fP
+will not daemonize and will exit after the clock is first
+synchronized. This behavior mimics that of the
+\fBntpdate\fP
+program, which will soon be replaced with a shell script.
+The
+\fB-g\fP
+and
+\fB-x\fP
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+.TP
+.NOP \f\*[B-Font]\-r\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-propagationdelay\f[]=\f\*[I-Font]string\f[]
+Broadcast/propagation delay.
+.sp
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+.TP
+.NOP \f\*[B-Font]\-\-saveconfigquit\f[]=\f\*[I-Font]string\f[]
+Save parsed configuration and quit.
+This option must not appear in combination with any of the following options:
+quit, wait-sync.
+.sp
+Cause \fBntpd\fP to parse its startup configuration file and save an
+equivalent to the given filename and exit. This option was
+designed for automated testing.
+.TP
+.NOP \f\*[B-Font]\-s\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-statsdir\f[]=\f\*[I-Font]string\f[]
+Statistics file location.
+.sp
+Specify the directory path for files created by the statistics facility.
+This is the same operation as the
+\fBstatsdir\fP \fIstatsdir\fP
+configuration file directive.
+.TP
+.NOP \f\*[B-Font]\-t\f[] \f\*[I-Font]tkey\f[], \f\*[B-Font]\-\-trustedkey\f[]=\f\*[I-Font]tkey\f[]
+Trusted key number.
+This option may appear an unlimited number of times.
+.sp
+Add the specified key number to the trusted key list.
+.TP
+.NOP \f\*[B-Font]\-u\f[] \f\*[I-Font]string\f[], \f\*[B-Font]\-\-user\f[]=\f\*[I-Font]string\f[]
+Run as userid (or userid:groupid).
+.sp
+Specify a user, and optionally a group, to switch to.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB--enable-clockctl\fP) or Linux (configure with
+\fB--enable-linuxcaps\fP) or Solaris (configure with \fB--enable-solarisprivs\fP).
+.TP
+.NOP \f\*[B-Font]\-U\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-updateinterval\f[]=\f\*[I-Font]number\f[]
+interval in seconds between scans for new or dropped interfaces.
+This option takes an integer number as its argument.
+.sp
+Give the time in seconds between two scans for new or dropped interfaces.
+For systems with routing socket support the scans will be performed shortly after the interface change
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+.TP
+.NOP \f\*[B-Font]\-\-var\f[]=\f\*[I-Font]nvar\f[]
+make ARG an ntp variable (RW).
+This option may appear an unlimited number of times.
+.sp
+.TP
+.NOP \f\*[B-Font]\-\-dvar\f[]=\f\*[I-Font]ndvar\f[]
+make ARG an ntp variable (RW|DEF).
+This option may appear an unlimited number of times.
+.sp
+.TP
+.NOP \f\*[B-Font]\-w\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-wait\-sync\f[]=\f\*[I-Font]number\f[]
+Seconds to wait for first clock sync.
+This option must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+This option takes an integer number as its argument.
+.sp
+If greater than zero, alters \fBntpd\fP's behavior when forking to
+daemonize. Instead of exiting with status 0 immediately after
+the fork, the parent waits up to the specified number of
+seconds for the child to first synchronize the clock. The exit
+status is zero (success) if the clock was synchronized,
+otherwise it is \fBETIMEDOUT\fP.
+This provides the option for a script starting \fBntpd\fP to easily
+wait for the first set of the clock before proceeding.
+.TP
+.NOP \f\*[B-Font]\-x\f[], \f\*[B-Font]\-\-slew\f[]
+Slew up to 600 seconds.
+.sp
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+This option can be used with the
+\fB-g\fP
+and
+\fB-q\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+.TP
+.NOP \f\*[B-Font]\-\-usepcc\f[]
+Use CPU cycle counter (Windows only).
+.sp
+Attempt to substitute the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter and \fBQueryPerformanceCounter\fP are compared, and if
+they have the same frequency, the CPU counter (RDTSC on x86) is
+used directly, saving the overhead of a system call.
+.TP
+.NOP \f\*[B-Font]\-\-pccfreq\f[]=\f\*[I-Font]string\f[]
+Force CPU cycle counter use (Windows only).
+.sp
+Force substitution the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter (RDTSC on x86) is used unconditionally with the
+given frequency (in Hz).
+.TP
+.NOP \f\*[B-Font]\-m\f[], \f\*[B-Font]\-\-mdns\f[]
+Register with mDNS as a NTP server.
+.sp
+Registers as an NTP server with the local mDNS server which allows
+the server to be discovered via mDNS client lookup.
+.TP
+.NOP \f\*[B-Font]\-\&?\f[], \f\*[B-Font]\-\-help\f[]
+Display usage information and exit.
+.TP
+.NOP \f\*[B-Font]\-\&!\f[], \f\*[B-Font]\-\-more-help\f[]
+Pass the extended usage information through a pager.
+.TP
+.NOP \f\*[B-Font]\-\-version\f[] [{\f\*[I-Font]v|c|n\f[]}]
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.PP
+.SH "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTPD_<option-name>\fP or \fBNTPD\fP
+.fi
+.ad
+.SH USAGE
+.SS "How NTP Operates"
+The
+\f\*[B-Font]ntpd\fP
+utility operates by exchanging messages with
+one or more configured servers over a range of designated poll intervals.
+When
+started, whether for the first or subsequent times, the program
+requires several exchanges from the majority of these servers so
+the signal processing and mitigation algorithms can accumulate and
+groom the data and set the clock.
+In order to protect the network
+from bursts, the initial poll interval for each server is delayed
+an interval randomized over a few seconds.
+At the default initial poll
+interval of 64s, several minutes can elapse before the clock is
+set.
+This initial delay to set the clock
+can be safely and dramatically reduced using the
+\f\*[B-Font]iburst\f[]
+keyword with the
+\f\*[B-Font]server\f[]
+configuration
+command, as described in
+\fCntp.conf\f[]\fR(5)\f[].
+.sp \n(Ppu
+.ne 2
+
+Most operating systems and hardware of today incorporate a
+time-of-year (TOY) chip to maintain the time during periods when
+the power is off.
+When the machine is booted, the chip is used to
+initialize the operating system time.
+After the machine has
+synchronized to a NTP server, the operating system corrects the
+chip from time to time.
+In the default case, if
+\f\*[B-Font]ntpd\fP
+detects that the time on the host
+is more than 1000s from the server time,
+\f\*[B-Font]ntpd\fP
+assumes something must be terribly wrong and the only
+reliable action is for the operator to intervene and set the clock
+by hand.
+(Reasons for this include there is no TOY chip,
+or its battery is dead, or that the TOY chip is just of poor quality.)
+This causes
+\f\*[B-Font]ntpd\fP
+to exit with a panic message to
+the system log.
+The
+\f\*[B-Font]\-g\f[]
+option overrides this check and the
+clock will be set to the server time regardless of the chip time
+(up to 68 years in the past or future \(em
+this is a limitation of the NTPv4 protocol).
+However, and to protect against broken hardware, such as when the
+CMOS battery fails or the clock counter becomes defective, once the
+clock has been set an error greater than 1000s will cause
+\f\*[B-Font]ntpd\fP
+to exit anyway.
+.sp \n(Ppu
+.ne 2
+
+Under ordinary conditions,
+\f\*[B-Font]ntpd\fP
+adjusts the clock in
+small steps so that the timescale is effectively continuous and
+without discontinuities.
+Under conditions of extreme network
+congestion, the roundtrip delay jitter can exceed three seconds and
+the synchronization distance, which is equal to one-half the
+roundtrip delay plus error budget terms, can become very large.
+The
+\f\*[B-Font]ntpd\fP
+algorithms discard sample offsets exceeding 128 ms,
+unless the interval during which no sample offset is less than 128
+ms exceeds 900s.
+The first sample after that, no matter what the
+offset, steps the clock to the indicated time.
+In practice this
+reduces the false alarm rate where the clock is stepped in error to
+a vanishingly low incidence.
+.sp \n(Ppu
+.ne 2
+
+As the result of this behavior, once the clock has been set it
+very rarely strays more than 128 ms even under extreme cases of
+network path congestion and jitter.
+Sometimes, in particular when
+\f\*[B-Font]ntpd\fP
+is first started without a valid drift file
+on a system with a large intrinsic drift
+the error might grow to exceed 128 ms,
+which would cause the clock to be set backwards
+if the local clock time is more than 128 s
+in the future relative to the server.
+In some applications, this behavior may be unacceptable.
+There are several solutions, however.
+If the
+\f\*[B-Font]\-x\f[]
+option is included on the command line, the clock will
+never be stepped and only slew corrections will be used.
+But this choice comes with a cost that
+should be carefully explored before deciding to use
+the
+\f\*[B-Font]\-x\f[]
+option.
+The maximum slew rate possible is limited
+to 500 parts-per-million (PPM) as a consequence of the correctness
+principles on which the NTP protocol and algorithm design are
+based.
+As a result, the local clock can take a long time to
+converge to an acceptable offset, about 2,000 s for each second the
+clock is outside the acceptable range.
+During this interval the
+local clock will not be consistent with any other network clock and
+the system cannot be used for distributed applications that require
+correctly synchronized network time.
+.sp \n(Ppu
+.ne 2
+
+In spite of the above precautions, sometimes when large
+frequency errors are present the resulting time offsets stray
+outside the 128-ms range and an eventual step or slew time
+correction is required.
+If following such a correction the
+frequency error is so large that the first sample is outside the
+acceptable range,
+\f\*[B-Font]ntpd\fP
+enters the same state as when the
+\fIntp.drift\f[]
+file is not present.
+The intent of this behavior
+is to quickly correct the frequency and restore operation to the
+normal tracking mode.
+In the most extreme cases
+(the host
+\f\*[B-Font]time.ien.it\f[]
+comes to mind), there may be occasional
+step/slew corrections and subsequent frequency corrections.
+It
+helps in these cases to use the
+\f\*[B-Font]burst\f[]
+keyword when
+configuring the server, but
+ONLY
+when you have permission to do so from the owner of the target host.
+.sp \n(Ppu
+.ne 2
+
+Finally,
+in the past many startup scripts would run
+\fCntpdate\f[]\fR(@NTPDATE_MS@)\f[]
+to get the system clock close to correct before starting
+\fCntpd\f[]\fR(@NTPD_MS@)\f[],
+but this was never more than a mediocre hack and is no longer needed.
+If you are following the instructions in
+\fIStarting NTP (Best Current Practice)\f[]
+and you still need to set the system time before starting
+\f\*[B-Font]ntpd\fP,
+please open a bug report and document what is going on,
+and then look at using
+\fCsntp\f[]\fR(@SNTP_MS@)\f[].
+.sp \n(Ppu
+.ne 2
+
+There is a way to start
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+that often addresses all of the problems mentioned above.
+.SS "Starting NTP (Best Current Practice)"
+First, use the
+\f\*[B-Font]iburst\f[]
+option on your
+\f\*[B-Font]server\f[]
+entries.
+.sp \n(Ppu
+.ne 2
+
+If you can also keep a good
+\fIntp.drift\f[]
+file then
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+will effectively "warm-start" and your system's clock will
+be stable in under 11 seconds' time.
+.sp \n(Ppu
+.ne 2
+
+As soon as possible in the startup sequence, start
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+with at least the
+\f\*[B-Font]\-g\f[]
+and perhaps the
+\f\*[B-Font]\-N\f[]
+options.
+Then,
+start the rest of your "normal" processes.
+This will give
+\fCntpd\f[]\fR(@NTPD_MS@)\f[]
+as much time as possible to get the system's clock synchronized and stable.
+.sp \n(Ppu
+.ne 2
+
+Finally,
+if you have processes like
+\f\*[B-Font]dovecot\f[]
+or database servers
+that require
+monotonically-increasing time,
+run
+\fCntp-wait\f[]\fR(@NTP_WAIT_MS@)\f[]
+as late as possible in the boot sequence
+(perhaps with the
+\f\*[B-Font]\-v\f[]
+flag)
+and after
+\fCntp-wait\f[]\fR(@NTP_WAIT_MS@)\f[]
+exits successfully
+it is as safe as it will ever be to start any process that require
+stable time.
+.SS "Frequency Discipline"
+The
+\f\*[B-Font]ntpd\fP
+behavior at startup depends on whether the
+frequency file, usually
+\fIntp.drift\f[],
+exists.
+This file
+contains the latest estimate of clock frequency error.
+When the
+\f\*[B-Font]ntpd\fP
+is started and the file does not exist, the
+\f\*[B-Font]ntpd\fP
+enters a special mode designed to quickly adapt to
+the particular system clock oscillator time and frequency error.
+This takes approximately 15 minutes, after which the time and
+frequency are set to nominal values and the
+\f\*[B-Font]ntpd\fP
+enters
+normal mode, where the time and frequency are continuously tracked
+relative to the server.
+After one hour the frequency file is
+created and the current frequency offset written to it.
+When the
+\f\*[B-Font]ntpd\fP
+is started and the file does exist, the
+\f\*[B-Font]ntpd\fP
+frequency is initialized from the file and enters normal mode
+immediately.
+After that the current frequency offset is written to
+the file at hourly intervals.
+.SS "Operating Modes"
+The
+\f\*[B-Font]ntpd\fP
+utility can operate in any of several modes, including
+symmetric active/passive, client/server broadcast/multicast and
+manycast, as described in the
+"Association Management"
+page
+(available as part of the HTML documentation
+provided in
+\fI/usr/share/doc/ntp\f[]).
+It normally operates continuously while
+monitoring for small changes in frequency and trimming the clock
+for the ultimate precision.
+However, it can operate in a one-time
+mode where the time is set from an external server and frequency is
+set from a previously recorded frequency file.
+A
+broadcast/multicast or manycast client can discover remote servers,
+compute server-client propagation delay correction factors and
+configure itself automatically.
+This makes it possible to deploy a
+fleet of workstations without specifying configuration details
+specific to the local environment.
+.sp \n(Ppu
+.ne 2
+
+By default,
+\f\*[B-Font]ntpd\fP
+runs in continuous mode where each of
+possibly several external servers is polled at intervals determined
+by an intricate state machine.
+The state machine measures the
+incidental roundtrip delay jitter and oscillator frequency wander
+and determines the best poll interval using a heuristic algorithm.
+Ordinarily, and in most operating environments, the state machine
+will start with 64s intervals and eventually increase in steps to
+1024s.
+A small amount of random variation is introduced in order to
+avoid bunching at the servers.
+In addition, should a server become
+unreachable for some time, the poll interval is increased in steps
+to 1024s in order to reduce network overhead.
+.sp \n(Ppu
+.ne 2
+
+In some cases it may not be practical for
+\f\*[B-Font]ntpd\fP
+to run continuously.
+A common workaround has been to run the
+\fCntpdate\f[]\fR(@NTPDATE_MS@)\f[]
+or
+\fCsntp\f[]\fR(@SNTP_MS@)\f[]
+programs from a
+\fCcron\f[]\fR(8)\f[]
+job at designated
+times.
+However, these programs do not have the crafted signal
+processing, error checking or mitigation algorithms of
+\f\*[B-Font]ntpd\fP.
+The
+\f\*[B-Font]\-q\f[]
+option is intended for this purpose.
+Setting this option will cause
+\f\*[B-Font]ntpd\fP
+to exit just after
+setting the clock for the first time.
+The procedure for initially
+setting the clock is the same as in continuous mode; most
+applications will probably want to specify the
+\f\*[B-Font]iburst\f[]
+keyword with the
+\f\*[B-Font]server\f[]
+configuration command.
+With this
+keyword a volley of messages are exchanged to groom the data and
+the clock is set in about 10 s.
+If nothing is heard after a
+couple of minutes, the daemon times out and exits.
+After a suitable
+period of mourning, the
+\fCntpdate\f[]\fR(@NTPDATE_MS@)\f[]
+program will be
+retired.
+.sp \n(Ppu
+.ne 2
+
+When kernel support is available to discipline the clock
+frequency, which is the case for stock Solaris, Tru64, Linux and
+FreeBSD,
+a useful feature is available to discipline the clock
+frequency.
+First,
+\f\*[B-Font]ntpd\fP
+is run in continuous mode with
+selected servers in order to measure and record the intrinsic clock
+frequency offset in the frequency file.
+It may take some hours for
+the frequency and offset to settle down.
+Then the
+\f\*[B-Font]ntpd\fP
+is
+stopped and run in one-time mode as required.
+At each startup, the
+frequency is read from the file and initializes the kernel
+frequency.
+.SS "Poll Interval Control"
+This version of NTP includes an intricate state machine to
+reduce the network load while maintaining a quality of
+synchronization consistent with the observed jitter and wander.
+There are a number of ways to tailor the operation in order enhance
+accuracy by reducing the interval or to reduce network overhead by
+increasing it.
+However, the user is advised to carefully consider
+the consequences of changing the poll adjustment range from the
+default minimum of 64 s to the default maximum of 1,024 s.
+The
+default minimum can be changed with the
+\f\*[B-Font]tinker\f[]
+\f\*[B-Font]minpoll\f[]
+command to a value not less than 16 s.
+This value is used for all
+configured associations, unless overridden by the
+\f\*[B-Font]minpoll\f[]
+option on the configuration command.
+Note that most device drivers
+will not operate properly if the poll interval is less than 64 s
+and that the broadcast server and manycast client associations will
+also use the default, unless overridden.
+.sp \n(Ppu
+.ne 2
+
+In some cases involving dial up or toll services, it may be
+useful to increase the minimum interval to a few tens of minutes
+and maximum interval to a day or so.
+Under normal operation
+conditions, once the clock discipline loop has stabilized the
+interval will be increased in steps from the minimum to the
+maximum.
+However, this assumes the intrinsic clock frequency error
+is small enough for the discipline loop correct it.
+The capture
+range of the loop is 500 PPM at an interval of 64s decreasing by a
+factor of two for each doubling of interval.
+At a minimum of 1,024
+s, for example, the capture range is only 31 PPM.
+If the intrinsic
+error is greater than this, the drift file
+\fIntp.drift\f[]
+will
+have to be specially tailored to reduce the residual error below
+this limit.
+Once this is done, the drift file is automatically
+updated once per hour and is available to initialize the frequency
+on subsequent daemon restarts.
+.SS "The huff-n'-puff Filter"
+In scenarios where a considerable amount of data are to be
+downloaded or uploaded over telephone modems, timekeeping quality
+can be seriously degraded.
+This occurs because the differential
+delays on the two directions of transmission can be quite large.
+In
+many cases the apparent time errors are so large as to exceed the
+step threshold and a step correction can occur during and after the
+data transfer is in progress.
+.sp \n(Ppu
+.ne 2
+
+The huff-n'-puff filter is designed to correct the apparent time
+offset in these cases.
+It depends on knowledge of the propagation
+delay when no other traffic is present.
+In common scenarios this
+occurs during other than work hours.
+The filter maintains a shift
+register that remembers the minimum delay over the most recent
+interval measured usually in hours.
+Under conditions of severe
+delay, the filter corrects the apparent offset using the sign of
+the offset and the difference between the apparent delay and
+minimum delay.
+The name of the filter reflects the negative (huff)
+and positive (puff) correction, which depends on the sign of the
+offset.
+.sp \n(Ppu
+.ne 2
+
+The filter is activated by the
+\f\*[B-Font]tinker\f[]
+command and
+\f\*[B-Font]huffpuff\f[]
+keyword, as described in
+\fCntp.conf\f[]\fR(5)\f[].
+.SH "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.SH FILES
+.TP 15
+.NOP \fI/etc/ntp.conf\f[]
+the default name of the configuration file
+.br
+.ns
+.TP 15
+.NOP \fI/etc/ntp.drift\f[]
+the default name of the drift file
+.br
+.ns
+.TP 15
+.NOP \fI/etc/ntp.keys\f[]
+the default name of the key file
+.PP
+.SH "EXIT STATUS"
+One of the following exit values will be returned:
+.TP
+.NOP 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.TP
+.NOP 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.TP
+.NOP 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+.PP
+.SH "SEE ALSO"
+\fCntp.conf\f[]\fR(5)\f[],
+\fCntpdate\f[]\fR(@NTPDATE_MS@)\f[],
+\fCntpdc\f[]\fR(@NTPDC_MS@)\f[],
+\fCntpq\f[]\fR(@NTPQ_MS@)\f[],
+\fCsntp\f[]\fR(@SNTP_MS@)\f[]
+.sp \n(Ppu
+.ne 2
+
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+\f[C]http://www.ntp.org/\f[].
+A snapshot of this documentation is available in HTML format in
+\fI/usr/share/doc/ntp\f[].
+David L. Mills,
+\fINetwork Time Protocol (Version 1)\fR,
+RFC1059
+.PP
+
+David L. Mills,
+\fINetwork Time Protocol (Version 2)\fR,
+RFC1119
+.PP
+
+David L. Mills,
+\fINetwork Time Protocol (Version 3)\fR,
+RFC1305
+.PP
+
+David L. Mills and J. Martin, Ed. and J. Burbank and W. Kasch,
+\fINetwork Time Protocol Version 4: Protocol and Algorithms Specification\fR,
+RFC5905
+.PP
+
+David L. Mills and B. Haberman, Ed.,
+\fINetwork Time Protocol Version 4: Autokey Specification\fR,
+RFC5906
+.PP
+
+H. Gerstung and C. Elliott and B. Haberman, Ed.,
+\fIDefinitions of Managed Objects for Network Time Protocol Version 4: (NTPv4)\fR,
+RFC5907
+.PP
+
+R. Gayraud and B. Lourdelet,
+\fINetwork Time Protocol (NTP) Server Option for DHCPv6\fR,
+RFC5908
+.PP
+
+.SH "AUTHORS"
+The University of Delaware and Network Time Foundation
+.SH "COPYRIGHT"
+Copyright (C) 1992-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.SH BUGS
+The
+\f\*[B-Font]ntpd\fP
+utility has gotten rather fat.
+While not huge, it has gotten
+larger than might be desirable for an elevated-priority
+\f\*[B-Font]ntpd\fP
+running on a workstation, particularly since many of
+the fancy features which consume the space were designed more with
+a busy primary server, rather than a high stratum workstation in
+mind.
+.sp \n(Ppu
+.ne 2
+
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.SH NOTES
+Portions of this document came from FreeBSD.
+.sp \n(Ppu
+.ne 2
+
+This manual page was \fIAutoGen\fP-erated from the \fBntpd\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntpd.mdoc.in b/contrib/ntp/ntpd/ntpd.mdoc.in
new file mode 100644
index 0000000..7d87d85
--- /dev/null
+++ b/contrib/ntp/ntpd/ntpd.mdoc.in
@@ -0,0 +1,904 @@
+.Dd June 29 2015
+.Dt NTPD @NTPD_MS@ User Commands
+.Os
+.\" EDIT THIS FILE WITH CAUTION (ntpd-opts.mdoc)
+.\"
+.\" It has been AutoGen-ed June 29, 2015 at 04:30:41 PM by AutoGen 5.18.5
+.\" From the definitions ntpd-opts.def
+.\" and the template file agmdoc-cmd.tpl
+.Sh NAME
+.Nm ntpd
+.Nd NTP daemon program
+.Sh SYNOPSIS
+.Nm
+.\" Mixture of short (flag) options and long options
+.Op Fl flags
+.Op Fl flag Op Ar value
+.Op Fl \-option\-name Ns Oo Oo Ns "=| " Oc Ns Ar value Oc
+[ <server1> ... <serverN> ]
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+utility is an operating system daemon which sets
+and maintains the system time of day in synchronism with Internet
+standard time servers.
+It is a complete implementation of the
+Network Time Protocol (NTP) version 4, as defined by RFC\-5905,
+but also retains compatibility with
+version 3, as defined by RFC\-1305, and versions 1
+and 2, as defined by RFC\-1059 and RFC\-1119, respectively.
+.Pp
+The
+.Nm
+utility does most computations in 64\-bit floating point
+arithmetic and does relatively clumsy 64\-bit fixed point operations
+only when necessary to preserve the ultimate precision, about 232
+picoseconds.
+While the ultimate precision is not achievable with
+ordinary workstations and networks of today, it may be required
+with future gigahertz CPU clocks and gigabit LANs.
+.Pp
+Ordinarily,
+.Nm
+reads the
+.Xr ntp.conf 5
+configuration file at startup time in order to determine the
+synchronization sources and operating modes.
+It is also possible to
+specify a working, although limited, configuration entirely on the
+command line, obviating the need for a configuration file.
+This may
+be particularly useful when the local host is to be configured as a
+broadcast/multicast client, with all peers being determined by
+listening to broadcasts at run time.
+.Pp
+If NetInfo support is built into
+.Nm ,
+then
+.Nm
+will attempt to read its configuration from the
+NetInfo if the default
+.Xr ntp.conf 5
+file cannot be read and no file is
+specified by the
+.Fl c
+option.
+.Pp
+Various internal
+.Nm
+variables can be displayed and
+configuration options altered while the
+.Nm
+is running
+using the
+.Xr ntpq @NTPQ_MS@
+and
+.Xr ntpdc @NTPDC_MS@
+utility programs.
+.Pp
+When
+.Nm
+starts it looks at the value of
+.Xr umask 2 ,
+and if zero
+.Nm
+will set the
+.Xr umask 2
+to 022.
+.Sh "OPTIONS"
+.Bl -tag
+.It Fl 4 , Fl \-ipv4
+Force IPv4 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv6.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+.It Fl 6 , Fl \-ipv6
+Force IPv6 DNS name resolution.
+This option must not appear in combination with any of the following options:
+ipv4.
+.sp
+Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+.It Fl a , Fl \-authreq
+Require crypto authentication.
+This option must not appear in combination with any of the following options:
+authnoreq.
+.sp
+Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+.It Fl A , Fl \-authnoreq
+Do not require crypto authentication.
+This option must not appear in combination with any of the following options:
+authreq.
+.sp
+Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+.It Fl b , Fl \-bcastsync
+Allow us to sync to broadcast servers.
+.sp
+.It Fl c Ar string , Fl \-configfile Ns = Ns Ar string
+configuration file name.
+.sp
+The name and path of the configuration file,
+\fI/etc/ntp.conf\fP
+by default.
+.It Fl d , Fl \-debug\-level
+Increase debug verbosity level.
+This option may appear an unlimited number of times.
+.sp
+.It Fl D Ar number , Fl \-set\-debug\-level Ns = Ns Ar number
+Set the debug verbosity level.
+This option may appear an unlimited number of times.
+This option takes an integer number as its argument.
+.sp
+.It Fl f Ar string , Fl \-driftfile Ns = Ns Ar string
+frequency drift file name.
+.sp
+The name and path of the frequency file,
+\fI/etc/ntp.drift\fP
+by default.
+This is the same operation as the
+\fBdriftfile\fP \fIdriftfile\fP
+configuration specification in the
+\fI/etc/ntp.conf\fP
+file.
+.It Fl g , Fl \-panicgate
+Allow the first adjustment to be Big.
+This option may appear an unlimited number of times.
+.sp
+Normally,
+\fBntpd\fP
+exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
+\fBntpd\fP
+will exit with a message to the system log. This option can be used with the
+\fB\-q\fP
+and
+\fB\-x\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+.It Fl G , Fl \-force\-step\-once
+Step any initial offset correction..
+.sp
+Normally,
+\fBntpd\fP
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the \fBtinker\fP configuration file directive for other options.
+.It Fl i Ar string , Fl \-jaildir Ns = Ns Ar string
+Jail directory.
+.sp
+Chroot the server to the directory
+\fIjaildir\fP
+.
+This option also implies that the server attempts to drop root privileges at startup.
+You may need to also specify a
+\fB\-u\fP
+option.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB\-\-enable\-clockctl\fP) or Linux (configure with
+\fB\-\-enable\-linuxcaps\fP) or Solaris (configure with \fB\-\-enable\-solarisprivs\fP).
+.It Fl I Ar iface , Fl \-interface Ns = Ns Ar iface
+Listen on an interface name or address.
+This option may appear an unlimited number of times.
+.sp
+Open the network address given, or all the addresses associated with the
+given interface name. This option may appear multiple times. This option
+also implies not opening other addresses, except wildcard and localhost.
+This option is deprecated. Please consider using the configuration file
+\fBinterface\fP command, which is more versatile.
+.It Fl k Ar string , Fl \-keyfile Ns = Ns Ar string
+path to symmetric keys.
+.sp
+Specify the name and path of the symmetric key file.
+\fI/etc/ntp.keys\fP
+is the default.
+This is the same operation as the
+\fBkeys\fP \fIkeyfile\fP
+configuration file directive.
+.It Fl l Ar string , Fl \-logfile Ns = Ns Ar string
+path to the log file.
+.sp
+Specify the name and path of the log file.
+The default is the system log file.
+This is the same operation as the
+\fBlogfile\fP \fIlogfile\fP
+configuration file directive.
+.It Fl L , Fl \-novirtualips
+Do not listen to virtual interfaces.
+.sp
+Do not listen to virtual interfaces, defined as those with
+names containing a colon. This option is deprecated. Please
+consider using the configuration file \fBinterface\fP command, which
+is more versatile.
+.It Fl M , Fl \-modifymmtimer
+Modify Multimedia Timer (Windows only).
+.sp
+Set the Windows Multimedia Timer to highest resolution. This
+ensures the resolution does not change while ntpd is running,
+avoiding timekeeping glitches associated with changes.
+.It Fl n , Fl \-nofork
+Do not fork.
+This option must not appear in combination with any of the following options:
+wait\-sync.
+.sp
+.It Fl N , Fl \-nice
+Run at high priority.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the highest priority.
+.It Fl p Ar string , Fl \-pidfile Ns = Ns Ar string
+path to the PID file.
+.sp
+Specify the name and path of the file used to record
+\fBntpd\fP's
+process ID.
+This is the same operation as the
+\fBpidfile\fP \fIpidfile\fP
+configuration file directive.
+.It Fl P Ar number , Fl \-priority Ns = Ns Ar number
+Process priority.
+This option takes an integer number as its argument.
+.sp
+To the extent permitted by the operating system, run
+\fBntpd\fP
+at the specified
+\fBsched_setscheduler(SCHED_FIFO)\fP
+priority.
+.It Fl q , Fl \-quit
+Set the time and quit.
+This option must not appear in combination with any of the following options:
+saveconfigquit, wait\-sync.
+.sp
+\fBntpd\fP
+will not daemonize and will exit after the clock is first
+synchronized. This behavior mimics that of the
+\fBntpdate\fP
+program, which will soon be replaced with a shell script.
+The
+\fB\-g\fP
+and
+\fB\-x\fP
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+.It Fl r Ar string , Fl \-propagationdelay Ns = Ns Ar string
+Broadcast/propagation delay.
+.sp
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+.It Fl \-saveconfigquit Ns = Ns Ar string
+Save parsed configuration and quit.
+This option must not appear in combination with any of the following options:
+quit, wait\-sync.
+.sp
+Cause \fBntpd\fP to parse its startup configuration file and save an
+equivalent to the given filename and exit. This option was
+designed for automated testing.
+.It Fl s Ar string , Fl \-statsdir Ns = Ns Ar string
+Statistics file location.
+.sp
+Specify the directory path for files created by the statistics facility.
+This is the same operation as the
+\fBstatsdir\fP \fIstatsdir\fP
+configuration file directive.
+.It Fl t Ar tkey , Fl \-trustedkey Ns = Ns Ar tkey
+Trusted key number.
+This option may appear an unlimited number of times.
+.sp
+Add the specified key number to the trusted key list.
+.It Fl u Ar string , Fl \-user Ns = Ns Ar string
+Run as userid (or userid:groupid).
+.sp
+Specify a user, and optionally a group, to switch to.
+This option is only available if the OS supports adjusting the clock
+without full root privileges.
+This option is supported under NetBSD (configure with
+\fB\-\-enable\-clockctl\fP) or Linux (configure with
+\fB\-\-enable\-linuxcaps\fP) or Solaris (configure with \fB\-\-enable\-solarisprivs\fP).
+.It Fl U Ar number , Fl \-updateinterval Ns = Ns Ar number
+interval in seconds between scans for new or dropped interfaces.
+This option takes an integer number as its argument.
+.sp
+Give the time in seconds between two scans for new or dropped interfaces.
+For systems with routing socket support the scans will be performed shortly after the interface change
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+.It Fl \-var Ns = Ns Ar nvar
+make ARG an ntp variable (RW).
+This option may appear an unlimited number of times.
+.sp
+.It Fl \-dvar Ns = Ns Ar ndvar
+make ARG an ntp variable (RW|DEF).
+This option may appear an unlimited number of times.
+.sp
+.It Fl w Ar number , Fl \-wait\-sync Ns = Ns Ar number
+Seconds to wait for first clock sync.
+This option must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+This option takes an integer number as its argument.
+.sp
+If greater than zero, alters \fBntpd\fP's behavior when forking to
+daemonize. Instead of exiting with status 0 immediately after
+the fork, the parent waits up to the specified number of
+seconds for the child to first synchronize the clock. The exit
+status is zero (success) if the clock was synchronized,
+otherwise it is \fBETIMEDOUT\fP.
+This provides the option for a script starting \fBntpd\fP to easily
+wait for the first set of the clock before proceeding.
+.It Fl x , Fl \-slew
+Slew up to 600 seconds.
+.sp
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+This option can be used with the
+\fB\-g\fP
+and
+\fB\-q\fP
+options.
+See the
+\fBtinker\fP
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+.It Fl \-usepcc
+Use CPU cycle counter (Windows only).
+.sp
+Attempt to substitute the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter and \fBQueryPerformanceCounter\fP are compared, and if
+they have the same frequency, the CPU counter (RDTSC on x86) is
+used directly, saving the overhead of a system call.
+.It Fl \-pccfreq Ns = Ns Ar string
+Force CPU cycle counter use (Windows only).
+.sp
+Force substitution the CPU counter for \fBQueryPerformanceCounter\fP.
+The CPU counter (RDTSC on x86) is used unconditionally with the
+given frequency (in Hz).
+.It Fl m , Fl \-mdns
+Register with mDNS as a NTP server.
+.sp
+Registers as an NTP server with the local mDNS server which allows
+the server to be discovered via mDNS client lookup.
+.It Fl \&? , Fl \-help
+Display usage information and exit.
+.It Fl \&! , Fl \-more\-help
+Pass the extended usage information through a pager.
+.It Fl \-version Op Brq Ar v|c|n
+Output version of program and exit. The default mode is `v', a simple
+version. The `c' mode will print copyright information and `n' will
+print the full copyright notice.
+.El
+.Sh "OPTION PRESETS"
+Any option that is not marked as \fInot presettable\fP may be preset
+by loading values from environment variables named:
+.nf
+ \fBNTPD_<option\-name>\fP or \fBNTPD\fP
+.fi
+.ad
+.Sh USAGE
+.Ss "How NTP Operates"
+The
+.Nm
+utility operates by exchanging messages with
+one or more configured servers over a range of designated poll intervals.
+When
+started, whether for the first or subsequent times, the program
+requires several exchanges from the majority of these servers so
+the signal processing and mitigation algorithms can accumulate and
+groom the data and set the clock.
+In order to protect the network
+from bursts, the initial poll interval for each server is delayed
+an interval randomized over a few seconds.
+At the default initial poll
+interval of 64s, several minutes can elapse before the clock is
+set.
+This initial delay to set the clock
+can be safely and dramatically reduced using the
+.Cm iburst
+keyword with the
+.Ic server
+configuration
+command, as described in
+.Xr ntp.conf 5 .
+.Pp
+Most operating systems and hardware of today incorporate a
+time\-of\-year (TOY) chip to maintain the time during periods when
+the power is off.
+When the machine is booted, the chip is used to
+initialize the operating system time.
+After the machine has
+synchronized to a NTP server, the operating system corrects the
+chip from time to time.
+In the default case, if
+.Nm
+detects that the time on the host
+is more than 1000s from the server time,
+.Nm
+assumes something must be terribly wrong and the only
+reliable action is for the operator to intervene and set the clock
+by hand.
+(Reasons for this include there is no TOY chip,
+or its battery is dead, or that the TOY chip is just of poor quality.)
+This causes
+.Nm
+to exit with a panic message to
+the system log.
+The
+.Fl g
+option overrides this check and the
+clock will be set to the server time regardless of the chip time
+(up to 68 years in the past or future \(em
+this is a limitation of the NTPv4 protocol).
+However, and to protect against broken hardware, such as when the
+CMOS battery fails or the clock counter becomes defective, once the
+clock has been set an error greater than 1000s will cause
+.Nm
+to exit anyway.
+.Pp
+Under ordinary conditions,
+.Nm
+adjusts the clock in
+small steps so that the timescale is effectively continuous and
+without discontinuities.
+Under conditions of extreme network
+congestion, the roundtrip delay jitter can exceed three seconds and
+the synchronization distance, which is equal to one\-half the
+roundtrip delay plus error budget terms, can become very large.
+The
+.Nm
+algorithms discard sample offsets exceeding 128 ms,
+unless the interval during which no sample offset is less than 128
+ms exceeds 900s.
+The first sample after that, no matter what the
+offset, steps the clock to the indicated time.
+In practice this
+reduces the false alarm rate where the clock is stepped in error to
+a vanishingly low incidence.
+.Pp
+As the result of this behavior, once the clock has been set it
+very rarely strays more than 128 ms even under extreme cases of
+network path congestion and jitter.
+Sometimes, in particular when
+.Nm
+is first started without a valid drift file
+on a system with a large intrinsic drift
+the error might grow to exceed 128 ms,
+which would cause the clock to be set backwards
+if the local clock time is more than 128 s
+in the future relative to the server.
+In some applications, this behavior may be unacceptable.
+There are several solutions, however.
+If the
+.Fl x
+option is included on the command line, the clock will
+never be stepped and only slew corrections will be used.
+But this choice comes with a cost that
+should be carefully explored before deciding to use
+the
+.Fl x
+option.
+The maximum slew rate possible is limited
+to 500 parts\-per\-million (PPM) as a consequence of the correctness
+principles on which the NTP protocol and algorithm design are
+based.
+As a result, the local clock can take a long time to
+converge to an acceptable offset, about 2,000 s for each second the
+clock is outside the acceptable range.
+During this interval the
+local clock will not be consistent with any other network clock and
+the system cannot be used for distributed applications that require
+correctly synchronized network time.
+.Pp
+In spite of the above precautions, sometimes when large
+frequency errors are present the resulting time offsets stray
+outside the 128\-ms range and an eventual step or slew time
+correction is required.
+If following such a correction the
+frequency error is so large that the first sample is outside the
+acceptable range,
+.Nm
+enters the same state as when the
+.Pa ntp.drift
+file is not present.
+The intent of this behavior
+is to quickly correct the frequency and restore operation to the
+normal tracking mode.
+In the most extreme cases
+(the host
+.Cm time.ien.it
+comes to mind), there may be occasional
+step/slew corrections and subsequent frequency corrections.
+It
+helps in these cases to use the
+.Cm burst
+keyword when
+configuring the server, but
+ONLY
+when you have permission to do so from the owner of the target host.
+.Pp
+Finally,
+in the past many startup scripts would run
+.Xr ntpdate @NTPDATE_MS@
+to get the system clock close to correct before starting
+.Xr ntpd @NTPD_MS@ ,
+but this was never more than a mediocre hack and is no longer needed.
+If you are following the instructions in
+.Sx "Starting NTP (Best Current Practice)"
+and you still need to set the system time before starting
+.Nm ,
+please open a bug report and document what is going on,
+and then look at using
+.Xr sntp @SNTP_MS@ .
+.Pp
+There is a way to start
+.Xr ntpd @NTPD_MS@
+that often addresses all of the problems mentioned above.
+.Ss "Starting NTP (Best Current Practice)"
+First, use the
+.Cm iburst
+option on your
+.Cm server
+entries.
+.Pp
+If you can also keep a good
+.Pa ntp.drift
+file then
+.Xr ntpd @NTPD_MS@
+will effectively "warm\-start" and your system's clock will
+be stable in under 11 seconds' time.
+.Pp
+As soon as possible in the startup sequence, start
+.Xr ntpd @NTPD_MS@
+with at least the
+.Fl g
+and perhaps the
+.Fl N
+options.
+Then,
+start the rest of your "normal" processes.
+This will give
+.Xr ntpd @NTPD_MS@
+as much time as possible to get the system's clock synchronized and stable.
+.Pp
+Finally,
+if you have processes like
+.Cm dovecot
+or database servers
+that require
+monotonically\-increasing time,
+run
+.Xr ntp\-wait 1ntp\-waitmdoc
+as late as possible in the boot sequence
+(perhaps with the
+.Fl v
+flag)
+and after
+.Xr ntp\-wait 1ntp\-waitmdoc
+exits successfully
+it is as safe as it will ever be to start any process that require
+stable time.
+.Ss "Frequency Discipline"
+The
+.Nm
+behavior at startup depends on whether the
+frequency file, usually
+.Pa ntp.drift ,
+exists.
+This file
+contains the latest estimate of clock frequency error.
+When the
+.Nm
+is started and the file does not exist, the
+.Nm
+enters a special mode designed to quickly adapt to
+the particular system clock oscillator time and frequency error.
+This takes approximately 15 minutes, after which the time and
+frequency are set to nominal values and the
+.Nm
+enters
+normal mode, where the time and frequency are continuously tracked
+relative to the server.
+After one hour the frequency file is
+created and the current frequency offset written to it.
+When the
+.Nm
+is started and the file does exist, the
+.Nm
+frequency is initialized from the file and enters normal mode
+immediately.
+After that the current frequency offset is written to
+the file at hourly intervals.
+.Ss "Operating Modes"
+The
+.Nm
+utility can operate in any of several modes, including
+symmetric active/passive, client/server broadcast/multicast and
+manycast, as described in the
+.Qq Association Management
+page
+(available as part of the HTML documentation
+provided in
+.Pa /usr/share/doc/ntp ) .
+It normally operates continuously while
+monitoring for small changes in frequency and trimming the clock
+for the ultimate precision.
+However, it can operate in a one\-time
+mode where the time is set from an external server and frequency is
+set from a previously recorded frequency file.
+A
+broadcast/multicast or manycast client can discover remote servers,
+compute server\-client propagation delay correction factors and
+configure itself automatically.
+This makes it possible to deploy a
+fleet of workstations without specifying configuration details
+specific to the local environment.
+.Pp
+By default,
+.Nm
+runs in continuous mode where each of
+possibly several external servers is polled at intervals determined
+by an intricate state machine.
+The state machine measures the
+incidental roundtrip delay jitter and oscillator frequency wander
+and determines the best poll interval using a heuristic algorithm.
+Ordinarily, and in most operating environments, the state machine
+will start with 64s intervals and eventually increase in steps to
+1024s.
+A small amount of random variation is introduced in order to
+avoid bunching at the servers.
+In addition, should a server become
+unreachable for some time, the poll interval is increased in steps
+to 1024s in order to reduce network overhead.
+.Pp
+In some cases it may not be practical for
+.Nm
+to run continuously.
+A common workaround has been to run the
+.Xr ntpdate @NTPDATE_MS@
+or
+.Xr sntp @SNTP_MS@
+programs from a
+.Xr cron 8
+job at designated
+times.
+However, these programs do not have the crafted signal
+processing, error checking or mitigation algorithms of
+.Nm .
+The
+.Fl q
+option is intended for this purpose.
+Setting this option will cause
+.Nm
+to exit just after
+setting the clock for the first time.
+The procedure for initially
+setting the clock is the same as in continuous mode; most
+applications will probably want to specify the
+.Cm iburst
+keyword with the
+.Ic server
+configuration command.
+With this
+keyword a volley of messages are exchanged to groom the data and
+the clock is set in about 10 s.
+If nothing is heard after a
+couple of minutes, the daemon times out and exits.
+After a suitable
+period of mourning, the
+.Xr ntpdate @NTPDATE_MS@
+program will be
+retired.
+.Pp
+When kernel support is available to discipline the clock
+frequency, which is the case for stock Solaris, Tru64, Linux and
+.Fx ,
+a useful feature is available to discipline the clock
+frequency.
+First,
+.Nm
+is run in continuous mode with
+selected servers in order to measure and record the intrinsic clock
+frequency offset in the frequency file.
+It may take some hours for
+the frequency and offset to settle down.
+Then the
+.Nm
+is
+stopped and run in one\-time mode as required.
+At each startup, the
+frequency is read from the file and initializes the kernel
+frequency.
+.Ss "Poll Interval Control"
+This version of NTP includes an intricate state machine to
+reduce the network load while maintaining a quality of
+synchronization consistent with the observed jitter and wander.
+There are a number of ways to tailor the operation in order enhance
+accuracy by reducing the interval or to reduce network overhead by
+increasing it.
+However, the user is advised to carefully consider
+the consequences of changing the poll adjustment range from the
+default minimum of 64 s to the default maximum of 1,024 s.
+The
+default minimum can be changed with the
+.Ic tinker
+.Cm minpoll
+command to a value not less than 16 s.
+This value is used for all
+configured associations, unless overridden by the
+.Cm minpoll
+option on the configuration command.
+Note that most device drivers
+will not operate properly if the poll interval is less than 64 s
+and that the broadcast server and manycast client associations will
+also use the default, unless overridden.
+.Pp
+In some cases involving dial up or toll services, it may be
+useful to increase the minimum interval to a few tens of minutes
+and maximum interval to a day or so.
+Under normal operation
+conditions, once the clock discipline loop has stabilized the
+interval will be increased in steps from the minimum to the
+maximum.
+However, this assumes the intrinsic clock frequency error
+is small enough for the discipline loop correct it.
+The capture
+range of the loop is 500 PPM at an interval of 64s decreasing by a
+factor of two for each doubling of interval.
+At a minimum of 1,024
+s, for example, the capture range is only 31 PPM.
+If the intrinsic
+error is greater than this, the drift file
+.Pa ntp.drift
+will
+have to be specially tailored to reduce the residual error below
+this limit.
+Once this is done, the drift file is automatically
+updated once per hour and is available to initialize the frequency
+on subsequent daemon restarts.
+.Ss "The huff\-n'\-puff Filter"
+In scenarios where a considerable amount of data are to be
+downloaded or uploaded over telephone modems, timekeeping quality
+can be seriously degraded.
+This occurs because the differential
+delays on the two directions of transmission can be quite large.
+In
+many cases the apparent time errors are so large as to exceed the
+step threshold and a step correction can occur during and after the
+data transfer is in progress.
+.Pp
+The huff\-n'\-puff filter is designed to correct the apparent time
+offset in these cases.
+It depends on knowledge of the propagation
+delay when no other traffic is present.
+In common scenarios this
+occurs during other than work hours.
+The filter maintains a shift
+register that remembers the minimum delay over the most recent
+interval measured usually in hours.
+Under conditions of severe
+delay, the filter corrects the apparent offset using the sign of
+the offset and the difference between the apparent delay and
+minimum delay.
+The name of the filter reflects the negative (huff)
+and positive (puff) correction, which depends on the sign of the
+offset.
+.Pp
+The filter is activated by the
+.Ic tinker
+command and
+.Cm huffpuff
+keyword, as described in
+.Xr ntp.conf 5 .
+.Sh "ENVIRONMENT"
+See \fBOPTION PRESETS\fP for configuration environment variables.
+.Sh FILES
+.Bl -tag -width /etc/ntp.drift -compact
+.It Pa /etc/ntp.conf
+the default name of the configuration file
+.It Pa /etc/ntp.drift
+the default name of the drift file
+.It Pa /etc/ntp.keys
+the default name of the key file
+.El
+.Sh "EXIT STATUS"
+One of the following exit values will be returned:
+.Bl -tag
+.It 0 " (EXIT_SUCCESS)"
+Successful program execution.
+.It 1 " (EXIT_FAILURE)"
+The operation failed or the command syntax was not valid.
+.It 70 " (EX_SOFTWARE)"
+libopts had an internal operational error. Please report
+it to autogen\-users@lists.sourceforge.net. Thank you.
+.El
+.Sh "SEE ALSO"
+.Xr ntp.conf 5 ,
+.Xr ntpdate @NTPDATE_MS@ ,
+.Xr ntpdc @NTPDC_MS@ ,
+.Xr ntpq @NTPQ_MS@ ,
+.Xr sntp @SNTP_MS@
+.Pp
+In addition to the manual pages provided,
+comprehensive documentation is available on the world wide web
+at
+.Li http://www.ntp.org/ .
+A snapshot of this documentation is available in HTML format in
+.Pa /usr/share/doc/ntp .
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 1)
+.%O RFC1059
+.Re
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 2)
+.%O RFC1119
+.Re
+.Rs
+.%A David L. Mills
+.%T Network Time Protocol (Version 3)
+.%O RFC1305
+.Re
+.Rs
+.%A David L. Mills
+.%A J. Martin, Ed.
+.%A J. Burbank
+.%A W. Kasch
+.%T Network Time Protocol Version 4: Protocol and Algorithms Specification
+.%O RFC5905
+.Re
+.Rs
+.%A David L. Mills
+.%A B. Haberman, Ed.
+.%T Network Time Protocol Version 4: Autokey Specification
+.%O RFC5906
+.Re
+.Rs
+.%A H. Gerstung
+.%A C. Elliott
+.%A B. Haberman, Ed.
+.%T Definitions of Managed Objects for Network Time Protocol Version 4: (NTPv4)
+.%O RFC5907
+.Re
+.Rs
+.%A R. Gayraud
+.%A B. Lourdelet
+.%T Network Time Protocol (NTP) Server Option for DHCPv6
+.%O RFC5908
+.Re
+.Sh "AUTHORS"
+The University of Delaware and Network Time Foundation
+.Sh "COPYRIGHT"
+Copyright (C) 1992\-2015 The University of Delaware and Network Time Foundation all rights reserved.
+This program is released under the terms of the NTP license, <http://ntp.org/license>.
+.Sh BUGS
+The
+.Nm
+utility has gotten rather fat.
+While not huge, it has gotten
+larger than might be desirable for an elevated\-priority
+.Nm
+running on a workstation, particularly since many of
+the fancy features which consume the space were designed more with
+a busy primary server, rather than a high stratum workstation in
+mind.
+.Pp
+Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
+.Sh NOTES
+Portions of this document came from FreeBSD.
+.Pp
+This manual page was \fIAutoGen\fP\-erated from the \fBntpd\fP
+option definitions.
diff --git a/contrib/ntp/ntpd/ntpd.texi b/contrib/ntp/ntpd/ntpd.texi
new file mode 100644
index 0000000..0ac091b
--- /dev/null
+++ b/contrib/ntp/ntpd/ntpd.texi
@@ -0,0 +1,113 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ntpd.info
+@settitle ntpd: Network Time Protocol (NTP) Daemon User's Manual
+@include ../sntp/include/version.texi
+@paragraphindent 2
+@c %**end of header
+
+@ifinfo
+This file documents the use of the NTP Project's ntpd, a program for
+controlling ntpd.
+@end ifinfo
+
+@direntry
+* ntpd: (ntpd). NTP Daemon program
+@end direntry
+
+@titlepage
+@title ntpd: Network Time Protocol (NTP) Daemon User's Manual
+@subtitle ntpd, version @value{VERSION}, @value{UPDATED}
+@c @author Max @email{foo@ntp.org}
+@end titlepage
+
+@c @page
+@c @vskip 0pt plus 1filll
+
+@node Top, ntpd Description, (dir), (dir)
+@top ntpd: Network Time Protocol (NTP) Daemon User Manual
+
+The @code{ntpd} program is an operating system daemon that synchronizes the
+system clock to remote NTP time servers or local reference clocks.
+It is a complete implementation of NTP version 4 defined by RFC-5905, but
+also retains compatible with version 3 defined by RFC-1305 and versions
+1 and 2, defined by RFC-1059 and RFC-1119, respectively.
+The program can operate in any of several modes, including client/server,
+symmetric and broadcast modes, and with both symmetric-key and public-key
+cryptography.
+
+This document applies to version @value{VERSION} of @code{ntpd}.
+
+@shortcontents
+
+@menu
+* ntpd Description:: Description
+* ntpd Invocation:: Invoking ntpd
+* Usage:: Usage
+@end menu
+
+@node ntpd Description
+@comment node-name, next, previous, up
+@section Description
+
+The @code{ntpd} program ordinarily requires
+a configuration file described at @ref{ntp.conf}.
+This configuration file contains configuration commands described on
+the pages listed above.
+However a client can discover remote servers and configure them
+automatically.
+This makes it possible to deploy a fleet of workstations without
+specifying configuration details specific to the local environment.
+
+The @code{ntpd} program normally operates continuously while adjusting the
+system time and frequency, but in some cases this might not be
+practical.
+With the @code{-q} option @code{ntpd} operates as in continuous mode, but
+exits just after setting the clock for the first time.
+Most applications will probably want to specify the @code{iburst}
+option with the @code{server} command.
+With this option an initial volley of messages is exchanged to
+groom the data and set the clock in about ten seconds' time.
+If nothing is heard after a few minutes' time,
+the daemon times out and exits without setting the clock.
+
+@include invoke-ntpd.texi
+
+@node Usage
+@comment node-name, next, previous, up
+@section Usage
+
+@multitable @columnfractions .23 .23 .05 .15
+@headitem What @tab Default @tab Flag @tab Option
+@item configuration file
+@tab @code{/etc/ntp.conf}
+@tab @code{-c}
+@tab @code{conffile}
+@item frequency file
+@tab none
+@tab @code{-f}
+@tab @code{driftfile}
+@item leapseconds file
+@tab none
+@tab
+@tab @code{leapfile}
+@item process ID file
+@tab none
+@tab @code{-p}
+@tab @code{pidfile}
+@item log file
+@tab system log
+@tab @code{-l}
+@tab @code{logfile}
+@item include file
+@tab none
+@tab none
+@tab @code{includefile}
+@item statistics path
+@tab @code{/var/NTP}
+@tab @code{-s}
+@tab @code{statsdir}
+@item keys path
+@tab @code{/usr/local/etc}
+@tab @code{-k}
+@tab @code{keysdir}
diff --git a/contrib/ntp/ntpd/ntpdbase-opts.def b/contrib/ntp/ntpd/ntpdbase-opts.def
index 852af45..66b9535 100644
--- a/contrib/ntp/ntpd/ntpdbase-opts.def
+++ b/contrib/ntp/ntpd/ntpdbase-opts.def
@@ -1,11 +1,17 @@
#include autogen-version.def
-test-main;
+include = <<- _EOF_
+ #ifdef __windows
+ extern int atoi(const char *);
+ #else
+ # include <stdlib.h>
+ #endif
+ _EOF_;
flag = {
name = ipv4;
value = 4;
- equivalence = ipv4;
+ flags-cant = ipv6;
descrip = "Force IPv4 DNS name resolution";
doc = <<- _EndOfDoc_
Force DNS resolution of following host names on the command line
@@ -16,7 +22,7 @@ flag = {
flag = {
name = ipv6;
value = 6;
- equivalence = ipv4;
+ flags-cant = ipv4;
descrip = "Force IPv6 DNS name resolution";
doc = <<- _EndOfDoc_
Force DNS resolution of following host names on the command line
@@ -56,17 +62,6 @@ flag = {
_EndOfDoc_;
};
-#ifdef SIM
-flag = {
- name = simbroadcastdelay;
- value = B;
- arg-type = string;
- descrip = "Simulator broadcast delay";
- doc = <<- _EndOfDoc_
- _EndOfDoc_;
-};
-#endif
-
flag = {
name = configfile;
value = c;
@@ -74,22 +69,11 @@ flag = {
descrip = "configuration file name";
doc = <<- _EndOfDoc_
The name and path of the configuration file,
- /etc/ntp.conf
+ @file{/etc/ntp.conf}
by default.
_EndOfDoc_;
};
-#ifdef SIM
-flag = {
- name = phasenoise;
- value = C;
- arg-type = string;
- descrip = "Phase noise level";
- doc = <<- _EndOfDoc_
- _EndOfDoc_;
-};
-#endif
-
#include debug-opt.def
flag = {
@@ -99,12 +83,12 @@ flag = {
descrip = "frequency drift file name";
doc = <<- _EndOfDoc_
The name and path of the frequency file,
- /etc/ntp.drift
+ @file{/etc/ntp.drift}
by default.
This is the same operation as the
- driftfile driftfile
- configuration specification in the
- /etc/ntp.conf
+ @code{driftfile} @kbd{driftfile}
+ configuration specification in the
+ @file{/etc/ntp.conf}
file.
_EndOfDoc_;
};
@@ -112,47 +96,62 @@ flag = {
flag = {
name = panicgate;
value = g;
+ max = NOLIMIT;
descrip = "Allow the first adjustment to be Big";
doc = <<- _EndOfDoc_
Normally,
- ntpd
+ @code{ntpd}
exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
- ntpd
+ @code{ntpd}
will exit with a message to the system log. This option can be used with the
- -q
+ @code{-q}
and
- -x
+ @code{-x}
options.
See the
- tinker
+ @code{tinker}
configuration file directive for other options.
_EndOfDoc_;
};
-#ifdef SIM
flag = {
- name = simslew;
- value = H;
- arg-type = string;
- descrip = "Simuator slew";
+ name = force_step_once;
+ value = G;
+ descrip = "Step any initial offset correction.";
doc = <<- _EndOfDoc_
+ Normally,
+ @code{ntpd}
+ steps the time if the time offset exceeds the step threshold,
+ which is 128 ms by default, and otherwise slews the time.
+ This option forces the initial offset correction to be stepped,
+ so the highest time accuracy can be achieved quickly.
+ However, this may also cause the time to be stepped back
+ so this option must not be used if
+ applications requiring monotonic time are running.
+ See the @code{tinker} configuration file directive for other options.
_EndOfDoc_;
};
-#endif
flag = {
+ ifdef = HAVE_DROPROOT;
name = jaildir;
value = i;
arg-type = string;
descrip = "Jail directory";
+ omitted-usage = "built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs";
doc = <<- _EndOfDoc_
Chroot the server to the directory
- jaildir
+ @kbd{jaildir}
.
- This option also implies that the server attempts to drop root privileges at startup (otherwise, chroot gives very little additional security), and it is only available if the OS supports to run the server without full root privileges.
+ This option also implies that the server attempts to drop root privileges at startup.
You may need to also specify a
- -u
+ @code{-u}
option.
+ This option is only available if the OS supports adjusting the clock
+ without full root privileges.
+ This option is supported under NetBSD (configure with
+ @code{--enable-clockctl}) or Linux (configure with
+ @code{--enable-linuxcaps}) or Solaris (configure with @code{--enable-solarisprivs}).
_EndOfDoc_;
};
@@ -160,11 +159,16 @@ flag = {
name = interface;
value = I;
arg-type = string;
- descrip = "Listen on interface";
+ descrip = "Listen on an interface name or address";
max = NOLIMIT;
arg-name = iface;
stack-arg;
doc = <<- _EndOfDoc_
+ Open the network address given, or all the addresses associated with the
+ given interface name. This option may appear multiple times. This option
+ also implies not opening other addresses, except wildcard and localhost.
+ This option is deprecated. Please consider using the configuration file
+ @code{interface} command, which is more versatile.
_EndOfDoc_;
};
@@ -175,10 +179,10 @@ flag = {
descrip = "path to symmetric keys";
doc = <<- _EndOfDoc_
Specify the name and path of the symmetric key file.
- /etc/ntp.keys
+ @file{/etc/ntp.keys}
is the default.
This is the same operation as the
- keys keyfile
+ @code{keys} @kbd{keyfile}
configuration file directive.
_EndOfDoc_;
};
@@ -192,7 +196,7 @@ flag = {
Specify the name and path of the log file.
The default is the system log file.
This is the same operation as the
- logfile logfile
+ @code{logfile} @kbd{logfile}
configuration file directive.
_EndOfDoc_;
};
@@ -200,9 +204,12 @@ flag = {
flag = {
name = novirtualips;
value = L;
- descrip = "Do not listen to virtual IPs";
+ descrip = "Do not listen to virtual interfaces";
doc = <<- _EndOfDoc_
- Do not listen to virtual IPs. The default is to listen.
+ Do not listen to virtual interfaces, defined as those with
+ names containing a colon. This option is deprecated. Please
+ consider using the configuration file @code{interface} command, which
+ is more versatile.
_EndOfDoc_;
};
@@ -212,13 +219,16 @@ flag = {
value = M;
descrip = "Modify Multimedia Timer (Windows only)";
doc = <<- _EndOfDoc_
- Set the Windows Multimedia Timer to highest resolution.
+ Set the Windows Multimedia Timer to highest resolution. This
+ ensures the resolution does not change while ntpd is running,
+ avoiding timekeeping glitches associated with changes.
_EndOfDoc_;
};
flag = {
name = nofork;
value = n;
+ flags-cant = wait-sync;
descrip = "Do not fork";
doc = <<- _EndOfDoc_
_EndOfDoc_;
@@ -230,22 +240,11 @@ flag = {
descrip = "Run at high priority";
doc = <<- _EndOfDoc_
To the extent permitted by the operating system, run
- ntpd
+ @code{ntpd}
at the highest priority.
_EndOfDoc_;
};
-#ifdef SIM
-flag = {
- name = servertime;
- value = O;
- arg-type = string;
- descrip = "Server time";
- doc = <<- _EndOfDoc_
- _EndOfDoc_;
-};
-#endif
-
flag = {
name = pidfile;
value = p;
@@ -253,10 +252,10 @@ flag = {
descrip = "path to the PID file";
doc = <<- _EndOfDoc_
Specify the name and path of the file used to record
- ntpd's
+ @code{ntpd}'s
process ID.
This is the same operation as the
- pidfile pidfile
+ @code{pidfile} @kbd{pidfile}
configuration file directive.
_EndOfDoc_;
};
@@ -268,9 +267,9 @@ flag = {
descrip = "Process priority";
doc = <<- _EndOfDoc_
To the extent permitted by the operating system, run
- ntpd
+ @code{ntpd}
at the specified
- sched_setscheduler(SCHED_FIFO)
+ @code{sched_setscheduler(SCHED_FIFO)}
priority.
_EndOfDoc_;
};
@@ -278,16 +277,19 @@ flag = {
flag = {
name = quit;
value = q;
+ flags-cant = saveconfigquit;
+ flags-cant = wait-sync;
descrip = "Set the time and quit";
doc = <<- _EndOfDoc_
- ntpd
- will exit just after the first time the clock is set. This behavior mimics that of the
- ntpdate
- program, which is to be retired.
+ @code{ntpd}
+ will not daemonize and will exit after the clock is first
+ synchronized. This behavior mimics that of the
+ @code{ntpdate}
+ program, which will soon be replaced with a shell script.
The
- -g
+ @code{-g}
and
- -x
+ @code{-x}
options can be used with this option.
Note: The kernel time discipline is disabled with this option.
_EndOfDoc_;
@@ -304,15 +306,16 @@ flag = {
};
flag = {
- name = updateinterval;
- value = U;
- arg-type = number;
- descrip = "interval in seconds between scans for new or dropped interfaces";
+ ifdef = SAVECONFIG;
+ name = saveconfigquit;
+ arg-type = string;
+ flags-cant = quit;
+ flags-cant = wait-sync;
+ descrip = "Save parsed configuration and quit";
doc = <<- _EndOfDoc_
- Give the time in seconds between two scans for new or dropped interfaces.
- For systems with routing socket support the scans will be performed shortly after the interface change
- has been detected by the system.
- Use 0 to disable scanning.
+ Cause @code{ntpd} to parse its startup configuration file and save an
+ equivalent to the given filename and exit. This option was
+ designed for automated testing.
_EndOfDoc_;
};
@@ -324,22 +327,11 @@ flag = {
doc = <<- _EndOfDoc_
Specify the directory path for files created by the statistics facility.
This is the same operation as the
- statsdir statsdir
+ @code{statsdir} @kbd{statsdir}
configuration file directive.
_EndOfDoc_;
};
-#ifdef SIM
-flag = {
- name = endsimtime;
- value = S;
- arg-type = string;
- descrip = "Simulation end time";
- doc = <<- _EndOfDoc_
- _EndOfDoc_;
-};
-#endif
-
flag = {
name = trustedkey;
value = t;
@@ -349,51 +341,43 @@ flag = {
arg-name = tkey;
stack-arg;
doc = <<- _EndOfDoc_
- Add a key number to the trusted key list.
+ Add the specified key number to the trusted key list.
_EndOfDoc_;
};
-#ifdef SIM
flag = {
- name = freqerr;
- value = T;
- arg-type = string;
- descrip = "Simulation frequency error";
- doc = <<- _EndOfDoc_
- _EndOfDoc_;
-};
-#endif
-
-#ifdef SIM
-flag = {
- name = walknoise;
- value = W;
+ ifdef = HAVE_DROPROOT;
+ name = user;
+ value = u;
arg-type = string;
- descrip = "Simulation random walk noise";
+ descrip = "Run as userid (or userid:groupid)";
+ omitted-usage = "built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs";
doc = <<- _EndOfDoc_
+ Specify a user, and optionally a group, to switch to.
+ This option is only available if the OS supports adjusting the clock
+ without full root privileges.
+ This option is supported under NetBSD (configure with
+ @code{--enable-clockctl}) or Linux (configure with
+ @code{--enable-linuxcaps}) or Solaris (configure with @code{--enable-solarisprivs}).
_EndOfDoc_;
};
-#endif
flag = {
- name = user;
- value = u;
- arg-type = string;
- descrip = "Run as userid (or userid:groupid)";
+ name = updateinterval;
+ value = U;
+ arg-type = number;
+ descrip = "interval in seconds between scans for new or dropped interfaces";
doc = <<- _EndOfDoc_
- Specify a user, and optionally a group, to switch to.
- This option is only available if the OS supports to run the server without full root privileges.
- Currently, this option is supported under NetBSD (configure with
- --enable-clockctl
- ) and Linux (configure with
- --enable-linuxcaps
- ).
+ Give the time in seconds between two scans for new or dropped interfaces.
+ For systems with routing socket support the scans will be performed shortly after the interface change
+ has been detected by the system.
+ Use 0 to disable scanning. 60 seconds is the minimum time between scans.
_EndOfDoc_;
};
flag = {
name = var;
- value = v;
+/* value = v; Bug 817 */
arg-type = string;
descrip = "make ARG an ntp variable (RW)";
max = NOLIMIT;
@@ -405,7 +389,7 @@ flag = {
flag = {
name = dvar;
- value = V;
+/* value = V; Bug 817 */
arg-type = string;
descrip = "make ARG an ntp variable (RW|DEF)";
max = NOLIMIT;
@@ -416,6 +400,31 @@ flag = {
};
flag = {
+ ifdef = HAVE_WORKING_FORK;
+ name = wait-sync;
+ value = w;
+ arg-type = number;
+ flags-cant = nofork;
+ flags-cant = quit;
+ flags-cant = saveconfigquit;
+ descrip = "Seconds to wait for first clock sync";
+ doc = <<- _EndOfDoc_
+ If greater than zero, alters @code{ntpd}'s behavior when forking to
+ daemonize. Instead of exiting with status 0 immediately after
+ the fork, the parent waits up to the specified number of
+ seconds for the child to first synchronize the clock. The exit
+ status is zero (success) if the clock was synchronized,
+ otherwise it is @code{ETIMEDOUT}.
+ This provides the option for a script starting @code{ntpd} to easily
+ wait for the first set of the clock before proceeding.
+ _EndOfDoc_;
+/*
+** XXX: is it "first set" or is it more? If it's only "first set" then
+** that's not the same as SYNC.
+*/
+};
+
+flag = {
name = slew;
value = x;
descrip = "Slew up to 600 seconds";
@@ -425,35 +434,48 @@ flag = {
Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
Thus, an adjustment as much as 600 s will take almost 14 days to complete.
This option can be used with the
- -g
+ @code{-g}
and
- -q
+ @code{-q}
options.
See the
- tinker
+ @code{tinker}
configuration file directive for other options.
Note: The kernel time discipline is disabled with this option.
_EndOfDoc_;
};
-#ifdef SIM
flag = {
- name = ndelay;
- value = Y;
- arg-type = string;
- descrip = "Simulation network delay";
+ ifdef = SYS_WINNT;
+ name = usepcc;
+ descrip = "Use CPU cycle counter (Windows only)";
doc = <<- _EndOfDoc_
+ Attempt to substitute the CPU counter for @code{QueryPerformanceCounter}.
+ The CPU counter and @code{QueryPerformanceCounter} are compared, and if
+ they have the same frequency, the CPU counter (RDTSC on x86) is
+ used directly, saving the overhead of a system call.
_EndOfDoc_;
};
-#endif
-#ifdef SIM
flag = {
- name = pdelay;
- value = Z;
+ ifdef = SYS_WINNT;
+ name = pccfreq;
arg-type = string;
- descrip = "Simulation processing delay";
+ descrip = "Force CPU cycle counter use (Windows only)";
+ doc = <<- _EndOfDoc_
+ Force substitution the CPU counter for @code{QueryPerformanceCounter}.
+ The CPU counter (RDTSC on x86) is used unconditionally with the
+ given frequency (in Hz).
+ _EndOfDoc_;
+};
+
+flag = {
+ ifdef = HAVE_DNSREGISTRATION;
+ name = mdns;
+ value = m;
+ descrip = "Register with mDNS as a NTP server";
doc = <<- _EndOfDoc_
+ Registers as an NTP server with the local mDNS server which allows
+ the server to be discovered via mDNS client lookup.
_EndOfDoc_;
};
-#endif
diff --git a/contrib/ntp/ntpd/ntpdsim-opts.c b/contrib/ntp/ntpd/ntpdsim-opts.c
deleted file mode 100644
index d9ef1b2..0000000
--- a/contrib/ntp/ntpd/ntpdsim-opts.c
+++ /dev/null
@@ -1,1262 +0,0 @@
-/*
- * EDIT THIS FILE WITH CAUTION (ntpdsim-opts.c)
- *
- * It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:13 AM EST
- * From the definitions ntpdsim-opts.def
- * and the template file options
- *
- * Generated from AutoOpts 29:0:4 templates.
- */
-
-/*
- * This file was produced by an AutoOpts template. AutoOpts is a
- * copyrighted work. This source file is not encumbered by AutoOpts
- * licensing, but is provided under the licensing terms chosen by the
- * ntpdsim author or copyright holder. AutoOpts is licensed under
- * the terms of the LGPL. The redistributable library (``libopts'') is
- * licensed under the terms of either the LGPL or, at the users discretion,
- * the BSD license. See the AutoOpts and/or libopts sources for details.
- *
- * This source file is copyrighted and licensed under the following terms:
- *
- * ntpdsim copyright 1970-2009 David L. Mills and/or others - all rights reserved
- *
- * see html/copyright.html
- */
-
-
-#include <limits.h>
-
-#define OPTION_CODE_COMPILE 1
-#include "ntpdsim-opts.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-tSCC zCopyright[] =
- "ntpdsim copyright (c) 1970-2009 David L. Mills and/or others, all rights reserved";
-tSCC zCopyrightNotice[] =
-
-/* extracted from ../include/copyright.def near line 8 */
-"see html/copyright.html";
-extern tUsageProc optionUsage;
-
-/*
- * global included definitions
- */
-#ifdef __windows
- extern int atoi(const char*);
-#else
-# include <stdlib.h>
-#endif
-
-#ifndef NULL
-# define NULL 0
-#endif
-#ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
-#endif
-#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
-#endif
-/*
- * Ipv4 option description:
- */
-tSCC zIpv4Text[] =
- "Force IPv4 DNS name resolution";
-tSCC zIpv4_NAME[] = "IPV4";
-tSCC zIpv4_Name[] = "ipv4";
-#define IPV4_FLAGS (OPTST_DISABLED)
-
-/*
- * Ipv6 option description:
- */
-tSCC zIpv6Text[] =
- "Force IPv6 DNS name resolution";
-tSCC zIpv6_NAME[] = "IPV6";
-tSCC zIpv6_Name[] = "ipv6";
-#define IPV6_FLAGS (OPTST_DISABLED)
-
-/*
- * Authreq option description with
- * "Must also have options" and "Incompatible options":
- */
-tSCC zAuthreqText[] =
- "Require crypto authentication";
-tSCC zAuthreq_NAME[] = "AUTHREQ";
-tSCC zAuthreq_Name[] = "authreq";
-static const int
- aAuthreqCantList[] = {
- INDEX_OPT_AUTHNOREQ, NO_EQUIVALENT };
-#define AUTHREQ_FLAGS (OPTST_DISABLED)
-
-/*
- * Authnoreq option description with
- * "Must also have options" and "Incompatible options":
- */
-tSCC zAuthnoreqText[] =
- "Do not require crypto authentication";
-tSCC zAuthnoreq_NAME[] = "AUTHNOREQ";
-tSCC zAuthnoreq_Name[] = "authnoreq";
-static const int
- aAuthnoreqCantList[] = {
- INDEX_OPT_AUTHREQ, NO_EQUIVALENT };
-#define AUTHNOREQ_FLAGS (OPTST_DISABLED)
-
-/*
- * Bcastsync option description:
- */
-tSCC zBcastsyncText[] =
- "Allow us to sync to broadcast servers";
-tSCC zBcastsync_NAME[] = "BCASTSYNC";
-tSCC zBcastsync_Name[] = "bcastsync";
-#define BCASTSYNC_FLAGS (OPTST_DISABLED)
-
-/*
- * Simbroadcastdelay option description:
- */
-tSCC zSimbroadcastdelayText[] =
- "Simulator broadcast delay";
-tSCC zSimbroadcastdelay_NAME[] = "SIMBROADCASTDELAY";
-tSCC zSimbroadcastdelay_Name[] = "simbroadcastdelay";
-#define SIMBROADCASTDELAY_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Configfile option description:
- */
-tSCC zConfigfileText[] =
- "configuration file name";
-tSCC zConfigfile_NAME[] = "CONFIGFILE";
-tSCC zConfigfile_Name[] = "configfile";
-#define CONFIGFILE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Phasenoise option description:
- */
-tSCC zPhasenoiseText[] =
- "Phase noise level";
-tSCC zPhasenoise_NAME[] = "PHASENOISE";
-tSCC zPhasenoise_Name[] = "phasenoise";
-#define PHASENOISE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Debug_Level option description:
- */
-#ifdef DEBUG
-tSCC zDebug_LevelText[] =
- "Increase output debug message level";
-tSCC zDebug_Level_NAME[] = "DEBUG_LEVEL";
-tSCC zDebug_Level_Name[] = "debug-level";
-#define DEBUG_LEVEL_FLAGS (OPTST_DISABLED)
-
-#else /* disable Debug_Level */
-#define VALUE_OPT_DEBUG_LEVEL NO_EQUIVALENT
-#define DEBUG_LEVEL_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
-#define zDebug_LevelText NULL
-#define zDebug_Level_NAME NULL
-#define zDebug_Level_Name NULL
-#endif /* DEBUG */
-
-/*
- * Set_Debug_Level option description:
- */
-#ifdef DEBUG
-tSCC zSet_Debug_LevelText[] =
- "Set the output debug message level";
-tSCC zSet_Debug_Level_NAME[] = "SET_DEBUG_LEVEL";
-tSCC zSet_Debug_Level_Name[] = "set-debug-level";
-#define SET_DEBUG_LEVEL_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-#else /* disable Set_Debug_Level */
-#define VALUE_OPT_SET_DEBUG_LEVEL NO_EQUIVALENT
-#define SET_DEBUG_LEVEL_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
-#define zSet_Debug_LevelText NULL
-#define zSet_Debug_Level_NAME NULL
-#define zSet_Debug_Level_Name NULL
-#endif /* DEBUG */
-
-/*
- * Driftfile option description:
- */
-tSCC zDriftfileText[] =
- "frequency drift file name";
-tSCC zDriftfile_NAME[] = "DRIFTFILE";
-tSCC zDriftfile_Name[] = "driftfile";
-#define DRIFTFILE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Panicgate option description:
- */
-tSCC zPanicgateText[] =
- "Allow the first adjustment to be Big";
-tSCC zPanicgate_NAME[] = "PANICGATE";
-tSCC zPanicgate_Name[] = "panicgate";
-#define PANICGATE_FLAGS (OPTST_DISABLED)
-
-/*
- * Simslew option description:
- */
-tSCC zSimslewText[] =
- "Simuator slew";
-tSCC zSimslew_NAME[] = "SIMSLEW";
-tSCC zSimslew_Name[] = "simslew";
-#define SIMSLEW_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Jaildir option description:
- */
-tSCC zJaildirText[] =
- "Jail directory";
-tSCC zJaildir_NAME[] = "JAILDIR";
-tSCC zJaildir_Name[] = "jaildir";
-#define JAILDIR_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Interface option description:
- */
-tSCC zInterfaceText[] =
- "Listen on interface";
-tSCC zInterface_NAME[] = "INTERFACE";
-tSCC zInterface_Name[] = "interface";
-#define INTERFACE_FLAGS (OPTST_DISABLED | OPTST_STACKED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Keyfile option description:
- */
-tSCC zKeyfileText[] =
- "path to symmetric keys";
-tSCC zKeyfile_NAME[] = "KEYFILE";
-tSCC zKeyfile_Name[] = "keyfile";
-#define KEYFILE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Logfile option description:
- */
-tSCC zLogfileText[] =
- "path to the log file";
-tSCC zLogfile_NAME[] = "LOGFILE";
-tSCC zLogfile_Name[] = "logfile";
-#define LOGFILE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Novirtualips option description:
- */
-tSCC zNovirtualipsText[] =
- "Do not listen to virtual IPs";
-tSCC zNovirtualips_NAME[] = "NOVIRTUALIPS";
-tSCC zNovirtualips_Name[] = "novirtualips";
-#define NOVIRTUALIPS_FLAGS (OPTST_DISABLED)
-
-/*
- * Modifymmtimer option description:
- */
-#ifdef SYS_WINNT
-tSCC zModifymmtimerText[] =
- "Modify Multimedia Timer (Windows only)";
-tSCC zModifymmtimer_NAME[] = "MODIFYMMTIMER";
-tSCC zModifymmtimer_Name[] = "modifymmtimer";
-#define MODIFYMMTIMER_FLAGS (OPTST_DISABLED)
-
-#else /* disable Modifymmtimer */
-#define VALUE_OPT_MODIFYMMTIMER NO_EQUIVALENT
-#define MODIFYMMTIMER_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
-#define zModifymmtimerText NULL
-#define zModifymmtimer_NAME NULL
-#define zModifymmtimer_Name NULL
-#endif /* SYS_WINNT */
-
-/*
- * Nofork option description:
- */
-tSCC zNoforkText[] =
- "Do not fork";
-tSCC zNofork_NAME[] = "NOFORK";
-tSCC zNofork_Name[] = "nofork";
-#define NOFORK_FLAGS (OPTST_DISABLED)
-
-/*
- * Nice option description:
- */
-tSCC zNiceText[] =
- "Run at high priority";
-tSCC zNice_NAME[] = "NICE";
-tSCC zNice_Name[] = "nice";
-#define NICE_FLAGS (OPTST_DISABLED)
-
-/*
- * Servertime option description:
- */
-tSCC zServertimeText[] =
- "Server time";
-tSCC zServertime_NAME[] = "SERVERTIME";
-tSCC zServertime_Name[] = "servertime";
-#define SERVERTIME_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Pidfile option description:
- */
-tSCC zPidfileText[] =
- "path to the PID file";
-tSCC zPidfile_NAME[] = "PIDFILE";
-tSCC zPidfile_Name[] = "pidfile";
-#define PIDFILE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Priority option description:
- */
-tSCC zPriorityText[] =
- "Process priority";
-tSCC zPriority_NAME[] = "PRIORITY";
-tSCC zPriority_Name[] = "priority";
-#define PRIORITY_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
-
-/*
- * Quit option description:
- */
-tSCC zQuitText[] =
- "Set the time and quit";
-tSCC zQuit_NAME[] = "QUIT";
-tSCC zQuit_Name[] = "quit";
-#define QUIT_FLAGS (OPTST_DISABLED)
-
-/*
- * Propagationdelay option description:
- */
-tSCC zPropagationdelayText[] =
- "Broadcast/propagation delay";
-tSCC zPropagationdelay_NAME[] = "PROPAGATIONDELAY";
-tSCC zPropagationdelay_Name[] = "propagationdelay";
-#define PROPAGATIONDELAY_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Updateinterval option description:
- */
-tSCC zUpdateintervalText[] =
- "interval in seconds between scans for new or dropped interfaces";
-tSCC zUpdateinterval_NAME[] = "UPDATEINTERVAL";
-tSCC zUpdateinterval_Name[] = "updateinterval";
-#define UPDATEINTERVAL_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
-
-/*
- * Statsdir option description:
- */
-tSCC zStatsdirText[] =
- "Statistics file location";
-tSCC zStatsdir_NAME[] = "STATSDIR";
-tSCC zStatsdir_Name[] = "statsdir";
-#define STATSDIR_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Endsimtime option description:
- */
-tSCC zEndsimtimeText[] =
- "Simulation end time";
-tSCC zEndsimtime_NAME[] = "ENDSIMTIME";
-tSCC zEndsimtime_Name[] = "endsimtime";
-#define ENDSIMTIME_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Trustedkey option description:
- */
-tSCC zTrustedkeyText[] =
- "Trusted key number";
-tSCC zTrustedkey_NAME[] = "TRUSTEDKEY";
-tSCC zTrustedkey_Name[] = "trustedkey";
-#define TRUSTEDKEY_FLAGS (OPTST_DISABLED | OPTST_STACKED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Freqerr option description:
- */
-tSCC zFreqerrText[] =
- "Simulation frequency error";
-tSCC zFreqerr_NAME[] = "FREQERR";
-tSCC zFreqerr_Name[] = "freqerr";
-#define FREQERR_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Walknoise option description:
- */
-tSCC zWalknoiseText[] =
- "Simulation random walk noise";
-tSCC zWalknoise_NAME[] = "WALKNOISE";
-tSCC zWalknoise_Name[] = "walknoise";
-#define WALKNOISE_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * User option description:
- */
-tSCC zUserText[] =
- "Run as userid (or userid:groupid)";
-tSCC zUser_NAME[] = "USER";
-tSCC zUser_Name[] = "user";
-#define USER_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Var option description:
- */
-tSCC zVarText[] =
- "make ARG an ntp variable (RW)";
-tSCC zVar_NAME[] = "VAR";
-tSCC zVar_Name[] = "var";
-#define VAR_FLAGS (OPTST_DISABLED | OPTST_STACKED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Dvar option description:
- */
-tSCC zDvarText[] =
- "make ARG an ntp variable (RW|DEF)";
-tSCC zDvar_NAME[] = "DVAR";
-tSCC zDvar_Name[] = "dvar";
-#define DVAR_FLAGS (OPTST_DISABLED | OPTST_STACKED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Slew option description:
- */
-tSCC zSlewText[] =
- "Slew up to 600 seconds";
-tSCC zSlew_NAME[] = "SLEW";
-tSCC zSlew_Name[] = "slew";
-#define SLEW_FLAGS (OPTST_DISABLED)
-
-/*
- * Ndelay option description:
- */
-tSCC zNdelayText[] =
- "Simulation network delay";
-tSCC zNdelay_NAME[] = "NDELAY";
-tSCC zNdelay_Name[] = "ndelay";
-#define NDELAY_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Pdelay option description:
- */
-tSCC zPdelayText[] =
- "Simulation processing delay";
-tSCC zPdelay_NAME[] = "PDELAY";
-tSCC zPdelay_Name[] = "pdelay";
-#define PDELAY_FLAGS (OPTST_DISABLED \
- | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
-
-/*
- * Help/More_Help/Version option descriptions:
- */
-tSCC zHelpText[] = "Display usage information and exit";
-tSCC zHelp_Name[] = "help";
-
-tSCC zMore_HelpText[] = "Extended usage information passed thru pager";
-tSCC zMore_Help_Name[] = "more-help";
-
-tSCC zVersionText[] = "Output version information and exit";
-tSCC zVersion_Name[] = "version";
-
-/*
- * Save/Load_Opts option description:
- */
-tSCC zSave_OptsText[] = "Save the option state to a config file";
-tSCC zSave_Opts_Name[] = "save-opts";
-
-tSCC zLoad_OptsText[] = "Load options from a config file";
-tSCC zLoad_Opts_NAME[] = "LOAD_OPTS";
-
-tSCC zNotLoad_Opts_Name[] = "no-load-opts";
-tSCC zNotLoad_Opts_Pfx[] = "no";
-#define zLoad_Opts_Name (zNotLoad_Opts_Name + 3)
-/*
- * Declare option callback procedures
- */
-#ifdef DEBUG
- static tOptProc doOptSet_Debug_Level;
-#else /* not DEBUG */
-# define doOptSet_Debug_Level NULL
-#endif /* def/not DEBUG */
-#if defined(TEST_NTPDSIM_OPTS)
-/*
- * Under test, omit argument processing, or call optionStackArg,
- * if multiple copies are allowed.
- */
-extern tOptProc
- optionNumericVal, optionPagedUsage, optionStackArg,
- optionVersionStderr;
-static tOptProc
- doUsageOpt;
-
-/*
- * #define map the "normal" callout procs to the test ones...
- */
-#define SET_DEBUG_LEVEL_OPT_PROC optionStackArg
-
-
-#else /* NOT defined TEST_NTPDSIM_OPTS */
-/*
- * When not under test, there are different procs to use
- */
-extern tOptProc
- optionNumericVal, optionPagedUsage, optionPrintVersion, optionStackArg;
-static tOptProc
- doUsageOpt;
-
-/*
- * #define map the "normal" callout procs
- */
-#define SET_DEBUG_LEVEL_OPT_PROC doOptSet_Debug_Level
-
-#define SET_DEBUG_LEVEL_OPT_PROC doOptSet_Debug_Level
-#endif /* defined(TEST_NTPDSIM_OPTS) */
-#ifdef TEST_NTPDSIM_OPTS
-# define DOVERPROC optionVersionStderr
-#else
-# define DOVERPROC optionPrintVersion
-#endif /* TEST_NTPDSIM_OPTS */
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Define the Ntpdsim Option Descriptions.
- */
-static tOptDesc optDesc[ OPTION_CT ] = {
- { /* entry idx, value */ 0, VALUE_OPT_IPV4,
- /* equiv idx, value */ NO_EQUIVALENT, 0,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ IPV4_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zIpv4Text, zIpv4_NAME, zIpv4_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 1, VALUE_OPT_IPV6,
- /* equiv idx, value */ NOLIMIT, NOLIMIT,
- /* equivalenced to */ INDEX_OPT_IPV4,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ IPV6_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zIpv6Text, zIpv6_NAME, zIpv6_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 2, VALUE_OPT_AUTHREQ,
- /* equiv idx, value */ 2, VALUE_OPT_AUTHREQ,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ AUTHREQ_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, aAuthreqCantList,
- /* option proc */ NULL,
- /* desc, NAME, name */ zAuthreqText, zAuthreq_NAME, zAuthreq_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 3, VALUE_OPT_AUTHNOREQ,
- /* equiv idx, value */ 3, VALUE_OPT_AUTHNOREQ,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ AUTHNOREQ_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, aAuthnoreqCantList,
- /* option proc */ NULL,
- /* desc, NAME, name */ zAuthnoreqText, zAuthnoreq_NAME, zAuthnoreq_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 4, VALUE_OPT_BCASTSYNC,
- /* equiv idx, value */ 4, VALUE_OPT_BCASTSYNC,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ BCASTSYNC_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zBcastsyncText, zBcastsync_NAME, zBcastsync_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 5, VALUE_OPT_SIMBROADCASTDELAY,
- /* equiv idx, value */ 5, VALUE_OPT_SIMBROADCASTDELAY,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ SIMBROADCASTDELAY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zSimbroadcastdelayText, zSimbroadcastdelay_NAME, zSimbroadcastdelay_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 6, VALUE_OPT_CONFIGFILE,
- /* equiv idx, value */ 6, VALUE_OPT_CONFIGFILE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ CONFIGFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zConfigfileText, zConfigfile_NAME, zConfigfile_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 7, VALUE_OPT_PHASENOISE,
- /* equiv idx, value */ 7, VALUE_OPT_PHASENOISE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ PHASENOISE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zPhasenoiseText, zPhasenoise_NAME, zPhasenoise_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 8, VALUE_OPT_DEBUG_LEVEL,
- /* equiv idx, value */ 8, VALUE_OPT_DEBUG_LEVEL,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ DEBUG_LEVEL_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zDebug_LevelText, zDebug_Level_NAME, zDebug_Level_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 9, VALUE_OPT_SET_DEBUG_LEVEL,
- /* equiv idx, value */ 9, VALUE_OPT_SET_DEBUG_LEVEL,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ SET_DEBUG_LEVEL_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ SET_DEBUG_LEVEL_OPT_PROC,
- /* desc, NAME, name */ zSet_Debug_LevelText, zSet_Debug_Level_NAME, zSet_Debug_Level_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 10, VALUE_OPT_DRIFTFILE,
- /* equiv idx, value */ 10, VALUE_OPT_DRIFTFILE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ DRIFTFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zDriftfileText, zDriftfile_NAME, zDriftfile_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 11, VALUE_OPT_PANICGATE,
- /* equiv idx, value */ 11, VALUE_OPT_PANICGATE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ PANICGATE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zPanicgateText, zPanicgate_NAME, zPanicgate_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 12, VALUE_OPT_SIMSLEW,
- /* equiv idx, value */ 12, VALUE_OPT_SIMSLEW,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ SIMSLEW_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zSimslewText, zSimslew_NAME, zSimslew_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 13, VALUE_OPT_JAILDIR,
- /* equiv idx, value */ 13, VALUE_OPT_JAILDIR,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ JAILDIR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zJaildirText, zJaildir_NAME, zJaildir_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 14, VALUE_OPT_INTERFACE,
- /* equiv idx, value */ 14, VALUE_OPT_INTERFACE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ INTERFACE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionStackArg,
- /* desc, NAME, name */ zInterfaceText, zInterface_NAME, zInterface_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 15, VALUE_OPT_KEYFILE,
- /* equiv idx, value */ 15, VALUE_OPT_KEYFILE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ KEYFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zKeyfileText, zKeyfile_NAME, zKeyfile_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 16, VALUE_OPT_LOGFILE,
- /* equiv idx, value */ 16, VALUE_OPT_LOGFILE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ LOGFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zLogfileText, zLogfile_NAME, zLogfile_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 17, VALUE_OPT_NOVIRTUALIPS,
- /* equiv idx, value */ 17, VALUE_OPT_NOVIRTUALIPS,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ NOVIRTUALIPS_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zNovirtualipsText, zNovirtualips_NAME, zNovirtualips_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 18, VALUE_OPT_MODIFYMMTIMER,
- /* equiv idx, value */ 18, VALUE_OPT_MODIFYMMTIMER,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ MODIFYMMTIMER_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zModifymmtimerText, zModifymmtimer_NAME, zModifymmtimer_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 19, VALUE_OPT_NOFORK,
- /* equiv idx, value */ 19, VALUE_OPT_NOFORK,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ NOFORK_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zNoforkText, zNofork_NAME, zNofork_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 20, VALUE_OPT_NICE,
- /* equiv idx, value */ 20, VALUE_OPT_NICE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ NICE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zNiceText, zNice_NAME, zNice_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 21, VALUE_OPT_SERVERTIME,
- /* equiv idx, value */ 21, VALUE_OPT_SERVERTIME,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ SERVERTIME_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zServertimeText, zServertime_NAME, zServertime_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 22, VALUE_OPT_PIDFILE,
- /* equiv idx, value */ 22, VALUE_OPT_PIDFILE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ PIDFILE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zPidfileText, zPidfile_NAME, zPidfile_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 23, VALUE_OPT_PRIORITY,
- /* equiv idx, value */ 23, VALUE_OPT_PRIORITY,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ PRIORITY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionNumericVal,
- /* desc, NAME, name */ zPriorityText, zPriority_NAME, zPriority_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 24, VALUE_OPT_QUIT,
- /* equiv idx, value */ 24, VALUE_OPT_QUIT,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ QUIT_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zQuitText, zQuit_NAME, zQuit_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 25, VALUE_OPT_PROPAGATIONDELAY,
- /* equiv idx, value */ 25, VALUE_OPT_PROPAGATIONDELAY,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ PROPAGATIONDELAY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zPropagationdelayText, zPropagationdelay_NAME, zPropagationdelay_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 26, VALUE_OPT_UPDATEINTERVAL,
- /* equiv idx, value */ 26, VALUE_OPT_UPDATEINTERVAL,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ UPDATEINTERVAL_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionNumericVal,
- /* desc, NAME, name */ zUpdateintervalText, zUpdateinterval_NAME, zUpdateinterval_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 27, VALUE_OPT_STATSDIR,
- /* equiv idx, value */ 27, VALUE_OPT_STATSDIR,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ STATSDIR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zStatsdirText, zStatsdir_NAME, zStatsdir_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 28, VALUE_OPT_ENDSIMTIME,
- /* equiv idx, value */ 28, VALUE_OPT_ENDSIMTIME,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ ENDSIMTIME_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zEndsimtimeText, zEndsimtime_NAME, zEndsimtime_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 29, VALUE_OPT_TRUSTEDKEY,
- /* equiv idx, value */ 29, VALUE_OPT_TRUSTEDKEY,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ TRUSTEDKEY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionStackArg,
- /* desc, NAME, name */ zTrustedkeyText, zTrustedkey_NAME, zTrustedkey_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 30, VALUE_OPT_FREQERR,
- /* equiv idx, value */ 30, VALUE_OPT_FREQERR,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ FREQERR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zFreqerrText, zFreqerr_NAME, zFreqerr_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 31, VALUE_OPT_WALKNOISE,
- /* equiv idx, value */ 31, VALUE_OPT_WALKNOISE,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ WALKNOISE_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zWalknoiseText, zWalknoise_NAME, zWalknoise_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 32, VALUE_OPT_USER,
- /* equiv idx, value */ 32, VALUE_OPT_USER,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ USER_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zUserText, zUser_NAME, zUser_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 33, VALUE_OPT_VAR,
- /* equiv idx, value */ 33, VALUE_OPT_VAR,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ VAR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionStackArg,
- /* desc, NAME, name */ zVarText, zVar_NAME, zVar_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 34, VALUE_OPT_DVAR,
- /* equiv idx, value */ 34, VALUE_OPT_DVAR,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ DVAR_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionStackArg,
- /* desc, NAME, name */ zDvarText, zDvar_NAME, zDvar_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 35, VALUE_OPT_SLEW,
- /* equiv idx, value */ 35, VALUE_OPT_SLEW,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ SLEW_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zSlewText, zSlew_NAME, zSlew_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 36, VALUE_OPT_NDELAY,
- /* equiv idx, value */ 36, VALUE_OPT_NDELAY,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ NDELAY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zNdelayText, zNdelay_NAME, zNdelay_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ 37, VALUE_OPT_PDELAY,
- /* equiv idx, value */ 37, VALUE_OPT_PDELAY,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ PDELAY_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zPdelayText, zPdelay_NAME, zPdelay_Name,
- /* disablement strs */ NULL, NULL },
-
-#ifdef NO_OPTIONAL_OPT_ARGS
-# define VERSION_OPT_FLAGS OPTST_IMM | OPTST_NO_INIT
-#else
-# define VERSION_OPT_FLAGS OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \
- OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT
-#endif
-
- { /* entry idx, value */ INDEX_OPT_VERSION, VALUE_OPT_VERSION,
- /* equiv idx value */ NO_EQUIVALENT, 0,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ VERSION_OPT_FLAGS, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ DOVERPROC,
- /* desc, NAME, name */ zVersionText, NULL, zVersion_Name,
- /* disablement strs */ NULL, NULL },
-
-#undef VERSION_OPT_FLAGS
-
-
- { /* entry idx, value */ INDEX_OPT_HELP, VALUE_OPT_HELP,
- /* equiv idx value */ NO_EQUIVALENT, 0,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ OPTST_IMM | OPTST_NO_INIT, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ doUsageOpt,
- /* desc, NAME, name */ zHelpText, NULL, zHelp_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ INDEX_OPT_MORE_HELP, VALUE_OPT_MORE_HELP,
- /* equiv idx value */ NO_EQUIVALENT, 0,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ OPTST_IMM | OPTST_NO_INIT, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionPagedUsage,
- /* desc, NAME, name */ zMore_HelpText, NULL, zMore_Help_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ INDEX_OPT_SAVE_OPTS, VALUE_OPT_SAVE_OPTS,
- /* equiv idx value */ NO_EQUIVALENT, 0,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, 1, 0,
- /* opt state flags */ OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)
- | OPTST_ARG_OPTIONAL | OPTST_NO_INIT, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ NULL,
- /* desc, NAME, name */ zSave_OptsText, NULL, zSave_Opts_Name,
- /* disablement strs */ NULL, NULL },
-
- { /* entry idx, value */ INDEX_OPT_LOAD_OPTS, VALUE_OPT_LOAD_OPTS,
- /* equiv idx value */ NO_EQUIVALENT, 0,
- /* equivalenced to */ NO_EQUIVALENT,
- /* min, max, act ct */ 0, NOLIMIT, 0,
- /* opt state flags */ OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) \
- | OPTST_DISABLE_IMM, 0,
- /* last opt argumnt */ { NULL },
- /* arg list/cookie */ NULL,
- /* must/cannot opts */ NULL, NULL,
- /* option proc */ optionLoadOpt,
- /* desc, NAME, name */ zLoad_OptsText, zLoad_Opts_NAME, zLoad_Opts_Name,
- /* disablement strs */ zNotLoad_Opts_Name, zNotLoad_Opts_Pfx }
-};
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Define the Ntpdsim Option Environment
- */
-tSCC zPROGNAME[] = "NTPDSIM";
-tSCC zUsageTitle[] =
-"ntpdsim - NTP daemon simulation program - Ver. 4.2.4p8\n\
-USAGE: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n";
-tSCC zRcName[] = ".ntprc";
-tSCC* apzHomeList[] = {
- "$HOME",
- ".",
- NULL };
-
-tSCC zBugsAddr[] = "http://bugs.ntp.org, bugs@ntp.org";
-#define zExplain NULL
-tSCC zDetail[] = "\n\n";
-tSCC zFullVersion[] = NTPDSIM_FULL_VERSION;
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/optcode.tpl near line 408 */
-
-#if defined(ENABLE_NLS)
-# define OPTPROC_BASE OPTPROC_TRANSLATE
- static tOptionXlateProc translate_option_strings;
-#else
-# define OPTPROC_BASE OPTPROC_NONE
-# define translate_option_strings NULL
-#endif /* ENABLE_NLS */
-
-tOptions ntpdsimOptions = {
- OPTIONS_STRUCT_VERSION,
- 0, NULL, /* original argc + argv */
- ( OPTPROC_BASE
- + OPTPROC_ERRSTOP
- + OPTPROC_SHORTOPT
- + OPTPROC_LONGOPT
- + OPTPROC_NO_REQ_OPT
- + OPTPROC_ENVIRON
- + OPTPROC_NO_ARGS
- + OPTPROC_HAS_IMMED ),
- 0, NULL, /* current option index, current option */
- NULL, NULL, zPROGNAME,
- zRcName, zCopyright, zCopyrightNotice,
- zFullVersion, apzHomeList, zUsageTitle,
- zExplain, zDetail, optDesc,
- zBugsAddr, /* address to send bugs to */
- NULL, NULL, /* extensions/saved state */
- optionUsage, /* usage procedure */
- translate_option_strings, /* translation procedure */
- /*
- * Indexes to special options
- */
- { INDEX_OPT_MORE_HELP,
- INDEX_OPT_SAVE_OPTS,
- NO_EQUIVALENT /* index of '-#' option */,
- NO_EQUIVALENT /* index of default opt */
- },
- 43 /* full option count */, 38 /* user option count */
-};
-
-/*
- * Create the static procedure(s) declared above.
- */
-static void
-doUsageOpt(
- tOptions* pOptions,
- tOptDesc* pOptDesc )
-{
- USAGE( EXIT_SUCCESS );
-}
-
-#if ! defined(TEST_NTPDSIM_OPTS)
-
-/* * * * * * *
- *
- * For the set-debug-level option, when DEBUG is #define-d.
- */
-#ifdef DEBUG
-static void
-doOptSet_Debug_Level(
- tOptions* pOptions,
- tOptDesc* pOptDesc )
-{
- /* extracted from ../include/debug-opt.def, line 29 */
-DESC(DEBUG_LEVEL).optOccCt = atoi( pOptDesc->pzLastArg );
-}
-#endif /* defined DEBUG */
-
-#endif /* defined(TEST_NTPDSIM_OPTS) */
-
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/optmain.tpl near line 92 */
-
-#if defined(TEST_NTPDSIM_OPTS) /* TEST MAIN PROCEDURE: */
-
-int
-main( int argc, char** argv )
-{
- int res = EXIT_SUCCESS;
- (void)optionProcess( &ntpdsimOptions, argc, argv );
- {
- void optionPutShell( tOptions* );
- optionPutShell( &ntpdsimOptions );
- }
- return res;
-}
-#endif /* defined TEST_NTPDSIM_OPTS */
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/optcode.tpl near line 514 */
-
-#if ENABLE_NLS
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <autoopts/usage-txt.h>
-
-static char* AO_gettext( char const* pz );
-static void coerce_it(void** s);
-
-static char*
-AO_gettext( char const* pz )
-{
- char* pzRes;
- if (pz == NULL)
- return NULL;
- pzRes = _(pz);
- if (pzRes == pz)
- return pzRes;
- pzRes = strdup( pzRes );
- if (pzRes == NULL) {
- fputs( _("No memory for duping translated strings\n"), stderr );
- exit( EXIT_FAILURE );
- }
- return pzRes;
-}
-
-static void coerce_it(void** s) { *s = AO_gettext(*s); }
-#define COERSION(_f) \
- coerce_it((void*)&(ntpdsimOptions._f))
-
-/*
- * This invokes the translation code (e.g. gettext(3)).
- */
-static void
-translate_option_strings( void )
-{
- /*
- * Guard against re-translation. It won't work. The strings will have
- * been changed by the first pass through this code. One shot only.
- */
- if (option_usage_text.field_ct == 0)
- return;
- /*
- * Do the translations. The first pointer follows the field count field.
- * The field count field is the size of a pointer.
- */
- {
- char** ppz = (char**)(void*)&(option_usage_text);
- int ix = option_usage_text.field_ct;
-
- do {
- ppz++;
- *ppz = AO_gettext(*ppz);
- } while (--ix > 0);
- }
- option_usage_text.field_ct = 0;
-
- {
- tOptDesc* pOD = ntpdsimOptions.pOptDesc;
- int ix = ntpdsimOptions.optCt;
-
- for (;;) {
- pOD->pzText = AO_gettext(pOD->pzText);
- pOD->pz_NAME = AO_gettext(pOD->pz_NAME);
- pOD->pz_Name = AO_gettext(pOD->pz_Name);
- pOD->pz_DisableName = AO_gettext(pOD->pz_DisableName);
- pOD->pz_DisablePfx = AO_gettext(pOD->pz_DisablePfx);
- if (--ix <= 0)
- break;
- pOD++;
- }
- }
- COERSION(pzCopyright);
- COERSION(pzCopyNotice);
- COERSION(pzFullVersion);
- COERSION(pzUsageTitle);
- COERSION(pzExplain);
- COERSION(pzDetail);
-}
-
-#endif /* ENABLE_NLS */
-
-#ifdef __cplusplus
-}
-#endif
-/* ntpdsim-opts.c ends here */
diff --git a/contrib/ntp/ntpd/ntpdsim-opts.def b/contrib/ntp/ntpd/ntpdsim-opts.def
deleted file mode 100644
index 093c325..0000000
--- a/contrib/ntp/ntpd/ntpdsim-opts.def
+++ /dev/null
@@ -1,15 +0,0 @@
-/* -*- Mode: Text -*- */
-
-autogen definitions options;
-
-#include copyright.def
-#include homerc.def
-
-prog-name = "ntpdsim";
-prog-title = "NTP daemon simulation program";
-
-#define SIM
-#include ntpdbase-opts.def
-
-detail = <<- _END_DETAIL
- _END_DETAIL;
diff --git a/contrib/ntp/ntpd/ntpdsim-opts.h b/contrib/ntp/ntpd/ntpdsim-opts.h
deleted file mode 100644
index 3458bbf..0000000
--- a/contrib/ntp/ntpd/ntpdsim-opts.h
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * EDIT THIS FILE WITH CAUTION (ntpdsim-opts.h)
- *
- * It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:12 AM EST
- * From the definitions ntpdsim-opts.def
- * and the template file options
- *
- * Generated from AutoOpts 29:0:4 templates.
- */
-
-/*
- * This file was produced by an AutoOpts template. AutoOpts is a
- * copyrighted work. This header file is not encumbered by AutoOpts
- * licensing, but is provided under the licensing terms chosen by the
- * ntpdsim author or copyright holder. AutoOpts is licensed under
- * the terms of the LGPL. The redistributable library (``libopts'') is
- * licensed under the terms of either the LGPL or, at the users discretion,
- * the BSD license. See the AutoOpts and/or libopts sources for details.
- *
- * This source file is copyrighted and licensed under the following terms:
- *
- * ntpdsim copyright 1970-2009 David L. Mills and/or others - all rights reserved
- *
- * see html/copyright.html
- */
-/*
- * This file contains the programmatic interface to the Automated
- * Options generated for the ntpdsim program.
- * These macros are documented in the AutoGen info file in the
- * "AutoOpts" chapter. Please refer to that doc for usage help.
- */
-#ifndef AUTOOPTS_NTPDSIM_OPTS_H_GUARD
-#define AUTOOPTS_NTPDSIM_OPTS_H_GUARD
-#include "config.h"
-#include <autoopts/options.h>
-
-/*
- * Ensure that the library used for compiling this generated header is at
- * least as new as the version current when the header template was released
- * (not counting patch version increments). Also ensure that the oldest
- * tolerable version is at least as old as what was current when the header
- * template was released.
- */
-#define AO_TEMPLATE_VERSION 118784
-#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
- || (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
-# error option template version mismatches autoopts/options.h header
- Choke Me.
-#endif
-
-/*
- * Enumeration of each option:
- */
-typedef enum {
- INDEX_OPT_IPV4 = 0,
- INDEX_OPT_IPV6 = 1,
- INDEX_OPT_AUTHREQ = 2,
- INDEX_OPT_AUTHNOREQ = 3,
- INDEX_OPT_BCASTSYNC = 4,
- INDEX_OPT_SIMBROADCASTDELAY = 5,
- INDEX_OPT_CONFIGFILE = 6,
- INDEX_OPT_PHASENOISE = 7,
- INDEX_OPT_DEBUG_LEVEL = 8,
- INDEX_OPT_SET_DEBUG_LEVEL = 9,
- INDEX_OPT_DRIFTFILE = 10,
- INDEX_OPT_PANICGATE = 11,
- INDEX_OPT_SIMSLEW = 12,
- INDEX_OPT_JAILDIR = 13,
- INDEX_OPT_INTERFACE = 14,
- INDEX_OPT_KEYFILE = 15,
- INDEX_OPT_LOGFILE = 16,
- INDEX_OPT_NOVIRTUALIPS = 17,
- INDEX_OPT_MODIFYMMTIMER = 18,
- INDEX_OPT_NOFORK = 19,
- INDEX_OPT_NICE = 20,
- INDEX_OPT_SERVERTIME = 21,
- INDEX_OPT_PIDFILE = 22,
- INDEX_OPT_PRIORITY = 23,
- INDEX_OPT_QUIT = 24,
- INDEX_OPT_PROPAGATIONDELAY = 25,
- INDEX_OPT_UPDATEINTERVAL = 26,
- INDEX_OPT_STATSDIR = 27,
- INDEX_OPT_ENDSIMTIME = 28,
- INDEX_OPT_TRUSTEDKEY = 29,
- INDEX_OPT_FREQERR = 30,
- INDEX_OPT_WALKNOISE = 31,
- INDEX_OPT_USER = 32,
- INDEX_OPT_VAR = 33,
- INDEX_OPT_DVAR = 34,
- INDEX_OPT_SLEW = 35,
- INDEX_OPT_NDELAY = 36,
- INDEX_OPT_PDELAY = 37,
- INDEX_OPT_VERSION = 38,
- INDEX_OPT_HELP = 39,
- INDEX_OPT_MORE_HELP = 40,
- INDEX_OPT_SAVE_OPTS = 41,
- INDEX_OPT_LOAD_OPTS = 42
-} teOptIndex;
-
-#define OPTION_CT 43
-#define NTPDSIM_VERSION "4.2.4p8"
-#define NTPDSIM_FULL_VERSION "ntpdsim - NTP daemon simulation program - Ver. 4.2.4p8"
-
-/*
- * Interface defines for all options. Replace "n" with the UPPER_CASED
- * option name (as in the teOptIndex enumeration above).
- * e.g. HAVE_OPT( IPV4 )
- */
-#define DESC(n) (ntpdsimOptions.pOptDesc[INDEX_OPT_## n])
-#define HAVE_OPT(n) (! UNUSED_OPT(& DESC(n)))
-#define OPT_ARG(n) (DESC(n).optArg.argString)
-#define STATE_OPT(n) (DESC(n).fOptState & OPTST_SET_MASK)
-#define COUNT_OPT(n) (DESC(n).optOccCt)
-#define ISSEL_OPT(n) (SELECTED_OPT(&DESC(n)))
-#define ISUNUSED_OPT(n) (UNUSED_OPT(& DESC(n)))
-#define ENABLED_OPT(n) (! DISABLED_OPT(& DESC(n)))
-#define STACKCT_OPT(n) (((tArgList*)(DESC(n).optCookie))->useCt)
-#define STACKLST_OPT(n) (((tArgList*)(DESC(n).optCookie))->apzArgs)
-#define CLEAR_OPT(n) STMTS( \
- DESC(n).fOptState &= OPTST_PERSISTENT_MASK; \
- if ( (DESC(n).fOptState & OPTST_INITENABLED) == 0) \
- DESC(n).fOptState |= OPTST_DISABLED; \
- DESC(n).optCookie = NULL )
-
-/*
- * Make sure there are no #define name conflicts with the option names
- */
-#ifndef NO_OPTION_NAME_WARNINGS
-# ifdef IPV4
-# warning undefining IPV4 due to option name conflict
-# undef IPV4
-# endif
-# ifdef IPV6
-# warning undefining IPV6 due to option name conflict
-# undef IPV6
-# endif
-# ifdef AUTHREQ
-# warning undefining AUTHREQ due to option name conflict
-# undef AUTHREQ
-# endif
-# ifdef AUTHNOREQ
-# warning undefining AUTHNOREQ due to option name conflict
-# undef AUTHNOREQ
-# endif
-# ifdef BCASTSYNC
-# warning undefining BCASTSYNC due to option name conflict
-# undef BCASTSYNC
-# endif
-# ifdef SIMBROADCASTDELAY
-# warning undefining SIMBROADCASTDELAY due to option name conflict
-# undef SIMBROADCASTDELAY
-# endif
-# ifdef CONFIGFILE
-# warning undefining CONFIGFILE due to option name conflict
-# undef CONFIGFILE
-# endif
-# ifdef PHASENOISE
-# warning undefining PHASENOISE due to option name conflict
-# undef PHASENOISE
-# endif
-# ifdef DEBUG_LEVEL
-# warning undefining DEBUG_LEVEL due to option name conflict
-# undef DEBUG_LEVEL
-# endif
-# ifdef SET_DEBUG_LEVEL
-# warning undefining SET_DEBUG_LEVEL due to option name conflict
-# undef SET_DEBUG_LEVEL
-# endif
-# ifdef DRIFTFILE
-# warning undefining DRIFTFILE due to option name conflict
-# undef DRIFTFILE
-# endif
-# ifdef PANICGATE
-# warning undefining PANICGATE due to option name conflict
-# undef PANICGATE
-# endif
-# ifdef SIMSLEW
-# warning undefining SIMSLEW due to option name conflict
-# undef SIMSLEW
-# endif
-# ifdef JAILDIR
-# warning undefining JAILDIR due to option name conflict
-# undef JAILDIR
-# endif
-# ifdef INTERFACE
-# warning undefining INTERFACE due to option name conflict
-# undef INTERFACE
-# endif
-# ifdef KEYFILE
-# warning undefining KEYFILE due to option name conflict
-# undef KEYFILE
-# endif
-# ifdef LOGFILE
-# warning undefining LOGFILE due to option name conflict
-# undef LOGFILE
-# endif
-# ifdef NOVIRTUALIPS
-# warning undefining NOVIRTUALIPS due to option name conflict
-# undef NOVIRTUALIPS
-# endif
-# ifdef MODIFYMMTIMER
-# warning undefining MODIFYMMTIMER due to option name conflict
-# undef MODIFYMMTIMER
-# endif
-# ifdef NOFORK
-# warning undefining NOFORK due to option name conflict
-# undef NOFORK
-# endif
-# ifdef NICE
-# warning undefining NICE due to option name conflict
-# undef NICE
-# endif
-# ifdef SERVERTIME
-# warning undefining SERVERTIME due to option name conflict
-# undef SERVERTIME
-# endif
-# ifdef PIDFILE
-# warning undefining PIDFILE due to option name conflict
-# undef PIDFILE
-# endif
-# ifdef PRIORITY
-# warning undefining PRIORITY due to option name conflict
-# undef PRIORITY
-# endif
-# ifdef QUIT
-# warning undefining QUIT due to option name conflict
-# undef QUIT
-# endif
-# ifdef PROPAGATIONDELAY
-# warning undefining PROPAGATIONDELAY due to option name conflict
-# undef PROPAGATIONDELAY
-# endif
-# ifdef UPDATEINTERVAL
-# warning undefining UPDATEINTERVAL due to option name conflict
-# undef UPDATEINTERVAL
-# endif
-# ifdef STATSDIR
-# warning undefining STATSDIR due to option name conflict
-# undef STATSDIR
-# endif
-# ifdef ENDSIMTIME
-# warning undefining ENDSIMTIME due to option name conflict
-# undef ENDSIMTIME
-# endif
-# ifdef TRUSTEDKEY
-# warning undefining TRUSTEDKEY due to option name conflict
-# undef TRUSTEDKEY
-# endif
-# ifdef FREQERR
-# warning undefining FREQERR due to option name conflict
-# undef FREQERR
-# endif
-# ifdef WALKNOISE
-# warning undefining WALKNOISE due to option name conflict
-# undef WALKNOISE
-# endif
-# ifdef USER
-# warning undefining USER due to option name conflict
-# undef USER
-# endif
-# ifdef VAR
-# warning undefining VAR due to option name conflict
-# undef VAR
-# endif
-# ifdef DVAR
-# warning undefining DVAR due to option name conflict
-# undef DVAR
-# endif
-# ifdef SLEW
-# warning undefining SLEW due to option name conflict
-# undef SLEW
-# endif
-# ifdef NDELAY
-# warning undefining NDELAY due to option name conflict
-# undef NDELAY
-# endif
-# ifdef PDELAY
-# warning undefining PDELAY due to option name conflict
-# undef PDELAY
-# endif
-#else /* NO_OPTION_NAME_WARNINGS */
-# undef IPV4
-# undef IPV6
-# undef AUTHREQ
-# undef AUTHNOREQ
-# undef BCASTSYNC
-# undef SIMBROADCASTDELAY
-# undef CONFIGFILE
-# undef PHASENOISE
-# undef DEBUG_LEVEL
-# undef SET_DEBUG_LEVEL
-# undef DRIFTFILE
-# undef PANICGATE
-# undef SIMSLEW
-# undef JAILDIR
-# undef INTERFACE
-# undef KEYFILE
-# undef LOGFILE
-# undef NOVIRTUALIPS
-# undef MODIFYMMTIMER
-# undef NOFORK
-# undef NICE
-# undef SERVERTIME
-# undef PIDFILE
-# undef PRIORITY
-# undef QUIT
-# undef PROPAGATIONDELAY
-# undef UPDATEINTERVAL
-# undef STATSDIR
-# undef ENDSIMTIME
-# undef TRUSTEDKEY
-# undef FREQERR
-# undef WALKNOISE
-# undef USER
-# undef VAR
-# undef DVAR
-# undef SLEW
-# undef NDELAY
-# undef PDELAY
-#endif /* NO_OPTION_NAME_WARNINGS */
-
-/*
- * Interface defines for specific options.
- */
-#define VALUE_OPT_IPV4 '4'
-#define WHICH_OPT_IPV4 (DESC(IPV4).optActualValue)
-#define WHICH_IDX_IPV4 (DESC(IPV4).optActualIndex)
-#define VALUE_OPT_IPV6 '6'
-#define VALUE_OPT_AUTHREQ 'a'
-#define VALUE_OPT_AUTHNOREQ 'A'
-#define VALUE_OPT_BCASTSYNC 'b'
-#define VALUE_OPT_SIMBROADCASTDELAY 'B'
-#define VALUE_OPT_CONFIGFILE 'c'
-#define VALUE_OPT_PHASENOISE 'C'
-#ifdef DEBUG
-#define VALUE_OPT_DEBUG_LEVEL 'd'
-#endif /* DEBUG */
-#ifdef DEBUG
-#define VALUE_OPT_SET_DEBUG_LEVEL 'D'
-#endif /* DEBUG */
-#define VALUE_OPT_DRIFTFILE 'f'
-#define VALUE_OPT_PANICGATE 'g'
-#define VALUE_OPT_SIMSLEW 'H'
-#define VALUE_OPT_JAILDIR 'i'
-#define VALUE_OPT_INTERFACE 'I'
-#define VALUE_OPT_KEYFILE 'k'
-#define VALUE_OPT_LOGFILE 'l'
-#define VALUE_OPT_NOVIRTUALIPS 'L'
-#ifdef SYS_WINNT
-#define VALUE_OPT_MODIFYMMTIMER 'M'
-#endif /* SYS_WINNT */
-#define VALUE_OPT_NOFORK 'n'
-#define VALUE_OPT_NICE 'N'
-#define VALUE_OPT_SERVERTIME 'O'
-#define VALUE_OPT_PIDFILE 'p'
-#define VALUE_OPT_PRIORITY 'P'
-#define OPT_VALUE_PRIORITY (DESC(PRIORITY).optArg.argInt)
-#define VALUE_OPT_QUIT 'q'
-#define VALUE_OPT_PROPAGATIONDELAY 'r'
-#define VALUE_OPT_UPDATEINTERVAL 'U'
-#define OPT_VALUE_UPDATEINTERVAL (DESC(UPDATEINTERVAL).optArg.argInt)
-#define VALUE_OPT_STATSDIR 's'
-#define VALUE_OPT_ENDSIMTIME 'S'
-#define VALUE_OPT_TRUSTEDKEY 't'
-#define VALUE_OPT_FREQERR 'T'
-#define VALUE_OPT_WALKNOISE 'W'
-#define VALUE_OPT_USER 'u'
-#define VALUE_OPT_VAR 'v'
-#define VALUE_OPT_DVAR 'V'
-#define VALUE_OPT_SLEW 'x'
-#define VALUE_OPT_NDELAY 'Y'
-#define VALUE_OPT_PDELAY 'Z'
-
-#define VALUE_OPT_VERSION 'v'
-#define VALUE_OPT_HELP '?'
-#define VALUE_OPT_MORE_HELP '!'
-#define VALUE_OPT_SAVE_OPTS '>'
-#define VALUE_OPT_LOAD_OPTS '<'
-#define SET_OPT_SAVE_OPTS(a) STMTS( \
- DESC(SAVE_OPTS).fOptState &= OPTST_PERSISTENT_MASK; \
- DESC(SAVE_OPTS).fOptState |= OPTST_SET; \
- DESC(SAVE_OPTS).optArg.argString = (char const*)(a) )
-/*
- * Interface defines not associated with particular options
- */
-#define ERRSKIP_OPTERR STMTS( ntpdsimOptions.fOptSet &= ~OPTPROC_ERRSTOP )
-#define ERRSTOP_OPTERR STMTS( ntpdsimOptions.fOptSet |= OPTPROC_ERRSTOP )
-#define RESTART_OPT(n) STMTS( \
- ntpdsimOptions.curOptIdx = (n); \
- ntpdsimOptions.pzCurOpt = NULL )
-#define START_OPT RESTART_OPT(1)
-#define USAGE(c) (*ntpdsimOptions.pUsageProc)( &ntpdsimOptions, c )
-/* extracted from /usr/local/gnu/autogen-5.9.1/share/autogen/opthead.tpl near line 360 */
-
-/* * * * * *
- *
- * Declare the ntpdsim option descriptor.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern tOptions ntpdsimOptions;
-
-#ifndef _
-# if ENABLE_NLS
-# include <stdio.h>
- static inline char* aoGetsText( char const* pz ) {
- if (pz == NULL) return NULL;
- return (char*)gettext( pz );
- }
-# define _(s) aoGetsText(s)
-# else /* ENABLE_NLS */
-# define _(s) s
-# endif /* ENABLE_NLS */
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* AUTOOPTS_NTPDSIM_OPTS_H_GUARD */
-/* ntpdsim-opts.h ends here */
diff --git a/contrib/ntp/ntpd/ntpdsim-opts.menu b/contrib/ntp/ntpd/ntpdsim-opts.menu
deleted file mode 100644
index c787458..0000000
--- a/contrib/ntp/ntpd/ntpdsim-opts.menu
+++ /dev/null
@@ -1 +0,0 @@
-* ntpdsim Invocation:: Invoking ntpdsim
diff --git a/contrib/ntp/ntpd/ntpdsim-opts.texi b/contrib/ntp/ntpd/ntpdsim-opts.texi
deleted file mode 100644
index ed52210..0000000
--- a/contrib/ntp/ntpd/ntpdsim-opts.texi
+++ /dev/null
@@ -1,568 +0,0 @@
-@node ntpdsim Invocation
-@section Invoking ntpdsim
-@pindex ntpdsim
-@cindex NTP daemon simulation program
-@ignore
-#
-# EDIT THIS FILE WITH CAUTION (ntpdsim-opts.texi)
-#
-# It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:15 AM EST
-# From the definitions ntpdsim-opts.def
-# and the template file aginfo.tpl
-@end ignore
-This program has no explanation.
-
-
-
-This section was generated by @strong{AutoGen},
-the aginfo template and the option descriptions for the @command{ntpdsim} program. It documents the ntpdsim usage text and option meanings.
-
-This software is released under a specialized copyright license.
-
-@menu
-* ntpdsim usage:: ntpdsim usage help (-?)
-* ntpdsim authnoreq:: authnoreq option (-A)
-* ntpdsim authreq:: authreq option (-a)
-* ntpdsim bcastsync:: bcastsync option (-b)
-* ntpdsim configfile:: configfile option (-c)
-* ntpdsim debug-level:: debug-level option (-d)
-* ntpdsim driftfile:: driftfile option (-f)
-* ntpdsim dvar:: dvar option (-V)
-* ntpdsim endsimtime:: endsimtime option (-S)
-* ntpdsim freqerr:: freqerr option (-T)
-* ntpdsim interface:: interface option (-I)
-* ntpdsim ipv4:: ipv4 option (-4)
-* ntpdsim ipv6:: ipv6 option (-6)
-* ntpdsim jaildir:: jaildir option (-i)
-* ntpdsim keyfile:: keyfile option (-k)
-* ntpdsim logfile:: logfile option (-l)
-* ntpdsim modifymmtimer:: modifymmtimer option (-M)
-* ntpdsim ndelay:: ndelay option (-Y)
-* ntpdsim nice:: nice option (-N)
-* ntpdsim nofork:: nofork option (-n)
-* ntpdsim novirtualips:: novirtualips option (-L)
-* ntpdsim panicgate:: panicgate option (-g)
-* ntpdsim pdelay:: pdelay option (-Z)
-* ntpdsim phasenoise:: phasenoise option (-C)
-* ntpdsim pidfile:: pidfile option (-p)
-* ntpdsim priority:: priority option (-P)
-* ntpdsim propagationdelay:: propagationdelay option (-r)
-* ntpdsim quit:: quit option (-q)
-* ntpdsim servertime:: servertime option (-O)
-* ntpdsim set-debug-level:: set-debug-level option (-D)
-* ntpdsim simbroadcastdelay:: simbroadcastdelay option (-B)
-* ntpdsim simslew:: simslew option (-H)
-* ntpdsim slew:: slew option (-x)
-* ntpdsim statsdir:: statsdir option (-s)
-* ntpdsim trustedkey:: trustedkey option (-t)
-* ntpdsim updateinterval:: updateinterval option (-U)
-* ntpdsim user:: user option (-u)
-* ntpdsim var:: var option (-v)
-* ntpdsim walknoise:: walknoise option (-W)
-@end menu
-
-@node ntpdsim usage
-@subsection ntpdsim usage help (-?)
-@cindex ntpdsim usage
-
-This is the automatically generated usage text for ntpdsim:
-
-@exampleindent 0
-@example
-ntpd - NTP daemon program - Ver. 4.2.5p247-RC
-USAGE: ntpdsim [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
- Flg Arg Option-Name Description
- -4 no ipv4 Force IPv4 DNS name resolution
- - prohibits these options:
- ipv6
- -6 no ipv6 Force IPv6 DNS name resolution
- - prohibits these options:
- ipv4
- -a no authreq Require crypto authentication
- - prohibits these options:
- authnoreq
- -A no authnoreq Do not require crypto authentication
- - prohibits these options:
- authreq
- -b no bcastsync Allow us to sync to broadcast servers
- -c Str configfile configuration file name
- -d no debug-level Increase output debug message level
- - may appear multiple times
- -D Str set-debug-level Set the output debug message level
- - may appear multiple times
- -f Str driftfile frequency drift file name
- -g no panicgate Allow the first adjustment to be Big
- - may appear multiple times
- -i --- jaildir built without --enable-clockctl or --enable-linuxcaps
- -I Str interface Listen on an interface name or address
- - may appear multiple times
- -k Str keyfile path to symmetric keys
- -l Str logfile path to the log file
- -L no novirtualips Do not listen to virtual interfaces
- -n no nofork Do not fork
- -N no nice Run at high priority
- -p Str pidfile path to the PID file
- -P Num priority Process priority
- -q no quit Set the time and quit
- -r Str propagationdelay Broadcast/propagation delay
- Str saveconfigquit Save parsed configuration and quit
- -s Str statsdir Statistics file location
- -t Str trustedkey Trusted key number
- - may appear multiple times
- -u --- user built without --enable-clockctl or --enable-linuxcaps
- -U Num updateinterval interval in seconds between scans for new or dropped interfaces
- Str var make ARG an ntp variable (RW)
- - may appear multiple times
- Str dvar make ARG an ntp variable (RW|DEF)
- - may appear multiple times
- -x no slew Slew up to 600 seconds
- opt version Output version information and exit
- -? no help Display extended usage information and exit
- -! no more-help Extended usage information passed thru pager
-
-Options are specified by doubled hyphens and their name
-or by a single hyphen and the flag character.
-
-The following option preset mechanisms are supported:
- - examining environment variables named NTPD_*
-
-
-
-please send bug reports to: http://bugs.ntp.org, bugs@@ntp.org
-@end example
-@exampleindent 4
-
-@node ntpdsim ipv4
-@subsection ipv4 option (-4)
-@cindex ntpdsim-ipv4
-
-This is the ``force ipv4 dns name resolution'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-is a member of the ipv4 class of options.
-@end itemize
-
-Force DNS resolution of following host names on the command line
-to the IPv4 namespace.
-
-@node ntpdsim ipv6
-@subsection ipv6 option (-6)
-@cindex ntpdsim-ipv6
-
-This is the ``force ipv6 dns name resolution'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-is a member of the ipv4 class of options.
-@end itemize
-
-Force DNS resolution of following host names on the command line
-to the IPv6 namespace.
-
-@node ntpdsim authreq
-@subsection authreq option (-a)
-@cindex ntpdsim-authreq
-
-This is the ``require crypto authentication'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-must not appear in combination with any of the following options:
-authnoreq.
-@end itemize
-
-Require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is the default.
-
-@node ntpdsim authnoreq
-@subsection authnoreq option (-A)
-@cindex ntpdsim-authnoreq
-
-This is the ``do not require crypto authentication'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-must not appear in combination with any of the following options:
-authreq.
-@end itemize
-
-Do not require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is almost never a good idea.
-
-@node ntpdsim bcastsync
-@subsection bcastsync option (-b)
-@cindex ntpdsim-bcastsync
-
-This is the ``allow us to sync to broadcast servers'' option.
-
-
-@node ntpdsim simbroadcastdelay
-@subsection simbroadcastdelay option (-B)
-@cindex ntpdsim-simbroadcastdelay
-
-This is the ``simulator broadcast delay'' option.
-
-
-@node ntpdsim configfile
-@subsection configfile option (-c)
-@cindex ntpdsim-configfile
-
-This is the ``configuration file name'' option.
-The name and path of the configuration file,
-/etc/ntp.conf
-by default.
-
-@node ntpdsim phasenoise
-@subsection phasenoise option (-C)
-@cindex ntpdsim-phasenoise
-
-This is the ``phase noise level'' option.
-
-
-@node ntpdsim debug-level
-@subsection debug-level option (-d)
-@cindex ntpdsim-debug-level
-
-This is the ``increase output debug message level'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@item
-must be compiled in by defining @code{DEBUG} during the compilation.
-@end itemize
-
-Increase the debugging message output level.
-
-@node ntpdsim set-debug-level
-@subsection set-debug-level option (-D)
-@cindex ntpdsim-set-debug-level
-
-This is the ``set the output debug message level'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@item
-must be compiled in by defining @code{DEBUG} during the compilation.
-@end itemize
-
-Set the output debugging level. Can be supplied multiple times,
-but each overrides the previous value(s).
-
-@node ntpdsim driftfile
-@subsection driftfile option (-f)
-@cindex ntpdsim-driftfile
-
-This is the ``frequency drift file name'' option.
-The name and path of the frequency file,
-/etc/ntp.drift
-by default.
-This is the same operation as the
-driftfile driftfile
-configuration specification in the
-/etc/ntp.conf
-file.
-
-@node ntpdsim panicgate
-@subsection panicgate option (-g)
-@cindex ntpdsim-panicgate
-
-This is the ``allow the first adjustment to be big'' option.
-Normally,
-ntpd
-exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
-ntpd
-will exit with a message to the system log. This option can be used with the
--q
-and
--x
-options.
-See the
-tinker
-configuration file directive for other options.
-
-@node ntpdsim simslew
-@subsection simslew option (-H)
-@cindex ntpdsim-simslew
-
-This is the ``simuator slew'' option.
-
-
-@node ntpdsim jaildir
-@subsection jaildir option (-i)
-@cindex ntpdsim-jaildir
-
-This is the ``jail directory'' option.
-Chroot the server to the directory
-jaildir
-.
-This option also implies that the server attempts to drop root privileges at startup (otherwise, chroot gives very little additional security), and it is only available if the OS supports to run the server without full root privileges.
-You may need to also specify a
--u
-option.
-
-@node ntpdsim interface
-@subsection interface option (-I)
-@cindex ntpdsim-interface
-
-This is the ``listen on interface'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-
-
-@node ntpdsim keyfile
-@subsection keyfile option (-k)
-@cindex ntpdsim-keyfile
-
-This is the ``path to symmetric keys'' option.
-Specify the name and path of the symmetric key file.
-/etc/ntp.keys
-is the default.
-This is the same operation as the
-keys keyfile
-configuration file directive.
-
-@node ntpdsim logfile
-@subsection logfile option (-l)
-@cindex ntpdsim-logfile
-
-This is the ``path to the log file'' option.
-Specify the name and path of the log file.
-The default is the system log file.
-This is the same operation as the
-logfile logfile
-configuration file directive.
-
-@node ntpdsim novirtualips
-@subsection novirtualips option (-L)
-@cindex ntpdsim-novirtualips
-
-This is the ``do not listen to virtual ips'' option.
-Do not listen to virtual IPs. The default is to listen.
-
-@node ntpdsim modifymmtimer
-@subsection modifymmtimer option (-M)
-@cindex ntpdsim-modifymmtimer
-
-This is the ``modify multimedia timer (windows only)'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-must be compiled in by defining @code{SYS_WINNT} during the compilation.
-@end itemize
-
-Set the Windows Multimedia Timer to highest resolution.
-
-@node ntpdsim nofork
-@subsection nofork option (-n)
-@cindex ntpdsim-nofork
-
-This is the ``do not fork'' option.
-
-
-@node ntpdsim nice
-@subsection nice option (-N)
-@cindex ntpdsim-nice
-
-This is the ``run at high priority'' option.
-To the extent permitted by the operating system, run
-ntpd
-at the highest priority.
-
-@node ntpdsim servertime
-@subsection servertime option (-O)
-@cindex ntpdsim-servertime
-
-This is the ``server time'' option.
-
-
-@node ntpdsim pidfile
-@subsection pidfile option (-p)
-@cindex ntpdsim-pidfile
-
-This is the ``path to the pid file'' option.
-Specify the name and path of the file used to record
-ntpd's
-process ID.
-This is the same operation as the
-pidfile pidfile
-configuration file directive.
-
-@node ntpdsim priority
-@subsection priority option (-P)
-@cindex ntpdsim-priority
-
-This is the ``process priority'' option.
-To the extent permitted by the operating system, run
-ntpd
-at the specified
-sched_setscheduler(SCHED_FIFO)
-priority.
-
-@node ntpdsim quit
-@subsection quit option (-q)
-@cindex ntpdsim-quit
-
-This is the ``set the time and quit'' option.
-ntpd
-will exit just after the first time the clock is set. This behavior mimics that of the
-ntpdate
-program, which is to be retired.
-The
--g
-and
--x
-options can be used with this option.
-Note: The kernel time discipline is disabled with this option.
-
-@node ntpdsim propagationdelay
-@subsection propagationdelay option (-r)
-@cindex ntpdsim-propagationdelay
-
-This is the ``broadcast/propagation delay'' option.
-Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
-
-@node ntpdsim updateinterval
-@subsection updateinterval option (-U)
-@cindex ntpdsim-updateinterval
-
-This is the ``interval in seconds between scans for new or dropped interfaces'' option.
-Give the time in seconds between two scans for new or dropped interfaces.
-For systems with routing socket support the scans will be performed shortly after the interface change
-has been detected by the system.
-Use 0 to disable scanning.
-
-@node ntpdsim statsdir
-@subsection statsdir option (-s)
-@cindex ntpdsim-statsdir
-
-This is the ``statistics file location'' option.
-Specify the directory path for files created by the statistics facility.
-This is the same operation as the
-statsdir statsdir
-configuration file directive.
-
-@node ntpdsim endsimtime
-@subsection endsimtime option (-S)
-@cindex ntpdsim-endsimtime
-
-This is the ``simulation end time'' option.
-
-
-@node ntpdsim trustedkey
-@subsection trustedkey option (-t)
-@cindex ntpdsim-trustedkey
-
-This is the ``trusted key number'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-Add a key number to the trusted key list.
-
-@node ntpdsim freqerr
-@subsection freqerr option (-T)
-@cindex ntpdsim-freqerr
-
-This is the ``simulation frequency error'' option.
-
-
-@node ntpdsim walknoise
-@subsection walknoise option (-W)
-@cindex ntpdsim-walknoise
-
-This is the ``simulation random walk noise'' option.
-
-
-@node ntpdsim user
-@subsection user option (-u)
-@cindex ntpdsim-user
-
-This is the ``run as userid (or userid:groupid)'' option.
-Specify a user, and optionally a group, to switch to.
-This option is only available if the OS supports to run the server without full root privileges.
-Currently, this option is supported under NetBSD (configure with
---enable-clockctl
-) and Linux (configure with
---enable-linuxcaps
-).
-
-@node ntpdsim var
-@subsection var option (-v)
-@cindex ntpdsim-var
-
-This is the ``make arg an ntp variable (rw)'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-
-
-@node ntpdsim dvar
-@subsection dvar option (-V)
-@cindex ntpdsim-dvar
-
-This is the ``make arg an ntp variable (rw|def)'' option.
-
-This option has some usage constraints. It:
-@itemize @bullet
-@item
-may appear an unlimited number of times.
-@end itemize
-
-
-
-@node ntpdsim slew
-@subsection slew option (-x)
-@cindex ntpdsim-slew
-
-This is the ``slew up to 600 seconds'' option.
-Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
-This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
-Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
-Thus, an adjustment as much as 600 s will take almost 14 days to complete.
-This option can be used with the
--g
-and
--q
-options.
-See the
-tinker
-configuration file directive for other options.
-Note: The kernel time discipline is disabled with this option.
-
-@node ntpdsim ndelay
-@subsection ndelay option (-Y)
-@cindex ntpdsim-ndelay
-
-This is the ``simulation network delay'' option.
-
-
-@node ntpdsim pdelay
-@subsection pdelay option (-Z)
-@cindex ntpdsim-pdelay
-
-This is the ``simulation processing delay'' option.
-
diff --git a/contrib/ntp/ntpd/ntpdsim.1 b/contrib/ntp/ntpd/ntpdsim.1
deleted file mode 100644
index 2028764..0000000
--- a/contrib/ntp/ntpd/ntpdsim.1
+++ /dev/null
@@ -1,357 +0,0 @@
-.TH NTPDSIM 1 2009-12-08 "( 4.2.4p8)" "Programmer's Manual"
-.\" EDIT THIS FILE WITH CAUTION (ntpdsim.1)
-.\"
-.\" It has been AutoGen-ed Tuesday December 8, 2009 at 08:13:14 AM EST
-.\" From the definitions ntpdsim-opts.def
-.\" and the template file agman1.tpl
-.\"
-.SH NAME
-ntpdsim \- NTP daemon simulation program
-.SH SYNOPSIS
-.B ntpdsim
-.\" Mixture of short (flag) options and long options
-.RB [ \-\fIflag\fP " [\fIvalue\fP]]... [" \--\fIopt-name\fP " [[=| ]\fIvalue\fP]]..."
-.PP
-All arguments must be options.
-.SH "DESCRIPTION"
-This manual page documents, briefly, the \fBntpdsim\fP command.
-
-.SH OPTIONS
-.TP
-.BR \-4 ", " \--ipv4
-Force IPv4 DNS name resolution.
-This option is a member of the ipv4 class of options.
-.sp
-Force DNS resolution of following host names on the command line
-to the IPv4 namespace.
-.TP
-.BR \-6 ", " \--ipv6
-Force IPv6 DNS name resolution.
-This option is a member of the ipv4 class of options.
-.sp
-Force DNS resolution of following host names on the command line
-to the IPv6 namespace.
-.TP
-.BR \-a ", " \--authreq
-Require crypto authentication.
-This option must not appear in combination with any of the following options:
-authnoreq.
-.sp
-Require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is the default.
-.TP
-.BR \-A ", " \--authnoreq
-Do not require crypto authentication.
-This option must not appear in combination with any of the following options:
-authreq.
-.sp
-Do not require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is almost never a good idea.
-.TP
-.BR \-b ", " \--bcastsync
-Allow us to sync to broadcast servers.
-.sp
-
-.TP
-.BR \-B " \fIstring\fP, " \--simbroadcastdelay "=" \fIstring\fP
-Simulator broadcast delay.
-.sp
-
-.TP
-.BR \-c " \fIstring\fP, " \--configfile "=" \fIstring\fP
-configuration file name.
-.sp
-The name and path of the configuration file,
-/etc/ntp.conf
-by default.
-.TP
-.BR \-C " \fIstring\fP, " \--phasenoise "=" \fIstring\fP
-Phase noise level.
-.sp
-
-.TP
-.BR \-d ", " \--debug-level
-Increase output debug message level.
-This option may appear an unlimited number of times.
-.sp
-Increase the debugging message output level.
-.TP
-.BR \-D " \fIstring\fP, " \--set-debug-level "=" \fIstring\fP
-Set the output debug message level.
-This option may appear an unlimited number of times.
-.sp
-Set the output debugging level. Can be supplied multiple times,
-but each overrides the previous value(s).
-.TP
-.BR \-f " \fIstring\fP, " \--driftfile "=" \fIstring\fP
-frequency drift file name.
-.sp
-The name and path of the frequency file,
-/etc/ntp.drift
-by default.
-This is the same operation as the
-driftfile driftfile
-configuration specification in the
-/etc/ntp.conf
-file.
-.TP
-.BR \-g ", " \--panicgate
-Allow the first adjustment to be Big.
-.sp
-Normally,
-ntpd
-exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
-ntpd
-will exit with a message to the system log. This option can be used with the
--q
-and
--x
-options.
-See the
-tinker
-configuration file directive for other options.
-.TP
-.BR \-H " \fIstring\fP, " \--simslew "=" \fIstring\fP
-Simuator slew.
-.sp
-
-.TP
-.BR \-i " \fIstring\fP, " \--jaildir "=" \fIstring\fP
-Jail directory.
-.sp
-Chroot the server to the directory
-jaildir
-.
-This option also implies that the server attempts to drop root privileges at startup (otherwise, chroot gives very little additional security), and it is only available if the OS supports to run the server without full root privileges.
-You may need to also specify a
--u
-option.
-.TP
-.BR \-I " \fIiface\fP, " \--interface "=" \fIiface\fP
-Listen on interface.
-This option may appear an unlimited number of times.
-.sp
-
-.TP
-.BR \-k " \fIstring\fP, " \--keyfile "=" \fIstring\fP
-path to symmetric keys.
-.sp
-Specify the name and path of the symmetric key file.
-/etc/ntp.keys
-is the default.
-This is the same operation as the
-keys keyfile
-configuration file directive.
-.TP
-.BR \-l " \fIstring\fP, " \--logfile "=" \fIstring\fP
-path to the log file.
-.sp
-Specify the name and path of the log file.
-The default is the system log file.
-This is the same operation as the
-logfile logfile
-configuration file directive.
-.TP
-.BR \-L ", " \--novirtualips
-Do not listen to virtual IPs.
-.sp
-Do not listen to virtual IPs. The default is to listen.
-.TP
-.BR \-M ", " \--modifymmtimer
-Modify Multimedia Timer (Windows only).
-.sp
-Set the Windows Multimedia Timer to highest resolution.
-.TP
-.BR \-n ", " \--nofork
-Do not fork.
-.sp
-
-.TP
-.BR \-N ", " \--nice
-Run at high priority.
-.sp
-To the extent permitted by the operating system, run
-ntpd
-at the highest priority.
-.TP
-.BR \-O " \fIstring\fP, " \--servertime "=" \fIstring\fP
-Server time.
-.sp
-
-.TP
-.BR \-p " \fIstring\fP, " \--pidfile "=" \fIstring\fP
-path to the PID file.
-.sp
-Specify the name and path of the file used to record
-ntpd's
-process ID.
-This is the same operation as the
-pidfile pidfile
-configuration file directive.
-.TP
-.BR \-P " \fInumber\fP, " \--priority "=" \fInumber\fP
-Process priority.
-This option takes an integer number as its argument.
-.sp
-To the extent permitted by the operating system, run
-ntpd
-at the specified
-sched_setscheduler(SCHED_FIFO)
-priority.
-.TP
-.BR \-q ", " \--quit
-Set the time and quit.
-.sp
-ntpd
-will exit just after the first time the clock is set. This behavior mimics that of the
-ntpdate
-program, which is to be retired.
-The
--g
-and
--x
-options can be used with this option.
-Note: The kernel time discipline is disabled with this option.
-.TP
-.BR \-r " \fIstring\fP, " \--propagationdelay "=" \fIstring\fP
-Broadcast/propagation delay.
-.sp
-Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
-.TP
-.BR \-U " \fInumber\fP, " \--updateinterval "=" \fInumber\fP
-interval in seconds between scans for new or dropped interfaces.
-This option takes an integer number as its argument.
-.sp
-Give the time in seconds between two scans for new or dropped interfaces.
-For systems with routing socket support the scans will be performed shortly after the interface change
-has been detected by the system.
-Use 0 to disable scanning.
-.TP
-.BR \-s " \fIstring\fP, " \--statsdir "=" \fIstring\fP
-Statistics file location.
-.sp
-Specify the directory path for files created by the statistics facility.
-This is the same operation as the
-statsdir statsdir
-configuration file directive.
-.TP
-.BR \-S " \fIstring\fP, " \--endsimtime "=" \fIstring\fP
-Simulation end time.
-.sp
-
-.TP
-.BR \-t " \fItkey\fP, " \--trustedkey "=" \fItkey\fP
-Trusted key number.
-This option may appear an unlimited number of times.
-.sp
-Add a key number to the trusted key list.
-.TP
-.BR \-T " \fIstring\fP, " \--freqerr "=" \fIstring\fP
-Simulation frequency error.
-.sp
-
-.TP
-.BR \-W " \fIstring\fP, " \--walknoise "=" \fIstring\fP
-Simulation random walk noise.
-.sp
-
-.TP
-.BR \-u " \fIstring\fP, " \--user "=" \fIstring\fP
-Run as userid (or userid:groupid).
-.sp
-Specify a user, and optionally a group, to switch to.
-This option is only available if the OS supports to run the server without full root privileges.
-Currently, this option is supported under NetBSD (configure with
---enable-clockctl
-) and Linux (configure with
---enable-linuxcaps
-).
-.TP
-.BR \-v " \fInvar\fP, " \--var "=" \fInvar\fP
-make ARG an ntp variable (RW).
-This option may appear an unlimited number of times.
-.sp
-
-.TP
-.BR \-V " \fIndvar\fP, " \--dvar "=" \fIndvar\fP
-make ARG an ntp variable (RW|DEF).
-This option may appear an unlimited number of times.
-.sp
-
-.TP
-.BR \-x ", " \--slew
-Slew up to 600 seconds.
-.sp
-Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
-This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
-Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
-Thus, an adjustment as much as 600 s will take almost 14 days to complete.
-This option can be used with the
--g
-and
--q
-options.
-See the
-tinker
-configuration file directive for other options.
-Note: The kernel time discipline is disabled with this option.
-.TP
-.BR \-Y " \fIstring\fP, " \--ndelay "=" \fIstring\fP
-Simulation network delay.
-.sp
-
-.TP
-.BR \-Z " \fIstring\fP, " \--pdelay "=" \fIstring\fP
-Simulation processing delay.
-.sp
-
-.TP
-.BR \-? , " \--help"
-Display usage information and exit.
-.TP
-.BR \-! , " \--more-help"
-Extended usage information passed thru pager.
-.TP
-.BR \-> " [\fIrcfile\fP]," " \--save-opts" "[=\fIrcfile\fP]"
-Save the option state to \fIrcfile\fP. The default is the \fIlast\fP
-configuration file listed in the \fBOPTION PRESETS\fP section, below.
-.TP
-.BR \-< " \fIrcfile\fP," " \--load-opts" "=\fIrcfile\fP," " \--no-load-opts"
-Load options from \fIrcfile\fP.
-The \fIno-load-opts\fP form will disable the loading
-of earlier RC/INI files. \fI--no-load-opts\fP is handled early,
-out of order.
-.TP
-.BR \-v " [{\fIv|c|n\fP}]," " \--version" "[=\fI{v|c|n}\fP]"
-Output version of program and exit. The default mode is `v', a simple
-version. The `c' mode will print copyright information and `n' will
-print the full copyright notice.
-.SH OPTION PRESETS
-Any option that is not marked as \fInot presettable\fP may be preset
-by loading values from configuration ("RC" or ".INI") file(s) and values from
-environment variables named:
-.nf
- \fBNTPDSIM_<option-name>\fP or \fBNTPDSIM\fP
-.fi
-.aj
-The environmental presets take precedence (are processed later than)
-the configuration files.
-The \fIhomerc\fP files are "\fI$HOME\fP", and "\fI.\fP".
-If any of these are directories, then the file \fI.ntprc\fP
-is searched for within those directories.
-.SH AUTHOR
-David L. Mills and/or others
-.br
-Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
-
-.PP
-.nf
-.na
-see html/copyright.html
-.fi
-.ad
-.PP
-This manual page was \fIAutoGen\fP-erated from the \fBntpdsim\fP
-option definitions.
diff --git a/contrib/ntp/ntpd/ntpsim.c b/contrib/ntp/ntpd/ntpsim.c
index d5ed587..b7c3218 100644
--- a/contrib/ntp/ntpd/ntpsim.c
+++ b/contrib/ntp/ntpd/ntpsim.c
@@ -1,89 +1,142 @@
-/*
- * NTP simulator engine - Harish Nair
- * University of Delaware, 2001
+/* ntpdsim.c
+ *
+ * The source code for the ntp discrete event simulator.
+ *
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
+ * Copyright (c) 2006
+ * (Some code shamelessly based on the original NTP discrete event simulator)
*/
+
+#include <config.h>
+#ifdef SIM
#include "ntpd.h"
-#include "ntpsim.h"
-#include "ntpdsim-opts.h"
+#include "ntp_config.h"
+
+/* forward prototypes */
+int determine_event_ordering(const Event *e1, const Event *e2);
+int determine_recv_buf_ordering(const struct recvbuf *b1,
+ const struct recvbuf *b2);
+void create_server_associations(void);
+void init_sim_io(void);
+
+/* Global Variable Definitions */
+sim_info simulation; /* Simulation Control Variables */
+local_clock_info simclock; /* Local Clock Variables */
+queue *event_queue; /* Event Queue */
+queue *recv_queue; /* Receive Queue */
+static double sys_residual = 0; /* adjustment residue (s) */
+
+void (*event_ptr[]) (Event *) = {
+ sim_event_beep, sim_update_clocks, sim_event_timer, sim_event_recv_packet
+}; /* Function pointer to the events */
-/*
- * Defines...
- */
-#define SIM_TIME 86400 /* end simulation time */
-#define NET_DLY .001 /* network delay */
-#define PROC_DLY .001 /* processing delay */
-#define BEEP_DLY 3600 /* beep interval (s) */
-#define SLEW 500e-6 /* correction rate (PPM) */
/*
- * Function pointers
+ * Define a function to compare two events to determine which one occurs
+ * first.
*/
-void (*funcPtr[]) (Node *, Event) = {
- &ndbeep, &ndeclk, &ntptmr, &netpkt
-};
+int
+determine_event_ordering(
+ const Event *e1,
+ const Event *e2
+ )
+{
+ return (e1->time - e2->time);
+}
/*
- * ntpsim - initialize global variables and event queue and start
+ * Define a function to compare two received packets to determine which
+ * one is received first.
*/
int
-ntpsim(
- int argc,
- char *argv[]
+determine_recv_buf_ordering(
+ const struct recvbuf *b1,
+ const struct recvbuf *b2
)
{
- Event e;
- double maxtime;
- struct timeval seed;
+ double recv_time1;
+ double recv_time2;
- /*
- * Initialize the global node
- */
- ntp_node.time = 0; /* simulation time */
- ntp_node.sim_time = SIM_TIME; /* end simulation time (-S) */
- ntp_node.ntp_time = 0; /* client disciplined time */
- ntp_node.adj = 0; /* remaining time correction */
- ntp_node.slew = SLEW; /* correction rate (-H) */
-
- ntp_node.clk_time = 0; /* server time (-O) */
- ntp_node.ferr = 0; /* frequency error (-T) */
- ntp_node.fnse = 0; /* random walk noise (-W) */
- ntp_node.ndly = NET_DLY; /* network delay (-Y) */
- ntp_node.snse = 0; /* phase noise (-C) */
- ntp_node.pdly = PROC_DLY; /* processing delay (-Z) */
- ntp_node.bdly = BEEP_DLY; /* beep interval (-B) */
-
- ntp_node.events = NULL;
- ntp_node.rbuflist = NULL;
+ /* Simply convert the time received to double and subtract */
+ LFPTOD(&b1->recv_time, recv_time1);
+ LFPTOD(&b2->recv_time, recv_time2);
- /*
- * Initialize ntp variables
- */
- initializing = 1;
- init_auth();
- init_util();
- init_restrict();
- init_mon();
- init_timer();
- init_lib();
- init_request();
- init_control();
- init_peer();
- init_proto();
- init_io();
- init_loopfilter();
- mon_start(MON_OFF);
-
- {
- int optct = optionProcess(&ntpdsimOptions, argc, argv);
- argc -= optct;
- argv += optct;
+ return (int)(recv_time1 - recv_time2);
+}
+
+
+/* Define a function to create the server associations */
+void create_server_associations(void)
+{
+ int i;
+
+ for (i = 0; i < simulation.num_of_servers; ++i) {
+ printf("%s\n", stoa(simulation.servers[i].addr));
+ if (peer_config(simulation.servers[i].addr,
+ NULL,
+ loopback_interface,
+ MODE_CLIENT,
+ NTP_VERSION,
+ NTP_MINDPOLL,
+ NTP_MAXDPOLL,
+ 0, /* peerflags */
+ 0, /* ttl */
+ 0, /* peerkey */
+ NULL /* group ident */) == 0) {
+ fprintf(stderr,
+ "ERROR!! Could not create association for: %s\n",
+ stoa(simulation.servers[i].addr));
+ }
}
+}
- getconfig(argc, argv);
- initializing = 0;
- loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
+/* Main Simulator Code */
+
+int
+ntpsim(
+ int argc,
+ char * argv[]
+ )
+{
+ Event * curr_event;
+ struct timeval seed;
+
+ /* Initialize the local Clock */
+ simclock.local_time = 0;
+ simclock.adj = 0;
+ simclock.slew = 500e-6;
+
+ /* Initialize the simulation */
+ simulation.num_of_servers = 0;
+ simulation.beep_delay = BEEP_DLY;
+ simulation.sim_time = 0;
+ simulation.end_time = SIM_TIME;
+
+ /* Initialize ntp modules */
+ initializing = TRUE;
+ msyslog_term = TRUE;
+ init_sim_io();
+ init_auth();
+ init_util();
+ init_restrict();
+ init_mon();
+ init_timer();
+ init_lib();
+ init_request();
+ init_control();
+ init_peer();
+ init_proto();
+ init_loopfilter();
+ mon_start(MON_OFF);
+
+ /* Call getconfig to parse the configuration file */
+ getconfig(argc, argv);
+ loop_config(LOOP_DRIFTINIT, 0);
+ initializing = FALSE;
/*
* Watch out here, we want the real time, not the silly stuff.
@@ -91,281 +144,514 @@ ntpsim(
gettimeofday(&seed, NULL);
ntp_srandom(seed.tv_usec);
- /*
- * Push a beep and timer interrupt on the queue
- */
- push(event(0, BEEP), &ntp_node.events);
- push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
+ /* Initialize the event queue */
+ event_queue = create_priority_queue((q_order_func)
+ determine_event_ordering);
- /*
+ /* Initialize the receive queue */
+ recv_queue = create_priority_queue((q_order_func)
+ determine_recv_buf_ordering);
+
+ /* Push a beep and a timer on the event queue */
+ enqueue(event_queue, event(0, BEEP));
+ enqueue(event_queue, event(simulation.sim_time + 1.0, TIMER));
+
+ /*
* Pop the queue until nothing is left or time is exceeded
*/
- maxtime = ntp_node.time + ntp_node.sim_time;
- while (ntp_node.time <= maxtime && ntp_node.events != NULL ) {
- e = pop(&ntp_node.events);
- ndeclk(&ntp_node, e);
- funcPtr[e.function](&ntp_node, e);
+ /* maxtime = simulation.sim_time + simulation.end_time;*/
+ while (simulation.sim_time <= simulation.end_time &&
+ (!empty(event_queue))) {
+ curr_event = dequeue(event_queue);
+ /* Update all the clocks to the time on the event */
+ sim_update_clocks(curr_event);
+
+ /* Execute the function associated with the event */
+ (*event_ptr[curr_event->function])(curr_event);
+ free_node(curr_event);
}
+ printf("sys_received: %lu\n", sys_received);
+ printf("sys_badlength: %lu\n", sys_badlength);
+ printf("sys_declined: %lu\n", sys_declined);
+ printf("sys_restricted: %lu\n", sys_restricted);
+ printf("sys_newversion: %lu\n", sys_newversion);
+ printf("sys_oldversion: %lu\n", sys_oldversion);
+ printf("sys_limitrejected: %lu\n", sys_limitrejected);
+ printf("sys_badauth: %lu\n", sys_badauth);
+
return (0);
}
-/*
- * Return an event
- */
-Event
-event(
- double t,
- funcTkn f
- )
+void
+init_sim_io(void)
{
- Event e;
-
- e.time = t;
- e.function = f;
- return (e);
+ loopback_interface = emalloc_zero(sizeof(*loopback_interface));
+ ep_list = loopback_interface;
+ strlcpy(loopback_interface->name, "IPv4loop",
+ sizeof(loopback_interface->name));
+ loopback_interface->flags = INT_UP | INT_LOOPBACK;
+ loopback_interface->fd = -1;
+ loopback_interface->bfd = -1;
+ loopback_interface->ifnum = 1;
+ loopback_interface->family = AF_INET;
+ AF(&loopback_interface->sin) = AF_INET;
+ SET_ADDR4(&loopback_interface->sin, LOOPBACKADR);
+ SET_PORT(&loopback_interface->sin, NTP_PORT);
+ AF(&loopback_interface->mask) = AF_INET;
+ SET_ADDR4(&loopback_interface->mask, LOOPNETMASK);
}
-/*
- * Create an event queue
- */
-Queue
-queue(
- Event e,
- Queue q
- )
+
+/* Define a function to create an return an Event */
+
+Event *event(double t, funcTkn f)
{
- Queue ret;
+ Event *e;
- if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
- abortsim("queue-malloc");
- ret->event = e;
- ret->next = q;
- return (ret);
+ if ((e = get_node(sizeof(*e))) == NULL)
+ abortsim("get_node failed in event");
+ e->time = t;
+ e->function = f;
+ return (e);
}
+/* NTP SIMULATION FUNCTIONS */
-/*
- * Push an event into the event queue
+/* Define a function for processing a timer interrupt.
+ * On every timer interrupt, call the NTP timer to send packets and process
+ * the clock and then call the receive function to receive packets.
*/
-void push(
- Event e,
- Queue *qp
- )
+void sim_event_timer(Event *e)
{
- Queue *tmp = qp;
-
- while (*tmp != NULL && ((*tmp)->event.time < e.time))
- tmp = &((*tmp)->next);
- *tmp = queue(e, (*tmp));
+ struct recvbuf *rbuf;
+
+ /* Call the NTP timer.
+ * This will be responsible for actually "sending the packets."
+ * Since this is a simulation, the packets sent over the network
+ * will be processed by the simulate_server routine below.
+ */
+ timer();
+
+ /* Process received buffers */
+ while (!empty(recv_queue)) {
+ rbuf = (struct recvbuf *)dequeue(recv_queue);
+ (*rbuf->receiver)(rbuf);
+ free_node(rbuf);
+ }
+
+ /* Arm the next timer interrupt. */
+ enqueue(event_queue,
+ event(simulation.sim_time + (1 << EVENT_TIMEOUT), TIMER));
}
-/*
- * Pop the first event from the event queue
+
+/* Define a function to simulate a server.
+ * This function processes the sent packet according to the server script,
+ * creates a reply packet and pushes the reply packet onto the event queue
*/
-Event
-pop(
- Queue *qp
- )
+int simulate_server(
+ sockaddr_u *serv_addr, /* Address of the server */
+ endpt * inter, /* Interface on which the reply should
+ be inserted */
+ struct pkt *rpkt /* Packet sent to the server that
+ needs to be processed. */
+ )
{
- Event ret;
- Queue tmp;
-
- tmp = *qp;
- if (tmp == NULL)
- abortsim("pop - empty queue");
- ret = tmp->event;
- *qp = tmp->next;
- free(tmp);
- return (ret);
+ struct pkt xpkt; /* Packet to be transmitted back
+ to the client */
+ struct recvbuf rbuf; /* Buffer for the received packet */
+ Event *e; /* Packet receive event */
+ server_info *server; /* Pointer to the server being simulated */
+ script_info *curr_script; /* Current script being processed */
+ int i;
+ double d1, d2, d3; /* Delays while the packet is enroute */
+ double t1, t2, t3, t4; /* The four timestamps in the packet */
+ l_fp lfp_host; /* host-order l_fp */
+
+ ZERO(xpkt);
+ ZERO(rbuf);
+
+ /* Search for the server with the desired address */
+ server = NULL;
+ for (i = 0; i < simulation.num_of_servers; ++i) {
+ if (memcmp(simulation.servers[i].addr, serv_addr,
+ sizeof(*serv_addr)) == 0) {
+ server = &simulation.servers[i];
+ break;
+ }
+ }
+
+ fprintf(stderr, "Received packet from %s on %s\n",
+ stoa(serv_addr), latoa(inter));
+ if (server == NULL)
+ abortsim("Server with specified address not found!!!");
+
+ /* Get the current script for the server */
+ curr_script = server->curr_script;
+
+ /* Create a server reply packet.
+ * Masquerade the reply as a stratum-1 server with a GPS clock
+ */
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
+ MODE_SERVER);
+ xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
+ memcpy(&xpkt.refid, "GPS", 4);
+ xpkt.ppoll = rpkt->ppoll;
+ xpkt.precision = rpkt->precision;
+ xpkt.rootdelay = 0;
+ xpkt.rootdisp = 0;
+
+ /* TIMESTAMP CALCULATIONS
+ t1 t4
+ \ /
+ d1 \ / d3
+ \ /
+ t2 ----------------- t3
+ d2
+ */
+ /* Compute the delays */
+ d1 = poisson(curr_script->prop_delay, curr_script->jitter);
+ d2 = poisson(curr_script->proc_delay, 0);
+ d3 = poisson(curr_script->prop_delay, curr_script->jitter);
+
+ /* Note: In the transmitted packet:
+ * 1. t1 and t4 are times in the client according to the local clock.
+ * 2. t2 and t3 are server times according to the simulated server.
+ * Compute t1, t2, t3 and t4
+ * Note: This function is called at time t1.
+ */
+
+ NTOHL_FP(&rpkt->xmt, &lfp_host);
+ LFPTOD(&lfp_host, t1);
+ t2 = server->server_time + d1;
+ t3 = server->server_time + d1 + d2;
+ t4 = t1 + d1 + d2 + d3;
+
+ /* Save the timestamps */
+ xpkt.org = rpkt->xmt;
+ DTOLFP(t2, &lfp_host);
+ HTONL_FP(&lfp_host, &xpkt.rec);
+ DTOLFP(t3, &lfp_host);
+ HTONL_FP(&lfp_host, &xpkt.xmt);
+ xpkt.reftime = xpkt.xmt;
+
+ /*
+ * Ok, we are done with the packet. Now initialize the receive
+ * buffer for the packet.
+ */
+ rbuf.used = 1;
+ rbuf.receiver = &receive; /* callback to process the packet */
+ rbuf.recv_length = LEN_PKT_NOMAC;
+ rbuf.recv_pkt = xpkt;
+ rbuf.dstadr = inter;
+ rbuf.fd = inter->fd;
+ memcpy(&rbuf.srcadr, serv_addr, sizeof(rbuf.srcadr));
+ memcpy(&rbuf.recv_srcadr, serv_addr, sizeof(rbuf.recv_srcadr));
+
+ /*
+ * Create a packet event and insert it onto the event_queue at the
+ * arrival time (t4) of the packet at the client
+ */
+ e = event(t4, PACKET);
+ e->rcv_buf = rbuf;
+ enqueue(event_queue, e);
+
+ /*
+ * Check if the time of the script has expired. If yes, delete it.
+ */
+ if (curr_script->duration > simulation.sim_time &&
+ NULL == HEAD_PFIFO(server->script)) {
+ printf("Hello\n");
+ /*
+ * For some reason freeing up the curr_script memory kills the
+ * simulation. Further debugging is needed to determine why.
+ * free(curr_script);
+ */
+ UNLINK_FIFO(curr_script, *server->script, link);
+ }
+
+ return (0);
}
-/*
- * Update clocks
+/* Define a function to update all the clocks
+ * Most of the code is modified from the systime.c file by Prof. Mills
*/
-void
-ndeclk(
- Node *n,
- Event e
- )
+
+void sim_update_clocks(Event *e)
{
- node_clock(n, e.time);
+ double time_gap;
+ double adj;
+ int i;
+
+ /* Compute the time between the last update event and this update */
+ time_gap = e->time - simulation.sim_time;
+
+ if (time_gap < 0)
+ printf("WARNING: e->time %.6g comes before sim_time %.6g (gap %+.6g)\n",
+ e->time, simulation.sim_time, time_gap);
+
+ /* Advance the client clock */
+ if (e->time + time_gap < simclock.local_time)
+ printf("WARNING: e->time + gap %.6g comes before local_time %.6g\n",
+ e->time + time_gap, simclock.local_time);
+ simclock.local_time = e->time + time_gap;
+
+ /* Advance the simulation time */
+ simulation.sim_time = e->time;
+
+ /* Advance the server clocks adjusted for systematic and random frequency
+ * errors. The random error is a random walk computed as the
+ * integral of samples from a Gaussian distribution.
+ */
+ for (i = 0; i < simulation.num_of_servers; ++i) {
+ simulation.servers[i].curr_script->freq_offset +=
+ gauss(0, time_gap * simulation.servers[i].curr_script->wander);
+
+ simulation.servers[i].server_time += time_gap *
+ (1 + simulation.servers[i].curr_script->freq_offset);
+ }
+
+ /* Perform the adjtime() function. If the adjustment completed
+ * in the previous interval, amortize the entire amount; if not,
+ * carry the leftover to the next interval.
+ */
+
+ adj = time_gap * simclock.slew;
+ if (adj < fabs(simclock.adj)) {
+ if (simclock.adj < 0) {
+ simclock.adj += adj;
+ simclock.local_time -= adj;
+ } else {
+ simclock.adj -= adj;
+ simclock.local_time += adj;
+ }
+ } else {
+ simclock.local_time += simclock.adj;
+ simclock.adj = 0;
+ }
}
-/*
- * Timer interrupt. Eventually, this results in calling the
- * srvr_rplyi() routine below.
- */
-void
-ntptmr(
- Node *n,
- Event e
- )
+/* Define a function that processes a receive packet event.
+ * This function simply inserts the packet received onto the receive queue
+ */
+
+void sim_event_recv_packet(Event *e)
{
- struct recvbuf *rbuf;
+ struct recvbuf *rbuf;
- timer();
+ /* Allocate a receive buffer and copy the packet to it */
+ if ((rbuf = get_node(sizeof(*rbuf))) == NULL)
+ abortsim("get_node failed in sim_event_recv_packet");
+ memcpy(rbuf, &e->rcv_buf, sizeof(*rbuf));
- /*
- * Process buffers received. They had better be in order by
- * receive timestamp. Note that there are no additional buffers
- * in the current implementation of ntpsim.
- */
- while (n->rbuflist != NULL) {
- rbuf = n->rbuflist;
- n->rbuflist = NULL;
- (rbuf->receiver)(rbuf);
- free(rbuf);
- }
+ /* Store the local time in the received packet */
+ DTOLFP(simclock.local_time, &rbuf->recv_time);
- /*
- * Arm the next timer interrupt.
- */
- push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
+ /* Insert the packet received onto the receive queue */
+ enqueue(recv_queue, rbuf);
}
-/*
- * srvr_rply() - send packet
+
+/* Define a function to output simulation statistics on a beep event
*/
-int srvr_rply(
- Node *n,
- struct sockaddr_storage *dest,
- struct interface *inter, struct pkt *rpkt
- )
+
+/*** TODO: Need to decide on how to output for multiple servers ***/
+void sim_event_beep(Event *e)
{
- struct pkt xpkt;
- struct recvbuf rbuf;
- Event xvnt;
- double dtemp, etemp;
+#if 0
+ static int first_time = 1;
+ char *dash = "-----------------";
+#endif
+
+ fprintf(stderr, "BEEP!!!\n");
+ enqueue(event_queue, event(e->time + simulation.beep_delay, BEEP));
+#if 0
+ if(simulation.beep_delay > 0) {
+ if (first_time) {
+ printf("\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n",
+ ' ', ' ', ' ', ' ',' ');
+ printf("\t%s\t%s\t%s\n", dash, dash, dash);
+ first_time = 0;
+
+ printf("\t%16.6f\t%16.6f\t%16.6f\n",
+ n->time, n->clk_time, n->ntp_time);
+ return;
+ }
+ printf("\t%16.6f\t%16.6f\t%16.6f\n",
+ simclock.local_time,
+ n->time, n->clk_time, n->ntp_time);
+#endif
- /*
- * Insert packet header values. We make this look like a
- * stratum-1 server with a GPS clock, but nobody will ever
- * notice that.
- */
- xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
- MODE_SERVER);
- xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
- memcpy(&xpkt.refid, "GPS", 4);
- xpkt.ppoll = rpkt->ppoll;
- xpkt.precision = rpkt->precision;
- xpkt.rootdelay = 0;
- xpkt.rootdispersion = 0;
+}
- /*
- * Insert the timestamps.
- */
- xpkt.org = rpkt->xmt;
- dtemp = poisson(n->ndly, n->snse); /* client->server delay */
- DTOLFP(dtemp + n->clk_time, &xpkt.rec);
- dtemp += poisson(n->pdly, 0); /* server delay */
- DTOLFP(dtemp + n->clk_time, &xpkt.xmt);
- xpkt.reftime = xpkt.xmt;
- dtemp += poisson(n->ndly, n->snse); /* server->client delay */
- /*
- * Insert the I/O stuff.
- */
- rbuf.receiver = receive;
- get_systime(&rbuf.recv_time);
- rbuf.recv_length = LEN_PKT_NOMAC;
- rbuf.recv_pkt = xpkt;
- memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage));
- memcpy(&rbuf.recv_srcadr, dest,
- sizeof(struct sockaddr_storage));
- if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL)
- abortsim("server-malloc");
- memcpy(rbuf.dstadr, inter, sizeof(struct interface));
+/* Define a function to abort the simulation on an error and spit out an
+ * error message
+ */
- /*
- * Very carefully predict the time of arrival for the received
- * packet.
- */
- LFPTOD(&xpkt.org, etemp);
- etemp += dtemp;
- xvnt = event(etemp, PACKET);
- xvnt.rcv_buf = rbuf;
- push(xvnt, &n->events);
- return (0);
+void abortsim(char *errmsg)
+{
+ perror(errmsg);
+ exit(1);
}
+
+/* CODE ORIGINALLY IN libntp/systime.c
+ * -----------------------------------
+ * This code was a part of the original NTP simulator and originally
+ * had its home in the libntp/systime.c file.
+ *
+ * It has been shamelessly moved to here and has been modified for the
+ * purposes of the current simulator.
+ */
+
+
/*
- * netpkt() - receive packet
+ * get_systime - return the system time in NTP timestamp format
*/
void
-netpkt(
- Node *n,
- Event e
- )
+get_systime(
+ l_fp *now /* current system time in l_fp */ )
{
- struct recvbuf *rbuf;
- struct recvbuf *obuf;
-
- /*
- * Insert the packet on the receive queue and record the arrival
- * time.
- */
- if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL)
- abortsim("ntprcv-malloc");
- memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf));
- rbuf->receiver = receive;
- DTOLFP(n->ntp_time, &rbuf->recv_time);
- obuf = n->rbuflist;
-
- /*
- * In the present incarnation, no more than one buffer can be on
- * the queue;
- */
- if (obuf == NULL) {
- n->rbuflist = rbuf;
- }
+ /*
+ * To fool the code that determines the local clock precision,
+ * we advance the clock a minimum of 200 nanoseconds on every
+ * clock read. This is appropriate for a typical modern machine
+ * with nanosecond clocks. Note we make no attempt here to
+ * simulate reading error, since the error is so small. This may
+ * change when the need comes to implement picosecond clocks.
+ */
+ if (simclock.local_time == simclock.last_read_time)
+ simclock.local_time += 200e-9;
+
+ simclock.last_read_time = simclock.local_time;
+ DTOLFP(simclock.local_time, now);
+/* OLD Code
+ if (ntp_node.ntp_time == ntp_node.last_time)
+ ntp_node.ntp_time += 200e-9;
+ ntp_node.last_time = ntp_node.ntp_time;
+ DTOLFP(ntp_node.ntp_time, now);
+*/
}
-
-
+
+
/*
- * ndbeep() - progress indicator
+ * adj_systime - advance or retard the system clock exactly like the
+ * real thng.
*/
-void
-ndbeep(
- Node *n,
- Event e
- )
+int /* always succeeds */
+adj_systime(
+ double now /* time adjustment (s) */
+ )
{
- static int first_time = 1;
- char *dash = "-----------------";
-
- if(n->bdly > 0) {
- if (first_time) {
- printf(
- "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' ');
- printf("\t%s\t%s\t%s\n", dash, dash, dash);
- first_time = 0;
- push(event(n->bdly, BEEP), &n->events);
- push(event(n->sim_time, BEEP), &n->events);
- printf("\t%16.6f\t%16.6f\t%16.6f\n",
- n->time, n->clk_time, n->ntp_time);
- return;
- }
- printf("\t%16.6f\t%16.6f\t%16.6f\n",
- n->time, n->clk_time, n->ntp_time);
- push(event(e.time + n->bdly, BEEP), &n->events);
- }
+ struct timeval adjtv; /* new adjustment */
+ double dtemp;
+ long ticks;
+ int isneg = 0;
+
+ /*
+ * Most Unix adjtime() implementations adjust the system clock
+ * in microsecond quanta, but some adjust in 10-ms quanta. We
+ * carefully round the adjustment to the nearest quantum, then
+ * adjust in quanta and keep the residue for later.
+ */
+ dtemp = now + sys_residual;
+ if (dtemp < 0) {
+ isneg = 1;
+ dtemp = -dtemp;
+ }
+ adjtv.tv_sec = (long)dtemp;
+ dtemp -= adjtv.tv_sec;
+ ticks = (long)(dtemp / sys_tick + .5);
+ adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
+ dtemp -= adjtv.tv_usec / 1e6;
+ sys_residual = dtemp;
+
+ /*
+ * Convert to signed seconds and microseconds for the Unix
+ * adjtime() system call. Note we purposely lose the adjtime()
+ * leftover.
+ */
+ if (isneg) {
+ adjtv.tv_sec = -adjtv.tv_sec;
+ adjtv.tv_usec = -adjtv.tv_usec;
+ sys_residual = -sys_residual;
+ }
+ simclock.adj = now;
+/* ntp_node.adj = now; */
+ return (1);
+}
+
+
+/*
+ * step_systime - step the system clock. We are religious here.
+ */
+int /* always succeeds */
+step_systime(
+ double now /* step adjustment (s) */
+ )
+{
+#ifdef DEBUG
+ if (debug)
+ printf("step_systime: time %.6f adj %.6f\n",
+ simclock.local_time, now);
+#endif
+ simclock.local_time += now;
+ return (1);
+}
+
+/*
+ * gauss() - returns samples from a gaussion distribution
+ */
+double /* Gaussian sample */
+gauss(
+ double m, /* sample mean */
+ double s /* sample standard deviation (sigma) */
+ )
+{
+ double q1, q2;
+
+ /*
+ * Roll a sample from a Gaussian distribution with mean m and
+ * standard deviation s. For m = 0, s = 1, mean(y) = 0,
+ * std(y) = 1.
+ */
+ if (s == 0)
+ return (m);
+ while ((q1 = drand48()) == 0)
+ /* empty statement */;
+ q2 = drand48();
+ return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));
}
-
+
/*
- * Abort simulation
+ * poisson() - returns samples from a network delay distribution
*/
-void
-abortsim(
- char *errmsg
- )
+double /* delay sample (s) */
+poisson(
+ double m, /* fixed propagation delay (s) */
+ double s /* exponential parameter (mu) */
+ )
{
- perror(errmsg);
- exit(1);
+ double q1;
+
+ /*
+ * Roll a sample from a composite distribution with propagation
+ * delay m and exponential distribution time with parameter s.
+ * For m = 0, s = 1, mean(y) = std(y) = 1.
+ */
+ if (s == 0)
+ return (m);
+ while ((q1 = drand48()) == 0)
+ /* empty statement */;
+ return (m - s * log(q1 * s));
}
+
+#endif
diff --git a/contrib/ntp/ntpd/rc_cmdlength.c b/contrib/ntp/ntpd/rc_cmdlength.c
new file mode 100644
index 0000000..2807d2a
--- /dev/null
+++ b/contrib/ntp/ntpd/rc_cmdlength.c
@@ -0,0 +1,35 @@
+#include <config.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+
+/* Bug 2853 */
+/* evaluate the length of the command sequence. This breaks at the first
+ * char that is not >= SPACE and <= 127 after trimming from the right.
+ */
+size_t
+remoteconfig_cmdlength(
+ const char *src_buf,
+ const char *src_end
+ )
+{
+ const char *scan;
+ unsigned char ch;
+
+ /* trim whitespace & garbage from the right */
+ while (src_end != src_buf) {
+ ch = src_end[-1];
+ if (ch > ' ' && ch < 128)
+ break;
+ --src_end;
+ }
+ /* now do a forward scan */
+ for (scan = src_buf; scan != src_end; ++scan) {
+ ch = scan[0];
+ if ((ch < ' ' || ch >= 128) && ch != '\t')
+ break;
+ }
+ return (size_t)(scan - src_buf);
+}
diff --git a/contrib/ntp/ntpd/refclock_acts.c b/contrib/ntp/ntpd/refclock_acts.c
index 57f2ca7..f62cc46 100644
--- a/contrib/ntp/ntpd/refclock_acts.c
+++ b/contrib/ntp/ntpd/refclock_acts.c
@@ -6,7 +6,7 @@
#include <config.h>
#endif
-#if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS))
+#if defined(REFCLOCK) && defined(CLOCK_ACTS)
#include "ntpd.h"
#include "ntp_io.h"
@@ -21,6 +21,12 @@
# include <sys/ioctl.h>
#endif /* HAVE_SYS_IOCTL_H */
+#ifdef SYS_WINNT
+#undef write /* ports/winnt/include/config.h: #define write _write */
+extern int async_write(int, const void *, unsigned int);
+#define write(fd, data, octets) async_write(fd, data, octets)
+#endif
+
/*
* This driver supports the US (NIST, USNO) and European (PTB, NPL,
* etc.) modem time services, as well as Spectracom GPS and WWVB
@@ -33,20 +39,19 @@
* This driver requires a modem with a Hayes-compatible command set and
* control over the modem data terminal ready (DTR) control line. The
* modem setup string is hard-coded in the driver and may require
- * changes for nonstandard modems or special circumstances. For reasons
- * unrelated to this driver, the data set ready (DSR) control line
- * should not be set when this driver is first started.
+ * changes for nonstandard modems or special circumstances.
*
- * The calling program is initiated by setting fudge flag1, either
- * manually or automatically. When flag1 is set, the calling program
- * dials the first number in the phone command of the configuration
- * file. If that call fails, the calling program dials the second number
- * and so on. The number is specified by the Hayes ATDT prefix followed
- * by the number itself, including the prefix and long-distance digits
- * and delay code, if necessary. The flag1 is reset and the calling
- * program terminated if (a) a valid clock update has been determined,
- * (b) no more numbers remain in the list, (c) a device fault or timeout
- * occurs or (d) fudge flag1 is reset manually.
+ * When enabled, the calling program dials the first number in the
+ * phones file. If that call fails, it dials the second number and
+ * so on. The phone number is specified by the Hayes ATDT prefix
+ * followed by the number itself, including the long-distance prefix
+ * and delay code, if necessary. The calling program is enabled
+ * when (a) fudge flag1 is set by ntpdc, (b) at each poll interval
+ * when no other synchronization sources are present, and (c) at each
+ * poll interval whether or not other synchronization sources are
+ * present. The calling program disconnects if (a) the called party
+ * is busy or does not answer, (b) the called party disconnects
+ * before a sufficient nuimber of timecodes have been received.
*
* The driver is transparent to each of the modem time services and
* Spectracom radios. It selects the parsing algorithm depending on the
@@ -59,18 +64,17 @@
*
* flag1 force a call in manual mode
* flag2 enable port locking (not verified)
- * flag3 no modem; port is directly connected to device
+ * flag3 not used
* flag4 not used
*
* time1 offset adjustment (s)
*
- * Ordinarily, the serial port is connected to a modem; however, it can
- * be connected directly to a device or another computer for testing and
- * calibration. In this case set fudge flag3 and the driver will send a
- * single character 'T' at each poll event. In principle, fudge flag2
- * enables port locking, allowing the modem to be shared when not in use
- * by this driver. At least on Solaris with the current NTP I/O
- * routines, this results only in lots of ugly error messages.
+ * Ordinarily, the serial port is connected to a modem and the phones
+ * list is defined. If no phones list is defined, the port can be
+ * connected directly to a device or another computer. In this case the
+ * driver will send a single character 'T' at each poll event. If
+ * fudge flag2 is enabled, port locking allows the modem to be shared
+ * when not in use by this driver.
*/
/*
* National Institute of Science and Technology (NIST)
@@ -89,7 +93,9 @@
*
* MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is
* the on-time markers echoed by the driver and used by NIST to measure
- * and correct for the propagation delay.
+ * and correct for the propagation delay. Note: the ACTS timecode has
+ * recently been changed to eliminate the * on-time indicator. The
+ * reason for this and the long term implications are not clear.
*
* US Naval Observatory (USNO)
*
@@ -129,26 +135,26 @@
* Interface definitions
*/
#define DEVICE "/dev/acts%d" /* device name and unit */
-#define SPEED232 B9600 /* uart speed (9600 baud) */
+#define SPEED232 B19200 /* uart speed (19200 bps) */
#define PRECISION (-10) /* precision assumed (about 1 ms) */
-#define LOCKFILE "/var/spool/locks/LCK..cua%d"
+#define LOCKFILE "/var/spool/lock/LCK..cua%d"
#define DESCRIPTION "Automated Computer Time Service" /* WRU */
#define REFID "NONE" /* default reference ID */
#define MSGCNT 20 /* max message count */
-#define SMAX 256 /* max clockstats line length */
+#define MAXPHONE 10 /* max number of phone numbers */
/*
- * Calling program modes
+ * Calling program modes (mode)
*/
-#define MODE_AUTO 0 /* automatic mode */
-#define MODE_BACKUP 1 /* backup mode */
+#define MODE_BACKUP 0 /* backup mode */
+#define MODE_AUTO 1 /* automatic mode */
#define MODE_MANUAL 2 /* manual mode */
/*
- * Service identifiers.
+ * Service identifiers (message length)
*/
#define REFACTS "NIST" /* NIST reference ID */
-#define LENACTS 50 /* NIST format */
+#define LENACTS 50 /* NIST format A */
#define REFUSNO "USNO" /* USNO reference ID */
#define LENUSNO 20 /* USNO */
#define REFPTB "PTB\0" /* PTB/NPL reference ID */
@@ -159,40 +165,41 @@
#define LF 0x0a /* ASCII LF */
/*
- * Modem setup strings. These may have to be changed for some modems.
+ * Modem setup strings. These may have to be changed for
+ * some modems.
*
* AT command prefix
* B1 US answer tone
* &C0 disable carrier detect
* &D2 hang up and return to command mode on DTR transition
* E0 modem command echo disabled
- * l1 set modem speaker volume to low level
+ * L1 set modem speaker volume to low level
* M1 speaker enabled until carrier detect
* Q0 return result codes
* V1 return result codes as English words
+ * Y1 enable long-space disconnect
*/
-#define MODEM_SETUP "ATB1&C0&D2E0L1M1Q0V1\r" /* modem setup */
-#define MODEM_HANGUP "ATH\r" /* modem disconnect */
+const char def_modem_setup[] = "ATB1&C0&D2E0L1M1Q0V1Y1";
+const char *modem_setup = def_modem_setup;
/*
* Timeouts (all in seconds)
*/
#define SETUP 3 /* setup timeout */
-#define DTR 1 /* DTR timeout */
+#define REDIAL 30 /* redial timeout */
#define ANSWER 60 /* answer timeout */
-#define CONNECT 20 /* first valid message timeout */
-#define TIMECODE 30 /* all valid messages timeout */
+#define TIMECODE 60 /* message timeout */
+#define MAXCODE 20 /* max timecodes */
/*
* State machine codes
*/
-#define S_IDLE 0 /* wait for poll */
-#define S_OK 1 /* wait for modem setup */
-#define S_DTR 2 /* wait for modem DTR */
-#define S_CONNECT 3 /* wait for answer*/
-#define S_FIRST 4 /* wait for first valid message */
-#define S_MSG 5 /* wait for all messages */
-#define S_CLOSE 6 /* wait after sending disconnect */
+typedef enum {
+ S_IDLE, /* wait for poll */
+ S_SETUP, /* send modem setup */
+ S_CONNECT, /* wait for answer */
+ S_MSG /* wait for timecode */
+} teModemState;
/*
* Unit control structure
@@ -204,26 +211,27 @@ struct actsunit {
int retry; /* retry index */
int msgcnt; /* count of messages received */
l_fp tstamp; /* on-time timestamp */
- char *bufptr; /* buffer pointer */
+ char *bufptr; /* next incoming char stored here */
+ char buf[BMAX]; /* bufptr roams within buf[] */
};
/*
* Function prototypes
*/
-static int acts_start P((int, struct peer *));
-static void acts_shutdown P((int, struct peer *));
-static void acts_receive P((struct recvbuf *));
-static void acts_message P((struct peer *));
-static void acts_timecode P((struct peer *, char *));
-static void acts_poll P((int, struct peer *));
-static void acts_timeout P((struct peer *));
-static void acts_disc P((struct peer *));
-static void acts_timer P((int, struct peer *));
+static int acts_start (int, struct peer *);
+static void acts_shutdown (int, struct peer *);
+static void acts_receive (struct recvbuf *);
+static void acts_message (struct peer *, const char *);
+static void acts_timecode (struct peer *, const char *);
+static void acts_poll (int, struct peer *);
+static void acts_timeout (struct peer *, teModemState);
+static void acts_timer (int, struct peer *);
+static void acts_close (struct peer *);
/*
* Transfer vector (conditional structure name)
*/
-struct refclock refclock_acts = {
+struct refclock refclock_acts = {
acts_start, /* start up driver */
acts_shutdown, /* shut down driver */
acts_poll, /* transmit poll message */
@@ -233,44 +241,45 @@ struct refclock refclock_acts = {
acts_timer /* housekeeping timer */
};
-struct refclock refclock_ptb;
-
/*
* Initialize data for processing
*/
static int
-acts_start (
+acts_start(
int unit,
struct peer *peer
)
{
struct actsunit *up;
struct refclockproc *pp;
+ const char *setup;
/*
* Allocate and initialize unit structure
*/
- up = emalloc(sizeof(struct actsunit));
- if (up == NULL)
- return (0);
-
- memset(up, 0, sizeof(struct actsunit));
+ up = emalloc_zero(sizeof(struct actsunit));
up->unit = unit;
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = acts_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
+ pp->io.fd = -1;
/*
* Initialize miscellaneous variables
*/
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
+ memcpy(&pp->refid, REFID, 4);
peer->sstclktype = CTL_SST_TS_TELEPHONE;
- peer->flags &= ~FLAG_FIXPOLL;
- up->bufptr = pp->a_lastcode;
+ up->bufptr = up->buf;
+ if (def_modem_setup == modem_setup) {
+ setup = get_ext_sys_var("modemsetup");
+ if (setup != NULL)
+ modem_setup = estrdup(setup);
+ }
+
return (1);
}
@@ -279,7 +288,7 @@ acts_start (
* acts_shutdown - shut down the clock
*/
static void
-acts_shutdown (
+acts_shutdown(
int unit,
struct peer *peer
)
@@ -291,7 +300,8 @@ acts_shutdown (
* Warning: do this only when a call is not in progress.
*/
pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
+ up = pp->unitptr;
+ acts_close(peer);
free(up);
}
@@ -300,15 +310,16 @@ acts_shutdown (
* acts_receive - receive data from the serial interface
*/
static void
-acts_receive (
+acts_receive(
struct recvbuf *rbufp
)
{
struct actsunit *up;
struct refclockproc *pp;
struct peer *peer;
- char tbuf[BMAX];
- char *tptr;
+ char tbuf[sizeof(up->buf)];
+ char * tptr;
+ int octets;
/*
* Initialize pointers and read the timecode and timestamp. Note
@@ -317,27 +328,27 @@ acts_receive (
* arbitrary fragments. Capture the timecode at the beginning of
* the message and at the '*' and '#' on-time characters.
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
- pp->lencode = refclock_gtraw(rbufp, tbuf, BMAX - (up->bufptr -
- pp->a_lastcode), &pp->lastrec);
+ up = pp->unitptr;
+ octets = sizeof(up->buf) - (up->bufptr - up->buf);
+ refclock_gtraw(rbufp, tbuf, octets, &pp->lastrec);
for (tptr = tbuf; *tptr != '\0'; tptr++) {
if (*tptr == LF) {
- if (up->bufptr == pp->a_lastcode) {
+ if (up->bufptr == up->buf) {
up->tstamp = pp->lastrec;
continue;
-
} else {
*up->bufptr = '\0';
- acts_message(peer);
- up->bufptr = pp->a_lastcode;
+ up->bufptr = up->buf;
+ acts_message(peer, up->buf);
}
- } else if (!iscntrl(*tptr)) {
+ } else if (!iscntrl((unsigned char)*tptr)) {
*up->bufptr++ = *tptr;
if (*tptr == '*' || *tptr == '#') {
up->tstamp = pp->lastrec;
- write(pp->io.fd, tptr, 1);
+ if (write(pp->io.fd, tptr, 1) < 0)
+ msyslog(LOG_ERR, "acts: write echo fails %m");
}
}
}
@@ -349,74 +360,361 @@ acts_receive (
*/
void
acts_message(
- struct peer *peer
+ struct peer *peer,
+ const char *msg
)
{
struct actsunit *up;
struct refclockproc *pp;
- int dtr = TIOCM_DTR;
- char tbuf[SMAX];
-#ifdef DEBUG
- u_int modem;
-#endif
+ char tbuf[BMAX];
+ int dtr = TIOCM_DTR;
+
+ DPRINTF(1, ("acts: %d %s\n", (int)strlen(msg), msg));
/*
* What to do depends on the state and the first token in the
- * message. A NO token sends the message to the clockstats.
+ * message.
*/
pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
-#ifdef DEBUG
- ioctl(pp->io.fd, TIOCMGET, (char *)&modem);
- sprintf(tbuf, "acts: %04x (%d %d) %lu %s", modem, up->state,
- up->timer, strlen(pp->a_lastcode), pp->a_lastcode);
- if (debug)
- printf("%s\n", tbuf);
-#endif
- strncpy(tbuf, pp->a_lastcode, SMAX);
+ up = pp->unitptr;
+
+ /*
+ * Extract the first token in the line.
+ */
+ strlcpy(tbuf, msg, sizeof(tbuf));
strtok(tbuf, " ");
- if (strcmp(tbuf, "NO") == 0)
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
- switch(up->state) {
+ switch (up->state) {
/*
* We are waiting for the OK response to the modem setup
- * command. When this happens, raise DTR and dial the number
- * followed by \r.
+ * command. When this happens, dial the number followed.
+ * If anything other than OK is received, just ignore it
+ * and wait for timeoue.
*/
- case S_OK:
+ case S_SETUP:
if (strcmp(tbuf, "OK") != 0) {
- msyslog(LOG_ERR, "acts: setup error %s",
- pp->a_lastcode);
- acts_disc(peer);
- return;
+ /*
+ * We disable echo with MODEM_SETUP's E0 but
+ * if the modem was previously E1, we will
+ * see MODEM_SETUP echoed before the OK/ERROR.
+ * Ignore it.
+ */
+ if (!strcmp(tbuf, modem_setup))
+ return;
+ break;
}
- ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr);
- up->state = S_DTR;
- up->timer = DTR;
+
+ mprintf_event(PEVNT_CLOCK, peer, "DIAL #%d %s",
+ up->retry, sys_phone[up->retry]);
+ if (ioctl(pp->io.fd, TIOCMBIS, &dtr) < 0)
+ msyslog(LOG_ERR, "acts: ioctl(TIOCMBIS) failed: %m");
+ if (write(pp->io.fd, sys_phone[up->retry],
+ strlen(sys_phone[up->retry])) < 0)
+ msyslog(LOG_ERR, "acts: write DIAL fails %m");
+ write(pp->io.fd, "\r", 1);
+ up->retry++;
+ up->state = S_CONNECT;
+ up->timer = ANSWER;
return;
/*
- * We are waiting for the call to be answered. All we care about
- * here is token CONNECT. Send the message to the clockstats.
+ * We are waiting for the CONNECT response to the dial
+ * command. When this happens, listen for timecodes. If
+ * somthing other than CONNECT is received, like BUSY
+ * or NO CARRIER, abort the call.
*/
case S_CONNECT:
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
- if (strcmp(tbuf, "CONNECT") != 0) {
- acts_disc(peer);
+ if (strcmp(tbuf, "CONNECT") != 0)
+ break;
+
+ report_event(PEVNT_CLOCK, peer, msg);
+ up->state = S_MSG;
+ up->timer = TIMECODE;
+ return;
+
+ /*
+ * We are waiting for a timecode response. Pass it to
+ * the parser. If NO CARRIER is received, save the
+ * messages and abort the call.
+ */
+ case S_MSG:
+ if (strcmp(tbuf, "NO") == 0)
+ report_event(PEVNT_CLOCK, peer, msg);
+ if (up->msgcnt < MAXCODE)
+ acts_timecode(peer, msg);
+ else
+ acts_timeout(peer, S_MSG);
+ return;
+ }
+
+ /*
+ * Other response. Tell us about it.
+ */
+ report_event(PEVNT_CLOCK, peer, msg);
+ acts_close(peer);
+}
+
+
+/*
+ * acts_timeout - called on timeout
+ */
+static void
+acts_timeout(
+ struct peer *peer,
+ teModemState dstate
+ )
+{
+ struct actsunit *up;
+ struct refclockproc *pp;
+ int fd;
+ int rc;
+ char device[20];
+ char lockfile[128], pidbuf[8];
+
+ /*
+ * The state machine is driven by messages from the modem,
+ * when first started and at timeout.
+ */
+ pp = peer->procptr;
+ up = pp->unitptr;
+ switch (dstate) {
+
+ /*
+ * System poll event. Lock the modem port, open the device
+ * and send the setup command.
+ */
+ case S_IDLE:
+ if (-1 != pp->io.fd)
+ return; /* port is already open */
+
+ /*
+ * Lock the modem port. If busy, retry later. Note: if
+ * something fails between here and the close, the lock
+ * file may not be removed.
+ */
+ if (pp->sloppyclockflag & CLK_FLAG2) {
+ snprintf(lockfile, sizeof(lockfile), LOCKFILE,
+ up->unit);
+ fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
+ 0644);
+ if (fd < 0) {
+ report_event(PEVNT_CLOCK, peer, "acts: port busy");
+ return;
+ }
+ snprintf(pidbuf, sizeof(pidbuf), "%d\n",
+ (u_int)getpid());
+ if (write(fd, pidbuf, strlen(pidbuf)) < 0)
+ msyslog(LOG_ERR, "acts: write lock fails %m");
+ close(fd);
+ }
+
+ /*
+ * Open the device in raw mode and link the I/O.
+ */
+ snprintf(device, sizeof(device), DEVICE,
+ up->unit);
+ fd = refclock_open(device, SPEED232, LDISC_ACTS |
+ LDISC_RAW | LDISC_REMOTE);
+ if (fd < 0) {
+ msyslog(LOG_ERR, "acts: open fails %m");
+ return;
+ }
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ msyslog(LOG_ERR, "acts: addclock fails");
+ close(fd);
+ pp->io.fd = -1;
+ return;
+ }
+ up->msgcnt = 0;
+ up->bufptr = up->buf;
+
+ /*
+ * If the port is directly connected to the device, skip
+ * the modem business and send 'T' for Spectrabum.
+ */
+ if (sys_phone[up->retry] == NULL) {
+ if (write(pp->io.fd, "T", 1) < 0)
+ msyslog(LOG_ERR, "acts: write T fails %m");
+ up->state = S_MSG;
+ up->timer = TIMECODE;
return;
}
- up->state = S_FIRST;
- up->timer = CONNECT;
+
+ /*
+ * Initialize the modem. This works with Hayes-
+ * compatible modems.
+ */
+ mprintf_event(PEVNT_CLOCK, peer, "SETUP %s",
+ modem_setup);
+ rc = write(pp->io.fd, modem_setup, strlen(modem_setup));
+ if (rc < 0)
+ msyslog(LOG_ERR, "acts: write SETUP fails %m");
+ write(pp->io.fd, "\r", 1);
+ up->state = S_SETUP;
+ up->timer = SETUP;
return;
/*
- * We are waiting for a timecode. Pass it to the parser.
+ * In SETUP state the modem did not respond OK to setup string.
+ */
+ case S_SETUP:
+ report_event(PEVNT_CLOCK, peer, "no modem");
+ break;
+
+ /*
+ * In CONNECT state the call did not complete. Abort the call.
+ */
+ case S_CONNECT:
+ report_event(PEVNT_CLOCK, peer, "no answer");
+ break;
+
+ /*
+ * In MSG states no further timecodes are expected. If any
+ * timecodes have arrived, update the clock. In any case,
+ * terminate the call.
*/
- case S_FIRST:
case S_MSG:
- acts_timecode(peer, pp->a_lastcode);
+ if (up->msgcnt == 0) {
+ report_event(PEVNT_CLOCK, peer, "no timecodes");
+ } else {
+ pp->lastref = pp->lastrec;
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
+ refclock_receive(peer);
+ }
+ break;
+ }
+ acts_close(peer);
+}
+
+
+/*
+ * acts_close - close and prepare for next call.
+ *
+ * In ClOSE state no further protocol actions are required
+ * other than to close and release the device and prepare to
+ * dial the next number if necessary.
+ */
+void
+acts_close(
+ struct peer *peer
+ )
+{
+ struct actsunit *up;
+ struct refclockproc *pp;
+ char lockfile[128];
+ int dtr;
+
+ pp = peer->procptr;
+ up = pp->unitptr;
+ if (pp->io.fd != -1) {
+ report_event(PEVNT_CLOCK, peer, "close");
+ dtr = TIOCM_DTR;
+ if (ioctl(pp->io.fd, TIOCMBIC, &dtr) < 0)
+ msyslog(LOG_ERR, "acts: ioctl(TIOCMBIC) failed: %m");
+ io_closeclock(&pp->io);
+ pp->io.fd = -1;
+ }
+ if (pp->sloppyclockflag & CLK_FLAG2) {
+ snprintf(lockfile, sizeof(lockfile),
+ LOCKFILE, up->unit);
+ unlink(lockfile);
+ }
+ if (up->msgcnt == 0 && up->retry > 0) {
+ if (sys_phone[up->retry] != NULL) {
+ up->state = S_IDLE;
+ up->timer = REDIAL;
+ return;
+ }
+ }
+ up->state = S_IDLE;
+ up->timer = 0;
+}
+
+
+/*
+ * acts_poll - called by the transmit routine
+ */
+static void
+acts_poll(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct actsunit *up;
+ struct refclockproc *pp;
+
+ /*
+ * This routine is called at every system poll. All it does is
+ * set flag1 under certain conditions. The real work is done by
+ * the timeout routine and state machine.
+ */
+ pp = peer->procptr;
+ up = pp->unitptr;
+ switch (peer->ttl) {
+
+ /*
+ * In manual mode the calling program is activated by the ntpdc
+ * program using the enable flag (fudge flag1), either manually
+ * or by a cron job.
+ */
+ case MODE_MANUAL:
+ return;
+
+ /*
+ * In automatic mode the calling program runs continuously at
+ * intervals determined by the poll event or specified timeout.
+ */
+ case MODE_AUTO:
break;
+
+ /*
+ * In backup mode the calling program runs continuously as long
+ * as either no peers are available or this peer is selected.
+ */
+ case MODE_BACKUP:
+ if (!(sys_peer == NULL || sys_peer == peer))
+ return;
+
+ break;
+ }
+ pp->polls++;
+ if (S_IDLE == up->state) {
+ up->retry = 0;
+ acts_timeout(peer, S_IDLE);
+ }
+}
+
+
+/*
+ * acts_timer - called at one-second intervals
+ */
+static void
+acts_timer(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct actsunit *up;
+ struct refclockproc *pp;
+
+ /*
+ * This routine implments a timeout which runs for a programmed
+ * interval. The counter is initialized by the state machine and
+ * counts down to zero. Upon reaching zero, the state machine is
+ * called. If flag1 is set while timer is zero, force a call.
+ */
+ pp = peer->procptr;
+ up = pp->unitptr;
+ if (up->timer == 0) {
+ if (pp->sloppyclockflag & CLK_FLAG1) {
+ pp->sloppyclockflag &= ~CLK_FLAG1;
+ acts_timeout(peer, S_IDLE);
+ }
+ } else {
+ up->timer--;
+ if (up->timer == 0)
+ acts_timeout(peer, up->state);
}
}
@@ -425,8 +723,8 @@ acts_message(
*/
void
acts_timecode(
- struct peer *peer, /* peer structure pointer */
- char *str /* timecode string */
+ struct peer * peer, /* peer structure pointer */
+ const char * str /* timecode string */
)
{
struct actsunit *up;
@@ -448,7 +746,7 @@ acts_timecode(
char dstchar; /* WWVB daylight/savings indicator */
int tz; /* WWVB timezone */
- u_int leapmonth; /* PTB/NPL month of leap */
+ int leapmonth; /* PTB/NPL month of leap */
char leapdir; /* PTB/NPL leap direction */
/*
@@ -457,9 +755,9 @@ acts_timecode(
* errors due noise are forgivable.
*/
pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
+ up = pp->unitptr;
pp->nsec = 0;
- switch(strlen(str)) {
+ switch (strlen(str)) {
/*
* For USNO format on-time character '*', which is on a line by
@@ -472,8 +770,8 @@ acts_timecode(
return;
/*
- * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
- * UTC(NIST) *"
+ * ACTS format A: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
+ * UTC(NIST) *".
*/
case LENACTS:
if (sscanf(str,
@@ -484,25 +782,17 @@ acts_timecode(
refclock_report(peer, CEVNT_BADREPLY);
return;
}
-
- /*
- * Wait until ACTS has calculated the roundtrip delay.
- * We don't need to do anything, as ACTS adjusts the
- * on-time epoch.
- */
- if (flag != '#')
- return;
-
pp->day = ymd2yd(pp->year, month, day);
pp->leap = LEAP_NOWARNING;
if (leap == 1)
- pp->leap = LEAP_ADDSECOND;
- else if (pp->leap == 2)
- pp->leap = LEAP_DELSECOND;
+ pp->leap = LEAP_ADDSECOND;
+ else if (leap == 2)
+ pp->leap = LEAP_DELSECOND;
memcpy(&pp->refid, REFACTS, 4);
- if (up->msgcnt == 0)
- record_clock_stats(&peer->srcadr, str);
up->msgcnt++;
+ if (flag != '#' && up->msgcnt < 10)
+ return;
+
break;
/*
@@ -523,10 +813,8 @@ acts_timecode(
*/
pp->leap = LEAP_NOWARNING;
memcpy(&pp->refid, REFUSNO, 4);
- if (up->msgcnt == 0)
- record_clock_stats(&peer->srcadr, str);
up->msgcnt++;
- return;
+ break;
/*
* PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ"
@@ -543,14 +831,12 @@ acts_timecode(
pp->leap = LEAP_NOWARNING;
if (leapmonth == month) {
if (leapdir == '+')
- pp->leap = LEAP_ADDSECOND;
+ pp->leap = LEAP_ADDSECOND;
else if (leapdir == '-')
- pp->leap = LEAP_DELSECOND;
+ pp->leap = LEAP_DELSECOND;
}
pp->day = ymd2yd(pp->year, month, day);
memcpy(&pp->refid, REFPTB, 4);
- if (up->msgcnt == 0)
- record_clock_stats(&peer->srcadr, str);
up->msgcnt++;
break;
@@ -569,8 +855,6 @@ acts_timecode(
if (synchar != ' ')
pp->leap = LEAP_NOTINSYNC;
memcpy(&pp->refid, REFWWVB, 4);
- if (up->msgcnt == 0)
- record_clock_stats(&peer->srcadr, str);
up->msgcnt++;
break;
@@ -592,8 +876,6 @@ acts_timecode(
else if (leapchar == 'L')
pp->leap = LEAP_ADDSECOND;
memcpy(&pp->refid, REFWWVB, 4);
- if (up->msgcnt == 0)
- record_clock_stats(&peer->srcadr, str);
up->msgcnt++;
break;
@@ -613,319 +895,17 @@ acts_timecode(
*/
peer->refid = pp->refid;
pp->lastrec = up->tstamp;
- if (!refclock_process(pp)) {
- refclock_report(peer, CEVNT_BADTIME);
- return;
- }
- pp->lastref = pp->lastrec;
- if (peer->disp > MAXDISTANCE)
- refclock_receive(peer);
- if (up->state != S_MSG) {
- up->state = S_MSG;
- up->timer = TIMECODE;
- }
-}
-
-
-/*
- * acts_poll - called by the transmit routine
- */
-static void
-acts_poll (
- int unit,
- struct peer *peer
- )
-{
- struct actsunit *up;
- struct refclockproc *pp;
-
- /*
- * This routine is called at every system poll. All it does is
- * set flag1 under certain conditions. The real work is done by
- * the timeout routine and state machine.
- */
- pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
- switch (peer->ttl) {
-
- /*
- * In manual mode the calling program is activated by the ntpdc
- * program using the enable flag (fudge flag1), either manually
- * or by a cron job.
- */
- case MODE_MANUAL:
- /* fall through */
- break;
-
- /*
- * In automatic mode the calling program runs continuously at
- * intervals determined by the poll event or specified timeout.
- */
- case MODE_AUTO:
- pp->sloppyclockflag |= CLK_FLAG1;
- break;
-
- /*
- * In backup mode the calling program runs continuously as long
- * as either no peers are available or this peer is selected.
- */
- case MODE_BACKUP:
- if (sys_peer == NULL || sys_peer == peer)
- pp->sloppyclockflag |= CLK_FLAG1;
- break;
- }
-}
-
-
-/*
- * acts_timer - called at one-second intervals
- */
-static void
-acts_timer(
- int unit,
- struct peer *peer
- )
-{
- struct actsunit *up;
- struct refclockproc *pp;
-
- /*
- * This routine implments a timeout which runs for a programmed
- * interval. The counter is initialized by the state machine and
- * counts down to zero. Upon reaching zero, the state machine is
- * called. If flag1 is set while in S_IDLE state, force a
- * timeout.
- */
- pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
- if (pp->sloppyclockflag & CLK_FLAG1 && up->state == S_IDLE) {
- acts_timeout(peer);
- return;
- }
- if (up->timer == 0)
- return;
-
- up->timer--;
- if (up->timer == 0)
- acts_timeout(peer);
-}
-
-
-/*
- * acts_timeout - called on timeout
- */
-static void
-acts_timeout(
- struct peer *peer
- )
-{
- struct actsunit *up;
- struct refclockproc *pp;
- int fd;
- char device[20];
- char lockfile[128], pidbuf[8];
- char tbuf[BMAX];
-
- /*
- * The state machine is driven by messages from the modem, when
- * first stated and at timeout.
- */
- pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
- pp->sloppyclockflag &= ~CLK_FLAG1;
- if (sys_phone[up->retry] == NULL && !(pp->sloppyclockflag &
- CLK_FLAG3)) {
- msyslog(LOG_ERR, "acts: no phones");
- return;
- }
- switch(up->state) {
-
- /*
- * System poll event. Lock the modem port and open the device.
- */
- case S_IDLE:
-
- /*
- * Lock the modem port. If busy, retry later. Note: if
- * something fails between here and the close, the lock
- * file may not be removed.
- */
- if (pp->sloppyclockflag & CLK_FLAG2) {
- sprintf(lockfile, LOCKFILE, up->unit);
- fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
- 0644);
- if (fd < 0) {
- msyslog(LOG_ERR, "acts: port busy");
- return;
- }
- sprintf(pidbuf, "%d\n", (u_int)getpid());
- write(fd, pidbuf, strlen(pidbuf));
- close(fd);
- }
-
- /*
- * Open the device in raw mode and link the I/O.
- */
- if (!pp->io.fd) {
- sprintf(device, DEVICE, up->unit);
- fd = refclock_open(device, SPEED232,
- LDISC_ACTS | LDISC_RAW | LDISC_REMOTE);
- if (fd == 0) {
- return;
- }
- pp->io.fd = fd;
- if (!io_addclock(&pp->io)) {
- msyslog(LOG_ERR,
- "acts: addclock fails");
- close(fd);
- pp->io.fd = 0;
- return;
- }
- }
-
- /*
- * If the port is directly connected to the device, skip
- * the modem business and send 'T' for Spectrabum.
- */
- if (pp->sloppyclockflag & CLK_FLAG3) {
- if (write(pp->io.fd, "T", 1) < 0) {
- msyslog(LOG_ERR, "acts: write %m");
- return;
- }
- up->state = S_FIRST;
- up->timer = CONNECT;
- return;
- }
-
- /*
- * Initialize the modem. This works with Hayes commands.
- */
-#ifdef DEBUG
- if (debug)
- printf("acts: setup %s\n", MODEM_SETUP);
-#endif
- if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) <
- 0) {
- msyslog(LOG_ERR, "acts: write %m");
- return;
- }
- up->state = S_OK;
- up->timer = SETUP;
- return;
-
- /*
- * In OK state the modem did not respond to setup.
- */
- case S_OK:
- msyslog(LOG_ERR, "acts: no modem");
- break;
-
- /*
- * In DTR state we are waiting for the modem to settle down
- * before hammering it with a dial command.
- */
- case S_DTR:
- sprintf(tbuf, "DIAL #%d %s", up->retry,
- sys_phone[up->retry]);
- record_clock_stats(&peer->srcadr, tbuf);
-#ifdef DEBUG
- if (debug)
- printf("%s\n", tbuf);
-#endif
- write(pp->io.fd, sys_phone[up->retry],
- strlen(sys_phone[up->retry]));
- write(pp->io.fd, "\r", 1);
- up->state = S_CONNECT;
- up->timer = ANSWER;
+ if (up->msgcnt == 0)
return;
- /*
- * In CONNECT state the call did not complete.
- */
- case S_CONNECT:
- msyslog(LOG_ERR, "acts: no answer");
- break;
-
- /*
- * In FIRST state no messages were received.
- */
- case S_FIRST:
- msyslog(LOG_ERR, "acts: no messages");
- break;
-
- /*
- * In CLOSE state hangup is complete. Close the doors and
- * windows and get some air.
- */
- case S_CLOSE:
-
- /*
- * Close the device and unlock a shared modem.
- */
- if (pp->io.fd) {
- io_closeclock(&pp->io);
- close(pp->io.fd);
- if (pp->sloppyclockflag & CLK_FLAG2) {
- sprintf(lockfile, LOCKFILE, up->unit);
- unlink(lockfile);
- }
- pp->io.fd = 0;
- }
-
- /*
- * If messages were received, fold the tent and wait for
- * the next poll. If no messages and there are more
- * numbers to dial, retry after a short wait.
- */
- up->bufptr = pp->a_lastcode;
- up->timer = 0;
- up->state = S_IDLE;
- if ( up->msgcnt == 0) {
- up->retry++;
- if (sys_phone[up->retry] == NULL)
- up->retry = 0;
- else
- up->timer = SETUP;
- } else {
- up->retry = 0;
- }
- up->msgcnt = 0;
+ strlcpy(pp->a_lastcode, str, sizeof(pp->a_lastcode));
+ pp->lencode = strlen(pp->a_lastcode);
+ if (!refclock_process(pp)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
- acts_disc(peer);
-}
-
-
-/*
- * acts_disc - disconnect the call and clean the place up.
- */
-static void
-acts_disc (
- struct peer *peer
- )
-{
- struct actsunit *up;
- struct refclockproc *pp;
- int dtr = TIOCM_DTR;
-
- /*
- * We get here if the call terminated successfully or if an
- * error occured. If the median filter has something in it,feed
- * the data to the clock filter. If a modem port, drop DTR to
- * force command mode and send modem hangup.
- */
- pp = peer->procptr;
- up = (struct actsunit *)pp->unitptr;
- if (up->msgcnt > 0)
- refclock_receive(peer);
- if (!(pp->sloppyclockflag & CLK_FLAG3)) {
- ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr);
- write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP));
- }
- up->timer = SETUP;
- up->state = S_CLOSE;
+ pp->lastref = pp->lastrec;
}
-
#else
int refclock_acts_bs;
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_arbiter.c b/contrib/ntp/ntpd/refclock_arbiter.c
index 88a3225..738be50 100644
--- a/contrib/ntp/ntpd/refclock_arbiter.c
+++ b/contrib/ntp/ntpd/refclock_arbiter.c
@@ -17,6 +17,12 @@
#include <stdio.h>
#include <ctype.h>
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets) async_write(fd, data, octets)
+#endif
+
/*
* This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
* The claimed accuracy of this clock is 100 ns relative to the PPS
@@ -97,6 +103,15 @@
#define MAXSTA 40 /* max length of status string */
#define MAXPOS 80 /* max length of position string */
+#ifdef PRE_NTP420
+#define MODE ttlmax
+#else
+#define MODE ttl
+#endif
+
+#define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" )
+#define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" )
+
/*
* ARB unit control structure
*/
@@ -111,10 +126,10 @@ struct arbunit {
/*
* Function prototypes
*/
-static int arb_start P((int, struct peer *));
-static void arb_shutdown P((int, struct peer *));
-static void arb_receive P((struct recvbuf *));
-static void arb_poll P((int, struct peer *));
+static int arb_start (int, struct peer *);
+static void arb_shutdown (int, struct peer *);
+static void arb_receive (struct recvbuf *);
+static void arb_poll (int, struct peer *);
/*
* Transfer vector
@@ -147,29 +162,27 @@ arb_start(
/*
* Open serial port. Use CLK line discipline, if available.
*/
- (void)sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, SPEED232, LDISC_CLK);
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct arbunit *)emalloc(sizeof(struct arbunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct arbunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = arb_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -177,7 +190,17 @@ arb_start(
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, REFID, 4);
- write(pp->io.fd, "B0", 2);
+ if (peer->MODE > 1) {
+ msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE);
+ close(fd);
+ pp->io.fd = -1;
+ free(up);
+ return (0);
+ }
+#ifdef DEBUG
+ if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); }
+#endif
+ write(pp->io.fd, COMMAND_HALT_BCAST, 2);
return (1);
}
@@ -195,9 +218,11 @@ arb_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct arbunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -220,10 +245,10 @@ arb_receive(
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct arbunit *)pp->unitptr;
- temp = refclock_gtlin(rbufp, tbuf, BMAX, &trtmp);
+ up = pp->unitptr;
+ temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp);
/*
* Note we get a buffer and timestamp for both a <cr> and <lf>,
@@ -264,39 +289,40 @@ arb_receive(
return;
} else if (!strncmp(tbuf, "SR", 2)) {
- strcpy(up->status, tbuf + 2);
+ strlcpy(up->status, tbuf + 2,
+ sizeof(up->status));
if (pp->sloppyclockflag & CLK_FLAG4)
write(pp->io.fd, "LA", 2);
else
- write(pp->io.fd, "B5", 2);
+ write(pp->io.fd, COMMAND_START_BCAST, 2);
return;
} else if (!strncmp(tbuf, "LA", 2)) {
- strcpy(up->latlon, tbuf + 2);
+ strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon));
write(pp->io.fd, "LO", 2);
return;
} else if (!strncmp(tbuf, "LO", 2)) {
- strcat(up->latlon, " ");
- strcat(up->latlon, tbuf + 2);
+ strlcat(up->latlon, " ", sizeof(up->latlon));
+ strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
write(pp->io.fd, "LH", 2);
return;
} else if (!strncmp(tbuf, "LH", 2)) {
- strcat(up->latlon, " ");
- strcat(up->latlon, tbuf + 2);
+ strlcat(up->latlon, " ", sizeof(up->latlon));
+ strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
write(pp->io.fd, "DB", 2);
return;
} else if (!strncmp(tbuf, "DB", 2)) {
- strcat(up->latlon, " ");
- strcat(up->latlon, tbuf + 2);
+ strlcat(up->latlon, " ", sizeof(up->latlon));
+ strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
record_clock_stats(&peer->srcadr, up->latlon);
#ifdef DEBUG
if (debug)
printf("arbiter: %s\n", up->latlon);
#endif
- write(pp->io.fd, "B5", 2);
+ write(pp->io.fd, COMMAND_START_BCAST, 2);
}
}
@@ -316,16 +342,16 @@ arb_receive(
/*
* Timecode format B5: "i yy ddd hh:mm:ss.000 "
*/
- strncpy(pp->a_lastcode, tbuf, BMAX);
+ strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode));
pp->a_lastcode[LENARB - 2] = up->qualchar;
- strcat(pp->a_lastcode, up->status);
+ strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode));
pp->lencode = strlen(pp->a_lastcode);
syncchar = ' ';
if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
&syncchar, &pp->year, &pp->day, &pp->hour,
&pp->minute, &pp->second) != 6) {
refclock_report(peer, CEVNT_BADREPLY);
- write(pp->io.fd, "B0", 2);
+ write(pp->io.fd, COMMAND_HALT_BCAST, 2);
return;
}
@@ -375,13 +401,13 @@ arb_receive(
case 'F': /* clock failure */
pp->disp = MAXDISPERSE;
refclock_report(peer, CEVNT_FAULT);
- write(pp->io.fd, "B0", 2);
+ write(pp->io.fd, COMMAND_HALT_BCAST, 2);
return;
default:
pp->disp = MAXDISPERSE;
refclock_report(peer, CEVNT_BADREPLY);
- write(pp->io.fd, "B0", 2);
+ write(pp->io.fd, COMMAND_HALT_BCAST, 2);
return;
}
if (syncchar != ' ')
@@ -398,9 +424,9 @@ arb_receive(
else if (peer->disp > MAXDISTANCE)
refclock_receive(peer);
- if (up->tcswitch >= MAXSTAGE) {
- write(pp->io.fd, "B0", 2);
- }
+ /* if (up->tcswitch >= MAXSTAGE) { */
+ write(pp->io.fd, COMMAND_HALT_BCAST, 2);
+ /* } */
}
@@ -425,7 +451,7 @@ arb_poll(
* need poll the clock; all others just listen in.
*/
pp = peer->procptr;
- up = (struct arbunit *)pp->unitptr;
+ up = pp->unitptr;
pp->polls++;
up->tcswitch = 0;
if (write(pp->io.fd, "TQ", 2) != 2)
diff --git a/contrib/ntp/ntpd/refclock_arc.c b/contrib/ntp/ntpd/refclock_arc.c
index af80621..e5d4cb4 100644
--- a/contrib/ntp/ntpd/refclock_arc.c
+++ b/contrib/ntp/ntpd/refclock_arc.c
@@ -6,6 +6,8 @@
#include <config.h>
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF)
static const char arc_version[] = { "V1.3 2003/02/21" };
@@ -138,27 +140,27 @@ GENERAL
2) PRECISION should be -4/-5 (63ms/31ms) for the following reasons:
a) The ARC documentation claims the internal clock is (only)
- accurate to about 20ms relative to Rugby (plus there must be
- noticable drift and delay in the ms range due to transmission
- delays and changing atmospheric effects). This clock is not
- designed for ms accuracy as NTP has spoilt us all to expect.
+ accurate to about 20ms relative to Rugby (plus there must be
+ noticable drift and delay in the ms range due to transmission
+ delays and changing atmospheric effects). This clock is not
+ designed for ms accuracy as NTP has spoilt us all to expect.
b) The clock oscillator looks like a simple uncompensated quartz
- crystal of the sort used in digital watches (ie 32768Hz) which
- can have large temperature coefficients and drifts; it is not
- clear if this oscillator is properly disciplined to the MSF
- transmission, but as the default is to resync only once per
- *day*, we can imagine that it is not, and is free-running. We
- can minimise drift by resyncing more often (at the cost of
- reduced battery life), but drift/wander may still be
- significant.
+ crystal of the sort used in digital watches (ie 32768Hz) which
+ can have large temperature coefficients and drifts; it is not
+ clear if this oscillator is properly disciplined to the MSF
+ transmission, but as the default is to resync only once per
+ *day*, we can imagine that it is not, and is free-running. We
+ can minimise drift by resyncing more often (at the cost of
+ reduced battery life), but drift/wander may still be
+ significant.
c) Note that the bit time of 3.3ms adds to the potential error in
- the the clock timestamp, since the bit clock of the serial link
- may effectively be free-running with respect to the host clock
- and the MSF clock. Actually, the error is probably 1/16th of
- the above, since the input data is probably sampled at at least
- 16x the bit rate.
+ the the clock timestamp, since the bit clock of the serial link
+ may effectively be free-running with respect to the host clock
+ and the MSF clock. Actually, the error is probably 1/16th of
+ the above, since the input data is probably sampled at at least
+ 16x the bit rate.
By keeping the clock marked as not very precise, it will have a
fairly large dispersion, and thus will tend to be used as a
@@ -178,9 +180,9 @@ GENERAL
IN ANY CASE, BE SURE TO SET AN APPROPRIATE FUDGE FACTOR TO REMOVE
ANY RESIDUAL SKEW, eg:
- server 127.127.27.0 # ARCRON MSF radio clock unit 0.
- # Fudge timestamps by about 20ms.
- fudge 127.127.27.0 time1 0.020
+ server 127.127.27.0 # ARCRON MSF radio clock unit 0.
+ # Fudge timestamps by about 20ms.
+ fudge 127.127.27.0 time1 0.020
You will need to observe your system's behaviour, assuming you have
some other NTP source to compare it with, to work out what the
@@ -317,28 +319,28 @@ You have to wait for character echo + 10ms before sending next character.
/* 12. year tens */
/* 13. year units */
/* 14. BST/UTC status */
-/* bit 7 parity */
-/* bit 6 always 0 */
-/* bit 5 always 1 */
-/* bit 4 always 1 */
-/* bit 3 always 0 */
-/* bit 2 =1 if UTC is in effect, complementary to the BST bit */
-/* bit 1 =1 if BST is in effect, according to the BST bit */
-/* bit 0 BST/UTC change impending bit=1 in case of change impending */
+/* bit 7 parity */
+/* bit 6 always 0 */
+/* bit 5 always 1 */
+/* bit 4 always 1 */
+/* bit 3 always 0 */
+/* bit 2 =1 if UTC is in effect, complementary to the BST bit */
+/* bit 1 =1 if BST is in effect, according to the BST bit */
+/* bit 0 BST/UTC change impending bit=1 in case of change impending */
/* 15. status */
-/* bit 7 parity */
-/* bit 6 always 0 */
-/* bit 5 always 1 */
-/* bit 4 always 1 */
-/* bit 3 =1 if low battery is detected */
-/* bit 2 =1 if the very last reception attempt failed and a valid */
-/* time information already exists (bit0=1) */
-/* =0 if the last reception attempt was successful */
-/* bit 1 =1 if at least one reception since 2:30 am was successful */
-/* =0 if no reception attempt since 2:30 am was successful */
-/* bit 0 =1 if the RC Computer Clock contains valid time information */
-/* This bit is zero after reset and one after the first */
-/* successful reception attempt */
+/* bit 7 parity */
+/* bit 6 always 0 */
+/* bit 5 always 1 */
+/* bit 4 always 1 */
+/* bit 3 =1 if low battery is detected */
+/* bit 2 =1 if the very last reception attempt failed and a valid */
+/* time information already exists (bit0=1) */
+/* =0 if the last reception attempt was successful */
+/* bit 1 =1 if at least one reception since 2:30 am was successful */
+/* =0 if no reception attempt since 2:30 am was successful */
+/* bit 0 =1 if the RC Computer Clock contains valid time information */
+/* This bit is zero after reset and one after the first */
+/* successful reception attempt */
/* DHD note:
Also note g<cr> command which confirms that a resync is in progress, and
@@ -375,15 +377,15 @@ Also note h<cr> command which starts a resync to MSF signal.
/*
* Interface definitions
*/
-#define DEVICE "/dev/arc%d" /* Device name and unit. */
-#define SPEED B300 /* UART speed (300 baud) */
-#define PRECISION (-4) /* Precision (~63 ms). */
-#define HIGHPRECISION (-5) /* If things are going well... */
-#define REFID "MSFa" /* Reference ID. */
-#define REFID_MSF "MSF" /* Reference ID. */
-#define REFID_DCF77 "DCF" /* Reference ID. */
-#define REFID_WWVB "WWVB" /* Reference ID. */
-#define DESCRIPTION "ARCRON MSF/DCF/WWVB Receiver"
+#define DEVICE "/dev/arc%d" /* Device name and unit. */
+#define SPEED B300 /* UART speed (300 baud) */
+#define PRECISION (-4) /* Precision (~63 ms). */
+#define HIGHPRECISION (-5) /* If things are going well... */
+#define REFID "MSFa" /* Reference ID. */
+#define REFID_MSF "MSF" /* Reference ID. */
+#define REFID_DCF77 "DCF" /* Reference ID. */
+#define REFID_WWVB "WWVB" /* Reference ID. */
+#define DESCRIPTION "ARCRON MSF/DCF/WWVB Receiver"
#ifdef PRE_NTP420
#define MODE ttlmax
@@ -391,18 +393,18 @@ Also note h<cr> command which starts a resync to MSF signal.
#define MODE ttl
#endif
-#define LENARC 16 /* Format `o' timecode length. */
+#define LENARC 16 /* Format `o' timecode length. */
-#define BITSPERCHAR 11 /* Bits per character. */
-#define BITTIME 0x0DA740E /* Time for 1 bit at 300bps. */
-#define CHARTIME10 0x8888888 /* Time for 10-bit char at 300bps. */
-#define CHARTIME11 0x962FC96 /* Time for 11-bit char at 300bps. */
-#define CHARTIME /* Time for char at 300bps. */ \
+#define BITSPERCHAR 11 /* Bits per character. */
+#define BITTIME 0x0DA740E /* Time for 1 bit at 300bps. */
+#define CHARTIME10 0x8888888 /* Time for 10-bit char at 300bps. */
+#define CHARTIME11 0x962FC96 /* Time for 11-bit char at 300bps. */
+#define CHARTIME /* Time for char at 300bps. */ \
( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \
(BITSPERCHAR * BITTIME) ) )
/* Allow for UART to accept char half-way through final stop bit. */
-#define INITIALOFFSET (u_int32)(-BITTIME/2)
+#define INITIALOFFSET ((u_int32)(-BITTIME/2))
/*
charoffsets[x] is the time after the start of the second that byte
@@ -457,12 +459,12 @@ Also note h<cr> command which starts a resync to MSF signal.
#endif
};
-#define DEFAULT_RESYNC_TIME (57*60) /* Gap between resync attempts (s). */
-#define RETRY_RESYNC_TIME (27*60) /* Gap to emergency resync attempt. */
+#define DEFAULT_RESYNC_TIME (57*60) /* Gap between resync attempts (s). */
+#define RETRY_RESYNC_TIME (27*60) /* Gap to emergency resync attempt. */
#ifdef ARCRON_KEEN
-#define INITIAL_RESYNC_DELAY 500 /* Delay before first resync. */
+#define INITIAL_RESYNC_DELAY 500 /* Delay before first resync. */
#else
-#define INITIAL_RESYNC_DELAY 50 /* Delay before first resync. */
+#define INITIAL_RESYNC_DELAY 50 /* Delay before first resync. */
#endif
static const int moff[12] =
@@ -470,30 +472,30 @@ Also note h<cr> command which starts a resync to MSF signal.
/* Flags for a raw open() of the clock serial device. */
#ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */
#define OPEN_FLAGS (O_RDWR | O_NOCTTY)
-#else /* Oh well, it may not matter... */
+#else /* Oh well, it may not matter... */
#define OPEN_FLAGS (O_RDWR)
#endif
/* Length of queue of command bytes to be sent. */
-#define CMDQUEUELEN 4 /* Enough for two cmds + each \r. */
+#define CMDQUEUELEN 4 /* Enough for two cmds + each \r. */
/* Queue tick time; interval in seconds between chars taken off queue. */
/* Must be >= 2 to allow o\r response to come back uninterrupted. */
-#define QUEUETICK 2 /* Allow o\r reply to finish. */
+#define QUEUETICK 2 /* Allow o\r reply to finish. */
/*
* ARC unit control structure
*/
struct arcunit {
- l_fp lastrec; /* Time tag for the receive time (system). */
- int status; /* Clock status. */
+ l_fp lastrec; /* Time tag for the receive time (system). */
+ int status; /* Clock status. */
- int quality; /* Quality of reception 0--5 for unit. */
+ int quality; /* Quality of reception 0--5 for unit. */
/* We may also use the values -1 or 6 internally. */
u_long quality_stamp; /* Next time to reset quality average. */
u_long next_resync; /* Next resync time (s) compared to current_time. */
- int resyncing; /* Resync in progress if true. */
+ int resyncing; /* Resync in progress if true. */
/* In the outgoing queue, cmdqueue[0] is next to be sent. */
char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */
@@ -527,11 +529,11 @@ static int possible_leap = 0; /* No resync required by default. */
#endif
#if 0
-static void dummy_event_handler P((struct peer *));
-static void arc_event_handler P((struct peer *));
+static void dummy_event_handler (struct peer *);
+static void arc_event_handler (struct peer *);
#endif /* 0 */
-#define QUALITY_UNKNOWN -1 /* Indicates unknown clock quality. */
+#define QUALITY_UNKNOWN -1 /* Indicates unknown clock quality. */
#define MIN_CLOCK_QUALITY 0 /* Min quality clock will return. */
#define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */
#define MAX_CLOCK_QUALITY 5 /* Max quality clock will return. */
@@ -539,28 +541,28 @@ static void arc_event_handler P((struct peer *));
/*
* Function prototypes
*/
-static int arc_start P((int, struct peer *));
-static void arc_shutdown P((int, struct peer *));
-static void arc_receive P((struct recvbuf *));
-static void arc_poll P((int, struct peer *));
+static int arc_start (int, struct peer *);
+static void arc_shutdown (int, struct peer *);
+static void arc_receive (struct recvbuf *);
+static void arc_poll (int, struct peer *);
/*
* Transfer vector
*/
struct refclock refclock_arc = {
- arc_start, /* start up driver */
- arc_shutdown, /* shut down driver */
- arc_poll, /* transmit poll message */
- noentry, /* not used (old arc_control) */
- noentry, /* initialize driver (not used) */
- noentry, /* not used (old arc_buginfo) */
- NOFLAGS /* not used */
+ arc_start, /* start up driver */
+ arc_shutdown, /* shut down driver */
+ arc_poll, /* transmit poll message */
+ noentry, /* not used (old arc_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old arc_buginfo) */
+ NOFLAGS /* not used */
};
/* Queue us up for the next tick. */
#define ENQUEUE(up) \
do { \
- peer->nextaction = current_time + QUEUETICK; \
+ peer->procptr->nextaction = current_time + QUEUETICK; \
} while(0)
/* Placeholder event handler---does nothing safely---soaks up loose tick. */
@@ -591,7 +593,7 @@ arc_event_handler(
)
{
struct refclockproc *pp = peer->procptr;
- register struct arcunit *up = (struct arcunit *)pp->unitptr;
+ register struct arcunit *up = pp->unitptr;
int i;
char c;
#ifdef DEBUG
@@ -627,48 +629,52 @@ arc_start(
{
register struct arcunit *up;
struct refclockproc *pp;
+ int temp_fd;
int fd;
char device[20];
#ifdef HAVE_TERMIOS
struct termios arg;
#endif
- msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit);
-#ifdef DEBUG
- if(debug) {
- printf("arc: %s: attempt to open unit %d.\n", arc_version, unit);
- }
-#endif
-
- /* Prevent a ridiculous device number causing overflow of device[]. */
- if((unit < 0) || (unit > 255)) { return(0); }
+ msyslog(LOG_NOTICE, "MSF_ARCRON %s: opening unit %d",
+ arc_version, unit);
+ DPRINTF(1, ("arc: %s: attempt to open unit %d.\n", arc_version,
+ unit));
/*
* Open serial port. Use CLK line discipline, if available.
*/
- (void)sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED, LDISC_CLK)))
- return(0);
-#ifdef DEBUG
- if(debug) { printf("arc: unit %d using open().\n", unit); }
-#endif
- fd = open(device, OPEN_FLAGS);
- if(fd < 0) {
-#ifdef DEBUG
- if(debug) { printf("arc: failed [open()] to open %s.\n", device); }
-#endif
- return(0);
+ snprintf(device, sizeof(device), DEVICE, unit);
+ temp_fd = refclock_open(device, SPEED, LDISC_CLK);
+ if (temp_fd <= 0)
+ return 0;
+ DPRINTF(1, ("arc: unit %d using tty_open().\n", unit));
+ fd = tty_open(device, OPEN_FLAGS, 0777);
+ if (fd < 0) {
+ msyslog(LOG_ERR, "MSF_ARCRON(%d): failed second open(%s, 0777): %m.",
+ unit, device);
+ close(temp_fd);
+ return 0;
}
+ close(temp_fd);
+ temp_fd = -1;
+
+#ifndef SYS_WINNT
+ if (-1 == fcntl(fd, F_SETFL, 0)) /* clear the descriptor flags */
+ msyslog(LOG_ERR, "MSF_ARCRON(%d): fcntl(F_SETFL, 0): %m.",
+ unit);
- fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */
-#ifdef DEBUG
- if(debug)
- { printf("arc: opened RS232 port with file descriptor %d.\n", fd); }
#endif
+ DPRINTF(1, ("arc: opened RS232 port with file descriptor %d.\n", fd));
#ifdef HAVE_TERMIOS
- tcgetattr(fd, &arg);
+ if (tcgetattr(fd, &arg) < 0) {
+ msyslog(LOG_ERR, "MSF_ARCRON(%d): tcgetattr(%s): %m.",
+ unit, device);
+ close(fd);
+ return 0;
+ }
arg.c_iflag = IGNBRK | ISTRIP;
arg.c_oflag = 0;
@@ -677,28 +683,36 @@ arc_start(
arg.c_cc[VMIN] = 1;
arg.c_cc[VTIME] = 0;
- tcsetattr(fd, TCSANOW, &arg);
+ if (tcsetattr(fd, TCSANOW, &arg) < 0) {
+ msyslog(LOG_ERR, "MSF_ARCRON(%d): tcsetattr(%s): %m.",
+ unit, device);
+ close(fd);
+ return 0;
+ }
#else
- msyslog(LOG_ERR, "ARCRON: termios not supported in this driver");
+ msyslog(LOG_ERR, "ARCRON: termios required by this driver");
(void)close(fd);
return 0;
#endif
- up = (struct arcunit *) emalloc(sizeof(struct arcunit));
- if(!up) { (void) close(fd); return(0); }
/* Set structure to all zeros... */
- memset((char *)up, 0, sizeof(struct arcunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = arc_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
- if(!io_addclock(&pp->io)) { (void) close(fd); free(up); return(0); }
- pp->unitptr = (caddr_t)up;
+ if (!io_addclock(&pp->io)) {
+ close(fd);
+ pp->io.fd = -1;
+ free(up);
+ return(0);
+ }
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -746,7 +760,7 @@ arc_start(
up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */
#endif
- peer->action = arc_event_handler;
+ peer->procptr->action = arc_event_handler;
ENQUEUE(up);
@@ -766,12 +780,14 @@ arc_shutdown(
register struct arcunit *up;
struct refclockproc *pp;
- peer->action = dummy_event_handler;
+ peer->procptr->action = dummy_event_handler;
pp = peer->procptr;
- up = (struct arcunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
/*
@@ -812,9 +828,9 @@ send_slow(
if(spaceleft < sl) { /* Should not normally happen... */
#ifdef DEBUG
msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)",
- sl, spaceleft);
+ sl, spaceleft);
#endif
- return(0); /* FAILED! */
+ return(0); /* FAILED! */
}
/* Copy in the command to be sent. */
@@ -827,7 +843,7 @@ send_slow(
static int
get2(char *p, int *val)
{
- if (!isdigit((int)p[0]) || !isdigit((int)p[1])) return 0;
+ if (!isdigit((unsigned char)p[0]) || !isdigit((unsigned char)p[1])) return 0;
*val = (p[0] - '0') * 10 + p[1] - '0';
return 1;
}
@@ -835,7 +851,7 @@ get2(char *p, int *val)
static int
get1(char *p, int *val)
{
- if (!isdigit((int)p[0])) return 0;
+ if (!isdigit((unsigned char)p[0])) return 0;
*val = p[0] - '0';
return 1;
}
@@ -846,10 +862,10 @@ get1(char *p, int *val)
(((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \
"OK, will use clock"))
- /*
+/*
* arc_receive - receive data from the serial interface
*/
- static void
+static void
arc_receive(
struct recvbuf *rbufp
)
@@ -867,9 +883,9 @@ arc_receive(
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct arcunit *)pp->unitptr;
+ up = pp->unitptr;
/*
@@ -927,7 +943,7 @@ arc_receive(
#ifdef DEBUG
if(debug) { /* Show \r as `R', other non-printing char as `?'. */
printf("arc: stamp -->%c<-- (%d chars rcvd)\n",
- ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')),
+ ((c == '\r') ? 'R' : (isgraph((unsigned char)c) ? c : '?')),
rbufp->recv_length);
}
#endif
@@ -992,7 +1008,7 @@ arc_receive(
diff = up->lastrec;
L_SUB(&diff, &timestamp);
printf("arc: adjusted timestamp by -%sms.\n",
- mfptoms(diff.l_i, diff.l_f, 3));
+ mfptoms(diff.l_ui, diff.l_uf, 3));
}
#endif
}
@@ -1005,7 +1021,7 @@ arc_receive(
/* Just in case we still have lots of rubbish in the buffer... */
/* ...and to avoid the same timestamp being reused by mistake, */
/* eg on receipt of the \r coming in on its own after the */
- /* timecode. */
+ /* timecode. */
if(pp->lencode >= LENARC) {
#ifdef DEBUG
if(debug && (rbufp->recv_buffer[0] != '\r'))
@@ -1083,9 +1099,9 @@ arc_receive(
}
#endif
msyslog(LOG_NOTICE,
- "ARCRON: sync finished, signal quality %d: %s",
- up->quality,
- quality_action(up->quality));
+ "ARCRON: sync finished, signal quality %d: %s",
+ up->quality,
+ quality_action(up->quality));
up->resyncing = 0; /* Resync is over. */
quality_average = 0;
quality_sum = 0;
@@ -1210,7 +1226,7 @@ arc_receive(
if(pp->year >= YEAR_PIVOT+2000-2 ) { /* Y2KFixes */
/*This should get attention B^> */
msyslog(LOG_NOTICE,
- "ARCRON: fix me! EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
+ "ARCRON: fix me! EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
}
#ifdef DEBUG
if(debug) {
@@ -1271,50 +1287,52 @@ arc_receive(
if(peer->MODE > 0) {
if(pp->sloppyclockflag & CLK_FLAG1) {
struct tm local;
- struct tm *gmtp;
- time_t unixtime;
+ struct tm *gmtp;
+ time_t unixtime;
- /*
- * Convert to GMT for sites that distribute localtime.
+ /*
+ * Convert to GMT for sites that distribute localtime.
* This means we have to do Y2K conversion on the
* 2-digit year; otherwise, we get the time wrong.
- */
-
+ */
+
+ memset(&local, 0, sizeof(local));
+
local.tm_year = pp->year-1900;
- local.tm_mon = month-1;
- local.tm_mday = pp->day;
- local.tm_hour = pp->hour;
- local.tm_min = pp->minute;
- local.tm_sec = pp->second;
- switch (peer->MODE) {
+ local.tm_mon = month-1;
+ local.tm_mday = pp->day;
+ local.tm_hour = pp->hour;
+ local.tm_min = pp->minute;
+ local.tm_sec = pp->second;
+ switch (peer->MODE) {
case 1:
local.tm_isdst = (flags & 2);
break;
case 2:
- local.tm_isdst = (flags & 2);
+ local.tm_isdst = (flags & 2);
break;
case 3:
switch (flags & 3) {
case 0: /* It is unclear exactly when the
- Arcron changes from DST->ST and
+ Arcron changes from DST->ST and
ST->DST. Testing has shown this
to be irregular. For the time
being, let the OS decide. */
- local.tm_isdst = 0;
+ local.tm_isdst = 0;
#ifdef DEBUG
if (debug)
printf ("arc: DST = 00 (0)\n");
#endif
break;
case 1: /* dst->st time */
- local.tm_isdst = -1;
+ local.tm_isdst = -1;
#ifdef DEBUG
if (debug)
printf ("arc: DST = 01 (1)\n");
#endif
break;
case 2: /* st->dst time */
- local.tm_isdst = -1;
+ local.tm_isdst = -1;
#ifdef DEBUG
if (debug)
printf ("arc: DST = 10 (2)\n");
@@ -1331,26 +1349,26 @@ arc_receive(
break;
default:
msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d",
- peer->MODE);
+ peer->MODE);
return;
break;
}
- unixtime = mktime (&local);
- if ((gmtp = gmtime (&unixtime)) == NULL)
- {
+ unixtime = mktime (&local);
+ if ((gmtp = gmtime (&unixtime)) == NULL)
+ {
pp->lencode = 0;
- refclock_report (peer, CEVNT_FAULT);
- return;
- }
+ refclock_report (peer, CEVNT_FAULT);
+ return;
+ }
pp->year = gmtp->tm_year+1900;
- month = gmtp->tm_mon+1;
- pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
- /* pp->day = gmtp->tm_yday; */
- pp->hour = gmtp->tm_hour;
- pp->minute = gmtp->tm_min;
- pp->second = gmtp->tm_sec;
+ month = gmtp->tm_mon+1;
+ pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
+ /* pp->day = gmtp->tm_yday; */
+ pp->hour = gmtp->tm_hour;
+ pp->minute = gmtp->tm_min;
+ pp->second = gmtp->tm_sec;
#ifdef DEBUG
- if (debug)
+ if (debug)
{
printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
pp->year,month,gmtp->tm_mday,pp->hour,pp->minute,
@@ -1359,10 +1377,10 @@ arc_receive(
#endif
} else
{
- /*
- * For more rational sites distributing UTC
- */
- pp->day = ymd2yd(pp->year,month,pp->day);
+ /*
+ * For more rational sites distributing UTC
+ */
+ pp->day = ymd2yd(pp->year,month,pp->day);
}
}
@@ -1391,10 +1409,10 @@ arc_receive(
if(up->saved_flags != pp->sloppyclockflag) {
#ifdef DEBUG
msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
- ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
- ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
- ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
- ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
+ ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
+ ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
+ ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
+ ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
/* Note effects of flags changing... */
if(debug) {
printf("arc: PRECISION = %d.\n", peer->precision);
@@ -1436,7 +1454,7 @@ arc_receive(
/* request_time() sends a time request to the clock with given peer. */
/* This automatically reports a fault if necessary. */
/* No data should be sent after this until arc_poll() returns. */
-static void request_time P((int, struct peer *));
+static void request_time (int, struct peer *);
static void
request_time(
int unit,
@@ -1444,7 +1462,7 @@ request_time(
)
{
struct refclockproc *pp = peer->procptr;
- register struct arcunit *up = (struct arcunit *)pp->unitptr;
+ register struct arcunit *up = pp->unitptr;
#ifdef DEBUG
if(debug) { printf("arc: unit %d: requesting time.\n", unit); }
#endif
@@ -1475,7 +1493,7 @@ arc_poll(
int resync_needed; /* Should we start a resync? */
pp = peer->procptr;
- up = (struct arcunit *)pp->unitptr;
+ up = pp->unitptr;
#if 0
pp->lencode = 0;
memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode));
@@ -1565,5 +1583,5 @@ arc_poll(
}
#else
-int refclock_arc_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif
diff --git a/contrib/ntp/ntpd/refclock_as2201.c b/contrib/ntp/ntpd/refclock_as2201.c
index f04d417b..1acf9b2 100644
--- a/contrib/ntp/ntpd/refclock_as2201.c
+++ b/contrib/ntp/ntpd/refclock_as2201.c
@@ -129,10 +129,10 @@ static char stat_command[][30] = {
/*
* Function prototypes
*/
-static int as2201_start P((int, struct peer *));
-static void as2201_shutdown P((int, struct peer *));
-static void as2201_receive P((struct recvbuf *));
-static void as2201_poll P((int, struct peer *));
+static int as2201_start (int, struct peer *);
+static void as2201_shutdown (int, struct peer *);
+static void as2201_receive (struct recvbuf *);
+static void as2201_poll (int, struct peer *);
/*
* Transfer vector
@@ -165,36 +165,32 @@ as2201_start(
/*
* Open serial port. Use CLK line discipline, if available.
*/
- (void)sprintf(gpsdev, DEVICE, unit);
- if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_CLK)))
+ snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
+ fd = refclock_open(gpsdev, SPEED232, LDISC_CLK);
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct as2201unit *)
- emalloc(sizeof(struct as2201unit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct as2201unit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = as2201_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
*/
peer->precision = PRECISION;
- peer->burst = NSTAGE;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, REFID, 4);
up->lastptr = up->stats;
@@ -216,9 +212,11 @@ as2201_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct as2201unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -234,13 +232,14 @@ as2201_receive(
struct refclockproc *pp;
struct peer *peer;
l_fp trtmp;
+ size_t octets;
/*
* Initialize pointers and read the timecode and timestamp.
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct as2201unit *)pp->unitptr;
+ up = pp->unitptr;
pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
#ifdef DEBUG
if (debug)
@@ -268,7 +267,7 @@ as2201_receive(
if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2)
return;
*up->lastptr++ = ' ';
- (void)strcpy(up->lastptr, pp->a_lastcode);
+ memcpy(up->lastptr, pp->a_lastcode, 1 + pp->lencode);
up->lastptr += pp->lencode;
return;
} else {
@@ -329,13 +328,17 @@ as2201_receive(
* send the next command. If not, simply write the timecode to
* the clockstats file.
*/
- (void)strcpy(up->lastptr, pp->a_lastcode);
+ if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2)
+ return;
+ memcpy(up->lastptr, pp->a_lastcode, pp->lencode);
up->lastptr += pp->lencode;
if (pp->sloppyclockflag & CLK_FLAG4) {
+ octets = strlen(stat_command[up->index]);
+ if ((int)(up->lastptr - up->stats + 1 + octets) > SMAX - 2)
+ return;
*up->lastptr++ = ' ';
- (void)strcpy(up->lastptr, stat_command[up->index]);
- up->lastptr += strlen(stat_command[up->index]);
- up->lastptr--;
+ memcpy(up->lastptr, stat_command[up->index], octets);
+ up->lastptr += octets - 1;
*up->lastptr = '\0';
(void)write(pp->io.fd, stat_command[up->index],
strlen(stat_command[up->index]));
@@ -373,14 +376,11 @@ as2201_poll(
if (!(pp->sloppyclockflag & CLK_FLAG2))
get_systime(&pp->lastrec);
}
- if (peer->burst > 0)
- return;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
}
refclock_receive(peer);
- peer->burst = NSTAGE;
}
#else
diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c
index 2e469ec..b3c0d6b 100644
--- a/contrib/ntp/ntpd/refclock_atom.c
+++ b/contrib/ntp/ntpd/refclock_atom.c
@@ -14,21 +14,23 @@
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
-#if defined(REFCLOCK) && defined(CLOCK_ATOM)
-
-#ifdef HAVE_PPSAPI
-# include "ppsapi_timepps.h"
-#endif /* HAVE_PPSAPI */
+/*
+ * This driver requires the PPSAPI interface (RFC 2783)
+ */
+#if defined(REFCLOCK) && defined(CLOCK_ATOM) && defined(HAVE_PPSAPI)
+#include "ppsapi_timepps.h"
+#include "refclock_atom.h"
/*
* This driver furnishes an interface for pulse-per-second (PPS) signals
* produced by a cesium clock, timing receiver or related equipment. It
- * can be used to remove accumulated jitter and retime a secondary
- * server when synchronized to a primary server over a congested, wide-
- * area network and before redistributing the time to local clients.
+ * can be used to remove accumulated jitter over a congested link and
+ * retime a server before redistributing the time to clients. It can
+ *also be used as a holdover should all other synchronization sources
+ * beconme unreachable.
*
* Before this driver becomes active, the local clock must be set to
- * within +-500 ms by another means, such as a radio clock or NTP
+ * within +-0.4 s by another means, such as a radio clock or NTP
* itself. There are two ways to connect the PPS signal, normally at TTL
* levels, to the computer. One is to shift to EIA levels and connect to
* pin 8 (DCD) of a serial port. This requires a level converter and
@@ -36,27 +38,13 @@
* to connect the PPS signal directly to pin 10 (ACK) of a PC paralell
* port. These methods are architecture dependent.
*
- * Both methods require a modified device driver and kernel interface
- * compatible with the Pulse-per-Second API for Unix-like Operating
+ * This driver requires the Pulse-per-Second API for Unix-like Operating
* Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are
- * available for FreeBSD, Linux, SunOS, Solaris and Alpha. However, at
- * present only the Alpha implementation provides the full generality of
+ * available for FreeBSD, Linux, SunOS, Solaris and Tru64. However, at
+ * present only the Tru64 implementation provides the full generality of
* the API with multiple PPS drivers and multiple handles per driver. If
* the PPSAPI is normally implemented in the /usr/include/sys/timepps.h
* header file and kernel support specific to each operating system.
- * However, this driver can operate without this interface if means are
- * proviced to call the pps_sample() routine from another driver. Please
- * note; if the PPSAPI interface is present, it must be used.
- *
- * In many configurations a single port is used for the radio timecode
- * and PPS signal. In order to provide for this configuration and others
- * involving dedicated multiple serial/parallel ports, the driver first
- * attempts to open the device /dev/pps%d, where %d is the unit number.
- * If this fails, the driver attempts to open the device specified by
- * the pps configuration command. If a port is to be shared, the pps
- * command must be placed before the radio device(s) and the radio
- * device(s) must be placed before the PPS driver(s) in the
- * configuration file.
*
* This driver normally uses the PLL/FLL clock discipline implemented in
* the ntpd code. Ordinarily, this is the most accurate means, as the
@@ -65,80 +53,62 @@
* to hundreds of PPM), it's better to used the kernel support, if
* available.
*
+ * This deriver is subject to the mitigation rules described in the
+ * "mitigation rulse and the prefer peer" page. However, there is an
+ * important difference. If this driver becomes the PPS driver according
+ * to these rules, it is acrive only if (a) a prefer peer other than
+ * this driver is among the survivors or (b) there are no survivors and
+ * the minsane option of the tos command is zero. This is intended to
+ * support space missions where updates from other spacecraft are
+ * infrequent, but a reliable PPS signal, such as from an Ultra Stable
+ * Oscillator (USO) is available.
+ *
* Fudge Factors
*
- * If flag2 is dim (default), the on-time epoch is the assert edge of
- * the PPS signal; if lit, the on-time epoch is the clear edge. If flag2
- * is lit, the assert edge is used; if flag3 is dim (default), the
- * kernel PPS support is disabled; if lit it is enabled. The time1
- * parameter can be used to compensate for miscellaneous device driver
- * and OS delays.
+ * The PPS timestamp is captured on the rising (assert) edge if flag2 is
+ * dim (default) and on the falling (clear) edge if lit. If flag3 is dim
+ * (default), the kernel PPS support is disabled; if lit it is enabled.
+ * If flag4 is lit, each timesampt is copied to the clockstats file for
+ * later analysis. This can be useful when constructing Allan deviation
+ * plots. The time1 parameter can be used to compensate for
+ * miscellaneous device driver and OS delays.
*/
/*
* Interface definitions
*/
-#ifdef HAVE_PPSAPI
#define DEVICE "/dev/pps%d" /* device name and unit */
-#endif /* HAVE_PPSAPI */
-
#define PRECISION (-20) /* precision assumed (about 1 us) */
#define REFID "PPS\0" /* reference ID */
#define DESCRIPTION "PPS Clock Discipline" /* WRU */
-#define NANOSECOND 1000000000 /* one second (ns) */
-#define RANGEGATE 500000 /* range gate (ns) */
-static struct peer *pps_peer; /* atom driver for PPS sources */
-
-#ifdef HAVE_PPSAPI
/*
* PPS unit control structure
*/
struct ppsunit {
- struct timespec ts; /* last timestamp */
- int fddev; /* pps device descriptor */
- pps_params_t pps_params; /* pps parameters */
- pps_info_t pps_info; /* last pps data */
- pps_handle_t handle; /* pps handlebars */
+ struct refclock_atom atom; /* atom structure pointer */
+ int fddev; /* file descriptor */
};
-#endif /* HAVE_PPSAPI */
/*
* Function prototypes
*/
-static int atom_start P((int, struct peer *));
-static void atom_poll P((int, struct peer *));
-static void atom_shutdown P((int, struct peer *));
-#ifdef HAVE_PPSAPI
-static void atom_control P((int, struct refclockstat *, struct
- refclockstat *, struct peer *));
-static void atom_timer P((int, struct peer *));
-static int atom_ppsapi P((struct peer *, int));
-#endif /* HAVE_PPSAPI */
+static int atom_start (int, struct peer *);
+static void atom_shutdown (int, struct peer *);
+static void atom_poll (int, struct peer *);
+static void atom_timer (int, struct peer *);
/*
* Transfer vector
*/
-#ifdef HAVE_PPSAPI
struct refclock refclock_atom = {
atom_start, /* start up driver */
atom_shutdown, /* shut down driver */
atom_poll, /* transmit poll message */
- atom_control, /* fudge control */
+ noentry, /* control (not used) */
noentry, /* initialize driver (not used) */
noentry, /* buginfo (not used) */
atom_timer, /* called once per second */
};
-#else /* HAVE_PPSAPI */
-struct refclock refclock_atom = {
- atom_start, /* start up driver */
- atom_shutdown, /* shut down driver */
- atom_poll, /* transmit poll message */
- noentry, /* fudge control (not used) */
- noentry, /* initialize driver (not used) */
- noentry, /* buginfo (not used) */
- NOFLAGS /* not used */
-};
-#endif /* HAVE_PPPSAPI */
/*
@@ -151,59 +121,37 @@ atom_start(
)
{
struct refclockproc *pp;
-#ifdef HAVE_PPSAPI
- register struct ppsunit *up;
+ struct ppsunit *up;
char device[80];
- int mode;
-#endif /* HAVE_PPSAPI */
/*
* Allocate and initialize unit structure
*/
- pps_peer = peer;
pp = peer->procptr;
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
pp->stratum = STRATUM_UNSPEC;
memcpy((char *)&pp->refid, REFID, 4);
-#ifdef HAVE_PPSAPI
up = emalloc(sizeof(struct ppsunit));
memset(up, 0, sizeof(struct ppsunit));
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Open PPS device. This can be any serial or parallel port and
* not necessarily the port used for the associated radio.
*/
- sprintf(device, DEVICE, unit);
- up->fddev = open(device, O_RDWR, 0777);
+ snprintf(device, sizeof(device), DEVICE, unit);
+ up->fddev = tty_open(device, O_RDWR, 0777);
if (up->fddev <= 0) {
msyslog(LOG_ERR,
- "refclock_atom: %s: %m", device);
- return (0);
- }
-
- /*
- * Light off the PPSAPI interface.
- */
- if (time_pps_create(up->fddev, &up->handle) < 0) {
- msyslog(LOG_ERR,
- "refclock_atom: time_pps_create failed: %m");
+ "refclock_atom: %s: %m", device);
return (0);
}
/*
- * If the mode is nonzero, use that for the time_pps_setparams()
- * mode; otherwise, PPS_CAPTUREASSERT. Enable kernel PPS if
- * flag3 is lit.
+ * Light up the PPSAPI interface.
*/
- mode = peer->ttl;
- if (mode == 0)
- mode = PPS_CAPTUREASSERT;
- return (atom_ppsapi(peer, mode));
-#else /* HAVE_PPSAPI */
- return (1);
-#endif /* HAVE_PPSAPI */
+ return (refclock_ppsapi(up->fddev, &up->atom));
}
@@ -217,249 +165,44 @@ atom_shutdown(
)
{
struct refclockproc *pp;
- register struct ppsunit *up;
+ struct ppsunit *up;
pp = peer->procptr;
- up = (struct ppsunit *)pp->unitptr;
-#ifdef HAVE_PPSAPI
+ up = pp->unitptr;
if (up->fddev > 0)
close(up->fddev);
- if (up->handle != 0)
- time_pps_destroy(up->handle);
-#endif /* HAVE_PPSAPI */
- if (pps_peer == peer)
- pps_peer = NULL;
free(up);
}
-
-#ifdef HAVE_PPSAPI
-/*
- * atom_control - fudge control
- */
-static void
-atom_control(
- int unit, /* unit (not used */
- struct refclockstat *in, /* input parameters (not uded) */
- struct refclockstat *out, /* output parameters (not used) */
- struct peer *peer /* peer structure pointer */
- )
-{
- struct refclockproc *pp;
- int mode;
-
- pp = peer->procptr;
- if (peer->ttl != 0) /* all legal modes must be nonzero */
- return;
-
- if (pp->sloppyclockflag & CLK_FLAG2)
- mode = PPS_CAPTURECLEAR;
- else
- mode = PPS_CAPTUREASSERT;
- atom_ppsapi(peer, mode);
-}
-
-
-/*
- * Initialize PPSAPI
- */
-int
-atom_ppsapi(
- struct peer *peer, /* peer structure pointer */
- int mode /* mode */
- )
-{
- struct refclockproc *pp;
- register struct ppsunit *up;
- int capability;
-
- pp = peer->procptr;
- up = (struct ppsunit *)pp->unitptr;
- if (up->handle == 0)
- return (0);
-
- if (time_pps_getcap(up->handle, &capability) < 0) {
- msyslog(LOG_ERR,
- "refclock_atom: time_pps_getcap failed: %m");
- return (0);
- }
- memset(&up->pps_params, 0, sizeof(pps_params_t));
- up->pps_params.api_version = PPS_API_VERS_1;
- up->pps_params.mode = mode | PPS_TSFMT_TSPEC;
- if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
- msyslog(LOG_ERR,
- "refclock_atom: time_pps_setparams failed: %m");
- return (0);
- }
- if (pp->sloppyclockflag & CLK_FLAG3) {
- if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
- up->pps_params.mode & ~PPS_TSFMT_TSPEC,
- PPS_TSFMT_TSPEC) < 0) {
- msyslog(LOG_ERR,
- "refclock_atom: time_pps_kcbind failed: %m");
- return (0);
- }
- pps_enable = 1;
- }
-#if DEBUG
- if (debug) {
- time_pps_getparams(up->handle, &up->pps_params);
- printf(
- "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x\n",
- up->fddev, capability, up->pps_params.api_version,
- up->pps_params.mode);
- }
-#endif
- return (1);
-}
-
-
/*
* atom_timer - called once per second
- *
- * This routine is called once per second when the PPSAPI interface is
- * present. It snatches the PPS timestamp from the kernel and saves the
- * sign-extended fraction in a circular buffer for processing at the
- * next poll event.
*/
-static void
+void
atom_timer(
- int unit, /* unit number (not used) */
+ int unit, /* unit pointer (not used) */
struct peer *peer /* peer structure pointer */
)
{
- register struct ppsunit *up;
+ struct ppsunit *up;
struct refclockproc *pp;
- pps_info_t pps_info;
- struct timespec timeout, ts;
- long sec, nsec;
- double dtemp;
- char tbuf[80]; /* monitor buffer */
+ char tbuf[80];
- /*
- * Convert the timespec nanoseconds field to signed double and
- * save in the median filter. for billboards. No harm is done if
- * previous data are overwritten. If the discipline comes bum or
- * the data grow stale, just forget it. A range gate rejects new
- * samples if less than a jiggle time from the next second.
- */
pp = peer->procptr;
- up = (struct ppsunit *)pp->unitptr;
- if (up->handle == 0)
+ up = pp->unitptr;
+ if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) <= 0)
return;
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
- if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
- &timeout) < 0) {
- refclock_report(peer, CEVNT_FAULT);
- return;
- }
- if (up->pps_params.mode & PPS_CAPTUREASSERT) {
- ts = up->pps_info.assert_timestamp;
- } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
- ts = up->pps_info.clear_timestamp;
- } else {
- refclock_report(peer, CEVNT_FAULT);
- return;
- }
+ peer->flags |= FLAG_PPS;
/*
- * There can be zero, one or two PPS seconds between polls. If
- * zero, either the poll clock is slightly faster than the PPS
- * clock or the PPS clock has died. If the PPS clock advanced
- * once between polls, we make sure the fraction time difference
- * since the last sample is within the range gate of 5 ms (500
- * PPM). If the PPS clock advanced twice since the last poll,
- * the poll bracketed more than one second and the first second
- * was lost to a slip. Since the interval since the last sample
- * found is now two seconds, just widen the range gate. If the
- * PPS clock advanced three or more times, either the signal has
- * failed for a number of seconds or we have runts, in which
- * case just ignore them.
- *
* If flag4 is lit, record each second offset to clockstats.
* That's so we can make awesome Allan deviation plots.
*/
- sec = ts.tv_sec - up->ts.tv_sec;
- nsec = ts.tv_nsec - up->ts.tv_nsec;
- up->ts = ts;
- if (nsec < 0) {
- sec --;
- nsec += NANOSECOND;
- } else if (nsec >= NANOSECOND) {
- sec++;
- nsec -= NANOSECOND;
- }
- if (sec * NANOSECOND + nsec > NANOSECOND + RANGEGATE)
- return;
-
- else if (sec * NANOSECOND + nsec < NANOSECOND - RANGEGATE)
- return;
-
- pp->lastrec.l_ui = ts.tv_sec + JAN_1970;
- dtemp = ts.tv_nsec * FRAC / 1e9;
- if (dtemp >= FRAC)
- pp->lastrec.l_ui++;
- pp->lastrec.l_uf = (u_int32)dtemp;
- if (ts.tv_nsec > NANOSECOND / 2)
- ts.tv_nsec -= NANOSECOND;
- dtemp = -(double)ts.tv_nsec / NANOSECOND;
- SAMPLE(dtemp + pp->fudgetime1);
- if (pp->sloppyclockflag & CLK_FLAG4){
- sprintf(tbuf, "%.9f", dtemp);
+ if (pp->sloppyclockflag & CLK_FLAG4) {
+ snprintf(tbuf, sizeof(tbuf), "%.9f",
+ pp->filter[pp->coderecv]);
record_clock_stats(&peer->srcadr, tbuf);
}
-#ifdef DEBUG
- if (debug > 1)
- printf("atom_timer: %lu %f %f\n", current_time,
- dtemp, pp->fudgetime1);
-#endif
- return;
-}
-#endif /* HAVE_PPSAPI */
-
-
-/*
- * pps_sample - receive PPS data from some other clock driver
- *
- * This routine is called once per second when the external clock driver
- * processes PPS information. It processes the PPS timestamp and saves
- * the sign-extended fraction in a circular buffer for processing at the
- * next poll event. This works only for a single PPS device.
- *
- * The routine should be used by another configured driver ONLY when
- * this driver is configured as well and the PPSAPI is NOT in use.
- */
-int
-pps_sample(
- l_fp *offset /* PPS offset */
- )
-{
- register struct peer *peer;
- struct refclockproc *pp;
- l_fp lftmp;
- double doffset;
-
- peer = pps_peer;
- if (peer == NULL)
- return (1);
-
- pp = peer->procptr;
-
- /*
- * Convert the timeval to l_fp and save for billboards. Sign-
- * extend the fraction and stash in the buffer. No harm is done
- * if previous data are overwritten. If the discipline comes bum
- * or the data grow stale, just forget it.
- */
- pp->lastrec = *offset;
- L_CLR(&lftmp);
- L_ADDF(&lftmp, pp->lastrec.l_f);
- LFPTOD(&lftmp, doffset);
- SAMPLE(-doffset + pp->fudgetime1);
- return (0);
}
@@ -473,45 +216,24 @@ atom_poll(
)
{
struct refclockproc *pp;
- pp = peer->procptr;
- pp->polls++;
/*
- * Valid time is returned only if the prefer peer has survived
- * the intersection algorithm and within 0.4 s of local time
- * and not too long ago. This ensures the PPS time is within
- * 0.5 s of the local time and the seconds numbering is
- * unambiguous. Note that the leap bits, stratum and refid are
- * set from the prefer peer, unless overriden by a fudge
- * command.
+ * Don't wiggle the clock until some other driver has numbered
+ * the seconds.
*/
- if (pp->codeproc == pp->coderecv) {
- refclock_report(peer, CEVNT_TIMEOUT);
+ if (sys_leap == LEAP_NOTINSYNC)
return;
- } else if (sys_prefer == NULL) {
- pp->codeproc = pp->coderecv;
- return;
-
- } else if (fabs(sys_prefer->offset) >= 0.4) {
- pp->codeproc = pp->coderecv;
+ pp = peer->procptr;
+ pp->polls++;
+ if (pp->codeproc == pp->coderecv) {
+ peer->flags &= ~FLAG_PPS;
+ refclock_report(peer, CEVNT_TIMEOUT);
return;
}
- pp->leap = sys_prefer->leap;
- if (pp->stratum >= STRATUM_UNSPEC)
- peer->stratum = sys_prefer->stratum;
- else
- peer->stratum = pp->stratum;
pp->lastref = pp->lastrec;
refclock_receive(peer);
}
#else
int refclock_atom_bs;
-int
-pps_sample(
- l_fp *offset /* PPS offset */
- )
-{
- return (1);
-}
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_bancomm.c b/contrib/ntp/ntpd/refclock_bancomm.c
index 9fc8c82..49922e3 100644
--- a/contrib/ntp/ntpd/refclock_bancomm.c
+++ b/contrib/ntp/ntpd/refclock_bancomm.c
@@ -20,26 +20,29 @@
* vme_control() and vme_buginfo() have been deleted because
* they are no longer being used.
*
- * The time on the bc635 TFP must be set to GMT due to the
- * fact that NTP makes use of GMT for all its calculations.
- *
- * Installation of the Datum/Bancomm driver creates the
- * device file /dev/btfp0
- *
* 04/28/2005 Rob Neal
* Modified to add support for Symmetricom bc637PCI-U Time &
* Frequency Processor.
+ * 2/21/2007 Ali Ghorashi
+ * Modified to add support for Symmetricom bc637PCI-U Time &
+ * Frequency Processor on Solaris.
+ * Tested on Solaris 10 with a bc635 card.
+ *
* Card bus type (VME/VXI or PCI) and environment are specified via the
* "mode" keyword on the server command in ntp.conf.
- * server 127.127.16.u prefer mode m (...)
- * Modes currently supported are
+ * server 127.127.16.u prefer mode M
+ * where u is the id (usually 0) of the entry in /dev (/dev/stfp0)
+ *
+ * and M is one of the following modes:
* 1 : FreeBSD PCI 635/637.
* 2 : Linux or Windows PCI 635/637.
+ * 3 : Solaris PCI 635/637
* not specified, or other number:
* : Assumed to be VME/VXI legacy Bancomm card on Solaris.
* Linux and Windows platforms require Symmetricoms' proprietary driver
- * for the TFP card.
- * Tested on FreeBSD 5.3 with a 637 card.
+ * for the TFP card.
+ * Solaris requires Symmetricom's driver and its header file (freely distributed) to
+ * be installed and running.
*/
#ifdef HAVE_CONFIG_H
@@ -58,7 +61,6 @@
#include <syslog.h>
#include <ctype.h>
-/* STUFF BY RES */
struct btfp_time /* Structure for reading 5 time words */
/* in one ioctl(2) operation. */
{
@@ -85,9 +87,37 @@ struct btfp_time /* Structure for reading 5 time words */
#define READTIME _IOR('u', 5, struct btfp_time )
#endif
-#define VMEFD "/dev/btfp0"
+/* Solaris specific section */
+struct stfp_tm {
+ int32_t tm_sec;
+ int32_t tm_min;
+ int32_t tm_hour;
+ int32_t tm_mday;
+ int32_t tm_mon;
+ int32_t tm_year;
+ int32_t tm_wday;
+ int32_t tm_yday;
+ int32_t tm_isdst;
+};
+
+struct stfp_time {
+ struct stfp_tm tm;
+ int32_t usec; /* usec 0 - 999999 */
+ int32_t hnsec; /* hnsec 0 - 9 (hundreds of nsecs) */
+ int32_t status;
+};
+
+#define SELTIMEFORMAT 2
+# define TIME_DECIMAL 0
+# define TIME_BINARY 1
-struct vmedate { /* structure returned by get_vmetime.c */
+#if defined(__sun__)
+#undef READTIME
+#define READTIME 9
+#endif /** __sun___ **/
+/* end solaris specific section */
+
+struct vmedate { /* structure returned by get_vmetime.c */
unsigned short year;
unsigned short day;
unsigned short hr;
@@ -97,7 +127,6 @@ struct vmedate { /* structure returned by get_vmetime.c */
unsigned short status;
};
-/* END OF STUFF FROM RES */
typedef void *SYMMT_PCI_HANDLE;
/*
@@ -117,11 +146,6 @@ typedef void *SYMMT_PCI_HANDLE;
extern u_long current_time; /* current time(s) */
/*
- * Imported from ntpd module
- */
-extern volatile int debug; /* global debug flag */
-
-/*
* VME unit control structure.
* Changes made to vmeunit structure. Most members are now available in the
* new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan
@@ -139,7 +163,11 @@ static void vme_shutdown (int, struct peer *);
static void vme_receive (struct recvbuf *);
static void vme_poll (int unit, struct peer *);
struct vmedate *get_datumtime(struct vmedate *);
-void tvme_fill(struct vmedate *, uint32_t btm[2]);
+void tvme_fill(struct vmedate *, uint32_t btm[2]);
+void stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp);
+inline const char *DEVICE_NAME(int n);
+
+
/*
* Define the bc*() functions as weak so we can compile/link without them.
* Only clients with the card will have the proprietary vendor device driver
@@ -167,6 +195,15 @@ int regvalue;
int tfp_type; /* mode selector, indicate platform and driver interface */
SYMMT_PCI_HANDLE stfp_handle;
+/**
+ * this macro returns the device name based on
+ * the platform we are running on and the device number
+ */
+#if defined(__sun__)
+inline const char *DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/stfp%d",n);return s;}
+#else
+inline const char* DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/btfp%d",n);return s;}
+#endif /**__sun__**/
/*
* vme_start - open the VME device and initialize data for processing
@@ -185,6 +222,7 @@ vme_start(
tfp_type = (int)(peer->ttl);
switch (tfp_type) {
case 1:
+ case 3:
break;
case 2:
stfp_handle = bcStartPci(); /* init the card in lin/win */
@@ -197,9 +235,9 @@ vme_start(
*/
#ifdef DEBUG
- printf("Opening DATUM VME DEVICE \n");
+ printf("Opening DATUM DEVICE %s\n",DEVICE_NAME(peer->refclkunit));
#endif
- if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
+ if ( (fd_vme = open(DEVICE_NAME(peer->refclkunit), O_RDWR)) < 0) {
msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
return (0);
}
@@ -207,6 +245,7 @@ vme_start(
switch (tfp_type) {
case 1: break;
case 2: break;
+ case 3:break;
default:
/* Release capture lockout in case it was set before. */
if( ioctl( fd_vme, RUNLOCK, &dummy ) )
@@ -222,21 +261,21 @@ vme_start(
/*
* Allocate unit structure
*/
- vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit));
- bzero((char *)vme, sizeof(struct vmeunit));
+ vme = emalloc_zero(sizeof(struct vmeunit));
/*
* Set up the structures
*/
pp = peer->procptr;
- pp->unitptr = (caddr_t) vme;
+ pp->unitptr = vme;
pp->timestarted = current_time;
pp->io.clock_recv = vme_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd_vme;
+ /* shouldn't there be an io_addclock() call? */
/*
* All done. Initialize a few random peer variables, then
@@ -265,11 +304,13 @@ vme_shutdown(
* Tell the I/O module to turn us off. We're history.
*/
pp = peer->procptr;
- vme = (struct vmeunit *)pp->unitptr;
+ vme = pp->unitptr;
io_closeclock(&pp->io);
pp->unitptr = NULL;
- free(vme);
- if (tfp_type == 2) bcStopPci(stfp_handle);
+ if (NULL != vme)
+ free(vme);
+ if (tfp_type == 2)
+ bcStopPci(stfp_handle);
}
@@ -303,7 +344,7 @@ vme_poll(
struct tm *tadr;
pp = peer->procptr;
- vme = (struct vmeunit *)pp->unitptr; /* Here is the structure */
+ vme = pp->unitptr; /* Here is the structure */
tptr = &vme->vmedata;
if ((tptr = get_datumtime(tptr)) == NULL ) {
@@ -324,14 +365,15 @@ vme_poll(
tadr = gmtime(&tloc);
tptr->year = (unsigned short)(tadr->tm_year + 1900);
- sprintf(pp->a_lastcode,
- "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
- tptr->day,
- tptr->hr,
- tptr->mn,
- tptr->sec,
- tptr->frac,
- tptr->status);
+ snprintf(pp->a_lastcode,
+ sizeof(pp->a_lastcode),
+ "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
+ tptr->day,
+ tptr->hr,
+ tptr->mn,
+ tptr->sec,
+ tptr->frac,
+ tptr->status);
pp->lencode = (u_short) strlen(pp->a_lastcode);
@@ -376,10 +418,10 @@ get_datumtime(struct vmedate *time_vme)
struct btfp_time vts;
uint32_t btm[2];
uint8_t dmy;
+ struct stfp_time stfpm;
- if ( time_vme == (struct vmedate *)NULL) {
- time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
- }
+ if (time_vme == NULL)
+ time_vme = emalloc(sizeof(*time_vme));
switch (tfp_type) {
case 1: /* BSD, PCI, 2 32bit time words */
@@ -397,41 +439,65 @@ get_datumtime(struct vmedate *time_vme)
}
tvme_fill(time_vme, btm);
break;
+
+ case 3: /** solaris **/
+ memset(&stfpm,0,sizeof(stfpm));
+
+ /* we need the time in decimal format */
+ /* Here we rudely assume that we are the only user of the driver.
+ * Other programs will have to set their own time format before reading
+ * the time.
+ */
+ if(ioctl (fd_vme, SELTIMEFORMAT, TIME_DECIMAL)){
+ msyslog(LOG_ERR, "Could not set time format");
+ return (NULL);
+ }
+ /* read the time */
+ if (ioctl(fd_vme, READTIME, &stfpm)) {
+ msyslog(LOG_ERR, "ioctl error: %m");
+ return(NULL);
+ }
+ stfp_time2tvme(time_vme, &stfpm);
+ break;
default: /* legacy bancomm card */
if (ioctl(fd_vme, READTIME, &vts)) {
- msyslog(LOG_ERR, "get_datumtime error: %m");
+ msyslog(LOG_ERR,
+ "get_datumtime error: %m");
return(NULL);
}
/* Get day */
- sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
- ((vts.btfp_time[ 1 ] & 0xff00) >> 8));
+ snprintf(cbuf, sizeof(cbuf), "%3.3x",
+ ((vts.btfp_time[ 0 ] & 0x000f) << 8) +
+ ((vts.btfp_time[ 1 ] & 0xff00) >> 8));
time_vme->day = (unsigned short)atoi(cbuf);
/* Get hour */
- sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff);
-
+ snprintf(cbuf, sizeof(cbuf), "%2.2x",
+ vts.btfp_time[ 1 ] & 0x00ff);
time_vme->hr = (unsigned short)atoi(cbuf);
/* Get minutes */
- sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8);
+ snprintf(cbuf, sizeof(cbuf), "%2.2x",
+ (vts.btfp_time[ 2 ] & 0xff00) >> 8);
time_vme->mn = (unsigned short)atoi(cbuf);
/* Get seconds */
- sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff);
+ snprintf(cbuf, sizeof(cbuf), "%2.2x",
+ vts.btfp_time[ 2 ] & 0x00ff);
time_vme->sec = (unsigned short)atoi(cbuf);
/* Get microseconds. Yes, we ignore the 0.1 microsecond digit so
we can use the TVTOTSF function later on...*/
- sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ],
- vts.btfp_time[ 4 ]>>8);
-
+ snprintf(cbuf, sizeof(cbuf), "%4.4x%2.2x",
+ vts.btfp_time[ 3 ],
+ vts.btfp_time[ 4 ] >> 8);
time_vme->frac = (u_long) atoi(cbuf);
/* Get status bit */
- time_vme->status = (vts.btfp_time[0] & 0x0010) >>4;
+ time_vme->status = (vts.btfp_time[0] & 0x0010) >> 4;
break;
}
@@ -462,6 +528,21 @@ tvme_fill(struct vmedate *time_vme, uint32_t btm[2])
return;
}
+
+/* Assign values to time_vme struct. Mostly for readability */
+void
+stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp)
+{
+
+ time_vme->day = stfp->tm.tm_yday+1;
+ time_vme->hr = stfp->tm.tm_hour;
+ time_vme->mn = stfp->tm.tm_min;
+ time_vme->sec = stfp->tm.tm_sec;
+ time_vme->frac = stfp->usec*1000;
+ time_vme->frac += stfp->hnsec * 100;
+ time_vme->status = stfp->status;
+ return;
+}
#else
int refclock_bancomm_bs;
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_chronolog.c b/contrib/ntp/ntpd/refclock_chronolog.c
index a1d131e..ee54b43 100644
--- a/contrib/ntp/ntpd/refclock_chronolog.c
+++ b/contrib/ntp/ntpd/refclock_chronolog.c
@@ -67,10 +67,10 @@ struct chronolog_unit {
/*
* Function prototypes
*/
-static int chronolog_start P((int, struct peer *));
-static void chronolog_shutdown P((int, struct peer *));
-static void chronolog_receive P((struct recvbuf *));
-static void chronolog_poll P((int, struct peer *));
+static int chronolog_start (int, struct peer *);
+static void chronolog_shutdown (int, struct peer *);
+static void chronolog_receive (struct recvbuf *);
+static void chronolog_poll (int, struct peer *);
/*
* Transfer vector
@@ -104,32 +104,30 @@ chronolog_start(
* Open serial port. Don't bother with CLK line discipline, since
* it's not available.
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
#ifdef DEBUG
if (debug)
printf ("starting Chronolog with device %s\n",device);
#endif
- if (!(fd = refclock_open(device, SPEED232, 0)))
+ fd = refclock_open(device, SPEED232, 0);
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct chronolog_unit *)
- emalloc(sizeof(struct chronolog_unit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct chronolog_unit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = chronolog_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
+ pp->unitptr = NULL;
return (0);
}
@@ -156,9 +154,11 @@ chronolog_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct chronolog_unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -184,9 +184,9 @@ chronolog_receive(
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct chronolog_unit *)pp->unitptr;
+ up = pp->unitptr;
temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
if (temp == 0) {
@@ -240,6 +240,8 @@ chronolog_receive(
* otherwise, we get the time wrong.
*/
+ memset(&local, 0, sizeof(local));
+
local.tm_year = up->year;
local.tm_mon = up->month-1;
local.tm_mday = up->day;
@@ -295,7 +297,7 @@ chronolog_receive(
pp->lastref = pp->lastrec;
refclock_receive(peer);
record_clock_stats(&peer->srcadr, pp->a_lastcode);
- up->lasthour = pp->hour;
+ up->lasthour = (u_char)pp->hour;
}
@@ -322,7 +324,7 @@ chronolog_poll(
char pollchar;
pp = peer->procptr;
- up = (struct chronolog_unit *)pp->unitptr;
+ up = pp->unitptr;
if (peer->burst == 0 && peer->reach == 0)
refclock_report(peer, CEVNT_TIMEOUT);
if (up->linect > 0)
diff --git a/contrib/ntp/ntpd/refclock_chu.c b/contrib/ntp/ntpd/refclock_chu.c
index 843e9aaa..6b1ae55 100644
--- a/contrib/ntp/ntpd/refclock_chu.c
+++ b/contrib/ntp/ntpd/refclock_chu.c
@@ -5,6 +5,8 @@
#include <config.h>
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_CHU)
#include "ntpd.h"
@@ -26,47 +28,47 @@
#ifdef ICOM
#include "icom.h"
#endif /* ICOM */
-
/*
* Audio CHU demodulator/decoder
*
* This driver synchronizes the computer time using data encoded in
* radio transmissions from Canadian time/frequency station CHU in
* Ottawa, Ontario. Transmissions are made continuously on 3330 kHz,
- * 7335 kHz and 14670 kHz in upper sideband, compatible AM mode. An
+ * 7850 kHz and 14670 kHz in upper sideband, compatible AM mode. An
* ordinary shortwave receiver can be tuned manually to one of these
* frequencies or, in the case of ICOM receivers, the receiver can be
- * tuned automatically using this program as propagation conditions
- * change throughout the day and night.
+ * tuned automatically as propagation conditions change throughout the
+ * day and season.
*
- * The driver receives, demodulates and decodes the radio signals when
- * connected to the audio codec of a suported workstation hardware and
- * operating system. These include Solaris, SunOS, FreeBSD, NetBSD and
- * Linux. In this implementation, only one audio driver and codec can be
- * supported on a single machine.
+ * The driver requires an audio codec or sound card with sampling rate 8
+ * kHz and mu-law companding. This is the same standard as used by the
+ * telephone industry and is supported by most hardware and operating
+ * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this
+ * implementation, only one audio driver and codec can be supported on a
+ * single machine.
*
* The driver can be compiled to use a Bell 103 compatible modem or
* modem chip to receive the radio signal and demodulate the data.
* Alternatively, the driver can be compiled to use the audio codec of
- * the Sun workstation or another with compatible audio drivers. In the
+ * the workstation or another with compatible audio drivers. In the
* latter case, the driver implements the modem using DSP routines, so
* the radio can be connected directly to either the microphone on line
* input port. In either case, the driver decodes the data using a
- * maximum likelihood technique which exploits the considerable degree
+ * maximum-likelihood technique which exploits the considerable degree
* of redundancy available to maximize accuracy and minimize errors.
*
* The CHU time broadcast includes an audio signal compatible with the
- * Bell 103 modem standard (mark = 2225 Hz, space = 2025 Hz). It consist
- * of nine, ten-character bursts transmitted at 300 bps and beginning
- * each second from second 31 to second 39 of the minute. Each character
- * consists of eight data bits plus one start bit and two stop bits to
- * encode two hex digits. The burst data consist of five characters (ten
- * hex digits) followed by a repeat of these characters. In format A,
- * the characters are repeated in the same polarity; in format B, the
- * characters are repeated in the opposite polarity.
+ * Bell 103 modem standard (mark = 2225 Hz, space = 2025 Hz). The signal
+ * consists of nine, ten-character bursts transmitted at 300 bps between
+ * seconds 31 and 39 of each minute. Each character consists of eight
+ * data bits plus one start bit and two stop bits to encode two hex
+ * digits. The burst data consist of five characters (ten hex digits)
+ * followed by a repeat of these characters. In format A, the characters
+ * are repeated in the same polarity; in format B, the characters are
+ * repeated in the opposite polarity.
*
* Format A bursts are sent at seconds 32 through 39 of the minute in
- * hex digits
+ * hex digits (nibble swapped)
*
* 6dddhhmmss6dddhhmmss
*
@@ -96,10 +98,10 @@
* By design, the last stop bit of the last character in the burst
* coincides with 0.5 second. Since characters have 11 bits and are
* transmitted at 300 bps, the last stop bit of the first character
- * coincides with 0.5 - 10 * 11/300 = 0.133 second. Depending on the
- * UART, character interrupts can vary somewhere between the beginning
- * of bit 9 and end of bit 11. These eccentricities can be corrected
- * along with the radio propagation delay using fudge time 1.
+ * coincides with 0.5 - 9 * 11/300 = 0.170 second. Depending on the
+ * UART, character interrupts can vary somewhere between the end of bit
+ * 9 and end of bit 11. These eccentricities can be corrected along with
+ * the radio propagation delay using fudge time 1.
*
* Debugging aids
*
@@ -107,11 +109,15 @@
* data helpful in diagnosing problems with the radio signal and serial
* connections. With debugging enabled (-d on the ntpd command line),
* the driver produces one line for each burst in two formats
- * corresponding to format A and B. Following is format A:
+ * corresponding to format A and B.Each line begins with the format code
+ * chuA or chuB followed by the status code and signal level (0-9999).
+ * The remainder of the line is as follows.
+ *
+ * Following is format A:
*
* n b f s m code
*
- * where n is the number of characters in the burst (0-11), b the burst
+ * where n is the number of characters in the burst (0-10), b the burst
* distance (0-40), f the field alignment (-1, 0, 1), s the
* synchronization distance (0-16), m the burst number (2-9) and code
* the burst characters as received. Note that the hex digits in each
@@ -119,43 +125,50 @@
*
* 10 38 0 16 9 06851292930685129293
*
- * is interpreted as containing 11 characters with burst distance 38,
+ * is interpreted as containing 10 characters with burst distance 38,
* field alignment 0, synchronization distance 16 and burst number 9.
* The nibble-swapped timecode shows day 58, hour 21, minute 29 and
* second 39.
*
- * When the audio driver is compiled, format A is preceded by
- * the current gain (0-255) and relative signal level (0-9999). The
- * receiver folume control should be set so that the gain is somewhere
- * near the middle of the range 0-255, which results in a signal level
- * near 1000.
- *
* Following is format B:
*
* n b s code
*
- * where n is the number of characters in the burst (0-11), b the burst
+ * where n is the number of characters in the burst (0-10), b the burst
* distance (0-40), s the synchronization distance (0-40) and code the
* burst characters as received. Note that the hex digits in each
* character are reversed and the last ten digits inverted, so the burst
*
- * 11 40 1091891300ef6e76ecff
+ * 10 40 1091891300ef6e76ec
*
- * is interpreted as containing 11 characters with burst distance 40.
+ * is interpreted as containing 10 characters with burst distance 40.
* The nibble-swapped timecode shows DUT1 +0.1 second, year 1998 and TAI
* - UTC 31 seconds.
*
+ * Each line is preceeded by the code chuA or chuB, as appropriate. If
+ * the audio driver is compiled, the current gain (0-255) and relative
+ * signal level (0-9999) follow the code. The receiver volume control
+ * should be set so that the gain is somewhere near the middle of the
+ * range 0-255, which results in a signal level near 1000.
+ *
* In addition to the above, the reference timecode is updated and
* written to the clockstats file and debug score after the last burst
* received in the minute. The format is
*
- * qq yyyy ddd hh:mm:ss nn dd tt
+ * sq yyyy ddd hh:mm:ss l s dd t agc ident m b
*
- * where qq are the error flags, as described below, yyyy is the year,
- * ddd the day, hh:mm:ss the time of day, nn the number of format A
- * bursts received during the previous minute, dd the decoding distance
- * and tt the number of timestamps. The error flags are cleared after
- * every update.
+ * s '?' before first synchronized and ' ' after that
+ * q status code (see below)
+ * yyyy year
+ * ddd day of year
+ * hh:mm:ss time of day
+ * l leap second indicator (space, L or D)
+ * dst Canadian daylight code (opaque)
+ * t number of minutes since last synchronized
+ * agc audio gain (0 - 255)
+ * ident identifier (CHU0 3330 kHz, CHU1 7850 kHz, CHU2 14670 kHz)
+ * m signal metric (0 - 100)
+ * b number of timecodes for the previous minute (0 - 59)
*
* Fudge factors
*
@@ -184,6 +197,11 @@
* 9600 bps if the high order 0x80 bit of the mode is zero and 1200 bps
* if one. The C-IV trace is turned on if the debug level is greater
* than one.
+ *
+ * Alarm codes
+ *
+ * CEVNT_BADTIME invalid date or time
+ * CEVNT_PROP propagation failure - no stations heard
*/
/*
* Interface definitions
@@ -194,8 +212,8 @@
#define DEVICE "/dev/chu%d" /* device name and unit */
#define SPEED232 B300 /* UART speed (300 baud) */
#ifdef ICOM
-#define TUNE .001 /* offset for narrow filter (kHz) */
-#define DWELL 5 /* minutes in a probe cycle */
+#define TUNE .001 /* offset for narrow filter (MHz) */
+#define DWELL 5 /* minutes in a dwell */
#define NCHAN 3 /* number of channels */
#define ISTAGE 3 /* number of integrator stages */
#endif /* ICOM */
@@ -210,6 +228,7 @@
#define SIZE 256 /* decompanding table size */
#define MAXAMP 6000. /* maximum signal level */
#define MAXCLP 100 /* max clips above reference per s */
+#define SPAN 800. /* min envelope span */
#define LIMIT 1000. /* soft limiter threshold */
#define AGAIN 6. /* baseband gain */
#define LAG 10 /* discriminator lag */
@@ -224,23 +243,28 @@
* Decoder definitions
*/
#define CHAR (11. / 300.) /* character time (s) */
-#define FUDGE .185 /* offset to first stop bit (s) */
#define BURST 11 /* max characters per burst */
-#define MINCHAR 9 /* min characters per burst */
+#define MINCHARS 9 /* min characters per burst */
#define MINDIST 28 /* min burst distance (of 40) */
-#define MINBURST 4 /* min bursts in minute */
#define MINSYNC 8 /* min sync distance (of 16) */
#define MINSTAMP 20 /* min timestamps (of 60) */
-#define METRIC 50. /* min channel metric */
-#define PANIC 1440 /* panic timeout (m) */
-#define HOLD 30 /* reach hold (m) */
+#define MINMETRIC 50 /* min channel metric (of 160) */
/*
- * Hex extension codes (>= 16)
+ * The on-time synchronization point for the driver is the last stop bit
+ * of the first character 170 ms. The modem delay is 0.8 ms, while the
+ * receiver delay is approxmately 4.7 ms at 2125 Hz. The fudge value 1.3
+ * ms due to the codec and other causes was determined by calibrating to
+ * a PPS signal from a GPS receiver. The additional propagation delay
+ * specific to each receiver location can be programmed in the fudge
+ * time1.
+ *
+ * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are
+ * generally within 0.5 ms short term with 0.3 ms jitter. The long-term
+ * offsets vary up to 0.3 ms due to ionospheric layer height variations.
+ * The processor load due to the driver is 0.4 percent.
*/
-#define HEX_MISS 16 /* miss _ */
-#define HEX_SOFT 17 /* soft error * */
-#define HEX_HARD 18 /* hard error = */
+#define PDELAY ((170 + .8 + 4.7 + 1.3) / 1000) /* system delay (s) */
/*
* Status bits (status)
@@ -256,6 +280,7 @@
#define AVALID 0x0100 /* valid A frame */
#define BVALID 0x0200 /* valid B frame */
#define INSYNC 0x0400 /* clock synchronized */
+#define METRIC 0x0800 /* one or more stations heard */
/*
* Alarm status bits (alarm)
@@ -273,12 +298,13 @@
#ifdef HAVE_AUDIO
/*
- * Maximum likelihood UART structure. There are eight of these
+ * Maximum-likelihood UART structure. There are eight of these
* corresponding to the number of phases.
*/
struct surv {
- double shift[12]; /* mark register */
- double es_max, es_min; /* max/min envelope signals */
+ l_fp cstamp; /* last bit timestamp */
+ double shift[12]; /* sample shift register */
+ double span; /* shift register envelope span */
double dist; /* sample distance */
int uart; /* decoded character */
};
@@ -301,19 +327,19 @@ struct xmtr {
* CHU unit control structure
*/
struct chuunit {
- u_char decode[20][16]; /* maximum likelihood decoding matrix */
+ u_char decode[20][16]; /* maximum-likelihood decoding matrix */
l_fp cstamp[BURST]; /* character timestamps */
l_fp tstamp[MAXSTAGE]; /* timestamp samples */
l_fp timestamp; /* current buffer timestamp */
l_fp laststamp; /* last buffer timestamp */
l_fp charstamp; /* character time as a l_fp */
+ int second; /* counts the seconds of the minute */
int errflg; /* error flags */
int status; /* status bits */
char ident[5]; /* station ID and channel */
#ifdef ICOM
int fd_icom; /* ICOM file descriptor */
- int chan; /* data channel */
- int achan; /* active channel */
+ int chan; /* radio channel */
int dwell; /* dwell cycle */
struct xmtr xmtr[NCHAN]; /* station metric */
#endif /* ICOM */
@@ -328,6 +354,8 @@ struct chuunit {
int burdist; /* burst distance */
int syndist; /* sync distance */
int burstcnt; /* format A bursts this minute */
+ double maxsignal; /* signal level (modem only) */
+ int gain; /* codec gain (modem only) */
/*
* Format particulars
@@ -344,7 +372,6 @@ struct chuunit {
int fd_audio; /* audio port file descriptor */
double comp[SIZE]; /* decompanding table */
int port; /* codec port */
- int gain; /* codec gain */
int mongain; /* codec monitor gain */
int clipcnt; /* sample clip count */
int seccnt; /* second interval counter */
@@ -357,15 +384,15 @@ struct chuunit {
double disc[LAG]; /* discriminator shift register */
double lpf[27]; /* FIR lowpass filter */
double monitor; /* audio monitor */
- double maxsignal; /* signal level */
int discptr; /* discriminator pointer */
/*
- * Maximum likelihood UART variables
+ * Maximum-likelihood UART variables
*/
double baud; /* baud interval */
struct surv surv[8]; /* UART survivor structures */
int decptr; /* decode pointer */
+ int decpha; /* decode phase */
int dbrk; /* holdoff counter */
#endif /* HAVE_AUDIO */
};
@@ -373,31 +400,32 @@ struct chuunit {
/*
* Function prototypes
*/
-static int chu_start P((int, struct peer *));
-static void chu_shutdown P((int, struct peer *));
-static void chu_receive P((struct recvbuf *));
-static void chu_poll P((int, struct peer *));
+static int chu_start (int, struct peer *);
+static void chu_shutdown (int, struct peer *);
+static void chu_receive (struct recvbuf *);
+static void chu_second (int, struct peer *);
+static void chu_poll (int, struct peer *);
/*
* More function prototypes
*/
-static void chu_decode P((struct peer *, int));
-static void chu_burst P((struct peer *));
-static void chu_clear P((struct peer *));
-static void chu_a P((struct peer *, int));
-static void chu_b P((struct peer *, int));
-static int chu_dist P((int, int));
-static double chu_major P((struct peer *));
+static void chu_decode (struct peer *, int, l_fp);
+static void chu_burst (struct peer *);
+static void chu_clear (struct peer *);
+static void chu_a (struct peer *, int);
+static void chu_b (struct peer *, int);
+static int chu_dist (int, int);
+static double chu_major (struct peer *);
#ifdef HAVE_AUDIO
-static void chu_uart P((struct surv *, double));
-static void chu_rf P((struct peer *, double));
-static void chu_gain P((struct peer *));
-static void chu_audio_receive P((struct recvbuf *rbufp));
+static void chu_uart (struct surv *, double);
+static void chu_rf (struct peer *, double);
+static void chu_gain (struct peer *);
+static void chu_audio_receive (struct recvbuf *rbufp);
#endif /* HAVE_AUDIO */
#ifdef ICOM
-static int chu_newchan P((struct peer *, double));
+static int chu_newchan (struct peer *, double);
#endif /* ICOM */
-static void chu_serial_receive P((struct recvbuf *rbufp));
+static void chu_serial_receive (struct recvbuf *rbufp);
/*
* Global variables
@@ -410,7 +438,7 @@ static char hexchar[] = "0123456789abcdef_*=";
* transmits on USB with carrier so we can use AM and the narrow SSB
* filter.
*/
-static double qsy[NCHAN] = {3.330, 7.335, 14.670}; /* freq (MHz) */
+static double qsy[NCHAN] = {3.330, 7.850, 14.670}; /* freq (MHz) */
#endif /* ICOM */
/*
@@ -423,7 +451,7 @@ struct refclock refclock_chu = {
noentry, /* not used (old chu_control) */
noentry, /* initialize driver (not used) */
noentry, /* not used (old chu_buginfo) */
- NOFLAGS /* not used */
+ chu_second /* housekeeping timer */
};
@@ -449,21 +477,22 @@ chu_start(
double step; /* codec adjustment */
/*
- * Open audio device.
+ * Open audio device. Don't complain if not there.
*/
fd_audio = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);
+
#ifdef DEBUG
- if (fd_audio > 0 && debug)
+ if (fd_audio >= 0 && debug)
audio_show();
#endif
/*
- * Open serial port in raw mode.
+ * If audio is unavailable, Open serial port in raw mode.
*/
- if (fd_audio > 0) {
+ if (fd_audio >= 0) {
fd = fd_audio;
} else {
- sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
fd = refclock_open(device, SPEED232, LDISC_RAW);
}
#else /* HAVE_AUDIO */
@@ -471,30 +500,28 @@ chu_start(
/*
* Open serial port in raw mode.
*/
- sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
fd = refclock_open(device, SPEED232, LDISC_RAW);
#endif /* HAVE_AUDIO */
- if (fd <= 0)
+
+ if (fd < 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct chuunit *)
- emalloc(sizeof(struct chuunit)))) {
- close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct chuunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = chu_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
close(fd);
+ pp->io.fd = -1;
free(up);
+ pp->unitptr = NULL;
return (0);
}
@@ -503,8 +530,8 @@ chu_start(
*/
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
- strcpy(up->ident, "CHU");
- memcpy(&peer->refid, up->ident, 4);
+ strlcpy(up->ident, "CHU", sizeof(up->ident));
+ memcpy(&pp->refid, up->ident, 4);
DTOLFP(CHAR, &up->charstamp);
#ifdef HAVE_AUDIO
@@ -543,16 +570,11 @@ chu_start(
}
if (up->fd_icom > 0) {
if (chu_newchan(peer, 0) != 0) {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "icom: radio not found");
- up->errflg = CEVNT_FAULT;
+ msyslog(LOG_NOTICE, "icom: radio not found");
close(up->fd_icom);
up->fd_icom = 0;
} else {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "icom: autotune enabled");
+ msyslog(LOG_NOTICE, "icom: autotune enabled");
}
}
#endif /* ICOM */
@@ -573,7 +595,7 @@ chu_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
if (up == NULL)
return;
@@ -599,9 +621,9 @@ chu_receive(
struct refclockproc *pp;
struct peer *peer;
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* If the audio codec is warmed up, the buffer contains codec
@@ -639,9 +661,9 @@ chu_audio_receive(
int bufcnt; /* buffer counter */
l_fp ltemp; /* l_fp temp */
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Main loop - read until there ain't no more. Note codec
@@ -674,7 +696,6 @@ chu_audio_receive(
*/
up->seccnt = (up->seccnt + 1) % SECOND;
if (up->seccnt == 0) {
- pp->second = (pp->second + 1) % 60;
chu_gain(peer);
}
}
@@ -698,7 +719,7 @@ chu_audio_receive(
*
* This routine implements a 300-baud Bell 103 modem with mark 2225 Hz
* and space 2025 Hz. It uses a bandpass filter followed by a soft
- * limiter, FM discriminator and lowpass filter. A maximum likelihood
+ * limiter, FM discriminator and lowpass filter. A maximum-likelihood
* decoder samples the baseband signal at eight times the baud rate and
* detects the start bit of each character.
*
@@ -723,16 +744,16 @@ chu_rf(
double limit; /* limiter signal */
double disc; /* discriminator signal */
double lpf; /* lowpass signal */
- double span; /* UART signal span */
double dist; /* UART signal distance */
int i, j;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Bandpass filter. 4th-order elliptic, 500-Hz bandpass centered
- * at 2125 Hz. Passband ripple 0.3 dB, stopband ripple 50 dB.
+ * at 2125 Hz. Passband ripple 0.3 dB, stopband ripple 50 dB,
+ * phase delay 0.24 ms.
*/
signal = (up->bpf[8] = up->bpf[7]) * 5.844676e-01;
signal += (up->bpf[7] = up->bpf[6]) * 4.884860e-01;
@@ -778,7 +799,7 @@ chu_rf(
disc = -SQRT(-disc);
/*
- * Lowpass filter. Raised cosine, Ts = 1 / 300, beta = 0.1.
+ * Lowpass filter. Raised cosine FIR, Ts = 1 / 300, beta = 0.1.
*/
lpf = (up->lpf[26] = up->lpf[25]) * 2.538771e-02;
lpf += (up->lpf[25] = up->lpf[24]) * 1.084671e-01;
@@ -809,44 +830,68 @@ chu_rf(
lpf += up->lpf[0] = disc * 2.538771e-02;
/*
- * Maximum likelihood decoder. The UART updates each of the
+ * Maximum-likelihood decoder. The UART updates each of the
* eight survivors and determines the span, slice level and
* tentative decoded character. Valid 11-bit characters are
- * framed so that bit 1 and bit 11 (stop bits) are mark and bit
- * 2 (start bit) is space. When a valid character is found, the
+ * framed so that bit 10 and bit 11 (stop bits) are mark and bit
+ * 1 (start bit) is space. When a valid character is found, the
* survivor with maximum distance determines the final decoded
* character.
*/
up->baud += 1. / SECOND;
if (up->baud > 1. / (BAUD * 8.)) {
up->baud -= 1. / (BAUD * 8.);
+ up->decptr = (up->decptr + 1) % 8;
sp = &up->surv[up->decptr];
- span = sp->es_max - sp->es_min;
- up->maxsignal += (span - up->maxsignal) / 80.;
+ sp->cstamp = up->timestamp;
+ chu_uart(sp, -lpf * AGAIN);
if (up->dbrk > 0) {
up->dbrk--;
- } else if ((sp->uart & 0x403) == 0x401 && span > 1000.)
- {
- dist = 0;
- j = 0;
- for (i = 0; i < 8; i++) {
- if (up->surv[i].dist > dist) {
- dist = up->surv[i].dist;
- j = i;
- }
+ if (up->dbrk > 0)
+ return;
+
+ up->decpha = up->decptr;
+ }
+ if (up->decptr != up->decpha)
+ return;
+
+ dist = 0;
+ j = -1;
+ for (i = 0; i < 8; i++) {
+
+ /*
+ * The timestamp is taken at the last bit, so
+ * for correct decoding we reqire sufficient
+ * span and correct start bit and two stop bits.
+ */
+ if ((up->surv[i].uart & 0x601) != 0x600 ||
+ up->surv[i].span < SPAN)
+ continue;
+
+ if (up->surv[i].dist > dist) {
+ dist = up->surv[i].dist;
+ j = i;
}
- chu_decode(peer, (up->surv[j].uart >> 2) &
- 0xff);
- up->dbrk = 80;
}
- up->decptr = (up->decptr + 1) % 8;
- chu_uart(sp, -lpf * AGAIN);
+ if (j < 0)
+ return;
+
+ /*
+ * Process the character, then blank the decoder until
+ * the end of the next character.This sets the decoding
+ * phase of the entire burst from the phase of the first
+ * character.
+ */
+ up->maxsignal = up->surv[j].span;
+ chu_decode(peer, (up->surv[j].uart >> 1) & 0xff,
+ up->surv[j].cstamp);
+ up->dbrk = 88;
}
}
/*
- * chu_uart - maximum likelihood UART
+ * chu_uart - maximum-likelihood UART
*
* This routine updates a shift register holding the last 11 envelope
* samples. It then computes the slice level and span over these samples
@@ -882,12 +927,15 @@ chu_uart(
}
/*
- * Determine the slice level midway beteen the maximum and
- * minimum and the span as the maximum less the minimum. Compute
- * the distance on the assumption the first and last bits must
- * be mark, the second space and the rest either mark or space.
+ * Determine the span as the maximum less the minimum and the
+ * slice level as the minimum plus a fraction of the span. Note
+ * the slight bias toward mark to correct for the modem tendency
+ * to make more mark than space errors. Compute the distance on
+ * the assumption the last two bits must be mark, the first
+ * space and the rest either mark or space.
*/
- slice = (es_max + es_min) / 2.;
+ sp->span = es_max - es_min;
+ slice = es_min + .45 * sp->span;
dist = 0;
sp->uart = 0;
for (i = 1; i < 12; i++) {
@@ -895,9 +943,9 @@ chu_uart(
dtemp = sp->shift[i];
if (dtemp > slice)
sp->uart |= 0x1;
- if (i == 1 || i == 11) {
+ if (i == 1 || i == 2) {
dist += dtemp - es_min;
- } else if (i == 10) {
+ } else if (i == 11) {
dist += es_max - dtemp;
} else {
if (dtemp > slice)
@@ -906,9 +954,7 @@ chu_uart(
dist += es_max - dtemp;
}
}
- sp->es_max = es_max;
- sp->es_min = es_min;
- sp->dist = dist / (11 * (es_max - es_min));
+ sp->dist = dist / (11 * sp->span);
}
#endif /* HAVE_AUDIO */
@@ -921,22 +967,14 @@ chu_serial_receive(
struct recvbuf *rbufp /* receive buffer structure pointer */
)
{
- struct chuunit *up;
- struct refclockproc *pp;
struct peer *peer;
u_char *dpt; /* receive buffer pointer */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ peer = rbufp->recv_peer;
- /*
- * Initialize pointers and read the timecode and timestamp.
- */
- up->timestamp = rbufp->recv_time;
dpt = (u_char *)&rbufp->recv_space;
- chu_decode(peer, *dpt);
+ chu_decode(peer, *dpt, rbufp->recv_time);
}
@@ -946,7 +984,8 @@ chu_serial_receive(
static void
chu_decode(
struct peer *peer, /* peer structure pointer */
- int hexhex /* data character */
+ int hexhex, /* data character */
+ l_fp cstamp /* data character timestamp */
)
{
struct refclockproc *pp;
@@ -956,7 +995,7 @@ chu_decode(
double dtemp;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* If the interval since the last character is greater than the
@@ -979,11 +1018,11 @@ chu_decode(
/*
* Append the character to the current burst and append the
- * timestamp to the timestamp list.
+ * character timestamp to the timestamp list.
*/
if (up->ndx < BURST) {
up->cbuf[up->ndx] = hexhex & 0xff;
- up->cstamp[up->ndx] = up->timestamp;
+ up->cstamp[up->ndx] = cstamp;
up->ndx++;
}
@@ -1004,7 +1043,7 @@ chu_burst(
int i;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Correlate a block of five characters with the next block of
@@ -1012,7 +1051,7 @@ chu_burst(
* of bits that match in the two blocks for format A and that
* match the inverse for format B.
*/
- if (up->ndx < MINCHAR) {
+ if (up->ndx < MINCHARS) {
up->status |= RUNT;
return;
}
@@ -1061,23 +1100,35 @@ chu_b(
u_char code[11]; /* decoded timecode */
char tbuf[80]; /* trace buffer */
- l_fp offset; /* timestamp offset */
+ char * p;
+ size_t chars;
+ size_t cb;
int i;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* In a format B burst, a character is considered valid only if
- * the first occurrence matches the last occurrence. The burst
- * is considered valid only if all characters are valid; that
- * is, only if the distance is 40. Note that once a valid frame
- * has been found errors are ignored.
+ * the first occurence matches the last occurence. The burst is
+ * considered valid only if all characters are valid; that is,
+ * only if the distance is 40. Note that once a valid frame has
+ * been found errors are ignored.
*/
- sprintf(tbuf, "chuB %04x %2d %2d ", up->status, nchar,
- -up->burdist);
- for (i = 0; i < nchar; i++)
- sprintf(&tbuf[strlen(tbuf)], "%02x", up->cbuf[i]);
+ snprintf(tbuf, sizeof(tbuf), "chuB %04x %4.0f %2d %2d ",
+ up->status, up->maxsignal, nchar, -up->burdist);
+ cb = sizeof(tbuf);
+ p = tbuf;
+ for (i = 0; i < nchar; i++) {
+ chars = strlen(p);
+ if (cb < chars + 1) {
+ msyslog(LOG_ERR, "chu_b() fatal out buffer");
+ exit(1);
+ }
+ cb -= chars;
+ p += chars;
+ snprintf(p, cb, "%02x", up->cbuf[i]);
+ }
if (pp->sloppyclockflag & CLK_FLAG4)
record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
@@ -1088,11 +1139,10 @@ chu_b(
up->status |= BFRAME;
return;
}
- up->status |= BVALID;
/*
- * Convert the burst data to internal format. If this succeeds,
- * save the timestamps for later.
+ * Convert the burst data to internal format. Don't bother with
+ * the timestamps.
*/
for (i = 0; i < 5; i++) {
code[2 * i] = hexchar[up->cbuf[i] & 0xf];
@@ -1104,17 +1154,9 @@ chu_b(
up->status |= BFORMAT;
return;
}
+ up->status |= BVALID;
if (up->leap & 0x8)
up->dut = -up->dut;
- offset.l_ui = 31;
- offset.l_f = 0;
- for (i = 0; i < nchar && i < 10; i++) {
- up->tstamp[up->ntstamp] = up->cstamp[i];
- L_SUB(&up->tstamp[up->ntstamp], &offset);
- L_ADD(&offset, &up->charstamp);
- if (up->ntstamp < MAXSTAGE - 1)
- up->ntstamp++;
- }
}
@@ -1131,19 +1173,22 @@ chu_a(
struct chuunit *up;
char tbuf[80]; /* trace buffer */
+ char * p;
+ size_t chars;
+ size_t cb;
l_fp offset; /* timestamp offset */
int val; /* distance */
int temp;
int i, j, k;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Determine correct burst phase. There are three cases
* corresponding to in-phase, one character early or one
* character late. These cases are distinguished by the position
- * of the framing digits x6 at positions 0 and 5 and x3 at
+ * of the framing digits 0x6 at positions 0 and 5 and 0x3 at
* positions 4 and 9. The correct phase is when the distance
* relative to the framing digits is maximum. The burst is valid
* only if the maximum distance is at least MINSYNC.
@@ -1164,27 +1209,31 @@ chu_a(
k = i;
}
}
+
+ /*
+ * Extract the second number; it must be in the range 2 through
+ * 9 and the two repititions must be the same.
+ */
temp = (up->cbuf[k + 4] >> 4) & 0xf;
- if (temp > 9 || k + 9 >= nchar || temp != ((up->cbuf[k + 9] >>
- 4) & 0xf))
+ if (temp < 2 || temp > 9 || k + 9 >= nchar || temp !=
+ ((up->cbuf[k + 9] >> 4) & 0xf))
temp = 0;
-#ifdef HAVE_AUDIO
- if (up->fd_audio)
- sprintf(tbuf, "chuA %04x %4.0f %2d %2d %2d %2d %1d ",
- up->status, up->maxsignal, nchar, up->burdist, k,
- up->syndist, temp);
- else
- sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ",
- up->status, nchar, up->burdist, k, up->syndist,
- temp);
-
-#else
- sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", up->status,
- nchar, up->burdist, k, up->syndist, temp);
-#endif /* HAVE_AUDIO */
- for (i = 0; i < nchar; i++)
- sprintf(&tbuf[strlen(tbuf)], "%02x",
- up->cbuf[i]);
+ snprintf(tbuf, sizeof(tbuf),
+ "chuA %04x %4.0f %2d %2d %2d %2d %1d ", up->status,
+ up->maxsignal, nchar, up->burdist, k, up->syndist,
+ temp);
+ cb = sizeof(tbuf);
+ p = tbuf;
+ for (i = 0; i < nchar; i++) {
+ chars = strlen(p);
+ if (cb < chars + 1) {
+ msyslog(LOG_ERR, "chu_a() fatal out buffer");
+ exit(1);
+ }
+ cb -= chars;
+ p += chars;
+ snprintf(p, cb, "%02x", up->cbuf[i]);
+ }
if (pp->sloppyclockflag & CLK_FLAG4)
record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
@@ -1203,10 +1252,13 @@ chu_a(
* processing. In addition, the seconds decode is advanced from
* the previous burst to the current one.
*/
- if (temp != 0) {
- pp->second = 30 + temp;
+ if (temp == 0) {
+ up->status |= AFORMAT;
+ } else {
+ up->status |= AVALID;
+ up->second = pp->second = 30 + temp;
offset.l_ui = 30 + temp;
- offset.l_f = 0;
+ offset.l_uf = 0;
i = 0;
if (k < 0)
offset = up->charstamp;
@@ -1216,7 +1268,7 @@ chu_a(
up->tstamp[up->ntstamp] = up->cstamp[i];
L_SUB(&up->tstamp[up->ntstamp], &offset);
L_ADD(&offset, &up->charstamp);
- if (up->ntstamp < MAXSTAGE - 1)
+ if (up->ntstamp < MAXSTAGE - 1)
up->ntstamp++;
}
while (temp > up->prevsec) {
@@ -1229,6 +1281,10 @@ chu_a(
up->prevsec++;
}
}
+
+ /*
+ * Stash the data in the decoding matrix.
+ */
i = -(2 * k);
for (j = 0; j < nchar; j++) {
if (i < 0 || i > 18) {
@@ -1240,7 +1296,6 @@ chu_a(
up->decode[i][(up->cbuf[j] >> 4) & 0xf]++;
i++;
}
- up->status |= AVALID;
up->burstcnt++;
}
@@ -1255,6 +1310,22 @@ chu_poll(
)
{
struct refclockproc *pp;
+
+ pp = peer->procptr;
+ pp->polls++;
+}
+
+
+/*
+ * chu_second - process minute data
+ */
+static void
+chu_second(
+ int unit,
+ struct peer *peer /* peer structure pointer */
+ )
+{
+ struct refclockproc *pp;
struct chuunit *up;
l_fp offset;
char synchar, qual, leapchar;
@@ -1262,41 +1333,25 @@ chu_poll(
double dtemp;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
- if (pp->coderecv == pp->codeproc)
- up->errflg = CEVNT_TIMEOUT;
- else
- pp->polls++;
+ up = pp->unitptr;
/*
- * If once in sync and the radio has not been heard for awhile
- * (30 m), it is no longer reachable. If not heard in a long
- * while (one day), turn out the lights and start from scratch.
+ * This routine is called once per minute to process the
+ * accumulated burst data. We do a bit of fancy footwork so that
+ * this doesn't run while burst data are being accumulated.
*/
- minset = ((current_time - peer->update) + 30) / 60;
- if (up->status & INSYNC) {
- if (minset > PANIC)
- up->status = 0;
- else if (minset <= HOLD)
- peer->reach |= 1;
- }
+ up->second = (up->second + 1) % 60;
+ if (up->second != 0)
+ return;
/*
* Process the last burst, if still in the burst buffer.
- * Don't mess with anything if nothing has been heard. If the
- * minute contains a valid A frame and valid B frame, assume
- * synchronized; however, believe the time only if within metric
- * threshold. Note the quality indicator is only for
- * diagnostics; the data are used only if in sync and above
- * metric threshold.
+ * If the minute contains a valid B frame with sufficient A
+ * frame metric, it is considered valid. However, the timecode
+ * is sent to clockstats even if invalid.
*/
chu_burst(peer);
- if (up->burstcnt == 0) {
-#ifdef ICOM
- chu_newchan(peer, 0);
-#endif /* ICOM */
- return;
- }
+ minset = ((current_time - peer->update) + 30) / 60;
dtemp = chu_major(peer);
qual = 0;
if (up->status & (BFRAME | AFRAME))
@@ -1307,7 +1362,7 @@ chu_poll(
qual |= DECERR;
if (up->status & STAMP)
qual |= TSPERR;
- if (up->status & AVALID && up->status & BVALID)
+ if (up->status & BVALID && dtemp >= MINMETRIC)
up->status |= INSYNC;
synchar = leapchar = ' ';
if (!(up->status & INSYNC)) {
@@ -1322,35 +1377,20 @@ chu_poll(
} else {
pp->leap = LEAP_NOWARNING;
}
-#ifdef HAVE_AUDIO
- if (up->fd_audio)
- sprintf(pp->a_lastcode,
- "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %d %s %.0f %d",
- synchar, qual, pp->year, pp->day, pp->hour,
- pp->minute, pp->second, leapchar, up->dst, up->dut,
- minset, up->gain, up->ident, dtemp, up->ntstamp);
- else
- sprintf(pp->a_lastcode,
- "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %s %.0f %d",
- synchar, qual, pp->year, pp->day, pp->hour,
- pp->minute, pp->second, leapchar, up->dst, up->dut,
- minset, up->ident, dtemp, up->ntstamp);
-#else
- sprintf(pp->a_lastcode,
- "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %s %.0f %d",
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%c%1X %04d %03d %02d:%02d:%02d %c%x %+d %d %d %s %.0f %d",
synchar, qual, pp->year, pp->day, pp->hour, pp->minute,
- pp->second, leapchar, up->dst, up->dut, minset, up->ident,
- dtemp, up->ntstamp);
-#endif /* HAVE_AUDIO */
+ pp->second, leapchar, up->dst, up->dut, minset, up->gain,
+ up->ident, dtemp, up->ntstamp);
pp->lencode = strlen(pp->a_lastcode);
/*
* If in sync and the signal metric is above threshold, the
* timecode is ipso fatso valid and can be selected to
- * discipline the clock. Be sure not to leave stray timestamps
- * around if signals are too weak or the clock time is invalid.
+ * discipline the clock.
*/
- if (up->status & INSYNC && dtemp > METRIC) {
+ if (up->status & INSYNC && !(up->status & (DECODE | STAMP)) &&
+ dtemp > MINMETRIC) {
if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT,
up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) {
up->errflg = CEVNT_BADTIME;
@@ -1358,15 +1398,14 @@ chu_poll(
offset.l_uf = 0;
for (i = 0; i < up->ntstamp; i++)
refclock_process_offset(pp, offset,
- up->tstamp[i], FUDGE +
+ up->tstamp[i], PDELAY +
pp->fudgetime1);
pp->lastref = up->timestamp;
refclock_receive(peer);
}
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
- } else if (pp->sloppyclockflag & CLK_FLAG4) {
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
}
+ if (dtemp > 0)
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
if (debug)
printf("chu: timecode %d %s\n", pp->lencode,
@@ -1394,66 +1433,44 @@ chu_major(
struct chuunit *up;
u_char code[11]; /* decoded timecode */
- int mindist; /* minimum distance */
- int val1, val2; /* maximum distance */
+ int metric; /* distance metric */
+ int val1; /* maximum distance */
int synchar; /* stray cat */
int temp;
int i, j, k;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Majority decoder. Each burst encodes two replications at each
* digit position in the timecode. Each row of the decoding
- * matrix encodes the number of occurrences of each digit found
+ * matrix encodes the number of occurences of each digit found
* at the corresponding position. The maximum over all
* occurrences at each position is the distance for this
- * position and the corresponding digit is the maximum
- * likelihood candidate. If the distance is zero, assume a miss
- * '_'; if the distance is not more than half the total number
- * of occurrences, assume a soft error '*'; if two different
- * digits with the same distance are found, assume a hard error
- * '='. These will later cause a format error when the timecode
- * is interpreted. The decoding distance is defined as the
- * minimum distance over the first nine digits. The tenth digit
- * varies over the seconds, so we don't count it.
+ * position and the corresponding digit is the maximum-
+ * likelihood candidate. If the distance is not more than half
+ * the total number of occurences, a majority has not been found
+ * and the data are discarded. The decoding distance is defined
+ * as the sum of the distances over the first nine digits. The
+ * tenth digit varies over the seconds, so we don't count it.
*/
- mindist = 16;
+ metric = 0;
for (i = 0; i < 9; i++) {
- val1 = val2 = 0;
+ val1 = 0;
k = 0;
for (j = 0; j < 16; j++) {
temp = up->decode[i][j] + up->decode[i + 10][j];
if (temp > val1) {
- val2 = val1;
val1 = temp;
k = j;
}
}
- if (val1 == 0)
- code[i] = HEX_MISS;
- else if (val1 == val2)
- code[i] = HEX_HARD;
- else if (val1 <= up->burstcnt)
- code[i] = HEX_SOFT;
- else
- code[i] = k;
- if (val1 < mindist)
- mindist = val1;
- code[i] = hexchar[code[i]];
+ if (val1 <= up->burstcnt)
+ up->status |= DECODE;
+ metric += val1;
+ code[i] = hexchar[k];
}
- code[i] = 0;
-
- /*
- * A valid timecode requires a minimum distance at least half
- * the total number of occurrences. A valid timecode also
- * requires at least 20 valid timestamps.
- */
- if (up->burstcnt < MINBURST || mindist < up->burstcnt)
- up->status |= DECODE;
- if (up->ntstamp < MINSTAMP)
- up->status |= STAMP;
/*
* Compute the timecode timestamp from the days, hours and
@@ -1463,15 +1480,11 @@ chu_major(
* for the years and does not use the years of the timecode.
*/
if (sscanf((char *)code, "%1x%3d%2d%2d", &synchar, &pp->day,
- &pp->hour, &pp->minute) != 4) {
- up->status |= AFORMAT;
- return (0);
- }
- if (up->status & (DECODE | STAMP)) {
- up->errflg = CEVNT_BADREPLY;
- return (0);
- }
- return (mindist * 100. / (2. * up->burstcnt));
+ &pp->hour, &pp->minute) != 4)
+ up->status |= DECODE;
+ if (up->ntstamp < MINSTAMP)
+ up->status |= STAMP;
+ return (metric);
}
@@ -1488,14 +1501,14 @@ chu_clear(
int i, j;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Clear stuff for the minute.
*/
up->ndx = up->prevsec = 0;
up->burstcnt = up->ntstamp = 0;
- up->status &= INSYNC;
+ up->status &= INSYNC | METRIC;
for (i = 0; i < 20; i++) {
for (j = 0; j < 16; j++)
up->decode[i][j] = 0;
@@ -1516,99 +1529,77 @@ chu_newchan(
struct chuunit *up;
struct refclockproc *pp;
struct xmtr *sp;
- char tbuf[80]; /* trace buffer */
int rval;
double metric;
- int i, j;
+ int i;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* The radio can be tuned to three channels: 0 (3330 kHz), 1
- * (7335 kHz) and 2 (14670 kHz). There are five one-minute
+ * (7850 kHz) and 2 (14670 kHz). There are five one-minute
* dwells in each cycle. During the first dwell the radio is
- * tuned to one of three probe channels; during the remaining
- * four dwells the radio is tuned to the data channel. The probe
- * channel is selects as the least recently used. At the end of
- * each dwell the channel metrics are measured and the highest
- * one is selected as the data channel.
+ * tuned to one of the three channels to measure the channel
+ * metric. The channel is selected as the one least recently
+ * measured. During the remaining four dwells the radio is tuned
+ * to the channel with the highest channel metric.
*/
if (up->fd_icom <= 0)
return (0);
- sp = &up->xmtr[up->achan];
+ /*
+ * Update the current channel metric and age of all channels.
+ * Scan all channels for the highest metric.
+ */
+ sp = &up->xmtr[up->chan];
sp->metric -= sp->integ[sp->iptr];
sp->integ[sp->iptr] = met;
sp->metric += sp->integ[sp->iptr];
+ sp->probe = 0;
sp->iptr = (sp->iptr + 1) % ISTAGE;
metric = 0;
- j = 0;
for (i = 0; i < NCHAN; i++) {
up->xmtr[i].probe++;
- if (i == up->achan)
- up->xmtr[i].probe = 0;
- if (up->xmtr[i].metric < metric)
- continue;
- metric = up->xmtr[i].metric;
- j = i;
- }
- if (j != up->chan && metric > 0) {
- up->chan = j;
- sprintf(tbuf, "chu: QSY to %.3f MHz metric %.0f",
- qsy[up->chan], metric);
- if (pp->sloppyclockflag & CLK_FLAG4)
- record_clock_stats(&peer->srcadr, tbuf);
-#ifdef DEBUG
- if (debug)
- printf("%s\n", tbuf);
-#endif
+ if (up->xmtr[i].metric > metric) {
+ up->status |= METRIC;
+ metric = up->xmtr[i].metric;
+ up->chan = i;
+ }
}
/*
- * Start the next dwell. We speed up the initial sync a little.
- * If not in sync and no bursts were heard the previous dwell,
- * restart the probe.
+ * Start the next dwell. If the first dwell or no stations have
+ * been heard, continue round-robin scan.
*/
- rval = 0;
- if (up->burstcnt == 0 && !(up->status & INSYNC))
- up->dwell = 0;
-#ifdef DEBUG
- if (debug)
- printf(
- "chu: at %ld dwell %d achan %d metric %.0f chan %d\n",
- current_time, up->dwell, up->achan, sp->metric,
- up->chan);
-#endif
- if (up->dwell == 0) {
+ up->dwell = (up->dwell + 1) % DWELL;
+ if (up->dwell == 0 || metric == 0) {
rval = 0;
for (i = 0; i < NCHAN; i++) {
- if (up->xmtr[i].probe < rval)
- continue;
- rval = up->xmtr[i].probe;
- up->achan = i;
- }
- rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
- qsy[up->achan] + TUNE);
-#ifdef DEBUG
- if (debug)
- printf("chu: at %ld probe channel %d\n",
- current_time, up->achan);
-#endif
- } else {
- if (up->achan != up->chan) {
- rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
- qsy[up->chan] + TUNE);
- up->achan = up->chan;
+ if (up->xmtr[i].probe > rval) {
+ rval = up->xmtr[i].probe;
+ up->chan = i;
+ }
}
}
- sprintf(up->ident, "CHU%d", up->achan);
- memcpy(&peer->refid, up->ident, 4);
- up->dwell = (up->dwell + 1) % DWELL;
+
+ /* Retune the radio at each dwell in case somebody nudges the
+ * tuning knob.
+ */
+ rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, qsy[up->chan] +
+ TUNE);
+ snprintf(up->ident, sizeof(up->ident), "CHU%d", up->chan);
+ memcpy(&pp->refid, up->ident, 4);
+ memcpy(&peer->refid, up->ident, 4);
+ if (metric == 0 && up->status & METRIC) {
+ up->status &= ~METRIC;
+ refclock_report(peer, CEVNT_PROP);
+ }
return (rval);
}
#endif /* ICOM */
+
/*
* chu_dist - determine the distance of two octet arguments
*/
@@ -1645,11 +1636,12 @@ chu_dist(
/*
* chu_gain - adjust codec gain
*
- * This routine is called once each second. If the signal envelope
- * amplitude is too low, the codec gain is bumped up by four units; if
- * too high, it is bumped down. The decoder is relatively insensitive to
- * amplitude, so this crudity works just fine. The input port is set and
- * the error flag is cleared, mostly to be ornery.
+ * This routine is called at the end of each second. During the second
+ * the number of signal clips above the MAXAMP threshold (6000). If
+ * there are no clips, the gain is bumped up; if there are more than
+ * MAXCLP clips (100), it is bumped down. The decoder is relatively
+ * insensitive to amplitude, so this crudity works just peachy. The
+ * routine also jiggles the input port and selectively mutes the
*/
static void
chu_gain(
@@ -1660,7 +1652,7 @@ chu_gain(
struct chuunit *up;
pp = peer->procptr;
- up = (struct chuunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Apparently, the codec uses only the high order bits of the
@@ -1683,5 +1675,5 @@ chu_gain(
#else
-int refclock_chu_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_conf.c b/contrib/ntp/ntpd/refclock_conf.c
index dc29d1e..30cc632 100644
--- a/contrib/ntp/ntpd/refclock_conf.c
+++ b/contrib/ntp/ntpd/refclock_conf.c
@@ -24,12 +24,6 @@ extern struct refclock refclock_local;
#define refclock_local refclock_none
#endif
-#if 0 && defined(CLOCK_TRAK) && defined(PPS)
-extern struct refclock refclock_trak;
-#else
-#define refclock_trak refclock_none
-#endif
-
#ifdef CLOCK_PST
extern struct refclock refclock_pst;
#else
@@ -138,7 +132,7 @@ extern struct refclock refclock_nmea;
#define refclock_nmea refclock_none
#endif
-#ifdef CLOCK_ATOM
+#if defined (CLOCK_ATOM) && defined(HAVE_PPSAPI)
extern struct refclock refclock_atom;
#else
#define refclock_atom refclock_none
@@ -168,8 +162,8 @@ extern struct refclock refclock_shm;
#define refclock_shm refclock_none
#endif
-#ifdef CLOCK_PALISADE
-extern struct refclock refclock_palisade;
+#ifdef CLOCK_PALISADE
+extern struct refclock refclock_palisade;
#else
#define refclock_palisade refclock_none
#endif
@@ -258,13 +252,24 @@ extern struct refclock refclock_neoclock4x;
#define refclock_neoclock4x refclock_none
#endif
+#ifdef CLOCK_TSYNCPCI
+extern struct refclock refclock_tsyncpci;
+#else
+#define refclock_tsyncpci refclock_none
+#endif
+
+#if defined(CLOCK_GPSDJSON) && !defined(SYS_WINNT)
+extern struct refclock refclock_gpsdjson;
+#else
+#define refclock_gpsdjson refclock_none
+#endif
/*
* Order is clock_start(), clock_shutdown(), clock_poll(),
* clock_control(), clock_init(), clock_buginfo, clock_flags;
*
* Types are defined in ntp.h. The index must match this.
*/
-struct refclock *refclock_conf[] = {
+struct refclock * const refclock_conf[] = {
&refclock_none, /* 0 REFCLK_NONE */
&refclock_local, /* 1 REFCLK_LOCAL */
&refclock_none, /* 2 deprecated: REFCLK_GPS_TRAK */
@@ -309,7 +314,9 @@ struct refclock *refclock_conf[] = {
&refclock_tt560, /* 41 REFCLK_TT560 */
&refclock_zyfer, /* 42 REFCLK_ZYFER */
&refclock_ripencc, /* 43 REFCLK_RIPENCC */
- &refclock_neoclock4x /* 44 REFCLK_NEOCLOCK4X */
+ &refclock_neoclock4x, /* 44 REFCLK_NEOCLOCK4X */
+ &refclock_tsyncpci, /* 45 REFCLK_TSYNCPCI */
+ &refclock_gpsdjson /* 46 REFCLK_GPSDJSON */
};
u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff --git a/contrib/ntp/ntpd/refclock_datum.c b/contrib/ntp/ntpd/refclock_datum.c
index b26fe73..95f13a8 100644
--- a/contrib/ntp/ntpd/refclock_datum.c
+++ b/contrib/ntp/ntpd/refclock_datum.c
@@ -11,6 +11,8 @@
# include <config.h>
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_DATUM)
/*
@@ -19,29 +21,16 @@
#include "ntpd.h"
#include "ntp_io.h"
+#include "ntp_tty.h"
#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
+#include "timevalops.h"
#include "ntp_stdlib.h"
#include <stdio.h>
#include <ctype.h>
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
#if defined(STREAM)
#include <stropts.h>
-#if defined(WWVBCLK)
-#include <sys/clkdefs.h>
-#endif /* WWVBCLK */
#endif /* STREAM */
#include "ntp_stdlib.h"
@@ -139,7 +128,6 @@
struct datum_pts_unit {
struct peer *peer; /* peer used by ntp */
- struct refclockio io; /* io structure used by ntp */
int PTS_fd; /* file descriptor for PTS */
u_int unit; /* id for unit */
u_long timestarted; /* time started */
@@ -166,20 +154,18 @@ struct datum_pts_unit {
static char TIME_REQUEST[6]; /* request message sent to datum for time */
static int nunits; /* number of active units */
-static struct datum_pts_unit
-**datum_pts_unit; /* dynamic array of datum PTS structures */
/*
** Callback function prototypes that ntpd needs to know about.
*/
-static int datum_pts_start P((int, struct peer *));
-static void datum_pts_shutdown P((int, struct peer *));
-static void datum_pts_poll P((int, struct peer *));
-static void datum_pts_control P((int, struct refclockstat *,
- struct refclockstat *, struct peer *));
-static void datum_pts_init P((void));
-static void datum_pts_buginfo P((int, struct refclockbug *, struct peer *));
+static int datum_pts_start (int, struct peer *);
+static void datum_pts_shutdown (int, struct peer *);
+static void datum_pts_poll (int, struct peer *);
+static void datum_pts_control (int, const struct refclockstat *,
+ struct refclockstat *, struct peer *);
+static void datum_pts_init (void);
+static void datum_pts_buginfo (int, struct refclockbug *, struct peer *);
/*
** This is the call back function structure that ntpd actually uses for
@@ -219,7 +205,7 @@ struct refclock refclock_datum = {
** the adjtime() call.
*/
-static void datum_pts_receive P((struct recvbuf *));
+static void datum_pts_receive (struct recvbuf *);
/*......................................................................*/
/* datum_pts_start - start up the datum PTS. This means open the */
@@ -232,10 +218,11 @@ datum_pts_start(
struct peer *peer
)
{
- struct datum_pts_unit **temp_datum_pts_unit;
+ struct refclockproc *pp;
struct datum_pts_unit *datum_pts;
int fd;
#ifdef HAVE_TERMIOS
+ int rc;
struct termios arg;
#endif
@@ -257,24 +244,16 @@ datum_pts_start(
/*
** Create the memory for the new unit
*/
-
- temp_datum_pts_unit = (struct datum_pts_unit **)
- malloc((nunits+1)*sizeof(struct datum_pts_unit *));
- if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
- nunits*sizeof(struct datum_pts_unit *));
- free(datum_pts_unit);
- datum_pts_unit = temp_datum_pts_unit;
- datum_pts_unit[nunits] = (struct datum_pts_unit *)
- malloc(sizeof(struct datum_pts_unit));
- datum_pts = datum_pts_unit[nunits];
-
+ datum_pts = emalloc_zero(sizeof(*datum_pts));
datum_pts->unit = unit; /* set my unit id */
datum_pts->yearstart = 0; /* initialize the yearstart to 0 */
datum_pts->sigma2 = 0.0; /* initialize the sigma2 to 0 */
datum_pts->PTS_fd = fd;
- fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */
+ if (-1 == fcntl(datum_pts->PTS_fd, F_SETFL, 0)) /* clear the descriptor flags */
+ msyslog(LOG_ERR, "MSF_ARCRON(%d): fcntl(F_SETFL, 0): %m.",
+ unit);
#ifdef DEBUG_DATUM_PTC
if (debug)
@@ -290,7 +269,7 @@ datum_pts_start(
** ntp folks so that it can become part of their regular distribution.
*/
-#ifdef HAVE_TERMIOS
+ memset(&arg, 0, sizeof(arg));
arg.c_iflag = IGNBRK;
arg.c_oflag = 0;
@@ -299,43 +278,39 @@ datum_pts_start(
arg.c_cc[VMIN] = 0; /* start timeout timer right away (not used) */
arg.c_cc[VTIME] = 30; /* 3 second timout on reads (not used) */
- tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg);
-
-#else
-
- msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver");
- (void)close(datum_pts->PTS_fd);
-
- peer->precision = PRECISION;
- pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
-
- return 0;
-
-#endif
+ rc = tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg);
+ if (rc < 0) {
+ msyslog(LOG_ERR, "Datum_PTS: tcsetattr(\"%s\") failed: %m", DATUM_DEV);
+ close(datum_pts->PTS_fd);
+ free(datum_pts);
+ return 0;
+ }
/*
** Initialize the ntpd IO structure
*/
datum_pts->peer = peer;
- datum_pts->io.clock_recv = datum_pts_receive;
- datum_pts->io.srcclock = (caddr_t)datum_pts;
- datum_pts->io.datalen = 0;
- datum_pts->io.fd = datum_pts->PTS_fd;
-
- if (!io_addclock(&(datum_pts->io))) {
-
+ pp = peer->procptr;
+ pp->io.clock_recv = datum_pts_receive;
+ pp->io.srcclock = peer;
+ pp->io.datalen = 0;
+ pp->io.fd = datum_pts->PTS_fd;
+
+ if (!io_addclock(&pp->io)) {
+ pp->io.fd = -1;
#ifdef DEBUG_DATUM_PTC
if (debug)
printf("Problem adding clock\n");
#endif
msyslog(LOG_ERR, "Datum_PTS: Problem adding clock");
- (void)close(datum_pts->PTS_fd);
+ close(datum_pts->PTS_fd);
+ free(datum_pts);
return 0;
}
+ peer->procptr->unitptr = datum_pts;
/*
** Now add one to the number of units and return a successful code
@@ -358,8 +333,8 @@ datum_pts_shutdown(
struct peer *peer
)
{
- int i,j;
- struct datum_pts_unit **temp_datum_pts_unit;
+ struct refclockproc *pp;
+ struct datum_pts_unit *datum_pts;
#ifdef DEBUG_DATUM_PTC
if (debug)
@@ -369,64 +344,18 @@ datum_pts_shutdown(
msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS");
/*
- ** First we have to find the right unit (i.e., the one with the same id).
- ** We do this by looping through the dynamic array of units intil we find
- ** it. Note, that I don't simply use an array with a maximimum number of
- ** Datum PTS units. Everything is completely dynamic.
+ ** We found the unit so close the file descriptor and free up the memory used
+ ** by the structure.
*/
-
- for (i=0; i<nunits; i++) {
- if (datum_pts_unit[i]->unit == unit) {
-
- /*
- ** We found the unit so close the file descriptor and free up the memory used
- ** by the structure.
- */
-
- io_closeclock(&datum_pts_unit[i]->io);
- close(datum_pts_unit[i]->PTS_fd);
- free(datum_pts_unit[i]);
-
- /*
- ** Now clean up the datum_pts_unit dynamic array so that there are no holes.
- ** This may mean moving pointers around, etc., to keep things compact.
- */
-
- if (nunits > 1) {
-
- temp_datum_pts_unit = (struct datum_pts_unit **)
- malloc((nunits-1)*sizeof(struct datum_pts_unit *));
- if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
- i*sizeof(struct datum_pts_unit *));
-
- for (j=i+1; j<nunits; j++) {
- temp_datum_pts_unit[j-1] = datum_pts_unit[j];
- }
-
- free(datum_pts_unit);
- datum_pts_unit = temp_datum_pts_unit;
-
- }else{
-
- free(datum_pts_unit);
- datum_pts_unit = NULL;
-
- }
-
- return;
-
- }
+ pp = peer->procptr;
+ datum_pts = pp->unitptr;
+ if (NULL != datum_pts) {
+ io_closeclock(&pp->io);
+ free(datum_pts);
}
-
-#ifdef DEBUG_DATUM_PTC
- if (debug)
- printf("Error, could not shut down unit %d\n",unit);
-#endif
-
- msyslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit);
-
}
+
/*......................................................................*/
/* datum_pts_poll - this routine sends out the time request to the */
/* Datum PTS device. The time will be passed back in the */
@@ -439,11 +368,11 @@ datum_pts_poll(
struct peer *peer
)
{
- int i;
- int unit_index;
int error_code;
struct datum_pts_unit *datum_pts;
+ datum_pts = peer->procptr->unitptr;
+
#ifdef DEBUG_DATUM_PTC
if (debug)
printf("Poll Datum PTS\n");
@@ -452,35 +381,10 @@ datum_pts_poll(
/*
** Find the right unit and send out a time request once it is found.
*/
-
- unit_index = -1;
- for (i=0; i<nunits; i++) {
- if (datum_pts_unit[i]->unit == unit) {
- unit_index = i;
- datum_pts = datum_pts_unit[i];
- error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6);
- if (error_code != 6) perror("TIME_REQUEST");
- datum_pts->nbytes = 0;
- break;
- }
- }
-
- /*
- ** Print out an error message if we could not find the right unit.
- */
-
- if (unit_index == -1) {
-
-#ifdef DEBUG_DATUM_PTC
- if (debug)
- printf("Error, could not poll unit %d\n",unit);
-#endif
-
- msyslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit);
- return;
-
- }
-
+ error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6);
+ if (error_code != 6)
+ perror("TIME_REQUEST");
+ datum_pts->nbytes = 0;
}
@@ -491,7 +395,7 @@ datum_pts_poll(
static void
datum_pts_control(
int unit,
- struct refclockstat *in,
+ const struct refclockstat *in,
struct refclockstat *out,
struct peer *peer
)
@@ -542,7 +446,6 @@ datum_pts_init(void)
** NULL since there are no units defined yet.
*/
- datum_pts_unit = NULL;
nunits = 0;
}
@@ -584,6 +487,7 @@ datum_pts_receive(
{
int i;
l_fp tstmp;
+ struct peer *p;
struct datum_pts_unit *datum_pts;
char *dpt;
int dpend;
@@ -600,13 +504,14 @@ datum_pts_receive(
** Get the time code (maybe partial) message out of the rbufp buffer.
*/
- datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock;
+ p = rbufp->recv_peer;
+ datum_pts = p->procptr->unitptr;
dpt = (char *)&rbufp->recv_space;
dpend = rbufp->recv_length;
#ifdef DEBUG_DATUM_PTC
if (debug)
- printf("Receive Datum PTS: %d bytes\n", dpend);
+ printf("Receive Datum PTS: %d bytes\n", dpend);
#endif
/* */
@@ -873,5 +778,5 @@ datum_pts_receive(
}
#else
-int refclock_datum_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_dumbclock.c b/contrib/ntp/ntpd/refclock_dumbclock.c
index 10ff2cf..89f0f47 100644
--- a/contrib/ntp/ntpd/refclock_dumbclock.c
+++ b/contrib/ntp/ntpd/refclock_dumbclock.c
@@ -35,7 +35,7 @@ extern int async_write(int, const void *, unsigned int);
*
* Input format:
*
- * hh:mm:ss <cr>
+ * hh:mm:ss <cr>
*
* hh:mm:ss -- what you'd expect, with a 24 hour clock. (Heck, that's the only
* way it could get stupider.) We take time on the <cr>.
@@ -64,21 +64,21 @@ extern int async_write(int, const void *, unsigned int);
* Dumb clock control structure
*/
struct dumbclock_unit {
- u_char tcswitch; /* timecode switch */
- l_fp laststamp; /* last receive timestamp */
- u_char lasthour; /* last hour (for monitor) */
- u_char linect; /* count ignored lines (for monitor */
- struct tm ymd; /* struct tm for y/m/d only */
+ u_char tcswitch; /* timecode switch */
+ l_fp laststamp; /* last receive timestamp */
+ u_char lasthour; /* last hour (for monitor) */
+ u_char linect; /* count ignored lines (for monitor */
+ struct tm ymd; /* struct tm for y/m/d only */
};
/*
* Function prototypes
*/
-static int dumbclock_start P((int, struct peer *));
-static void dumbclock_shutdown P((int, struct peer *));
-static void dumbclock_receive P((struct recvbuf *));
+static int dumbclock_start (int, struct peer *);
+static void dumbclock_shutdown (int, struct peer *);
+static void dumbclock_receive (struct recvbuf *);
#if 0
-static void dumbclock_poll P((int, struct peer *));
+static void dumbclock_poll (int, struct peer *);
#endif
/*
@@ -115,33 +115,30 @@ dumbclock_start(
* Open serial port. Don't bother with CLK line discipline, since
* it's not available.
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
#ifdef DEBUG
if (debug)
printf ("starting Dumbclock with device %s\n",device);
#endif
fd = refclock_open(device, SPEED232, 0);
- if (fd < 0)
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- up = (struct dumbclock_unit *)emalloc(sizeof(struct dumbclock_unit));
- if (up == NULL) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct dumbclock_unit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = dumbclock_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
+ pp->unitptr = NULL;
return (0);
}
@@ -153,14 +150,10 @@ dumbclock_start(
tm_time_p = gmtime(&now);
#endif
if (tm_time_p)
- {
- up->ymd = *tm_time_p;
- }
+ up->ymd = *tm_time_p;
else
- {
- return 0;
- }
-
+ return 0;
+
/*
* Initialize miscellaneous variables
*/
@@ -184,9 +177,11 @@ dumbclock_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct dumbclock_unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -202,19 +197,19 @@ dumbclock_receive(
struct refclockproc *pp;
struct peer *peer;
- l_fp trtmp; /* arrival timestamp */
- int hours; /* hour-of-day */
- int minutes; /* minutes-past-the-hour */
- int seconds; /* seconds */
- int temp; /* int temp */
- int got_good; /* got a good time flag */
+ l_fp trtmp; /* arrival timestamp */
+ int hours; /* hour-of-day */
+ int minutes; /* minutes-past-the-hour */
+ int seconds; /* seconds */
+ int temp; /* int temp */
+ int got_good; /* got a good time flag */
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct dumbclock_unit *)pp->unitptr;
+ up = pp->unitptr;
temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
if (temp == 0) {
@@ -222,7 +217,7 @@ dumbclock_receive(
up->tcswitch = 1;
up->laststamp = trtmp;
} else
- up->tcswitch = 0;
+ up->tcswitch = 0;
return;
}
pp->lencode = (u_short)temp;
@@ -249,16 +244,18 @@ dumbclock_receive(
struct tm asserted_tm; /* the struct tm of the same */
int adjyear;
int adjmon;
- int reality_delta;
+ time_t reality_delta;
time_t now;
/*
* Convert to GMT for sites that distribute localtime. This
- * means we have to figure out what day it is. Easier said
+ * means we have to figure out what day it is. Easier said
* than done...
*/
+ memset(&asserted_tm, 0, sizeof(asserted_tm));
+
asserted_tm.tm_year = up->ymd.tm_year;
asserted_tm.tm_mon = up->ymd.tm_mon;
asserted_tm.tm_mday = up->ymd.tm_mday;
@@ -366,7 +363,7 @@ dumbclock_poll(
*/
#if 0
pp = peer->procptr;
- up = (struct dumbclock_unit *)pp->unitptr;
+ up = pp->unitptr;
if (peer->reach == 0)
refclock_report(peer, CEVNT_TIMEOUT);
if (up->linect > 0)
@@ -383,4 +380,4 @@ dumbclock_poll(
#else
int refclock_dumbclock_bs;
-#endif /* REFCLOCK */
+#endif /* defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) */
diff --git a/contrib/ntp/ntpd/refclock_fg.c b/contrib/ntp/ntpd/refclock_fg.c
index ce5085a..d5915da 100644
--- a/contrib/ntp/ntpd/refclock_fg.c
+++ b/contrib/ntp/ntpd/refclock_fg.c
@@ -33,20 +33,20 @@
/*
* Function prototypes
*/
-static int fg_init P((int));
-static int fg_start P((int, struct peer *));
-static void fg_shutdown P((int, struct peer *));
-static void fg_poll P((int, struct peer *));
-static void fg_receive P((struct recvbuf *));
+static int fg_init (int);
+static int fg_start (int, struct peer *);
+static void fg_shutdown (int, struct peer *);
+static void fg_poll (int, struct peer *);
+static void fg_receive (struct recvbuf *);
/*
* Forum Graphic unit control structure
*/
struct fgunit {
- int pollnum; /* Use peer.poll instead? */
- int status; /* Hug to check status information on GPS */
- int y2kwarn; /* Y2K bug */
+ int pollnum; /* Use peer.poll instead? */
+ int status; /* Hug to check status information on GPS */
+ int y2kwarn; /* Y2K bug */
};
/*
@@ -61,13 +61,13 @@ static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
* Transfer vector
*/
struct refclock refclock_fg = {
- fg_start, /* start up driver */
- fg_shutdown, /* shut down driver */
- fg_poll, /* transmit poll message */
- noentry, /* not used */
- noentry, /* initialize driver (not used) */
- noentry, /* not used */
- NOFLAGS /* not used */
+ fg_start, /* start up driver */
+ fg_shutdown, /* shut down driver */
+ fg_poll, /* transmit poll message */
+ noentry, /* not used */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used */
+ NOFLAGS /* not used */
};
/*
@@ -76,14 +76,13 @@ struct refclock refclock_fg = {
static int
fg_init(
- int fd
- )
+ int fd
+ )
{
if (write(fd, fginit, LENFG) != LENFG)
- return 0;
-
- return (1);
+ return 0;
+ return 1;
}
/*
@@ -91,7 +90,7 @@ fg_init(
*/
static int
fg_start(
- int unit,
+ int unit,
struct peer *peer
)
{
@@ -104,35 +103,31 @@ fg_start(
/*
* Open device file for reading.
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
-#ifdef DEBUG
- if (debug)
- printf ("starting FG with device %s\n",device);
-#endif
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
- return (0);
+ DPRINTF(1, ("starting FG with device %s\n",device));
+
+ fd = refclock_open(device, SPEED232, LDISC_CLK);
+ if (fd <= 0)
+ return (0);
- /*
- * Allocate and initialize unit structure
- */
-
- if (!(up = (struct fgunit *)
- emalloc(sizeof(struct fgunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct fgunit));
+ /*
+ * Allocate and initialize unit structure
+ */
+
+ up = emalloc(sizeof(struct fgunit));
+ memset(up, 0, sizeof(struct fgunit));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = fg_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
- return (0);
- }
+ close(fd);
+ pp->io.fd = -1;
+ return 0;
+ }
/*
@@ -140,13 +135,13 @@ fg_start(
*/
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 3);
+ memcpy(&pp->refid, REFID, 3);
up->pollnum = 0;
/*
* Setup dating station to use GPS receiver.
* GPS receiver should work before this operation.
- */
+ */
if(!fg_init(pp->io.fd))
refclock_report(peer, CEVNT_FAULT);
@@ -167,9 +162,11 @@ fg_shutdown(
struct fgunit *up;
pp = peer->procptr;
- up = (struct fgunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (pp->io.fd != -1)
+ io_closeclock(&pp->io);
+ if (up != NULL)
+ free(up);
}
@@ -186,30 +183,26 @@ fg_poll(
pp = peer->procptr;
- /*
- * Time to poll the clock. The FG clock responds to a
- * "<DLE>D<DLE><CR>" by returning a timecode in the format specified
- * above. If nothing is heard from the clock for two polls,
- * declare a timeout and keep going.
- */
+ /*
+ * Time to poll the clock. The FG clock responds to a
+ * "<DLE>D<DLE><CR>" by returning a timecode in the format specified
+ * above. If nothing is heard from the clock for two polls,
+ * declare a timeout and keep going.
+ */
if (write(pp->io.fd, fgdate, LENFG) != LENFG)
- refclock_report(peer, CEVNT_FAULT);
- else
- pp->polls++;
+ refclock_report(peer, CEVNT_FAULT);
+ else
+ pp->polls++;
- if (peer->burst > 0)
- return;
/*
- if (pp->coderecv == pp->codeproc) {
- refclock_report(peer, CEVNT_TIMEOUT);
- return;
- }
+ if (pp->coderecv == pp->codeproc) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ return;
+ }
*/
- peer->burst = NSTAGE;
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
-
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
return;
@@ -220,36 +213,34 @@ fg_poll(
*/
static void
fg_receive(
- struct recvbuf *rbufp
- )
+ struct recvbuf *rbufp
+ )
{
- struct refclockproc *pp;
+ struct refclockproc *pp;
struct fgunit *up;
- struct peer *peer;
+ struct peer *peer;
char *bpt;
- /*
- * Initialize pointers and read the timecode and timestamp
+ /*
+ * Initialize pointers and read the timecode and timestamp
* We can't use gtlin function because we need bynary data in buf */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct fgunit *)pp->unitptr;
+ peer = rbufp->recv_peer;
+ pp = peer->procptr;
+ up = pp->unitptr;
/*
- * Below hug to implement receiving of status information
- */
- if(!up->pollnum)
- {
+ * Below hug to implement receiving of status information
+ */
+ if(!up->pollnum) {
up->pollnum++;
return;
}
- if (rbufp->recv_length < (LENFG-2))
- {
+ if (rbufp->recv_length < (LENFG - 2)) {
refclock_report(peer, CEVNT_BADREPLY);
- return; /* The reply is invalid discard it. */
+ return; /* The reply is invalid discard it. */
}
/* Below I trying to find a correct reply in buffer.
@@ -258,30 +249,29 @@ fg_receive(
*/
bpt = (char *)rbufp->recv_space.X_recv_buffer;
- while(*bpt != '')
+ while (*bpt != '\x10')
bpt++;
#define BP2(x) ( bpt[x] & 15 )
#define BP1(x) (( bpt[x] & 240 ) >> 4)
- pp->year = BP1(2)*10 + BP2(2);
+ pp->year = BP1(2) * 10 + BP2(2);
- if(pp->year == 94)
- {
+ if (pp->year == 94) {
refclock_report(peer, CEVNT_BADREPLY);
- if(!fg_init(pp->io.fd))
+ if (!fg_init(pp->io.fd))
refclock_report(peer, CEVNT_FAULT);
- return;
+ return;
/* GPS is just powered up. The date is invalid -
discarding it. Initilize GPS one more time */
/* Sorry - this driver will broken in 2094 ;) */
}
if (pp->year < 99)
- pp->year += 100;
+ pp->year += 100;
- pp->year += 1900;
- pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);
+ pp->year += 1900;
+ pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);
/*
After Jan, 10 2000 Forum Graphic GPS receiver had a very strange
@@ -290,51 +280,51 @@ fg_receive(
Hope it is a problem of my unit only and not a Y2K problem of FG GPS.
Below small code to avoid such situation.
*/
- if(up->y2kwarn > 10)
- pp->hour = BP1(6)*10 + BP2(6);
+ if (up->y2kwarn > 10)
+ pp->hour = BP1(6)*10 + BP2(6);
else
- pp->hour = BP1(5)*10 + BP2(5);
-
- if((up->y2kwarn > 10) && (pp->hour == 10))
- {
- pp->minute = BP1(7)*10 + BP2(7);
- pp->second = BP1(8)*10 + BP2(8);
- pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000;
- pp->nsec += BP1(10) * 1000;
+ pp->hour = BP1(5)*10 + BP2(5);
+
+ if ((up->y2kwarn > 10) && (pp->hour == 10)) {
+ pp->minute = BP1(7)*10 + BP2(7);
+ pp->second = BP1(8)*10 + BP2(8);
+ pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000;
+ pp->nsec += BP1(10) * 1000;
} else {
- pp->hour = BP1(5)*10 + BP2(5);
- pp->minute = BP1(6)*10 + BP2(6);
- pp->second = BP1(7)*10 + BP2(7);
- pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000;
- pp->nsec += BP1(9) * 1000;
+ pp->hour = BP1(5)*10 + BP2(5);
+ pp->minute = BP1(6)*10 + BP2(6);
+ pp->second = BP1(7)*10 + BP2(7);
+ pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000;
+ pp->nsec += BP1(9) * 1000;
}
-
- if((pp->hour == 10) && (pp->minute == 10))
- {
+
+ if ((pp->hour == 10) && (pp->minute == 10)) {
up->y2kwarn++;
}
- sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second);
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%d %d %d %d %d", pp->year, pp->day, pp->hour,
+ pp->minute, pp->second);
pp->lencode = strlen(pp->a_lastcode);
- /*get_systime(&pp->lastrec);*/
+ /*get_systime(&pp->lastrec);*/
#ifdef DEBUG
- if (debug)
- printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
- pp->year, pp->day, pp->hour, pp->minute, pp->second);
+ if (debug)
+ printf("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
+ pp->year, pp->day, pp->hour, pp->minute, pp->second);
#endif
- pp->disp = (10e-6);
+ pp->disp = (10e-6);
pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */
/* pp->leap = LEAP_NOWARNING; */
- /*
- * Process the new sample in the median filter and determine the
- * timecode timestamp.
- */
+ /*
+ * Process the new sample in the median filter and determine the
+ * timecode timestamp.
+ */
- if (!refclock_process(pp))
- refclock_report(peer, CEVNT_BADTIME);
- pp->lastref = pp->lastrec;
+ if (!refclock_process(pp))
+ refclock_report(peer, CEVNT_BADTIME);
+ pp->lastref = pp->lastrec;
refclock_receive(peer);
return;
}
diff --git a/contrib/ntp/ntpd/refclock_gpsdjson.c b/contrib/ntp/ntpd/refclock_gpsdjson.c
new file mode 100644
index 0000000..0a88cec
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_gpsdjson.c
@@ -0,0 +1,2210 @@
+/*
+ * refclock_gpsdjson.c - clock driver as GPSD JSON client
+ * Juergen Perlinger (perlinger@ntp.org)
+ * Feb 11, 2014 for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ *
+ * Heavily inspired by refclock_nmea.c
+ *
+ * Special thanks to Gary Miller and Hal Murray for their comments and
+ * ideas.
+ *
+ * Note: This will currently NOT work with Windows due to some
+ * limitations:
+ *
+ * - There is no GPSD for Windows. (There is an unofficial port to
+ * cygwin, but Windows is not officially supported.)
+ *
+ * - To work properly, this driver needs PPS and TPV/TOFF sentences
+ * from GPSD. I don't see how the cygwin port should deal with the
+ * PPS signal.
+ *
+ * - The device name matching must be done in a different way for
+ * Windows. (Can be done with COMxx matching, as done for NMEA.)
+ *
+ * Apart from those minor hickups, once GPSD has been fully ported to
+ * Windows, there's no reason why this should not work there ;-) If this
+ * is ever to happen at all is a different question.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * This driver works slightly different from most others, as the PPS
+ * information (if available) is also coming from GPSD via the data
+ * connection. This makes using both the PPS data and the serial data
+ * easier, but OTOH it's not possible to use the ATOM driver to feed a
+ * raw PPS stream to the core of NTPD.
+ *
+ * To go around this, the driver can use a secondary clock unit
+ * (units>=128) that operate in tandem with the primary clock unit
+ * (unit%128). The primary clock unit does all the IO stuff and data
+ * decoding; if a a secondary unit is attached to a primary unit, this
+ * secondary unit is feed with the PPS samples only and can act as a PPS
+ * source to the clock selection.
+ *
+ * The drawback is that the primary unit must be present for the
+ * secondary unit to work.
+ *
+ * This design is a compromise to reduce the IO load for both NTPD and
+ * GPSD; it also ensures that data is transmitted and evaluated only
+ * once on the side of NTPD.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * trouble shooting hints:
+ *
+ * Enable and check the clock stats. Check if there are bad replies;
+ * there should be none. If there are actually bad replies, then the
+ * driver cannot parse all JSON records from GPSD, and some record
+ * types are vital for the operation of the driver. This indicates a
+ * problem on the protocol level.
+ *
+ * When started on the command line with a debug level >= 2, the
+ * driver dumps the raw received data and the parser input to
+ * stdout. Since the debug level is global, NTPD starts to create a
+ * *lot* of output. It makes sense to pipe it through '(f)grep
+ * GPSD_JSON' before writing the result to disk.
+ *
+ * A bit less intrusive is using netcat or telnet to connect to GPSD
+ * and snoop what NTPD would get. If you try this, you have to send a
+ * WATCH command to GPSD:
+ *
+ * ?WATCH={"device":"/dev/gps0","enable":true,"json":true,"pps":true};<CRLF>
+ *
+ * should show you what GPSD has to say to NTPD. Replace "/dev/gps0"
+ * with the device link used by GPSD, if necessary.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ntp_types.h"
+
+#if defined(REFCLOCK) && defined(CLOCK_GPSDJSON) && !defined(SYS_WINNT)
+
+/* =====================================================================
+ * Get the little JSMN library directly into our guts. Use the 'parent
+ * link' feature for maximum speed.
+ */
+#define JSMN_PARENT_LINKS
+#include "../libjsmn/jsmn.c"
+
+/* =====================================================================
+ * JSON parsing stuff
+ */
+
+#define JSMN_MAXTOK 350
+#define INVALID_TOKEN (-1)
+
+typedef struct json_ctx {
+ char * buf;
+ int ntok;
+ jsmntok_t tok[JSMN_MAXTOK];
+} json_ctx;
+
+typedef int tok_ref;
+
+/* Not all targets have 'long long', and not all of them have 'strtoll'.
+ * Sigh. We roll our own integer number parser.
+ */
+#ifdef HAVE_LONG_LONG
+typedef signed long long int json_int;
+typedef unsigned long long int json_uint;
+#define JSON_INT_MAX LLONG_MAX
+#define JSON_INT_MIN LLONG_MIN
+#else
+typedef signed long int json_int;
+typedef unsigned long int json_uint;
+#define JSON_INT_MAX LONG_MAX
+#define JSON_INT_MIN LONG_MIN
+#endif
+
+/* =====================================================================
+ * header stuff we need
+ */
+
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/tcp.h>
+
+#if defined(HAVE_SYS_POLL_H)
+# include <sys/poll.h>
+#elif defined(HAVE_SYS_SELECT_H)
+# include <sys/select.h>
+#else
+# error need poll() or select()
+#endif
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+#include "ntp_calendar.h"
+#include "timespecops.h"
+
+/* get operation modes from mode word.
+
+ * + SERIAL (default) evaluates only serial time information ('STI') as
+ * provided by TPV and TOFF records. TPV evaluation suffers from a
+ * bigger jitter than TOFF, sine it does not contain the receive time
+ * from GPSD and therefore the receive time of NTPD must be
+ * substituted for it. The network latency makes this a second rate
+ * guess.
+ *
+ * If TOFF records are detected in the data stream, the timing
+ * information is gleaned from this record -- it contains the local
+ * receive time stamp from GPSD and therefore eliminates the
+ * transmission latency between GPSD and NTPD. The timing information
+ * from TPV is ignored once a TOFF is detected or expected.
+ *
+ * TPV is still used to check the fix status, so the driver can stop
+ * feeding samples when GPSD says that the time information is
+ * effectively unreliable.
+ *
+ * + STRICT means only feed clock samples when a valid STI/PPS pair is
+ * available. Combines the reference time from STI with the pulse time
+ * from PPS. Masks the serial data jitter as long PPS is available,
+ * but can rapidly deteriorate once PPS drops out.
+ *
+ * + AUTO tries to use STI/PPS pairs if available for some time, and if
+ * this fails for too long switches back to STI only until the PPS
+ * signal becomes available again. See the HTML docs for this driver
+ * about the gotchas and why this is not the default.
+ */
+#define MODE_OP_MASK 0x03
+#define MODE_OP_STI 0
+#define MODE_OP_STRICT 1
+#define MODE_OP_AUTO 2
+#define MODE_OP_MAXVAL 2
+#define MODE_OP_MODE(x) ((x) & MODE_OP_MASK)
+
+#define PRECISION (-9) /* precision assumed (about 2 ms) */
+#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
+#define REFID "GPSD" /* reference id */
+#define DESCRIPTION "GPSD JSON client clock" /* who we are */
+
+#define MAX_PDU_LEN 1600
+#define TICKOVER_LOW 10
+#define TICKOVER_HIGH 120
+#define LOGTHROTTLE 3600
+
+/* Primary channel PPS avilability dance:
+ * Every good PPS sample gets us a credit of PPS_INCCOUNT points, every
+ * bad/missing PPS sample costs us a debit of PPS_DECCOUNT points. When
+ * the account reaches the upper limit we change to a mode where only
+ * PPS-augmented samples are fed to the core; when the account drops to
+ * zero we switch to a mode where TPV-only timestamps are fed to the
+ * core.
+ * This reduces the chance of rapid alternation between raw and
+ * PPS-augmented time stamps.
+ */
+#define PPS_MAXCOUNT 60 /* upper limit of account */
+#define PPS_INCCOUNT 3 /* credit for good samples */
+#define PPS_DECCOUNT 1 /* debit for bad samples */
+
+/* The secondary (PPS) channel uses a different strategy to avoid old
+ * PPS samples in the median filter.
+ */
+#define PPS2_MAXCOUNT 10
+
+#ifndef BOOL
+# define BOOL int
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#define PROTO_VERSION(hi,lo) \
+ ((((uint32_t)(hi) << 16) & 0xFFFF0000u) | \
+ ((uint32_t)(lo) & 0x0FFFFu))
+
+/* some local typedefs: The NTPD formatting style cries for short type
+ * names, and we provide them locally. Note:the suffix '_t' is reserved
+ * for the standard; I use a capital T instead.
+ */
+typedef struct peer peerT;
+typedef struct refclockproc clockprocT;
+typedef struct addrinfo addrinfoT;
+
+/* =====================================================================
+ * We use the same device name scheme as does the NMEA driver; since
+ * GPSD supports the same links, we can select devices by a fixed name.
+ */
+static const char * s_dev_stem = "/dev/gps";
+
+/* =====================================================================
+ * forward declarations for transfer vector and the vector itself
+ */
+
+static void gpsd_init (void);
+static int gpsd_start (int, peerT *);
+static void gpsd_shutdown (int, peerT *);
+static void gpsd_receive (struct recvbuf *);
+static void gpsd_poll (int, peerT *);
+static void gpsd_control (int, const struct refclockstat *,
+ struct refclockstat *, peerT *);
+static void gpsd_timer (int, peerT *);
+
+static int myasprintf(char**, char const*, ...) NTP_PRINTF(2, 3);
+
+static void enter_opmode(peerT *peer, int mode);
+static void leave_opmode(peerT *peer, int mode);
+
+struct refclock refclock_gpsdjson = {
+ gpsd_start, /* start up driver */
+ gpsd_shutdown, /* shut down driver */
+ gpsd_poll, /* transmit poll message */
+ gpsd_control, /* fudge control */
+ gpsd_init, /* initialize driver */
+ noentry, /* buginfo */
+ gpsd_timer /* called once per second */
+};
+
+/* =====================================================================
+ * our local clock unit and data
+ */
+struct gpsd_unit;
+typedef struct gpsd_unit gpsd_unitT;
+
+struct gpsd_unit {
+ /* links for sharing between master/slave units */
+ gpsd_unitT *next_unit;
+ size_t refcount;
+
+ /* data for the secondary PPS channel */
+ peerT *pps_peer;
+
+ /* unit and operation modes */
+ int unit;
+ int mode;
+ char *logname; /* cached name for log/print */
+ char * device; /* device name of unit */
+
+ /* current line protocol version */
+ uint32_t proto_version;
+
+ /* PPS time stamps primary + secondary channel */
+ l_fp pps_local; /* when we received the PPS message */
+ l_fp pps_stamp; /* related reference time */
+ l_fp pps_recvt; /* when GPSD detected the pulse */
+ l_fp pps_stamp2;/* related reference time (secondary) */
+ l_fp pps_recvt2;/* when GPSD detected the pulse (secondary)*/
+ int ppscount; /* PPS counter (primary unit) */
+ int ppscount2; /* PPS counter (secondary unit) */
+
+ /* TPV or TOFF serial time information */
+ l_fp sti_local; /* when we received the TPV/TOFF message */
+ l_fp sti_stamp; /* effective GPS time stamp */
+ l_fp sti_recvt; /* when GPSD got the fix */
+
+ /* precision estimates */
+ int16_t sti_prec; /* serial precision based on EPT */
+ int16_t pps_prec; /* PPS precision from GPSD or above */
+
+ /* fudge values for correction, mirrored as 'l_fp' */
+ l_fp pps_fudge; /* PPS fudge primary channel */
+ l_fp pps_fudge2; /* PPS fudge secondary channel */
+ l_fp sti_fudge; /* TPV/TOFF serial data fudge */
+
+ /* Flags to indicate available data */
+ int fl_nosync: 1; /* GPSD signals bad quality */
+ int fl_sti : 1; /* valid TPV/TOFF seen (have time) */
+ int fl_pps : 1; /* valid pulse seen */
+ int fl_pps2 : 1; /* valid pulse seen for PPS channel */
+ int fl_rawsti: 1; /* permit raw TPV/TOFF time stamps */
+ int fl_vers : 1; /* have protocol version */
+ int fl_watch : 1; /* watch reply seen */
+ /* protocol flags */
+ int pf_nsec : 1; /* have nanosec PPS info */
+ int pf_toff : 1; /* have TOFF record for timing */
+
+ /* admin stuff for sockets and device selection */
+ int fdt; /* current connecting socket */
+ addrinfoT * addr; /* next address to try */
+ u_int tickover; /* timeout countdown */
+ u_int tickpres; /* timeout preset */
+
+ /* tallies for the various events */
+ u_int tc_recv; /* received known records */
+ u_int tc_breply; /* bad replies / parsing errors */
+ u_int tc_nosync; /* TPV / sample cycles w/o fix */
+ u_int tc_sti_recv;/* received serial time info records */
+ u_int tc_sti_used;/* used --^-- */
+ u_int tc_pps_recv;/* received PPS timing info records */
+ u_int tc_pps_used;/* used --^-- */
+
+ /* log bloat throttle */
+ u_int logthrottle;/* seconds to next log slot */
+
+ /* The parse context for the current record */
+ json_ctx json_parse;
+
+ /* record assemby buffer and saved length */
+ int buflen;
+ char buffer[MAX_PDU_LEN];
+};
+
+/* =====================================================================
+ * static local helpers forward decls
+ */
+static void gpsd_init_socket(peerT * const peer);
+static void gpsd_test_socket(peerT * const peer);
+static void gpsd_stop_socket(peerT * const peer);
+
+static void gpsd_parse(peerT * const peer,
+ const l_fp * const rtime);
+static BOOL convert_ascii_time(l_fp * fp, const char * gps_time);
+static void save_ltc(clockprocT * const pp, const char * const tc);
+static int syslogok(clockprocT * const pp, gpsd_unitT * const up);
+static void log_data(peerT *peer, const char *what,
+ const char *buf, size_t len);
+static int16_t clamped_precision(int rawprec);
+
+/* =====================================================================
+ * local / static stuff
+ */
+
+/* The logon string is actually the ?WATCH command of GPSD, using JSON
+ * data and selecting the GPS device name we created from our unit
+ * number. We have an old a newer version that request PPS (and TOFF)
+ * transmission.
+ * Note: These are actually format strings!
+ */
+static const char * const s_req_watch[2] = {
+ "?WATCH={\"device\":\"%s\",\"enable\":true,\"json\":true};\r\n",
+ "?WATCH={\"device\":\"%s\",\"enable\":true,\"json\":true,\"pps\":true};\r\n"
+};
+
+static const char * const s_req_version =
+ "?VERSION;\r\n";
+
+/* We keep a static list of network addresses for 'localhost:gpsd' or a
+ * fallback alias of it, and we try to connect to them in round-robin
+ * fashion. The service lookup is done during the driver init
+ * function to minmise the impact of 'getaddrinfo()'.
+ *
+ * Alas, the init function is called even if there are no clocks
+ * configured for this driver. So it makes sense to defer the logging of
+ * any errors or other notifications until the first clock unit is
+ * started -- otherwise there might be syslog entries from a driver that
+ * is not used at all.
+ */
+static addrinfoT *s_gpsd_addr;
+static gpsd_unitT *s_clock_units;
+
+/* list of service/socket names we want to resolve against */
+static const char * const s_svctab[][2] = {
+ { "localhost", "gpsd" },
+ { "localhost", "2947" },
+ { "127.0.0.1", "2947" },
+ { NULL, NULL }
+};
+
+/* list of address resolution errors and index of service entry that
+ * finally worked.
+ */
+static int s_svcerr[sizeof(s_svctab)/sizeof(s_svctab[0])];
+static int s_svcidx;
+
+/* =====================================================================
+ * log throttling
+ */
+static int/*BOOL*/
+syslogok(
+ clockprocT * const pp,
+ gpsd_unitT * const up)
+{
+ int res = (0 != (pp->sloppyclockflag & CLK_FLAG3))
+ || (0 == up->logthrottle )
+ || (LOGTHROTTLE == up->logthrottle );
+ if (res)
+ up->logthrottle = LOGTHROTTLE;
+ return res;
+}
+
+/* =====================================================================
+ * the clock functions
+ */
+
+/* ---------------------------------------------------------------------
+ * Init: This currently just gets the socket address for the GPS daemon
+ */
+static void
+gpsd_init(void)
+{
+ addrinfoT hints;
+ int rc, idx;
+
+ memset(s_svcerr, 0, sizeof(s_svcerr));
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_socktype = SOCK_STREAM;
+
+ for (idx = 0; s_svctab[idx][0] && !s_gpsd_addr; idx++) {
+ rc = getaddrinfo(s_svctab[idx][0], s_svctab[idx][1],
+ &hints, &s_gpsd_addr);
+ s_svcerr[idx] = rc;
+ if (0 == rc)
+ break;
+ s_gpsd_addr = NULL;
+ }
+ s_svcidx = idx;
+}
+
+/* ---------------------------------------------------------------------
+ * Init Check: flush pending log messages and check if we can proceed
+ */
+static int/*BOOL*/
+gpsd_init_check(void)
+{
+ int idx;
+
+ /* Check if there is something to log */
+ if (s_svcidx == 0)
+ return (s_gpsd_addr != NULL);
+
+ /* spool out the resolver errors */
+ for (idx = 0; idx < s_svcidx; ++idx) {
+ msyslog(LOG_WARNING,
+ "GPSD_JSON: failed to resolve '%s:%s', rc=%d (%s)",
+ s_svctab[idx][0], s_svctab[idx][1],
+ s_svcerr[idx], gai_strerror(s_svcerr[idx]));
+ }
+
+ /* check if it was fatal, or if we can proceed */
+ if (s_gpsd_addr == NULL)
+ msyslog(LOG_ERR, "%s",
+ "GPSD_JSON: failed to get socket address, giving up.");
+ else if (idx != 0)
+ msyslog(LOG_WARNING,
+ "GPSD_JSON: using '%s:%s' instead of '%s:%s'",
+ s_svctab[idx][0], s_svctab[idx][1],
+ s_svctab[0][0], s_svctab[0][1]);
+
+ /* make sure this gets logged only once and tell if we can
+ * proceed or not
+ */
+ s_svcidx = 0;
+ return (s_gpsd_addr != NULL);
+}
+
+/* ---------------------------------------------------------------------
+ * Start: allocate a unit pointer and set up the runtime data
+ */
+static int
+gpsd_start(
+ int unit,
+ peerT * peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * up;
+ gpsd_unitT ** uscan = &s_clock_units;
+
+ struct stat sb;
+
+ /* check if we can proceed at all or if init failed */
+ if ( ! gpsd_init_check())
+ return FALSE;
+
+ /* search for matching unit */
+ while ((up = *uscan) != NULL && up->unit != (unit & 0x7F))
+ uscan = &up->next_unit;
+ if (up == NULL) {
+ /* alloc unit, add to list and increment use count ASAP. */
+ up = emalloc_zero(sizeof(*up));
+ *uscan = up;
+ ++up->refcount;
+
+ /* initialize the unit structure */
+ up->logname = estrdup(refnumtoa(&peer->srcadr));
+ up->unit = unit & 0x7F;
+ up->fdt = -1;
+ up->addr = s_gpsd_addr;
+ up->tickpres = TICKOVER_LOW;
+
+ /* Create the device name and check for a Character
+ * Device. It's assumed that GPSD was started with the
+ * same link, so the names match. (If this is not
+ * practicable, we will have to read the symlink, if
+ * any, so we can get the true device file.)
+ */
+ if (-1 == myasprintf(&up->device, "%s%u",
+ s_dev_stem, up->unit)) {
+ msyslog(LOG_ERR, "%s: clock device name too long",
+ up->logname);
+ goto dev_fail;
+ }
+ if (-1 == stat(up->device, &sb) || !S_ISCHR(sb.st_mode)) {
+ msyslog(LOG_ERR, "%s: '%s' is not a character device",
+ up->logname, up->device);
+ goto dev_fail;
+ }
+ } else {
+ /* All set up, just increment use count. */
+ ++up->refcount;
+ }
+
+ /* setup refclock processing */
+ pp->unitptr = (caddr_t)up;
+ pp->io.fd = -1;
+ pp->io.clock_recv = gpsd_receive;
+ pp->io.srcclock = peer;
+ pp->io.datalen = 0;
+ pp->a_lastcode[0] = '\0';
+ pp->lencode = 0;
+ pp->clockdesc = DESCRIPTION;
+ memcpy(&pp->refid, REFID, 4);
+
+ /* Initialize miscellaneous variables */
+ if (unit >= 128)
+ peer->precision = PPS_PRECISION;
+ else
+ peer->precision = PRECISION;
+
+ /* If the daemon name lookup failed, just give up now. */
+ if (NULL == up->addr) {
+ msyslog(LOG_ERR, "%s: no GPSD socket address, giving up",
+ up->logname);
+ goto dev_fail;
+ }
+
+ LOGIF(CLOCKINFO,
+ (LOG_NOTICE, "%s: startup, device is '%s'",
+ refnumtoa(&peer->srcadr), up->device));
+ up->mode = MODE_OP_MODE(peer->ttl);
+ if (up->mode > MODE_OP_MAXVAL)
+ up->mode = 0;
+ if (unit >= 128)
+ up->pps_peer = peer;
+ else
+ enter_opmode(peer, up->mode);
+ return TRUE;
+
+dev_fail:
+ /* On failure, remove all UNIT ressources and declare defeat. */
+
+ INSIST (up);
+ if (!--up->refcount) {
+ *uscan = up->next_unit;
+ free(up->device);
+ free(up);
+ }
+
+ pp->unitptr = (caddr_t)NULL;
+ return FALSE;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_shutdown(
+ int unit,
+ peerT * peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+ gpsd_unitT ** uscan = &s_clock_units;
+
+ UNUSED_ARG(unit);
+
+ /* The unit pointer might have been removed already. */
+ if (up == NULL)
+ return;
+
+ /* now check if we must close IO resources */
+ if (peer != up->pps_peer) {
+ if (-1 != pp->io.fd) {
+ DPRINTF(1, ("%s: closing clock, fd=%d\n",
+ up->logname, pp->io.fd));
+ io_closeclock(&pp->io);
+ pp->io.fd = -1;
+ }
+ if (up->fdt != -1)
+ close(up->fdt);
+ }
+ /* decrement use count and eventually remove this unit. */
+ if (!--up->refcount) {
+ /* unlink this unit */
+ while (*uscan != NULL)
+ if (*uscan == up)
+ *uscan = up->next_unit;
+ else
+ uscan = &(*uscan)->next_unit;
+ free(up->logname);
+ free(up->device);
+ free(up);
+ }
+ pp->unitptr = (caddr_t)NULL;
+ LOGIF(CLOCKINFO,
+ (LOG_NOTICE, "%s: shutdown", refnumtoa(&peer->srcadr)));
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_receive(
+ struct recvbuf * rbufp)
+{
+ /* declare & init control structure ptrs */
+ peerT * const peer = rbufp->recv_peer;
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ const char *psrc, *esrc;
+ char *pdst, *edst, ch;
+
+ /* log the data stream, if this is enabled */
+ log_data(peer, "recv", (const char*)rbufp->recv_buffer,
+ (size_t)rbufp->recv_length);
+
+
+ /* Since we're getting a raw stream data, we must assemble lines
+ * in our receive buffer. We can't use neither 'refclock_gtraw'
+ * not 'refclock_gtlin' here... We process chars until we reach
+ * an EoL (that is, line feed) but we truncate the message if it
+ * does not fit the buffer. GPSD might truncate messages, too,
+ * so dealing with truncated buffers is necessary anyway.
+ */
+ psrc = (const char*)rbufp->recv_buffer;
+ esrc = psrc + rbufp->recv_length;
+
+ pdst = up->buffer + up->buflen;
+ edst = pdst + sizeof(up->buffer) - 1; /* for trailing NUL */
+
+ while (psrc != esrc) {
+ ch = *psrc++;
+ if (ch == '\n') {
+ /* trim trailing whitespace & terminate buffer */
+ while (pdst != up->buffer && pdst[-1] <= ' ')
+ --pdst;
+ *pdst = '\0';
+ /* process data and reset buffer */
+ up->buflen = pdst - up->buffer;
+ gpsd_parse(peer, &rbufp->recv_time);
+ pdst = up->buffer;
+ } else if (pdst != edst) {
+ /* add next char, ignoring leading whitespace */
+ if (ch > ' ' || pdst != up->buffer)
+ *pdst++ = ch;
+ }
+ }
+ up->buflen = pdst - up->buffer;
+ up->tickover = TICKOVER_LOW;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+poll_primary(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ if (pp->coderecv != pp->codeproc) {
+ /* all is well */
+ pp->lastref = pp->lastrec;
+ refclock_report(peer, CEVNT_NOMINAL);
+ refclock_receive(peer);
+ } else {
+ /* Not working properly, admit to it. If we have no
+ * connection to GPSD, declare the clock as faulty. If
+ * there were bad replies, this is handled as the major
+ * cause, and everything else is just a timeout.
+ */
+ peer->precision = PRECISION;
+ if (-1 == pp->io.fd)
+ refclock_report(peer, CEVNT_FAULT);
+ else if (0 != up->tc_breply)
+ refclock_report(peer, CEVNT_BADREPLY);
+ else
+ refclock_report(peer, CEVNT_TIMEOUT);
+ }
+
+ if (pp->sloppyclockflag & CLK_FLAG4)
+ mprintf_clock_stats(
+ &peer->srcadr,"%u %u %u %u %u %u %u",
+ up->tc_recv,
+ up->tc_breply, up->tc_nosync,
+ up->tc_sti_recv, up->tc_sti_used,
+ up->tc_pps_recv, up->tc_pps_used);
+
+ /* clear tallies for next round */
+ up->tc_breply = 0;
+ up->tc_recv = 0;
+ up->tc_nosync = 0;
+ up->tc_sti_recv = 0;
+ up->tc_sti_used = 0;
+ up->tc_pps_recv = 0;
+ up->tc_pps_used = 0;
+}
+
+static void
+poll_secondary(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ if (pp->coderecv != pp->codeproc) {
+ /* all is well */
+ pp->lastref = pp->lastrec;
+ refclock_report(peer, CEVNT_NOMINAL);
+ refclock_receive(peer);
+ } else {
+ peer->precision = PPS_PRECISION;
+ peer->flags &= ~FLAG_PPS;
+ refclock_report(peer, CEVNT_TIMEOUT);
+ }
+}
+
+static void
+gpsd_poll(
+ int unit,
+ peerT * peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ ++pp->polls;
+ if (peer == up->pps_peer)
+ poll_secondary(peer, pp, up);
+ else
+ poll_primary(peer, pp, up);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_control(
+ int unit,
+ const struct refclockstat * in_st,
+ struct refclockstat * out_st,
+ peerT * peer )
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ if (peer == up->pps_peer) {
+ DTOLFP(pp->fudgetime1, &up->pps_fudge2);
+ if ( ! (pp->sloppyclockflag & CLK_FLAG1))
+ peer->flags &= ~FLAG_PPS;
+ } else {
+ /* save preprocessed fudge times */
+ DTOLFP(pp->fudgetime1, &up->pps_fudge);
+ DTOLFP(pp->fudgetime2, &up->sti_fudge);
+
+ if (MODE_OP_MODE(up->mode ^ peer->ttl)) {
+ leave_opmode(peer, up->mode);
+ up->mode = MODE_OP_MODE(peer->ttl);
+ enter_opmode(peer, up->mode);
+ }
+ }
+ }
+
+/* ------------------------------------------------------------------ */
+
+static void
+timer_primary(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ int rc;
+
+ /* This is used for timeout handling. Nothing that needs
+ * sub-second precison happens here, so receive/connect/retry
+ * timeouts are simply handled by a count down, and then we
+ * decide what to do by the socket values.
+ *
+ * Note that the timer stays at zero here, unless some of the
+ * functions set it to another value.
+ */
+ if (up->logthrottle)
+ --up->logthrottle;
+ if (up->tickover)
+ --up->tickover;
+ switch (up->tickover) {
+ case 4:
+ /* If we are connected to GPSD, try to get a live signal
+ * by querying the version. Otherwise just check the
+ * socket to become ready.
+ */
+ if (-1 != pp->io.fd) {
+ size_t rlen = strlen(s_req_version);
+ DPRINTF(2, ("%s: timer livecheck: '%s'\n",
+ up->logname, s_req_version));
+ log_data(peer, "send", s_req_version, rlen);
+ rc = write(pp->io.fd, s_req_version, rlen);
+ (void)rc;
+ } else if (-1 != up->fdt) {
+ gpsd_test_socket(peer);
+ }
+ break;
+
+ case 0:
+ if (-1 != pp->io.fd)
+ gpsd_stop_socket(peer);
+ else if (-1 != up->fdt)
+ gpsd_test_socket(peer);
+ else if (NULL != s_gpsd_addr)
+ gpsd_init_socket(peer);
+ break;
+
+ default:
+ if (-1 == pp->io.fd && -1 != up->fdt)
+ gpsd_test_socket(peer);
+ }
+}
+
+static void
+timer_secondary(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ /* Reduce the count by one. Flush sample buffer and clear PPS
+ * flag when this happens.
+ */
+ up->ppscount2 = max(0, (up->ppscount2 - 1));
+ if (0 == up->ppscount2) {
+ if (pp->coderecv != pp->codeproc) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ pp->coderecv = pp->codeproc;
+ }
+ peer->flags &= ~FLAG_PPS;
+ }
+}
+
+static void
+gpsd_timer(
+ int unit,
+ peerT * peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ if (peer == up->pps_peer)
+ timer_secondary(peer, pp, up);
+ else
+ timer_primary(peer, pp, up);
+}
+
+/* =====================================================================
+ * handle opmode switches
+ */
+
+static void
+enter_opmode(
+ peerT *peer,
+ int mode)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ DPRINTF(1, ("%s: enter operation mode %d\n",
+ up->logname, MODE_OP_MODE(mode)));
+
+ if (MODE_OP_MODE(mode) == MODE_OP_AUTO) {
+ up->fl_rawsti = 0;
+ up->ppscount = PPS_MAXCOUNT / 2;
+ }
+ up->fl_pps = 0;
+ up->fl_sti = 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+leave_opmode(
+ peerT *peer,
+ int mode)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ DPRINTF(1, ("%s: leaving operation mode %d\n",
+ up->logname, MODE_OP_MODE(mode)));
+
+ if (MODE_OP_MODE(mode) == MODE_OP_AUTO) {
+ up->fl_rawsti = 0;
+ up->ppscount = 0;
+ }
+ up->fl_pps = 0;
+ up->fl_sti = 0;
+}
+
+/* =====================================================================
+ * operation mode specific evaluation
+ */
+
+static void
+add_clock_sample(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ l_fp stamp,
+ l_fp recvt)
+{
+ pp->lastref = stamp;
+ if (pp->coderecv == pp->codeproc)
+ refclock_report(peer, CEVNT_NOMINAL);
+ refclock_process_offset(pp, stamp, recvt, 0.0);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+eval_strict(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ if (up->fl_sti && up->fl_pps) {
+ /* use TPV reference time + PPS receive time */
+ add_clock_sample(peer, pp, up->sti_stamp, up->pps_recvt);
+ peer->precision = up->pps_prec;
+ /* both packets consumed now... */
+ up->fl_pps = 0;
+ up->fl_sti = 0;
+ ++up->tc_sti_used;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+/* PPS processing for the secondary channel. GPSD provides us with full
+ * timing information, so there's no danger of PLL-locking to the wrong
+ * second. The belts and suspenders needed for the raw ATOM clock are
+ * unnecessary here.
+ */
+static void
+eval_pps_secondary(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ if (up->fl_pps2) {
+ /* feed data */
+ add_clock_sample(peer, pp, up->pps_stamp2, up->pps_recvt2);
+ peer->precision = up->pps_prec;
+ /* PPS peer flag logic */
+ up->ppscount2 = min(PPS2_MAXCOUNT, (up->ppscount2 + 2));
+ if ((PPS2_MAXCOUNT == up->ppscount2) &&
+ (pp->sloppyclockflag & CLK_FLAG1) )
+ peer->flags |= FLAG_PPS;
+ /* mark time stamp as burned... */
+ up->fl_pps2 = 0;
+ ++up->tc_pps_used;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+eval_serial(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ if (up->fl_sti) {
+ add_clock_sample(peer, pp, up->sti_stamp, up->sti_recvt);
+ peer->precision = up->sti_prec;
+ /* mark time stamp as burned... */
+ up->fl_sti = 0;
+ ++up->tc_sti_used;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+static void
+eval_auto(
+ peerT * const peer ,
+ clockprocT * const pp ,
+ gpsd_unitT * const up )
+{
+ /* If there's no TPV available, stop working here... */
+ if (!up->fl_sti)
+ return;
+
+ /* check how to handle STI+PPS: Can PPS be used to augment STI
+ * (or vice versae), do we drop the sample because there is a
+ * temporary missing PPS signal, or do we feed on STI time
+ * stamps alone?
+ *
+ * Do a counter/threshold dance to decide how to proceed.
+ */
+ if (up->fl_pps) {
+ up->ppscount = min(PPS_MAXCOUNT,
+ (up->ppscount + PPS_INCCOUNT));
+ if ((PPS_MAXCOUNT == up->ppscount) && up->fl_rawsti) {
+ up->fl_rawsti = 0;
+ msyslog(LOG_INFO,
+ "%s: expect valid PPS from now",
+ up->logname);
+ }
+ } else {
+ up->ppscount = max(0, (up->ppscount - PPS_DECCOUNT));
+ if ((0 == up->ppscount) && !up->fl_rawsti) {
+ up->fl_rawsti = -1;
+ msyslog(LOG_WARNING,
+ "%s: use TPV alone from now",
+ up->logname);
+ }
+ }
+
+ /* now eventually feed the sample */
+ if (up->fl_rawsti)
+ eval_serial(peer, pp, up);
+ else
+ eval_strict(peer, pp, up);
+}
+
+/* =====================================================================
+ * JSON parsing stuff
+ */
+
+/* ------------------------------------------------------------------ */
+/* Parse a decimal integer with a possible sign. Works like 'strtoll()'
+ * or 'strtol()', but with a fixed base of 10 and without eating away
+ * leading whitespace. For the error codes, the handling of the end
+ * pointer and the return values see 'strtol()'.
+ */
+static json_int
+strtojint(
+ const char *cp, char **ep)
+{
+ json_uint accu, limit_lo, limit_hi;
+ int flags; /* bit 0: overflow; bit 1: sign */
+ const char * hold;
+
+ /* pointer union to circumvent a tricky/sticky const issue */
+ union { const char * c; char * v; } vep;
+
+ /* store initial value of 'cp' -- see 'strtol()' */
+ vep.c = cp;
+
+ /* Eat away an optional sign and set the limits accordingly: The
+ * high limit is the maximum absolute value that can be returned,
+ * and the low limit is the biggest value that does not cause an
+ * overflow when multiplied with 10. Avoid negation overflows.
+ */
+ if (*cp == '-') {
+ cp += 1;
+ flags = 2;
+ limit_hi = (json_uint)-(JSON_INT_MIN + 1) + 1;
+ } else {
+ cp += (*cp == '+');
+ flags = 0;
+ limit_hi = (json_uint)JSON_INT_MAX;
+ }
+ limit_lo = limit_hi / 10;
+
+ /* Now try to convert a sequence of digits. */
+ hold = cp;
+ accu = 0;
+ while (isdigit(*(const unsigned char*)cp)) {
+ flags |= (accu > limit_lo);
+ accu = accu * 10 + (*(const unsigned char*)cp++ - '0');
+ flags |= (accu > limit_hi);
+ }
+ /* Check for empty conversion (no digits seen). */
+ if (hold != cp)
+ vep.c = cp;
+ else
+ errno = EINVAL; /* accu is still zero */
+ /* Check for range overflow */
+ if (flags & 1) {
+ errno = ERANGE;
+ accu = limit_hi;
+ }
+ /* If possible, store back the end-of-conversion pointer */
+ if (ep)
+ *ep = vep.v;
+ /* If negative, return the negated result if the accu is not
+ * zero. Avoid negation overflows.
+ */
+ if ((flags & 2) && accu)
+ return -(json_int)(accu - 1) - 1;
+ else
+ return (json_int)accu;
+}
+
+/* ------------------------------------------------------------------ */
+
+static tok_ref
+json_token_skip(
+ const json_ctx * ctx,
+ tok_ref tid)
+{
+ if (tid >= 0 && tid < ctx->ntok) {
+ int len = ctx->tok[tid].size;
+ /* For arrays and objects, the size is the number of
+ * ITEMS in the compound. Thats the number of objects in
+ * the array, and the number of key/value pairs for
+ * objects. In theory, the key must be a string, and we
+ * could simply skip one token before skipping the
+ * value, which can be anything. We're a bit paranoid
+ * and lazy at the same time: We simply double the
+ * number of tokens to skip and fall through into the
+ * array processing when encountering an object.
+ */
+ switch (ctx->tok[tid].type) {
+ case JSMN_OBJECT:
+ len *= 2;
+ /* FALLTHROUGH */
+ case JSMN_ARRAY:
+ for (++tid; len; --len)
+ tid = json_token_skip(ctx, tid);
+ break;
+
+ default:
+ ++tid;
+ break;
+ }
+ if (tid > ctx->ntok) /* Impossible? Paranoia rulez. */
+ tid = ctx->ntok;
+ }
+ return tid;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int
+json_object_lookup(
+ const json_ctx * ctx ,
+ tok_ref tid ,
+ const char * key ,
+ int what)
+{
+ int len;
+
+ if (tid < 0 || tid >= ctx->ntok ||
+ ctx->tok[tid].type != JSMN_OBJECT)
+ return INVALID_TOKEN;
+
+ len = ctx->tok[tid].size;
+ for (++tid; len && tid+1 < ctx->ntok; --len) {
+ if (ctx->tok[tid].type != JSMN_STRING) { /* Blooper! */
+ tid = json_token_skip(ctx, tid); /* skip key */
+ tid = json_token_skip(ctx, tid); /* skip val */
+ } else if (strcmp(key, ctx->buf + ctx->tok[tid].start)) {
+ tid = json_token_skip(ctx, tid+1); /* skip key+val */
+ } else if (what < 0 || what == ctx->tok[tid+1].type) {
+ return tid + 1;
+ } else {
+ break;
+ }
+ /* if skipping ahead returned an error, bail out here. */
+ if (tid < 0)
+ break;
+ }
+ return INVALID_TOKEN;
+}
+
+/* ------------------------------------------------------------------ */
+
+static const char*
+json_object_lookup_primitive(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key)
+{
+ tid = json_object_lookup(ctx, tid, key, JSMN_PRIMITIVE);
+ if (INVALID_TOKEN != tid)
+ return ctx->buf + ctx->tok[tid].start;
+ else
+ return NULL;
+}
+/* ------------------------------------------------------------------ */
+/* look up a boolean value. This essentially returns a tribool:
+ * 0->false, 1->true, (-1)->error/undefined
+ */
+static int
+json_object_lookup_bool(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key)
+{
+ const char *cp;
+ cp = json_object_lookup_primitive(ctx, tid, key);
+ switch ( cp ? *cp : '\0') {
+ case 't': return 1;
+ case 'f': return 0;
+ default : return -1;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+
+static const char*
+json_object_lookup_string(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key)
+{
+ tid = json_object_lookup(ctx, tid, key, JSMN_STRING);
+ if (INVALID_TOKEN != tid)
+ return ctx->buf + ctx->tok[tid].start;
+ return NULL;
+}
+
+static const char*
+json_object_lookup_string_default(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key,
+ const char * def)
+{
+ tid = json_object_lookup(ctx, tid, key, JSMN_STRING);
+ if (INVALID_TOKEN != tid)
+ return ctx->buf + ctx->tok[tid].start;
+ return def;
+}
+
+/* ------------------------------------------------------------------ */
+
+static json_int
+json_object_lookup_int(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key)
+{
+ json_int ret;
+ const char * cp;
+ char * ep;
+
+ cp = json_object_lookup_primitive(ctx, tid, key);
+ if (NULL != cp) {
+ ret = strtojint(cp, &ep);
+ if (cp != ep && '\0' == *ep)
+ return ret;
+ } else {
+ errno = EINVAL;
+ }
+ return 0;
+}
+
+static json_int
+json_object_lookup_int_default(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key,
+ json_int def)
+{
+ json_int ret;
+ const char * cp;
+ char * ep;
+
+ cp = json_object_lookup_primitive(ctx, tid, key);
+ if (NULL != cp) {
+ ret = strtojint(cp, &ep);
+ if (cp != ep && '\0' == *ep)
+ return ret;
+ }
+ return def;
+}
+
+/* ------------------------------------------------------------------ */
+#if 0 /* currently unused */
+static double
+json_object_lookup_float(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key)
+{
+ double ret;
+ const char * cp;
+ char * ep;
+
+ cp = json_object_lookup_primitive(ctx, tid, key);
+ if (NULL != cp) {
+ ret = strtod(cp, &ep);
+ if (cp != ep && '\0' == *ep)
+ return ret;
+ } else {
+ errno = EINVAL;
+ }
+ return 0.0;
+}
+#endif
+
+static double
+json_object_lookup_float_default(
+ const json_ctx * ctx,
+ tok_ref tid,
+ const char * key,
+ double def)
+{
+ double ret;
+ const char * cp;
+ char * ep;
+
+ cp = json_object_lookup_primitive(ctx, tid, key);
+ if (NULL != cp) {
+ ret = strtod(cp, &ep);
+ if (cp != ep && '\0' == *ep)
+ return ret;
+ }
+ return def;
+}
+
+/* ------------------------------------------------------------------ */
+
+static BOOL
+json_parse_record(
+ json_ctx * ctx,
+ char * buf,
+ size_t len)
+{
+ jsmn_parser jsm;
+ int idx, rc;
+
+ jsmn_init(&jsm);
+ rc = jsmn_parse(&jsm, buf, len, ctx->tok, JSMN_MAXTOK);
+ if (rc <= 0)
+ return FALSE;
+ ctx->buf = buf;
+ ctx->ntok = rc;
+
+ if (JSMN_OBJECT != ctx->tok[0].type)
+ return FALSE; /* not object!?! */
+
+ /* Make all tokens NUL terminated by overwriting the
+ * terminator symbol. Makes string compares and number parsing a
+ * lot easier!
+ */
+ for (idx = 0; idx < ctx->ntok; ++idx)
+ if (ctx->tok[idx].end > ctx->tok[idx].start)
+ ctx->buf[ctx->tok[idx].end] = '\0';
+ return TRUE;
+}
+
+
+/* =====================================================================
+ * static local helpers
+ */
+static BOOL
+get_binary_time(
+ l_fp * const dest ,
+ json_ctx * const jctx ,
+ const char * const time_name,
+ const char * const frac_name,
+ long fscale )
+{
+ BOOL retv = FALSE;
+ struct timespec ts;
+
+ errno = 0;
+ ts.tv_sec = (time_t)json_object_lookup_int(jctx, 0, time_name);
+ ts.tv_nsec = (long )json_object_lookup_int(jctx, 0, frac_name);
+ if (0 == errno) {
+ ts.tv_nsec *= fscale;
+ *dest = tspec_stamp_to_lfp(ts);
+ retv = TRUE;
+ }
+ return retv;
+}
+
+/* ------------------------------------------------------------------ */
+/* Process a WATCH record
+ *
+ * Currently this is only used to recognise that the device is present
+ * and that we're listed subscribers.
+ */
+static void
+process_watch(
+ peerT * const peer ,
+ json_ctx * const jctx ,
+ const l_fp * const rtime)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ const char * path;
+
+ path = json_object_lookup_string(jctx, 0, "device");
+ if (NULL == path || strcmp(path, up->device))
+ return;
+
+ if (json_object_lookup_bool(jctx, 0, "enable") > 0 &&
+ json_object_lookup_bool(jctx, 0, "json" ) > 0 )
+ up->fl_watch = -1;
+ else
+ up->fl_watch = 0;
+ DPRINTF(2, ("%s: process_watch, enabled=%d\n",
+ up->logname, (up->fl_watch & 1)));
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+process_version(
+ peerT * const peer ,
+ json_ctx * const jctx ,
+ const l_fp * const rtime)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ int len;
+ char * buf;
+ const char *revision;
+ const char *release;
+ uint16_t pvhi, pvlo;
+
+ /* get protocol version number */
+ revision = json_object_lookup_string_default(
+ jctx, 0, "rev", "(unknown)");
+ release = json_object_lookup_string_default(
+ jctx, 0, "release", "(unknown)");
+ errno = 0;
+ pvhi = (uint16_t)json_object_lookup_int(jctx, 0, "proto_major");
+ pvlo = (uint16_t)json_object_lookup_int(jctx, 0, "proto_minor");
+
+ if (0 == errno) {
+ if ( ! up->fl_vers)
+ msyslog(LOG_INFO,
+ "%s: GPSD revision=%s release=%s protocol=%u.%u",
+ up->logname, revision, release,
+ pvhi, pvlo);
+ up->proto_version = PROTO_VERSION(pvhi, pvlo);
+ up->fl_vers = -1;
+ } else {
+ if (syslogok(pp, up))
+ msyslog(LOG_INFO,
+ "%s: could not evaluate version data",
+ up->logname);
+ return;
+ }
+ /* With the 3.9 GPSD protocol, '*_musec' vanished from the PPS
+ * record and was replace by '*_nsec'.
+ */
+ up->pf_nsec = -(up->proto_version >= PROTO_VERSION(3,9));
+
+ /* With the 3.10 protocol we can get TOFF records for better
+ * timing information.
+ */
+ up->pf_toff = -(up->proto_version >= PROTO_VERSION(3,10));
+
+ /* request watch for our GPS device if not yet watched.
+ *
+ * The version string is also sent as a life signal, if we have
+ * seen useable data. So if we're already watching the device,
+ * skip the request.
+ *
+ * Reuse the input buffer, which is no longer needed in the
+ * current cycle. Also assume that we can write the watch
+ * request in one sweep into the socket; since we do not do
+ * output otherwise, this should always work. (Unless the
+ * TCP/IP window size gets lower than the length of the
+ * request. We handle that when it happens.)
+ */
+ if (up->fl_watch)
+ return;
+
+ snprintf(up->buffer, sizeof(up->buffer),
+ s_req_watch[up->pf_toff != 0], up->device);
+ buf = up->buffer;
+ len = strlen(buf);
+ log_data(peer, "send", buf, len);
+ if (len != write(pp->io.fd, buf, len) && (syslogok(pp, up))) {
+ /* Note: if the server fails to read our request, the
+ * resulting data timeout will take care of the
+ * connection!
+ */
+ msyslog(LOG_ERR, "%s: failed to write watch request (%m)",
+ up->logname);
+ }
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+process_tpv(
+ peerT * const peer ,
+ json_ctx * const jctx ,
+ const l_fp * const rtime)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ const char * gps_time;
+ int gps_mode;
+ double ept;
+ int xlog2;
+
+ gps_mode = (int)json_object_lookup_int_default(
+ jctx, 0, "mode", 0);
+
+ gps_time = json_object_lookup_string(
+ jctx, 0, "time");
+
+ /* accept time stamps only in 2d or 3d fix */
+ if (gps_mode < 2 || NULL == gps_time) {
+ /* receiver has no fix; tell about and avoid stale data */
+ if ( ! up->pf_toff)
+ ++up->tc_sti_recv;
+ ++up->tc_nosync;
+ up->fl_sti = 0;
+ up->fl_pps = 0;
+ up->fl_nosync = -1;
+ return;
+ }
+ up->fl_nosync = 0;
+
+ /* convert clock and set resulting ref time, but only if the
+ * TOFF sentence is *not* available
+ */
+ if ( ! up->pf_toff) {
+ ++up->tc_sti_recv;
+ /* save last time code to clock data */
+ save_ltc(pp, gps_time);
+ /* now parse the time string */
+ if (convert_ascii_time(&up->sti_stamp, gps_time)) {
+ DPRINTF(2, ("%s: process_tpv, stamp='%s',"
+ " recvt='%s' mode=%u\n",
+ up->logname,
+ gmprettydate(&up->sti_stamp),
+ gmprettydate(&up->sti_recvt),
+ gps_mode));
+
+ /* have to use local receive time as substitute
+ * for the real receive time: TPV does not tell
+ * us.
+ */
+ up->sti_local = *rtime;
+ up->sti_recvt = *rtime;
+ L_SUB(&up->sti_recvt, &up->sti_fudge);
+ up->fl_sti = -1;
+ } else {
+ ++up->tc_breply;
+ up->fl_sti = 0;
+ }
+ }
+
+ /* Set the precision from the GPSD data
+ * Use the ETP field for an estimation of the precision of the
+ * serial data. If ETP is not available, use the default serial
+ * data presion instead. (Note: The PPS branch has a different
+ * precision estimation, since it gets the proper value directly
+ * from GPSD!)
+ */
+ ept = json_object_lookup_float_default(jctx, 0, "ept", 2.0e-3);
+ ept = frexp(fabs(ept)*0.70710678, &xlog2); /* ~ sqrt(0.5) */
+ if (ept < 0.25)
+ xlog2 = INT_MIN;
+ if (ept > 2.0)
+ xlog2 = INT_MAX;
+ up->sti_prec = clamped_precision(xlog2);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+process_pps(
+ peerT * const peer ,
+ json_ctx * const jctx ,
+ const l_fp * const rtime)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ int xlog2;
+
+ ++up->tc_pps_recv;
+
+ /* Bail out if there's indication that time sync is bad or
+ * if we're explicitely requested to ignore PPS data.
+ */
+ if (up->fl_nosync)
+ return;
+
+ up->pps_local = *rtime;
+ /* Now grab the time values. 'clock_*' is the event time of the
+ * pulse measured on the local system clock; 'real_*' is the GPS
+ * reference time GPSD associated with the pulse.
+ */
+ if (up->pf_nsec) {
+ if ( ! get_binary_time(&up->pps_recvt2, jctx,
+ "clock_sec", "clock_nsec", 1))
+ goto fail;
+ if ( ! get_binary_time(&up->pps_stamp2, jctx,
+ "real_sec", "real_nsec", 1))
+ goto fail;
+ } else {
+ if ( ! get_binary_time(&up->pps_recvt2, jctx,
+ "clock_sec", "clock_musec", 1000))
+ goto fail;
+ if ( ! get_binary_time(&up->pps_stamp2, jctx,
+ "real_sec", "real_musec", 1000))
+ goto fail;
+ }
+
+ /* Try to read the precision field from the PPS record. If it's
+ * not there, take the precision from the serial data.
+ */
+ xlog2 = json_object_lookup_int_default(
+ jctx, 0, "precision", up->sti_prec);
+ up->pps_prec = clamped_precision(xlog2);
+
+ /* Get fudged receive times for primary & secondary unit */
+ up->pps_recvt = up->pps_recvt2;
+ L_SUB(&up->pps_recvt , &up->pps_fudge );
+ L_SUB(&up->pps_recvt2, &up->pps_fudge2);
+ pp->lastrec = up->pps_recvt;
+
+ /* Map to nearest full second as reference time stamp for the
+ * primary channel. Sanity checks are done in evaluation step.
+ */
+ up->pps_stamp = up->pps_recvt;
+ L_ADDUF(&up->pps_stamp, 0x80000000u);
+ up->pps_stamp.l_uf = 0;
+
+ if (NULL != up->pps_peer)
+ save_ltc(up->pps_peer->procptr,
+ gmprettydate(&up->pps_stamp2));
+ DPRINTF(2, ("%s: PPS record processed,"
+ " stamp='%s', recvt='%s'\n",
+ up->logname,
+ gmprettydate(&up->pps_stamp2),
+ gmprettydate(&up->pps_recvt2)));
+
+ up->fl_pps = (0 != (pp->sloppyclockflag & CLK_FLAG2)) - 1;
+ up->fl_pps2 = -1;
+ return;
+
+ fail:
+ DPRINTF(1, ("%s: PPS record processing FAILED\n",
+ up->logname));
+ ++up->tc_breply;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+process_toff(
+ peerT * const peer ,
+ json_ctx * const jctx ,
+ const l_fp * const rtime)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ ++up->tc_sti_recv;
+
+ /* remember this! */
+ up->pf_toff = -1;
+
+ /* bail out if there's indication that time sync is bad */
+ if (up->fl_nosync)
+ return;
+
+ if ( ! get_binary_time(&up->sti_recvt, jctx,
+ "clock_sec", "clock_nsec", 1))
+ goto fail;
+ if ( ! get_binary_time(&up->sti_stamp, jctx,
+ "real_sec", "real_nsec", 1))
+ goto fail;
+ L_SUB(&up->sti_recvt, &up->sti_fudge);
+ up->sti_local = *rtime;
+ up->fl_sti = -1;
+
+ save_ltc(pp, gmprettydate(&up->sti_stamp));
+ DPRINTF(2, ("%s: TOFF record processed,"
+ " stamp='%s', recvt='%s'\n",
+ up->logname,
+ gmprettydate(&up->sti_stamp),
+ gmprettydate(&up->sti_recvt)));
+ return;
+
+ fail:
+ DPRINTF(1, ("%s: TOFF record processing FAILED\n",
+ up->logname));
+ ++up->tc_breply;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_parse(
+ peerT * const peer ,
+ const l_fp * const rtime)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ const char * clsid;
+
+ DPRINTF(2, ("%s: gpsd_parse: time %s '%.*s'\n",
+ up->logname, ulfptoa(rtime, 6),
+ up->buflen, up->buffer));
+
+ /* See if we can grab anything potentially useful. JSMN does not
+ * need a trailing NUL, but it needs the number of bytes to
+ * process. */
+ if (!json_parse_record(&up->json_parse, up->buffer, up->buflen)) {
+ ++up->tc_breply;
+ return;
+ }
+
+ /* Now dispatch over the objects we know */
+ clsid = json_object_lookup_string(&up->json_parse, 0, "class");
+ if (NULL == clsid) {
+ ++up->tc_breply;
+ return;
+ }
+
+ if (!strcmp("TPV", clsid))
+ process_tpv(peer, &up->json_parse, rtime);
+ else if (!strcmp("PPS", clsid))
+ process_pps(peer, &up->json_parse, rtime);
+ else if (!strcmp("TOFF", clsid))
+ process_toff(peer, &up->json_parse, rtime);
+ else if (!strcmp("VERSION", clsid))
+ process_version(peer, &up->json_parse, rtime);
+ else if (!strcmp("WATCH", clsid))
+ process_watch(peer, &up->json_parse, rtime);
+ else
+ return; /* nothing we know about... */
+ ++up->tc_recv;
+
+ /* if possible, feed the PPS side channel */
+ if (up->pps_peer)
+ eval_pps_secondary(
+ up->pps_peer, up->pps_peer->procptr, up);
+
+ /* check PPS vs. STI receive times:
+ * If STI is before PPS, then clearly the STI is too old. If PPS
+ * is before STI by more than one second, then PPS is too old.
+ * Weed out stale time stamps & flags.
+ */
+ if (up->fl_pps && up->fl_sti) {
+ l_fp diff;
+ diff = up->sti_local;
+ L_SUB(&diff, &up->pps_local);
+ if (diff.l_i > 0)
+ up->fl_pps = 0; /* pps too old */
+ else if (diff.l_i < 0)
+ up->fl_sti = 0; /* serial data too old */
+ }
+
+ /* dispatch to the mode-dependent processing functions */
+ switch (up->mode) {
+ default:
+ case MODE_OP_STI:
+ eval_serial(peer, pp, up);
+ break;
+
+ case MODE_OP_STRICT:
+ eval_strict(peer, pp, up);
+ break;
+
+ case MODE_OP_AUTO:
+ eval_auto(peer, pp, up);
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_stop_socket(
+ peerT * const peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ if (-1 != pp->io.fd) {
+ if (syslogok(pp, up))
+ msyslog(LOG_INFO,
+ "%s: closing socket to GPSD, fd=%d",
+ up->logname, pp->io.fd);
+ else
+ DPRINTF(1, ("%s: closing socket to GPSD, fd=%d\n",
+ up->logname, pp->io.fd));
+ io_closeclock(&pp->io);
+ pp->io.fd = -1;
+ }
+ up->tickover = up->tickpres;
+ up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
+ up->fl_vers = 0;
+ up->fl_sti = 0;
+ up->fl_pps = 0;
+ up->fl_watch = 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_init_socket(
+ peerT * const peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+ addrinfoT * ai;
+ int rc;
+ int ov;
+
+ /* draw next address to try */
+ if (NULL == up->addr)
+ up->addr = s_gpsd_addr;
+ ai = up->addr;
+ up->addr = ai->ai_next;
+
+ /* try to create a matching socket */
+ up->fdt = socket(
+ ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (-1 == up->fdt) {
+ if (syslogok(pp, up))
+ msyslog(LOG_ERR,
+ "%s: cannot create GPSD socket: %m",
+ up->logname);
+ goto no_socket;
+ }
+
+ /* Make sure the socket is non-blocking. Connect/reconnect and
+ * IO happen in an event-driven environment, and synchronous
+ * operations wreak havoc on that.
+ */
+ rc = fcntl(up->fdt, F_SETFL, O_NONBLOCK, 1);
+ if (-1 == rc) {
+ if (syslogok(pp, up))
+ msyslog(LOG_ERR,
+ "%s: cannot set GPSD socket to non-blocking: %m",
+ up->logname);
+ goto no_socket;
+ }
+ /* Disable nagling. The way both GPSD and NTPD handle the
+ * protocol makes it record-oriented, and in most cases
+ * complete records (JSON serialised objects) will be sent in
+ * one sweep. Nagling gives not much advantage but adds another
+ * delay, which can worsen the situation for some packets.
+ */
+ ov = 1;
+ rc = setsockopt(up->fdt, IPPROTO_TCP, TCP_NODELAY,
+ (char*)&ov, sizeof(ov));
+ if (-1 == rc) {
+ if (syslogok(pp, up))
+ msyslog(LOG_INFO,
+ "%s: cannot disable TCP nagle: %m",
+ up->logname);
+ }
+
+ /* Start a non-blocking connect. There might be a synchronous
+ * connection result we have to handle.
+ */
+ rc = connect(up->fdt, ai->ai_addr, ai->ai_addrlen);
+ if (-1 == rc) {
+ if (errno == EINPROGRESS) {
+ DPRINTF(1, ("%s: async connect pending, fd=%d\n",
+ up->logname, up->fdt));
+ return;
+ }
+
+ if (syslogok(pp, up))
+ msyslog(LOG_ERR,
+ "%s: cannot connect GPSD socket: %m",
+ up->logname);
+ goto no_socket;
+ }
+
+ /* We had a successful synchronous connect, so we add the
+ * refclock processing ASAP. We still have to wait for the
+ * version string and apply the watch command later on, but we
+ * might as well get the show on the road now.
+ */
+ DPRINTF(1, ("%s: new socket connection, fd=%d\n",
+ up->logname, up->fdt));
+
+ pp->io.fd = up->fdt;
+ up->fdt = -1;
+ if (0 == io_addclock(&pp->io)) {
+ if (syslogok(pp, up))
+ msyslog(LOG_ERR,
+ "%s: failed to register with I/O engine",
+ up->logname);
+ goto no_socket;
+ }
+
+ return;
+
+ no_socket:
+ if (-1 != pp->io.fd)
+ close(pp->io.fd);
+ if (-1 != up->fdt)
+ close(up->fdt);
+ pp->io.fd = -1;
+ up->fdt = -1;
+ up->tickover = up->tickpres;
+ up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void
+gpsd_test_socket(
+ peerT * const peer)
+{
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ int ec, rc;
+ socklen_t lc;
+
+ /* Check if the non-blocking connect was finished by testing the
+ * socket for writeability. Use the 'poll()' API if available
+ * and 'select()' otherwise.
+ */
+ DPRINTF(2, ("%s: check connect, fd=%d\n",
+ up->logname, up->fdt));
+
+#if defined(HAVE_SYS_POLL_H)
+ {
+ struct pollfd pfd;
+
+ pfd.events = POLLOUT;
+ pfd.fd = up->fdt;
+ rc = poll(&pfd, 1, 0);
+ if (1 != rc || !(pfd.revents & POLLOUT))
+ return;
+ }
+#elif defined(HAVE_SYS_SELECT_H)
+ {
+ struct timeval tout;
+ fd_set wset;
+
+ memset(&tout, 0, sizeof(tout));
+ FD_ZERO(&wset);
+ FD_SET(up->fdt, &wset);
+ rc = select(up->fdt+1, NULL, &wset, NULL, &tout);
+ if (0 == rc || !(FD_ISSET(up->fdt, &wset)))
+ return;
+ }
+#else
+# error Blooper! That should have been found earlier!
+#endif
+
+ /* next timeout is a full one... */
+ up->tickover = TICKOVER_LOW;
+
+ /* check for socket error */
+ ec = 0;
+ lc = sizeof(ec);
+ rc = getsockopt(up->fdt, SOL_SOCKET, SO_ERROR, &ec, &lc);
+ if (-1 == rc || 0 != ec) {
+ const char *errtxt;
+ if (0 == ec)
+ ec = errno;
+ errtxt = strerror(ec);
+ if (syslogok(pp, up))
+ msyslog(LOG_ERR,
+ "%s: async connect to GPSD failed,"
+ " fd=%d, ec=%d(%s)",
+ up->logname, up->fdt, ec, errtxt);
+ else
+ DPRINTF(1, ("%s: async connect to GPSD failed,"
+ " fd=%d, ec=%d(%s)\n",
+ up->logname, up->fdt, ec, errtxt));
+ goto no_socket;
+ } else {
+ DPRINTF(1, ("%s: async connect to GPSD succeeded, fd=%d\n",
+ up->logname, up->fdt));
+ }
+
+ /* swap socket FDs, and make sure the clock was added */
+ pp->io.fd = up->fdt;
+ up->fdt = -1;
+ if (0 == io_addclock(&pp->io)) {
+ if (syslogok(pp, up))
+ msyslog(LOG_ERR,
+ "%s: failed to register with I/O engine",
+ up->logname);
+ goto no_socket;
+ }
+ return;
+
+ no_socket:
+ if (-1 != up->fdt) {
+ DPRINTF(1, ("%s: closing socket, fd=%d\n",
+ up->logname, up->fdt));
+ close(up->fdt);
+ }
+ up->fdt = -1;
+ up->tickover = up->tickpres;
+ up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
+}
+
+/* =====================================================================
+ * helper stuff
+ */
+
+/* -------------------------------------------------------------------
+ * store a properly clamped precision value
+ */
+static int16_t
+clamped_precision(
+ int rawprec)
+{
+ if (rawprec > 0)
+ rawprec = 0;
+ if (rawprec < -32)
+ rawprec = -32;
+ return (int16_t)rawprec;
+}
+
+/* -------------------------------------------------------------------
+ * Convert a GPSD timestamp (ISO8601 Format) to an l_fp
+ */
+static BOOL
+convert_ascii_time(
+ l_fp * fp ,
+ const char * gps_time)
+{
+ char *ep;
+ struct tm gd;
+ struct timespec ts;
+ uint32_t dw;
+
+ /* Use 'strptime' to take the brunt of the work, then parse
+ * the fractional part manually, starting with a digit weight of
+ * 10^8 nanoseconds.
+ */
+ ts.tv_nsec = 0;
+ ep = strptime(gps_time, "%Y-%m-%dT%H:%M:%S", &gd);
+ if (NULL == ep)
+ return FALSE; /* could not parse the mandatory stuff! */
+ if (*ep == '.') {
+ dw = 100000000u;
+ while (isdigit(*(unsigned char*)++ep)) {
+ ts.tv_nsec += (*(unsigned char*)ep - '0') * dw;
+ dw /= 10u;
+ }
+ }
+ if (ep[0] != 'Z' || ep[1] != '\0')
+ return FALSE; /* trailing garbage */
+
+ /* Now convert the whole thing into a 'l_fp'. We do not use
+ * 'mkgmtime()' since its not standard and going through the
+ * calendar routines is not much effort, either.
+ */
+ ts.tv_sec = (ntpcal_tm_to_rd(&gd) - DAY_NTP_STARTS) * SECSPERDAY
+ + ntpcal_tm_to_daysec(&gd);
+ *fp = tspec_intv_to_lfp(ts);
+
+ return TRUE;
+}
+
+/* -------------------------------------------------------------------
+ * Save the last timecode string, making sure it's properly truncated
+ * if necessary and NUL terminated in any case.
+ */
+static void
+save_ltc(
+ clockprocT * const pp,
+ const char * const tc)
+{
+ size_t len;
+
+ len = (tc) ? strlen(tc) : 0;
+ if (len >= sizeof(pp->a_lastcode))
+ len = sizeof(pp->a_lastcode) - 1;
+ pp->lencode = (u_short)len;
+ memcpy(pp->a_lastcode, tc, len);
+ pp->a_lastcode[len] = '\0';
+}
+
+/* -------------------------------------------------------------------
+ * asprintf replacement... it's not available everywhere...
+ */
+static int
+myasprintf(
+ char ** spp,
+ char const * fmt,
+ ... )
+{
+ size_t alen, plen;
+
+ alen = 32;
+ *spp = NULL;
+ do {
+ va_list va;
+
+ alen += alen;
+ free(*spp);
+ *spp = (char*)malloc(alen);
+ if (NULL == *spp)
+ return -1;
+
+ va_start(va, fmt);
+ plen = (size_t)vsnprintf(*spp, alen, fmt, va);
+ va_end(va);
+ } while (plen >= alen);
+
+ return (int)plen;
+}
+
+/* -------------------------------------------------------------------
+ * dump a raw data buffer
+ */
+
+static char *
+add_string(
+ char *dp,
+ char *ep,
+ const char *sp)
+{
+ while (dp != ep && *sp)
+ *dp++ = *sp++;
+ return dp;
+}
+
+static void
+log_data(
+ peerT *peer,
+ const char *what,
+ const char *buf ,
+ size_t len )
+{
+ /* we're running single threaded with regards to the clocks. */
+ static char s_lbuf[2048];
+
+ clockprocT * const pp = peer->procptr;
+ gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
+
+ if (debug > 1) {
+ const char *sptr = buf;
+ const char *stop = buf + len;
+ char *dptr = s_lbuf;
+ char *dtop = s_lbuf + sizeof(s_lbuf) - 1; /* for NUL */
+
+ while (sptr != stop && dptr != dtop) {
+ if (*sptr == '\\') {
+ dptr = add_string(dptr, dtop, "\\\\");
+ } else if (isprint(*sptr)) {
+ *dptr++ = *sptr;
+ } else {
+ char fbuf[6];
+ snprintf(fbuf, sizeof(fbuf), "\\%03o", *(const u_char*)sptr);
+ dptr = add_string(dptr, dtop, fbuf);
+ }
+ sptr++;
+ }
+ *dptr = '\0';
+ mprintf("%s[%s]: '%s'\n", up->logname, what, s_lbuf);
+ }
+}
+
+#else
+NONEMPTY_TRANSLATION_UNIT
+#endif /* REFCLOCK && CLOCK_GPSDJSON */
diff --git a/contrib/ntp/ntpd/refclock_gpsvme.c b/contrib/ntp/ntpd/refclock_gpsvme.c
index 9f9e85c..66ccc9a 100644
--- a/contrib/ntp/ntpd/refclock_gpsvme.c
+++ b/contrib/ntp/ntpd/refclock_gpsvme.c
@@ -104,13 +104,9 @@ psc_start(
return 0;
}
- if (!up) {
- msyslog(LOG_ERR, "psc_start: unit: %d, emalloc: %m", unit);
- return 0;
- }
memset(up, '\0', sizeof *up);
- sprintf(buf, DEVICE, unit); /* dev file name */
+ snprintf(buf, sizeof(buf), DEVICE, unit); /* dev file name */
fd[unit] = open(buf, O_RDONLY); /* open device file */
if (fd[unit] < 0) {
msyslog(LOG_ERR, "psc_start: unit: %d, open failed. %m", unit);
@@ -126,12 +122,12 @@ psc_start(
/* initialize peer variables */
pp = peer->procptr;
pp->io.clock_recv = noentry;
- pp->io.srcclock = (caddr_t) peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = -1;
- pp->unitptr = (caddr_t) up;
+ pp->unitptr = up;
get_systime(&pp->lastrec);
- memcpy((char *)&pp->refid, REFID, 4);
+ memcpy(&pp->refid, REFID, 4);
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
up->unit = unit;
@@ -149,8 +145,10 @@ psc_shutdown(
struct peer *peer
)
{
- free(peer->procptr->unitptr);
- close(fd[unit]);
+ if (NULL != peer->procptr->unitptr)
+ free(peer->procptr->unitptr);
+ if (fd[unit] > 0)
+ close(fd[unit]);
}
/* psc_poll: read, decode, and record device time */
@@ -175,7 +173,7 @@ psc_poll(
if (!up->msg_flag[unit]) { /* write once to system log */
msyslog(LOG_WARNING,
"SYNCHRONIZATION LOST on unit %1d, status %02x\n",
- status, unit);
+ unit, status);
up->msg_flag[unit] = 1;
}
return;
@@ -196,9 +194,10 @@ psc_poll(
pp->nsec = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
BCD2INT3(tlo & 0x00000FFF);
- sprintf(pp->a_lastcode, "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x",
- pp->day, pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
- tlo);
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day,
+ pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
+ tlo);
pp->lencode = strlen(pp->a_lastcode);
/* compute the timecode timestamp */
diff --git a/contrib/ntp/ntpd/refclock_heath.c b/contrib/ntp/ntpd/refclock_heath.c
index a56b491..aed056c 100644
--- a/contrib/ntp/ntpd/refclock_heath.c
+++ b/contrib/ntp/ntpd/refclock_heath.c
@@ -186,10 +186,10 @@ static int speed[] = {B1200, B2400, B4800, B9600};
/*
* Function prototypes
*/
-static int heath_start P((int, struct peer *));
-static void heath_shutdown P((int, struct peer *));
-static void heath_receive P((struct recvbuf *));
-static void heath_poll P((int, struct peer *));
+static int heath_start (int, struct peer *);
+static void heath_shutdown (int, struct peer *);
+static void heath_receive (struct recvbuf *);
+static void heath_poll (int, struct peer *);
/*
* Transfer vector
@@ -221,17 +221,19 @@ heath_start(
/*
* Open serial port
*/
- sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, speed[peer->ttl & 0x3],
- LDISC_REMOTE)))
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, speed[peer->ttl & 0x3],
+ LDISC_REMOTE);
+ if (fd <= 0)
return (0);
pp = peer->procptr;
pp->io.clock_recv = heath_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
return (0);
}
@@ -239,9 +241,8 @@ heath_start(
* Initialize miscellaneous variables
*/
peer->precision = PRECISION;
- peer->burst = NSTAGE;
pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
+ memcpy(&pp->refid, REFID, 4);
return (1);
}
@@ -258,7 +259,8 @@ heath_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- io_closeclock(&pp->io);
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
}
@@ -280,7 +282,7 @@ heath_receive(
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX,
&trtmp);
@@ -377,7 +379,7 @@ heath_receive(
/*
* Determine synchronization and last update
*/
- if (!isdigit((int)dsec))
+ if (!isdigit((unsigned char)dsec))
pp->leap = LEAP_NOTINSYNC;
else {
pp->nsec = (dsec - '0') * 100000000;
@@ -428,8 +430,6 @@ heath_poll(
if (write(pp->io.fd, "T", 1) != 1)
refclock_report(peer, CEVNT_FAULT);
ioctl(pp->io.fd, TIOCMBIS, (char *)&bits);
- if (peer->burst > 0)
- return;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
@@ -442,7 +442,6 @@ heath_poll(
printf("heath: timecode %d %s\n", pp->lencode,
pp->a_lastcode);
#endif
- peer->burst = MAXSTAGE;
pp->polls++;
}
diff --git a/contrib/ntp/ntpd/refclock_hopfpci.c b/contrib/ntp/ntpd/refclock_hopfpci.c
index 81c186d..95bcab9 100644
--- a/contrib/ntp/ntpd/refclock_hopfpci.c
+++ b/contrib/ntp/ntpd/refclock_hopfpci.c
@@ -124,51 +124,38 @@ hopfpci_start(
/*
* Allocate and initialize unit structure
*/
- up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
-
- if (!(up)) {
- msyslog(LOG_ERR, "hopfPCIClock(%d) emalloc: %m",unit);
-#ifdef DEBUG
- printf("hopfPCIClock(%d) emalloc\n",unit);
-#endif
- return (0);
- }
- memset((char *)up, 0, sizeof(struct hopfclock_unit));
+ up = emalloc_zero(sizeof(*up));
#ifndef SYS_WINNT
fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */
#else
- if (!OpenHopfDevice()){
- msyslog(LOG_ERR,"Start: %s unit: %d failed!",DEVICE,unit);
+ if (!OpenHopfDevice()) {
+ msyslog(LOG_ERR, "Start: %s unit: %d failed!", DEVICE, unit);
+ free(up);
return (0);
}
#endif
pp = peer->procptr;
pp->io.clock_recv = noentry;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = INVALID_SOCKET;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
get_systime(&pp->lastrec);
/*
* Initialize miscellaneous peer variables
*/
- if (pp->unitptr!=0) {
- memcpy((char *)&pp->refid, REFID, 4);
- peer->precision = PRECISION;
- pp->clockdesc = DESCRIPTION;
- up->leap_status = 0;
- up->unit = (short) unit;
- return (1);
- }
- else {
- return 0;
- }
+ memcpy((char *)&pp->refid, REFID, 4);
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ up->leap_status = 0;
+ up->unit = (short) unit;
+ return (1);
}
@@ -187,6 +174,8 @@ hopfpci_shutdown(
#else
CloseHopfDevice();
#endif
+ if (NULL != peer->procptr->unitptr)
+ free(peer->procptr->unitptr);
}
@@ -205,7 +194,9 @@ hopfpci_poll(
pp = peer->procptr;
#ifndef SYS_WINNT
- ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time);
+ if (ioctl(fd, HOPF_CLOCK_GET_UTC, &m_time) < 0)
+ msyslog(LOG_ERR, "HOPF_P(%d): HOPF_CLOCK_GET_UTC: %m",
+ unit);
#else
GetHopfSystemTime(&m_time);
#endif
@@ -221,9 +212,11 @@ hopfpci_poll(
else
pp->leap = LEAP_NOWARNING;
- sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d",
- m_time.wStatus, pp->hour, pp->minute, pp->second,
- pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear);
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d",
+ m_time.wStatus, pp->hour, pp->minute, pp->second,
+ pp->nsec / 1000000, m_time.wDay, m_time.wMonth,
+ m_time.wYear);
pp->lencode = (u_short)strlen(pp->a_lastcode);
get_systime(&pp->lastrec);
diff --git a/contrib/ntp/ntpd/refclock_hopfser.c b/contrib/ntp/ntpd/refclock_hopfser.c
index 9037d4a..dae8b37 100644
--- a/contrib/ntp/ntpd/refclock_hopfser.c
+++ b/contrib/ntp/ntpd/refclock_hopfser.c
@@ -95,11 +95,11 @@ struct hopfclock_unit {
* Function prototypes
*/
-static int hopfserial_start P((int, struct peer *));
-static void hopfserial_shutdown P((int, struct peer *));
-static void hopfserial_receive P((struct recvbuf *));
-static void hopfserial_poll P((int, struct peer *));
-/* static void hopfserial_io P((struct recvbuf *)); */
+static int hopfserial_start (int, struct peer *);
+static void hopfserial_shutdown (int, struct peer *);
+static void hopfserial_receive (struct recvbuf *);
+static void hopfserial_poll (int, struct peer *);
+/* static void hopfserial_io (struct recvbuf *); */
/*
* Transfer vector
*/
@@ -127,11 +127,8 @@ hopfserial_start (
int fd;
char gpsdev[20];
-#ifdef SYS_WINNT
- (void) sprintf(gpsdev, "COM%d:", unit);
-#else
- (void) sprintf(gpsdev, DEVICE, unit);
-#endif
+ snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
+
/* LDISC_STD, LDISC_RAW
* Open serial port. Use CLK line discipline, if available.
*/
@@ -149,30 +146,21 @@ hopfserial_start (
/*
* Allocate and initialize unit structure
*/
- up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
-
- if (!(up)) {
- msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit);
-#ifdef DEBUG
- printf("hopfSerialClock(%d) emalloc\n",unit);
-#endif
- (void) close(fd);
- return (0);
- }
-
- memset((char *)up, 0, sizeof(struct hopfclock_unit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = hopfserial_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
#ifdef DEBUG
- printf("hopfSerialClock(%d) io_addclock\n",unit);
+ printf("hopfSerialClock(%d) io_addclock\n", unit);
#endif
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
+ pp->unitptr = NULL;
return (0);
}
@@ -181,7 +169,6 @@ hopfserial_start (
*/
pp->clockdesc = DESCRIPTION;
peer->precision = PRECISION;
- peer->burst = NSTAGE;
memcpy((char *)&pp->refid, REFID, 4);
up->leap_status = 0;
@@ -204,9 +191,12 @@ hopfserial_shutdown (
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct hopfclock_unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -224,30 +214,31 @@ hopfserial_receive (
struct refclockproc *pp;
struct peer *peer;
- int synch; /* synchhronization indicator */
- int DoW; /* Dow */
+ int synch; /* synchhronization indicator */
+ int DoW; /* Day of Week */
int day, month; /* ddd conversion */
+ int converted;
/*
* Initialize pointers and read the timecode and timestamp.
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct hopfclock_unit *)pp->unitptr;
+ up = pp->unitptr;
if (up->rpt_next == 0 )
return;
-
up->rpt_next = 0; /* wait until next poll interval occur */
- pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
-
- if (pp->lencode == 0)
+ pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode,
+ sizeof(pp->a_lastcode),
+ &pp->lastrec);
+ if (pp->lencode == 0)
return;
- sscanf(pp->a_lastcode,
+ converted = sscanf(pp->a_lastcode,
#if 1
"%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */
#else
@@ -267,9 +258,9 @@ hopfserial_receive (
Validate received values at least enough to prevent internal
array-bounds problems, etc.
*/
- if((pp->hour < 0) || (pp->hour > 23) ||
- (pp->minute < 0) || (pp->minute > 59) ||
- (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
+ if ((8 != converted) || (pp->hour < 0) || (pp->hour > 23) ||
+ (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) ||
+ (pp->second > 60) /*Allow for leap seconds.*/ ||
(day < 1) || (day > 31) ||
(month < 1) || (month > 12) ||
(pp->year < 0) || (pp->year > 99)) {
@@ -292,7 +283,7 @@ hopfserial_receive (
/* preparation for timecode ntpq rl command ! */
#if 0
- wsprintf(pp->a_lastcode,
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
"STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d",
synch,
DoW,
@@ -364,7 +355,7 @@ hopfserial_poll (
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct hopfclock_unit *)pp->unitptr;
+ up = pp->unitptr;
pp->polls++;
up->rpt_next = 1;
diff --git a/contrib/ntp/ntpd/refclock_hpgps.c b/contrib/ntp/ntpd/refclock_hpgps.c
index 5efd19e..0b45fc7 100644
--- a/contrib/ntp/ntpd/refclock_hpgps.c
+++ b/contrib/ntp/ntpd/refclock_hpgps.c
@@ -125,10 +125,10 @@ struct hpgpsunit {
/*
* Function prototypes
*/
-static int hpgps_start P((int, struct peer *));
-static void hpgps_shutdown P((int, struct peer *));
-static void hpgps_receive P((struct recvbuf *));
-static void hpgps_poll P((int, struct peer *));
+static int hpgps_start (int, struct peer *);
+static void hpgps_shutdown (int, struct peer *);
+static void hpgps_receive (struct recvbuf *);
+static void hpgps_poll (int, struct peer *);
/*
* Transfer vector
@@ -156,42 +156,40 @@ hpgps_start(
register struct hpgpsunit *up;
struct refclockproc *pp;
int fd;
+ int speed, ldisc;
char device[20];
/*
* Open serial port. Use CLK line discipline, if available.
* Default is HP 58503A, mode arg selects HP Z3801A
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
+ ldisc = LDISC_CLK;
+ speed = SPEED232;
/* mode parameter to server config line shares ttl slot */
- if ((peer->ttl == 1)) {
- if (!(fd = refclock_open(device, SPEED232Z,
- LDISC_CLK | LDISC_7O1)))
- return (0);
- } else {
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
- return (0);
+ if (1 == peer->ttl) {
+ ldisc |= LDISC_7O1;
+ speed = SPEED232Z;
}
+ fd = refclock_open(device, speed, ldisc);
+ if (fd <= 0)
+ return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct hpgpsunit *)
- emalloc(sizeof(struct hpgpsunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct hpgpsunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = hpgps_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -231,9 +229,11 @@ hpgps_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct hpgpsunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -266,9 +266,9 @@ hpgps_receive(
/*
* Initialize pointers and read the receiver response
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct hpgpsunit *)pp->unitptr;
+ up = pp->unitptr;
*pp->a_lastcode = '\0';
pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
@@ -301,7 +301,7 @@ hpgps_receive(
if (up->linecnt-- > 0) {
if ((int)(pp->lencode + 2) <= (SMAX - (up->lastptr - up->statscrn))) {
*up->lastptr++ = '\n';
- (void)strcpy(up->lastptr, pp->a_lastcode);
+ memcpy(up->lastptr, pp->a_lastcode, pp->lencode);
up->lastptr += pp->lencode;
}
if (up->linecnt == 0)
@@ -334,7 +334,7 @@ hpgps_receive(
*
*/
- (void)strcpy(prompt,pp->a_lastcode);
+ strlcpy(prompt, pp->a_lastcode, sizeof(prompt));
tcp = strrchr(pp->a_lastcode,'>');
if (tcp == NULL)
tcp = pp->a_lastcode;
@@ -532,18 +532,25 @@ hpgps_receive(
pp->leap = LEAP_NOTINSYNC;
}
else {
+ pp->leap = LEAP_NOWARNING;
switch (leapchar) {
- case '+':
- pp->leap = LEAP_ADDSECOND;
+ case '0':
break;
- case '0':
- pp->leap = LEAP_NOWARNING;
+ /* See http://bugs.ntp.org/1090
+ * Ignore leap announcements unless June or December.
+ * Better would be to use :GPSTime? to find the month,
+ * but that seems too likely to introduce other bugs.
+ */
+ case '+':
+ if ((month==6) || (month==12))
+ pp->leap = LEAP_ADDSECOND;
break;
case '-':
- pp->leap = LEAP_DELSECOND;
+ if ((month==6) || (month==12))
+ pp->leap = LEAP_DELSECOND;
break;
default:
@@ -602,7 +609,7 @@ hpgps_poll(
* declare a timeout and keep going.
*/
pp = peer->procptr;
- up = (struct hpgpsunit *)pp->unitptr;
+ up = pp->unitptr;
if (up->pollcnt == 0)
refclock_report(peer, CEVNT_TIMEOUT);
else
diff --git a/contrib/ntp/ntpd/refclock_irig.c b/contrib/ntp/ntpd/refclock_irig.c
index 6be09d9..abc94f6 100644
--- a/contrib/ntp/ntpd/refclock_irig.c
+++ b/contrib/ntp/ntpd/refclock_irig.c
@@ -25,27 +25,36 @@
/*
* Audio IRIG-B/E demodulator/decoder
*
- * This driver receives, demodulates and decodes IRIG-B/E signals when
- * connected to the audio codec /dev/audio. The IRIG signal format is an
- * amplitude-modulated carrier with pulse-width modulated data bits. For
- * IRIG-B, the carrier frequency is 1000 Hz and bit rate 100 b/s; for
- * IRIG-E, the carrier frequenchy is 100 Hz and bit rate 10 b/s. The
- * driver automatically recognizes which format is in use.
+ * This driver synchronizes the computer time using data encoded in
+ * IRIG-B/E signals commonly produced by GPS receivers and other timing
+ * devices. The IRIG signal is an amplitude-modulated carrier with
+ * pulse-width modulated data bits. For IRIG-B, the carrier frequency is
+ * 1000 Hz and bit rate 100 b/s; for IRIG-E, the carrier frequenchy is
+ * 100 Hz and bit rate 10 b/s. The driver automatically recognizes which
+ & format is in use.
+ *
+ * The driver requires an audio codec or sound card with sampling rate 8
+ * kHz and mu-law companding. This is the same standard as used by the
+ * telephone industry and is supported by most hardware and operating
+ * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this
+ * implementation, only one audio driver and codec can be supported on a
+ * single machine.
*
* The program processes 8000-Hz mu-law companded samples using separate
* signal filters for IRIG-B and IRIG-E, a comb filter, envelope
* detector and automatic threshold corrector. Cycle crossings relative
* to the corrected slice level determine the width of each pulse and
- * its value - zero, one or position identifier. The data encode 20 BCD
- * digits which determine the second, minute, hour and day of the year
- * and sometimes the year and synchronization condition. The comb filter
- * exponentially averages the corresponding samples of successive baud
- * intervals in order to reliably identify the reference carrier cycle.
- * A type-II phase-lock loop (PLL) performs additional integration and
- * interpolation to accurately determine the zero crossing of that
- * cycle, which determines the reference timestamp. A pulse-width
- * discriminator demodulates the data pulses, which are then encoded as
- * the BCD digits of the timecode.
+ * its value - zero, one or position identifier.
+ *
+ * The data encode 20 BCD digits which determine the second, minute,
+ * hour and day of the year and sometimes the year and synchronization
+ * condition. The comb filter exponentially averages the corresponding
+ * samples of successive baud intervals in order to reliably identify
+ * the reference carrier cycle. A type-II phase-lock loop (PLL) performs
+ * additional integration and interpolation to accurately determine the
+ * zero crossing of that cycle, which determines the reference
+ * timestamp. A pulse-width discriminator demodulates the data pulses,
+ * which are then encoded as the BCD digits of the timecode.
*
* The timecode and reference timestamp are updated once each second
* with IRIG-B (ten seconds with IRIG-E) and local clock offset samples
@@ -60,70 +69,60 @@
* decompanded input signal amplitude must be greater than 100 units and
* the codec sample frequency error less than 250 PPM (.025 percent).
*
- * The program performs a number of error checks to protect against
- * overdriven or underdriven input signal levels, incorrect signal
- * format or improper hardware configuration. Specifically, if any of
- * the following errors occur for a time measurement, the data are
- * rejected.
- *
- * o The peak carrier amplitude is less than DRPOUT (100). This usually
- * means dead IRIG signal source, broken cable or wrong input port.
- *
- * o The frequency error is greater than MAXFREQ +-250 PPM (.025%). This
- * usually means broken codec hardware or wrong codec configuration.
- *
- * o The modulation index is less than MODMIN (0.5). This usually means
- * overdriven IRIG signal or wrong IRIG format.
- *
- * o A frame synchronization error has occurred. This usually means
- * wrong IRIG signal format or the IRIG signal source has lost
- * synchronization (signature control).
- *
- * o A data decoding error has occurred. This usually means wrong IRIG
- * signal format.
- *
- * o The current second of the day is not exactly one greater than the
- * previous one. This usually means a very noisy IRIG signal or
- * insufficient CPU resources.
+ * Monitor Data
*
- * o An audio codec error (overrun) occurred. This usually means
- * insufficient CPU resources, as sometimes happens with Sun SPARC
- * IPCs when doing something useful.
+ * The timecode format used for debugging and data recording includes
+ * data helpful in diagnosing problems with the IRIG signal and codec
+ * connections. The driver produces one line for each timecode in the
+ * following format:
*
- * Note that additional checks are done elsewhere in the reference clock
- * interface routines.
+ * 00 00 98 23 19:26:52 2782 143 0.694 10 0.3 66.5 3094572411.00027
*
- * Debugging aids
+ * If clockstats is enabled, the most recent line is written to the
+ * clockstats file every 64 s. If verbose recording is enabled (fudge
+ * flag 4) each line is written as generated.
*
- * The timecode format used for debugging and data recording includes
- * data helpful in diagnosing problems with the IRIG signal and codec
- * connections. With debugging enabled (-d on the ntpd command line),
- * the driver produces one line for each timecode in the following
- * format:
+ * The first field containes the error flags in hex, where the hex bits
+ * are interpreted as below. This is followed by the year of century,
+ * day of year and time of day. Note that the time of day is for the
+ * previous minute, not the current time. The status indicator and year
+ * are not produced by some IRIG devices and appear as zeros. Following
+ * these fields are the carrier amplitude (0-3000), codec gain (0-255),
+ * modulation index (0-1), time constant (4-10), carrier phase error
+ * +-.5) and carrier frequency error (PPM). The last field is the on-
+ * time timestamp in NTP format.
*
- * 00 1 98 23 19:26:52 721 143 0.694 20 0.1 66.5 3094572411.00027
+ * The error flags are defined as follows in hex:
*
- * The most recent line is also written to the clockstats file at 64-s
- * intervals.
+ * x01 Low signal. The carrier amplitude is less than 100 units. This
+ * is usually the result of no signal or wrong input port.
+ * x02 Frequency error. The codec frequency error is greater than 250
+ * PPM. This may be due to wrong signal format or (rarely)
+ * defective codec.
+ * x04 Modulation error. The IRIG modulation index is less than 0.5.
+ * This is usually the result of an overdriven codec, wrong signal
+ * format or wrong input port.
+ * x08 Frame synch error. The decoder frame does not match the IRIG
+ * frame. This is usually the result of an overdriven codec, wrong
+ * signal format or noisy IRIG signal. It may also be the result of
+ * an IRIG signature check which indicates a failure of the IRIG
+ * signal synchronization source.
+ * x10 Data bit error. The data bit length is out of tolerance. This is
+ * usually the result of an overdriven codec, wrong signal format
+ * or noisy IRIG signal.
+ * x20 Seconds numbering discrepancy. The decoder second does not match
+ * the IRIG second. This is usually the result of an overdriven
+ * codec, wrong signal format or noisy IRIG signal.
+ * x40 Codec error (overrun). The machine is not fast enough to keep up
+ * with the codec.
+ * x80 Device status error (Spectracom).
*
- * The first field contains the error flags in hex, where the hex bits
- * are interpreted as below. This is followed by the IRIG status
- * indicator, year of century, day of year and time of day. The status
- * indicator and year are not produced by some IRIG devices. Following
- * these fields are the signal amplitude (0-8100), codec gain (0-255),
- * modulation index (0-1), time constant (2-20), carrier phase error
- * (us) and carrier frequency error (PPM). The last field is the on-time
- * timestamp in NTP format.
*
- * The fraction part of the on-time timestamp is a good indicator of how
- * well the driver is doing. Once upon a time, an UltrSPARC 30 and
- * Solaris 2.7 kept the clock within a few tens of microseconds relative
- * to the IRIG-B signal. Accuracy with IRIG-E was about ten times worse.
- * Unfortunately, Sun broke the 2.7 audio driver in 2.8, which has a 10-
- * ms sawtooth modulation. The driver attempts to remove the modulation
- * by some clever estimation techniques which mostly work. With the
- * "mixerctl -o" command before starting the daemon, the jitter is down
- * to about 100 microseconds. Your experience may vary.
+ * Once upon a time, an UltrSPARC 30 and Solaris 2.7 kept the clock
+ * within a few tens of microseconds relative to the IRIG-B signal.
+ * Accuracy with IRIG-E was about ten times worse. Unfortunately, Sun
+ * broke the 2.7 audio driver in 2.8, which has a 10-ms sawtooth
+ * modulation.
*
* Unlike other drivers, which can have multiple instantiations, this
* one supports only one. It does not seem likely that more than one
@@ -137,8 +136,13 @@
* port, where 0 is the mike port (default) and 1 is the line-in port.
* It does not seem useful to select the compact disc player port. Fudge
* flag3 enables audio monitoring of the input signal. For this purpose,
- * the monitor gain is set to a default value. Fudgetime2 is used as a
+ * the monitor gain is set t a default value. Fudgetime2 is used as a
* frequency vernier for broken codec sample frequency.
+ *
+ * Alarm codes
+ *
+ * CEVNT_BADTIME invalid date or time
+ * CEVNT_TIMEOUT no IRIG data since last poll
*/
/*
* Interface definitions
@@ -152,26 +156,30 @@
#define BAUD 80 /* samples per baud interval */
#define OFFSET 128 /* companded sample offset */
#define SIZE 256 /* decompanding table size */
-#define CYCLE 8 /* samples per carrier cycle */
-#define SUBFLD 10 /* bits per subfield */
-#define FIELD 10 /* subfields per field */
+#define CYCLE 8 /* samples per bit */
+#define SUBFLD 10 /* bits per frame */
+#define FIELD 100 /* bits per second */
#define MINTC 2 /* min PLL time constant */
-#define MAXTC 20 /* max PLL time constant max */
-#define MAXAMP 6000. /* maximum signal level */
-#define MAXCLP 100 /* max clips above reference per s */
-#define DRPOUT 100. /* dropout signal level */
+#define MAXTC 10 /* max PLL time constant max */
+#define MAXAMP 3000. /* maximum signal amplitude */
+#define MINAMP 2000. /* minimum signal amplitude */
+#define DRPOUT 100. /* dropout signal amplitude */
#define MODMIN 0.5 /* minimum modulation index */
#define MAXFREQ (250e-6 * SECOND) /* freq tolerance (.025%) */
-#define PI 3.1415926535 /* the real thing */
-#ifdef IRIG_SUCKS
-#define WIGGLE 11 /* wiggle filter length */
-#endif /* IRIG_SUCKS */
/*
- * Experimentally determined filter delays
+ * The on-time synchronization point is the positive-going zero crossing
+ * of the first cycle of the second. The IIR baseband filter phase delay
+ * is 1.03 ms for IRIG-B and 3.47 ms for IRIG-E. The fudge value 2.68 ms
+ * due to the codec and other causes was determined by calibrating to a
+ * PPS signal from a GPS receiver.
+ *
+ * The results with a 2.4-GHz P4 running FreeBSD 6.1 are generally
+ * within .02 ms short-term with .02 ms jitter. The processor load due
+ * to the driver is 0.51 percent.
*/
-#define IRIG_B .0019 /* IRIG-B filter delay */
-#define IRIG_E .0019 /* IRIG-E filter delay */
+#define IRIG_B ((1.03 + 2.68) / 1000) /* IRIG-B system delay (s) */
+#define IRIG_E ((3.47 + 2.68) / 1000) /* IRIG-E system delay (s) */
/*
* Data bit definitions
@@ -181,7 +189,7 @@
#define BITP 2 /* position identifier */
/*
- * Error flags (up->errflg)
+ * Error flags
*/
#define IRIG_ERR_AMP 0x01 /* low carrier amplitude */
#define IRIG_ERR_FREQ 0x02 /* frequency tolerance exceeded */
@@ -192,13 +200,18 @@
#define IRIG_ERR_ERROR 0x40 /* codec error (overrun) */
#define IRIG_ERR_SIGERR 0x80 /* IRIG status error (Spectracom) */
+static char hexchar[] = "0123456789abcdef";
+
/*
* IRIG unit control structure
*/
struct irigunit {
- u_char timecode[21]; /* timecode string */
+ u_char timecode[2 * SUBFLD + 1]; /* timecode string */
l_fp timestamp; /* audio sample timestamp */
l_fp tick; /* audio sample increment */
+ l_fp refstamp; /* reference timestamp */
+ l_fp chrstamp; /* baud timestamp */
+ l_fp prvstamp; /* previous baud timestamp */
double integ[BAUD]; /* baud integrator */
double phase, freq; /* logical clock phase and frequency */
double zxing; /* phase detector integrator */
@@ -212,20 +225,20 @@ struct irigunit {
* Audio codec variables
*/
double comp[SIZE]; /* decompanding table */
+ double signal; /* peak signal for AGC */
int port; /* codec port */
int gain; /* codec gain */
int mongain; /* codec monitor gain */
- int clipcnt; /* sample clipped count */
int seccnt; /* second interval counter */
/*
* RF variables
*/
- double hpf[5]; /* IRIG-B filter shift register */
+ double bpf[9]; /* IRIG-B filter shift register */
double lpf[5]; /* IRIG-E filter shift register */
+ double envmin, envmax; /* envelope min and max */
+ double slice; /* envelope slice level */
double intmin, intmax; /* integrated envelope min and max */
- double envmax; /* peak amplitude */
- double envmin; /* noise amplitude */
double maxsignal; /* integrated peak amplitude */
double noise; /* integrated noise amplitude */
double lastenv[CYCLE]; /* last cycle amplitudes */
@@ -235,7 +248,6 @@ struct irigunit {
int decim; /* sample decimation factor */
int envphase; /* envelope phase */
int envptr; /* envelope phase pointer */
- int carphase; /* carrier phase */
int envsw; /* envelope state */
int envxing; /* envelope slice crossing */
int tc; /* time constant */
@@ -248,36 +260,30 @@ struct irigunit {
int pulse; /* cycle counter */
int cycles; /* carrier cycles */
int dcycles; /* data cycles */
- int xptr; /* translate table pointer */
- int lastbit; /* last code element length */
+ int lastbit; /* last code element */
int second; /* previous second */
- int fieldcnt; /* subfield count in field */
+ int bitcnt; /* bit count in frame */
+ int frmcnt; /* bit count in second */
+ int xptr; /* timecode pointer */
int bits; /* demodulated bits */
- int bitcnt; /* bit count in subfield */
-#ifdef IRIG_SUCKS
- l_fp wigwag; /* wiggle accumulator */
- int wp; /* wiggle filter pointer */
- l_fp wiggle[WIGGLE]; /* wiggle filter */
- l_fp wigbot[WIGGLE]; /* wiggle bottom fisher*/
-#endif /* IRIG_SUCKS */
- l_fp wuggle;
};
/*
* Function prototypes
*/
-static int irig_start P((int, struct peer *));
-static void irig_shutdown P((int, struct peer *));
-static void irig_receive P((struct recvbuf *));
-static void irig_poll P((int, struct peer *));
+static int irig_start (int, struct peer *);
+static void irig_shutdown (int, struct peer *);
+static void irig_receive (struct recvbuf *);
+static void irig_poll (int, struct peer *);
/*
* More function prototypes
*/
-static void irig_base P((struct peer *, double));
-static void irig_rf P((struct peer *, double));
-static void irig_decode P((struct peer *, int));
-static void irig_gain P((struct peer *));
+static void irig_base (struct peer *, double);
+static void irig_rf (struct peer *, double);
+static void irig_baud (struct peer *, int);
+static void irig_decode (struct peer *, int);
+static void irig_gain (struct peer *);
/*
* Transfer vector
@@ -292,16 +298,6 @@ struct refclock refclock_irig = {
NOFLAGS /* not used */
};
-/*
- * Global variables
- */
-static char hexchar[] = { /* really quick decoding table */
- '0', '8', '4', 'c', /* 0000 0001 0010 0011 */
- '2', 'a', '6', 'e', /* 0100 0101 0110 0111 */
- '1', '9', '5', 'd', /* 1000 1001 1010 1011 */
- '3', 'b', '7', 'f' /* 1100 1101 1110 1111 */
-};
-
/*
* irig_start - open the devices and initialize data for processing
@@ -336,23 +332,19 @@ irig_start(
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct irigunit *)
- emalloc(sizeof(struct irigunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct irigunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
pp->io.clock_recv = irig_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void)close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -362,7 +354,6 @@ irig_start(
memcpy((char *)&pp->refid, REFID, 4);
up->tc = MINTC;
up->decim = 1;
- up->fdelay = IRIG_B;
up->gain = 127;
/*
@@ -376,7 +367,7 @@ irig_start(
for (i = 3; i < OFFSET; i++) {
up->comp[i] = up->comp[i - 1] + step;
up->comp[OFFSET + i] = -up->comp[i];
- if (i % 16 == 0)
+ if (i % 16 == 0)
step *= 2.;
}
DTOLFP(1. / SECOND, &up->tick);
@@ -397,9 +388,11 @@ irig_shutdown(
struct irigunit *up;
pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -426,9 +419,9 @@ irig_receive(
int bufcnt; /* buffer counter */
l_fp ltemp; /* l_fp temp */
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Main loop - read until there ain't no more. Note codec
@@ -442,19 +435,6 @@ irig_receive(
sample = up->comp[~*dpt++ & 0xff];
/*
- * Clip noise spikes greater than MAXAMP. If no clips,
- * increase the gain a tad; if the clips are too high,
- * decrease a tad.
- */
- if (sample > MAXAMP) {
- sample = MAXAMP;
- up->clipcnt++;
- } else if (sample < -MAXAMP) {
- sample = -MAXAMP;
- up->clipcnt++;
- }
-
- /*
* Variable frequency oscillator. The codec oscillator
* runs at the nominal rate of 8000 samples per second,
* or 125 us per sample. A frequency change of one unit
@@ -462,7 +442,7 @@ irig_receive(
* per second, which results in a frequency change of
* 125 PPM.
*/
- up->phase += up->freq / SECOND;
+ up->phase += (up->freq + clock_codec) / SECOND;
up->phase += pp->fudgetime2 / 1e6;
if (up->phase >= .5) {
up->phase -= 1.;
@@ -474,6 +454,11 @@ irig_receive(
irig_rf(peer, sample);
}
L_ADD(&up->timestamp, &up->tick);
+ sample = fabs(sample);
+ if (sample > up->signal)
+ up->signal = sample;
+ up->signal += (sample - up->signal) /
+ 1000;
/*
* Once each second, determine the IRIG format and gain.
@@ -487,8 +472,9 @@ irig_receive(
up->decim = 10;
up->fdelay = IRIG_E;
}
- irig_gain(peer);
up->irig_b = up->irig_e = 0;
+ irig_gain(peer);
+
}
}
@@ -505,14 +491,14 @@ irig_receive(
up->mongain = 0;
}
+
/*
* irig_rf - RF processing
*
- * This routine filters the RF signal using a highpass filter for IRIG-B
+ * This routine filters the RF signal using a bandass filter for IRIG-B
* and a lowpass filter for IRIG-E. In case of IRIG-E, the samples are
- * decimated by a factor of ten. The lowpass filter functions also as a
- * decimation filter in this case. Note that the codec filters function
- * as roofing filters to attenuate both the high and low ends of the
+ * decimated by a factor of ten. Note that the codec filters function as
+ * roofing filters to attenuate both the high and low ends of the
* passband. IIR filter coefficients were determined using Matlab Signal
* Processing Toolkit.
*/
@@ -531,39 +517,48 @@ irig_rf(
double irig_b, irig_e; /* irig filter outputs */
pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
+ up = pp->unitptr;
/*
- * IRIG-B filter. 4th-order elliptic, 800-Hz highpass, 0.3 dB
- * passband ripple, -50 dB stopband ripple, phase delay .0022
- * s)
+ * IRIG-B filter. Matlab 4th-order IIR elliptic, 800-1200 Hz
+ * bandpass, 0.3 dB passband ripple, -50 dB stopband ripple,
+ * phase delay 1.03 ms.
*/
- irig_b = (up->hpf[4] = up->hpf[3]) * 2.322484e-01;
- irig_b += (up->hpf[3] = up->hpf[2]) * -1.103929e+00;
- irig_b += (up->hpf[2] = up->hpf[1]) * 2.351081e+00;
- irig_b += (up->hpf[1] = up->hpf[0]) * -2.335036e+00;
- up->hpf[0] = sample - irig_b;
- irig_b = up->hpf[0] * 4.335855e-01
- + up->hpf[1] * -1.695859e+00
- + up->hpf[2] * 2.525004e+00
- + up->hpf[3] * -1.695859e+00
- + up->hpf[4] * 4.335855e-01;
+ irig_b = (up->bpf[8] = up->bpf[7]) * 6.505491e-001;
+ irig_b += (up->bpf[7] = up->bpf[6]) * -3.875180e+000;
+ irig_b += (up->bpf[6] = up->bpf[5]) * 1.151180e+001;
+ irig_b += (up->bpf[5] = up->bpf[4]) * -2.141264e+001;
+ irig_b += (up->bpf[4] = up->bpf[3]) * 2.712837e+001;
+ irig_b += (up->bpf[3] = up->bpf[2]) * -2.384486e+001;
+ irig_b += (up->bpf[2] = up->bpf[1]) * 1.427663e+001;
+ irig_b += (up->bpf[1] = up->bpf[0]) * -5.352734e+000;
+ up->bpf[0] = sample - irig_b;
+ irig_b = up->bpf[0] * 4.952157e-003
+ + up->bpf[1] * -2.055878e-002
+ + up->bpf[2] * 4.401413e-002
+ + up->bpf[3] * -6.558851e-002
+ + up->bpf[4] * 7.462108e-002
+ + up->bpf[5] * -6.558851e-002
+ + up->bpf[6] * 4.401413e-002
+ + up->bpf[7] * -2.055878e-002
+ + up->bpf[8] * 4.952157e-003;
up->irig_b += irig_b * irig_b;
/*
- * IRIG-E filter. 4th-order elliptic, 130-Hz lowpass, 0.3 dB
- * passband ripple, -50 dB stopband ripple, phase delay .0219 s.
+ * IRIG-E filter. Matlab 4th-order IIR elliptic, 130-Hz lowpass,
+ * 0.3 dB passband ripple, -50 dB stopband ripple, phase delay
+ * 3.47 ms.
*/
- irig_e = (up->lpf[4] = up->lpf[3]) * 8.694604e-01;
- irig_e += (up->lpf[3] = up->lpf[2]) * -3.589893e+00;
- irig_e += (up->lpf[2] = up->lpf[1]) * 5.570154e+00;
- irig_e += (up->lpf[1] = up->lpf[0]) * -3.849667e+00;
+ irig_e = (up->lpf[4] = up->lpf[3]) * 8.694604e-001;
+ irig_e += (up->lpf[3] = up->lpf[2]) * -3.589893e+000;
+ irig_e += (up->lpf[2] = up->lpf[1]) * 5.570154e+000;
+ irig_e += (up->lpf[1] = up->lpf[0]) * -3.849667e+000;
up->lpf[0] = sample - irig_e;
- irig_e = up->lpf[0] * 3.215696e-03
- + up->lpf[1] * -1.174951e-02
- + up->lpf[2] * 1.712074e-02
- + up->lpf[3] * -1.174951e-02
- + up->lpf[4] * 3.215696e-03;
+ irig_e = up->lpf[0] * 3.215696e-003
+ + up->lpf[1] * -1.174951e-002
+ + up->lpf[2] * 1.712074e-002
+ + up->lpf[3] * -1.174951e-002
+ + up->lpf[4] * 3.215696e-003;
up->irig_e += irig_e * irig_e;
/*
@@ -583,7 +578,8 @@ irig_rf(
*
* This routine processes the baseband signal and demodulates the AM
* carrier using a synchronous detector. It then synchronizes to the
- * data frame at the baud rate and decodes the data pulses.
+ * data frame at the baud rate and decodes the width-modulated data
+ * pulses.
*/
static void
irig_base(
@@ -597,61 +593,53 @@ irig_base(
/*
* Local variables
*/
- double xxing; /* phase detector interpolated output */
double lope; /* integrator output */
double env; /* envelope detector output */
- double dtemp; /* double temp */
+ double dtemp;
+ int carphase; /* carrier phase */
pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Synchronous baud integrator. Corresponding samples of current
* and past baud intervals are integrated to refine the envelope
- * amplitude and phase estimate. We keep one cycle of both the
- * raw and integrated data for later use.
+ * amplitude and phase estimate. We keep one cycle (1 ms) of the
+ * raw data and one baud (10 ms) of the integrated data.
*/
up->envphase = (up->envphase + 1) % BAUD;
- up->carphase = (up->carphase + 1) % CYCLE;
up->integ[up->envphase] += (sample - up->integ[up->envphase]) /
(5 * up->tc);
lope = up->integ[up->envphase];
- up->lastenv[up->carphase] = sample;
- up->lastint[up->carphase] = lope;
+ carphase = up->envphase % CYCLE;
+ up->lastenv[carphase] = sample;
+ up->lastint[carphase] = lope;
/*
- * Phase detector. Sample amplitudes are integrated over the
- * baud interval. Cycle phase is determined from these
- * amplitudes using an eight-sample cyclic buffer. A phase
- * change of 360 degrees produces an output change of one unit.
+ * Phase detector. Find the negative-going zero crossing
+ * relative to sample 4 in the 8-sample sycle. A phase change of
+ * 360 degrees produces an output change of one unit.
*/
- if (up->lastsig > 0 && lope <= 0) {
- xxing = lope / (up->lastsig - lope);
- up->zxing += (up->carphase - 4 + xxing) / CYCLE;
- }
+ if (up->lastsig > 0 && lope <= 0)
+ up->zxing += (double)(carphase - 4) / CYCLE;
up->lastsig = lope;
/*
- * Update signal/noise estimates and PLL phase/frequency.
+ * End of the baud. Update signal/noise estimates and PLL
+ * phase, frequency and time constant.
*/
if (up->envphase == 0) {
-
- /*
- * Update envelope signal and noise estimates and mess
- * with error bits.
- */
- up->maxsignal = up->intmax;
- up->noise = up->intmin;
+ up->maxsignal = up->intmax; up->noise = up->intmin;
+ up->intmin = 1e6; up->intmax = -1e6;
if (up->maxsignal < DRPOUT)
up->errflg |= IRIG_ERR_AMP;
if (up->maxsignal > 0)
- up->modndx = (up->intmax - up->intmin) /
- up->intmax;
+ up->modndx = (up->maxsignal - up->noise) /
+ up->maxsignal;
else
up->modndx = 0;
if (up->modndx < MODMIN)
up->errflg |= IRIG_ERR_MOD;
- up->intmin = 1e6; up->intmax = 0;
if (up->errflg & (IRIG_ERR_AMP | IRIG_ERR_FREQ |
IRIG_ERR_MOD | IRIG_ERR_SYNCH)) {
up->tc = MINTC;
@@ -681,17 +669,17 @@ irig_base(
/*
* Synchronous demodulator. There are eight samples in the cycle
- * and ten cycles in the baud interval. The amplitude of each
- * cycle is determined at the last sample in the cycle. The
+ * and ten cycles in the baud. Since the PLL has aligned the
+ * negative-going zero crossing at sample 4, the maximum
+ * amplitude is at sample 2 and minimum at sample 6. The
* beginning of the data pulse is determined from the integrated
* samples, while the end of the pulse is determined from the
* raw samples. The raw data bits are demodulated relative to
* the slice level and left-shifted in the decoding register.
*/
- if (up->carphase != 7)
+ if (carphase != 7)
return;
- env = (up->lastenv[2] - up->lastenv[6]) / 2.;
lope = (up->lastint[2] - up->lastint[6]) / 2.;
if (lope > up->intmax)
up->intmax = lope;
@@ -705,91 +693,130 @@ irig_base(
* when three correct frames have been found.
*/
up->pulse = (up->pulse + 1) % 10;
- if (up->pulse == 1)
- up->envmax = env;
- else if (up->pulse == 9)
- up->envmin = env;
- up->dcycles <<= 1;
- if (env >= (up->envmax + up->envmin) / 2.)
- up->dcycles |= 1;
up->cycles <<= 1;
if (lope >= (up->maxsignal + up->noise) / 2.)
up->cycles |= 1;
if ((up->cycles & 0x303c0f03) == 0x300c0300) {
- l_fp ltemp;
- int bitz;
-
- /*
- * The PLL time constant starts out small, in order to
- * sustain a frequency tolerance of 250 PPM. It
- * gradually increases as the loop settles down. Note
- * that small wiggles are not believed, unless they
- * persist for lots of samples.
- */
- if (up->pulse != 9)
+ if (up->pulse != 0)
up->errflg |= IRIG_ERR_SYNCH;
- up->pulse = 9;
- up->exing = -up->yxing;
- if (fabs(up->envxing - up->envphase) <= 1) {
- up->tcount++;
- if (up->tcount > 50 * up->tc) {
- up->tc++;
- if (up->tc > MAXTC)
- up->tc = MAXTC;
- up->tcount = 0;
- up->envxing = up->envphase;
- } else {
- up->exing -= up->envxing - up->envphase;
- }
- } else {
+ up->pulse = 0;
+ }
+
+ /*
+ * Assemble the baud and max/min to get the slice level for the
+ * next baud. The slice level is based on the maximum over the
+ * first two bits and the minimum over the last two bits, with
+ * the slice level halfway between the maximum and minimum.
+ */
+ env = (up->lastenv[2] - up->lastenv[6]) / 2.;
+ up->dcycles <<= 1;
+ if (env >= up->slice)
+ up->dcycles |= 1;
+ switch(up->pulse) {
+
+ case 0:
+ irig_baud(peer, up->dcycles);
+ if (env < up->envmin)
+ up->envmin = env;
+ up->slice = (up->envmax + up->envmin) / 2;
+ up->envmin = 1e6; up->envmax = -1e6;
+ break;
+
+ case 1:
+ up->envmax = env;
+ break;
+
+ case 2:
+ if (env > up->envmax)
+ up->envmax = env;
+ break;
+
+ case 9:
+ up->envmin = env;
+ break;
+ }
+}
+
+/*
+ * irig_baud - update the PLL and decode the pulse-width signal
+ */
+static void
+irig_baud(
+ struct peer *peer, /* peer structure pointer */
+ int bits /* decoded bits */
+ )
+{
+ struct refclockproc *pp;
+ struct irigunit *up;
+ double dtemp;
+ l_fp ltemp;
+
+ pp = peer->procptr;
+ up = pp->unitptr;
+
+ /*
+ * The PLL time constant starts out small, in order to
+ * sustain a frequency tolerance of 250 PPM. It
+ * gradually increases as the loop settles down. Note
+ * that small wiggles are not believed, unless they
+ * persist for lots of samples.
+ */
+ up->exing = -up->yxing;
+ if (abs(up->envxing - up->envphase) <= 1) {
+ up->tcount++;
+ if (up->tcount > 20 * up->tc) {
+ up->tc++;
+ if (up->tc > MAXTC)
+ up->tc = MAXTC;
up->tcount = 0;
up->envxing = up->envphase;
+ } else {
+ up->exing -= up->envxing - up->envphase;
}
+ } else {
+ up->tcount = 0;
+ up->envxing = up->envphase;
+ }
- /*
- * Determine a reference timestamp, accounting for the
- * codec delay and filter delay. Note the timestamp is
- * for the previous frame, so we have to backtrack for
- * this plus the delay since the last carrier positive
- * zero crossing.
- */
- dtemp = up->decim * ((up->exing + BAUD) / SECOND + 1.) +
- up->fdelay;
- DTOLFP(dtemp, &ltemp);
- pp->lastrec = up->timestamp;
- L_SUB(&pp->lastrec, &ltemp);
+ /*
+ * Strike the baud timestamp as the positive zero crossing of
+ * the first bit, accounting for the codec delay and filter
+ * delay.
+ */
+ up->prvstamp = up->chrstamp;
+ dtemp = up->decim * (up->exing / SECOND) + up->fdelay;
+ DTOLFP(dtemp, &ltemp);
+ up->chrstamp = up->timestamp;
+ L_SUB(&up->chrstamp, &ltemp);
- /*
- * The data bits are collected in ten-bit frames. The
- * first two and last two bits are determined by frame
- * sync and ignored here; the resulting patterns
- * represent zero (0-1 bits), one (2-4 bits) and
- * position identifier (5-6 bits). The remaining
- * patterns represent errors and are treated as zeros.
- */
- bitz = up->dcycles & 0xfc;
- switch(bitz) {
-
- case 0x00:
- case 0x80:
- irig_decode(peer, BIT0);
- break;
-
- case 0xc0:
- case 0xe0:
- case 0xf0:
- irig_decode(peer, BIT1);
- break;
-
- case 0xf8:
- case 0xfc:
- irig_decode(peer, BITP);
- break;
-
- default:
- irig_decode(peer, 0);
- up->errflg |= IRIG_ERR_DECODE;
- }
+ /*
+ * The data bits are collected in ten-bit bauds. The first two
+ * bits are not used. The resulting patterns represent runs of
+ * 0-1 bits (0), 2-4 bits (1) and 5-7 bits (PI). The remaining
+ * 8-bit run represents a soft error and is treated as 0.
+ */
+ switch (up->dcycles & 0xff) {
+
+ case 0x00: /* 0-1 bits (0) */
+ case 0x80:
+ irig_decode(peer, BIT0);
+ break;
+
+ case 0xc0: /* 2-4 bits (1) */
+ case 0xe0:
+ case 0xf0:
+ irig_decode(peer, BIT1);
+ break;
+
+ case 0xf8: /* (5-7 bits (PI) */
+ case 0xfc:
+ case 0xfe:
+ irig_decode(peer, BITP);
+ break;
+
+ default: /* 8 bits (error) */
+ irig_decode(peer, BIT0);
+ up->errflg |= IRIG_ERR_DECODE;
}
}
@@ -797,11 +824,10 @@ irig_base(
/*
* irig_decode - decode the data
*
- * This routine assembles bits into digits, digits into subfields and
- * subfields into the timecode field. Bits can have values of zero, one
- * or position identifier. There are four bits per digit, two digits per
- * subfield and ten subfields per field. The last bit in every subfield
- * and the first bit in the first subfield are position identifiers.
+ * This routine assembles bauds into digits, digits into frames and
+ * frames into the timecode fields. Bits can have values of zero, one
+ * or position identifier. There are four bits per digit, ten digits per
+ * frame and ten frames per second.
*/
static void
irig_decode(
@@ -811,115 +837,59 @@ irig_decode(
{
struct refclockproc *pp;
struct irigunit *up;
-#ifdef IRIG_SUCKS
- int i;
-#endif /* IRIG_SUCKS */
/*
* Local variables
*/
- char syncchar; /* sync character (Spectracom) */
- char sbs[6]; /* binary seconds since 0h */
- char spare[2]; /* mulligan digits */
+ int syncdig; /* sync digit (Spectracom) */
+ char sbs[6 + 1]; /* binary seconds since 0h */
+ char spare[2 + 1]; /* mulligan digits */
+ int temp;
- pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
+ syncdig = 0;
+ pp = peer->procptr;
+ up = pp->unitptr;
/*
- * Assemble subfield bits.
+ * Assemble frame bits.
*/
- up->bits <<= 1;
+ up->bits >>= 1;
if (bit == BIT1) {
- up->bits |= 1;
+ up->bits |= 0x200;
} else if (bit == BITP && up->lastbit == BITP) {
/*
- * Frame sync - two adjacent position identifiers.
- * Monitor the reference timestamp and wiggle the
- * clock, but only if no errors have occurred.
+ * Frame sync - two adjacent position identifiers, which
+ * mark the beginning of the second. The reference time
+ * is the beginning of the second position identifier,
+ * so copy the character timestamp to the reference
+ * timestamp.
*/
- up->bitcnt = 1;
- up->fieldcnt = 0;
- up->lastbit = 0;
- if (up->errflg == 0) {
-#ifdef IRIG_SUCKS
- l_fp ltemp;
-
- /*
- * You really don't wanna know what comes down
- * here. Leave it to say Solaris 2.8 broke the
- * nice clean audio stream, apparently affected
- * by a 5-ms sawtooth jitter. Sundown on
- * Solaris. This leaves a little twilight.
- *
- * The scheme involves differentiation, forward
- * learning and integration. The sawtooth has a
- * period of 11 seconds. The timestamp
- * differences are integrated and subtracted
- * from the signal.
- */
- ltemp = pp->lastrec;
- L_SUB(&ltemp, &pp->lastref);
- if (ltemp.l_f < 0)
- ltemp.l_i = -1;
- else
- ltemp.l_i = 0;
- pp->lastref = pp->lastrec;
- if (!L_ISNEG(&ltemp))
- L_CLR(&up->wigwag);
- else
- L_ADD(&up->wigwag, &ltemp);
- L_SUB(&pp->lastrec, &up->wigwag);
- up->wiggle[up->wp] = ltemp;
-
- /*
- * Bottom fisher. To understand this, you have
- * to know about velocity microphones and AM
- * transmitters. No further explanation is
- * offered, as this is truly a black art.
- */
- up->wigbot[up->wp] = pp->lastrec;
- for (i = 0; i < WIGGLE; i++) {
- if (i != up->wp)
- up->wigbot[i].l_ui++;
- L_SUB(&pp->lastrec, &up->wigbot[i]);
- if (L_ISNEG(&pp->lastrec))
- L_ADD(&pp->lastrec,
- &up->wigbot[i]);
- else
- pp->lastrec = up->wigbot[i];
- }
- up->wp++;
- up->wp %= WIGGLE;
- up->wuggle = pp->lastrec;
- refclock_process(pp);
-#else /* IRIG_SUCKS */
- pp->lastref = pp->lastrec;
- up->wuggle = pp->lastrec;
- refclock_process(pp);
-#endif /* IRIG_SUCKS */
- }
- up->errflg = 0;
+ if (up->frmcnt != 1)
+ up->errflg |= IRIG_ERR_SYNCH;
+ up->frmcnt = 1;
+ up->refstamp = up->prvstamp;
}
- up->bitcnt = (up->bitcnt + 1) % SUBFLD;
- if (up->bitcnt == 0) {
+ up->lastbit = bit;
+ if (up->frmcnt % SUBFLD == 0) {
/*
- * End of subfield. Encode two hexadecimal digits in
- * little-endian timecode field.
+ * End of frame. Encode two hexadecimal digits in
+ * little-endian timecode field. Note frame 1 is shifted
+ * right one bit to account for the marker PI.
*/
- if (up->fieldcnt == 0)
- up->bits <<= 1;
- if (up->xptr < 2)
- up->xptr = 2 * FIELD;
- up->timecode[--up->xptr] = hexchar[(up->bits >> 5) &
- 0xf];
- up->timecode[--up->xptr] = hexchar[up->bits & 0xf];
- up->fieldcnt = (up->fieldcnt + 1) % FIELD;
- if (up->fieldcnt == 0) {
+ temp = up->bits;
+ if (up->frmcnt == 10)
+ temp >>= 1;
+ if (up->xptr >= 2) {
+ up->timecode[--up->xptr] = hexchar[temp & 0xf];
+ up->timecode[--up->xptr] = hexchar[(temp >> 5) &
+ 0xf];
+ }
+ if (up->frmcnt == 0) {
/*
- * End of field. Decode the timecode and wind
+ * End of second. Decode the timecode and wind
* the clock. Not all IRIG generators have the
* year; if so, it is nonzero after year 2000.
* Not all have the hardware status bit; if so,
@@ -931,40 +901,68 @@ irig_decode(
* refclock_process() will reject the timecode
* as invalid.
*/
- up->xptr = 2 * FIELD;
+ up->xptr = 2 * SUBFLD;
if (sscanf((char *)up->timecode,
- "%6s%2d%c%2s%3d%2d%2d%2d", sbs, &pp->year,
- &syncchar, spare, &pp->day, &pp->hour,
+ "%6s%2d%1d%2s%3d%2d%2d%2d", sbs, &pp->year,
+ &syncdig, spare, &pp->day, &pp->hour,
&pp->minute, &pp->second) != 8)
pp->leap = LEAP_NOTINSYNC;
else
pp->leap = LEAP_NOWARNING;
up->second = (up->second + up->decim) % 60;
- if (pp->year > 0)
- pp->year += 2000;
+
+ /*
+ * Raise an alarm if the day field is zero,
+ * which happens when signature control is
+ * enabled and the device has lost
+ * synchronization. Raise an alarm if the year
+ * field is nonzero and the sync indicator is
+ * zero, which happens when a Spectracom radio
+ * has lost synchronization. Raise an alarm if
+ * the expected second does not agree with the
+ * decoded second, which happens with a garbled
+ * IRIG signal. We are very particular.
+ */
+ if (pp->day == 0 || (pp->year != 0 && syncdig ==
+ 0))
+ up->errflg |= IRIG_ERR_SIGERR;
if (pp->second != up->second)
up->errflg |= IRIG_ERR_CHECK;
up->second = pp->second;
- sprintf(pp->a_lastcode,
- "%02x %c %2d %3d %02d:%02d:%02d %4.0f %3d %6.3f %2d %6.1f %6.1f %s",
- up->errflg, syncchar, pp->year, pp->day,
+
+ /*
+ * Wind the clock only if there are no errors
+ * and the time constant has reached the
+ * maximum.
+ */
+ if (up->errflg == 0 && up->tc == MAXTC) {
+ pp->lastref = pp->lastrec;
+ pp->lastrec = up->refstamp;
+ if (!refclock_process(pp))
+ refclock_report(peer,
+ CEVNT_BADTIME);
+ }
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%02x %02d %03d %02d:%02d:%02d %4.0f %3d %6.3f %2d %6.2f %6.1f %s",
+ up->errflg, pp->year, pp->day,
pp->hour, pp->minute, pp->second,
up->maxsignal, up->gain, up->modndx,
up->tc, up->exing * 1e6 / SECOND, up->freq *
- 1e6 / SECOND, ulfptoa(&up->wuggle, 6));
+ 1e6 / SECOND, ulfptoa(&pp->lastrec, 6));
pp->lencode = strlen(pp->a_lastcode);
+ up->errflg = 0;
if (pp->sloppyclockflag & CLK_FLAG4) {
record_clock_stats(&peer->srcadr,
pp->a_lastcode);
#ifdef DEBUG
if (debug)
- printf("irig: %s\n",
+ printf("irig %s\n",
pp->a_lastcode);
#endif /* DEBUG */
}
}
}
- up->lastbit = bit;
+ up->frmcnt = (up->frmcnt + 1) % FIELD;
}
@@ -973,8 +971,7 @@ irig_decode(
*
* This routine sweeps up the timecode updates since the last poll. For
* IRIG-B there should be at least 60 updates; for IRIG-E there should
- * be at least 6. If nothing is heard, a timeout event is declared and
- * any orphaned timecode updates are sent to foster care.
+ * be at least 6. If nothing is heard, a timeout event is declared.
*/
static void
irig_poll(
@@ -983,21 +980,20 @@ irig_poll(
)
{
struct refclockproc *pp;
- struct irigunit *up;
pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
- } else {
- refclock_receive(peer);
+ }
+ refclock_receive(peer);
+ if (!(pp->sloppyclockflag & CLK_FLAG4)) {
record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
if (debug)
- printf("irig: %s\n", pp->a_lastcode);
+ printf("irig %s\n", pp->a_lastcode);
#endif /* DEBUG */
}
pp->polls++;
@@ -1008,11 +1004,10 @@ irig_poll(
/*
* irig_gain - adjust codec gain
*
- * This routine is called once each second. If the signal envelope
- * amplitude is too low, the codec gain is bumped up by four units; if
- * too high, it is bumped down. The decoder is relatively insensitive to
- * amplitude, so this crudity works just fine. The input port is set and
- * the error flag is cleared, mostly to be ornery.
+ * This routine is called at the end of each second. It uses the AGC to
+ * bradket the maximum signal level between MINAMP and MAXAMP to avoid
+ * hunting. The routine also jiggles the input port and selectively
+ * mutes the monitor.
*/
static void
irig_gain(
@@ -1023,26 +1018,26 @@ irig_gain(
struct irigunit *up;
pp = peer->procptr;
- up = (struct irigunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Apparently, the codec uses only the high order bits of the
* gain control field. Thus, it may take awhile for changes to
* wiggle the hardware bits.
*/
- if (up->clipcnt == 0) {
+ if (up->maxsignal < MINAMP) {
up->gain += 4;
if (up->gain > MAXGAIN)
up->gain = MAXGAIN;
- } else if (up->clipcnt > MAXCLP) {
+ } else if (up->maxsignal > MAXAMP) {
up->gain -= 4;
if (up->gain < 0)
up->gain = 0;
}
audio_gain(up->gain, up->mongain, up->port);
- up->clipcnt = 0;
}
+
#else
int refclock_irig_bs;
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_jjy.c b/contrib/ntp/ntpd/refclock_jjy.c
index d1707ce..fef829c 100644
--- a/contrib/ntp/ntpd/refclock_jjy.c
+++ b/contrib/ntp/ntpd/refclock_jjy.c
@@ -3,80 +3,109 @@
*/
/**********************************************************************/
-/* */
-/* Copyright (C) 2001-2004, Takao Abe. All rights reserved. */
-/* */
+/* */
+/* Copyright (C) 2001-2015, Takao Abe. All rights reserved. */
+/* */
/* Permission to use, copy, modify, and distribute this software */
-/* and its documentation for any purpose is hereby granted */
+/* and its documentation for any purpose is hereby granted */
/* without fee, provided that the following conditions are met: */
-/* */
+/* */
/* One retains the entire copyright notice properly, and both the */
/* copyright notice and this license. in the documentation and/or */
-/* other materials provided with the distribution. */
-/* */
+/* other materials provided with the distribution. */
+/* */
/* This software and the name of the author must not be used to */
/* endorse or promote products derived from this software without */
-/* prior written permission. */
-/* */
+/* prior written permission. */
+/* */
/* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */
-/* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */
-/* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */
-/* PARTICULAR PURPOSE. */
+/* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */
+/* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE. */
/* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */
/* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
-/* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
+/* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
/* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */
/* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
-/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */
+/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */
/* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */
/* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-/* */
+/* */
/* This driver is developed in my private time, and is opened as */
-/* voluntary contributions for the NTP. */
+/* voluntary contributions for the NTP. */
/* The manufacturer of the JJY receiver has not participated in */
-/* a development of this driver. */
+/* a development of this driver. */
/* The manufacturer does not warrant anything about this driver, */
-/* and is not liable for anything about this driver. */
-/* */
+/* and is not liable for anything about this driver. */
+/* */
/**********************************************************************/
-/* */
-/* Author Takao Abe */
-/* Email abetakao@bea.hi-ho.ne.jp */
-/* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */
-/* */
+/* */
+/* Author Takao Abe */
+/* Email takao_abe@xurb.jp */
+/* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */
+/* */
+/* The email address abetakao@bea.hi-ho.ne.jp is never read */
+/* from 2010, because a few filtering rule are provided by the */
+/* "hi-ho.ne.jp", and lots of spam mail are reached. */
+/* New email address for supporting the refclock_jjy is */
+/* takao_abe@xurb.jp */
+/* */
/**********************************************************************/
-/* */
-/* History */
-/* */
-/* 2001/07/15 */
-/* [New] Support the Tristate Ltd. JJY receiver */
-/* */
-/* 2001/08/04 */
-/* [Change] Log to clockstats even if bad reply */
-/* [Fix] PRECISION = (-3) (about 100 ms) */
-/* [Add] Support the C-DEX Co.Ltd. JJY receiver */
-/* */
-/* 2001/12/04 */
+/* */
+/* History */
+/* */
+/* 2001/07/15 */
+/* [New] Support the Tristate Ltd. JJY receiver */
+/* */
+/* 2001/08/04 */
+/* [Change] Log to clockstats even if bad reply */
+/* [Fix] PRECISION = (-3) (about 100 ms) */
+/* [Add] Support the C-DEX Co.Ltd. JJY receiver */
+/* */
+/* 2001/12/04 */
/* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */
-/* */
-/* 2002/07/12 */
-/* [Fix] Portability for FreeBSD ( patched by the user ) */
-/* */
-/* 2004/10/31 */
+/* */
+/* 2002/07/12 */
+/* [Fix] Portability for FreeBSD ( patched by the user ) */
+/* */
+/* 2004/10/31 */
/* [Change] Command send timing for the Tristate Ltd. JJY receiver */
-/* JJY-01 ( Firmware version 2.01 ) */
-/* Thanks to Andy Taki for testing under FreeBSD */
-/* */
-/* 2004/11/28 */
-/* [Add] Support the Echo Keisokuki LT-2000 receiver */
-/* */
-/* 2006/11/04 */
-/* [Fix] C-DEX JST2000 */
-/* Thanks to Hideo Kuramatsu for the patch */
-/* */
-/* 2009/04/05 */
-/* [Add] Support the CITIZEN T.I.C JJY-200 receiver */
-/* */
+/* JJY-01 ( Firmware version 2.01 ) */
+/* Thanks to Andy Taki for testing under FreeBSD */
+/* */
+/* 2004/11/28 */
+/* [Add] Support the Echo Keisokuki LT-2000 receiver */
+/* */
+/* 2006/11/04 */
+/* [Fix] C-DEX JST2000 */
+/* Thanks to Hideo Kuramatsu for the patch */
+/* */
+/* 2009/04/05 */
+/* [Add] Support the CITIZEN T.I.C JJY-200 receiver */
+/* */
+/* 2010/11/20 */
+/* [Change] Bug 1618 ( Harmless ) */
+/* Code clean up ( Remove unreachable codes ) in */
+/* jjy_start() */
+/* [Change] Change clockstats format of the Tristate JJY01/02 */
+/* Issues more command to get the status of the receiver */
+/* when "fudge 127.127.40.X flag1 1" is specified */
+/* ( DATE,STIM -> DCST,STUS,DATE,STIM ) */
+/* */
+/* 2011/04/30 */
+/* [Add] Support the Tristate Ltd. TS-GPSclock-01 */
+/* */
+/* 2015/03/29 */
+/* [Add] Support the Telephone JJY */
+/* [Change] Split the start up routine into each JJY receivers. */
+/* Change raw data internal bufferring process */
+/* Change over midnight handling of TS-JJY01 and TS-GPS01 */
+/* to put DATE command between before and after TIME's. */
+/* Unify the writing clockstats of all JJY receivers. */
+/* */
+/* 2015/05/15 */
+/* [Add] Support the SEIKO TIME SYSTEMS TDC-300 */
+/* */
/**********************************************************************/
#ifdef HAVE_CONFIG_H
@@ -99,132 +128,298 @@
#include "ntp_stdlib.h"
/**********************************************************************/
-/* */
-/* The Tristate Ltd. JJY receiver JJY01 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */
-/* time<CR><LF> HH:MM:SS<CR><LF> */
-/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
-/* */
-/* During synchronization after a receiver is turned on, */
-/* It replies the past time from 2000/01/01 00:00:00. */
-/* The function "refclock_process" checks the time and tells */
-/* as an insanity time. */
-/* */
-/**********************************************************************/
-/* */
-/* The C-DEX Co. Ltd. JJY receiver JST2000 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */
-/* */
-/**********************************************************************/
-/* */
-/* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* # Mode 1 (Request&Send) */
-/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
-/* C Mode 2 (Continuous) */
-/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
-/* <SUB> Second signal */
-/* */
-/**********************************************************************/
-/* */
-/* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* 'XX YY/MM/DD W HH:MM:SS<CR> */
-/* XX: OK|NG|ER */
-/* W: 0(Monday)-6(Sunday) */
-/* */
-/**********************************************************************/
/*
* Interface definitions
*/
-#define DEVICE "/dev/jjy%d" /* device name and unit */
-#define SPEED232 B9600 /* uart speed (9600 baud) */
-#define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
-#define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
-#define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
-#define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
-#define REFID "JJY" /* reference ID */
+#define DEVICE "/dev/jjy%d" /* device name and unit */
+#define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
+#define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
+#define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
+#define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
+#define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */
+#define SPEED232_SEIKO_TIMESYS_TDC_300 B2400 /* UART speed (2400 baud) */
+#define SPEED232_TELEPHONE B2400 /* UART speed (4800 baud) */
+#define REFID "JJY" /* reference ID */
#define DESCRIPTION "JJY Receiver"
-#define PRECISION (-3) /* precision assumed (about 100 ms) */
+#define PRECISION (-3) /* precision assumed (about 100 ms) */
/*
* JJY unit control structure
*/
+
+struct jjyRawDataBreak {
+ char *pString ;
+ int iLength ;
+} ;
+
+#define MAX_TIMESTAMP 6
+#define MAX_RAWBUF 100
+#define MAX_LOOPBACK 5
+
struct jjyunit {
- char unittype ; /* UNITTYPE_XXXXXXXXXX */
- short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */
- short version ;
- short linediscipline ; /* LDISC_CLK or LDISC_RAW */
- char bPollFlag ; /* Set by jjy_pool and Reset by jjy_receive */
- int linecount ;
- int lineerror ;
+/* Set up by the function "jjy_start_xxxxxxxx" */
+ char unittype ; /* UNITTYPE_XXXXXXXXXX */
+ short operationmode ; /* Echo Keisokuki LT-2000 */
+ int linespeed ; /* SPEED232_XXXXXXXXXX */
+ short linediscipline ; /* LDISC_CLK or LDISC_RAW */
+/* Receiving data */
+ char bInitError ; /* Set by jjy_start if any error during initialization */
+ short iProcessState ; /* JJY_PROCESS_STATE_XXXXXX */
+ char bReceiveFlag ; /* Set and reset by jjy_receive */
+ char bLineError ; /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
+ short iCommandSeq ; /* 0:Idle Non-Zero:Issued */
+ short iReceiveSeq ;
+ int iLineCount ;
int year, month, day, hour, minute, second, msecond ;
+ int leapsecond ;
+ int iTimestampCount ; /* TS-JJY01, TS-GPS01, Telephone-JJY */
+ int iTimestamp [ MAX_TIMESTAMP ] ; /* Serial second ( 0 - 86399 ) */
/* LDISC_RAW only */
-#define MAX_LINECOUNT 8
-#define MAX_RAWBUF 64
- int lineexpect ;
- int charexpect [ MAX_LINECOUNT ] ;
- int charcount ;
- char rawbuf [ MAX_RAWBUF ] ;
+ char sRawBuf [ MAX_RAWBUF ] ;
+ int iRawBufLen ;
+ struct jjyRawDataBreak *pRawBreak ;
+ char bWaitBreakString ;
+ char sLineBuf [ MAX_RAWBUF ] ;
+ int iLineBufLen ;
+ char sTextBuf [ MAX_RAWBUF ] ;
+ int iTextBufLen ;
+ char bSkipCntrlCharOnly ;
+/* Telephone JJY auto measurement of the loopback delay */
+ char bLoopbackMode ;
+ short iLoopbackCount ;
+ struct timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
+ char bLoopbackTimeout[MAX_LOOPBACK] ;
+ short iLoopbackValidCount ;
+/* Telephone JJY timer */
+ short iTeljjySilentTimer ;
+ short iTeljjyStateTimer ;
+/* Telephone JJY control finite state machine */
+ short iClockState ;
+ short iClockEvent ;
+ short iClockCommandSeq ;
+/* Modem timer */
+ short iModemSilentCount ;
+ short iModemSilentTimer ;
+ short iModemStateTimer ;
+/* Modem control finite state machine */
+ short iModemState ;
+ short iModemEvent ;
+ short iModemCommandSeq ;
};
-#define UNITTYPE_TRISTATE_JJY01 1
-#define UNITTYPE_CDEX_JST2000 2
+#define UNITTYPE_TRISTATE_JJY01 1
+#define UNITTYPE_CDEX_JST2000 2
#define UNITTYPE_ECHOKEISOKUKI_LT2000 3
#define UNITTYPE_CITIZENTIC_JJY200 4
+#define UNITTYPE_TRISTATE_GPSCLOCK01 5
+#define UNITTYPE_SEIKO_TIMESYS_TDC_300 6
+#define UNITTYPE_TELEPHONE 100
+
+#define JJY_PROCESS_STATE_IDLE 0
+#define JJY_PROCESS_STATE_POLL 1
+#define JJY_PROCESS_STATE_RECEIVE 2
+#define JJY_PROCESS_STATE_DONE 3
+#define JJY_PROCESS_STATE_ERROR 4
+
+/**********************************************************************/
/*
+ * Function calling structure
+ *
+ * jjy_start
+ * |-- jjy_start_tristate_jjy01
+ * |-- jjy_start_cdex_jst2000
+ * |-- jjy_start_echokeisokuki_lt2000
+ * |-- jjy_start_citizentic_jjy200
+ * |-- jjy_start_tristate_gpsclock01
+ * |-- jjy_start_seiko_tsys_tdc_300
+ * |-- jjy_start_telephone
+ *
+ * jjy_shutdown
+ *
+ * jjy_poll
+ * |-- jjy_poll_tristate_jjy01
+ * |-- jjy_poll_cdex_jst2000
+ * |-- jjy_poll_echokeisokuki_lt2000
+ * |-- jjy_poll_citizentic_jjy200
+ * |-- jjy_poll_tristate_gpsclock01
+ * |-- jjy_poll_seiko_tsys_tdc_300
+ * |-- jjy_poll_telephone
+ * |-- teljjy_control
+ * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- modem_connect
+ * |-- modem_control
+ * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ *
+ * jjy_receive
+ * |
+ * |-- jjy_receive_tristate_jjy01
+ * | |-- jjy_synctime
+ * |-- jjy_receive_cdex_jst2000
+ * | |-- jjy_synctime
+ * |-- jjy_receive_echokeisokuki_lt2000
+ * | |-- jjy_synctime
+ * |-- jjy_receive_citizentic_jjy200
+ * | |-- jjy_synctime
+ * |-- jjy_receive_tristate_gpsclock01
+ * | |-- jjy_synctime
+ * |-- jjy_receive_seiko_tsys_tdc_300
+ * | |-- jjy_synctime
+ * |-- jjy_receive_telephone
+ * |-- modem_receive
+ * | |-- modem_control
+ * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- teljjy_control
+ * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- jjy_synctime
+ * |-- modem_disconnect
+ * |-- modem_control
+ * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ *
+ * jjy_timer
+ * |-- jjy_timer_telephone
+ * |-- modem_timer
+ * | |-- modem_control
+ * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- teljjy_control
+ * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- modem_disconnect
+ * |-- modem_control
+ * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ *
* Function prototypes
*/
-static int jjy_start P((int, struct peer *));
-static void jjy_shutdown P((int, struct peer *));
-static void jjy_poll P((int, struct peer *));
-static void jjy_poll_tristate_jjy01 P((int, struct peer *));
-static void jjy_poll_cdex_jst2000 P((int, struct peer *));
-static void jjy_poll_echokeisokuki_lt2000 P((int, struct peer *));
-static void jjy_poll_citizentic_jjy200 P((int, struct peer *));
-static void jjy_receive P((struct recvbuf *));
-static int jjy_receive_tristate_jjy01 P((struct recvbuf *));
-static int jjy_receive_cdex_jst2000 P((struct recvbuf *));
-static int jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
-static int jjy_receive_citizentic_jjy200 P((struct recvbuf *));
+
+static int jjy_start (int, struct peer *);
+static int jjy_start_tristate_jjy01 (int, struct peer *, struct jjyunit *);
+static int jjy_start_cdex_jst2000 (int, struct peer *, struct jjyunit *);
+static int jjy_start_echokeisokuki_lt2000 (int, struct peer *, struct jjyunit *);
+static int jjy_start_citizentic_jjy200 (int, struct peer *, struct jjyunit *);
+static int jjy_start_tristate_gpsclock01 (int, struct peer *, struct jjyunit *);
+static int jjy_start_seiko_tsys_tdc_300 (int, struct peer *, struct jjyunit *);
+static int jjy_start_telephone (int, struct peer *, struct jjyunit *);
+
+static void jjy_shutdown (int, struct peer *);
+
+static void jjy_poll (int, struct peer *);
+static void jjy_poll_tristate_jjy01 (int, struct peer *);
+static void jjy_poll_cdex_jst2000 (int, struct peer *);
+static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *);
+static void jjy_poll_citizentic_jjy200 (int, struct peer *);
+static void jjy_poll_tristate_gpsclock01 (int, struct peer *);
+static void jjy_poll_seiko_tsys_tdc_300 (int, struct peer *);
+static void jjy_poll_telephone (int, struct peer *);
+
+static void jjy_receive (struct recvbuf *);
+static int jjy_receive_tristate_jjy01 (struct recvbuf *);
+static int jjy_receive_cdex_jst2000 (struct recvbuf *);
+static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
+static int jjy_receive_citizentic_jjy200 (struct recvbuf *);
+static int jjy_receive_tristate_gpsclock01 (struct recvbuf *);
+static int jjy_receive_seiko_tsys_tdc_300 (struct recvbuf *);
+static int jjy_receive_telephone (struct recvbuf *);
+
+static void jjy_timer (int, struct peer *);
+static void jjy_timer_telephone (int, struct peer *);
+
+static void jjy_synctime ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static void jjy_write_clockstats ( struct peer *, int, const char* ) ;
+
+static int getRawDataBreakPosition ( struct jjyunit *, int ) ;
+
+static short getModemState ( struct jjyunit * ) ;
+static int isModemStateConnect ( short ) ;
+static int isModemStateDisconnect ( short ) ;
+static int isModemStateTimerOn ( struct jjyunit * ) ;
+static void modem_connect ( int, struct peer * ) ;
+static void modem_disconnect ( int, struct peer * ) ;
+static int modem_receive ( struct recvbuf * ) ;
+static void modem_timer ( int, struct peer * );
+
+static void printableString ( char*, int, const char*, int ) ;
/*
* Transfer vector
*/
struct refclock refclock_jjy = {
- jjy_start, /* start up driver */
- jjy_shutdown, /* shutdown driver */
- jjy_poll, /* transmit poll message */
- noentry, /* not used */
- noentry, /* not used */
- noentry, /* not used */
- NOFLAGS /* not used */
+ jjy_start, /* start up driver */
+ jjy_shutdown, /* shutdown driver */
+ jjy_poll, /* transmit poll message */
+ noentry, /* not used */
+ noentry, /* not used */
+ noentry, /* not used */
+ jjy_timer /* 1 second interval timer */
};
/*
* Start up driver return code
*/
#define RC_START_SUCCESS 1
-#define RC_START_ERROR 0
+#define RC_START_ERROR 0
/*
* Local constants definition
*/
-#define MAX_LOGTEXT 64
+#define MAX_LOGTEXT 100
+#ifndef TRUE
+#define TRUE (0==0)
+#endif
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif
+
+/* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
+
+#define JJY_RECEIVE_DONE 0
+#define JJY_RECEIVE_SKIP 1
+#define JJY_RECEIVE_UNPROCESS 2
+#define JJY_RECEIVE_WAIT 3
+#define JJY_RECEIVE_ERROR 4
+
+/* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
+
+#define JJY_CLOCKSTATS_MARK_NONE 0
+#define JJY_CLOCKSTATS_MARK_JJY 1
+#define JJY_CLOCKSTATS_MARK_SEND 2
+#define JJY_CLOCKSTATS_MARK_RECEIVE 3
+#define JJY_CLOCKSTATS_MARK_INFORMATION 4
+#define JJY_CLOCKSTATS_MARK_ATTENTION 5
+#define JJY_CLOCKSTATS_MARK_WARNING 6
+#define JJY_CLOCKSTATS_MARK_ERROR 7
+
+/* Local constants definition for the clockstats messages */
+
+#define JJY_CLOCKSTATS_MESSAGE_ECHOBACK "* Echoback"
+#define JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY "* Ignore replay : [%s]"
+#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2 "* Over midnight : timestamp=%d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3 "* Over midnight : timestamp=%d, %d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE "* Unsure timestamp : %s"
+#define JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY "* Loopback delay : %d.%03d mSec."
+#define JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST "* Delay adjustment : %d mSec. ( valid=%hd/%d )"
+#define JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST "* Delay adjustment : None ( valid=%hd/%d )"
+
+#define JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY "# Unexpected reply : [%s]"
+#define JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH "# Invalid length : length=%d"
+#define JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY "# Too many reply : count=%d"
+#define JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY "# Invalid reply : [%s]"
+#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2 "# Slow reply : timestamp=%d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3 "# Slow reply : timestamp=%d, %d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE "# Invalid date : rc=%d year=%d month=%d day=%d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME "# Invalid time : rc=%d hour=%d minute=%d second=%d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME "# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP "# Invalid leap : leapsecond=[%s]"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS "# Invalid status : status=[%s]"
+
+/* Debug print macro */
+
+#ifdef DEBUG
+#define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen) { if ( debug ) { printf ( "refclock_jjy.c : %s : iProcessState=%d bLineError=%d iCommandSeq=%d iLineCount=%d iTimestampCount=%d iLen=%d\n", sFunc, up->iProcessState, up->bLineError, up->iCommandSeq, up->iLineCount, up->iTimestampCount, iLen ) ; } }
+#else
+#define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
+#endif
/**************************************************************************************************/
/* jjy_start - open the devices and initialize data for processing */
@@ -233,145 +428,123 @@ static int
jjy_start ( int unit, struct peer *peer )
{
- struct jjyunit *up ;
- struct refclockproc *pp ;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+ int rc ;
int fd ;
- char *pDeviceName ;
- short iDiscipline ;
- int iSpeed232 ;
+ char sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ;
- printf ( DEVICE, unit ) ;
- printf ( "\n" ) ;
+ printf( "refclock_jjy.c : jjy_start : %s mode=%d dev=%s unit=%d\n",
+ ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
}
#endif
- /*
- * Open serial port
- */
- if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
- return RC_START_ERROR ;
- }
- sprintf ( pDeviceName, DEVICE, unit ) ;
- /*
- * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
- */
- switch ( peer->ttl ) {
- case 0 :
- case 1 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_TRISTATE_JJY01 ;
- break ;
- case 2 :
- iDiscipline = LDISC_RAW ;
- iSpeed232 = SPEED232_CDEX_JST2000 ;
- break ;
- case 3 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_ECHOKEISOKUKI_LT2000 ;
- break ;
- case 4 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_CITIZENTIC_JJY200 ;
- break ;
- default :
- msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
- ntoa(&peer->srcadr), peer->ttl ) ;
- free ( (void*) pDeviceName ) ;
+ /* Allocate memory for the unit structure */
+ up = emalloc( sizeof(*up) ) ;
+ if ( up == NULL ) {
+ msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
return RC_START_ERROR ;
}
+ memset ( up, 0, sizeof(*up) ) ;
- if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
- free ( (void*) pDeviceName ) ;
- return RC_START_ERROR ;
- }
- free ( (void*) pDeviceName ) ;
+ up->bInitError = FALSE ;
+ up->iProcessState = JJY_PROCESS_STATE_IDLE ;
+ up->bReceiveFlag = FALSE ;
+ up->iCommandSeq = 0 ;
+ up->iLineCount = 0 ;
+ up->iTimestampCount = 0 ;
+ up->bWaitBreakString = FALSE ;
+ up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
+ up->bSkipCntrlCharOnly = TRUE ;
- /*
- * Allocate and initialize unit structure
- */
- if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
- close ( fd ) ;
- return RC_START_ERROR ;
- }
+ /* Set up the device name */
+ snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
- memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
- up->linediscipline = iDiscipline ;
+ snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
/*
* peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
*/
switch ( peer->ttl ) {
case 0 :
- /*
- * The mode 0 is a default clock type at this time.
- * But this will be change to auto-detect mode in the future.
- */
case 1 :
- up->unittype = UNITTYPE_TRISTATE_JJY01 ;
- up->version = 100 ;
- up->lineexpect = 2 ;
- up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
- up->charexpect[1] = 8 ; /* HH:MM:SS<CR><LF> */
+ rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
break ;
case 2 :
- up->unittype = UNITTYPE_CDEX_JST2000 ;
- up->lineexpect = 1 ;
- up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
+ rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
break ;
case 3 :
- up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
- up->operationmode = 2 ; /* Mode 2 : Continuous mode */
- up->lineexpect = 1 ;
- switch ( up->operationmode ) {
- case 1 :
- up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
- break ;
- case 2 :
- up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
- break ;
- }
+ rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
+ break ;
+ case 4 :
+ rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
+ break ;
+ case 5 :
+ rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
+ break ;
+ case 6 :
+ rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
+ break ;
+ case 100 :
+ rc = jjy_start_telephone ( unit, peer, up ) ;
break ;
- case 4 :
- up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
- up->lineexpect = 1 ;
- up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
- break ;
default :
- msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
- ntoa(&peer->srcadr), peer->ttl ) ;
- close ( fd ) ;
+ if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
+ rc = jjy_start_telephone ( unit, peer, up ) ;
+ } else {
+ msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
+ ntoa(&peer->srcadr), peer->ttl ) ;
+ free ( (void*) up ) ;
+ return RC_START_ERROR ;
+ }
+ }
+
+ if ( rc != 0 ) {
+ msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
+ ntoa(&peer->srcadr), peer->ttl ) ;
+ free ( (void*) up ) ;
+ return RC_START_ERROR ;
+ }
+
+ /* Open the device */
+ fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
+ if ( fd <= 0 ) {
free ( (void*) up ) ;
return RC_START_ERROR ;
}
+ /*
+ * Initialize variables
+ */
pp = peer->procptr ;
- pp->unitptr = (caddr_t) up ;
+
+ pp->clockdesc = DESCRIPTION ;
+ pp->unitptr = up ;
pp->io.clock_recv = jjy_receive ;
- pp->io.srcclock = (caddr_t) peer ;
- pp->io.datalen = 0 ;
- pp->io.fd = fd ;
+ pp->io.srcclock = peer ;
+ pp->io.datalen = 0 ;
+ pp->io.fd = fd ;
if ( ! io_addclock(&pp->io) ) {
close ( fd ) ;
- free ( (void*) up ) ;
+ pp->io.fd = -1 ;
+ free ( up ) ;
+ pp->unitptr = NULL ;
return RC_START_ERROR ;
}
+ memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
- /*
- * Initialize miscellaneous variables
- */
peer->precision = PRECISION ;
- peer->burst = 1 ;
- pp->clockdesc = DESCRIPTION ;
- memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
+
+ snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
return RC_START_SUCCESS ;
}
-
/**************************************************************************************************/
/* jjy_shutdown - shutdown the clock */
/**************************************************************************************************/
@@ -379,16 +552,24 @@ static void
jjy_shutdown ( int unit, struct peer *peer )
{
- struct jjyunit *up;
+ struct jjyunit *up;
struct refclockproc *pp;
+ char sLog [ 60 ] ;
+
pp = peer->procptr ;
- up = (struct jjyunit *) pp->unitptr ;
- io_closeclock ( &pp->io ) ;
- free ( (void*) up ) ;
+ up = pp->unitptr ;
+ if ( -1 != pp->io.fd ) {
+ io_closeclock ( &pp->io ) ;
+ }
+ if ( NULL != up ) {
+ free ( up ) ;
+ }
-}
+ snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
+ record_clock_stats( &peer->srcadr, sLog ) ;
+}
/**************************************************************************************************/
/* jjy_receive - receive data from the serial interface */
@@ -396,129 +577,438 @@ jjy_shutdown ( int unit, struct peer *peer )
static void
jjy_receive ( struct recvbuf *rbufp )
{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_receive" ;
+#endif
- struct jjyunit *up ;
+ struct jjyunit *up ;
struct refclockproc *pp ;
- struct peer *peer;
+ struct peer *peer;
l_fp tRecvTimestamp; /* arrival timestamp */
int rc ;
- char sLogText [ MAX_LOGTEXT ] ;
- int i, bCntrlChar ;
+ char *pBuf, sLogText [ MAX_LOGTEXT ] ;
+ int iLen, iCopyLen ;
+ int i, j, iReadRawBuf, iBreakPosition ;
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *) rbufp->recv_srcclock ;
+ peer = rbufp->recv_peer ;
pp = peer->procptr ;
- up = (struct jjyunit *) pp->unitptr ;
+ up = pp->unitptr ;
/*
* Get next input line
*/
- pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
-
if ( up->linediscipline == LDISC_RAW ) {
+
+ pp->lencode = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
+ /* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions (OVERRUN)" */
+ /* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
+ /* To avoid its claim, pass the value BMAX-1. */
+
/*
- * The reply with <STX> and <ETX> may give a blank line
- */
- if ( pp->lencode == 0 && up->charcount == 0 ) return ;
- /*
- * Copy received charaters to temporary buffer
+ * Append received charaters to temporary buffer
*/
- for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
- up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
- }
- while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
- for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
- up->charcount -- ;
+ for ( i = 0 ;
+ i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
+ i ++ , up->iRawBufLen ++ ) {
+ up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
}
- bCntrlChar = 0 ;
- for ( i = 0 ; i < up->charcount ; i ++ ) {
- if ( up->rawbuf[i] < ' ' ) {
- bCntrlChar = 1 ;
- break ;
- }
+ up->sRawBuf[up->iRawBufLen] = 0 ;
+
+
+ } else {
+
+ pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
+
+ }
+#ifdef DEBUG
+ printf( "\nrefclock_jjy.c : %s : Len=%d ", sFunctionName, pp->lencode ) ;
+ for ( i = 0 ; i < pp->lencode ; i ++ ) {
+ if ( iscntrl( pp->a_lastcode[i] & 0x7F ) ) {
+ printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
+ } else {
+ printf( "%c", pp->a_lastcode[i] ) ;
}
- if ( pp->lencode > 0 && up->linecount < up->lineexpect ) {
- if ( bCntrlChar == 0 && up->charcount < up->charexpect[up->linecount] ) return ;
+ }
+ printf( "\n" ) ;
+#endif
+
+ /*
+ * The reply with <CR><LF> gives a blank line
+ */
+
+ if ( pp->lencode == 0 ) return ;
+
+ /*
+ * Receiving data is not expected
+ */
+
+ if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
+ || up->iProcessState == JJY_PROCESS_STATE_DONE
+ || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
+ /* Discard received data */
+ up->iRawBufLen = 0 ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
}
- up->rawbuf[up->charcount] = 0 ;
- } else {
- /*
- * The reply with <CR><LF> gives a blank line
- */
- if ( pp->lencode == 0 ) return ;
+#endif
+ return ;
}
+
/*
* We get down to business
*/
pp->lastrec = tRecvTimestamp ;
- up->linecount ++ ;
+ up->iLineCount ++ ;
+
+ up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
+ up->bReceiveFlag = TRUE ;
+
+ iReadRawBuf = 0 ;
+ iBreakPosition = up->iRawBufLen - 1 ;
+ for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
+
+ if ( up->linediscipline == LDISC_RAW ) {
+
+ if ( up->bWaitBreakString ) {
+ iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
+ if ( iBreakPosition == -1 ) {
+ /* Break string have not come yet */
+ if ( up->iRawBufLen < MAX_RAWBUF - 2
+ || iReadRawBuf > 0 ) {
+ /* Temporary buffer is not full */
+ break ;
+ } else {
+ /* Temporary buffer is full */
+ iBreakPosition = up->iRawBufLen - 1 ;
+ }
+ }
+ } else {
+ iBreakPosition = up->iRawBufLen - 1 ;
+ }
+
+ /* Copy charaters from temporary buffer to process buffer */
+ up->iLineBufLen = up->iTextBufLen = 0 ;
+ for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
+
+ /* Copy all characters */
+ up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
+ up->iLineBufLen ++ ;
+
+ /* Copy printable characters */
+ if ( ! iscntrl( up->sRawBuf[i] ) ) {
+ up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
+ up->iTextBufLen ++ ;
+ }
+
+ }
+ up->sLineBuf[up->iLineBufLen] = 0 ;
+ up->sTextBuf[up->iTextBufLen] = 0 ;
+#ifdef DEBUG
+ printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
+ sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
+#endif
+
+ if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
+#ifdef DEBUG
+ printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
+ sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
+#endif
+ if ( iBreakPosition + 1 < up->iRawBufLen ) {
+ iReadRawBuf = iBreakPosition + 1 ;
+ continue ;
+ } else {
+ break ;
+ }
+
+ }
+
+ }
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sLineBuf ;
+ iLen = up->iLineBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
+ strncpy( sLogText, pBuf, iCopyLen ) ;
+ sLogText[iCopyLen] = 0 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
+
+ switch ( up->unittype ) {
+
+ case UNITTYPE_TRISTATE_JJY01 :
+ rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_CDEX_JST2000 :
+ rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_ECHOKEISOKUKI_LT2000 :
+ rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_CITIZENTIC_JJY200 :
+ rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_TRISTATE_GPSCLOCK01 :
+ rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
+ rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_TELEPHONE :
+ rc = jjy_receive_telephone ( rbufp ) ;
+ break ;
+
+ default :
+ rc = JJY_RECEIVE_ERROR ;
+ break ;
+
+ }
+
+ switch ( rc ) {
+ case JJY_RECEIVE_DONE :
+ case JJY_RECEIVE_SKIP :
+ up->iProcessState = JJY_PROCESS_STATE_DONE ;
+ break ;
+ case JJY_RECEIVE_ERROR :
+ up->iProcessState = JJY_PROCESS_STATE_ERROR ;
+ break ;
+ default :
+ break ;
+ }
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ if ( rc == JJY_RECEIVE_UNPROCESS ) {
+ break ;
+ }
+ iReadRawBuf = iBreakPosition + 1 ;
+ if ( iReadRawBuf >= up->iRawBufLen ) {
+ /* Processed all received data */
+ break ;
+ }
+ }
+
+ if ( up->linediscipline == LDISC_CLK ) {
+ break ;
+ }
+
+ }
+
+ if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
+ for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
+ up->sRawBuf[i] = up->sRawBuf[j] ;
+ }
+ up->iRawBufLen -= iReadRawBuf ;
+ if ( up->iRawBufLen < 0 ) {
+ up->iRawBufLen = 0 ;
+ }
+ }
+
+ up->bReceiveFlag = FALSE ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+getRawDataBreakPosition ( struct jjyunit *up, int iStart )
+{
+
+ int i, j ;
+
+ if ( iStart >= up->iRawBufLen ) {
+#ifdef DEBUG
+ printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
+#endif
+ return -1 ;
+ }
+
+ for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
+
+ for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
+
+ if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
+
+ if ( strncmp( up->sRawBuf + i,
+ up->pRawBreak[j].pString,
+ up->pRawBreak[j].iLength ) == 0 ) {
+
+#ifdef DEBUG
+ printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
+ iStart, i + up->pRawBreak[j].iLength - 1 ) ;
+#endif
+ return i + up->pRawBreak[j].iLength - 1 ;
+
+ }
+ }
+ }
+ }
- if ( up->lineerror != 0 ) return ;
+#ifdef DEBUG
+ printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
+#endif
+ return -1 ;
+
+}
+
+/**************************************************************************************************/
+/* jjy_poll - called by the transmit procedure */
+/**************************************************************************************************/
+static void
+jjy_poll ( int unit, struct peer *peer )
+{
+
+ char sLog [ 40 ], sReach [ 9 ] ;
+
+ struct jjyunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = pp->unitptr ;
+
+ if ( up->bInitError ) {
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
+ return ;
+ }
+
+ if ( pp->polls > 0 && up->iLineCount == 0 ) {
+ /*
+ * No reply for last command
+ */
+ refclock_report ( peer, CEVNT_TIMEOUT ) ;
+ }
+
+ pp->polls ++ ;
+
+ sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
+ sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
+ sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
+ sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
+ sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
+ sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
+ sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
+ sReach[7] = 0 ; /* This poll */
+ sReach[8] = 0 ;
+
+ snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
+
+ up->iProcessState = JJY_PROCESS_STATE_POLL ;
+ up->iCommandSeq = 0 ;
+ up->iReceiveSeq = 0 ;
+ up->iLineCount = 0 ;
+ up->bLineError = FALSE ;
+ up->iRawBufLen = 0 ;
switch ( up->unittype ) {
case UNITTYPE_TRISTATE_JJY01 :
- rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
+ jjy_poll_tristate_jjy01 ( unit, peer ) ;
break ;
case UNITTYPE_CDEX_JST2000 :
- rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
+ jjy_poll_cdex_jst2000 ( unit, peer ) ;
break ;
case UNITTYPE_ECHOKEISOKUKI_LT2000 :
- rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
+ jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
+ break ;
+
+ case UNITTYPE_CITIZENTIC_JJY200 :
+ jjy_poll_citizentic_jjy200 ( unit, peer ) ;
+ break ;
+
+ case UNITTYPE_TRISTATE_GPSCLOCK01 :
+ jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
+ break ;
+
+ case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
+ jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
break ;
- case UNITTYPE_CITIZENTIC_JJY200 :
- rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
- break ;
+ case UNITTYPE_TELEPHONE :
+ jjy_poll_telephone ( unit, peer ) ;
+ break ;
default :
- rc = 0 ;
break ;
}
- if ( up->linediscipline == LDISC_RAW ) {
- if ( up->linecount <= up->lineexpect && up->charcount > up->charexpect[up->linecount-1] ) {
- for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
- up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
- }
- up->charcount -= up->charexpect[up->linecount-1] ;
- } else {
- up->charcount = 0 ;
- }
- }
+}
- if ( rc == 0 ) return ;
+/**************************************************************************************************/
+/* jjy_timer - called at one-second intervals */
+/**************************************************************************************************/
+static void
+jjy_timer ( int unit, struct peer *peer )
+{
- up->bPollFlag = 0 ;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
- if ( up->lineerror != 0 ) {
- refclock_report ( peer, CEVNT_BADREPLY ) ;
- strcpy ( sLogText, "BAD REPLY [" ) ;
- if ( up->linediscipline == LDISC_RAW ) {
- strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
- } else {
- strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "refclock_jjy.c : jjy_timer\n" ) ;
+ }
+#endif
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ if ( up->bReceiveFlag ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
}
- sLogText[MAX_LOGTEXT-1] = 0 ;
- if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
+#endif
return ;
}
+ switch ( up->unittype ) {
+
+ case UNITTYPE_TELEPHONE :
+ jjy_timer_telephone ( unit, peer ) ;
+ break ;
+
+ default :
+ break ;
+
+ }
+
+}
+
+/**************************************************************************************************/
+/* jjy_synctime */
+/**************************************************************************************************/
+static void
+jjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char sLog [ 80 ], cStatus ;
+ const char *pStatus ;
+
pp->year = up->year ;
- pp->day = ymd2yd ( up->year, up->month, up->day ) ;
+ pp->day = ymd2yd( up->year, up->month, up->day ) ;
pp->hour = up->hour ;
pp->minute = up->minute ;
pp->second = up->second ;
- pp->nsec = up->msecond * 1000000;
+ pp->nsec = up->msecond * 1000000 ;
/*
* JST to UTC
@@ -529,631 +1019,3439 @@ jjy_receive ( struct recvbuf *rbufp )
pp->day -- ;
if ( pp->day < 1 ) {
pp->year -- ;
- pp->day = ymd2yd ( pp->year, 12, 31 ) ;
+ pp->day = ymd2yd( pp->year, 12, 31 ) ;
+ }
+ }
+
+ /*
+ * Process the new sample in the median filter and determine the
+ * timecode timestamp.
+ */
+
+ if ( ! refclock_process( pp ) ) {
+ refclock_report( peer, CEVNT_BADTIME ) ;
+ return ;
+ }
+
+ pp->lastref = pp->lastrec ;
+
+ refclock_receive( peer ) ;
+
+ /*
+ * Write into the clockstats file
+ */
+ snprintf ( sLog, sizeof(sLog),
+ "%04d/%02d/%02d %02d:%02d:%02d.%03d JST ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
+ up->year, up->month, up->day,
+ up->hour, up->minute, up->second, up->msecond,
+ pp->year, pp->day, pp->hour, pp->minute, pp->second,
+ (int)(pp->nsec/1000000) ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
+
+ cStatus = ' ' ;
+ pStatus = "" ;
+
+ switch ( peer->status ) {
+ case 0 : cStatus = ' ' ; pStatus = "Reject" ; break ;
+ case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
+ case 2 : cStatus = '.' ; pStatus = "Excess" ; break ;
+ case 3 : cStatus = '-' ; pStatus = "Outlier" ; break ;
+ case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
+ case 5 : cStatus = '#' ; pStatus = "Selected" ; break ;
+ case 6 : cStatus = '*' ; pStatus = "Sys.Peer" ; break ;
+ case 7 : cStatus = 'o' ; pStatus = "PPS.Peer" ; break ;
+ default : break ;
+ }
+
+ snprintf ( sLog, sizeof(sLog),
+ "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
+ peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 1 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* dcst<CR><LF> VALID<CR><LF> or INVALID<CR><LF> */
+/* stus<CR><LF> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
+/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> XXX is the day of the week */
+/* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */
+/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
+/* */
+/*################################################################################################*/
+
+#define TS_JJY01_COMMAND_NUMBER_DATE 1
+#define TS_JJY01_COMMAND_NUMBER_TIME 2
+#define TS_JJY01_COMMAND_NUMBER_STIM 3
+#define TS_JJY01_COMMAND_NUMBER_STUS 4
+#define TS_JJY01_COMMAND_NUMBER_DCST 5
+
+#define TS_JJY01_REPLY_DATE "yyyy/mm/dd www"
+#define TS_JJY01_REPLY_STIM "hh:mm:ss"
+#define TS_JJY01_REPLY_STUS_ADJUSTED "adjusted"
+#define TS_JJY01_REPLY_STUS_UNADJUSTED "unadjusted"
+#define TS_JJY01_REPLY_DCST_VALID "valid"
+#define TS_JJY01_REPLY_DCST_INVALID "invalid"
+
+#define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED 8 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED 10 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */
+
+static struct
+{
+ const char commandNumber ;
+ const char *command ;
+ int commandLength ;
+ int iExpectedReplyLength [ 2 ] ;
+} tristate_jjy01_command_sequence[] =
+{
+ { 0, NULL, 0, { 0, 0 } }, /* Idle */
+ { TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
+ { TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
+ { TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME , TS_JJY01_REPLY_LENGTH_TIME } },
+ { TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE , TS_JJY01_REPLY_LENGTH_DATE } },
+ { TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM , TS_JJY01_REPLY_LENGTH_STIM } },
+ /* End of command */
+ { 0, NULL, 0, { 0, 0 } }
+} ;
+
+/**************************************************************************************************/
+
+static int
+jjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
+
+ up->unittype = UNITTYPE_TRISTATE_JJY01 ;
+ up->linespeed = SPEED232_TRISTATE_JJY01 ;
+ up->linediscipline = LDISC_CLK ;
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
+{
+ struct jjyunit *up ;
+ struct refclockproc *pp ;
+ struct peer *peer;
+
+ char *pBuf, sLog [ 100 ] ;
+ int iLen ;
+ int rc ;
+
+ const char *pCmd ;
+ int iCmdLen ;
+
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
+
+ /* Check expected reply */
+
+ if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence has not been started, or has been completed */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* Check reply length */
+
+ if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
+ && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* Parse reply */
+
+ switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
+
+ case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
+
+ rc = sscanf ( pBuf, "%4d/%2d/%2d",
+ &up->year, &up->month, &up->day ) ;
+
+ if ( rc != 3 || up->year < 2000 || 2099 <= up->year
+ || up->month < 1 || 12 < up->month
+ || up->day < 1 || 31 < up->day ) {
+ /* Invalid date */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
+ rc, up->year, up->month, up->day ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
+
+ break ;
+
+ case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
+ case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
+
+ if ( up->iTimestampCount >= 2 ) {
+ /* Too many time reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
+ up->iTimestampCount ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ rc = sscanf ( pBuf, "%2d:%2d:%2d",
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
+ up->second > 60 ) {
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
+
+ up->iTimestampCount++ ;
+
+ up->msecond = 0 ;
+
+ break ;
+
+ case TS_JJY01_COMMAND_NUMBER_STUS :
+
+ if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
+ TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0
+ || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
+ TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
+ /* Good */
+ } else {
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ break ;
+
+ case TS_JJY01_COMMAND_NUMBER_DCST :
+
+ if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
+ TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
+ || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
+ TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
+ /* Good */
+ } else {
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ break ;
+
+ default : /* Unexpected reply */
+
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+
+ }
+
+ if ( up->iTimestampCount == 2 ) {
+ /* Process date and time */
+
+ if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
+ && up->iTimestamp[0] <= up->iTimestamp[1] ) {
+ /* 3 commands (time,date,stim) was excuted in two seconds */
+ jjy_synctime( peer, pp, up ) ;
+ return JJY_RECEIVE_DONE ;
+ } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
+ /* Over midnight, and date is unsure */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ return JJY_RECEIVE_SKIP ;
+ } else {
+ /* Slow reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ }
+
+ /* Issue next command */
+
+ if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
+ up->iCommandSeq ++ ;
+ }
+
+ if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence completed */
+ return JJY_RECEIVE_DONE ;
+ }
+
+ pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
+ if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
}
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return JJY_RECEIVE_WAIT ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
+{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
+#endif
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ const char *pCmd ;
+ int iCmdLen ;
+
+ pp = peer->procptr;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+ up->iTimestampCount = 0 ;
+
+ if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
+ /* Skip "dcst" and "stus" commands */
+ up->iCommandSeq = 2 ;
+ up->iLineCount = 2 ;
+ }
+
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ",
- up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
- printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
- pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ;
+ printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
+ sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
+ up->iLineCount ) ;
}
#endif
/*
- * Process the new sample in the median filter and determine the
- * timecode timestamp.
+ * Send a first command
*/
- sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
- up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
+ up->iCommandSeq ++ ;
- if ( ! refclock_process ( pp ) ) {
- refclock_report(peer, CEVNT_BADTIME);
- return ;
+ pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
+ if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
}
- pp->lastref = pp->lastrec;
- refclock_receive(peer);
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
}
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 2 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> J is a fixed character */
+/* */
+/*################################################################################################*/
+
+static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
+{
+ { "\x03", 1 }, { NULL, 0 }
+} ;
+
/**************************************************************************************************/
static int
-jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
+jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
{
- static char *sFunctionName = "jjy_receive_tristate_jjy01" ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
+
+ up->unittype = UNITTYPE_CDEX_JST2000 ;
+ up->linespeed = SPEED232_CDEX_JST2000 ;
+ up->linediscipline = LDISC_RAW ;
+
+ up->pRawBreak = cdex_jst2000_raw_break ;
+ up->bWaitBreakString = TRUE ;
+
+ up->bSkipCntrlCharOnly = FALSE ;
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
+{
struct jjyunit *up ;
struct refclockproc *pp ;
- struct peer *peer;
+ struct peer *peer ;
- char *pBuf ;
+ char *pBuf, sLog [ 100 ] ;
int iLen ;
int rc ;
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
+
+ /* Check expected reply */
+
+ if ( up->iCommandSeq != 1 ) {
+ /* Command sequence has not been started, or has been completed */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* Wait until ETX comes */
+
+ if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
+ return JJY_RECEIVE_UNPROCESS ;
+ }
+
+ /* Check reply length */
+
+ if ( iLen != 15 ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* JYYMMDD HHMMSSS */
+
+ rc = sscanf ( pBuf, "J%2d%2d%2d %2d%2d%2d%1d",
+ &up->year, &up->month, &up->day,
+ &up->hour, &up->minute, &up->second,
+ &up->msecond ) ;
+
+ if ( rc != 7 || up->month < 1 || up->month > 12 ||
+ up->day < 1 || up->day > 31 || up->hour > 23 ||
+ up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ up->year += 2000 ;
+ up->msecond *= 100 ;
+
+ jjy_synctime( peer, pp, up ) ;
+
+ return JJY_RECEIVE_DONE ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+ up->iRawBufLen = 0 ;
+ up->iLineBufLen = 0 ;
+ up->iTextBufLen = 0 ;
+
/*
- * Initialize pointers and read the timecode and timestamp
+ * Send "<ENQ>1J<ETX>" command
*/
- peer = (struct peer *) rbufp->recv_srcclock ;
+
+ up->iCommandSeq ++ ;
+
+ if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 3 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* # Mode 1 ( Request & Send ) */
+/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
+/* C Mode 2 ( Continuous ) */
+/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */
+/* <SUB> Second signal */
+/* */
+/*################################################################################################*/
+
+#define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1
+#define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2
+#define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3
+
+#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#"
+#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T"
+#define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C"
+
+/**************************************************************************************************/
+
+static int
+jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
+
+ up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
+ up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
+ up->linediscipline = LDISC_CLK ;
+
+ up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
+{
+
+ struct jjyunit *up ;
+ struct refclockproc *pp ;
+ struct peer *peer;
+
+ char *pBuf, sLog [ 100 ], sErr [ 60 ] ;
+ int iLen ;
+ int rc ;
+ int i, ibcc, ibcc1, ibcc2 ;
+
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
pp = peer->procptr ;
- up = (struct jjyunit *) pp->unitptr ;
+ up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
- pBuf = pp->a_lastcode ;
- iLen = pp->lencode ;
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
}
- switch ( up->linecount ) {
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
+
+ /* Check reply length */
+
+ if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
+ && iLen != 15 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
+ && iLen != 17 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
+ && iLen != 17 ) ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- case 1 : /* YYYY/MM/DD WWW */
+ if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
+ /* YYMMDDWHHMMSS<BCC1><BCC2> */
- if ( iLen != 14 ) {
-#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
- }
-#endif
- up->lineerror = 1 ;
- break ;
+ for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
+ ibcc ^= pBuf[i] ;
}
- rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
- if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
-#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
- }
-#endif
- up->lineerror = 1 ;
- break ;
+
+ ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
+ ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
+ if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
+ snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
+ pBuf[13] & 0xFF, pBuf[14] & 0xFF,
+ ibcc1, ibcc2 ) ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ sErr ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- /*** Start of modification on 2004/10/31 */
- /*
- * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
- * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
- * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
- * so this driver issues the second command "stim" after the reply of the first command "date".
- */
+ }
- /*
- * Send "stim<CR><LF>" or "time<CR><LF>" command
- */
-
+ if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
+ && iLen == 15 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
+ && iLen == 17 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
+ && iLen == 17 ) ) {
+ /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
- if ( up->version >= 100 ) {
-#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ;
- }
-#endif
- if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
- } else {
-#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ;
- }
-#endif
- if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+ rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
+ &up->year, &up->month, &up->day,
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 6 || up->month < 1 || up->month > 12
+ || up->day < 1 || up->day > 31
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ up->year += 2000 ;
+
+ if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
+ || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
+ /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
+
+ up->msecond = 500 ;
+ up->second -- ;
+ if ( up->second < 0 ) {
+ up->second = 59 ;
+ up->minute -- ;
+ if ( up->minute < 0 ) {
+ up->minute = 59 ;
+ up->hour -- ;
+ if ( up->hour < 0 ) {
+ up->hour = 23 ;
+ up->day -- ;
+ if ( up->day < 1 ) {
+ up->month -- ;
+ if ( up->month < 1 ) {
+ up->month = 12 ;
+ up->year -- ;
+ }
+ }
+ }
+ }
}
+
}
- /*** End of modification ***/
- return 0 ;
+ jjy_synctime( peer, pp, up ) ;
+
+
+ }
+
+ if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
+ /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
- case 2 : /* HH:MM:SS */
+ iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
+ if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
+
+ }
+
+ return JJY_RECEIVE_DONE ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ char sCmd[2] ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+
+ /*
+ * Send "T" or "C" command
+ */
+
+ switch ( up->operationmode ) {
+ case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
+ sCmd[0] = 'T' ;
+ break ;
+ case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
+ case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
+ sCmd[0] = 'C' ;
+ break ;
+ }
+ sCmd[1] = 0 ;
+
+ if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 4 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */
+/* */
+/*################################################################################################*/
+
+static int
+jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
+
+ up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
+ up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
+ up->linediscipline = LDISC_CLK ;
+
+ return 0 ;
+
+}
- if ( iLen != 8 ) {
+/**************************************************************************************************/
+
+static int
+jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
+{
+
+ struct jjyunit *up ;
+ struct refclockproc *pp ;
+ struct peer *peer;
+
+ char *pBuf, sLog [ 100 ], sMsg [ 16 ] ;
+ int iLen ;
+ int rc ;
+ char cApostrophe, sStatus[3] ;
+ int iWeekday ;
+
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
+
+ /*
+ * JJY-200 sends a timestamp every second.
+ * So, a timestamp is ignored unless it is right after polled.
+ */
+
+ if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
+ return JJY_RECEIVE_SKIP ;
+ }
+
+ /* Check reply length */
+
+ if ( iLen != 23 ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* 'XX YY/MM/DD W HH:MM:SS<CR> */
+
+ rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
+ &cApostrophe, sStatus,
+ &up->year, &up->month, &up->day, &iWeekday,
+ &up->hour, &up->minute, &up->second ) ;
+ sStatus[2] = 0 ;
+
+ if ( rc != 9 || cApostrophe != '\''
+ || ( strcmp( sStatus, "OK" ) != 0
+ && strcmp( sStatus, "NG" ) != 0
+ && strcmp( sStatus, "ER" ) != 0 )
+ || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || iWeekday > 6
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ } else if ( strcmp( sStatus, "NG" ) == 0
+ || strcmp( sStatus, "ER" ) == 0 ) {
+ /* Timestamp is unsure */
+ snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
+ sMsg ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
+ return JJY_RECEIVE_SKIP ;
+ }
+
+ up->year += 2000 ;
+ up->msecond = 0 ;
+
+ jjy_synctime( peer, pp, up ) ;
+
+ return JJY_RECEIVE_DONE ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The Tristate Ltd. GPS clock TS-GPS01 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 5 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* This clock has NMEA mode and command/respose mode. */
+/* When this jjy driver are used, set to command/respose mode of this clock */
+/* by the onboard switch SW4, and make sure the LED-Y is tured on. */
+/* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */
+/* works with the NMEA mode of this clock. */
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* stus<CR><LF> *R|*G|*U|+U<CR><LF> */
+/* date<CR><LF> YY/MM/DD<CR><LF> */
+/* time<CR><LF> HH:MM:SS<CR><LF> */
+/* */
+/*################################################################################################*/
+
+#define TS_GPS01_COMMAND_NUMBER_DATE 1
+#define TS_GPS01_COMMAND_NUMBER_TIME 2
+#define TS_GPS01_COMMAND_NUMBER_STUS 4
+
+#define TS_GPS01_REPLY_DATE "yyyy/mm/dd"
+#define TS_GPS01_REPLY_TIME "hh:mm:ss"
+#define TS_GPS01_REPLY_STUS_RTC "*R"
+#define TS_GPS01_REPLY_STUS_GPS "*G"
+#define TS_GPS01_REPLY_STUS_UTC "*U"
+#define TS_GPS01_REPLY_STUS_PPS "+U"
+
+#define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */
+#define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
+#define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */
+
+static struct
+{
+ char commandNumber ;
+ const char *command ;
+ int commandLength ;
+ int iExpectedReplyLength ;
+} tristate_gps01_command_sequence[] =
+{
+ { 0, NULL, 0, 0 }, /* Idle */
+ { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
+ { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
+ { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
+ { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
+ /* End of command */
+ { 0, NULL, 0, 0 }
+} ;
+
+/**************************************************************************************************/
+
+static int
+jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
+
+ up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
+ up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
+ up->linediscipline = LDISC_CLK ;
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
+{
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
- }
+ static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ;
#endif
- up->lineerror = 1 ;
- break ;
+
+ struct jjyunit *up ;
+ struct refclockproc *pp ;
+ struct peer *peer;
+
+ char *pBuf, sLog [ 100 ] ;
+ int iLen ;
+ int rc ;
+
+ const char *pCmd ;
+ int iCmdLen ;
+
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
+
+ /* Ignore NMEA data stream */
+
+ if ( iLen > 5
+ && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
+ sFunctionName, pBuf ) ;
}
- rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
- if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+#endif
+ return JJY_RECEIVE_WAIT ;
+ }
+
+ /*
+ * Skip command prompt '$Cmd>' from the TS-GPSclock-01
+ */
+ if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
+ return JJY_RECEIVE_WAIT ;
+ } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
+ pBuf += 5 ;
+ iLen -= 5 ;
+ }
+
+ /*
+ * Ignore NMEA data stream after command prompt
+ */
+ if ( iLen > 5
+ && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
- }
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
+ sFunctionName, pBuf ) ;
+ }
#endif
- up->lineerror = 1 ;
- break ;
+ return JJY_RECEIVE_WAIT ;
+ }
+
+ /* Check expected reply */
+
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence has not been started, or has been completed */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* Check reply length */
+
+ if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* Parse reply */
+
+ switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
+
+ case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
+
+ rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
+
+ if ( rc != 3 || up->year < 2000 || 2099 <= up->year
+ || up->month < 1 || 12 < up->month
+ || up->day < 1 || 31 < up->day ) {
+ /* Invalid date */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
+ rc, up->year, up->month, up->day ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ break ;
+
+ case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
+
+ if ( up->iTimestampCount >= 2 ) {
+ /* Too many time reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
+ up->iTimestampCount ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ rc = sscanf ( pBuf, "%2d:%2d:%2d",
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 3
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
+
+ up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
+
+ up->iTimestampCount++ ;
+
up->msecond = 0 ;
- if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
- /*
- * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
- * But the JJY receiver replies a date and time separately.
- * Just after midnight transitions, we ignore this time.
- */
- return 0 ;
+
+ break ;
+
+ case TS_GPS01_COMMAND_NUMBER_STUS :
+
+ if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
+ || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
+ || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
+ || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
+ /* Good */
+ } else {
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
+
break ;
default : /* Unexpected reply */
- up->lineerror = 1 ;
- break ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+
+ }
+
+ if ( up->iTimestampCount == 2 ) {
+ /* Process date and time */
+
+ if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
+ && up->iTimestamp[0] <= up->iTimestamp[1] ) {
+ /* 3 commands (time,date,stim) was excuted in two seconds */
+ jjy_synctime( peer, pp, up ) ;
+ return JJY_RECEIVE_DONE ;
+ } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
+ /* Over midnight, and date is unsure */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ return JJY_RECEIVE_SKIP ;
+ } else {
+ /* Slow reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ }
+
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence completed */
+ jjy_synctime( peer, pp, up ) ;
+ return JJY_RECEIVE_DONE ;
+ }
+
+ /* Issue next command */
+
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
+ up->iCommandSeq ++ ;
+ }
+
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence completed */
+ up->iProcessState = JJY_PROCESS_STATE_DONE ;
+ return JJY_RECEIVE_DONE ;
+ }
+ pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
+ if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
}
- return 1 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return JJY_RECEIVE_WAIT ;
}
/**************************************************************************************************/
-static int
-jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
+static void
+jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
+#endif
- static char *sFunctionName = "jjy_receive_cdex_jst2000" ;
-
- struct jjyunit *up ;
struct refclockproc *pp ;
- struct peer *peer;
+ struct jjyunit *up ;
- char *pBuf ;
- int iLen ;
- int rc ;
+ const char *pCmd ;
+ int iCmdLen ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->iTimestampCount = 0 ;
+
+ if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
+ /* Skip "stus" command */
+ up->iCommandSeq = 1 ;
+ up->iLineCount = 1 ;
+ }
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
+ sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
+ up->iLineCount ) ;
+ }
+#endif
/*
- * Initialize pointers and read the timecode and timestamp
+ * Send a first command
*/
- peer = (struct peer *) rbufp->recv_srcclock ;
+
+ up->iCommandSeq ++ ;
+
+ pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
+ if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The SEIKO TIME SYSTEMS TDC-300 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 6 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Type Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* Type 1 <STX>HH:MM:SS<ETX> */
+/* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */
+/* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */
+/* <STX><xE5><ETX> 5 to 10 mSec. before second */
+/* */
+/*################################################################################################*/
+
+static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
+{
+ { "\x03", 1 }, { NULL, 0 }
+} ;
+
+/**************************************************************************************************/
+
+static int
+jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
+
+ up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
+ up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
+ up->linediscipline = LDISC_RAW ;
+
+ up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
+ up->bWaitBreakString = TRUE ;
+
+ up->bSkipCntrlCharOnly = FALSE ;
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
+{
+
+ struct peer *peer;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ char *pBuf, sLog [ 100 ] ;
+ int iLen, i ;
+ int rc, iWeekday ;
+ time_t now ;
+ struct tm *pTime ;
+
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
pp = peer->procptr ;
- up = (struct jjyunit *) pp->unitptr ;
+ up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
- pBuf = pp->a_lastcode ;
- iLen = pp->lencode ;
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
+
+ /*
+ * TDC-300 sends a timestamp every second.
+ * So, a timestamp is ignored unless it is right after polled.
+ */
+
+ if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
+ return JJY_RECEIVE_SKIP ;
}
- switch ( up->linecount ) {
+ /* Process timestamp */
- case 1 : /* JYYMMDD HHMMSSS */
+ up->iReceiveSeq ++ ;
- if ( iLen != 15 ) {
-#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
- }
-#endif
- up->lineerror = 1 ;
- break ;
+ switch ( iLen ) {
+
+ case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
+
+ for ( i = 0 ; i < iLen ; i ++ ) {
+ pBuf[i] &= 0x7F ;
}
- rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
- &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
- if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+
+ rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 3
|| up->hour > 23 || up->minute > 59 || up->second > 60 ) {
-#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName,
- rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
- }
-#endif
- up->lineerror = 1 ;
- break ;
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
+ /* Uncertainty date guard */
+ return JJY_RECEIVE_WAIT ;
}
- up->year += 2000 ;
- up->msecond *= 100 ;
+
+ time( &now ) ;
+ pTime = localtime( &now ) ;
+ up->year = pTime->tm_year ;
+ up->month = pTime->tm_mon + 1 ;
+ up->day = pTime->tm_mday ;
+
break ;
- default : /* Unexpected reply */
+ case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
+
+ for ( i = 0 ; i < iLen ; i ++ ) {
+ pBuf[i] &= 0x7F ;
+ }
+
+ rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
+ &up->year, &up->month, &up->day,
+ &up->hour, &up->minute, &up->second, &iWeekday ) ;
+
+ if ( rc != 7
+ || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || iWeekday > 6
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- up->lineerror = 1 ;
break ;
+ case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
+
+ rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
+ &up->year, &up->month, &up->day, &iWeekday,
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 7
+ || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || iWeekday > 6
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ return JJY_RECEIVE_WAIT ;
+
+ case 1 : /* Type 3 : <STX><xE5><ETX> */
+
+ if ( ( *pBuf & 0xFF ) != 0xE5 ) {
+ /* Invalid second signal */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ up->sLineBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ } else if ( up->iReceiveSeq == 1 ) {
+ /* Wait for next timestamp */
+ up->iReceiveSeq -- ;
+ return JJY_RECEIVE_WAIT ;
+ } else if ( up->iReceiveSeq >= 3 ) {
+ /* Unexpected second signal */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ up->sLineBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ break ;
+
+ default : /* Unexpected reply length */
+
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+
}
- return 1 ;
+ up->year += 2000 ;
+ up->msecond = 0 ;
+
+ jjy_synctime( peer, pp, up ) ;
+
+ return JJY_RECEIVE_DONE ;
}
/**************************************************************************************************/
+static void
+jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## Telephone JJY ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 100 to 180 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Prompt Command Response Remarks */
+/* -------------------- -------------------- -------------------- -------------------------- */
+/* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */
+/* > 4DATE<CR> YYYYMMDD<CR> */
+/* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */
+/* > TIME<CR> HHMMSS<CR> 3 times on second */
+/* > BYE<CR> Sayounara messages */
+/* */
+/*################################################################################################*/
+
+static struct jjyRawDataBreak teljjy_raw_break [ ] =
+{
+ { "\r\n", 2 },
+ { "\r" , 1 },
+ { "\n" , 1 },
+ { "Name ? ", 7 },
+ { ">" , 1 },
+ { "+++" , 3 },
+ { NULL , 0 }
+} ;
+
+#define TELJJY_STATE_IDLE 0
+#define TELJJY_STATE_DAILOUT 1
+#define TELJJY_STATE_LOGIN 2
+#define TELJJY_STATE_CONNECT 3
+#define TELJJY_STATE_BYE 4
+
+#define TELJJY_EVENT_NULL 0
+#define TELJJY_EVENT_START 1
+#define TELJJY_EVENT_CONNECT 2
+#define TELJJY_EVENT_DISCONNECT 3
+#define TELJJY_EVENT_COMMAND 4
+#define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */
+#define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */
+
+static void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+
+static int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+
+static int ( *pTeljjyHandler [ ] [ 5 ] ) ( ) =
+{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
+/* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
+/* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
+/* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
+/* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc },
+/* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem },
+/* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
+/* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore },
+/* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore },
+/* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
+/* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
+/* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem }
+} ;
+
+static short iTeljjyNextState [ ] [ 5 ] =
+{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
+/* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE },
+/* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
+/* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE },
+/* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
+/* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }
+} ;
+
+static short iTeljjyPostEvent [ ] [ 5 ] =
+{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
+/* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
+/* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
+/* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
+/* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
+} ;
+
+static short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ;
+static short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ;
+
+#define TELJJY_STAY_CLOCK_STATE 0
+#define TELJJY_CHANGE_CLOCK_STATE 1
+
+/* Command and replay */
+
+#define TELJJY_REPLY_NONE 0
+#define TELJJY_REPLY_4DATE 1
+#define TELJJY_REPLY_TIME 2
+#define TELJJY_REPLY_LEAPSEC 3
+#define TELJJY_REPLY_LOOP 4
+#define TELJJY_REPLY_PROMPT 5
+#define TELJJY_REPLY_LOOPBACK 6
+#define TELJJY_REPLY_COM 7
+
+#define TELJJY_COMMAND_START_SKIP_LOOPBACK 7
+
+static struct
+{
+ const char *command ;
+ int commandLength ;
+ int iEchobackReplyLength ;
+ int iExpectedReplyType ;
+ int iExpectedReplyLength ;
+} teljjy_command_sequence[] =
+{
+ { NULL, 0, 0, 0, 0 }, /* Idle */
+ { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */
+ /* TELJJY_COMMAND_START_SKIP_LOOPBACK */
+ { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
+ { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 },
+ { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
+ { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
+ { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 },
+ /* End of command */
+ { NULL, 0, 0, 0, 0 }
+} ;
+
+#define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */
+
+#ifdef DEBUG
+#define DEBUG_TELJJY_PRINTF(sFunc) { if ( debug ) { printf ( "refclock_jjy.c : %s : iClockState=%d iClockEvent=%d iTeljjySilentTimer=%d iTeljjyStateTimer=%d iClockCommandSeq=%d\n", sFunc, up->iClockState, up->iClockEvent, up->iTeljjySilentTimer, up->iTeljjyStateTimer, up->iClockCommandSeq ) ; } }
+#else
+#define DEBUG_TELJJY_PRINTF(sFunc)
+#endif
+
+/**************************************************************************************************/
+
static int
-jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
+jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
{
- static char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
+ char sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
+ int i, iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
+ int iFirstThreeDigitsCount ;
- struct jjyunit *up ;
- struct refclockproc *pp ;
- struct peer *peer;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
+
+ up->unittype = UNITTYPE_TELEPHONE ;
+ up->linespeed = SPEED232_TELEPHONE ;
+ up->linediscipline = LDISC_RAW ;
+
+ up->pRawBreak = teljjy_raw_break ;
+ up->bWaitBreakString = TRUE ;
+
+ up->bSkipCntrlCharOnly = TRUE ;
+
+ up->iClockState = TELJJY_STATE_IDLE ;
+ up->iClockEvent = TELJJY_EVENT_NULL ;
+
+ /* Check the telephone number */
+
+ if ( sys_phone[0] == NULL ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ if ( sys_phone[1] != NULL ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
+ for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
+ if ( isdigit( *(sys_phone[0]+i) ) ) {
+ if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
+ sFirstThreeDigits[iFirstThreeDigitsCount++] = *(sys_phone[0]+i) ;
+ }
+ iNumberOfDigitsOfPhoneNumber ++ ;
+ } else if ( *(sys_phone[0]+i) == ',' ) {
+ iCommaCount ++ ;
+ if ( iCommaCount > 1 ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+ iFirstThreeDigitsCount = 0 ;
+ iCommaPosition = i ;
+ } else if ( *(sys_phone[0]+i) != '-' ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+ }
+ sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
+
+ if ( iCommaCount == 1 ) {
+ if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+ }
+
+ if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
+ /* Too short or too long */
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
+ || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) {
+ /* Not allowed because of emergency numbers or special service numbers */
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
+
+ if ( peer->minpoll < 8 ) {
+ /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
+ int oldminpoll = peer->minpoll ;
+ peer->minpoll = 8 ;
+ if ( peer->ppoll < peer->minpoll ) {
+ peer->ppoll = peer->minpoll ;
+ }
+ if ( peer->maxpoll < peer->minpoll ) {
+ peer->maxpoll = peer->minpoll ;
+ }
+ snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
+ }
+
+ return 0 ;
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_telephone ( struct recvbuf *rbufp )
+{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_receive_telephone" ;
+#endif
+
+ struct peer *peer;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
char *pBuf ;
- int iLen ;
- int rc ;
- int i, ibcc, ibcc1, ibcc2 ;
+ int iLen ;
+ short iPreviousModemState ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
- peer = (struct peer *) rbufp->recv_srcclock ;
+ peer = rbufp->recv_peer ;
pp = peer->procptr ;
- up = (struct jjyunit *) pp->unitptr ;
+ up = pp->unitptr ;
+
+ DEBUG_TELJJY_PRINTF( sFunctionName ) ;
+
+ if ( up->iClockState == TELJJY_STATE_IDLE
+ || up->iClockState == TELJJY_STATE_DAILOUT
+ || up->iClockState == TELJJY_STATE_BYE ) {
+
+ iPreviousModemState = getModemState( up ) ;
+
+ modem_receive ( rbufp ) ;
+
+ if ( iPreviousModemState != up->iModemState ) {
+ /* Modem state is changed just now. */
+ if ( isModemStateDisconnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ } else if ( isModemStateConnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_CONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+ }
+
+ return JJY_RECEIVE_WAIT ;
+
+ }
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
- pBuf = pp->a_lastcode ;
- iLen = pp->lencode ;
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
}
- switch ( up->linecount ) {
+ up->iTeljjySilentTimer = 0 ;
+ if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; }
+ else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
+ else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; }
+ else { up->iClockEvent = TELJJY_EVENT_DATA ; }
+
+ teljjy_control ( peer, pp, up ) ;
- case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
+ return JJY_RECEIVE_WAIT ;
- if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_telephone ( int unit, struct peer *peer )
+{
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
- }
+ static const char *sFunctionName = "jjy_poll_telephone" ;
#endif
- if ( up->operationmode == 1 ) {
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_TELJJY_PRINTF( sFunctionName ) ;
+
+ if ( up->iClockState == TELJJY_STATE_IDLE ) {
+ up->iRawBufLen = 0 ;
+ up->iLineBufLen = 0 ;
+ up->iTextBufLen = 0 ;
+ }
+
+ up->iClockEvent = TELJJY_EVENT_START ;
+ teljjy_control ( peer, pp, up ) ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_timer_telephone ( int unit, struct peer *peer )
+{
#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
- }
+ static const char *sFunctionName = "jjy_timer_telephone" ;
#endif
- if ( write ( pp->io.fd, "#",1 ) != 1 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+ short iPreviousModemState ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_TELJJY_PRINTF( sFunctionName ) ;
+
+ if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
+ up->iTeljjySilentTimer++ ;
+ if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
+ up->iClockEvent = TELJJY_EVENT_SILENT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+ }
+
+ if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
+ up->iTeljjyStateTimer++ ;
+ if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
+ up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+ }
+
+ if ( isModemStateTimerOn( up ) ) {
+
+ iPreviousModemState = getModemState( up ) ;
+
+ modem_timer ( unit, peer ) ;
+
+ if ( iPreviousModemState != up->iModemState ) {
+ /* Modem state is changed just now. */
+ if ( isModemStateDisconnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ } else if ( isModemStateConnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_CONNECT ;
+ teljjy_control ( peer, pp, up ) ;
}
- up->lineerror = 1 ;
- break ;
}
- if ( up->operationmode == 1 ) {
+ }
+
+}
+
+/**************************************************************************************************/
+
+static void
+teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ int i, rc ;
+ short iPostEvent = TELJJY_EVENT_NULL ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
+
+ rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
- for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
- ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
- ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
- if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
+ if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
+ iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
- }
+ if ( debug ) {
+ printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n",
+ up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
+ }
#endif
- up->lineerror = 1 ;
- break ;
+ up->iTeljjySilentTimer = 0 ;
+ if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
+ /* Telephone JJY state is changing now */
+ up->iTeljjyStateTimer = 0 ;
+ up->bLineError = FALSE ;
+ up->iClockCommandSeq = 0 ;
+ up->iTimestampCount = 0 ;
+ up->iLoopbackCount = 0 ;
+ for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
+ up->bLoopbackTimeout[i] = FALSE ;
}
+ if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
+ /* Telephone JJY state is changing to IDLE just now */
+ up->iProcessState = JJY_PROCESS_STATE_DONE ;
+ }
+ }
+ up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
+
+ }
- }
+ if ( iPostEvent != TELJJY_EVENT_NULL ) {
+ up->iClockEvent = iPostEvent ;
+ teljjy_control ( peer, pp, up ) ;
+ }
- rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
- &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
- if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
- || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ up->iClockEvent = TELJJY_EVENT_NULL ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+teljjy_setDelay ( struct peer *peer, struct jjyunit *up )
+{
+
+ char sLog [ 60 ] ;
+ int milliSecond, microSecond ;
+
+ gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
+
+ up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ;
+ up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
+ if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
+ up->delayTime[up->iLoopbackCount].tv_sec -- ;
+ up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
+ }
+
+ milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
+ microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
+ milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
+
+ snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
+ milliSecond, microSecond ) ;
+
+ if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
+ /* Delay > 700 mS */
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
+ } else {
+ /* Delay <= 700 mS */
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ }
+
+}
+
+/**************************************************************************************************/
+
+static int
+teljjy_getDelay ( struct peer *peer, struct jjyunit *up )
+{
+
+ struct timeval maxTime, minTime, averTime ;
+ int i ;
+ int minIndex = 0, maxIndex = 0, iAverCount = 0 ;
+ int iThresholdSecond, iThresholdMicroSecond ;
+ int iPercent ;
+
+ minTime.tv_sec = minTime.tv_usec = 0 ;
+ maxTime.tv_sec = maxTime.tv_usec = 0 ;
+
+ iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
+ iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
+
+ up->iLoopbackValidCount = 0 ;
+
+ for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
+ if ( up->bLoopbackTimeout[i]
+ || up->delayTime[i].tv_sec > iThresholdSecond
+ || ( up->delayTime[i].tv_sec == iThresholdSecond
+ && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
+ continue ;
+ }
+ if ( up->iLoopbackValidCount == 0 ) {
+ minTime.tv_sec = up->delayTime[i].tv_sec ;
+ minTime.tv_usec = up->delayTime[i].tv_usec ;
+ maxTime.tv_sec = up->delayTime[i].tv_sec ;
+ maxTime.tv_usec = up->delayTime[i].tv_usec ;
+ minIndex = maxIndex = i ;
+ } else if ( minTime.tv_sec > up->delayTime[i].tv_sec
+ || ( minTime.tv_sec == up->delayTime[i].tv_sec
+ && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
+ minTime.tv_sec = up->delayTime[i].tv_sec ;
+ minTime.tv_usec = up->delayTime[i].tv_usec ;
+ minIndex = i ;
+ } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec
+ || ( maxTime.tv_sec == up->delayTime[i].tv_sec
+ && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
+ maxTime.tv_sec = up->delayTime[i].tv_sec ;
+ maxTime.tv_usec = up->delayTime[i].tv_usec ;
+ maxIndex = i ;
+ }
+ up->iLoopbackValidCount ++ ;
+ }
+
+ if ( up->iLoopbackValidCount < 2 ) {
+ return -1 ;
+ }
+
+ averTime.tv_usec = 0;
+
+ for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
+ if ( up->bLoopbackTimeout[i]
+ || up->delayTime[i].tv_sec > iThresholdSecond
+ || ( up->delayTime[i].tv_sec == iThresholdSecond
+ && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
+ continue ;
+ }
+ if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
+ continue ;
+ }
+ if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
+ continue ;
+ }
+ averTime.tv_usec += up->delayTime[i].tv_usec ;
+ iAverCount ++ ;
+ }
+
+ if ( iAverCount == 0 ) {
+ /* This is never happened. */
+ /* Previous for-if-for blocks assure iAverCount > 0. */
+ /* This code avoids a claim by the coverity scan tool. */
+ return -1 ;
+ }
+
+ /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
+
+ iPercent = ( peer->ttl - 100 ) ;
+
+ /* Average delay time in milli second */
+
+ return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
+
+}
+
+/******************************/
+static int
+teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
+
+ modem_connect ( peer->refclkunit, peer ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ int i ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
+
+ up->bLineError = FALSE ;
+ up->iClockCommandSeq = 0 ;
+ up->iTimestampCount = 0 ;
+ up->iLoopbackCount = 0 ;
+ for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
+ up->bLoopbackTimeout[i] = FALSE ;
+ }
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd ;
+ int iCmdLen ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
+
+ /* Send a guest user ID */
+ pCmd = "TJJY\r" ;
+
+ /* Send login ID */
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
+
+ if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
+
+ up->iTeljjySilentTimer = 0 ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ const char *pCmd ;
+ int i, iLen, iNextClockState ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
+
+ if ( up->iClockCommandSeq > 0
+ && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
+ /* Command sequence has been completed */
+ return TELJJY_CHANGE_CLOCK_STATE ;
+ }
+
+ if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
+ /* Skip loopback */
+
+ up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
+
+ } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
+ /* Loopback start */
+
+ up->iLoopbackCount = 0 ;
+ for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
+ up->bLoopbackTimeout[i] = FALSE ;
+ }
+
+ } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
+ && up->iLoopbackCount < MAX_LOOPBACK ) {
+ /* Loopback character comes */
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName,
- rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
- }
+ if ( debug ) {
+ printf( "refclock_jjy.c : teljjy_conn_send : iLoopbackCount=%d\n",
+ up->iLoopbackCount ) ;
+ }
#endif
- up->lineerror = 1 ;
- break ;
+
+ teljjy_setDelay( peer, up ) ;
+
+ up->iLoopbackCount ++ ;
+
+ }
+
+ up->iClockCommandSeq++ ;
+
+ pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
+ iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
+
+ if ( pCmd != NULL ) {
+
+ if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
}
- up->year += 2000 ;
+ if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
+ /* Loopback character and timestamp */
+ gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
+ up->bLoopbackMode = TRUE ;
+ } else {
+ /* Regular command */
+ up->bLoopbackMode = FALSE ;
+ }
- if ( up->operationmode == 2 ) {
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
- /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
- up->msecond = 500 ;
- pp->second -- ;
- if ( pp->second < 0 ) {
- pp->second = 59 ;
- pp->minute -- ;
- if ( pp->minute < 0 ) {
- pp->minute = 59 ;
- pp->hour -- ;
- if ( pp->hour < 0 ) {
- pp->hour = 23 ;
- pp->day -- ;
- if ( pp->day < 1 ) {
- pp->year -- ;
- pp->day = ymd2yd ( pp->year, 12, 31 ) ;
- }
- }
- }
- }
+ if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
+ /* Last command of the command sequence */
+ iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
+ } else {
+ /* More commands to be issued */
+ iNextClockState = TELJJY_STAY_CLOCK_STATE ;
+ }
- /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
-#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
- }
+ } else {
+
+ iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
+
+ }
+
+ return iNextClockState ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pBuf ;
+ int iLen, rc ;
+ char sLog [ 80 ] ;
+ char bAdjustment ;
+
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
+ && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
+ && up->iLoopbackCount < MAX_LOOPBACK ) {
+ /* Loopback */
+
+ teljjy_setDelay( peer, up ) ;
+
+ up->iLoopbackCount ++ ;
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
+ && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
+ /* Maybe echoback */
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
+ /* 4DATE<CR> -> YYYYMMDD<CR> */
+
+ rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
+
+ if ( rc != 3 || up->year < 2000 || 2099 <= up->year
+ || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
+ /* Invalid date */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
+ rc, up->year, up->month, up->day ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ }
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
+ && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
+ /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
+
+ rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
+
+ if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
+ /* Invalid leap second */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ }
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
+ /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
+
+ rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ }
+ up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
+
+ up->iTimestampCount++ ;
+
+ if ( up->iTimestampCount == 6 && ! up->bLineError ) {
+#if DEBUG
+ printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
+ up->bLineError,
+ up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
#endif
- if ( write ( pp->io.fd, "#",1 ) != 1 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+ bAdjustment = TRUE ;
+
+ if ( peer->ttl == 100 ) {
+ /* mode=100 */
+ up->msecond = 0 ;
+ } else {
+ /* mode=101 to 110 */
+ up->msecond = teljjy_getDelay( peer, up ) ;
+ if (up->msecond < 0 ) {
+ up->msecond = 0 ;
+ bAdjustment = FALSE ;
+ }
}
+ if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
+ && up->iTimestamp[2] <= up->iTimestamp[3]
+ && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4]
+ && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) {
+ /* Non over midnight */
+
+ jjy_synctime( peer, pp, up ) ;
+
+ if ( peer->ttl != 100 ) {
+ if ( bAdjustment ) {
+ snprintf( sLog, sizeof(sLog),
+ JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
+ up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ } else {
+ snprintf( sLog, sizeof(sLog),
+ JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
+ up->iLoopbackValidCount, MAX_LOOPBACK ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ }
+ }
+
+ }
}
- break ;
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
+ /* Loopback noise ( Unexpected replay ) */
- default : /* Unexpected reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
+
+ } else {
+
+ up->bLineError = TRUE ;
+
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+
+ }
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ const char *pCmd ;
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
+
+ if ( up->iClockCommandSeq >= 1
+ && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
+ /* Loopback */
#ifdef DEBUG
if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
+ printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
}
#endif
- if ( write ( pp->io.fd, "#",1 ) != 1 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+ if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
+ up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
}
+ up->iTeljjySilentTimer = 0 ;
+ return teljjy_conn_send( peer, pp, up ) ;
+ } else {
+ pCmd = "\r" ;
+ }
- up->lineerror = 1 ;
- break ;
-
+ if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
}
- return 1 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ up->iTeljjySilentTimer = 0 ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
}
+/******************************/
+static int
+teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
+
+ modem_disconnect ( peer->refclkunit, peer ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## Modem control finite state machine ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+
+/* struct jjyunit.iModemState */
+
+#define MODEM_STATE_DISCONNECT 0
+#define MODEM_STATE_INITIALIZE 1
+#define MODEM_STATE_DAILING 2
+#define MODEM_STATE_CONNECT 3
+#define MODEM_STATE_ESCAPE 4
+
+/* struct jjyunit.iModemEvent */
+
+#define MODEM_EVENT_NULL 0
+#define MODEM_EVENT_INITIALIZE 1
+#define MODEM_EVENT_DIALOUT 2
+#define MODEM_EVENT_DISCONNECT 3
+#define MODEM_EVENT_RESP_OK 4
+#define MODEM_EVENT_RESP_CONNECT 5
+#define MODEM_EVENT_RESP_RING 6
+#define MODEM_EVENT_RESP_NO_CARRIER 7
+#define MODEM_EVENT_RESP_ERROR 8
+#define MODEM_EVENT_RESP_CONNECT_X 9
+#define MODEM_EVENT_RESP_NO_DAILTONE 10
+#define MODEM_EVENT_RESP_BUSY 11
+#define MODEM_EVENT_RESP_NO_ANSWER 12
+#define MODEM_EVENT_RESP_UNKNOWN 13
+#define MODEM_EVENT_SILENT 14
+#define MODEM_EVENT_TIMEOUT 15
+
+/* Function prototypes */
+
+static void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+
+static int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+
+static int ( *pModemHandler [ ] [ 5 ] ) ( ) =
+{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
+/* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
+/* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
+/* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
+/* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape },
+/* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
+/* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
+/* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
+/* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
+/* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
+/* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
+/* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc }
+} ;
+
+static short iModemNextState [ ] [ 5 ] =
+{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
+/* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE },
+/* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
+/* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
+} ;
+
+static short iModemPostEvent [ ] [ 5 ] =
+{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
+/* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
+/* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
+} ;
+
+static short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ;
+static short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ;
+
+#define STAY_MODEM_STATE 0
+#define CHANGE_MODEM_STATE 1
+
+#ifdef DEBUG
+#define DEBUG_MODEM_PRINTF(sFunc) { if ( debug ) { printf ( "refclock_jjy.c : %s : iModemState=%d iModemEvent=%d iModemSilentTimer=%d iModemStateTimer=%d\n", sFunc, up->iModemState, up->iModemEvent, up->iModemSilentTimer, up->iModemStateTimer ) ; } }
+#else
+#define DEBUG_MODEM_PRINTF(sFunc)
+#endif
+
+/**************************************************************************************************/
+
+static short
+getModemState ( struct jjyunit *up )
+{
+ return up->iModemState ;
+}
+
/**************************************************************************************************/
static int
-jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
+isModemStateConnect ( short iCheckState )
+{
+ return ( iCheckState == MODEM_STATE_CONNECT ) ;
+}
+
+/**************************************************************************************************/
+
+static int
+isModemStateDisconnect ( short iCheckState )
+{
+ return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
+}
+
+/**************************************************************************************************/
+
+static int
+isModemStateTimerOn ( struct jjyunit *up )
+{
+ return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
+}
+
+/**************************************************************************************************/
+
+static void
+modem_connect ( int unit, struct peer *peer )
+{
+ struct refclockproc *pp;
+ struct jjyunit *up;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_MODEM_PRINTF( "modem_connect" ) ;
+
+ up->iModemEvent = MODEM_EVENT_INITIALIZE ;
+
+ modem_control ( peer, pp, up ) ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+modem_disconnect ( int unit, struct peer *peer )
{
+ struct refclockproc *pp;
+ struct jjyunit *up;
- static char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
- struct jjyunit *up ;
- struct refclockproc *pp ;
- struct peer *peer;
+ DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
- char *pBuf ;
- int iLen ;
- int rc ;
- char cApostrophe, sStatus[3] ;
- int iWeekday ;
+ up->iModemEvent = MODEM_EVENT_DISCONNECT ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
- peer = (struct peer *) rbufp->recv_srcclock ;
- pp = peer->procptr ;
- up = (struct jjyunit *) pp->unitptr ;
+ modem_control ( peer, pp, up ) ;
- if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
- } else {
- pBuf = pp->a_lastcode ;
- iLen = pp->lencode ;
- }
+}
- /*
- * JJY-200 sends a timestamp every second.
- * So, a timestamp is ignored unless it is right after polled.
- */
- if ( ! up->bPollFlag ) return 0 ;
+/**************************************************************************************************/
- switch ( up->linecount ) {
+static int
+modem_receive ( struct recvbuf *rbufp )
+{
- case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
+ struct peer *peer;
+ struct jjyunit *up;
+ struct refclockproc *pp;
+ char *pBuf ;
+ int iLen ;
- if ( iLen != 23 ) {
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
- }
+ static const char *sFunctionName = "modem_receive" ;
#endif
- up->lineerror = 1 ;
- break ;
- }
-
- rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
- &cApostrophe, sStatus,
- &up->year, &up->month, &up->day, &iWeekday, &up->hour, &up->minute, &up->second ) ;
- sStatus[2] = 0 ;
- if ( rc != 9 || cApostrophe != '\'' || strcmp( sStatus, "OK" ) != 0
- || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
- || iWeekday > 6
- || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_MODEM_PRINTF( sFunctionName ) ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; }
+ else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; }
+ else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; }
+ else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; }
+ else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; }
+ else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; }
+ else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
+ else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; }
+ else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; }
+ else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; }
+
#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", sFunctionName,
- rc, cApostrophe, sStatus, up->year, up->month, up->day, iWeekday, up->hour, up->minute, up->second ) ;
- }
+ if ( debug ) {
+ char sResp [ 40 ] ;
+ int iCopyLen ;
+ iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
+ strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
+ sResp[iCopyLen] = 0 ;
+ printf ( "refclock_jjy.c : modem_receive : iLen=%d pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
+ }
#endif
- up->lineerror = 1 ;
- break ;
- }
+ modem_control ( peer, pp, up ) ;
- up->year += 2000 ;
- up->msecond = 0 ;
+ return 0 ;
- break ;
+}
- default : /* Unexpected reply */
+/**************************************************************************************************/
- up->lineerror = 1 ;
- break ;
+static void
+modem_timer ( int unit, struct peer *peer )
+{
- }
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
- return 1 ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_MODEM_PRINTF( "modem_timer" ) ;
+
+ if ( iModemSilentTimeout[up->iModemState] != 0 ) {
+ up->iModemSilentTimer++ ;
+ if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
+ up->iModemEvent = MODEM_EVENT_SILENT ;
+ modem_control ( peer, pp, up ) ;
+ }
+ }
+
+ if ( iModemStateTimeout[up->iModemState] != 0 ) {
+ up->iModemStateTimer++ ;
+ if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
+ up->iModemEvent = MODEM_EVENT_TIMEOUT ;
+ modem_control ( peer, pp, up ) ;
+ }
+ }
}
/**************************************************************************************************/
-/* jjy_poll - called by the transmit procedure */
-/**************************************************************************************************/
+
static void
-jjy_poll ( int unit, struct peer *peer )
+modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
{
- struct jjyunit *up;
- struct refclockproc *pp;
+ int rc ;
+ short iPostEvent = MODEM_EVENT_NULL ;
- pp = peer->procptr;
- up = (struct jjyunit *) pp->unitptr ;
+ DEBUG_MODEM_PRINTF( "modem_control" ) ;
- if ( pp->polls > 0 && up->linecount == 0 ) {
- /*
- * No reply for last command
- */
- refclock_report ( peer, CEVNT_TIMEOUT ) ;
+ rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
+
+ if ( rc == CHANGE_MODEM_STATE ) {
+ iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n",
+ up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
+ }
+#endif
+
+ if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
+ up->iModemSilentCount = 0 ;
+ up->iModemStateTimer = 0 ;
+ up->iModemCommandSeq = 0 ;
+ }
+
+ up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
}
+ if ( iPostEvent != MODEM_EVENT_NULL ) {
+ up->iModemEvent = iPostEvent ;
+ modem_control ( peer, pp, up ) ;
+ }
+
+ up->iModemEvent = MODEM_EVENT_NULL ;
+
+}
+
+/******************************/
+static int
+modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
+
+ up->iModemCommandSeq = 0 ;
+
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
+ printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
}
#endif
- pp->polls ++ ;
+ return modem_init_resp00( peer, pp, up ) ;
+
+}
- up->bPollFlag = 1 ;
- up->linecount = 0 ;
- up->lineerror = 0 ;
- up->charcount = 0 ;
+/******************************/
+static int
+modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
- switch ( up->unittype ) {
-
- case UNITTYPE_TRISTATE_JJY01 :
- jjy_poll_tristate_jjy01 ( unit, peer ) ;
+ char *pCmd, cBuf [ 46 ] ;
+ int iCmdLen ;
+ int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
+ int iNextModemState = STAY_MODEM_STATE ;
+
+ DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
+
+ up->iModemCommandSeq++ ;
+
+ switch ( up->iModemCommandSeq ) {
+
+ case 1 :
+ /* En = Echoback 0:Off 1:On */
+ /* Qn = Result codes 0:On 1:Off */
+ /* Vn = Result codes 0:Numeric 1:Text */
+ pCmd = "ATE0Q0V1\r\n" ;
break ;
- case UNITTYPE_CDEX_JST2000 :
- jjy_poll_cdex_jst2000 ( unit, peer ) ;
+ case 2 :
+ /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */
+ if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
+ /* fudge 127.127.40.n flag3 0 */
+ iSpeakerSwitch = 0 ;
+ } else {
+ /* fudge 127.127.40.n flag3 1 */
+ iSpeakerSwitch = 2 ;
+ }
+
+ /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */
+ if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
+ /* fudge 127.127.40.n flag4 0 */
+ iSpeakerVolume = 1 ;
+ } else {
+ /* fudge 127.127.40.n flag4 1 */
+ iSpeakerVolume = 2 ;
+ }
+
+ pCmd = cBuf ;
+ snprintf( pCmd, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
break ;
- case UNITTYPE_ECHOKEISOKUKI_LT2000 :
- jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
+ case 3 :
+ /* &Kn = Flow control 4:XON/XOFF */
+ pCmd = "AT&K4\r\n" ;
break ;
- case UNITTYPE_CITIZENTIC_JJY200 :
- jjy_poll_citizentic_jjy200 ( unit, peer ) ;
- break ;
+ case 4 :
+ /* +MS = Protocol V22B:1200,2400bpsiV.22bis) */
+ pCmd = "AT+MS=V22B\r\n" ;
+ break ;
+
+ case 5 :
+ /* %Cn = Data compression 0:No data compression */
+ pCmd = "AT%C0\r\n" ;
+ break ;
+
+ case 6 :
+ /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */
+ if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
+ /* fudge 127.127.40.n flag2 0 */
+ iErrorCorrection = 0 ;
+ } else {
+ /* fudge 127.127.40.n flag2 1 */
+ iErrorCorrection = 3 ;
+ }
+
+ pCmd = cBuf ;
+ snprintf( pCmd, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
+ break ;
+
+ case 7 :
+ /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */
+ pCmd = "ATH1\r\n" ;
+ break ;
+
+ case 8 :
+ /* Initialize completion */
+ pCmd = NULL ;
+ iNextModemState = CHANGE_MODEM_STATE ;
+ break ;
default :
+ pCmd = NULL ;
break ;
}
-}
+ if ( pCmd != NULL ) {
-/**************************************************************************************************/
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
-static void
-jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ }
+
+ return iNextModemState ;
+
+}
+
+/******************************/
+static int
+modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
{
- struct refclockproc *pp;
+ DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
- pp = peer->procptr;
+ return modem_init_resp00( peer, pp, up ) ;
- /*
- * Send "date<CR><LF>" command
- */
+}
+
+/******************************/
+static int
+modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+ DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
+ printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
}
#endif
- if ( write ( pp->io.fd, "date\r\n",6 ) != 6 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
+ return CHANGE_MODEM_STATE ;
}
-/**************************************************************************************************/
+/******************************/
+static int
+modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
-static void
-jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
+ DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
{
- struct refclockproc *pp;
+ char sCmd [ 46 ] ;
+ int iCmdLen ;
+ char cToneOrPulse ;
- pp = peer->procptr;
+ DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
- /*
- * Send "<ENQ>1J<ETX>" command
- */
+ /* Tone or Pulse */
+ if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
+ /* fudge 127.127.40.n flag1 0 */
+ cToneOrPulse = 'T' ;
+ } else {
+ /* fudge 127.127.40.n flag1 1 */
+ cToneOrPulse = 'P' ;
+ }
+
+ /* Connect ( Dial number ) */
+ snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
+
+ /* Send command */
+ iCmdLen = strlen( sCmd ) ;
+ if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+ DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
+ printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
}
#endif
- if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+ return modem_conn_escape( peer, pp, up ) ;
+
+}
+
+/******************************/
+static int
+modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
}
+#endif
+
+ modem_esc_disc( peer, pp, up ) ;
+
+ return CHANGE_MODEM_STATE ;
}
-/**************************************************************************************************/
+/******************************/
+static int
+modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
-static void
-jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
+ DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
{
- struct jjyunit *up;
- struct refclockproc *pp;
+ DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
- char sCmd[2] ;
+ return CHANGE_MODEM_STATE ;
- pp = peer->procptr;
- up = (struct jjyunit *) pp->unitptr ;
+}
- /*
- * Send "T" or "C" command
- */
+/******************************/
+static int
+modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
- switch ( up->operationmode ) {
- case 1 : sCmd[0] = 'T' ; break ;
- case 2 : sCmd[0] = 'C' ; break ;
+ DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd ;
+ int iCmdLen ;
+
+ DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
+
+ /* Escape command ( Go to command mode ) */
+ pCmd = "+++" ;
+
+ /* Send command */
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
+
+ up->iModemSilentTimer = 0 ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
+
+ up->iModemSilentCount ++ ;
+
+ if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
+ }
+#endif
+ modem_esc_escape( peer, pp, up ) ;
+ up->iModemSilentTimer = 0 ;
+ return STAY_MODEM_STATE ;
}
- sCmd[1] = 0 ;
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
+ printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
}
#endif
+ return modem_esc_disc( peer, pp, up ) ;
- if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+}
+/******************************/
+static int
+modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd ;
+ int iCmdLen ;
+
+ DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
+
+ /* Disconnect */
+ pCmd = "ATH0\r\n" ;
+
+ /* Send command */
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
}
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return CHANGE_MODEM_STATE ;
+
}
-/**************************************************************************************************/
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## jjy_write_clockstats ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
static void
-jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
+jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
+{
+
+ char sLog [ 100 ] ;
+ char *pMark ;
+ int iMarkLen, iDataLen ;
+
+ switch ( iMark ) {
+ case JJY_CLOCKSTATS_MARK_JJY :
+ pMark = "JJY " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_SEND :
+ pMark = "--> " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_RECEIVE :
+ pMark = "<-- " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_INFORMATION :
+ pMark = "--- " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_ATTENTION :
+ pMark = "=== " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_WARNING :
+ pMark = "-W- " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_ERROR :
+ pMark = "-X- " ;
+ break ;
+ default :
+ pMark = "" ;
+ break ;
+ }
+
+ iDataLen = strlen( pData ) ;
+ iMarkLen = strlen( pMark ) ;
+ strcpy( sLog, pMark ) ; /* Harmless because of enough length */
+ printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
+ }
+#endif
+ record_clock_stats( &peer->srcadr, sLog ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## printableString ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+
+static void
+printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
{
+ const char *printableControlChar[] = {
+ "<NUL>", "<SOH>", "<STX>", "<ETX>",
+ "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
+ "<BS>" , "<HT>" , "<LF>" , "<VT>" ,
+ "<FF>" , "<CR>" , "<SO>" , "<SI>" ,
+ "<DLE>", "<DC1>", "<DC2>", "<DC3>",
+ "<DC4>", "<NAK>", "<SYN>", "<ETB>",
+ "<CAN>", "<EM>" , "<SUB>", "<ESC>",
+ "<FS>" , "<GS>" , "<RS>" , "<US>" ,
+ " " } ;
+
+ size_t i, j, n ;
+ size_t InputLen;
+ size_t OutputLen;
+
+ InputLen = (size_t)iInputLen;
+ OutputLen = (size_t)iOutputLen;
+ for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
+ if ( isprint( (unsigned char)sInput[i] ) ) {
+ n = 1 ;
+ if ( j + 1 >= OutputLen )
+ break ;
+ sOutput[j] = sInput[i] ;
+ } else if ( ( sInput[i] & 0xFF ) <
+ COUNTOF(printableControlChar) ) {
+ n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
+ if ( j + n + 1 >= OutputLen )
+ break ;
+ strlcpy( sOutput + j,
+ printableControlChar[sInput[i] & 0xFF],
+ OutputLen - j ) ;
+ } else {
+ n = 5 ;
+ if ( j + n + 1 >= OutputLen )
+ break ;
+ snprintf( sOutput + j, OutputLen - j, "<x%X>",
+ sInput[i] & 0xFF ) ;
+ }
+ j += n ;
+ }
- /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
+ sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
}
+/**************************************************************************************************/
+
#else
int refclock_jjy_bs ;
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_jupiter.c b/contrib/ntp/ntpd/refclock_jupiter.c
index c10d9fa..02b33df 100644
--- a/contrib/ntp/ntpd/refclock_jupiter.c
+++ b/contrib/ntp/ntpd/refclock_jupiter.c
@@ -52,17 +52,12 @@
# include "ppsapi_timepps.h"
#endif
-#ifdef XNTP_BIG_ENDIAN
+#ifdef WORDS_BIGENDIAN
#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
#else
-#define getshort(s) (s)
-#define putshort(s) (s)
-#endif
-
-/* XXX */
-#ifdef sun
-char *strerror(int);
+#define getshort(s) ((u_short)(s))
+#define putshort(s) ((u_short)(s))
#endif
/*
@@ -135,28 +130,29 @@ struct instance {
/*
* Function prototypes
*/
-static void jupiter_canmsg P((struct instance *, u_int));
-static u_short jupiter_cksum P((u_short *, u_int));
-static int jupiter_config P((struct instance *));
-static void jupiter_debug P((struct peer *, char *, char *, ...))
- __attribute__ ((format (printf, 3, 4)));
-static char * jupiter_parse_t P((struct instance *, u_short *));
-static char * jupiter_parse_gpos P((struct instance *, u_short *));
-static void jupiter_platform P((struct instance *, u_int));
-static void jupiter_poll P((int, struct peer *));
-static void jupiter_control P((int, struct refclockstat *, struct
- refclockstat *, struct peer *));
+static void jupiter_canmsg (struct instance *, u_int);
+static u_short jupiter_cksum (u_short *, u_int);
+static int jupiter_config (struct instance *);
+static void jupiter_debug (struct peer *, const char *,
+ const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+static const char * jupiter_parse_t (struct instance *, u_short *);
+static const char * jupiter_parse_gpos (struct instance *, u_short *);
+static void jupiter_platform (struct instance *, u_int);
+static void jupiter_poll (int, struct peer *);
+static void jupiter_control (int, const struct refclockstat *,
+ struct refclockstat *, struct peer *);
#ifdef HAVE_PPSAPI
-static int jupiter_ppsapi P((struct instance *));
-static int jupiter_pps P((struct instance *));
+static int jupiter_ppsapi (struct instance *);
+static int jupiter_pps (struct instance *);
#endif /* HAVE_PPSAPI */
-static int jupiter_recv P((struct instance *));
-static void jupiter_receive P((struct recvbuf *rbufp));
-static void jupiter_reqmsg P((struct instance *, u_int, u_int));
-static void jupiter_reqonemsg P((struct instance *, u_int));
-static char * jupiter_send P((struct instance *, struct jheader *));
-static void jupiter_shutdown P((int, struct peer *));
-static int jupiter_start P((int, struct peer *));
+static int jupiter_recv (struct instance *);
+static void jupiter_receive (struct recvbuf *rbufp);
+static void jupiter_reqmsg (struct instance *, u_int, u_int);
+static void jupiter_reqonemsg(struct instance *, u_int);
+static char * jupiter_send (struct instance *, struct jheader *);
+static void jupiter_shutdown(int, struct peer *);
+static int jupiter_start (int, struct peer *);
/*
* Transfer vector
@@ -182,39 +178,35 @@ jupiter_start(
{
struct refclockproc *pp;
struct instance *instance;
- int fd = -1;
+ int fd;
char gpsdev[20];
/*
* Open serial port
*/
- (void)sprintf(gpsdev, DEVICE, unit);
+ snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
- if (fd == 0) {
- jupiter_debug(peer, "jupiter_start", "open %s: %s",
- gpsdev, strerror(errno));
+ if (fd <= 0) {
+ jupiter_debug(peer, "jupiter_start", "open %s: %m",
+ gpsdev);
return (0);
}
/* Allocate unit structure */
- if ((instance = (struct instance *)
- emalloc(sizeof(struct instance))) == NULL) {
- (void) close(fd);
- return (0);
- }
- memset((char *)instance, 0, sizeof(struct instance));
+ instance = emalloc_zero(sizeof(*instance));
instance->peer = peer;
pp = peer->procptr;
pp->io.clock_recv = jupiter_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(instance);
return (0);
}
- pp->unitptr = (caddr_t)instance;
+ pp->unitptr = instance;
/*
* Initialize miscellaneous variables
@@ -261,7 +253,7 @@ jupiter_shutdown(int unit, struct peer *peer)
struct refclockproc *pp;
pp = peer->procptr;
- instance = (struct instance *)pp->unitptr;
+ instance = pp->unitptr;
if (!instance)
return;
@@ -272,7 +264,8 @@ jupiter_shutdown(int unit, struct peer *peer)
}
#endif /* HAVE_PPSAPI */
- io_closeclock(&pp->io);
+ if (pp->io.fd != -1)
+ io_closeclock(&pp->io);
free(instance);
}
@@ -282,7 +275,7 @@ jupiter_shutdown(int unit, struct peer *peer)
static int
jupiter_config(struct instance *instance)
{
- jupiter_debug(instance->peer, "jupiter_config", "init receiver");
+ jupiter_debug(instance->peer, __func__, "init receiver");
/*
* Initialize the unit variables
@@ -290,8 +283,7 @@ jupiter_config(struct instance *instance)
instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag;
instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2);
if (instance->moving)
- jupiter_debug(instance->peer, "jupiter_config",
- "mobile platform");
+ jupiter_debug(instance->peer, __func__, "mobile platform");
instance->pollcnt = 2;
instance->polled = 0;
@@ -368,14 +360,14 @@ jupiter_ppsapi(
"refclock_jupiter: time_pps_kcbind failed: %m");
return (0);
}
- pps_enable = 1;
+ hardpps_enable = 1;
}
/* instance->peer->precision = PPS_PRECISION; */
#if DEBUG
if (debug) {
time_pps_getparams(instance->pps_handle, &instance->pps_params);
- jupiter_debug(instance->peer, "refclock_jupiter",
+ jupiter_debug(instance->peer, __func__,
"pps capability 0x%x version %d mode 0x%x kern %d",
capability, instance->pps_params.api_version,
instance->pps_params.mode, instance->hardpps);
@@ -426,7 +418,7 @@ jupiter_pps(struct instance *instance)
return 1;
instance->ts = ts;
- tstmp.l_ui = ts.tv_sec + JAN_1970;
+ tstmp.l_ui = (u_int32)ts.tv_sec + JAN_1970;
dtemp = ts.tv_nsec * FRAC / 1e9;
tstmp.l_uf = (u_int32)dtemp;
instance->peer->procptr->lastrec = tstmp;
@@ -444,7 +436,7 @@ jupiter_poll(int unit, struct peer *peer)
struct refclockproc *pp;
pp = peer->procptr;
- instance = (struct instance *)pp->unitptr;
+ instance = pp->unitptr;
/*
* You don't need to poll this clock. It puts out timecodes
@@ -479,7 +471,7 @@ jupiter_poll(int unit, struct peer *peer)
static void
jupiter_control(
int unit, /* unit (not used) */
- struct refclockstat *in, /* input parameters (not used) */
+ const struct refclockstat *in, /* input parameters (not used) */
struct refclockstat *out, /* output parameters (not used) */
struct peer *peer /* peer structure pointer */
)
@@ -489,7 +481,7 @@ jupiter_control(
u_char sloppyclockflag;
pp = peer->procptr;
- instance = (struct instance *)pp->unitptr;
+ instance = pp->unitptr;
DTOLFP(pp->fudgetime2, &instance->limit);
/* Force positive value. */
@@ -505,8 +497,7 @@ jupiter_control(
instance->sloppyclockflag = pp->sloppyclockflag;
if ((instance->sloppyclockflag & CLK_FLAG2) !=
(sloppyclockflag & CLK_FLAG2)) {
- jupiter_debug(peer,
- "jupiter_control",
+ jupiter_debug(peer, __func__,
"mode switch: reset receiver");
jupiter_config(instance);
return;
@@ -520,10 +511,11 @@ jupiter_control(
static void
jupiter_receive(struct recvbuf *rbufp)
{
- int bpcnt, cc, size, ppsret;
+ size_t bpcnt;
+ int cc, size, ppsret;
time_t last_timecode;
u_int32 laststime;
- char *cp;
+ const char *cp;
u_char *bp;
u_short *sp;
struct jid *ip;
@@ -534,9 +526,9 @@ jupiter_receive(struct recvbuf *rbufp)
l_fp tstamp;
/* Initialize pointers and read the timecode and timestamp */
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- instance = (struct instance *)pp->unitptr;
+ instance = pp->unitptr;
bp = (u_char *)rbufp->recv_buffer;
bpcnt = rbufp->recv_length;
@@ -550,7 +542,7 @@ jupiter_receive(struct recvbuf *rbufp)
instance->ssize += bpcnt;
/* While there's at least a header and we parse an intact message */
- while (instance->ssize > sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) {
+ while (instance->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) {
instance->pollcnt = 2;
tstamp = rbufp->recv_time;
@@ -561,8 +553,8 @@ jupiter_receive(struct recvbuf *rbufp)
case JUPITER_O_PULSE:
if (size != sizeof(struct jpulse)) {
- jupiter_debug(peer,
- "jupiter_receive", "pulse: len %d != %u",
+ jupiter_debug(peer, __func__,
+ "pulse: len %d != %u",
size, (int)sizeof(struct jpulse));
refclock_report(peer, CEVNT_BADREPLY);
break;
@@ -581,7 +573,7 @@ jupiter_receive(struct recvbuf *rbufp)
laststime = instance->stime;
instance->stime = DS2UI(((struct jpulse *)sp)->stime);
if (laststime != 0 && instance->stime - laststime <= 21) {
- jupiter_debug(peer, "jupiter_receive",
+ jupiter_debug(peer, __func__,
"avoided firmware bug (stime %.2f, laststime %.2f)",
(double)instance->stime * 0.01, (double)laststime * 0.01);
break;
@@ -602,8 +594,8 @@ jupiter_receive(struct recvbuf *rbufp)
/* Parse timecode (even when there's no pps) */
last_timecode = instance->timecode;
if ((cp = jupiter_parse_t(instance, sp)) != NULL) {
- jupiter_debug(peer,
- "jupiter_receive", "pulse: %s", cp);
+ jupiter_debug(peer, __func__,
+ "pulse: %s", cp);
break;
}
@@ -616,7 +608,7 @@ jupiter_receive(struct recvbuf *rbufp)
break;
/* Add the new sample to a median filter */
- tstamp.l_ui = JAN_1970 + last_timecode;
+ tstamp.l_ui = JAN_1970 + (u_int32)last_timecode;
tstamp.l_uf = 0;
refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1);
@@ -652,24 +644,24 @@ jupiter_receive(struct recvbuf *rbufp)
case JUPITER_O_GPOS:
if (size != sizeof(struct jgpos)) {
- jupiter_debug(peer,
- "jupiter_receive", "gpos: len %d != %u",
+ jupiter_debug(peer, __func__,
+ "gpos: len %d != %u",
size, (int)sizeof(struct jgpos));
refclock_report(peer, CEVNT_BADREPLY);
break;
}
if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) {
- jupiter_debug(peer,
- "jupiter_receive", "gpos: %s", cp);
+ jupiter_debug(peer, __func__,
+ "gpos: %s", cp);
break;
}
break;
case JUPITER_O_ID:
if (size != sizeof(struct jid)) {
- jupiter_debug(peer,
- "jupiter_receive", "id: len %d != %u",
+ jupiter_debug(peer, __func__,
+ "id: len %d != %u",
size, (int)sizeof(struct jid));
refclock_report(peer, CEVNT_BADREPLY);
break;
@@ -679,8 +671,8 @@ jupiter_receive(struct recvbuf *rbufp)
* just powered instance, it needs to be reconfigured.
*/
ip = (struct jid *)sp;
- jupiter_debug(peer,
- "jupiter_receive", "%s chan ver %s, %s (%s)",
+ jupiter_debug(peer, __func__,
+ "%s chan ver %s, %s (%s)",
ip->chans, ip->vers, ip->date, ip->opts);
msyslog(LOG_DEBUG,
"jupiter_receive: %s chan ver %s, %s (%s)",
@@ -688,8 +680,7 @@ jupiter_receive(struct recvbuf *rbufp)
if (instance->wantid)
instance->wantid = 0;
else {
- jupiter_debug(peer,
- "jupiter_receive", "reset receiver");
+ jupiter_debug(peer, __func__, "reset receiver");
jupiter_config(instance);
/*
* Restore since jupiter_config() just
@@ -700,8 +691,7 @@ jupiter_receive(struct recvbuf *rbufp)
break;
default:
- jupiter_debug(peer,
- "jupiter_receive", "unknown message id %d",
+ jupiter_debug(peer, __func__, "unknown message id %d",
getshort(hp->id));
break;
}
@@ -714,7 +704,7 @@ jupiter_receive(struct recvbuf *rbufp)
}
}
-static char *
+static const char *
jupiter_parse_t(struct instance *instance, u_short *sp)
{
struct tm *tm;
@@ -764,8 +754,8 @@ jupiter_parse_t(struct instance *instance, u_short *sp)
}
else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) {
++instance->gweek;
- jupiter_debug(instance->peer,
- "jupiter_parse_t", "NEW gps week %u", instance->gweek);
+ jupiter_debug(instance->peer, __func__,
+ "NEW gps week %u", instance->gweek);
}
/*
@@ -781,14 +771,14 @@ jupiter_parse_t(struct instance *instance, u_short *sp)
* Then we warped.
*/
if (instance->lastsweek == sweek)
- jupiter_debug(instance->peer,
- "jupiter_parse_t", "gps sweek not incrementing (%d)",
+ jupiter_debug(instance->peer, __func__,
+ "gps sweek not incrementing (%d)",
sweek);
else if (instance->lastsweek != 2 * WEEKSECS &&
instance->lastsweek + 1 != sweek &&
!(sweek == 0 && instance->lastsweek == WEEKSECS - 1))
- jupiter_debug(instance->peer,
- "jupiter_parse_t", "gps sweek jumped (was %d, now %d)",
+ jupiter_debug(instance->peer, __func__,
+ "gps sweek jumped (was %d, now %d)",
instance->lastsweek, sweek);
instance->lastsweek = sweek;
@@ -799,16 +789,16 @@ jupiter_parse_t(struct instance *instance, u_short *sp)
if (last_timecode == 0)
/* XXX debugging */
- jupiter_debug(instance->peer,
- "jupiter_parse_t", "UTC <none> (gweek/sweek %u/%u)",
+ jupiter_debug(instance->peer, __func__,
+ "UTC <none> (gweek/sweek %u/%u)",
instance->gweek, sweek);
else {
/* XXX debugging */
tm = gmtime(&last_timecode);
cp = asctime(tm);
- jupiter_debug(instance->peer,
- "jupiter_parse_t", "UTC %.24s (gweek/sweek %u/%u)",
+ jupiter_debug(instance->peer, __func__,
+ "UTC %.24s (gweek/sweek %u/%u)",
cp, instance->gweek, sweek);
/* Billboard last_timecode (which is now the current time) */
@@ -836,7 +826,7 @@ jupiter_parse_t(struct instance *instance, u_short *sp)
return (NULL);
}
-static char *
+static const char *
jupiter_parse_gpos(struct instance *instance, u_short *sp)
{
struct jgpos *jg;
@@ -868,8 +858,8 @@ jupiter_parse_gpos(struct instance *instance, u_short *sp)
tm = gmtime(&t);
cp = asctime(tm);
- jupiter_debug(instance->peer,
- "jupiter_parse_g", "GPS %.24s (gweek/sweek %u/%u)",
+ jupiter_debug(instance->peer, __func__,
+ "GPS %.24s (gweek/sweek %u/%u)",
cp, instance->gpos_gweek, instance->gpos_sweek);
return (NULL);
}
@@ -877,36 +867,27 @@ jupiter_parse_gpos(struct instance *instance, u_short *sp)
/*
* jupiter_debug - print debug messages
*/
-#if defined(__STDC__) || defined(SYS_WINNT)
-static void
-jupiter_debug(struct peer *peer, char *function, char *fmt, ...)
-#else
static void
-jupiter_debug(peer, function, fmt, va_alist)
- struct peer *peer;
- char *function;
- char *fmt;
-#endif /* __STDC__ */
+jupiter_debug(
+ struct peer * peer,
+ const char * function,
+ const char * fmt,
+ ...
+ )
{
- char buffer[200];
- va_list ap;
+ char buffer[200];
+ va_list ap;
-#if defined(__STDC__) || defined(SYS_WINNT)
va_start(ap, fmt);
-#else
- va_start(ap);
-#endif /* __STDC__ */
/*
* Print debug message to stdout
* In the future, we may want to get get more creative...
*/
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
- record_clock_stats(&(peer->srcadr), buffer);
+ mvsnprintf(buffer, sizeof(buffer), fmt, ap);
+ record_clock_stats(&peer->srcadr, buffer);
#ifdef DEBUG
if (debug) {
- fprintf(stdout, "%s: ", function);
- fprintf(stdout, buffer);
- fprintf(stdout, "\n");
+ printf("%s: %s\n", function, buffer);
fflush(stdout);
}
#endif
@@ -919,7 +900,7 @@ static char *
jupiter_send(struct instance *instance, struct jheader *hp)
{
u_int len, size;
- int cc;
+ ssize_t cc;
u_short *sp;
static char errstr[132];
@@ -934,10 +915,10 @@ jupiter_send(struct instance *instance, struct jheader *hp)
}
if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) {
- (void)sprintf(errstr, "write: %s", strerror(errno));
+ msnprintf(errstr, sizeof(errstr), "write: %m");
return (errstr);
- } else if (cc != size) {
- (void)sprintf(errstr, "short write (%d != %d)", cc, size);
+ } else if (cc != (int)size) {
+ snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size);
return (errstr);
}
return (NULL);
@@ -970,7 +951,7 @@ jupiter_reqmsg(struct instance *instance, u_int id,
rp->trigger = putshort(interval == 0);
rp->interval = putshort(interval);
if ((cp = jupiter_send(instance, hp)) != NULL)
- jupiter_debug(instance->peer, "jupiter_reqmsg", "%u: %s", id, cp);
+ jupiter_debug(instance->peer, __func__, "%u: %s", id, cp);
}
/* Cancel periodic message output */
@@ -989,7 +970,7 @@ jupiter_canmsg(struct instance *instance, u_int id)
hp = &canmsg;
hp->id = putshort(id);
if ((cp = jupiter_send(instance, hp)) != NULL)
- jupiter_debug(instance->peer, "jupiter_canmsg", "%u: %s", id, cp);
+ jupiter_debug(instance->peer, __func__, "%u: %s", id, cp);
}
/* Request a single message output */
@@ -1008,7 +989,7 @@ jupiter_reqonemsg(struct instance *instance, u_int id)
hp = &reqonemsg;
hp->id = putshort(id);
if ((cp = jupiter_send(instance, hp)) != NULL)
- jupiter_debug(instance->peer, "jupiter_reqonemsg", "%u: %s", id, cp);
+ jupiter_debug(instance->peer, __func__, "%u: %s", id, cp);
}
/* Set the platform dynamics */
@@ -1033,7 +1014,7 @@ jupiter_platform(struct instance *instance, u_int platform)
pp = &platmsg.jplat;
pp->platform = putshort(platform);
if ((cp = jupiter_send(instance, hp)) != NULL)
- jupiter_debug(instance->peer, "jupiter_platform", "%u: %s", platform, cp);
+ jupiter_debug(instance->peer, __func__, "%u: %s", platform, cp);
}
/* Checksum "len" shorts */
@@ -1070,13 +1051,14 @@ jupiter_recv(struct instance *instance)
hp = (struct jheader *)sp;
if (getshort(hp->sync) != JUPITER_SYNC) {
/* Wasn't at the front, sync up */
- jupiter_debug(instance->peer, "jupiter_recv", "syncing");
+ jupiter_debug(instance->peer, __func__, "syncing");
bp = (u_char *)sp;
n = size;
while (n >= 2) {
if (bp[0] != (JUPITER_SYNC & 0xff)) {
/*
- jupiter_debug(instance->peer, "{0x%x}", bp[0]);
+ jupiter_debug(instance->peer, __func__,
+ "{0x%x}", bp[0]);
*/
++bp;
--n;
@@ -1085,13 +1067,14 @@ jupiter_recv(struct instance *instance)
if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff))
break;
/*
- jupiter_debug(instance->peer, "{0x%x 0x%x}", bp[0], bp[1]);
+ jupiter_debug(instance->peer, __func__,
+ "{0x%x 0x%x}", bp[0], bp[1]);
*/
bp += 2;
n -= 2;
}
/*
- jupiter_debug(instance->peer, "\n");
+ jupiter_debug(instance->peer, __func__, "\n");
*/
/* Shuffle data to front of input buffer */
if (n > 0)
@@ -1104,7 +1087,7 @@ jupiter_recv(struct instance *instance)
if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) !=
getshort(hp->hsum)) {
- jupiter_debug(instance->peer, "jupiter_recv", "bad header checksum!");
+ jupiter_debug(instance->peer, __func__, "bad header checksum!");
/* This is drastic but checksum errors should be rare */
instance->ssize = 0;
return (0);
@@ -1122,7 +1105,7 @@ jupiter_recv(struct instance *instance)
sp = (u_short *)(hp + 1);
if (jupiter_cksum(sp, len) != getshort(sp[len])) {
jupiter_debug(instance->peer,
- "jupiter_recv", "bad payload checksum!");
+ __func__, "bad payload checksum!");
/* This is drastic but checksum errors should be rare */
instance->ssize = 0;
return (0);
diff --git a/contrib/ntp/ntpd/refclock_leitch.c b/contrib/ntp/ntpd/refclock_leitch.c
index e1ba0c4..69ffdc5 100644
--- a/contrib/ntp/ntpd/refclock_leitch.c
+++ b/contrib/ntp/ntpd/refclock_leitch.c
@@ -6,23 +6,17 @@
# include <config.h>
#endif
-#if defined(REFCLOCK) && defined(CLOCK_LEITCH)
+#include "ntp_types.h"
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
+#if defined(REFCLOCK) && defined(CLOCK_LEITCH)
#include <stdio.h>
#include <ctype.h>
-#ifdef STREAM
-#include <stropts.h>
-#if defined(LEITCHCLK)
-#include <sys/clkdefs.h>
-#endif /* LEITCHCLK */
-#endif /* STREAM */
-
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "timevalops.h"
#include "ntp_stdlib.h"
@@ -43,6 +37,7 @@
* STATUS: G (good), D (diag fail), T (time not provided) or
* P (last phone update failed)
*/
+#define PRECISION (-20) /* 1x10-8 */
#define MAXUNITS 1 /* max number of LEITCH units */
#define LEITCHREFID "ATOM" /* reference id */
#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"
@@ -96,20 +91,20 @@ struct leitchunit {
/*
* Function prototypes
*/
-static void leitch_init P((void));
-static int leitch_start P((int, struct peer *));
-static void leitch_shutdown P((int, struct peer *));
-static void leitch_poll P((int, struct peer *));
-static void leitch_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
+static void leitch_init (void);
+static int leitch_start (int, struct peer *);
+static void leitch_shutdown (int, struct peer *);
+static void leitch_poll (int, struct peer *);
+static void leitch_control (int, const struct refclockstat *, struct refclockstat *, struct peer *);
#define leitch_buginfo noentry
-static void leitch_receive P((struct recvbuf *));
-static void leitch_process P((struct leitchunit *));
+static void leitch_receive (struct recvbuf *);
+static void leitch_process (struct leitchunit *);
#if 0
-static void leitch_timeout P((struct peer *));
+static void leitch_timeout (struct peer *);
#endif
-static int leitch_get_date P((struct recvbuf *, struct leitchunit *));
-static int leitch_get_time P((struct recvbuf *, struct leitchunit *, int));
-static int days_per_year P((int));
+static int leitch_get_date (struct recvbuf *, struct leitchunit *);
+static int leitch_get_time (struct recvbuf *, struct leitchunit *, int);
+static int days_per_year (int);
static struct leitchunit leitchunits[MAXUNITS];
static u_char unitinuse[MAXUNITS];
@@ -149,9 +144,17 @@ leitch_shutdown(
struct peer *peer
)
{
+ struct leitchunit *leitch;
+
+ if (unit >= MAXUNITS) {
+ return;
+ }
+ leitch = &leitchunits[unit];
+ if (-1 != leitch->leitchio.fd)
+ io_closeclock(&leitch->leitchio);
#ifdef DEBUG
if (debug)
- fprintf(stderr, "leitch_shutdown()\n");
+ fprintf(stderr, "leitch_shutdown()\n");
#endif
}
@@ -192,7 +195,7 @@ leitch_poll(
static void
leitch_control(
int unit,
- struct refclockstat *in,
+ const struct refclockstat *in,
struct refclockstat *out,
struct peer *passed_peer
)
@@ -257,7 +260,7 @@ leitch_start(
/*
* Open serial port.
*/
- (void) sprintf(leitchdev, LEITCH232, unit);
+ snprintf(leitchdev, sizeof(leitchdev), LEITCH232, unit);
fd232 = open(leitchdev, O_RDWR, 0777);
if (fd232 == -1) {
msyslog(LOG_ERR,
@@ -266,7 +269,7 @@ leitch_start(
}
leitch = &leitchunits[unit];
- memset((char*)leitch, 0, sizeof(*leitch));
+ memset(leitch, 0, sizeof(*leitch));
#if defined(HAVE_SYSV_TTYS)
/*
@@ -294,9 +297,6 @@ leitch_start(
#if defined(HAVE_TERMIOS)
/*
* POSIX serial line parameters (termios interface)
- *
- * The LEITCHCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module.
*/
{ struct termios ttyb, *ttyp;
@@ -323,27 +323,12 @@ leitch_start(
}
}
#endif /* HAVE_TERMIOS */
-#ifdef STREAM
-#if defined(LEITCHCLK)
- if (ioctl(fd232, I_PUSH, "clk") < 0)
- msyslog(LOG_ERR,
- "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev);
- if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
- msyslog(LOG_ERR,
- "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev);
-#endif /* LEITCHCLK */
-#endif /* STREAM */
#if defined(HAVE_BSD_TTYS)
/*
* 4.3bsd serial line parameters (sgttyb interface)
- *
- * The LEITCHCLK option provides timestamping at the driver level.
- * It requires the tty_clk line discipline and 4.3bsd or later.
*/
- { struct sgttyb ttyb;
-#if defined(LEITCHCLK)
- int ldisc = CLKLDISC;
-#endif /* LEITCHCLK */
+ {
+ struct sgttyb ttyb;
if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
msyslog(LOG_ERR,
@@ -351,25 +336,13 @@ leitch_start(
goto screwed;
}
ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
-#if defined(LEITCHCLK)
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
-#else
ttyb.sg_erase = ttyb.sg_kill = '\0';
ttyb.sg_flags = EVENP|ODDP|CRMOD;
-#endif /* LEITCHCLK */
if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
msyslog(LOG_ERR,
"leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);
goto screwed;
}
-#if defined(LEITCHCLK)
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- msyslog(LOG_ERR,
- "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev);
- goto screwed;
- }
-#endif /* LEITCHCLK */
}
#endif /* HAVE_BSD_TTYS */
@@ -382,10 +355,11 @@ leitch_start(
leitch->fudge1 = 15; /* 15ms */
leitch->leitchio.clock_recv = leitch_receive;
- leitch->leitchio.srcclock = (caddr_t) leitch;
+ leitch->leitchio.srcclock = peer;
leitch->leitchio.datalen = 0;
leitch->leitchio.fd = fd232;
if (!io_addclock(&leitch->leitchio)) {
+ leitch->leitchio.fd = -1;
goto screwed;
}
@@ -393,7 +367,7 @@ leitch_start(
* All done. Initialize a few random peer variables, then
* return success.
*/
- peer->precision = 0;
+ peer->precision = PRECISION;
peer->stratum = stratumtouse[unit];
peer->refid = refid[unit];
unitinuse[unit] = 1;
@@ -416,7 +390,7 @@ leitch_receive(
struct recvbuf *rbufp
)
{
- struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock;
+ struct leitchunit *leitch = rbufp->recv_peer->procptr->unitptr;
#ifdef DEBUG
if (debug)
@@ -622,5 +596,5 @@ leitch_get_time(
}
#else
-int refclock_leitch_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_local.c b/contrib/ntp/ntpd/refclock_local.c
index dc6f1ae..d1b2871 100644
--- a/contrib/ntp/ntpd/refclock_local.c
+++ b/contrib/ntp/ntpd/refclock_local.c
@@ -24,19 +24,20 @@
/*
* This is a hack to allow a machine to use its own system clock as a
* reference clock, i.e., to free-run using no outside clock discipline
- * source. This is useful if you want to use NTP in an isolated
- * environment with no radio clock or NIST modem available. Pick a
- * machine that you figure has a good clock oscillator and configure it
- * with this driver. Set the clock using the best means available, like
+ * source. Note that the clock selection algorithm will not select this
+ * driver unless all other sources of synchronization have been lost.
+ * This is useful if you want to use NTP in an isolated environment
+ * with no radio clock or NIST modem available. Pick a machine that you
+ * figure has a good clock oscillator and configure it with this
+ * driver. Set the clock using the best means available, like
* eyeball-and-wristwatch. Then, point all the other machines at this
* one or use broadcast (not multicast) mode to distribute time.
*
* Another application for this driver is if you want to use a
* particular server's clock as the clock of last resort when all other
* normal synchronization sources have gone away. This is especially
- * useful if that server has an ovenized oscillator. For this you would
- * configure this driver at a higher stratum (say 5) to prevent the
- * server's stratum from falling below that.
+ * useful if that server has an ovenized oscillator. However, the
+ * preferred was to do this is using orphan mode. See the documentation.
*
* A third application for this driver is when an external discipline
* source is available, such as the NIST "lockclock" program, which
@@ -52,42 +53,17 @@
* oscillator. In extreme cases, this can cause clients to exceed the
* 128-ms slew window and drop off the NTP subnet.
*
- * THis driver includes provisions to telegraph synchronization state
- * and related variables by means of kernel variables with specially
- * modified kernels. This is done using the ntp_adjtime() syscall.
- * In the cases where another protocol or device synchronizes the local
- * host, the data given to the kernel can be slurped up by this driver
- * and distributed to clients by ordinary NTP messaging.
- *
- * In the default mode the behavior of the clock selection algorithm is
- * modified when this driver is in use. The algorithm is designed so
- * that this driver will never be selected unless no other discipline
- * source is available. This can be overriden with the prefer keyword of
- * the server configuration command, in which case only this driver will
- * be selected for synchronization and all other discipline sources will
- * be ignored. This behavior is intended for use when an external
- * discipline source controls the system clock.
- *
* Fudge Factors
*
- * The stratum for this driver set at 5 by default, but it can be
- * changed by the fudge command and/or the ntpdc utility. The reference
- * ID is 127.0.0.1 by default, but can be changed using the same mechanism.
- * *NEVER* configure this driver to operate at a stratum which might
- * possibly disrupt a client with access to a bona fide primary server,
- * unless the local clock oscillator is reliably disciplined by another
- * source. *NEVER NEVER* configure a server which might devolve to an
- * undisciplined local clock to use multicast mode. Always remember that
- * an improperly configured local clock driver let loose in the Internet
- * can cause very serious disruption. This is why most of us who care
- * about good time use cryptographic authentication.
+ * If fudge flag1 is lit, the leap second bit is set in the peer
+ * status word. It should be set early in the day of a leap second
+ * event and set dark on the day after the event.
*
- * This driver provides a mechanism to trim the local clock in both time
- * and frequency, as well as a way to manipulate the leap bits. The
- * fudge time1 parameter adjusts the time, in seconds, and the fudge
- * time2 parameter adjusts the frequency, in ppm. The fudge time1
- * parameter is additive; that is, it adds an increment to the current
- * time. The fudge time2 parameter directly sets the frequency.
+ * Note the fudge time1 and time2 have been deprecated. The fudge time1
+ * was intended to apply a bias offset. This can be done using the Unix
+ * date command. The fudge time2 was intended to apply a bias frequency.
+ * This can be done using the frequency file and/or the freq
+ * configuration command.
*/
/*
* Local interface definitions
@@ -107,20 +83,11 @@ extern u_long current_time;
*/
extern s_char sys_precision;
-#ifdef KERNEL_PLL
-/*
- * Imported from ntp_loopfilter
- */
-extern int pll_control; /* kernel pll control */
-extern int kern_enable; /* kernel pll enabled */
-extern int ext_enable; /* external clock enable */
-#endif /* KERNEL_PLL */
-
/*
* Function prototypes
*/
-static int local_start P((int, struct peer *));
-static void local_poll P((int, struct peer *));
+static int local_start (int, struct peer *);
+static void local_poll (int, struct peer *);
/*
* Local variables
@@ -191,6 +158,12 @@ local_poll(
#endif /* KERNEL_PLL LOCKCLOCK */
struct refclockproc *pp;
+ /*
+ * Do no evil unless the house is dark or lit with our own lamp.
+ */
+ if (!(sys_peer == NULL || sys_peer == peer))
+ return;
+
#if defined(VMS) && defined(VMS_LOCALUNIT)
if (unit == VMS_LOCALUNIT) {
extern void vms_local_poll(struct peer *);
@@ -199,6 +172,7 @@ local_poll(
return;
}
#endif /* VMS && VMS_LOCALUNIT */
+
pp = peer->procptr;
pp->polls++;
@@ -209,12 +183,8 @@ local_poll(
* time1 (s) and a continuous frequency adjustment using fudge
* time 2 (ppm).
*/
- get_systime(&pp->lastrec);
- pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time -
- poll_time);
poll_time = current_time;
- refclock_process_offset(pp, pp->lastrec, pp->lastrec,
- pp->fudgetime1);
+ refclock_process_offset(pp, pp->lastrec, pp->lastrec, 0);
/*
* If another process is disciplining the system clock, we set
@@ -245,13 +215,15 @@ local_poll(
pp->disp = 0;
pp->jitter = 0;
#else /* KERNEL_PLL LOCKCLOCK */
- pp->leap = LEAP_NOWARNING;
+ if (pp->sloppyclockflag & CLK_FLAG1)
+ pp->leap = LEAP_ADDSECOND;
+ else
+ pp->leap = LEAP_NOWARNING;
pp->disp = DISPERSION;
pp->jitter = 0;
#endif /* KERNEL_PLL LOCKCLOCK */
pp->lastref = pp->lastrec;
refclock_receive(peer);
- pp->fudgetime1 = 0;
}
#else
int refclock_local_bs;
diff --git a/contrib/ntp/ntpd/refclock_msfees.c b/contrib/ntp/ntpd/refclock_msfees.c
index 98034b5..8399c96 100644
--- a/contrib/ntp/ntpd/refclock_msfees.c
+++ b/contrib/ntp/ntpd/refclock_msfees.c
@@ -4,6 +4,8 @@
#include <config.h>
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS)
/* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
@@ -14,8 +16,7 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
-#include "ntp_calendar.h"
+#include "timevalops.h"
#include <ctype.h>
#if defined(HAVE_BSD_TTYS)
@@ -349,11 +350,7 @@ static void dump_buf P((l_fp *coffs, int from, int to, char *text));
static void ees_report_event P((struct eesunit *ees, int code));
static void ees_receive P((struct recvbuf *rbufp));
static void ees_process P((struct eesunit *ees));
-#ifdef QSORT_USES_VOID_P
static int offcompare P((const void *va, const void *vb));
-#else
-static int offcompare P((const l_fp *a, const l_fp *b));
-#endif /* QSORT_USES_VOID_P */
/*
@@ -382,11 +379,15 @@ dump_buf(
int i;
register char *ptr = buff;
- sprintf(ptr, text);
- for (i=from; i<to; i++)
- { while (*ptr) ptr++;
- if ((ptr-buff) > DUMP_BUF_SIZE) msyslog(LOG_DEBUG, "D: %s", ptr=buff);
- sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295);
+ snprintf(buff, sizeof(buff), text);
+ for (i = from; i < to; i++) {
+ ptr += strlen(ptr);
+ if ((ptr - buff) > DUMP_BUF_SIZE) {
+ msyslog(LOG_DEBUG, "D: %s", buff);
+ ptr = buff;
+ }
+ snprintf(ptr, sizeof(buff) - (ptr - buff),
+ " %06d", ((int)coffs[i].l_f) / 4295);
}
msyslog(LOG_DEBUG, "D: %s", buff);
}
@@ -450,7 +451,7 @@ msfees_start(
/* Unit okay, attempt to open the devices. We do them both at
* once to make sure we can */
- (void) sprintf(eesdev, EES232, unit);
+ snprintf(eesdev, sizeof(eesdev), EES232, unit);
fd232 = open(eesdev, O_RDWR, 0777);
if (fd232 == -1) {
@@ -533,7 +534,7 @@ msfees_start(
ees->timestarted= current_time;
ees->ttytype = 0;
ees->io.clock_recv= ees_receive;
- ees->io.srcclock= (caddr_t)ees;
+ ees->io.srcclock= peer;
ees->io.datalen = 0;
ees->io.fd = fd232;
@@ -585,7 +586,7 @@ msfees_start(
peer->refid = htonl(EESHSREFID);
}
unitinuse[unit] = 1;
- pp->unitptr = (caddr_t) &eesunits[unit];
+ pp->unitptr = &eesunits[unit];
pp->clockdesc = EESDESCRIPTION;
msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
return (1);
@@ -673,7 +674,7 @@ ees_receive(
#endif
/* Get the clock this applies to and a pointer to the data */
- ees = (struct eesunit *)rbufp->recv_srcclock;
+ ees = (struct eesunit *)rbufp->recv_peer->procptr->unitptr;
dpt = (u_char *)&rbufp->recv_space;
dpend = dpt + rbufp->recv_length;
if ((dbg & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
@@ -917,9 +918,9 @@ ees_receive(
if (pps_step != 1 && pps_step != 2)
fprintf(stderr, "PPS step: %d too far off %ld (%d)\n",
ppsclockev.serial, ees->last_pps_no, pps_step);
- else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
- fprintf(stderr, "buftvtots failed\n");
- else { /* if ((ABS(time difference) - 0.25) < 0)
+ else {
+ pps_arrvstamp = tval_stamp_to_lfp(ppsclockev.tv);
+ /* if ((ABS(time difference) - 0.25) < 0)
* then believe it ...
*/
l_fp diff;
@@ -987,17 +988,20 @@ ees_receive(
/* Dump the deltas each minute */
if (dbg & DB_DUMP_DELTAS)
- { if (/*0 <= ees->second && */
- ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
+ {
+ if (/*0 <= ees->second && */
+ ees->second < COUNTOF(deltas))
+ deltas[ees->second] = delta_sfsec;
/* Dump on second 1, as second 0 sometimes missed */
if (ees->second == 1) {
- char text[16 * ((sizeof deltas) / (sizeof deltas[0]))];
+ char text[16 * COUNTOF(deltas)];
char *cptr=text;
int i;
- for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) {
- sprintf(cptr, " %d.%04d",
- msec(deltas[i]), subms(deltas[i]));
- while (*cptr) cptr++;
+ for (i = 0; i < COUNTOF(deltas); i++) {
+ snprintf(cptr, sizeof(text) / COUNTOF(deltas),
+ " %d.%04d", msec(deltas[i]),
+ subms(deltas[i]));
+ cptr += strlen(cptr);
}
msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
@@ -1220,7 +1224,6 @@ ees_receive(
/* offcompare - auxiliary comparison routine for offset sort */
-#ifdef QSORT_USES_VOID_P
static int
offcompare(
const void *va,
@@ -1231,16 +1234,6 @@ offcompare(
const l_fp *b = (const l_fp *)vb;
return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
}
-#else
-static int
-offcompare(
- const l_fp *a,
- const l_fp *b
- )
-{
- return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
-}
-#endif /* QSORT_USES_VOID_P */
/* ees_process - process a pile of samples from the clock */
@@ -1282,16 +1275,11 @@ ees_process(
if (samples < 1) return;
/* If requested, dump the raw data we have in the buffer */
- if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:");
+ if (ees->dump_vals)
+ dump_buf(coffs, 0, samples, "Raw data is:");
/* Sort the offsets, trim off the extremes, then choose one. */
- qsort(
-#ifdef QSORT_USES_VOID_P
- (void *)
-#else
- (char *)
-#endif
- coffs, (size_t)samples, sizeof(l_fp), offcompare);
+ qsort(coffs, (size_t)samples, sizeof(coffs[0]), offcompare);
noff = samples;
i = 0;
@@ -1423,7 +1411,7 @@ ees_process(
* reference time, and lastsampletime as the receive time.
*/
if (ees->fix_pending) {
- msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
+ msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x",
ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
ees->fix_pending = 0;
}
@@ -1458,5 +1446,5 @@ msfees_poll(
#else
-int refclock_msfees_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_mx4200.c b/contrib/ntp/ntpd/refclock_mx4200.c
index 68150b7..c942229 100644
--- a/contrib/ntp/ntpd/refclock_mx4200.c
+++ b/contrib/ntp/ntpd/refclock_mx4200.c
@@ -67,8 +67,6 @@
# include <sys/ppsclock.h>
#endif
-#include "ntp_sprintf.h"
-
#ifndef HAVE_STRUCT_PPSCLOCKEV
struct ppsclockev {
# ifdef HAVE_STRUCT_TIMESPEC
@@ -167,28 +165,24 @@ static char pmvxg[] = "PMVXG";
/*
* Function prototypes
*/
-static int mx4200_start P((int, struct peer *));
-static void mx4200_shutdown P((int, struct peer *));
-static void mx4200_receive P((struct recvbuf *));
-static void mx4200_poll P((int, struct peer *));
-
-static char * mx4200_parse_t P((struct peer *));
-static char * mx4200_parse_p P((struct peer *));
-static char * mx4200_parse_s P((struct peer *));
-#ifdef QSORT_USES_VOID_P
-int mx4200_cmpl_fp P((const void *, const void *));
-#else
-int mx4200_cmpl_fp P((const l_fp *, const l_fp *));
-#endif /* not QSORT_USES_VOID_P */
-static int mx4200_config P((struct peer *));
-static void mx4200_ref P((struct peer *));
-static void mx4200_send P((struct peer *, char *, ...))
+static int mx4200_start (int, struct peer *);
+static void mx4200_shutdown (int, struct peer *);
+static void mx4200_receive (struct recvbuf *);
+static void mx4200_poll (int, struct peer *);
+
+static char * mx4200_parse_t (struct peer *);
+static char * mx4200_parse_p (struct peer *);
+static char * mx4200_parse_s (struct peer *);
+int mx4200_cmpl_fp (const void *, const void *);
+static int mx4200_config (struct peer *);
+static void mx4200_ref (struct peer *);
+static void mx4200_send (struct peer *, char *, ...)
__attribute__ ((format (printf, 2, 3)));
-static u_char mx4200_cksum P((char *, int));
-static int mx4200_jday P((int, int, int));
-static void mx4200_debug P((struct peer *, char *, ...))
+static u_char mx4200_cksum (char *, int);
+static int mx4200_jday (int, int, int);
+static void mx4200_debug (struct peer *, char *, ...)
__attribute__ ((format (printf, 2, 3)));
-static int mx4200_pps P((struct peer *));
+static int mx4200_pps (struct peer *);
/*
* Transfer vector
@@ -222,31 +216,27 @@ mx4200_start(
/*
* Open serial port
*/
- (void)sprintf(gpsdev, DEVICE, unit);
- if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_PPS))) {
- return (0);
- }
+ snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
+ fd = refclock_open(gpsdev, SPEED232, LDISC_PPS);
+ if (fd <= 0)
+ return 0;
/*
* Allocate unit structure
*/
- if (!(up = (struct mx4200unit *) emalloc(sizeof(struct mx4200unit)))) {
- perror("emalloc");
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct mx4200unit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = mx4200_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -273,9 +263,11 @@ mx4200_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -294,7 +286,7 @@ mx4200_config(
int mode;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Initialize the unit variables
@@ -494,7 +486,7 @@ mx4200_ref(
char nsc, ewc;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
/* Should never happen! */
if (up->moving) return;
@@ -576,9 +568,9 @@ mx4200_ref(
}
alt = up->avg_alt;
minute = (lat - (double)(int)lat) * 60.0;
- sprintf(lats,"%02d%02.4f", (int)lat, minute);
+ snprintf(lats, sizeof(lats), "%02d%02.4f", (int)lat, minute);
minute = (lon - (double)(int)lon) * 60.0;
- sprintf(lons,"%03d%02.4f", (int)lon, minute);
+ snprintf(lons, sizeof(lons), "%03d%02.4f", (int)lon, minute);
mx4200_send(peer, "%s,%03d,,,,,%s,%c,%s,%c,%.2f,%d", pmvxg,
PMVXG_S_INITMODEA,
@@ -612,7 +604,7 @@ mx4200_poll(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
/*
* You don't need to poll this clock. It puts out timecodes
@@ -679,9 +671,9 @@ mx4200_receive(
/*
* Initialize pointers and read the timecode and timestamp.
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
/*
* If operating mode has been changed, then reinitialize the receiver
@@ -845,7 +837,7 @@ mx4200_receive(
* Capture the last PPS signal.
* Precision timestamp is returned in pp->lastrec
*/
- if (mx4200_pps(peer) != NULL) {
+ if (0 != mx4200_pps(peer)) {
mx4200_debug(peer, "mx4200_receive: pps failure\n");
refclock_report(peer, CEVNT_FAULT);
return;
@@ -961,18 +953,18 @@ mx4200_parse_t(
char time_mark_valid, time_sync, op_mode;
int sentence_type, valid;
int year, day_of_year, month, day_of_month;
- int hour, minute, second, leapsec;
+ int hour, minute, second, leapsec_warn;
int oscillator_offset, time_mark_error, time_bias;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
- leapsec = 0; /* Not all receivers output leap second warnings (!) */
+ leapsec_warn = 0; /* Not all receivers output leap second warnings (!) */
sscanf(pp->a_lastcode,
"$PMVXG,%d,%c,%d,%d,%d,%d:%d:%d,%c,%c,%d,%d,%d,%d",
&sentence_type, &time_mark_valid, &year, &month, &day_of_month,
&hour, &minute, &second, &time_sync, &op_mode,
- &oscillator_offset, &time_mark_error, &time_bias, &leapsec);
+ &oscillator_offset, &time_mark_error, &time_bias, &leapsec_warn);
if (sentence_type != PMVXG_D_TRECOVOUT)
return ("wrong rec-type");
@@ -1005,8 +997,8 @@ mx4200_parse_t(
mx4200_debug(peer,
"mx4200_parse_t: bad time %02d:%02d:%02d",
hour, minute, second);
- if (leapsec != 0)
- mx4200_debug(peer, " (leap %+d\n)", leapsec);
+ if (leapsec_warn != 0)
+ mx4200_debug(peer, " (leap %+d\n)", leapsec_warn);
mx4200_debug(peer, "\n");
refclock_report(peer, CEVNT_BADTIME);
return ("bad time");
@@ -1068,7 +1060,7 @@ mx4200_parse_t(
/*
* Setup leap second indicator
*/
- switch (leapsec) {
+ switch (leapsec_warn) {
case 0:
pp->leap = LEAP_NOWARNING;
break;
@@ -1085,12 +1077,12 @@ mx4200_parse_t(
/*
* Any change to the leap second warning status?
*/
- if (leapsec != up->last_leap ) {
+ if (leapsec_warn != up->last_leap ) {
msyslog(LOG_DEBUG,
"mx4200: leap second warning: %d to %d (%d)",
- up->last_leap, leapsec, pp->leap);
+ up->last_leap, leapsec_warn, pp->leap);
}
- up->last_leap = leapsec;
+ up->last_leap = leapsec_warn;
/*
* Copy time data for billboard monitoring.
@@ -1245,7 +1237,7 @@ mx4200_parse_p(
char north_south, east_west;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
/* Should never happen! */
if (up->moving) return ("mobile platform - no pos!");
@@ -1464,7 +1456,7 @@ mx4200_parse_s(
int sentence_type;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
sscanf ( pp->a_lastcode, "$PMVXG,%d", &sentence_type);
@@ -1509,7 +1501,7 @@ mx4200_pps(
struct timespec timeout;
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Grab the timestamp of the PPS signal.
@@ -1520,14 +1512,14 @@ mx4200_pps(
if (time_pps_fetch(up->pps_h, PPS_TSFMT_TSPEC, &(up->pps_i),
&timeout) < 0) {
mx4200_debug(peer,
- "mx4200_pps: time_pps_fetch: serial=%ul, %s\n",
- (unsigned long)up->pps_i.assert_sequence, strerror(errno));
+ "mx4200_pps: time_pps_fetch: serial=%lu, %m\n",
+ (unsigned long)up->pps_i.assert_sequence);
refclock_report(peer, CEVNT_FAULT);
return(1);
}
if (temp_serial == up->pps_i.assert_sequence) {
mx4200_debug(peer,
- "mx4200_pps: assert_sequence serial not incrementing: %ul\n",
+ "mx4200_pps: assert_sequence serial not incrementing: %lu\n",
(unsigned long)up->pps_i.assert_sequence);
refclock_report(peer, CEVNT_FAULT);
return(1);
@@ -1540,7 +1532,7 @@ mx4200_pps(
if (up->pps_i.assert_sequence == up->lastserial) {
mx4200_debug(peer, "mx4200_pps: no new pps event\n");
} else {
- mx4200_debug(peer, "mx4200_pps: missed %ul pps events\n",
+ mx4200_debug(peer, "mx4200_pps: missed %lu pps events\n",
up->pps_i.assert_sequence - up->lastserial - 1UL);
}
refclock_report(peer, CEVNT_FAULT);
@@ -1562,15 +1554,8 @@ mx4200_pps(
/*
* mx4200_debug - print debug messages
*/
-#if defined(__STDC__)
static void
mx4200_debug(struct peer *peer, char *fmt, ...)
-#else
-static void
-mx4200_debug(peer, fmt, va_alist)
- struct peer *peer;
- char *fmt;
-#endif /* __STDC__ */
{
#ifdef DEBUG
va_list ap;
@@ -1578,22 +1563,16 @@ mx4200_debug(peer, fmt, va_alist)
struct mx4200unit *up;
if (debug) {
-
-#if defined(__STDC__)
va_start(ap, fmt);
-#else
- va_start(ap);
-#endif /* __STDC__ */
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
-
+ up = pp->unitptr;
/*
* Print debug message to stdout
* In the future, we may want to get get more creative...
*/
- vprintf(fmt, ap);
+ mvprintf(fmt, ap);
va_end(ap);
}
@@ -1630,7 +1609,7 @@ mx4200_send(peer, fmt, va_alist)
#endif /* __STDC__ */
pp = peer->procptr;
- up = (struct mx4200unit *)pp->unitptr;
+ up = pp->unitptr;
cp = buf;
*cp++ = '$';
diff --git a/contrib/ntp/ntpd/refclock_neoclock4x.c b/contrib/ntp/ntpd/refclock_neoclock4x.c
index 374c81a..6fda0f0 100644
--- a/contrib/ntp/ntpd/refclock_neoclock4x.c
+++ b/contrib/ntp/ntpd/refclock_neoclock4x.c
@@ -3,18 +3,11 @@
* Refclock_neoclock4x.c
* - NeoClock4X driver for DCF77 or FIA Timecode
*
- * Date: 2006-01-11 v1.15
+ * Date: 2009-12-04 v1.16
*
* see http://www.linum.com/redir/jump/id=neoclock4x&action=redir
* for details about the NeoClock4X device
*
- * Copyright (C) 2002-2004 by Linum Software GmbH <neoclock4x@linum.com>
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- *
*/
#ifdef HAVE_CONFIG_H
@@ -109,7 +102,7 @@
#define NEOCLOCK4X_OFFSET_ANTENNA2 33
#define NEOCLOCK4X_OFFSET_CRC 35
-#define NEOCLOCK4X_DRIVER_VERSION "1.15 (2006-01-11)"
+#define NEOCLOCK4X_DRIVER_VERSION "1.16 (2009-12-04)"
#define NSEC_TO_MILLI 1000000
@@ -138,20 +131,20 @@ struct neoclock4x_unit {
int utc_msec;
};
-static int neoclock4x_start P((int, struct peer *));
-static void neoclock4x_shutdown P((int, struct peer *));
-static void neoclock4x_receive P((struct recvbuf *));
-static void neoclock4x_poll P((int, struct peer *));
-static void neoclock4x_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
-
-static int neol_atoi_len P((const char str[], int *, int));
-static int neol_hexatoi_len P((const char str[], int *, int));
-static void neol_jdn_to_ymd P((unsigned long, int *, int *, int *));
-static void neol_localtime P((unsigned long, int* , int*, int*, int*, int*, int*));
-static unsigned long neol_mktime P((int, int, int, int, int, int));
+static int neoclock4x_start (int, struct peer *);
+static void neoclock4x_shutdown (int, struct peer *);
+static void neoclock4x_receive (struct recvbuf *);
+static void neoclock4x_poll (int, struct peer *);
+static void neoclock4x_control (int, const struct refclockstat *, struct refclockstat *, struct peer *);
+
+static int neol_atoi_len (const char str[], int *, int);
+static int neol_hexatoi_len (const char str[], int *, int);
+static void neol_jdn_to_ymd (unsigned long, int *, int *, int *);
+static void neol_localtime (unsigned long, int* , int*, int*, int*, int*, int*);
+static unsigned long neol_mktime (int, int, int, int, int, int);
#if !defined(NEOCLOCK4X_FIRMWARE)
-static int neol_query_firmware P((int, int, char *, int));
-static int neol_check_firmware P((int, const char*, char *));
+static int neol_query_firmware (int, int, char *, size_t);
+static int neol_check_firmware (int, const char*, char *);
#endif
struct refclock refclock_neoclock4x = {
@@ -301,9 +294,9 @@ neoclock4x_start(int unit,
memset((char *)up, 0, sizeof(struct neoclock4x_unit));
pp = peer->procptr;
pp->clockdesc = "NeoClock4X";
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->io.clock_recv = neoclock4x_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
/*
@@ -319,15 +312,14 @@ neoclock4x_start(int unit,
* Initialize miscellaneous variables
*/
peer->precision = -10;
- peer->burst = NSTAGE;
memcpy((char *)&pp->refid, "neol", 4);
up->leap_status = 0;
up->unit = unit;
- strcpy(up->firmware, "?");
+ strlcpy(up->firmware, "?", sizeof(up->firmware));
up->firmwaretag = '?';
- strcpy(up->serial, "?");
- strcpy(up->radiosignal, "?");
+ strlcpy(up->serial, "?", sizeof(up->serial));
+ strlcpy(up->radiosignal, "?", sizeof(up->radiosignal));
up->timesource = '?';
up->dststatus = '?';
up->quarzstatus = '?';
@@ -343,7 +335,8 @@ neoclock4x_start(int unit,
#if defined(NEOCLOCK4X_FIRMWARE)
#if NEOCLOCK4X_FIRMWARE == NEOCLOCK4X_FIRMWARE_VERSION_A
- strcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)");
+ strlcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)",
+ sizeof(up->firmware));
up->firmwaretag = 'A';
#else
msyslog(LOG_EMERG, "NeoClock4X(%d): unknown firmware defined at compile time for NeoClock4X",
@@ -407,7 +400,7 @@ neoclock4x_shutdown(int unit,
pp = peer->procptr;
if(pp != NULL)
{
- up = (struct neoclock4x_unit *)pp->unitptr;
+ up = pp->unitptr;
if(up != NULL)
{
if(-1 != pp->io.fd)
@@ -461,9 +454,9 @@ neoclock4x_receive(struct recvbuf *rbufp)
unsigned char calc_chksum;
int recv_chksum;
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct neoclock4x_unit *)pp->unitptr;
+ up = pp->unitptr;
/* wait till poll interval is reached */
if(0 == up->recvnow)
@@ -670,7 +663,7 @@ neoclock4x_poll(int unit,
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct neoclock4x_unit *)pp->unitptr;
+ up = pp->unitptr;
pp->polls++;
up->recvnow = 1;
@@ -678,7 +671,7 @@ neoclock4x_poll(int unit,
static void
neoclock4x_control(int unit,
- struct refclockstat *in,
+ const struct refclockstat *in,
struct refclockstat *out,
struct peer *peer)
{
@@ -698,7 +691,7 @@ neoclock4x_control(int unit,
return;
}
- up = (struct neoclock4x_unit *)pp->unitptr;
+ up = pp->unitptr;
if(NULL == up)
{
msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
@@ -792,9 +785,9 @@ neol_hexatoi_len(const char str[],
int i;
int n = 0;
- for(i=0; isxdigit((int)str[i]) && i < maxlen; i++)
+ for(i=0; isxdigit((unsigned char)str[i]) && i < maxlen; i++)
{
- hexdigit = isdigit((int)str[i]) ? toupper(str[i]) - '0' : toupper(str[i]) - 'A' + 10;
+ hexdigit = isdigit((unsigned char)str[i]) ? toupper((unsigned char)str[i]) - '0' : toupper((unsigned char)str[i]) - 'A' + 10;
n = 16 * n + hexdigit;
}
*result = n;
@@ -810,7 +803,7 @@ neol_atoi_len(const char str[],
int i;
int n = 0;
- for(i=0; isdigit((int)str[i]) && i < maxlen; i++)
+ for(i=0; isdigit((unsigned char)str[i]) && i < maxlen; i++)
{
digit = str[i] - '0';
n = 10 * n + digit;
@@ -905,10 +898,10 @@ static int
neol_query_firmware(int fd,
int unit,
char *firmware,
- int maxlen)
+ size_t maxlen)
{
char tmpbuf[256];
- int len;
+ size_t len;
int lastsearch;
unsigned char c;
int last_c_was_crlf;
@@ -938,20 +931,20 @@ neol_query_firmware(int fd,
if(read_errors > 5)
{
msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit);
- strcpy(tmpbuf, "unknown due to timeout");
+ strlcpy(tmpbuf, "unknown due to timeout", sizeof(tmpbuf));
break;
}
if(chars_read > 500)
{
msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit);
- strcpy(tmpbuf, "unknown due to garbage input");
+ strlcpy(tmpbuf, "unknown due to garbage input", sizeof(tmpbuf));
break;
}
if(-1 == read(fd, &c, 1))
{
if(EAGAIN != errno)
{
- msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %s", unit ,strerror(errno));
+ msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %m", unit);
read_errors++;
}
else
@@ -970,7 +963,7 @@ neol_query_firmware(int fd,
if(0xA9 != c) /* wait for (c) char in input stream */
continue;
- strcpy(tmpbuf, "(c)");
+ strlcpy(tmpbuf, "(c)", sizeof(tmpbuf));
len = 3;
init = 0;
continue;
@@ -1008,22 +1001,28 @@ neol_query_firmware(int fd,
tmpbuf[len++] = (char) c;
}
tmpbuf[len] = '\0';
- if(len > sizeof(tmpbuf)-5)
+ if (len > sizeof(tmpbuf)-5)
break;
}
}
else
{
msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit);
- strcpy(tmpbuf, "unknown error");
+ strlcpy(tmpbuf, "unknown error", sizeof(tmpbuf));
}
- strncpy(firmware, tmpbuf, maxlen);
- firmware[maxlen] = '\0';
+ if (strlcpy(firmware, tmpbuf, maxlen) >= maxlen)
+ strlcpy(firmware, "buffer too small", maxlen);
if(flag)
{
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware);
+
+ if(strstr(firmware, "/R2"))
+ {
+ msyslog(LOG_INFO, "NeoClock4X(%d): Your NeoClock4X uses the new R2 firmware release. Please note the changed LED behaviour.", unit);
+ }
+
}
return (flag);
@@ -1110,4 +1109,16 @@ int refclock_neoclock4x_bs;
* - remove some unsued #ifdefs
* - fix nsec calculation, closes #499
*
+ * 2009/12/04 cjh
+ * Revision 1.16
+ * - change license to ntp COPYRIGHT notice. This should allow Debian
+ * to add this refclock driver in further releases.
+ * - detect R2 hardware
+ *
*/
+
+
+
+
+
+
diff --git a/contrib/ntp/ntpd/refclock_nmea.c b/contrib/ntp/ntpd/refclock_nmea.c
index a176ee8..126b530 100644
--- a/contrib/ntp/ntpd/refclock_nmea.c
+++ b/contrib/ntp/ntpd/refclock_nmea.c
@@ -2,39 +2,58 @@
* refclock_nmea.c - clock driver for an NMEA GPS CLOCK
* Michael Petry Jun 20, 1994
* based on refclock_heathn.c
+ *
+ * Updated to add support for Accord GPS Clock
+ * Venu Gopal Dec 05, 2007
+ * neo.venu@gmail.com, venugopal_d@pgad.gov.in
+ *
+ * Updated to process 'time1' fudge factor
+ * Venu Gopal May 05, 2008
+ *
+ * Converted to common PPSAPI code, separate PPS fudge time1
+ * from serial timecode fudge time2.
+ * Dave Hart July 1, 2009
+ * hart@ntp.org, davehart@davehart.com
*/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_NMEA)
+#define NMEA_WRITE_SUPPORT 0 /* no write support at the moment */
+
+#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
+#include "ntp_calendar.h"
+#include "timespecops.h"
#ifdef HAVE_PPSAPI
# include "ppsapi_timepps.h"
+# include "refclock_atom.h"
#endif /* HAVE_PPSAPI */
-#ifdef SYS_WINNT
-extern int async_write(int, const void *, unsigned int);
-#undef write
-#define write(fd, data, octets) async_write(fd, data, octets)
-#endif
/*
- * This driver supports the NMEA GPS Receiver with
+ * This driver supports NMEA-compatible GPS receivers
*
- * Protype was refclock_trak.c, Thanks a lot.
+ * Prototype was refclock_trak.c, Thanks a lot.
*
* The receiver used spits out the NMEA sentences for boat navigation.
- * And you thought it was an information superhighway. Try a raging river
+ * And you thought it was an information superhighway. Try a raging river
* filled with rapids and whirlpools that rip away your data and warp time.
*
* If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
@@ -52,712 +71,1889 @@ extern int async_write(int, const void *, unsigned int);
* bit 0 - enables RMC (1)
* bit 1 - enables GGA (2)
* bit 2 - enables GLL (4)
- * multiple sentences may be selected
+ * bit 3 - enables ZDA (8) - Standard Time & Date
+ * bit 3 - enables ZDG (8) - Accord GPS Clock's custom sentence with GPS time
+ * very close to standard ZDA
+ *
+ * Multiple sentences may be selected except when ZDG/ZDA is selected.
+ *
+ * bit 4/5/6 - selects the baudrate for serial port :
+ * 0 for 4800 (default)
+ * 1 for 9600
+ * 2 for 19200
+ * 3 for 38400
+ * 4 for 57600
+ * 5 for 115200
+ */
+#define NMEA_MESSAGE_MASK 0x0000FF0FU
+#define NMEA_BAUDRATE_MASK 0x00000070U
+#define NMEA_BAUDRATE_SHIFT 4
+
+#define NMEA_DELAYMEAS_MASK 0x80
+#define NMEA_EXTLOG_MASK 0x00010000U
+#define NMEA_DATETRUST_MASK 0x02000000U
+
+#define NMEA_PROTO_IDLEN 5 /* tag name must be at least 5 chars */
+#define NMEA_PROTO_MINLEN 6 /* min chars in sentence, excluding CS */
+#define NMEA_PROTO_MAXLEN 80 /* max chars in sentence, excluding CS */
+#define NMEA_PROTO_FIELDS 32 /* not official; limit on fields per record */
+
+/*
+ * We check the timecode format and decode its contents. We only care
+ * about a few of them, the most important being the $GPRMC format:
+ *
+ * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
+ *
+ * mode (0,1,2,3) selects sentence ANY/ALL, RMC, GGA, GLL, ZDA
+ * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
+ * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
+ * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
+ *
+ * Defining GPZDA to support Standard Time & Date
+ * sentence. The sentence has the following format
+ *
+ * $--ZDA,HHMMSS.SS,DD,MM,YYYY,TH,TM,*CS<CR><LF>
+ *
+ * Apart from the familiar fields,
+ * 'TH' Time zone Hours
+ * 'TM' Time zone Minutes
+ *
+ * Defining GPZDG to support Accord GPS Clock's custom NMEA
+ * sentence. The sentence has the following format
+ *
+ * $GPZDG,HHMMSS.S,DD,MM,YYYY,AA.BB,V*CS<CR><LF>
+ *
+ * It contains the GPS timestamp valid for next PPS pulse.
+ * Apart from the familiar fields,
+ * 'AA.BB' denotes the signal strength( should be < 05.00 )
+ * 'V' denotes the GPS sync status :
+ * '0' indicates INVALID time,
+ * '1' indicates accuracy of +/-20 ms
+ * '2' indicates accuracy of +/-100 ns
+ *
+ * Defining PGRMF for Garmin GPS Fix Data
+ * $PGRMF,WN,WS,DATE,TIME,LS,LAT,LAT_DIR,LON,LON_DIR,MODE,FIX,SPD,DIR,PDOP,TDOP
+ * WN -- GPS week number (weeks since 1980-01-06, mod 1024)
+ * WS -- GPS seconds in week
+ * LS -- GPS leap seconds, accumulated ( UTC + LS == GPS )
+ * FIX -- Fix type: 0=nofix, 1=2D, 2=3D
+ * DATE/TIME are standard date/time strings in UTC time scale
+ *
+ * The GPS time can be used to get the full century for the truncated
+ * date spec.
*/
/*
* Definitions
*/
-#ifdef SYS_WINNT
-# define DEVICE "COM%d:" /* COM 1 - 3 supported */
-#else
-# define DEVICE "/dev/gps%d" /* name of radio device */
-#endif
+#define DEVICE "/dev/gps%d" /* GPS serial device */
+#define PPSDEV "/dev/gpspps%d" /* PPSAPI device override */
#define SPEED232 B4800 /* uart speed (4800 bps) */
#define PRECISION (-9) /* precision assumed (about 2 ms) */
#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
#define REFID "GPS\0" /* reference id */
#define DESCRIPTION "NMEA GPS Clock" /* who we are */
-#define NANOSECOND 1000000000 /* one second (ns) */
-#define RANGEGATE 500000 /* range gate (ns) */
+#ifndef O_NOCTTY
+#define M_NOCTTY 0
+#else
+#define M_NOCTTY O_NOCTTY
+#endif
+#ifndef O_NONBLOCK
+#define M_NONBLOCK 0
+#else
+#define M_NONBLOCK O_NONBLOCK
+#endif
+#define PPSOPENMODE (O_RDWR | M_NOCTTY | M_NONBLOCK)
-#define LENNMEA 75 /* min timecode length */
+/* NMEA sentence array indexes for those we use */
+#define NMEA_GPRMC 0 /* recommended min. nav. */
+#define NMEA_GPGGA 1 /* fix and quality */
+#define NMEA_GPGLL 2 /* geo. lat/long */
+#define NMEA_GPZDA 3 /* date/time */
+/*
+ * $GPZDG is a proprietary sentence that violates the spec, by not
+ * using $P and an assigned company identifier to prefix the sentence
+ * identifier. When used with this driver, the system needs to be
+ * isolated from other NTP networks, as it operates in GPS time, not
+ * UTC as is much more common. GPS time is >15 seconds different from
+ * UTC due to not respecting leap seconds since 1970 or so. Other
+ * than the different timebase, $GPZDG is similar to $GPZDA.
+ */
+#define NMEA_GPZDG 4
+#define NMEA_PGRMF 5
+#define NMEA_ARRAY_SIZE (NMEA_PGRMF + 1)
/*
- * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
- * leap.
+ * Sentence selection mode bits
+ */
+#define USE_GPRMC 0x00000001u
+#define USE_GPGGA 0x00000002u
+#define USE_GPGLL 0x00000004u
+#define USE_GPZDA 0x00000008u
+#define USE_PGRMF 0x00000100u
+
+/* mapping from sentence index to controlling mode bit */
+static const u_int32 sentence_mode[NMEA_ARRAY_SIZE] =
+{
+ USE_GPRMC,
+ USE_GPGGA,
+ USE_GPGLL,
+ USE_GPZDA,
+ USE_GPZDA,
+ USE_PGRMF
+};
+
+/* date formats we support */
+enum date_fmt {
+ DATE_1_DDMMYY, /* use 1 field with 2-digit year */
+ DATE_3_DDMMYYYY /* use 3 fields with 4-digit year */
+};
+
+/* results for 'field_init()'
+ *
+ * Note: If a checksum is present, the checksum test must pass OK or the
+ * sentence is tagged invalid.
*/
-static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+#define CHECK_EMPTY -1 /* no data */
+#define CHECK_INVALID 0 /* not a valid NMEA sentence */
+#define CHECK_VALID 1 /* valid but without checksum */
+#define CHECK_CSVALID 2 /* valid with checksum OK */
/*
* Unit control structure
*/
-struct nmeaunit {
- int pollcnt; /* poll message counter */
- int polled; /* Hand in a sample? */
- l_fp tstamp; /* timestamp of last poll */
+typedef struct {
#ifdef HAVE_PPSAPI
- struct timespec ts; /* last timestamp */
- pps_params_t pps_params; /* pps parameters */
- pps_info_t pps_info; /* last pps data */
- pps_handle_t handle; /* pps handlebars */
+ struct refclock_atom atom; /* PPSAPI structure */
+ int ppsapi_fd; /* fd used with PPSAPI */
+ u_char ppsapi_tried; /* attempt PPSAPI once */
+ u_char ppsapi_lit; /* time_pps_create() worked */
+ u_char ppsapi_gate; /* system is on PPS */
#endif /* HAVE_PPSAPI */
-};
+ u_char gps_time; /* use GPS time, not UTC */
+ u_short century_cache; /* cached current century */
+ l_fp last_reftime; /* last processed reference stamp */
+ short epoch_warp; /* last epoch warp, for logging */
+ /* tally stats, reset each poll cycle */
+ struct
+ {
+ u_int total;
+ u_int accepted;
+ u_int rejected; /* GPS said not enough signal */
+ u_int malformed; /* Bad checksum, invalid date or time */
+ u_int filtered; /* mode bits, not GPZDG, same second */
+ u_int pps_used;
+ }
+ tally;
+ /* per sentence checksum seen flag */
+ u_char cksum_type[NMEA_ARRAY_SIZE];
+} nmea_unit;
+
+/*
+ * helper for faster field access
+ */
+typedef struct {
+ char *base; /* buffer base */
+ char *cptr; /* current field ptr */
+ int blen; /* buffer length */
+ int cidx; /* current field index */
+} nmea_data;
+
+/*
+ * NMEA gps week/time information
+ * This record contains the number of weeks since 1980-01-06 modulo
+ * 1024, the seconds elapsed since start of the week, and the number of
+ * leap seconds that are the difference between GPS and UTC time scale.
+ */
+typedef struct {
+ u_int32 wt_time; /* seconds since weekstart */
+ u_short wt_week; /* week number */
+ short wt_leap; /* leap seconds */
+} gps_weektm;
+
+/*
+ * The GPS week time scale starts on Sunday, 1980-01-06. We need the
+ * rata die number of this day.
+ */
+#ifndef DAY_GPS_STARTS
+#define DAY_GPS_STARTS 722820
+#endif
/*
* Function prototypes
*/
-static int nmea_start P((int, struct peer *));
-static void nmea_shutdown P((int, struct peer *));
+static void nmea_init (void);
+static int nmea_start (int, struct peer *);
+static void nmea_shutdown (int, struct peer *);
+static void nmea_receive (struct recvbuf *);
+static void nmea_poll (int, struct peer *);
#ifdef HAVE_PPSAPI
-static void nmea_control P((int, struct refclockstat *, struct
- refclockstat *, struct peer *));
-static int nmea_ppsapi P((struct peer *, int, int));
-static int nmea_pps P((struct nmeaunit *, l_fp *));
+static void nmea_control (int, const struct refclockstat *,
+ struct refclockstat *, struct peer *);
+#define NMEA_CONTROL nmea_control
+#else
+#define NMEA_CONTROL noentry
#endif /* HAVE_PPSAPI */
-static void nmea_receive P((struct recvbuf *));
-static void nmea_poll P((int, struct peer *));
-static void gps_send P((int, const char *, struct peer *));
-static char *field_parse P((char *, int));
+static void nmea_timer (int, struct peer *);
+
+/* parsing helpers */
+static int field_init (nmea_data * data, char * cp, int len);
+static char * field_parse (nmea_data * data, int fn);
+static void field_wipe (nmea_data * data, ...);
+static u_char parse_qual (nmea_data * data, int idx,
+ char tag, int inv);
+static int parse_time (struct calendar * jd, long * nsec,
+ nmea_data *, int idx);
+static int parse_date (struct calendar *jd, nmea_data*,
+ int idx, enum date_fmt fmt);
+static int parse_weekdata (gps_weektm *, nmea_data *,
+ int weekidx, int timeidx, int leapidx);
+/* calendar / date helpers */
+static int unfold_day (struct calendar * jd, u_int32 rec_ui);
+static int unfold_century (struct calendar * jd, u_int32 rec_ui);
+static int gpsfix_century (struct calendar * jd, const gps_weektm * wd,
+ u_short * ccentury);
+static l_fp eval_gps_time (struct peer * peer, const struct calendar * gpst,
+ const struct timespec * gpso, const l_fp * xrecv);
+
+static int nmead_open (const char * device);
+static void save_ltc (struct refclockproc * const, const char * const,
+ size_t);
/*
+ * If we want the driver to ouput sentences, too: re-enable the send
+ * support functions by defining NMEA_WRITE_SUPPORT to non-zero...
+ */
+#if NMEA_WRITE_SUPPORT
+
+static void gps_send(int, const char *, struct peer *);
+# ifdef SYS_WINNT
+# undef write /* ports/winnt/include/config.h: #define write _write */
+extern int async_write(int, const void *, unsigned int);
+# define write(fd, data, octets) async_write(fd, data, octets)
+# endif /* SYS_WINNT */
+
+#endif /* NMEA_WRITE_SUPPORT */
+
+static int32_t g_gpsMinBase;
+static int32_t g_gpsMinYear;
+
+/*
+ * -------------------------------------------------------------------
* Transfer vector
+ * -------------------------------------------------------------------
*/
-struct refclock refclock_nmea = {
+struct refclock refclock_nmea = {
nmea_start, /* start up driver */
- nmea_shutdown, /* shut down driver */
+ nmea_shutdown, /* shut down driver */
nmea_poll, /* transmit poll message */
-#ifdef HAVE_PPSAPI
- nmea_control, /* fudge control */
-#else
- noentry, /* fudge control */
-#endif /* HAVE_PPSAPI */
- noentry, /* initialize driver */
+ NMEA_CONTROL, /* fudge control */
+ nmea_init, /* initialize driver */
noentry, /* buginfo */
- NOFLAGS /* not used */
+ nmea_timer /* called once per second */
};
/*
+ * -------------------------------------------------------------------
+ * nmea_init - initialise data
+ *
+ * calculates a few runtime constants that cannot be made compile time
+ * constants.
+ * -------------------------------------------------------------------
+ */
+static void
+nmea_init(void)
+{
+ struct calendar date;
+
+ /* - calculate min. base value for GPS epoch & century unfolding
+ * This assumes that the build system was roughly in sync with
+ * the world, and that really synchronising to a time before the
+ * program was created would be unsafe or insane. If the build
+ * date cannot be stablished, at least use the start of GPS
+ * (1980-01-06) as minimum, because GPS can surely NOT
+ * synchronise beyond it's own big bang. We add a little safety
+ * margin for the fuzziness of the build date, which is in an
+ * undefined time zone. */
+ if (ntpcal_get_build_date(&date))
+ g_gpsMinBase = ntpcal_date_to_rd(&date) - 2;
+ else
+ g_gpsMinBase = 0;
+
+ if (g_gpsMinBase < DAY_GPS_STARTS)
+ g_gpsMinBase = DAY_GPS_STARTS;
+
+ ntpcal_rd_to_date(&date, g_gpsMinBase);
+ g_gpsMinYear = date.year;
+ g_gpsMinBase -= DAY_NTP_STARTS;
+}
+
+/*
+ * -------------------------------------------------------------------
* nmea_start - open the GPS devices and initialize data for processing
+ *
+ * return 0 on error, 1 on success. Even on error the peer structures
+ * must be in a state that permits 'nmea_shutdown()' to clean up all
+ * resources, because it will be called immediately to do so.
+ * -------------------------------------------------------------------
*/
static int
nmea_start(
- int unit,
- struct peer *peer
+ int unit,
+ struct peer * peer
)
{
- register struct nmeaunit *up;
- struct refclockproc *pp;
- int fd;
- char device[20];
-
- /*
- * Open serial port. Use CLK line discipline, if available.
- */
- (void)sprintf(device, DEVICE, unit);
-
- fd = refclock_open(device, SPEED232, LDISC_CLK);
- if (fd <= 0) {
-#ifdef HAVE_READLINK
- /* nmead support added by Jon Miner (cp_n18@yahoo.com)
- *
- * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
- * for information about nmead
- *
- * To use this, you need to create a link from /dev/gpsX to
- * the server:port where nmead is running. Something like this:
- *
- * ln -s server:port /dev/gps1
- */
- char buffer[80];
- char *nmea_host;
- int nmea_port;
- int len;
- struct hostent *he;
- struct protoent *p;
- struct sockaddr_in so_addr;
-
- if ((len = readlink(device,buffer,sizeof(buffer))) == -1)
- return(0);
- buffer[len] = 0;
-
- if ((nmea_host = strtok(buffer,":")) == NULL)
- return(0);
-
- nmea_port = atoi(strtok(NULL,":"));
-
- if ((he = gethostbyname(nmea_host)) == NULL)
- return(0);
- if ((p = getprotobyname("ip")) == NULL)
- return(0);
- so_addr.sin_family = AF_INET;
- so_addr.sin_port = htons(nmea_port);
- so_addr.sin_addr = *((struct in_addr *) he->h_addr);
-
- if ((fd = socket(PF_INET,SOCK_STREAM,p->p_proto)) == -1)
- return(0);
- if (connect(fd,(struct sockaddr *)&so_addr,SOCKLEN(&so_addr)) == -1) {
- close(fd);
- return (0);
- }
-#else
- return (0);
+ struct refclockproc * const pp = peer->procptr;
+ nmea_unit * const up = emalloc_zero(sizeof(*up));
+ char device[20];
+ size_t devlen;
+ u_int32 rate;
+ int baudrate;
+ const char * baudtext;
+
+
+ /* Get baudrate choice from mode byte bits 4/5/6 */
+ rate = (peer->ttl & NMEA_BAUDRATE_MASK) >> NMEA_BAUDRATE_SHIFT;
+
+ switch (rate) {
+ case 0:
+ baudrate = SPEED232;
+ baudtext = "4800";
+ break;
+ case 1:
+ baudrate = B9600;
+ baudtext = "9600";
+ break;
+ case 2:
+ baudrate = B19200;
+ baudtext = "19200";
+ break;
+ case 3:
+ baudrate = B38400;
+ baudtext = "38400";
+ break;
+#ifdef B57600
+ case 4:
+ baudrate = B57600;
+ baudtext = "57600";
+ break;
#endif
- }
-
- /*
- * Allocate and initialize unit structure
- */
- up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit));
- if (up == NULL) {
- (void) close(fd);
- return (0);
+#ifdef B115200
+ case 5:
+ baudrate = B115200;
+ baudtext = "115200";
+ break;
+#endif
+ default:
+ baudrate = SPEED232;
+ baudtext = "4800 (fallback)";
+ break;
}
- memset((char *)up, 0, sizeof(struct nmeaunit));
- pp = peer->procptr;
+
+ /* Allocate and initialize unit structure */
+ pp->unitptr = (caddr_t)up;
+ pp->io.fd = -1;
pp->io.clock_recv = nmea_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
- pp->io.fd = fd;
- if (!io_addclock(&pp->io)) {
- (void) close(fd);
- free(up);
- return (0);
- }
- pp->unitptr = (caddr_t)up;
+ /* force change detection on first valid message */
+ memset(&up->last_reftime, 0xFF, sizeof(up->last_reftime));
+ /* force checksum on GPRMC, see below */
+ up->cksum_type[NMEA_GPRMC] = CHECK_CSVALID;
+#ifdef HAVE_PPSAPI
+ up->ppsapi_fd = -1;
+#endif
+ ZERO(up->tally);
- /*
- * Initialize miscellaneous variables
- */
+ /* Initialize miscellaneous variables */
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
- up->pollcnt = 2;
- gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
-
-#ifdef HAVE_PPSAPI
- /*
- * Start the PPSAPI interface if it is there. Default to use
- * the assert edge and do not enable the kernel hardpps.
- */
- if (time_pps_create(fd, &up->handle) < 0) {
- up->handle = 0;
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_create failed: %m");
- return (1);
+ memcpy(&pp->refid, REFID, 4);
+
+ /* Open serial port. Use CLK line discipline, if available. */
+ devlen = snprintf(device, sizeof(device), DEVICE, unit);
+ if (devlen >= sizeof(device)) {
+ msyslog(LOG_ERR, "%s clock device name too long",
+ refnumtoa(&peer->srcadr));
+ return FALSE; /* buffer overflow */
}
- return(nmea_ppsapi(peer, 0, 0));
-#else
- return (1);
-#endif /* HAVE_PPSAPI */
+ pp->io.fd = refclock_open(device, baudrate, LDISC_CLK);
+ if (0 >= pp->io.fd) {
+ pp->io.fd = nmead_open(device);
+ if (-1 == pp->io.fd)
+ return FALSE;
+ }
+ LOGIF(CLOCKINFO, (LOG_NOTICE, "%s serial %s open at %s bps",
+ refnumtoa(&peer->srcadr), device, baudtext));
+
+ /* succeed if this clock can be added */
+ return io_addclock(&pp->io) != 0;
}
+
/*
+ * -------------------------------------------------------------------
* nmea_shutdown - shut down a GPS clock
+ *
+ * NOTE this routine is called after nmea_start() returns failure,
+ * as well as during a normal shutdown due to ntpq :config unpeer.
+ * -------------------------------------------------------------------
*/
static void
nmea_shutdown(
- int unit,
- struct peer *peer
+ int unit,
+ struct peer * peer
)
{
- register struct nmeaunit *up;
- struct refclockproc *pp;
+ struct refclockproc * const pp = peer->procptr;
+ nmea_unit * const up = (nmea_unit *)pp->unitptr;
+
+ UNUSED_ARG(unit);
- pp = peer->procptr;
- up = (struct nmeaunit *)pp->unitptr;
+ if (up != NULL) {
#ifdef HAVE_PPSAPI
- if (up->handle != 0)
- time_pps_destroy(up->handle);
-#endif /* HAVE_PPSAPI */
- io_closeclock(&pp->io);
- free(up);
+ if (up->ppsapi_lit)
+ time_pps_destroy(up->atom.handle);
+ if (up->ppsapi_tried && up->ppsapi_fd != pp->io.fd)
+ close(up->ppsapi_fd);
+#endif
+ free(up);
+ }
+ pp->unitptr = (caddr_t)NULL;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ pp->io.fd = -1;
}
-#ifdef HAVE_PPSAPI
/*
- * nmea_control - fudge control
+ * -------------------------------------------------------------------
+ * nmea_control - configure fudge params
+ * -------------------------------------------------------------------
*/
+#ifdef HAVE_PPSAPI
static void
nmea_control(
- int unit, /* unit (not used */
- struct refclockstat *in, /* input parameters (not uded) */
- struct refclockstat *out, /* output parameters (not used) */
- struct peer *peer /* peer structure pointer */
+ int unit,
+ const struct refclockstat * in_st,
+ struct refclockstat * out_st,
+ struct peer * peer
)
{
- struct refclockproc *pp;
+ struct refclockproc * const pp = peer->procptr;
+ nmea_unit * const up = (nmea_unit *)pp->unitptr;
- pp = peer->procptr;
- nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
- pp->sloppyclockflag & CLK_FLAG3);
-}
+ char device[32];
+ size_t devlen;
+
+ UNUSED_ARG(in_st);
+ UNUSED_ARG(out_st);
+ /*
+ * PPS control
+ *
+ * If /dev/gpspps$UNIT can be opened that will be used for
+ * PPSAPI. Otherwise, the GPS serial device /dev/gps$UNIT
+ * already opened is used for PPSAPI as well. (This might not
+ * work, in which case the PPS API remains unavailable...)
+ */
+
+ /* Light up the PPSAPI interface if not yet attempted. */
+ if ((CLK_FLAG1 & pp->sloppyclockflag) && !up->ppsapi_tried) {
+ up->ppsapi_tried = TRUE;
+ devlen = snprintf(device, sizeof(device), PPSDEV, unit);
+ if (devlen < sizeof(device)) {
+ up->ppsapi_fd = open(device, PPSOPENMODE,
+ S_IRUSR | S_IWUSR);
+ } else {
+ up->ppsapi_fd = -1;
+ msyslog(LOG_ERR, "%s PPS device name too long",
+ refnumtoa(&peer->srcadr));
+ }
+ if (-1 == up->ppsapi_fd)
+ up->ppsapi_fd = pp->io.fd;
+ if (refclock_ppsapi(up->ppsapi_fd, &up->atom)) {
+ /* use the PPS API for our own purposes now. */
+ up->ppsapi_lit = refclock_params(
+ pp->sloppyclockflag, &up->atom);
+ if (!up->ppsapi_lit) {
+ /* failed to configure, drop PPS unit */
+ time_pps_destroy(up->atom.handle);
+ msyslog(LOG_WARNING,
+ "%s set PPSAPI params fails",
+ refnumtoa(&peer->srcadr));
+ }
+ /* note: the PPS I/O handle remains valid until
+ * flag1 is cleared or the clock is shut down.
+ */
+ } else {
+ msyslog(LOG_WARNING,
+ "%s flag1 1 but PPSAPI fails",
+ refnumtoa(&peer->srcadr));
+ }
+ }
+
+ /* shut down PPS API if activated */
+ if (!(CLK_FLAG1 & pp->sloppyclockflag) && up->ppsapi_tried) {
+ /* shutdown PPS API */
+ if (up->ppsapi_lit)
+ time_pps_destroy(up->atom.handle);
+ up->atom.handle = 0;
+ /* close/drop PPS fd */
+ if (up->ppsapi_fd != pp->io.fd)
+ close(up->ppsapi_fd);
+ up->ppsapi_fd = -1;
+
+ /* clear markers and peer items */
+ up->ppsapi_gate = FALSE;
+ up->ppsapi_lit = FALSE;
+ up->ppsapi_tried = FALSE;
+
+ peer->flags &= ~FLAG_PPS;
+ peer->precision = PRECISION;
+ }
+}
+#endif /* HAVE_PPSAPI */
/*
- * Initialize PPSAPI
+ * -------------------------------------------------------------------
+ * nmea_timer - called once per second
+ * this only polls (older?) Oncore devices now
+ *
+ * Usually 'nmea_receive()' can get a timestamp every second, but at
+ * least one Motorola unit needs prompting each time. Doing so in
+ * 'nmea_poll()' gives only one sample per poll cycle, which actually
+ * defeats the purpose of the median filter. Polling once per second
+ * seems a much better idea.
+ * -------------------------------------------------------------------
*/
-int
-nmea_ppsapi(
- struct peer *peer, /* peer structure pointer */
- int enb_clear, /* clear enable */
- int enb_hardpps /* hardpps enable */
+static void
+nmea_timer(
+ int unit,
+ struct peer * peer
)
{
- struct refclockproc *pp;
- struct nmeaunit *up;
- int capability;
-
- pp = peer->procptr;
- up = (struct nmeaunit *)pp->unitptr;
- if (time_pps_getcap(up->handle, &capability) < 0) {
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_getcap failed: %m");
- return (0);
- }
- memset(&up->pps_params, 0, sizeof(pps_params_t));
- if (enb_clear)
- up->pps_params.mode = capability & PPS_CAPTURECLEAR;
- else
- up->pps_params.mode = capability & PPS_CAPTUREASSERT;
- if (!up->pps_params.mode) {
- msyslog(LOG_ERR,
- "refclock_nmea: invalid capture edge %d",
- !enb_clear);
- return (0);
- }
- up->pps_params.mode |= PPS_TSFMT_TSPEC;
- if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_setparams failed: %m");
- return (0);
- }
- if (enb_hardpps) {
- if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
- up->pps_params.mode & ~PPS_TSFMT_TSPEC,
- PPS_TSFMT_TSPEC) < 0) {
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_kcbind failed: %m");
- return (0);
- }
- pps_enable = 1;
- }
- peer->precision = PPS_PRECISION;
+#if NMEA_WRITE_SUPPORT
+
+ struct refclockproc * const pp = peer->procptr;
-#if DEBUG
- if (debug) {
- time_pps_getparams(up->handle, &up->pps_params);
- printf(
- "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n",
- capability, up->pps_params.api_version,
- up->pps_params.mode, enb_hardpps);
- }
-#endif
+ UNUSED_ARG(unit);
- return (1);
+ if (-1 != pp->io.fd) /* any mode bits to evaluate here? */
+ gps_send(pp->io.fd, "$PMOTG,RMC,0000*1D\r\n", peer);
+#else
+
+ UNUSED_ARG(unit);
+ UNUSED_ARG(peer);
+
+#endif /* NMEA_WRITE_SUPPORT */
}
+#ifdef HAVE_PPSAPI
/*
- * Get PPSAPI timestamps.
+ * -------------------------------------------------------------------
+ * refclock_ppsrelate(...) -- correlate with PPS edge
+ *
+ * This function is used to correlate a receive time stamp and a
+ * reference time with a PPS edge time stamp. It applies the necessary
+ * fudges (fudge1 for PPS, fudge2 for receive time) and then tries to
+ * move the receive time stamp to the corresponding edge. This can warp
+ * into future, if a transmission delay of more than 500ms is not
+ * compensated with a corresponding fudge time2 value, because then the
+ * next PPS edge is nearer than the last. (Similiar to what the PPS ATOM
+ * driver does, but we deal with full time stamps here, not just phase
+ * shift information.) Likewise, a negative fudge time2 value must be
+ * used if the reference time stamp correlates with the *following* PPS
+ * pulse.
*
- * Return 0 on failure and 1 on success.
+ * Note that the receive time fudge value only needs to move the receive
+ * stamp near a PPS edge but that close proximity is not required;
+ * +/-100ms precision should be enough. But since the fudge value will
+ * probably also be used to compensate the transmission delay when no
+ * PPS edge can be related to the time stamp, it's best to get it as
+ * close as possible.
+ *
+ * It should also be noted that the typical use case is matching to the
+ * preceeding edge, as most units relate their sentences to the current
+ * second.
+ *
+ * The function returns PPS_RELATE_NONE (0) if no PPS edge correlation
+ * can be fixed; PPS_RELATE_EDGE (1) when a PPS edge could be fixed, but
+ * the distance to the reference time stamp is too big (exceeds
+ * +/-400ms) and the ATOM driver PLL cannot be used to fix the phase;
+ * and PPS_RELATE_PHASE (2) when the ATOM driver PLL code can be used.
+ *
+ * On output, the receive time stamp is replaced with the corresponding
+ * PPS edge time if a fix could be made; the PPS fudge is updated to
+ * reflect the proper fudge time to apply. (This implies that
+ * 'refclock_process_offset()' must be used!)
+ * -------------------------------------------------------------------
*/
+#define PPS_RELATE_NONE 0 /* no pps correlation possible */
+#define PPS_RELATE_EDGE 1 /* recv time fixed, no phase lock */
+#define PPS_RELATE_PHASE 2 /* recv time fixed, phase lock ok */
+
static int
-nmea_pps(
- struct nmeaunit *up,
- l_fp *tsptr
+refclock_ppsrelate(
+ const struct refclockproc * pp , /* for sanity */
+ const struct refclock_atom * ap , /* for PPS io */
+ const l_fp * reftime ,
+ l_fp * rd_stamp, /* i/o read stamp */
+ double pp_fudge, /* pps fudge */
+ double * rd_fudge /* i/o read fudge */
)
{
- pps_info_t pps_info;
- struct timespec timeout, ts;
- double dtemp;
- l_fp tstmp;
-
- /*
- * Convert the timespec nanoseconds field to ntp l_fp units.
- */
- if (up->handle == 0)
- return (0);
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
- if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
- &timeout) < 0)
- return (0);
- if (up->pps_params.mode & PPS_CAPTUREASSERT) {
- if (pps_info.assert_sequence ==
- up->pps_info.assert_sequence)
- return (0);
- ts = up->pps_info.assert_timestamp;
- } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
- if (pps_info.clear_sequence ==
- up->pps_info.clear_sequence)
- return (0);
- ts = up->pps_info.clear_timestamp;
- } else {
- return (0);
- }
- if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
- return (0);
- up->ts = ts;
-
- tstmp.l_ui = ts.tv_sec + JAN_1970;
- dtemp = ts.tv_nsec * FRAC / 1e9;
- tstmp.l_uf = (u_int32)dtemp;
- *tsptr = tstmp;
- return (1);
+ pps_info_t pps_info;
+ struct timespec timeout;
+ l_fp pp_stamp, pp_delta;
+ double delta, idelta;
+
+ if (pp->leap == LEAP_NOTINSYNC)
+ return PPS_RELATE_NONE; /* clock is insane, no chance */
+
+ ZERO(timeout);
+ ZERO(pps_info);
+ if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC,
+ &pps_info, &timeout) < 0)
+ return PPS_RELATE_NONE; /* can't get time stamps */
+
+ /* get last active PPS edge before receive */
+ if (ap->pps_params.mode & PPS_CAPTUREASSERT)
+ timeout = pps_info.assert_timestamp;
+ else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
+ timeout = pps_info.clear_timestamp;
+ else
+ return PPS_RELATE_NONE; /* WHICH edge, please?!? */
+
+ /* get delta between receive time and PPS time */
+ pp_stamp = tspec_stamp_to_lfp(timeout);
+ pp_delta = *rd_stamp;
+ L_SUB(&pp_delta, &pp_stamp);
+ LFPTOD(&pp_delta, delta);
+ delta += pp_fudge - *rd_fudge;
+ if (fabs(delta) > 1.5)
+ return PPS_RELATE_NONE; /* PPS timeout control */
+
+ /* eventually warp edges, check phase */
+ idelta = floor(delta + 0.5);
+ pp_fudge -= idelta;
+ delta -= idelta;
+ if (fabs(delta) > 0.45)
+ return PPS_RELATE_NONE; /* dead band control */
+
+ /* we actually have a PPS edge to relate with! */
+ *rd_stamp = pp_stamp;
+ *rd_fudge = pp_fudge;
+
+ /* if whole system out-of-sync, do not try to PLL */
+ if (sys_leap == LEAP_NOTINSYNC)
+ return PPS_RELATE_EDGE; /* cannot PLL with atom code */
+
+ /* check against reftime if ATOM PLL can be used */
+ pp_delta = *reftime;
+ L_SUB(&pp_delta, &pp_stamp);
+ LFPTOD(&pp_delta, delta);
+ delta += pp_fudge;
+ if (fabs(delta) > 0.45)
+ return PPS_RELATE_EDGE; /* cannot PLL with atom code */
+
+ /* all checks passed, gets an AAA rating here! */
+ return PPS_RELATE_PHASE; /* can PLL with atom code */
}
-#endif /* HAVE_PPSAPI */
+#endif /* HAVE_PPSAPI */
/*
+ * -------------------------------------------------------------------
* nmea_receive - receive data from the serial interface
+ *
+ * This is the workhorse for NMEA data evaluation:
+ *
+ * + it checks all NMEA data, and rejects sentences that are not valid
+ * NMEA sentences
+ * + it checks whether a sentence is known and to be used
+ * + it parses the time and date data from the NMEA data string and
+ * augments the missing bits. (century in dat, whole date, ...)
+ * + it rejects data that is not from the first accepted sentence in a
+ * burst
+ * + it eventually replaces the receive time with the PPS edge time.
+ * + it feeds the data to the internal processing stages.
+ * -------------------------------------------------------------------
*/
static void
nmea_receive(
- struct recvbuf *rbufp
+ struct recvbuf * rbufp
)
{
- register struct nmeaunit *up;
- struct refclockproc *pp;
- struct peer *peer;
- int month, day;
- int i;
- char *cp, *dp;
- int cmdtype;
- /* Use these variables to hold data until we decide its worth keeping */
- char rd_lastcode[BMAX];
- l_fp rd_tmp;
- u_short rd_lencode;
-
- /*
- * Initialize pointers and read the timecode and timestamp
- */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct nmeaunit *)pp->unitptr;
- rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
+ /* declare & init control structure ptrs */
+ struct peer * const peer = rbufp->recv_peer;
+ struct refclockproc * const pp = peer->procptr;
+ nmea_unit * const up = (nmea_unit*)pp->unitptr;
- /*
- * There is a case that a <CR><LF> gives back a "blank" line
+ /* Use these variables to hold data until we decide its worth keeping */
+ nmea_data rdata;
+ char rd_lastcode[BMAX];
+ l_fp rd_timestamp, rd_reftime;
+ int rd_lencode;
+ double rd_fudge;
+
+ /* working stuff */
+ struct calendar date; /* to keep & convert the time stamp */
+ struct timespec tofs; /* offset to full-second reftime */
+ gps_weektm gpsw; /* week time storage */
+ /* results of sentence/date/time parsing */
+ u_char sentence; /* sentence tag */
+ int checkres;
+ char * cp;
+ int rc_date;
+ int rc_time;
+
+ /* make sure data has defined pristine state */
+ ZERO(tofs);
+ ZERO(date);
+ ZERO(gpsw);
+ sentence = 0;
+ rc_date = 0;
+ rc_time = 0;
+ /*
+ * Read the timecode and timestamp, then initialise field
+ * processing. The <CR><LF> at the NMEA line end is translated
+ * to <LF><LF> by the terminal input routines on most systems,
+ * and this gives us one spurious empty read per record which we
+ * better ignore silently.
*/
- if (rd_lencode == 0)
- return;
+ rd_lencode = refclock_gtlin(rbufp, rd_lastcode,
+ sizeof(rd_lastcode), &rd_timestamp);
+ checkres = field_init(&rdata, rd_lastcode, rd_lencode);
+ switch (checkres) {
+
+ case CHECK_INVALID:
+ DPRINTF(1, ("%s invalid data: '%s'\n",
+ refnumtoa(&peer->srcadr), rd_lastcode));
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
-#ifdef DEBUG
- if (debug)
- printf("nmea: gpsread %d %s\n", rd_lencode,
- rd_lastcode);
-#endif
+ case CHECK_EMPTY:
+ return;
- /*
- * We check the timecode format and decode its contents. The
- * we only care about a few of them. The most important being
- * the $GPRMC format
- * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
- * For Magellan (ColorTrak) GLL probably datum (order of sentences)
- * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL
- * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
- * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
- * $GPRMB,...
- * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
- * $GPAPB,...
- * $GPGSA,...
- * $GPGSV,...
- * $GPGSV,...
- */
-#define GPXXX 0
-#define GPRMC 1
-#define GPGGA 2
-#define GPGLL 4
- cp = rd_lastcode;
- cmdtype=0;
- if(strncmp(cp,"$GPRMC",6)==0) {
- cmdtype=GPRMC;
- }
- else if(strncmp(cp,"$GPGGA",6)==0) {
- cmdtype=GPGGA;
- }
- else if(strncmp(cp,"$GPGLL",6)==0) {
- cmdtype=GPGLL;
- }
- else if(strncmp(cp,"$GPXXX",6)==0) {
- cmdtype=GPXXX;
+ default:
+ DPRINTF(1, ("%s gpsread: %d '%s'\n",
+ refnumtoa(&peer->srcadr), rd_lencode,
+ rd_lastcode));
+ break;
}
+ up->tally.total++;
+
+ /*
+ * --> below this point we have a valid NMEA sentence <--
+ *
+ * Check sentence name. Skip first 2 chars (talker ID) in most
+ * cases, to allow for $GLGGA and $GPGGA etc. Since the name
+ * field has at least 5 chars we can simply shift the field
+ * start.
+ */
+ cp = field_parse(&rdata, 0);
+ if (strncmp(cp + 2, "RMC,", 4) == 0)
+ sentence = NMEA_GPRMC;
+ else if (strncmp(cp + 2, "GGA,", 4) == 0)
+ sentence = NMEA_GPGGA;
+ else if (strncmp(cp + 2, "GLL,", 4) == 0)
+ sentence = NMEA_GPGLL;
+ else if (strncmp(cp + 2, "ZDA,", 4) == 0)
+ sentence = NMEA_GPZDA;
+ else if (strncmp(cp + 2, "ZDG,", 4) == 0)
+ sentence = NMEA_GPZDG;
+ else if (strncmp(cp, "PGRMF,", 6) == 0)
+ sentence = NMEA_PGRMF;
else
- return;
-
-
+ return; /* not something we know about */
+
+ /* Eventually output delay measurement now. */
+ if (peer->ttl & NMEA_DELAYMEAS_MASK) {
+ mprintf_clock_stats(&peer->srcadr, "delay %0.6f %.*s",
+ ldexp(rd_timestamp.l_uf, -32),
+ (int)(strchr(rd_lastcode, ',') - rd_lastcode),
+ rd_lastcode);
+ }
+
/* See if I want to process this message type */
- if ( ((peer->ttl == 0) && (cmdtype != GPRMC))
- || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) )
+ if ((peer->ttl & NMEA_MESSAGE_MASK) &&
+ !(peer->ttl & sentence_mode[sentence])) {
+ up->tally.filtered++;
return;
+ }
- pp->lencode = rd_lencode;
- strcpy(pp->a_lastcode,rd_lastcode);
- cp = pp->a_lastcode;
-
- pp->lastrec = up->tstamp = rd_tmp;
- up->pollcnt = 2;
+ /*
+ * make sure it came in clean
+ *
+ * Apparently, older NMEA specifications (which are expensive)
+ * did not require the checksum for all sentences. $GPMRC is
+ * the only one so far identified which has always been required
+ * to include a checksum.
+ *
+ * Today, most NMEA GPS receivers checksum every sentence. To
+ * preserve its error-detection capabilities with modern GPSes
+ * while allowing operation without checksums on all but $GPMRC,
+ * we keep track of whether we've ever seen a valid checksum on
+ * a given sentence, and if so, reject future instances without
+ * checksum. ('up->cksum_type[NMEA_GPRMC]' is set in
+ * 'nmea_start()' to enforce checksums for $GPRMC right from the
+ * start.)
+ */
+ if (up->cksum_type[sentence] <= (u_char)checkres) {
+ up->cksum_type[sentence] = (u_char)checkres;
+ } else {
+ DPRINTF(1, ("%s checksum missing: '%s'\n",
+ refnumtoa(&peer->srcadr), rd_lastcode));
+ refclock_report(peer, CEVNT_BADREPLY);
+ up->tally.malformed++;
+ return;
+ }
-#ifdef DEBUG
- if (debug)
- printf("nmea: timecode %d %s\n", pp->lencode,
- pp->a_lastcode);
-#endif
+ /*
+ * $GPZDG provides GPS time not UTC, and the two mix poorly.
+ * Once have processed a $GPZDG, do not process any further UTC
+ * sentences (all but $GPZDG currently).
+ */
+ if (up->gps_time && NMEA_GPZDG != sentence) {
+ up->tally.filtered++;
+ return;
+ }
+ DPRINTF(1, ("%s processing %d bytes, timecode '%s'\n",
+ refnumtoa(&peer->srcadr), rd_lencode, rd_lastcode));
- /* Grab field depending on clock string type */
- switch( cmdtype ) {
- case GPRMC:
- /*
- * Test for synchronization. Check for quality byte.
- */
- dp = field_parse(cp,2);
- if( dp[0] != 'A')
- pp->leap = LEAP_NOTINSYNC;
- else
- pp->leap = LEAP_NOWARNING;
-
- /* Now point at the time field */
- dp = field_parse(cp,1);
+ /*
+ * Grab fields depending on clock string type and possibly wipe
+ * sensitive data from the last timecode.
+ */
+ switch (sentence) {
+
+ case NMEA_GPRMC:
+ /* Check quality byte, fetch data & time */
+ rc_time = parse_time(&date, &tofs.tv_nsec, &rdata, 1);
+ pp->leap = parse_qual(&rdata, 2, 'A', 0);
+ rc_date = parse_date(&date, &rdata, 9, DATE_1_DDMMYY)
+ && unfold_century(&date, rd_timestamp.l_ui);
+ if (CLK_FLAG4 & pp->sloppyclockflag)
+ field_wipe(&rdata, 3, 4, 5, 6, -1);
break;
+ case NMEA_GPGGA:
+ /* Check quality byte, fetch time only */
+ rc_time = parse_time(&date, &tofs.tv_nsec, &rdata, 1);
+ pp->leap = parse_qual(&rdata, 6, '0', 1);
+ rc_date = unfold_day(&date, rd_timestamp.l_ui);
+ if (CLK_FLAG4 & pp->sloppyclockflag)
+ field_wipe(&rdata, 2, 4, -1);
+ break;
- case GPGGA:
- /*
- * Test for synchronization. Check for quality byte.
- */
- dp = field_parse(cp,6);
- if( dp[0] == '0')
- pp->leap = LEAP_NOTINSYNC;
- else
- pp->leap = LEAP_NOWARNING;
-
- /* Now point at the time field */
- dp = field_parse(cp,1);
+ case NMEA_GPGLL:
+ /* Check quality byte, fetch time only */
+ rc_time = parse_time(&date, &tofs.tv_nsec, &rdata, 5);
+ pp->leap = parse_qual(&rdata, 6, 'A', 0);
+ rc_date = unfold_day(&date, rd_timestamp.l_ui);
+ if (CLK_FLAG4 & pp->sloppyclockflag)
+ field_wipe(&rdata, 1, 3, -1);
+ break;
+
+ case NMEA_GPZDA:
+ /* No quality. Assume best, fetch time & full date */
+ pp->leap = LEAP_NOWARNING;
+ rc_time = parse_time(&date, &tofs.tv_nsec, &rdata, 1);
+ rc_date = parse_date(&date, &rdata, 2, DATE_3_DDMMYYYY);
break;
+ case NMEA_GPZDG:
+ /* Check quality byte, fetch time & full date */
+ rc_time = parse_time(&date, &tofs.tv_nsec, &rdata, 1);
+ rc_date = parse_date(&date, &rdata, 2, DATE_3_DDMMYYYY);
+ pp->leap = parse_qual(&rdata, 4, '0', 1);
+ tofs.tv_sec = -1; /* GPZDG is following second */
+ break;
- case GPGLL:
- /*
- * Test for synchronization. Check for quality byte.
+ case NMEA_PGRMF:
+ /* get date, time, qualifier and GPS weektime. We need
+ * date and time-of-day for the century fix, so we read
+ * them first.
*/
- dp = field_parse(cp,6);
- if( dp[0] != 'A')
- pp->leap = LEAP_NOTINSYNC;
- else
- pp->leap = LEAP_NOWARNING;
-
- /* Now point at the time field */
- dp = field_parse(cp,5);
+ rc_date = parse_weekdata(&gpsw, &rdata, 1, 2, 5)
+ && parse_date(&date, &rdata, 3, DATE_1_DDMMYY);
+ rc_time = parse_time(&date, &tofs.tv_nsec, &rdata, 4);
+ pp->leap = parse_qual(&rdata, 11, '0', 1);
+ rc_date = rc_date
+ && gpsfix_century(&date, &gpsw, &up->century_cache);
+ if (CLK_FLAG4 & pp->sloppyclockflag)
+ field_wipe(&rdata, 6, 8, -1);
break;
-
-
- case GPXXX:
- return;
- default:
+
+ default:
+ INVARIANT(0); /* Coverity 97123 */
return;
-
}
- /*
- * Check time code format of NMEA
- */
-
- if( !isdigit((int)dp[0]) ||
- !isdigit((int)dp[1]) ||
- !isdigit((int)dp[2]) ||
- !isdigit((int)dp[3]) ||
- !isdigit((int)dp[4]) ||
- !isdigit((int)dp[5])
- ) {
- refclock_report(peer, CEVNT_BADREPLY);
- return;
- }
-
-
- /*
- * Convert time and check values.
- */
- pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0';
- pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0';
- pp->second = ((dp[4] - '0') * 10) + dp[5] - '0';
- /* Default to 0 milliseconds, if decimal convert milliseconds in
- one, two or three digits
- */
- pp->nsec = 0;
- if (dp[6] == '.') {
- if (isdigit((int)dp[7])) {
- pp->nsec = (dp[7] - '0') * 100000000;
- if (isdigit((int)dp[8])) {
- pp->nsec += (dp[8] - '0') * 10000000;
- if (isdigit((int)dp[9])) {
- pp->nsec += (dp[9] - '0') * 1000000;
- }
- }
- }
+ /* Check sanity of time-of-day. */
+ if (rc_time == 0) { /* no time or conversion error? */
+ checkres = CEVNT_BADTIME;
+ up->tally.malformed++;
+ }
+ /* Check sanity of date. */
+ else if (rc_date == 0) {/* no date or conversion error? */
+ checkres = CEVNT_BADDATE;
+ up->tally.malformed++;
}
+ /* check clock sanity; [bug 2143] */
+ else if (pp->leap == LEAP_NOTINSYNC) { /* no good status? */
+ checkres = CEVNT_BADREPLY;
+ up->tally.rejected++;
+ }
+ else
+ checkres = -1;
- if (pp->hour > 23 || pp->minute > 59 || pp->second > 59
- || pp->nsec > 1000000000) {
- refclock_report(peer, CEVNT_BADTIME);
+ if (checkres != -1) {
+ save_ltc(pp, rd_lastcode, rd_lencode);
+ refclock_report(peer, checkres);
return;
}
+ DPRINTF(1, ("%s effective timecode: %04u-%02u-%02u %02d:%02d:%02d\n",
+ refnumtoa(&peer->srcadr),
+ date.year, date.month, date.monthday,
+ date.hour, date.minute, date.second));
+ /* Check if we must enter GPS time mode; log so if we do */
+ if (!up->gps_time && (sentence == NMEA_GPZDG)) {
+ msyslog(LOG_INFO, "%s using GPS time as if it were UTC",
+ refnumtoa(&peer->srcadr));
+ up->gps_time = 1;
+ }
+
/*
- * Convert date and check values.
+ * Get the reference time stamp from the calendar buffer.
+ * Process the new sample in the median filter and determine the
+ * timecode timestamp, but only if the PPS is not in control.
+ * Discard sentence if reference time did not change.
*/
- if (cmdtype==GPRMC) {
- dp = field_parse(cp,9);
- day = dp[0] - '0';
- day = (day * 10) + dp[1] - '0';
- month = dp[2] - '0';
- month = (month * 10) + dp[3] - '0';
- pp->year = dp[4] - '0';
- pp->year = (pp->year * 10) + dp[5] - '0';
- }
- else {
- /* only time */
- time_t tt = time(NULL);
- struct tm * t = gmtime(&tt);
- day = t->tm_mday;
- month = t->tm_mon + 1;
- pp->year= t->tm_year;
- }
-
- if (month < 1 || month > 12 || day < 1) {
- refclock_report(peer, CEVNT_BADTIME);
+ rd_reftime = eval_gps_time(peer, &date, &tofs, &rd_timestamp);
+ if (L_ISEQU(&up->last_reftime, &rd_reftime)) {
+ /* Do not touch pp->a_lastcode on purpose! */
+ up->tally.filtered++;
return;
}
+ up->last_reftime = rd_reftime;
+ rd_fudge = pp->fudgetime2;
- /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */
- /* good thing that 2000 is a leap year */
- /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */
- if (pp->year % 4) {
- if (day > day1tab[month - 1]) {
- refclock_report(peer, CEVNT_BADTIME);
- return;
- }
- for (i = 0; i < month - 1; i++)
- day += day1tab[i];
- } else {
- if (day > day2tab[month - 1]) {
- refclock_report(peer, CEVNT_BADTIME);
- return;
+ DPRINTF(1, ("%s using '%s'\n",
+ refnumtoa(&peer->srcadr), rd_lastcode));
+
+ /* Data will be accepted. Update stats & log data. */
+ up->tally.accepted++;
+ save_ltc(pp, rd_lastcode, rd_lencode);
+ pp->lastrec = rd_timestamp;
+
+#ifdef HAVE_PPSAPI
+ /*
+ * If we have PPS running, we try to associate the sentence
+ * with the last active edge of the PPS signal.
+ */
+ if (up->ppsapi_lit)
+ switch (refclock_ppsrelate(
+ pp, &up->atom, &rd_reftime, &rd_timestamp,
+ pp->fudgetime1, &rd_fudge))
+ {
+ case PPS_RELATE_PHASE:
+ up->ppsapi_gate = TRUE;
+ peer->precision = PPS_PRECISION;
+ peer->flags |= FLAG_PPS;
+ DPRINTF(2, ("%s PPS_RELATE_PHASE\n",
+ refnumtoa(&peer->srcadr)));
+ up->tally.pps_used++;
+ break;
+
+ case PPS_RELATE_EDGE:
+ up->ppsapi_gate = TRUE;
+ peer->precision = PPS_PRECISION;
+ DPRINTF(2, ("%s PPS_RELATE_EDGE\n",
+ refnumtoa(&peer->srcadr)));
+ break;
+
+ case PPS_RELATE_NONE:
+ default:
+ /*
+ * Resetting precision and PPS flag is done in
+ * 'nmea_poll', since it might be a glitch. But
+ * at the end of the poll cycle we know...
+ */
+ DPRINTF(2, ("%s PPS_RELATE_NONE\n",
+ refnumtoa(&peer->srcadr)));
+ break;
}
- for (i = 0; i < month - 1; i++)
- day += day2tab[i];
- }
- pp->day = day;
+#endif /* HAVE_PPSAPI */
+
+ refclock_process_offset(pp, rd_reftime, rd_timestamp, rd_fudge);
+}
+/*
+ * -------------------------------------------------------------------
+ * nmea_poll - called by the transmit procedure
+ *
+ * Does the necessary bookkeeping stuff to keep the reported state of
+ * the clock in sync with reality.
+ *
+ * We go to great pains to avoid changing state here, since there may
+ * be more than one eavesdropper receiving the same timecode.
+ * -------------------------------------------------------------------
+ */
+static void
+nmea_poll(
+ int unit,
+ struct peer * peer
+ )
+{
+ struct refclockproc * const pp = peer->procptr;
+ nmea_unit * const up = (nmea_unit *)pp->unitptr;
+
+ /*
+ * Process median filter samples. If none received, declare a
+ * timeout and keep going.
+ */
#ifdef HAVE_PPSAPI
/*
- * If the PPSAPI is working, rather use its timestamps.
- * assume that the PPS occurs on the second so blow any msec
+ * If we don't have PPS pulses and time stamps, turn PPS down
+ * for now.
*/
- if (nmea_pps(up, &rd_tmp) == 1) {
- pp->lastrec = up->tstamp = rd_tmp;
- pp->nsec = 0;
+ if (!up->ppsapi_gate) {
+ peer->flags &= ~FLAG_PPS;
+ peer->precision = PRECISION;
+ } else {
+ up->ppsapi_gate = FALSE;
}
#endif /* HAVE_PPSAPI */
/*
- * Process the new sample in the median filter and determine the
- * reference clock offset and dispersion. We use lastrec as both
- * the reference time and receive time, in order to avoid being
- * cute, like setting the reference time later than the receive
- * time, which may cause a paranoid protocol module to chuck out
- * the data.
+ * If the median filter is empty, claim a timeout. Else process
+ * the input data and keep the stats going.
*/
+ if (pp->coderecv == pp->codeproc) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ } else {
+ pp->polls++;
+ pp->lastref = pp->lastrec;
+ refclock_receive(peer);
+ }
+
+ /*
+ * If extended logging is required, write the tally stats to the
+ * clockstats file; otherwise just do a normal clock stats
+ * record. Clear the tally stats anyway.
+ */
+ if (peer->ttl & NMEA_EXTLOG_MASK) {
+ /* Log & reset counters with extended logging */
+ const char *nmea = pp->a_lastcode;
+ if (*nmea == '\0') nmea = "(none)";
+ mprintf_clock_stats(
+ &peer->srcadr, "%s %u %u %u %u %u %u",
+ nmea,
+ up->tally.total, up->tally.accepted,
+ up->tally.rejected, up->tally.malformed,
+ up->tally.filtered, up->tally.pps_used);
+ } else {
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
+ }
+ ZERO(up->tally);
+}
- if (!refclock_process(pp)) {
- refclock_report(peer, CEVNT_BADTIME);
- return;
+/*
+ * -------------------------------------------------------------------
+ * Save the last timecode string, making sure it's properly truncated
+ * if necessary and NUL terminated in any case.
+ */
+static void
+save_ltc(
+ struct refclockproc * const pp,
+ const char * const tc,
+ size_t len
+ )
+{
+ if (len >= sizeof(pp->a_lastcode))
+ len = sizeof(pp->a_lastcode) - 1;
+ pp->lencode = (u_short)len;
+ memcpy(pp->a_lastcode, tc, len);
+ pp->a_lastcode[len] = '\0';
+}
+
+
+#if NMEA_WRITE_SUPPORT
+/*
+ * -------------------------------------------------------------------
+ * gps_send(fd, cmd, peer) Sends a command to the GPS receiver.
+ * as in gps_send(fd, "rqts,u", peer);
+ *
+ * If 'cmd' starts with a '$' it is assumed that this command is in raw
+ * format, that is, starts with '$', ends with '<cr><lf>' and that any
+ * checksum is correctly provided; the command will be send 'as is' in
+ * that case. Otherwise the function will create the necessary frame
+ * (start char, chksum, final CRLF) on the fly.
+ *
+ * We don't currently send any data, but would like to send RTCM SC104
+ * messages for differential positioning. It should also give us better
+ * time. Without a PPS output, we're Just fooling ourselves because of
+ * the serial code paths
+ * -------------------------------------------------------------------
+ */
+static void
+gps_send(
+ int fd,
+ const char * cmd,
+ struct peer * peer
+ )
+{
+ /* $...*xy<CR><LF><NUL> add 7 */
+ char buf[NMEA_PROTO_MAXLEN + 7];
+ int len;
+ u_char dcs;
+ const u_char *beg, *end;
+
+ if (*cmd != '$') {
+ /* get checksum and length */
+ beg = end = (const u_char*)cmd;
+ dcs = 0;
+ while (*end >= ' ' && *end != '*')
+ dcs ^= *end++;
+ len = end - beg;
+ /* format into output buffer with overflow check */
+ len = snprintf(buf, sizeof(buf), "$%.*s*%02X\r\n",
+ len, beg, dcs);
+ if ((size_t)len >= sizeof(buf)) {
+ DPRINTF(1, ("%s gps_send: buffer overflow for command '%s'\n",
+ refnumtoa(&peer->srcadr), cmd));
+ return; /* game over player 1 */
+ }
+ cmd = buf;
+ } else {
+ len = strlen(cmd);
}
+ DPRINTF(1, ("%s gps_send: '%.*s'\n", refnumtoa(&peer->srcadr),
+ len - 2, cmd));
+ /* send out the whole stuff */
+ if (write(fd, cmd, len) == -1)
+ refclock_report(peer, CEVNT_FAULT);
+}
+#endif /* NMEA_WRITE_SUPPORT */
- /*
- * Only go on if we had been polled.
+/*
+ * -------------------------------------------------------------------
+ * helpers for faster field splitting
+ * -------------------------------------------------------------------
+ *
+ * set up a field record, check syntax and verify checksum
+ *
+ * format is $XXXXX,1,2,3,4*ML
+ *
+ * 8-bit XOR of characters between $ and * noninclusive is transmitted
+ * in last two chars M and L holding most and least significant nibbles
+ * in hex representation such as:
+ *
+ * $GPGLL,5057.970,N,00146.110,E,142451,A*27
+ * $GPVTG,089.0,T,,,15.2,N,,*7F
+ *
+ * Some other constraints:
+ * + The field name must at least 5 upcase characters or digits and must
+ * start with a character.
+ * + The checksum (if present) must be uppercase hex digits.
+ * + The length of a sentence is limited to 80 characters (not including
+ * the final CR/LF nor the checksum, but including the leading '$')
+ *
+ * Return values:
+ * + CHECK_INVALID
+ * The data does not form a valid NMEA sentence or a checksum error
+ * occurred.
+ * + CHECK_VALID
+ * The data is a valid NMEA sentence but contains no checksum.
+ * + CHECK_CSVALID
+ * The data is a valid NMEA sentence and passed the checksum test.
+ * -------------------------------------------------------------------
+ */
+static int
+field_init(
+ nmea_data * data, /* context structure */
+ char * cptr, /* start of raw data */
+ int dlen /* data len, not counting trailing NUL */
+ )
+{
+ u_char cs_l; /* checksum local computed */
+ u_char cs_r; /* checksum remote given */
+ char * eptr; /* buffer end end pointer */
+ char tmp; /* char buffer */
+
+ cs_l = 0;
+ cs_r = 0;
+ /* some basic input constraints */
+ if (dlen < 0)
+ dlen = 0;
+ eptr = cptr + dlen;
+ *eptr = '\0';
+
+ /* load data context */
+ data->base = cptr;
+ data->cptr = cptr;
+ data->cidx = 0;
+ data->blen = dlen;
+
+ /* syntax check follows here. check allowed character
+ * sequences, updating the local computed checksum as we go.
+ *
+ * regex equiv: '^\$[A-Z][A-Z0-9]{4,}[^*]*(\*[0-9A-F]{2})?$'
*/
- if (!up->polled)
- return;
- up->polled = 0;
- pp->lastref = pp->lastrec;
- refclock_receive(peer);
- /* If we get here - what we got from the clock is OK, so say so */
- refclock_report(peer, CEVNT_NOMINAL);
+ /* -*- start character: '^\$' */
+ if (*cptr == '\0')
+ return CHECK_EMPTY;
+ if (*cptr++ != '$')
+ return CHECK_INVALID;
+
+ /* -*- advance context beyond start character */
+ data->base++;
+ data->cptr++;
+ data->blen--;
+
+ /* -*- field name: '[A-Z][A-Z0-9]{4,},' */
+ if (*cptr < 'A' || *cptr > 'Z')
+ return CHECK_INVALID;
+ cs_l ^= *cptr++;
+ while ((*cptr >= 'A' && *cptr <= 'Z') ||
+ (*cptr >= '0' && *cptr <= '9') )
+ cs_l ^= *cptr++;
+ if (*cptr != ',' || (cptr - data->base) < NMEA_PROTO_IDLEN)
+ return CHECK_INVALID;
+ cs_l ^= *cptr++;
+
+ /* -*- data: '[^*]*' */
+ while (*cptr && *cptr != '*')
+ cs_l ^= *cptr++;
+
+ /* -*- checksum field: (\*[0-9A-F]{2})?$ */
+ if (*cptr == '\0')
+ return CHECK_VALID;
+ if (*cptr != '*' || cptr != eptr - 3 ||
+ (cptr - data->base) >= NMEA_PROTO_MAXLEN)
+ return CHECK_INVALID;
+
+ for (cptr++; (tmp = *cptr) != '\0'; cptr++) {
+ if (tmp >= '0' && tmp <= '9')
+ cs_r = (cs_r << 4) + (tmp - '0');
+ else if (tmp >= 'A' && tmp <= 'F')
+ cs_r = (cs_r << 4) + (tmp - 'A' + 10);
+ else
+ break;
+ }
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
+ /* -*- make sure we are at end of string and csum matches */
+ if (cptr != eptr || cs_l != cs_r)
+ return CHECK_INVALID;
+ return CHECK_CSVALID;
}
/*
- * nmea_poll - called by the transmit procedure
+ * -------------------------------------------------------------------
+ * fetch a data field by index, zero being the name field. If this
+ * function is called repeatedly with increasing indices, the total load
+ * is O(n), n being the length of the string; if it is called with
+ * decreasing indices, the total load is O(n^2). Try not to go backwards
+ * too often.
+ * -------------------------------------------------------------------
+ */
+static char *
+field_parse(
+ nmea_data * data,
+ int fn
+ )
+{
+ char tmp;
+
+ if (fn < data->cidx) {
+ data->cidx = 0;
+ data->cptr = data->base;
+ }
+ while ((fn > data->cidx) && (tmp = *data->cptr) != '\0') {
+ data->cidx += (tmp == ',');
+ data->cptr++;
+ }
+ return data->cptr;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Wipe (that is, overwrite with '_') data fields and the checksum in
+ * the last timecode. The list of field indices is given as integers
+ * in a varargs list, preferrably in ascending order, in any case
+ * terminated by a negative field index.
+ *
+ * A maximum number of 8 fields can be overwritten at once to guard
+ * against runaway (that is, unterminated) argument lists.
*
- * We go to great pains to avoid changing state here, since there may be
- * more than one eavesdropper receiving the same timecode.
+ * This function affects what a remote user can see with
+ *
+ * ntpq -c clockvar <server>
+ *
+ * Note that this also removes the wiped fields from any clockstats
+ * log. Some NTP operators monitor their NMEA GPS using the change in
+ * location in clockstats over time as as a proxy for the quality of
+ * GPS reception and thereby time reported.
+ * -------------------------------------------------------------------
*/
static void
-nmea_poll(
- int unit,
- struct peer *peer
+field_wipe(
+ nmea_data * data,
+ ...
+ )
+{
+ va_list va; /* vararg index list */
+ int fcnt; /* safeguard against runaway arglist */
+ int fidx; /* field to nuke, or -1 for checksum */
+ char * cp; /* overwrite destination */
+
+ fcnt = 8;
+ cp = NULL;
+ va_start(va, data);
+ do {
+ fidx = va_arg(va, int);
+ if (fidx >= 0 && fidx <= NMEA_PROTO_FIELDS) {
+ cp = field_parse(data, fidx);
+ } else {
+ cp = data->base + data->blen;
+ if (data->blen >= 3 && cp[-3] == '*')
+ cp -= 2;
+ }
+ for ( ; '\0' != *cp && '*' != *cp && ',' != *cp; cp++)
+ if ('.' != *cp)
+ *cp = '_';
+ } while (fcnt-- && fidx >= 0);
+ va_end(va);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * PARSING HELPERS
+ * -------------------------------------------------------------------
+ *
+ * Check sync status
+ *
+ * If the character at the data field start matches the tag value,
+ * return LEAP_NOWARNING and LEAP_NOTINSYNC otherwise. If the 'inverted'
+ * flag is given, just the opposite value is returned. If there is no
+ * data field (*cp points to the NUL byte) the result is LEAP_NOTINSYNC.
+ * -------------------------------------------------------------------
+ */
+static u_char
+parse_qual(
+ nmea_data * rd,
+ int idx,
+ char tag,
+ int inv
+ )
+{
+ static const u_char table[2] =
+ { LEAP_NOTINSYNC, LEAP_NOWARNING };
+ char * dp;
+
+ dp = field_parse(rd, idx);
+
+ return table[ *dp && ((*dp == tag) == !inv) ];
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Parse a time stamp in HHMMSS[.sss] format with error checking.
+ *
+ * returns 1 on success, 0 on failure
+ * -------------------------------------------------------------------
+ */
+static int
+parse_time(
+ struct calendar * jd, /* result calendar pointer */
+ long * ns, /* storage for nsec fraction */
+ nmea_data * rd,
+ int idx
)
{
- register struct nmeaunit *up;
- struct refclockproc *pp;
+ static const unsigned long weight[4] = {
+ 0, 100000000, 10000000, 1000000
+ };
+
+ int rc;
+ u_int h;
+ u_int m;
+ u_int s;
+ int p1;
+ int p2;
+ u_long f;
+ char * dp;
+
+ dp = field_parse(rd, idx);
+ rc = sscanf(dp, "%2u%2u%2u%n.%3lu%n", &h, &m, &s, &p1, &f, &p2);
+ if (rc < 3 || p1 != 6) {
+ DPRINTF(1, ("nmea: invalid time code: '%.6s'\n", dp));
+ return FALSE;
+ }
+
+ /* value sanity check */
+ if (h > 23 || m > 59 || s > 60) {
+ DPRINTF(1, ("nmea: invalid time spec %02u:%02u:%02u\n",
+ h, m, s));
+ return FALSE;
+ }
- pp = peer->procptr;
- up = (struct nmeaunit *)pp->unitptr;
- if (up->pollcnt == 0)
- refclock_report(peer, CEVNT_TIMEOUT);
+ jd->hour = (u_char)h;
+ jd->minute = (u_char)m;
+ jd->second = (u_char)s;
+ /* if we have a fraction, scale it up to nanoseconds. */
+ if (rc == 4)
+ *ns = f * weight[p2 - p1 - 1];
else
- up->pollcnt--;
- pp->polls++;
- up->polled = 1;
+ *ns = 0;
+
+ return TRUE;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Parse a date string from an NMEA sentence. This could either be a
+ * partial date in DDMMYY format in one field, or DD,MM,YYYY full date
+ * spec spanning three fields. This function does some extensive error
+ * checking to make sure the date string was consistent.
+ *
+ * returns 1 on success, 0 on failure
+ * -------------------------------------------------------------------
+ */
+static int
+parse_date(
+ struct calendar * jd, /* result pointer */
+ nmea_data * rd,
+ int idx,
+ enum date_fmt fmt
+ )
+{
+ int rc;
+ u_int y;
+ u_int m;
+ u_int d;
+ int p;
+ char * dp;
+
+ dp = field_parse(rd, idx);
+ switch (fmt) {
+
+ case DATE_1_DDMMYY:
+ rc = sscanf(dp, "%2u%2u%2u%n", &d, &m, &y, &p);
+ if (rc != 3 || p != 6) {
+ DPRINTF(1, ("nmea: invalid date code: '%.6s'\n",
+ dp));
+ return FALSE;
+ }
+ break;
+
+ case DATE_3_DDMMYYYY:
+ rc = sscanf(dp, "%2u,%2u,%4u%n", &d, &m, &y, &p);
+ if (rc != 3 || p != 10) {
+ DPRINTF(1, ("nmea: invalid date code: '%.10s'\n",
+ dp));
+ return FALSE;
+ }
+ break;
+
+ default:
+ DPRINTF(1, ("nmea: invalid parse format: %d\n", fmt));
+ return FALSE;
+ }
+
+ /* value sanity check */
+ if (d < 1 || d > 31 || m < 1 || m > 12) {
+ DPRINTF(1, ("nmea: invalid date spec (YMD) %04u:%02u:%02u\n",
+ y, m, d));
+ return FALSE;
+ }
+
+ /* store results */
+ jd->monthday = (u_char)d;
+ jd->month = (u_char)m;
+ jd->year = (u_short)y;
+
+ return TRUE;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Parse GPS week time info from an NMEA sentence. This info contains
+ * the GPS week number, the GPS time-of-week and the leap seconds GPS
+ * to UTC.
+ *
+ * returns 1 on success, 0 on failure
+ * -------------------------------------------------------------------
+ */
+static int
+parse_weekdata(
+ gps_weektm * wd,
+ nmea_data * rd,
+ int weekidx,
+ int timeidx,
+ int leapidx
+ )
+{
+ u_long secs;
+ int fcnt;
+
+ /* parse fields and count success */
+ fcnt = sscanf(field_parse(rd, weekidx), "%hu", &wd->wt_week);
+ fcnt += sscanf(field_parse(rd, timeidx), "%lu", &secs);
+ fcnt += sscanf(field_parse(rd, leapidx), "%hd", &wd->wt_leap);
+ if (fcnt != 3 || wd->wt_week >= 1024 || secs >= 7*SECSPERDAY) {
+ DPRINTF(1, ("nmea: parse_weekdata: invalid weektime spec\n"));
+ return FALSE;
+ }
+ wd->wt_time = (u_int32)secs;
+
+ return TRUE;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * funny calendar-oriented stuff -- perhaps a bit hard to grok.
+ * -------------------------------------------------------------------
+ *
+ * Unfold a time-of-day (seconds since midnight) around the current
+ * system time in a manner that guarantees an absolute difference of
+ * less than 12hrs.
+ *
+ * This function is used for NMEA sentences that contain no date
+ * information. This requires the system clock to be in +/-12hrs
+ * around the true time, or the clock will synchronize the system 1day
+ * off if not augmented with a time sources that also provide the
+ * necessary date information.
+ *
+ * The function updates the calendar structure it also uses as
+ * input to fetch the time from.
+ *
+ * returns 1 on success, 0 on failure
+ * -------------------------------------------------------------------
+ */
+static int
+unfold_day(
+ struct calendar * jd,
+ u_int32 rec_ui
+ )
+{
+ vint64 rec_qw;
+ ntpcal_split rec_ds;
/*
- * usually nmea_receive can get a timestamp every second
+ * basically this is the peridiodic extension of the receive
+ * time - 12hrs to the time-of-day with a period of 1 day.
+ * But we would have to execute this in 64bit arithmetic, and we
+ * cannot assume we can do this; therefore this is done
+ * in split representation.
*/
+ rec_qw = ntpcal_ntp_to_ntp(rec_ui - SECSPERDAY/2, NULL);
+ rec_ds = ntpcal_daysplit(&rec_qw);
+ rec_ds.lo = ntpcal_periodic_extend(rec_ds.lo,
+ ntpcal_date_to_daysec(jd),
+ SECSPERDAY);
+ rec_ds.hi += ntpcal_daysec_to_date(jd, rec_ds.lo);
+ return (ntpcal_rd_to_date(jd, rec_ds.hi + DAY_NTP_STARTS) >= 0);
+}
- gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
+/*
+ * -------------------------------------------------------------------
+ * A 2-digit year is expanded into full year spec around the year found
+ * in 'jd->year'. This should be in +79/-19 years around the system time,
+ * or the result will be off by 100 years. The assymetric behaviour was
+ * chosen to enable inital sync for systems that do not have a
+ * battery-backup clock and start with a date that is typically years in
+ * the past.
+ *
+ * Since the GPS epoch starts at 1980-01-06, the resulting year will be
+ * not be before 1980 in any case.
+ *
+ * returns 1 on success, 0 on failure
+ * -------------------------------------------------------------------
+ */
+static int
+unfold_century(
+ struct calendar * jd,
+ u_int32 rec_ui
+ )
+{
+ struct calendar rec;
+ int32 baseyear;
+
+ ntpcal_ntp_to_date(&rec, rec_ui, NULL);
+ baseyear = rec.year - 20;
+ if (baseyear < g_gpsMinYear)
+ baseyear = g_gpsMinYear;
+ jd->year = (u_short)ntpcal_periodic_extend(baseyear, jd->year,
+ 100);
+
+ return ((baseyear <= jd->year) && (baseyear + 100 > jd->year));
}
/*
+ * -------------------------------------------------------------------
+ * A 2-digit year is expanded into a full year spec by correlation with
+ * a GPS week number and the current leap second count.
+ *
+ * The GPS week time scale counts weeks since Sunday, 1980-01-06, modulo
+ * 1024 and seconds since start of the week. The GPS time scale is based
+ * on international atomic time (TAI), so the leap second difference to
+ * UTC is also needed for a proper conversion.
*
- * gps_send(fd,cmd, peer) Sends a command to the GPS receiver.
- * as gps_send(fd,"rqts,u\r", peer);
+ * A brute-force analysis (that is, test for every date) shows that a
+ * wrong assignment of the century can not happen between the years 1900
+ * to 2399 when comparing the week signatures for different
+ * centuries. (I *think* that will not happen for 400*1024 years, but I
+ * have no valid proof. -*-perlinger@ntp.org-*-)
*
- * We don't currently send any data, but would like to send
- * RTCM SC104 messages for differential positioning. It should
- * also give us better time. Without a PPS output, we're
- * Just fooling ourselves because of the serial code paths
+ * This function is bound to to work between years 1980 and 2399
+ * (inclusive), which should suffice for now ;-)
*
+ * Note: This function needs a full date&time spec on input due to the
+ * necessary leap second corrections!
+ *
+ * returns 1 on success, 0 on failure
+ * -------------------------------------------------------------------
*/
-static void
-gps_send(
- int fd,
- const char *cmd,
- struct peer *peer
- )
+static int
+gpsfix_century(
+ struct calendar * jd,
+ const gps_weektm * wd,
+ u_short * century
+ )
{
+ int32 days;
+ int32 doff;
+ u_short week;
+ u_short year;
+ int loop;
+
+ /* Get day offset. Assumes that the input time is in range and
+ * that the leap seconds do not shift more than +/-1 day.
+ */
+ doff = ntpcal_date_to_daysec(jd) + wd->wt_leap;
+ doff = (doff >= SECSPERDAY) - (doff < 0);
- if (write(fd, cmd, strlen(cmd)) == -1) {
- refclock_report(peer, CEVNT_FAULT);
+ /*
+ * Loop over centuries to get a match, starting with the last
+ * successful one. (Or with the 19th century if the cached value
+ * is out of range...)
+ */
+ year = jd->year % 100;
+ for (loop = 5; loop > 0; loop--,(*century)++) {
+ if (*century < 19 || *century >= 24)
+ *century = 19;
+ /* Get days and week in GPS epoch */
+ jd->year = year + *century * 100;
+ days = ntpcal_date_to_rd(jd) - DAY_GPS_STARTS + doff;
+ week = (days / 7) % 1024;
+ if (days >= 0 && wd->wt_week == week)
+ return TRUE; /* matched... */
}
+
+ jd->year = year;
+ return FALSE; /* match failed... */
}
-static char *
-field_parse(
- char *cp,
- int fn
+/*
+ * -------------------------------------------------------------------
+ * And now the final execise: Considering the fact that many (most?)
+ * GPS receivers cannot handle a GPS epoch wrap well, we try to
+ * compensate for that problem by unwrapping a GPS epoch around the
+ * receive stamp. Another execise in periodic unfolding, of course,
+ * but with enough points to take care of.
+ *
+ * Note: The integral part of 'tofs' is intended to handle small(!)
+ * systematic offsets, as -1 for handling $GPZDG, which gives the
+ * following second. (sigh...) The absolute value shall be less than a
+ * day (86400 seconds).
+ * -------------------------------------------------------------------
+ */
+static l_fp
+eval_gps_time(
+ struct peer * peer, /* for logging etc */
+ const struct calendar * gpst, /* GPS time stamp */
+ const struct timespec * tofs, /* GPS frac second & offset */
+ const l_fp * xrecv /* receive time stamp */
)
{
- char *tp;
- int i = fn;
+ struct refclockproc * const pp = peer->procptr;
+ nmea_unit * const up = (nmea_unit *)pp->unitptr;
+
+ l_fp retv;
+
+ /* components of calculation */
+ int32_t rcv_sec, rcv_day; /* receive ToD and day */
+ int32_t gps_sec, gps_day; /* GPS ToD and day in NTP epoch */
+ int32_t adj_day, weeks; /* adjusted GPS day and week shift */
+
+ /* some temporaries to shuffle data */
+ vint64 vi64;
+ ntpcal_split rs64;
+
+ /* evaluate time stamp from receiver. */
+ gps_sec = ntpcal_date_to_daysec(gpst);
+ gps_day = ntpcal_date_to_rd(gpst) - DAY_NTP_STARTS;
+
+ /* merge in fractional offset */
+ retv = tspec_intv_to_lfp(*tofs);
+ gps_sec += retv.l_i;
+
+ /* If we fully trust the GPS receiver, just combine days and
+ * seconds and be done. */
+ if (peer->ttl & NMEA_DATETRUST_MASK) {
+ retv.l_ui = ntpcal_dayjoin(gps_day, gps_sec).D_s.lo;
+ return retv;
+ }
- for (tp = cp; *tp != '\0'; tp++) {
- if (*tp == ',')
- i--;
- if (i == 0)
- break;
+ /* So we do not trust the GPS receiver to deliver a correct date
+ * due to the GPS epoch changes. We map the date from the
+ * receiver into the +/-512 week interval around the receive
+ * time in that case. This would be a tad easier with 64bit
+ * calculations, but again, we restrict the code to 32bit ops
+ * when possible. */
+
+ /* - make sure the GPS fractional day is normalised
+ * Applying the offset value might have put us slightly over the
+ * edge of the allowed range for seconds-of-day. Doing a full
+ * division with floor correction is overkill here; a simple
+ * addition or subtraction step is sufficient. Using WHILE loops
+ * gives the right result even if the offset exceeds one day,
+ * which is NOT what it's intented for! */
+ while (gps_sec >= SECSPERDAY) {
+ gps_sec -= SECSPERDAY;
+ gps_day += 1;
}
- return (++tp);
+ while (gps_sec < 0) {
+ gps_sec += SECSPERDAY;
+ gps_day -= 1;
+ }
+
+ /* - get unfold base: day of full recv time - 512 weeks */
+ vi64 = ntpcal_ntp_to_ntp(xrecv->l_ui, NULL);
+ rs64 = ntpcal_daysplit(&vi64);
+ rcv_sec = rs64.lo;
+ rcv_day = rs64.hi - 512 * 7;
+
+ /* - take the fractional days into account
+ * If the fractional day of the GPS time is smaller than the
+ * fractional day of the receive time, we shift the base day for
+ * the unfold by 1. */
+ if ( gps_sec < rcv_sec
+ || (gps_sec == rcv_sec && retv.l_uf < xrecv->l_uf))
+ rcv_day += 1;
+
+ /* - don't warp ahead of GPS invention! */
+ if (rcv_day < g_gpsMinBase)
+ rcv_day = g_gpsMinBase;
+
+ /* - let the magic happen: */
+ adj_day = ntpcal_periodic_extend(rcv_day, gps_day, 1024*7);
+
+ /* - check if we should log a GPS epoch warp */
+ weeks = (adj_day - gps_day) / 7;
+ if (weeks != up->epoch_warp) {
+ up->epoch_warp = weeks;
+ LOGIF(CLOCKINFO, (LOG_INFO,
+ "%s Changed GPS epoch warp to %d weeks",
+ refnumtoa(&peer->srcadr), weeks));
+ }
+
+ /* - build result and be done */
+ retv.l_ui = ntpcal_dayjoin(adj_day, gps_sec).D_s.lo;
+ return retv;
+}
+
+/*
+ * ===================================================================
+ *
+ * NMEAD support
+ *
+ * original nmead support added by Jon Miner (cp_n18@yahoo.com)
+ *
+ * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
+ * for information about nmead
+ *
+ * To use this, you need to create a link from /dev/gpsX to
+ * the server:port where nmead is running. Something like this:
+ *
+ * ln -s server:port /dev/gps1
+ *
+ * Split into separate function by Juergen Perlinger
+ * (perlinger-at-ntp-dot-org)
+ *
+ * ===================================================================
+ */
+static int
+nmead_open(
+ const char * device
+ )
+{
+ int fd = -1; /* result file descriptor */
+
+#ifdef HAVE_READLINK
+ char host[80]; /* link target buffer */
+ char * port; /* port name or number */
+ int rc; /* result code (several)*/
+ int sh; /* socket handle */
+ struct addrinfo ai_hint; /* resolution hint */
+ struct addrinfo *ai_list; /* resolution result */
+ struct addrinfo *ai; /* result scan ptr */
+
+ fd = -1;
+
+ /* try to read as link, make sure no overflow occurs */
+ rc = readlink(device, host, sizeof(host));
+ if ((size_t)rc >= sizeof(host))
+ return fd; /* error / overflow / truncation */
+ host[rc] = '\0'; /* readlink does not place NUL */
+
+ /* get port */
+ port = strchr(host, ':');
+ if (!port)
+ return fd; /* not 'host:port' syntax ? */
+ *port++ = '\0'; /* put in separator */
+
+ /* get address infos and try to open socket
+ *
+ * This getaddrinfo() is naughty in ntpd's nonblocking main
+ * thread, but you have to go out of your wary to use this code
+ * and typically the blocking is at startup where its impact is
+ * reduced. The same holds for the 'connect()', as it is
+ * blocking, too...
+ */
+ ZERO(ai_hint);
+ ai_hint.ai_protocol = IPPROTO_TCP;
+ ai_hint.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(host, port, &ai_hint, &ai_list))
+ return fd;
+
+ for (ai = ai_list; ai && (fd == -1); ai = ai->ai_next) {
+ sh = socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ if (INVALID_SOCKET == sh)
+ continue;
+ rc = connect(sh, ai->ai_addr, ai->ai_addrlen);
+ if (-1 != rc)
+ fd = sh;
+ else
+ close(sh);
+ }
+ freeaddrinfo(ai_list);
+#else
+ fd = -1;
+#endif
+
+ return fd;
}
#else
-int refclock_nmea_bs;
-#endif /* REFCLOCK */
+NONEMPTY_TRANSLATION_UNIT
+#endif /* REFCLOCK && CLOCK_NMEA */
diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c
index e1d23a9..30924b8 100644
--- a/contrib/ntp/ntpd/refclock_oncore.c
+++ b/contrib/ntp/ntpd/refclock_oncore.c
@@ -11,7 +11,7 @@
* Driver for some of the various the Motorola Oncore GPS receivers.
* should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
* The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
- * than the others.
+ * than the others.
* The receivers without position hold (GT, GT+) will be less accurate.
*
* Tested with:
@@ -52,6 +52,48 @@
* MANUFACTUR DATE 2J17 MANUFACTUR DATE 3G15
*
* --------------------------------------------------------------------------
+ * Reg Clemens (June 2009)
+ * BUG[1220] OK, big patch, but mostly done mechanically. Change direct calls to write
+ * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog.
+ * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New
+ * routine oncore_log.
+ * --------------------------------------------------------------------------
+ * Reg Clemens (June 2009)
+ * BUG[1218] The comment on where the oncore driver gets its input file does not
+ * agree with the code. Change the comment.
+ * --------------------------------------------------------------------------
+ * Reg Clemens (June 2009)
+ * change exit statements to return(0) in main program. I had assumed that if the
+ * PPS driver did not start for some reason, we shuould stop NTPD itelf. Others
+ * disagree. We now give an ERR log message and stop this driver.
+ * --------------------------------------------------------------------------
+ * Reg Clemens (June 2009)
+ * A bytes available message for the input subsystem (Debug message).
+ * --------------------------------------------------------------------------
+ * Reg Clemens (Nov 2008)
+ * This code adds a message for TRAIM messages. Users often worry about the
+ * driver not starting up, and it is often because of signal strength being low.
+ * Low signal strength will give TRAIM messages.
+ * --------------------------------------------------------------------------
+ * Reg Clemens (Nov 2008)
+ * Add waiting on Almanac Message.
+ * --------------------------------------------------------------------------
+ * Reg Clemens (Nov 2008)
+ * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs
+ * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command
+ * that says 'Leap Pending'. As documented it only becomes true in the month
+ * before the leap second is to be applied, but in practice at least some of
+ * the receivers turn this indicator on as soon as the message is posted, which
+ * can be 6months early. As such, we use the Bj command to turn on the
+ * instance->pp->leap indicator but only run this test in December and June for
+ * updates on 1Jan and 1July.
+ *
+ * The @@Gj command exists in later ONCOREs, and it gives the exact date
+ * and size of the Leap Update. It can be emulated in the VP using the @@Bl
+ * command which reads the raw Satellite Broadcast Messages.
+ * We use these two commands to print informative messages in the clockstats
+ * file once per day as soon as the message appears on the satellites.
+ * --------------------------------------------------------------------------
* Reg Clemens (Feb 2006)
* Fix some gcc4 compiler complaints
* Fix possible segfault in oncore_init_shmem
@@ -119,9 +161,11 @@
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_refclock.h"
+#include "ntp_calendar.h"
#include "ntp_stdlib.h"
#include <stdio.h>
+#include <stdarg.h>
#include <ctype.h>
#include <sys/stat.h>
#ifdef ONCORE_SHMEM_STATUS
@@ -137,9 +181,17 @@
# include "ppsapi_timepps.h"
#endif
-#ifdef HAVE_SYS_SIO_H
-# include <sys/sio.h>
-#endif
+struct Bl {
+ int dt_ls;
+ int dt_lsf;
+ int WN;
+ int DN;
+ int WN_lsf;
+ int DN_lsf;
+ int wn_flg;
+ int lsf_flg;
+ int Bl_day;
+} Bl;
enum receive_state {
ONCORE_NO_IDEA,
@@ -265,14 +317,18 @@ struct instance {
u_char count4; /* cycles thru leap after Gj to issue Bj */
u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */
u_char count5_set; /* only set count5 once */
+ u_char counta; /* count for waiting on almanac message */
u_char pollcnt;
u_char timeout; /* count to retry Cj after Fa self-test */
+ u_char max_len; /* max length message seen by oncore_log, for debugging */
+ u_char max_count; /* count for message statistics */
struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */
+ struct Bl Bl; /* Satellite Broadcast Data Message */
u_char printed;
u_char polled;
u_long ev_serial;
- int Rcvptr;
+ unsigned Rcvptr;
u_char Rcvbuf[500];
u_char BEHa[160]; /* Ba, Ea or Ha */
u_char BEHn[80]; /* Bn , En , or Hn */
@@ -281,6 +337,7 @@ struct instance {
u_char saw_At;
u_char saw_Ay;
u_char saw_Az;
+ s_char saw_Bj;
s_char saw_Gj;
u_char have_dH;
u_char init_type;
@@ -294,60 +351,67 @@ struct instance {
u_char once; /* one pass code at top of BaEaHa */
s_char assert;
u_char hardpps;
+ s_char pps_control; /* PPS control, M12 only */
+ s_char pps_control_msg_seen;
};
#define rcvbuf instance->Rcvbuf
#define rcvptr instance->Rcvptr
-static int oncore_start P((int, struct peer *));
-static void oncore_poll P((int, struct peer *));
-static void oncore_shutdown P((int, struct peer *));
-static void oncore_consume P((struct instance *));
-static void oncore_read_config P((struct instance *));
-static void oncore_receive P((struct recvbuf *));
-static int oncore_ppsapi P((struct instance *));
-static void oncore_get_timestamp P((struct instance *, long, long));
-static void oncore_init_shmem P((struct instance *));
-
-static void oncore_antenna_report P((struct instance *, enum antenna_state));
-static void oncore_chan_test P((struct instance *));
-static void oncore_check_almanac P((struct instance *));
-static void oncore_check_antenna P((struct instance *));
-static void oncore_check_leap_sec P((struct instance *));
-static int oncore_checksum_ok P((u_char *, int));
-static void oncore_compute_dH P((struct instance *));
-static void oncore_load_almanac P((struct instance *));
-static void oncore_print_Cb P((struct instance *, u_char *));
-/* static void oncore_print_array P((u_char *, int)); */
-static void oncore_print_posn P((struct instance *));
-static void oncore_sendmsg P((int, u_char *, size_t));
-static void oncore_set_posn P((struct instance *));
-static void oncore_set_traim P((struct instance *));
-static void oncore_shmem_get_3D P((struct instance *));
-static void oncore_ss P((struct instance *));
-static int oncore_wait_almanac P((struct instance *));
-
-static void oncore_msg_any P((struct instance *, u_char *, size_t, int));
-static void oncore_msg_Adef P((struct instance *, u_char *, size_t));
-static void oncore_msg_Ag P((struct instance *, u_char *, size_t));
-static void oncore_msg_As P((struct instance *, u_char *, size_t));
-static void oncore_msg_At P((struct instance *, u_char *, size_t));
-static void oncore_msg_Ay P((struct instance *, u_char *, size_t));
-static void oncore_msg_Az P((struct instance *, u_char *, size_t));
-static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t));
-static void oncore_msg_Bd P((struct instance *, u_char *, size_t));
-static void oncore_msg_Bj P((struct instance *, u_char *, size_t));
-static void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t));
-static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t));
-static void oncore_msg_Cb P((struct instance *, u_char *, size_t));
-static void oncore_msg_Cf P((struct instance *, u_char *, size_t));
-static void oncore_msg_Cj P((struct instance *, u_char *, size_t));
-static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t));
-static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
-static void oncore_msg_Ga P((struct instance *, u_char *, size_t));
-static void oncore_msg_Gb P((struct instance *, u_char *, size_t));
-static void oncore_msg_Gj P((struct instance *, u_char *, size_t));
-static void oncore_msg_Sz P((struct instance *, u_char *, size_t));
+static int oncore_start (int, struct peer *);
+static void oncore_poll (int, struct peer *);
+static void oncore_shutdown (int, struct peer *);
+static void oncore_consume (struct instance *);
+static void oncore_read_config (struct instance *);
+static void oncore_receive (struct recvbuf *);
+static int oncore_ppsapi (struct instance *);
+static void oncore_get_timestamp (struct instance *, long, long);
+static void oncore_init_shmem (struct instance *);
+
+static void oncore_antenna_report (struct instance *, enum antenna_state);
+static void oncore_chan_test (struct instance *);
+static void oncore_check_almanac (struct instance *);
+static void oncore_check_antenna (struct instance *);
+static void oncore_check_leap_sec (struct instance *);
+static int oncore_checksum_ok (u_char *, int);
+static void oncore_compute_dH (struct instance *);
+static void oncore_load_almanac (struct instance *);
+static void oncore_log (struct instance *, int, const char *);
+static int oncore_log_f (struct instance *, int, const char *, ...)
+ NTP_PRINTF(3, 4);
+static void oncore_print_Cb (struct instance *, u_char *);
+/* static void oncore_print_array (u_char *, int); */
+static void oncore_print_posn (struct instance *);
+static void oncore_sendmsg (struct instance *, u_char *, size_t);
+static void oncore_set_posn (struct instance *);
+static void oncore_set_traim (struct instance *);
+static void oncore_shmem_get_3D (struct instance *);
+static void oncore_ss (struct instance *);
+static int oncore_wait_almanac (struct instance *);
+
+static void oncore_msg_any (struct instance *, u_char *, size_t, int);
+static void oncore_msg_Adef (struct instance *, u_char *, size_t);
+static void oncore_msg_Ag (struct instance *, u_char *, size_t);
+static void oncore_msg_As (struct instance *, u_char *, size_t);
+static void oncore_msg_At (struct instance *, u_char *, size_t);
+static void oncore_msg_Ay (struct instance *, u_char *, size_t);
+static void oncore_msg_Az (struct instance *, u_char *, size_t);
+static void oncore_msg_BaEaHa (struct instance *, u_char *, size_t);
+static void oncore_msg_Bd (struct instance *, u_char *, size_t);
+static void oncore_msg_Bj (struct instance *, u_char *, size_t);
+static void oncore_msg_Bl (struct instance *, u_char *, size_t);
+static void oncore_msg_BnEnHn (struct instance *, u_char *, size_t);
+static void oncore_msg_CaFaIa (struct instance *, u_char *, size_t);
+static void oncore_msg_Cb (struct instance *, u_char *, size_t);
+static void oncore_msg_Cf (struct instance *, u_char *, size_t);
+static void oncore_msg_Cj (struct instance *, u_char *, size_t);
+static void oncore_msg_Cj_id (struct instance *, u_char *, size_t);
+static void oncore_msg_Cj_init (struct instance *, u_char *, size_t);
+static void oncore_msg_Ga (struct instance *, u_char *, size_t);
+static void oncore_msg_Gb (struct instance *, u_char *, size_t);
+static void oncore_msg_Gc (struct instance *, u_char *, size_t);
+static void oncore_msg_Gj (struct instance *, u_char *, size_t);
+static void oncore_msg_Sz (struct instance *, u_char *, size_t);
struct refclock refclock_oncore = {
oncore_start, /* start up driver */
@@ -367,51 +431,52 @@ struct refclock refclock_oncore = {
static struct msg_desc {
const char flag[3];
const int len;
- void (*handler) P((struct instance *, u_char *, size_t));
+ void (*handler) (struct instance *, u_char *, size_t);
const char *fmt;
int shmem;
} oncore_messages[] = {
/* Ea and En first since they're most common */
- { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
- { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
- { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
- { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
- { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
- { "Hn", 78, oncore_msg_BnEnHn, "" },
- { "Ab", 10, 0, "" },
- { "Ac", 11, 0, "" },
- { "Ad", 11, oncore_msg_Adef, "" },
- { "Ae", 11, oncore_msg_Adef, "" },
- { "Af", 15, oncore_msg_Adef, "" },
- { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */
- { "As", 20, oncore_msg_As, "" },
- { "At", 8, oncore_msg_At, "" },
- { "Au", 12, 0, "" },
- { "Av", 8, 0, "" },
- { "Aw", 8, 0, "" },
- { "Ay", 11, oncore_msg_Ay, "" },
- { "Az", 11, oncore_msg_Az, "" },
- { "AB", 8, 0, "" },
- { "Bb", 92, 0, "" },
- { "Bd", 23, oncore_msg_Bd, "" },
- { "Bj", 8, oncore_msg_Bj, "" },
- { "Ca", 9, oncore_msg_CaFaIa, "" },
- { "Cb", 33, oncore_msg_Cb, "" },
- { "Cf", 7, oncore_msg_Cf, "" },
- { "Cg", 8, 0, "" },
- { "Ch", 9, 0, "" },
- { "Cj", 294, oncore_msg_Cj, "" },
- { "Ek", 71, 0, "" },
- { "Fa", 9, oncore_msg_CaFaIa, "" },
- { "Ga", 20, oncore_msg_Ga, "" },
- { "Gb", 17, oncore_msg_Gb, "" },
- { "Gc", 8, 0, "" },
- { "Gd", 8, 0, "" },
- { "Ge", 8, 0, "" },
- { "Gj", 21, oncore_msg_Gj, "" },
- { "Ia", 10, oncore_msg_CaFaIa, "" },
- { "Sz", 8, oncore_msg_Sz, "" },
- { {0}, 7, 0, "" }
+ { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC", 0 },
+ { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC", 0 },
+ { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC", 0 },
+ { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC", 0 },
+ { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC", 0 },
+ { "Hn", 78, oncore_msg_BnEnHn, "", 0 },
+ { "Ab", 10, 0, "", 0 },
+ { "Ac", 11, 0, "", 0 },
+ { "Ad", 11, oncore_msg_Adef, "", 0 },
+ { "Ae", 11, oncore_msg_Adef, "", 0 },
+ { "Af", 15, oncore_msg_Adef, "", 0 },
+ { "Ag", 8, oncore_msg_Ag, "", 0 }, /* Satellite mask angle */
+ { "As", 20, oncore_msg_As, "", 0 },
+ { "At", 8, oncore_msg_At, "", 0 },
+ { "Au", 12, 0, "", 0 },
+ { "Av", 8, 0, "", 0 },
+ { "Aw", 8, 0, "", 0 },
+ { "Ay", 11, oncore_msg_Ay, "", 0 },
+ { "Az", 11, oncore_msg_Az, "", 0 },
+ { "AB", 8, 0, "", 0 },
+ { "Bb", 92, 0, "", 0 },
+ { "Bd", 23, oncore_msg_Bd, "", 0 },
+ { "Bj", 8, oncore_msg_Bj, "", 0 },
+ { "Bl", 41, oncore_msg_Bl, "", 0 },
+ { "Ca", 9, oncore_msg_CaFaIa, "", 0 },
+ { "Cb", 33, oncore_msg_Cb, "", 0 },
+ { "Cf", 7, oncore_msg_Cf, "", 0 },
+ { "Cg", 8, 0, "", 0 },
+ { "Ch", 9, 0, "", 0 },
+ { "Cj", 294, oncore_msg_Cj, "", 0 },
+ { "Ek", 71, 0, "", 0 },
+ { "Fa", 9, oncore_msg_CaFaIa, "", 0 },
+ { "Ga", 20, oncore_msg_Ga, "", 0 },
+ { "Gb", 17, oncore_msg_Gb, "", 0 },
+ { "Gc", 8, oncore_msg_Gc, "", 0 },
+ { "Gd", 8, 0, "", 0 },
+ { "Ge", 8, 0, "", 0 },
+ { "Gj", 21, oncore_msg_Gj, "", 0 },
+ { "Ia", 10, oncore_msg_CaFaIa, "", 0 },
+ { "Sz", 8, oncore_msg_Sz, "", 0 },
+ { {0}, 7, 0, "", 0 }
};
@@ -446,6 +511,7 @@ static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satel
static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
+static u_char oncore_cmd_Bl[] = { 'B', 'l', 1 }; /* VP Satellite Broadcast Data Msg */
static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim on */
static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on, traim on */
static u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim off */
@@ -465,7 +531,7 @@ static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12
0xff, 0xff, 0xff, 0xff, /* */
0xff, 0xff, 0xff, 0xff, 0xff }; /* */
static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
-static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
+static u_char oncore_cmd_Gc[] = { 'G', 'c', 0 }; /* 12 PPS Control: Off, On, 1+satellite,TRAIM */
static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
@@ -487,9 +553,6 @@ static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */
* Gj in UT as of 3.0, 1999 , Bj as of 1.3
*/
-static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
- "Aug", "Sep", "Oct", "Nov", "Dec" };
-
#define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
#define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
@@ -531,23 +594,20 @@ oncore_start(
#define STRING_LEN 32
register struct instance *instance;
struct refclockproc *pp;
- int fd1, fd2, num;
- char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
- const char *cp;
+ int fd1, fd2;
+ char device1[STRING_LEN], device2[STRING_LEN];
+#ifndef SYS_WINNT
struct stat stat1, stat2;
+#endif
/* create instance structure for this unit */
- if (!(instance = (struct instance *) malloc(sizeof *instance))) {
- perror("malloc");
- return (0);
- }
- memset((char *) instance, 0, sizeof *instance);
+ instance = emalloc(sizeof(*instance));
+ memset(instance, 0, sizeof(*instance));
/* initialize miscellaneous variables */
pp = peer->procptr;
- pp->unitptr = (caddr_t) instance;
instance->pp = pp;
instance->unit = unit;
instance->peer = peer;
@@ -558,32 +618,32 @@ oncore_start(
instance->traim = -1;
instance->traim_in = -1;
instance->chan_in = -1;
+ instance->pps_control = -1; /* PPS control, M12 only */
+ instance->pps_control_msg_seen = -1; /* Have seen response to Gc msg */
instance->model = ONCORE_UNKNOWN;
instance->mode = MODE_UNKNOWN;
instance->site_survey = ONCORE_SS_UNKNOWN;
instance->Ag = 0xff; /* Satellite mask angle, unset by user */
instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
+ peer->flags &= ~FLAG_PPS; /* PPS not active yet */
peer->precision = -26;
peer->minpoll = 4;
peer->maxpoll = 4;
pp->clockdesc = "Motorola Oncore GPS Receiver";
memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
- cp = "ONCORE DRIVER -- CONFIGURING";
- record_clock_stats(&(instance->peer->srcadr), cp);
-
+ oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING");
instance->o_state = ONCORE_NO_IDEA;
- cp = "state = ONCORE_NO_IDEA";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA");
/* Now open files.
* This is a bit complicated, a we dont want to open the same file twice
* (its a problem on some OS), and device2 may not exist for the new PPS
*/
- (void)sprintf(device1, DEVICE1, unit);
- (void)sprintf(device2, DEVICE2, unit);
+ (void)snprintf(device1, sizeof(device1), DEVICE1, unit);
+ (void)snprintf(device2, sizeof(device2), DEVICE2, unit);
/* OPEN DEVICES */
/* opening different devices for fd1 and fd2 presents no problems */
@@ -594,42 +654,64 @@ oncore_start(
Since things ALWAYS work if we only open the device once, we check
to see if the two devices are in fact the same, then proceed to
do one open or two.
- */
+ For use with linuxPPS we assume that the N_TTY file has been opened
+ and that the line discipline has been changed to N_PPS by another
+ program (say ppsldisc) so that the two files expected by the oncore
+ driver can be opened.
+
+ Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do
+ the stat below without error even though the file has already had its
+ line discipline changed by another process.
+
+ The Windows port of ntpd arranges to return duplicate handles for
+ multiple opens of the same serial device, and doesn't have inodes
+ for serial handles, so we just open both on Windows.
+ */
+#ifndef SYS_WINNT
if (stat(device1, &stat1)) {
- sprintf(Msg, "Can't stat fd1 (%s)\n", device1);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- exit(1);
+ oncore_log_f(instance, LOG_ERR, "Can't stat fd1 (%s)",
+ device1);
+ return(0); /* exit, no file, can't start driver */
}
if (stat(device2, &stat2)) {
- sprintf(Msg, "Can't stat fd2 (%s)\n", device2);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- exit(1);
+ stat2.st_dev = stat2.st_ino = -2;
+ oncore_log_f(instance, LOG_ERR, "Can't stat fd2 (%s) %d %m",
+ device2, errno);
}
+#endif /* !SYS_WINNT */
- if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
- sprintf(Msg, "Can't open fd1 (%s)\n", device1);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- exit(1);
+ fd1 = refclock_open(device1, SPEED, LDISC_RAW);
+ if (fd1 <= 0) {
+ oncore_log_f(instance, LOG_ERR, "Can't open fd1 (%s)",
+ device1);
+ return(0); /* exit, can't open file, can't start driver */
}
+ /* for LINUX the PPS device is the result of a line discipline.
+ It seems simplest to let an external program create the appropriate
+ /dev/pps<n> file, and only check (carefully) for its existance here
+ */
+
+#ifndef SYS_WINNT
if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */
fd2 = fd1;
- else { /* different devices here */
- if ((fd2=open(device2, O_RDWR)) < 0) {
- sprintf(Msg, "Can't open fd2 (%s)\n", device2);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- exit(1);
+ else
+#endif /* !SYS_WINNT */
+ { /* different devices here */
+ if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) {
+ oncore_log_f(instance, LOG_ERR,
+ "Can't open fd2 (%s)", device2);
+ return(0); /* exit, can't open PPS file, can't start driver */
}
}
- num = fd2;
- /* open ppsapi soure */
+ /* open ppsapi source */
- if (time_pps_create(num, &instance->pps_h) < 0) {
- record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel");
- return(0);
+ if (time_pps_create(fd2, &instance->pps_h) < 0) {
+ oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel");
+ return(0); /* exit, don't find PPSAPI in kernel */
}
/* continue initialization */
@@ -645,15 +727,17 @@ oncore_start(
return(0);
pp->io.clock_recv = oncore_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd1;
if (!io_addclock(&pp->io)) {
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock");
- (void) close(fd1);
+ oncore_log(instance, LOG_ERR, "can't do io_addclock");
+ close(fd1);
+ pp->io.fd = -1;
free(instance);
return (0);
}
+ pp->unitptr = instance;
#ifdef ONCORE_SHMEM_STATUS
/*
@@ -671,12 +755,11 @@ oncore_start(
*/
instance->o_state = ONCORE_CHECK_ID;
- cp = "state = ONCORE_CHECK_ID";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID");
instance->timeout = 4;
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+ oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
+ oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
instance->pollcnt = 2;
return (1);
@@ -697,21 +780,24 @@ oncore_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- instance = (struct instance *) pp->unitptr;
+ instance = pp->unitptr;
- io_closeclock(&pp->io);
+ if (pp->io.fd != -1)
+ io_closeclock(&pp->io);
- time_pps_destroy (instance->pps_h);
+ if (instance != NULL) {
+ time_pps_destroy (instance->pps_h);
- close(instance->ttyfd);
+ close(instance->ttyfd);
- if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
- close(instance->ppsfd);
+ if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
+ close(instance->ppsfd);
- if (instance->shmemfd)
- close(instance->shmemfd);
+ if (instance->shmemfd)
+ close(instance->shmemfd);
- free(instance);
+ free(instance);
+ }
}
@@ -728,19 +814,16 @@ oncore_poll(
{
struct instance *instance;
- instance = (struct instance *) peer->procptr->unitptr;
+ instance = peer->procptr->unitptr;
if (instance->timeout) {
- char *cp;
-
instance->timeout--;
if (instance->timeout == 0) {
- cp = "Oncore: No response from @@Cj, shutting down driver";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_ERR,
+ "Oncore: No response from @@Cj, shutting down driver");
oncore_shutdown(unit, peer);
} else {
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
- cp = "Oncore: Resend @@Cj";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+ oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj");
}
return;
}
@@ -765,15 +848,15 @@ oncore_ppsapi(
)
{
int cap, mode, mode1;
- char *cp, Msg[160];
+ const char *cp;
if (time_pps_getcap(instance->pps_h, &cap) < 0) {
- msyslog(LOG_ERR, "time_pps_getcap failed: %m");
+ oncore_log_f(instance, LOG_ERR, "time_pps_getcap failed: %m");
return (0);
}
if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
- msyslog(LOG_ERR, "time_pps_getparams failed: %m");
+ oncore_log_f(instance, LOG_ERR, "time_pps_getparams failed: %m");
return (0);
}
@@ -782,26 +865,27 @@ oncore_ppsapi(
*/
if (instance->assert) {
- cp = "Assert.";
+ cp = "Assert";
mode = PPS_CAPTUREASSERT;
mode1 = PPS_OFFSETASSERT;
} else {
- cp = "Clear.";
+ cp = "Clear";
mode = PPS_CAPTURECLEAR;
mode1 = PPS_OFFSETCLEAR;
}
- sprintf(Msg, "Initializing timeing to %s.", cp);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "Initializing timing to %s.",
+ cp);
if (!(mode & cap)) {
- sprintf(Msg, "Can't set timeing to %s, exiting...", cp);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_ERR,
+ "Can't set timing to %s, exiting...", cp);
return(0);
}
if (!(mode1 & cap)) {
- sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "Can't set %s, this will increase jitter.",
+ cp);
mode1 = 0;
}
@@ -810,8 +894,8 @@ oncore_ppsapi(
instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails");
- exit(1);
+ oncore_log_f(instance, LOG_ERR, "ONCORE: time_pps_setparams fails %m");
+ return(0); /* exit, can't do time_pps_setparans on PPS file */
}
/* If HARDPPS is on, we tell kernel */
@@ -819,7 +903,7 @@ oncore_ppsapi(
if (instance->hardpps) {
int i;
- record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set.");
+ oncore_log(instance, LOG_INFO, "HARDPPS Set.");
if (instance->assert)
i = PPS_CAPTUREASSERT;
@@ -830,11 +914,12 @@ oncore_ppsapi(
if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
PPS_TSFMT_TSPEC) < 0) {
- msyslog(LOG_ERR, "time_pps_kcbind failed: %m");
- record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort...");
+ oncore_log_f(instance, LOG_ERR, "time_pps_kcbind failed: %m");
+ oncore_log(instance, LOG_ERR, "HARDPPS failed, abort...");
return (0);
}
- pps_enable = 1;
+
+ hardpps_enable = 1;
}
return(1);
}
@@ -847,14 +932,13 @@ oncore_init_shmem(
struct instance *instance
)
{
- int i, l, n, fd, shmem_old_size, n1;
- char Msg[160];
+ int l, fd;
u_char *cp, *cp1, *buf, *shmem_old;
struct msg_desc *mp;
struct stat sbuf;
- size_t shmem_length;
+ size_t i, n, n1, shmem_length, shmem_old_size;
- /*
+ /*
* The first thing we do is see if there is an instance->shmem_fname file (still)
* out there from a previous run. If so, we copy it in and use it to initialize
* shmem (so we won't lose our almanac if we need it).
@@ -863,16 +947,13 @@ oncore_init_shmem(
shmem_old = 0;
shmem_old_size = 0;
if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file");
+ oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file");
else {
fstat(fd, &sbuf);
shmem_old_size = sbuf.st_size;
if (shmem_old_size != 0) {
- shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
- if (shmem_old == NULL)
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old");
- else
- read(fd, shmem_old, shmem_old_size);
+ shmem_old = emalloc((unsigned) sbuf.st_size);
+ read(fd, shmem_old, shmem_old_size);
}
close(fd);
}
@@ -880,7 +961,7 @@ oncore_init_shmem(
/* OK, we now create the NEW SHMEM. */
if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem");
+ oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem");
if (shmem_old)
free(shmem_old);
@@ -913,16 +994,7 @@ oncore_init_shmem(
}
shmem_length = n + 2;
- buf = malloc(shmem_length);
- if (buf == NULL) {
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem");
- close(instance->shmemfd);
- if (shmem_old)
- free(shmem_old);
-
- return;
- }
-
+ buf = emalloc(shmem_length);
memset(buf, 0, shmem_length);
/* next build the new SHMEM buffer in memory */
@@ -977,7 +1049,7 @@ oncore_init_shmem(
free(buf);
if (i != shmem_length) {
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem");
+ oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem");
close(instance->shmemfd);
return;
}
@@ -995,9 +1067,9 @@ oncore_init_shmem(
return;
}
- sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s",
- (u_long) shmem_length, instance->shmem_fname);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "SHMEM (size = %ld) is CONFIGURED and available as %s",
+ (u_long) shmem_length, instance->shmem_fname);
}
#endif /* ONCORE_SHMEM_STATUS */
@@ -1014,10 +1086,10 @@ oncore_read_config(
{
/*
* First we try to open the configuration file
- * /etc/oncoreN
+ * /etc/ntp.oncore.N
* where N is the unit number viz 127.127.30.N.
* If we don't find it we try
- * /etc/ntp.oncore.N
+ * /etc/ntp.oncoreN
* and then
* /etc/ntp.oncore
*
@@ -1092,7 +1164,7 @@ oncore_read_config(
* For Flag2, ASSERT=0, and hence is default.
*
* There is an optional line, with HARDPPS on it. Including this line causes
- * the PPS signal to control the kernel PLL.
+ * the PPS signal to control the kernel PLL.
* HARDPPS can also be set with FLAG3 of the ntp.conf input.
* For Flag3, 0 is disabled, and the default.
*
@@ -1118,6 +1190,17 @@ oncore_read_config(
* elevation angle for satellites to be tracked by the receiver. The default value
* is 10 deg for the VP and 0 deg for all other receivers.
*
+ * There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T
+ * receivers, the option is read, but ignored for all others)
+ * and it is followed by:
+ * ON Turn PPS on. This is the default and the default for other
+ * oncore receivers. The PPS is on even if not tracking
+ * any satellites.
+ * SATELLITE Turns PPS on if tracking at least 1 satellite, else off.
+ * TRAIM Turns PPS on or off controlled by TRAIM.
+ * The OFF option is NOT implemented, since the Oncore driver will not work
+ * without the PPS signal.
+ *
* So acceptable input would be
* # these are my coordinates (RWC)
* LON -106 34.610
@@ -1127,22 +1210,25 @@ oncore_read_config(
*/
FILE *fd;
- char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp;
- char *dirs[] = { "/etc/ntp", "/etc", 0 };
+ char *cc, *ca, line[100], units[2], device[64];
+ const char *dirs[] = { "/etc/ntp", "/etc", 0 };
+ const char *cp, **cpp;
int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
double f1, f2, f3;
fd = NULL; /* just to shutup gcc complaint */
for (cpp=dirs; *cpp; cpp++) {
cp = *cpp;
- sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */
+ snprintf(device, sizeof(device), "%s/ntp.oncore.%d",
+ cp, instance->unit); /* try "ntp.oncore.0 */
if ((fd=fopen(device, "r")))
break;
- sprintf(device, "%s/ntp.oncore%d", cp, instance->unit); /* try "ntp.oncore0" */
+ snprintf(device, sizeof(device), "%s/ntp.oncore%d",
+ cp, instance->unit); /* try "ntp.oncore0" */
if ((fd=fopen(device, "r")))
break;
- sprintf(device, "%s/ntp.oncore", cp); /* and finally "ntp.oncore" */
- if ((fd=fopen(device, "r")))
+ snprintf(device, sizeof(device), "%s/ntp.oncore", cp);
+ if ((fd=fopen(device, "r"))) /* last try "ntp.oncore" */
break;
}
@@ -1154,19 +1240,20 @@ oncore_read_config(
mode = mask = 0;
lat_flg = long_flg = ht_flg = 0;
while (fgets(line, 100, fd)) {
+ char *cpw;
/* Remove comments */
- if ((cp = strchr(line, '#')))
- *cp = '\0';
+ if ((cpw = strchr(line, '#')))
+ *cpw = '\0';
/* Remove trailing space */
for (i = strlen(line);
- i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
+ i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]);
)
line[--i] = '\0';
/* Remove leading space */
- for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
+ for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++)
continue;
/* Stop if nothing left */
@@ -1175,29 +1262,27 @@ oncore_read_config(
/* Uppercase the command and find the arg */
for (ca = cc; *ca; ca++) {
- if (isascii((int)*ca)) {
- if (islower((int)*ca)) {
- *ca = toupper(*ca);
- } else if (isspace((int)*ca) || (*ca == '='))
+ if (isascii((unsigned char)*ca)) {
+ if (islower((unsigned char)*ca)) {
+ *ca = toupper((unsigned char)*ca);
+ } else if (isspace((unsigned char)*ca) || (*ca == '='))
break;
}
}
/* Remove space (and possible =) leading the arg */
- for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
+ for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++)
continue;
if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
- i = strlen(ca);
- instance->shmem_fname = (char *) malloc((unsigned) (i+1));
- strcpy(instance->shmem_fname, ca);
+ instance->shmem_fname = estrdup(ca);
continue;
}
/* Uppercase argument as well */
- for (cp = ca; *cp; cp++)
- if (isascii((int)*cp) && islower((int)*cp))
- *cp = toupper(*cp);
+ for (cpw = ca; *cpw; cpw++)
+ if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw))
+ *cpw = toupper((unsigned char)*cpw);
if (!strncmp(cc, "LAT", (size_t) 3)) {
f1 = f2 = f3 = 0;
@@ -1241,10 +1326,11 @@ oncore_read_config(
f1 = 1000000000 * f1;
if (f1 < 0 || f1 > 1.e9)
f1 = 0;
- if (f1 < 0 || f1 > 999999) {
- sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- } else
+ if (f1 < 0 || f1 > 999999)
+ oncore_log_f(instance, LOG_WARNING,
+ "PPS Cable delay of %fns out of Range, ignored",
+ f1);
+ else
instance->delay = f1; /* delay in ns */
} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
f1 = 0;
@@ -1260,10 +1346,11 @@ oncore_read_config(
f1 = 1000000000 * f1;
if (f1 < 0 || f1 > 1.e9)
f1 = 0;
- if (f1 < 0 || f1 > 999999999.) {
- sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- } else
+ if (f1 < 0 || f1 > 999999999.)
+ oncore_log_f(instance, LOG_WARNING,
+ "PPS Offset of %fns out of Range, ignored",
+ f1);
+ else
instance->offset = f1; /* offset in ns */
} else if (!strncmp(cc, "MODE", (size_t) 4)) {
sscanf(ca, "%d", &mode);
@@ -1291,6 +1378,18 @@ oncore_read_config(
sscanf(ca, "%d", &mask);
if (mask > -1 && mask < 90)
instance->Ag = mask; /* Satellite mask angle */
+ } else if (!strncmp(cc,"PPSCONTROL",10)) { /* pps control M12 only */
+ if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) {
+ instance->pps_control = 1; /* PPS always on */
+ } else if (!strcmp(ca,"SATELLITE")) {
+ instance->pps_control = 2; /* PPS on when satellite is available */
+ } else if (!strcmp(ca,"TRAIM")) {
+ instance->pps_control = 3; /* PPS on when TRAIM status is OK */
+ } else {
+ oncore_log_f(instance, LOG_WARNING,
+ "Unknown value \"%s\" for PPSCONTROL, ignored",
+ cc);
+ }
}
}
fclose(fd);
@@ -1302,18 +1401,19 @@ oncore_read_config(
instance->posn_set = 1;
if (!( lat_flg && long_flg && ht_flg )) {
- printf("ONCORE: incomplete data on %s\n", device);
+ oncore_log_f(instance, LOG_WARNING,
+ "ONCORE: incomplete data on %s", device);
instance->posn_set = 0;
if (mode == 1 || mode == 3) {
- sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_WARNING,
+ "Input Mode = %d, but no/incomplete position, mode set to %d",
+ mode, mode+1);
mode++;
}
}
instance->init_type = mode;
- sprintf(Msg, "Input mode = %d", mode);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "Input mode = %d", mode);
}
@@ -1332,21 +1432,31 @@ oncore_receive(
struct peer *peer;
struct instance *instance;
- peer = (struct peer *)rbufp->recv_srcclock;
- instance = (struct instance *) peer->procptr->unitptr;
+ peer = rbufp->recv_peer;
+ instance = peer->procptr->unitptr;
p = (u_char *) &rbufp->recv_space;
-#if 0
+#ifdef ONCORE_VERBOSE_RECEIVE
if (debug > 4) {
int i;
- printf("ONCORE: >>>");
- for(i=0; i<rbufp->recv_length; i++)
- printf("%02x ", p[i]);
- printf("\n");
- printf("ONCORE: >>>");
- for(i=0; i<rbufp->recv_length; i++)
- printf("%03o ", p[i]);
- printf("\n");
+ char Msg[120], Msg2[10];
+
+ oncore_log_f(instance, LOG_DEBUG,
+ ">>> %d bytes available",
+ rbufp->recv_length);
+ strlcpy(Msg, ">>>", sizeof(Msg));
+ for (i = 0; i < rbufp->recv_length; i++) {
+ snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]);
+ strlcat(Msg, Msg2, sizeof(Msg));
+ }
+ oncore_log(instance, LOG_DEBUG, Msg);
+
+ strlcpy(Msg, ">>>", sizeof(Msg));
+ for (i = 0; i < rbufp->recv_length; i++) {
+ snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]);
+ strlcat(Msg, Msg2, sizeof(Msg));
+ }
+ oncore_log(instance, LOG_DEBUG, Msg);
}
#endif
@@ -1369,8 +1479,7 @@ oncore_consume(
struct instance *instance
)
{
- int i, m;
- unsigned l;
+ unsigned i, m, l;
while (rcvptr >= 7) {
if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
@@ -1378,9 +1487,11 @@ oncore_consume(
for (i=1; i < rcvptr-1; i++)
if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
break;
-#ifdef DEBUG
+#ifdef ONCORE_VERBOSE_CONSUME
if (debug > 4)
- printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
+ oncore_log_f(instance, LOG_DEBUG,
+ ">>> skipping %d chars",
+ i);
#endif
if (i != rcvptr)
memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
@@ -1394,9 +1505,11 @@ oncore_consume(
if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
break;
if (m == l) {
-#ifdef DEBUG
+#ifdef ONCORE_VERBOSE_CONSUME
if (debug > 4)
- printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
+ oncore_log_f(instance, LOG_DEBUG,
+ ">>> Unknown MSG, skipping 4 (%c%c)",
+ rcvbuf[2], rcvbuf[3]);
#endif
memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
rcvptr -= 4;
@@ -1404,9 +1517,12 @@ oncore_consume(
}
l = oncore_messages[m].len;
-#if 0
+#ifdef ONCORE_VERBOSE_CONSUME
if (debug > 3)
- printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
+ oncore_log_f(instance, LOG_DEBUG,
+ "GOT: %c%c %d of %d entry %d",
+ instance->unit, rcvbuf[2],
+ rcvbuf[3], rcvptr, l, m);
#endif
/* Got the entire message ? */
@@ -1416,9 +1532,9 @@ oncore_consume(
/* are we at the end of message? should be <Cksum><CR><LF> */
if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
-#ifdef DEBUG
+#ifdef ONCORE_VERBOSE_CONSUME
if (debug)
- printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
+ oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message");
#endif
} else { /* check the CheckSum */
if (oncore_checksum_ok(rcvbuf, l)) {
@@ -1431,13 +1547,18 @@ oncore_consume(
if (oncore_messages[m].handler)
oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
}
-#ifdef DEBUG
+#ifdef ONCORE_VERBOSE_CONSUME
else if (debug) {
- printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
- printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
- for (i=4; i<l; i++)
- printf("%03o ", rcvbuf[i]);
- printf("\n");
+ char Msg[120], Msg2[10];
+
+ oncore_log(instance, LOG_ERR, "Checksum mismatch!");
+ snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]);
+ for (i = 4; i < l; i++) {
+ snprintf(Msg2, sizeof(Msg2),
+ "%03o ", rcvbuf[i]);
+ strlcat(Msg, Msg2, sizeof(Msg));
+ }
+ oncore_log(instance, LOG_DEBUG, Msg);
}
#endif
}
@@ -1467,10 +1588,13 @@ oncore_get_timestamp(
struct timeval *tsp = 0;
#endif
int current_mode;
- u_long i;
pps_params_t current_params;
struct timespec timeout;
+ struct peer *peer;
pps_info_t pps_i;
+ char Msg[160];
+
+ peer = instance->peer;
#if 1
/* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
@@ -1479,18 +1603,22 @@ oncore_get_timestamp(
* This gives good time, which gets better when the SS is done.
*/
- if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
+ if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) {
#else
/* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
- if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
+ if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) {
#endif
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
+ }
/* Don't do anything without an almanac to define the GPS->UTC delta */
- if (instance->rsm.bad_almanac)
+ if (instance->rsm.bad_almanac) {
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
+ }
/* Once the Almanac is valid, the M12+T does not produce valid UTC
* immediately.
@@ -1500,6 +1628,7 @@ oncore_get_timestamp(
if (instance->count5) {
instance->count5--;
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
@@ -1508,51 +1637,66 @@ oncore_get_timestamp(
timeout.tv_nsec = 0;
if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
&timeout) < 0) {
- printf("ONCORE: time_pps_fetch failed\n");
+ oncore_log_f(instance, LOG_ERR,
+ "time_pps_fetch failed %m");
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
if (instance->assert) {
tsp = &pps_i.assert_timestamp;
-#ifdef DEBUG
+#ifdef ONCORE_VERBOSE_GET_TIMESTAMP
if (debug > 2) {
+ u_long i;
+
i = (u_long) pps_i.assert_sequence;
# ifdef HAVE_STRUCT_TIMESPEC
- printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
- instance->unit, i, j,
- (long)tsp->tv_sec, (long)tsp->tv_nsec);
+ oncore_log_f(instance, LOG_DEBUG,
+ "serial/j (%lu, %lu) %ld.%09ld", i,
+ j, (long)tsp->tv_sec,
+ (long)tsp->tv_nsec);
# else
- printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
- instance->unit, i, j,
- (long)tsp->tv_sec, (long)tsp->tv_usec);
+ oncore_log_f(instance, LOG_DEBUG,
+ "serial/j (%lu, %lu) %ld.%06ld", i,
+ j, (long)tsp->tv_sec,
+ (long)tsp->tv_usec);
# endif
}
#endif
if (pps_i.assert_sequence == j) {
- printf("ONCORE: oncore_get_timestamp, error serial pps\n");
+ oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps");
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
+
instance->ev_serial = pps_i.assert_sequence;
} else {
tsp = &pps_i.clear_timestamp;
-#ifdef DEBUG
+#if 0
if (debug > 2) {
+ u_long i;
+
i = (u_long) pps_i.clear_sequence;
# ifdef HAVE_STRUCT_TIMESPEC
- printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
- instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
+ oncore_log_f(instance, LOG_DEBUG,
+ "serial/j (%lu, %lu) %ld.%09ld", i,
+ j, (long)tsp->tv_sec,
+ (long)tsp->tv_nsec);
# else
- printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
- instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
+ oncore_log_f(instance, LOG_DEBUG,
+ "serial/j (%lu, %lu) %ld.%06ld", i,
+ j, (long)tsp->tv_sec,
+ (long)tsp->tv_usec);
# endif
}
#endif
if (pps_i.clear_sequence == j) {
- printf("ONCORE: oncore_get_timestamp, error serial pps\n");
+ oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps");
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
instance->ev_serial = pps_i.clear_sequence;
@@ -1611,12 +1755,16 @@ oncore_get_timestamp(
*/
if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
- msyslog(LOG_ERR, "time_pps_getcap failed: %m");
+ oncore_log_f(instance, LOG_ERR,
+ "time_pps_getcap failed: %m");
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
- msyslog(LOG_ERR, "time_pps_getparams failed: %m");
+ oncore_log_f(instance, LOG_ERR,
+ "time_pps_getparams failed: %m");
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
@@ -1631,7 +1779,7 @@ oncore_get_timestamp(
current_params.clear_offset.tv_nsec = -dt2;
if (time_pps_setparams(instance->pps_h, &current_params))
- record_clock_stats(&(instance->peer->srcadr), "ONCORE: Error doing time_pps_setparams");
+ oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams");
/* have time from UNIX origin, convert to NTP origin. */
@@ -1656,17 +1804,22 @@ oncore_get_timestamp(
if (instance->chan == 6 || instance->chan == 8) {
char f1[5], f2[5], f3[5], f4[5];
if (instance->traim) {
- sprintf(f1, "%d", instance->BEHn[21]);
- sprintf(f2, "%d", instance->BEHn[22]);
- sprintf(f3, "%2d", instance->BEHn[23]*256+instance->BEHn[24]);
- sprintf(f4, "%3d", (s_char) instance->BEHn[25]);
+ snprintf(f1, sizeof(f1), "%d",
+ instance->BEHn[21]);
+ snprintf(f2, sizeof(f2), "%d",
+ instance->BEHn[22]);
+ snprintf(f3, sizeof(f3), "%2d",
+ instance->BEHn[23] * 256 +
+ instance->BEHn[24]);
+ snprintf(f4, sizeof(f4), "%3d",
+ (s_char)instance->BEHn[25]);
} else {
- strcpy(f1, "x");
- strcpy(f2, "x");
- strcpy(f3, "xx");
- strcpy(f4, "xxx");
+ strlcpy(f1, "x", sizeof(f1));
+ strlcpy(f2, "x", sizeof(f2));
+ strlcpy(f3, "xx", sizeof(f3));
+ strlcpy(f4, "xxx", sizeof(f4));
}
- sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 121 */
+ snprintf(Msg, sizeof(Msg), /* MAX length 128, currently at 127 */
"%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d",
ts.l_ui, j,
instance->pp->year, instance->pp->day,
@@ -1684,17 +1837,22 @@ oncore_get_timestamp(
} else if (instance->chan == 12) {
char f1[5], f2[5], f3[5], f4[5];
if (instance->traim) {
- sprintf(f1, "%d", instance->BEHn[6]);
- sprintf(f2, "%d", instance->BEHn[7]);
- sprintf(f3, "%d", instance->BEHn[12]*256+instance->BEHn[13]);
- sprintf(f4, "%3d", (s_char) instance->BEHn[14]);
+ snprintf(f1, sizeof(f1), "%d",
+ instance->BEHn[6]);
+ snprintf(f2, sizeof(f2), "%d",
+ instance->BEHn[7]);
+ snprintf(f3, sizeof(f3), "%d",
+ instance->BEHn[12] * 256 +
+ instance->BEHn[13]);
+ snprintf(f4, sizeof(f4), "%3d",
+ (s_char)instance->BEHn[14]);
} else {
- strcpy(f1, "x");
- strcpy(f2, "x");
- strcpy(f3, "x");
- strcpy(f4, "xxx");
+ strlcpy(f1, "x", sizeof(f1));
+ strlcpy(f2, "x", sizeof(f2));
+ strlcpy(f3, "xx", sizeof(f3));
+ strlcpy(f4, "xxx", sizeof(f4));
}
- sprintf(instance->pp->a_lastcode,
+ snprintf(Msg, sizeof(Msg),
"%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d%d%d%d%d",
ts.l_ui, j,
instance->pp->year, instance->pp->day,
@@ -1712,23 +1870,15 @@ oncore_get_timestamp(
);
}
-#ifdef DEBUG
- if (debug > 2) {
- int n;
-
- n = strlen(instance->pp->a_lastcode);
- printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
- }
-#endif
-
/* and some things I dont understand (magic ntp things) */
if (!refclock_process(instance->pp)) {
refclock_report(instance->peer, CEVNT_BADTIME);
+ peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
return;
}
- record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
+ oncore_log(instance, LOG_INFO, Msg); /* this is long message above */
instance->pollcnt = 2;
if (instance->polled) {
@@ -1737,6 +1887,7 @@ oncore_get_timestamp(
instance->pp->lastref = instance->pp->lastrec;
refclock_receive(instance->peer);
}
+ peer->flags |= FLAG_PPS;
}
@@ -1755,15 +1906,18 @@ oncore_msg_any(
int idx
)
{
+#ifdef ONCORE_VERBOSE_MSG_ANY
int i;
const char *fmt = oncore_messages[idx].fmt;
const char *p;
+ char *q;
+ char *qlim;
#ifdef HAVE_GETCLOCK
struct timespec ts;
#endif
struct timeval tv;
+ char Msg[120], Msg2[10];
-#ifdef DEBUG
if (debug > 3) {
# ifdef HAVE_GETCLOCK
(void) getclock(TIMEOFDAY, &ts);
@@ -1772,26 +1926,36 @@ oncore_msg_any(
# else
GETTIMEOFDAY(&tv, 0);
# endif
- printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
+ oncore_log(instance, LOG_DEBUG, "%ld.%06ld",
+ (long)tv.tv_sec, (long)tv.tv_usec);
if (!*fmt) {
- printf(">>@@%c%c ", buf[2], buf[3]);
- for(i=2; i < len && i < 2400 ; i++)
- printf("%02x", buf[i]);
- printf("\n");
+ snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2],
+ buf[3]);
+ for(i = 2; i < len && i < 2400 ; i++) {
+ snprintf(Msg2, sizeof(Msg2), "%02x",
+ buf[i]);
+ strlcat(Msg, Msg2, sizeof(Msg));
+ }
+ oncore_log(instance, LOG_DEBUG, Msg);
return;
} else {
- printf("##");
- for (p = fmt; *p; p++) {
- putchar(*p);
- putchar('_');
+ strlcpy(Msg, "##", sizeof(Msg));
+ qlim = Msg + sizeof(Msg) - 3;
+ for (p = fmt, q = Msg + 2; q < qlim && *p; ) {
+ *q++ = *p++;
+ *q++ = '_';
}
- printf("\n%c%c", buf[2], buf[3]);
+ *q = '\0';
+ oncore_log(instance, LOG_DEBUG, Msg);
+ snprintf(Msg, sizeof(Msg), "%c%c", buf[2],
+ buf[3]);
i = 4;
for (p = fmt; *p; p++) {
- printf("%02x", buf[i++]);
+ snprintf(Msg2, "%02x", buf[i++]);
+ strlcat(Msg, Msg2, sizeof(Msg));
}
- printf("\n");
+ oncore_log(instance, LOG_DEBUG, Msg);
}
}
#endif
@@ -1820,15 +1984,17 @@ oncore_msg_Ag(
u_char *buf,
size_t len
)
-{ char Msg[160], *cp;
+{
+ const char *cp;
- cp = "set to";
- if (instance->o_state == ONCORE_RUN)
- cp = "is";
+ cp = "set to";
+ if (instance->o_state == ONCORE_RUN)
+ cp = "is";
- instance->Ag = buf[4];
- sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ instance->Ag = buf[4];
+ oncore_log_f(instance, LOG_INFO,
+ "Satellite mask angle %s %d degrees", cp,
+ (int)instance->Ag);
}
@@ -1866,16 +2032,13 @@ oncore_msg_At(
size_t len
)
{
- char *cp;
-
instance->saw_At = 1;
if (instance->site_survey == ONCORE_SS_TESTING) {
if (buf[4] == 2) {
- record_clock_stats(&(instance->peer->srcadr),
+ oncore_log(instance, LOG_NOTICE,
"Initiating hardware 3D site survey");
- cp = "SSstate = ONCORE_SS_HW";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
instance->site_survey = ONCORE_SS_HW;
}
}
@@ -1895,8 +2058,6 @@ oncore_msg_Ay(
size_t len
)
{
- char Msg[120];
-
if (instance->saw_Ay)
return;
@@ -1904,8 +2065,8 @@ oncore_msg_Ay(
instance->offset = buf_w32(&buf[4]);
- sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns",
+ instance->offset);
}
@@ -1921,8 +2082,6 @@ oncore_msg_Az(
size_t len
)
{
- char Msg[120];
-
if (instance->saw_Az)
return;
@@ -1930,8 +2089,8 @@ oncore_msg_Az(
instance->delay = buf_w32(&buf[4]);
- sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns",
+ instance->delay);
}
@@ -1946,7 +2105,6 @@ oncore_msg_BaEaHa(
)
{
const char *cp;
- char Msg[160];
int mode;
/* OK, we are close to the RUN state now.
@@ -1977,21 +2135,20 @@ oncore_msg_BaEaHa(
else /* set from test */
instance->chan = instance->chan_ck;
- sprintf(Msg, "Input says chan = %d", instance->chan_in);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- sprintf(Msg, "Model # says chan = %d", instance->chan_id);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- sprintf(Msg, "Testing says chan = %d", instance->chan_ck);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- sprintf(Msg, "Using chan = %d", instance->chan);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "Input says chan = %d",
+ instance->chan_in);
+ oncore_log_f(instance, LOG_INFO, "Model # says chan = %d",
+ instance->chan_id);
+ oncore_log_f(instance, LOG_INFO, "Testing says chan = %d",
+ instance->chan_ck);
+ oncore_log_f(instance, LOG_INFO, "Using chan = %d",
+ instance->chan);
instance->o_state = ONCORE_HAVE_CHAN;
- cp = "state = ONCORE_HAVE_CHAN";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN");
instance->timeout = 4;
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+ oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
return;
}
@@ -2008,6 +2165,15 @@ oncore_msg_BaEaHa(
memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */
+ /* check if we saw a response to Gc (M12 or M12+T */
+
+ if (instance->pps_control_msg_seen != -2) {
+ if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) {
+ oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)");
+ }
+ instance->pps_control_msg_seen = -2;
+ }
+
/* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
oncore_check_almanac(instance);
@@ -2030,9 +2196,9 @@ oncore_msg_BaEaHa(
/* if not, message out */
if (instance->chan != 12 && !instance->saw_At) {
- cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
- record_clock_stats(&(instance->peer->srcadr), cp);
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
+ oncore_log(instance, LOG_NOTICE,
+ "Not Good, no @@At command (no Position Hold), must be a GT/GT+");
+ oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
}
/* have an Almanac, can start the SiteSurvey
@@ -2046,35 +2212,33 @@ oncore_msg_BaEaHa(
case 1: /* Use given Position */
case 3:
instance->site_survey = ONCORE_SS_DONE;
- cp = "SSstate = ONCORE_SS_DONE";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
break;
case 2:
case 4: /* Site Survey */
- cp = "SSstate = ONCORE_SS_TESTING";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING");
instance->site_survey = ONCORE_SS_TESTING;
instance->count1 = 1;
if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
+ oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
else
- oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
+ oncore_sendmsg(instance, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
break;
}
/* Read back PPS Offset for Output */
/* Nb. This will fail silently for early UT (no plus) and M12 models */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
+ oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
/* Read back Cable Delay for Output */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
+ oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
/* Read back Satellite Mask Angle for Output */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
+ oncore_sendmsg(instance, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
}
@@ -2091,13 +2255,13 @@ oncore_msg_BaEaHa(
if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
instance->count1 = 0;
if (instance->BEHa[130]&0x10) {
- record_clock_stats(&(instance->peer->srcadr),
+ oncore_log(instance, LOG_NOTICE,
"Initiating hardware 3D site survey");
- record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_HW");
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
instance->site_survey = ONCORE_SS_HW;
} else {
- record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
instance->site_survey = ONCORE_SS_SW;
}
}
@@ -2124,19 +2288,19 @@ oncore_msg_BaEaHa(
* We will have to do it ourselves (done above)
*/
- sprintf(Msg, "Initiating software 3D site survey (%d samples)",
- POS_HOLD_AVERAGE);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO,
+ "Initiating software 3D site survey (%d samples)",
+ POS_HOLD_AVERAGE);
- record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
instance->site_survey = ONCORE_SS_SW;
instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
+ oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
else {
- oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
+ oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
+ oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
}
}
}
@@ -2208,7 +2372,7 @@ oncore_msg_BaEaHa(
instance->traim = 0;
instance->traim_delay = 0;
cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_INFO, cp);
oncore_set_traim(instance);
} else
@@ -2249,8 +2413,7 @@ oncore_msg_BaEaHa(
/* if not, and non-zero offset, zero the offset, and send message */
if (!instance->saw_Ay && instance->offset) {
- cp = "No @@Ay command, PPS OFFSET ignored";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored");
instance->offset = 0;
}
}
@@ -2284,11 +2447,10 @@ oncore_msg_Bd(
size_t len
)
{
- char Msg[160];
-
- sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
- ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) );
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
+ ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6],
+ buf[7], w32(&buf[8]));
}
@@ -2313,6 +2475,8 @@ oncore_msg_Bj(
{
const char *cp;
+ instance->saw_Bj = 1;
+
switch(buf[4]) {
case 1:
instance->pp->leap = LEAP_ADDSECOND;
@@ -2328,12 +2492,134 @@ oncore_msg_Bj(
cp = "Set pp.leap to LEAP_NOWARNING";
break;
}
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, cp);
}
static void
+oncore_msg_Bl(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ int subframe, valid, page, i, j, tow;
+ int day_now, day_lsf;
+ const char *cp;
+ enum {
+ WARN_NOT_YET,
+ WARN_0,
+ WARN_PLUS,
+ WARN_MINUS
+ } warn;
+
+ day_now = day_lsf = 0;
+ cp = NULL; /* keep gcc happy */
+
+ subframe = buf[6] & 017;
+ valid = (buf[6] >> 4) & 017;
+ page = buf[7];
+
+ if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) {
+ instance->Bl.dt_ls = buf[32];
+ instance->Bl.WN_lsf = buf[33];
+ instance->Bl.DN_lsf = buf[34];
+ instance->Bl.dt_lsf = buf[35];
+ instance->Bl.lsf_flg++;
+ }
+ if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) {
+ i = (buf[7+7]<<8) + buf[7+8];
+ instance->Bl.WN = i >> 6;
+ tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6];
+ tow >>= 7;
+ tow = tow & 0377777;
+ tow <<= 2;
+ instance->Bl.DN = tow/57600L + 1;
+ instance->Bl.wn_flg++;
+ }
+ if (instance->Bl.wn_flg && instance->Bl.lsf_flg) {
+ instance->Bl.wn_flg = instance->Bl.lsf_flg = 0;
+ oncore_cmd_Bl[2] = 0;
+ oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl);
+ oncore_cmd_Bl[2] = 1;
+
+ i = instance->Bl.WN&01400;
+ instance->Bl.WN_lsf |= i;
+
+ /* have everything I need, doit */
+
+ i = (instance->Bl.WN_lsf - instance->Bl.WN);
+ if (i < 0)
+ i += 1024;
+ day_now = instance->Bl.DN;
+ day_lsf = 7*i + instance->Bl.DN_lsf;
+
+ /* ignore if in past or more than a month in future */
+
+ warn = WARN_NOT_YET;
+ if (day_lsf >= day_now && day_lsf - day_now < 32) {
+ /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */
+ if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) {
+ i = instance->Bl.dt_lsf - instance->Bl.dt_ls;
+ switch (i) {
+ case -1:
+ warn = WARN_MINUS;
+ break;
+ case 0:
+ warn = WARN_0;
+ break;
+ case 1:
+ warn = WARN_PLUS;
+ break;
+ }
+ }
+ }
+
+ switch (warn) {
+ case WARN_0:
+ case WARN_NOT_YET:
+ instance->peer->leap = LEAP_NOWARNING;
+ cp = "Set peer.leap to LEAP_NOWARNING";
+ break;
+ case WARN_MINUS:
+ instance->peer->leap = LEAP_DELSECOND;
+ cp = "Set peer.leap to LEAP_DELSECOND";
+ break;
+ case WARN_PLUS:
+ instance->peer->leap = LEAP_ADDSECOND;
+ cp = "Set peer.leap to LEAP_ADDSECOND";
+ break;
+ }
+ oncore_log(instance, LOG_NOTICE, cp);
+
+ i = instance->Bl.dt_lsf-instance->Bl.dt_ls;
+ if (i) {
+ j = (i >= 0) ? i : -i; /* abs(i) */
+ oncore_log_f(instance, LOG_NOTICE,
+ "see Leap_Second (%c%d) in %d days",
+ ((i >= 0) ? '+' : '-'), j,
+ day_lsf-day_now);
+ }
+ }
+
+/*
+ * Reg only wants the following output for "deeper" driver debugging.
+ * See Bug 2142 and Bug 1866
+ */
+#if 0
+ oncore_log_f(instance, LOG_DEBUG,
+ "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d",
+ instance->Bl.dt_ls, instance->Bl.dt_lsf,
+ instance->Bl.WN, instance->Bl.DN,
+ instance->Bl.WN_lsf, instance->Bl.DN_lsf,
+ instance->Bl.wn_flg, instance->Bl.lsf_flg,
+ instance->Bl.Bl_day);
+#endif
+}
+
+
+static void
oncore_msg_BnEnHn(
struct instance *instance,
u_char *buf,
@@ -2341,7 +2627,6 @@ oncore_msg_BnEnHn(
)
{
long dt1, dt2;
- char *cp;
if (instance->o_state != ONCORE_RUN)
return;
@@ -2349,8 +2634,7 @@ oncore_msg_BnEnHn(
if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */
instance->traim_ck = 1;
instance->traim_delay = 0;
- cp = "ONCORE: Detected TRAIM, TRAIM = ON";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON");
oncore_set_traim(instance);
}
@@ -2363,8 +2647,10 @@ oncore_msg_BnEnHn(
/* If Time RAIM doesn't like it, don't trust it */
if (buf[2] == 'H') {
- if (instance->BEHn[6]) /* bad TRAIM */
+ if (instance->BEHn[6]) { /* bad TRAIM */
+ oncore_log(instance, LOG_WARNING, "BAD TRAIM");
return;
+ }
dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
@@ -2406,7 +2692,6 @@ oncore_msg_CaFaIa(
size_t len
)
{
- char *cp;
int i;
if (instance->o_state == ONCORE_TEST_SENT) {
@@ -2414,12 +2699,16 @@ oncore_msg_CaFaIa(
instance->timeout = 0;
-#ifdef DEBUG
+#if ONCORE_VERBOSE_SELF_TEST
if (debug > 2) {
if (buf[2] == 'I')
- printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
+ oncore_log_f(instance, LOG_DEBUG,
+ ">>@@%ca %x %x %x", buf[2],
+ buf[4], buf[5], buf[6]);
else
- printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
+ oncore_log_f(instance, LOG_DEBUG,
+ ">>@@%ca %x %x", buf[2],
+ buf[4], buf[5]);
}
#endif
@@ -2429,15 +2718,17 @@ oncore_msg_CaFaIa(
i = buf[4] || buf[5];
if (buf[2] == 'I') i = i || buf[6];
if (i) {
- if (buf[2] == 'I') {
- msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x",
- instance->unit, buf[4], buf[5], buf[6]);
- } else {
- msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x",
- instance->unit, buf[4], buf[5]);
- }
- cp = "ONCORE: self test failed, shutting down driver";
- record_clock_stats(&instance->peer->srcadr, cp);
+ if (buf[2] == 'I')
+ oncore_log_f(instance, LOG_ERR,
+ "self test failed: result %02x %02x %02x",
+ buf[4], buf[5], buf[6]);
+ else
+ oncore_log_f(instance, LOG_ERR,
+ "self test failed: result %02x %02x",
+ buf[4], buf[5]);
+
+ oncore_log(instance, LOG_ERR,
+ "ONCORE: self test failed, shutting down driver");
refclock_report(instance->peer, CEVNT_FAULT);
oncore_shutdown(instance->unit, instance->peer);
@@ -2449,11 +2740,10 @@ oncore_msg_CaFaIa(
oncore_antenna_report(instance, antenna);
instance->o_state = ONCORE_INIT;
- cp = "state = ONCORE_INIT";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT");
instance->timeout = 4;
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+ oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
}
}
@@ -2484,10 +2774,7 @@ oncore_msg_Cb(
else if (buf[4] == 4 && buf[5] == 25)
i = 34;
else {
- char *cp;
-
- cp = "Cb: Response is NO ALMANAC";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC");
return;
}
@@ -2495,12 +2782,9 @@ oncore_msg_Cb(
instance->shmem[instance->shmem_Cb + i + 2]++;
memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
-#if 1
- {
- char Msg[160];
- sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- }
+#ifdef ONCORE_VERBOSE_MSG_CB
+ oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4],
+ buf[5]);
#endif
}
@@ -2518,16 +2802,13 @@ oncore_msg_Cf(
size_t len
)
{
- const char *cp;
-
if (instance->o_state == ONCORE_RESET_SENT) {
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
+ oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
/* Reset set VP to IDLE */
instance->o_state = ONCORE_TEST_SENT;
- cp = "state = ONCORE_TEST_SENT";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+ oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
}
}
@@ -2556,7 +2837,6 @@ oncore_msg_Cj(
)
{
int mode;
- char *cp;
memcpy(instance->Cj, buf, len);
@@ -2568,23 +2848,21 @@ oncore_msg_Cj(
mode = instance->init_type;
if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */
instance->o_state = ONCORE_RESET_SENT;
- cp = "state = ONCORE_RESET_SENT";
- record_clock_stats(&(instance->peer->srcadr), cp);
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT");
+ oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
} else {
instance->o_state = ONCORE_TEST_SENT;
- cp = "state = ONCORE_TEST_SENT";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
}
}
if (instance->o_state == ONCORE_TEST_SENT) {
if (instance->chan == 6)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
+ oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
else if (instance->chan == 8)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
+ oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
else if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
+ oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
} else if (instance->o_state == ONCORE_INIT)
oncore_msg_Cj_init(instance, buf, len);
}
@@ -2610,19 +2888,20 @@ oncore_msg_Cj_id(
size_t len
)
{
- char *cp, *cp1, *cp2, Model[21], Msg[160];
+ char *cp2, Model[21];
+ const char *cp, *cp1;
/* Write Receiver ID message to clockstats file */
instance->Cj[294] = '\0';
- for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
- cp1 = strchr(cp, '\r');
- if (!cp1)
- cp1 = (char *)&instance->Cj[294];
- *cp1 = '\0';
- record_clock_stats(&(instance->peer->srcadr), cp);
- *cp1 = '\r';
- cp = cp1+2;
+ for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
+ char *cpw = strchr(cp, '\r');
+ if (!cpw)
+ cpw = (char *)&instance->Cj[294];
+ *cpw = '\0';
+ oncore_log(instance, LOG_NOTICE, cp);
+ *cpw = '\r';
+ cp = cpw+2;
}
/* next, the Firmware Version and Revision numbers */
@@ -2637,7 +2916,7 @@ oncore_msg_Cj_id(
;
cp1 = cp;
cp2 = Model;
- for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
+ for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++)
*cp2 = *cp;
*cp2 = '\0';
@@ -2681,8 +2960,9 @@ oncore_msg_Cj_id(
/* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
- sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO,
+ "This looks like an Oncore %s with version %d.%d firmware.",
+ cp, instance->version, instance->revision);
instance->chan_id = 8; /* default */
if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
@@ -2700,9 +2980,13 @@ oncore_msg_Cj_id(
else if (instance->model == ONCORE_M12)
instance->traim_id = -1;
- sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id,
- ((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF")));
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s",
+ instance->chan_id,
+ ((instance->traim_id < 0)
+ ? "UNKNOWN"
+ : (instance->traim_id > 0)
+ ? "ON"
+ : "OFF"));
}
@@ -2720,8 +3004,7 @@ oncore_msg_Cj_init(
size_t len
)
{
- char *cp, Msg[160];
- u_char Cmd[20];
+ u_char Cmd[20];
int mode;
@@ -2733,17 +3016,18 @@ oncore_msg_Cj_init(
if (instance->chan == 12) {
instance->shmem_bad_Ea = 1;
- sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***",
+ instance->version, instance->revision);
}
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
+ oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
+ oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
+ oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
+ oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
+ oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
+ oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
+ oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
mode = instance->init_type;
@@ -2753,31 +3037,29 @@ oncore_msg_Cj_init(
*/
if (instance->posn_set) {
- record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data");
+ oncore_log(instance, LOG_INFO, "Setting Posn from input data");
oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */
} else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
if (instance->chan != 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
+ oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
if (mode != 0) {
/* cable delay in ns */
memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
- w32_buf(&Cmd[-2+4], instance->delay);
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
+ w32_buf(&Cmd[-2+4], (int)instance->delay);
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
/* PPS offset in ns */
- if (instance->offset) {
- memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
- w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay));
- }
+ memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
+ w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay));
/* Satellite mask angle */
if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */
memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
Cmd[-2+4] = instance->Ag;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ag));
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag));
}
}
@@ -2789,29 +3071,30 @@ oncore_msg_Cj_init(
*/
if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
+ oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
+ oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
+ oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
+ oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
+ oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
} else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
+ oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
+ oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
+ oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
+ oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
+ oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
} else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
+ oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
+ oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
+ oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
+ oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
+ oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
+ oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control;
+ oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */
}
instance->count = 1;
instance->o_state = ONCORE_ALMANAC;
- cp = "state = ONCORE_ALMANAC";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC");
}
@@ -2825,7 +3108,6 @@ oncore_msg_Ga(
size_t len
)
{
- char Msg[160];
long lat, lon, ht;
double Lat, Lon, Ht;
@@ -2842,9 +3124,9 @@ oncore_msg_Ga(
Lon /= 3600000;
Ht /= 100;
-
- sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat,
+ Lon, Ht);
instance->ss_lat = lat;
instance->ss_long = lon;
@@ -2864,7 +3146,7 @@ oncore_msg_Gb(
size_t len
)
{
- char Msg[160], *gmts;
+ const char * gmts;
int mo, d, y, h, m, s, gmth, gmtm;
mo = buf[4];
@@ -2879,9 +3161,27 @@ oncore_msg_Gb(
gmth = buf[12];
gmtm = buf[13];
- sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
- d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
+ d, months[mo-1], y, h, m, s, gmts, gmth, gmtm);
+}
+
+
+
+/* Response to PPS Control message (M12 and M12+T only ) */
+
+static void
+oncore_msg_Gc(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" };
+
+ instance->pps_control_msg_seen = 1;
+ oncore_log_f(instance, LOG_INFO, "PPS Control set to %s",
+ tbl[buf[4]]);
}
@@ -2896,8 +3196,13 @@ oncore_msg_Gj(
size_t len
)
{
+ static const char * insrem[2] = {
+ "removed",
+ "inserted"
+ };
+
int dt;
- char Msg[160], *cp;
+ const char *cp;
instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
@@ -2905,21 +3210,32 @@ oncore_msg_Gj(
dt = buf[5] - buf[4];
-#if 1
- sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
- instance->unit,
- buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
- (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
- buf[15], buf[16], buf[17]);
- record_clock_stats(&(instance->peer->srcadr), Msg);
-#endif
- if (dt) {
- sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
- instance->unit,
- dt, buf[9], Month[buf[8]-1], 256*buf[6]+buf[7],
- buf[15], buf[16], buf[17]);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- }
+ oncore_log_f(instance, LOG_INFO,
+ "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
+ buf[4], buf[5], 256 * buf[6] + buf[7], buf[8],
+ buf[9], buf[10],
+ (buf[14] + 256 *
+ (buf[13] + 256 * (buf[12] + 256 * buf[11]))),
+ buf[15], buf[16], buf[17]);
+
+ /* There seems to be eternal confusion about when a leap second
+ * takes place. It's the second *before* the new TAI offset
+ * becomes effective. But since the ONCORE receiver tells us
+ * just that, we would have to do some time/date calculations to
+ * get the actual leap second -- that is, the one that is
+ * deleted or inserted.
+ *
+ * Going through all this for a simple log is probably overkill,
+ * so for fixing bug#1050 the message output is changed to
+ * reflect the fact that it tells the second after the leap
+ * second.
+ */
+ if (dt)
+ oncore_log_f(instance, LOG_NOTICE,
+ "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u",
+ insrem[(dt > 0)], dt,
+ 256u * buf[6] + buf[7], buf[8], buf[9],
+ buf[15], buf[16], buf[17]);
/* Only raise warning within a month of the leap second */
@@ -2938,7 +3254,7 @@ oncore_msg_Gj(
}
}
}
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_INFO, cp);
}
@@ -2952,11 +3268,8 @@ oncore_msg_Sz(
size_t len
)
{
- const char *cp;
-
- cp = "Oncore: System Failure at Power On";
if (instance && instance->peer) {
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On");
oncore_shutdown(instance->unit, instance->peer);
}
}
@@ -2969,7 +3282,7 @@ oncore_antenna_report(
struct instance *instance,
enum antenna_state new_state)
{
- char *cp;
+ const char *cp;
if (instance->ant_state == new_state)
return;
@@ -2983,7 +3296,7 @@ oncore_antenna_report(
}
instance->ant_state = new_state;
- record_clock_stats(&instance->peer->srcadr, cp);
+ oncore_log(instance, LOG_NOTICE, cp);
}
@@ -2993,8 +3306,6 @@ oncore_chan_test(
struct instance *instance
)
{
- char *cp;
-
/* subroutine oncore_Cj_id has determined the number of channels from the
* model number of the attached oncore. This is not always correct since
* the oncore could have non-standard firmware. Here we check (independently) by
@@ -3005,13 +3316,12 @@ oncore_chan_test(
*/
instance->o_state = ONCORE_CHECK_CHAN;
- cp = "state = ONCORE_CHECK_CHAN";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN");
instance->count3 = 1;
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
+ oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
+ oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
+ oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
}
@@ -3040,20 +3350,20 @@ oncore_check_almanac(
bits3 = instance->BEHa[141]; /* UTC parameters */
if (!instance->count5_set && (bits3 & 0xC0)) {
- instance->count5 = 2;
+ instance->count5 = 4; /* was 2 [Bug 1766] */
instance->count5_set = 1;
}
-#if 0
-{
- char Msg[160];
-
- sprintf(Msg, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x\n",
- instance->unit,
- instance->BEHa[129], instance->BEHa[130], bits1, bits2, bits3, instance->mode == MODE_0D,
- instance->mode == MODE_2D, instance->mode == MODE_3D,
- instance->rsm.bad_almanac, instance->rsm.bad_fix);
- record_clock_stats(&(instance->peer->srcadr), Msg);
-}
+#ifdef ONCORE_VERBOSE_CHECK_ALMANAC
+ oncore_log_f(instance, LOG_DEBUG,
+ "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x",
+ instance->BEHa[129], instance->BEHa[130],
+ bits1, bits2, bits3,
+ instance->mode == MODE_0D,
+ instance->mode == MODE_2D,
+ instance->mode == MODE_3D,
+ instance->rsm.bad_almanac,
+ instance->rsm.bad_fix);
+ }
#endif
}
}
@@ -3108,19 +3418,21 @@ oncore_check_leap_sec(
struct instance *instance
)
{
- if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
+ oncore_cmd_Bl[2] = 1; /* just to be sure */
+ if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
instance->Bj_day = instance->BEHa[5];
if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */
if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
+ oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
+ oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
return;
}
if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */
instance->count4 = 1;
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
+ oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
return;
}
@@ -3134,8 +3446,10 @@ oncore_check_leap_sec(
else if (instance->count4++ > 5) { /* delay, waiting for Gj response */
instance->saw_Gj = -1; /* didnt see it, will use Bj */
instance->count4 = 0;
- if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
+ if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) {
+ oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
+ oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
+ }
}
}
}
@@ -3170,7 +3484,6 @@ oncore_compute_dH(
)
{
int GPS, MSL;
- char Msg[160];
/* Here calculate dH = GPS - MSL for output message */
/* also set Altitude Hold mode if GT */
@@ -3188,10 +3501,9 @@ oncore_compute_dH(
/* if MSL is not set, the calculation is meaningless */
- if (MSL) { /* not set ! */
- sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- }
+ if (MSL) /* not set ! */
+ oncore_log_f(instance, LOG_INFO,
+ "dH = (GPS - MSL) = %.2fm", instance->dH);
}
@@ -3213,44 +3525,40 @@ oncore_load_almanac(
if (!instance->shmem)
return;
-#if 1
- for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
+#ifndef ONCORE_VERBOSE_LOAD_ALMANAC
+ for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
+ cp += (n + 3)) {
if (!strncmp((char *) cp, "@@Cb", 4) &&
oncore_checksum_ok(cp, 33) &&
(*(cp+4) == 4 || *(cp+4) == 5)) {
write(instance->ttyfd, cp, n);
-#if 1
oncore_print_Cb(instance, cp);
-#endif
}
}
-#else
-/************DEBUG************/
- for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
- char Msg[160];
-
- sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
- record_clock_stats(&(instance->peer->srcadr), Msg);
+#else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */
+ for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
+ cp += (n+3)) {
+ oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d",
+ *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
if (!strncmp(cp, "@@Cb", 4)) {
oncore_print_Cb(instance, cp);
if (oncore_checksum_ok(cp, 33)) {
if (*(cp+4) == 4 || *(cp+4) == 5) {
- record_clock_stats(&(instance->peer->srcadr), "GOOD SF");
+ oncore_log(instance, LOG_DEBUG, "GOOD SF");
write(instance->ttyfd, cp, n);
} else
- record_clock_stats(&(instance->peer->srcadr), "BAD SF");
+ oncore_log(instance, LOG_DEBUG, "BAD SF");
} else
- record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM");
+ oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM");
}
}
-/************DEBUG************/
#endif
/* Must load position and time or the Almanac doesn't do us any good */
if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */
- record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM");
+ oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM");
for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) ||
(instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) ||
@@ -3261,12 +3569,11 @@ oncore_load_almanac(
ii = buf_w32(cp + 15);
jj = buf_w32(cp + 19);
kk = buf_w32(cp + 23);
-#if 0
-{
-char Msg[160];
-sprintf(Msg, "SHMEM posn = %ld (%d, %d, %d)", (long) (cp-instance->shmem), ii, jj, kk);
-record_clock_stats(&(instance->peer->srcadr), Msg);
-}
+#ifdef ONCORE_VERBOSE_LOAD_ALMANAC
+ oncore_log_f(instance, LOG_DEBUG,
+ "SHMEM posn = %ld (%d, %d, %d)",
+ (long)(cp-instance->shmem),
+ ii, jj, kk);
#endif
if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
instance->ss_lat = ii;
@@ -3280,15 +3587,13 @@ record_clock_stats(&(instance->peer->srcadr), Msg);
/* and set time to time from Computer clock */
- gettimeofday(&tv, 0);
+ GETTIMEOFDAY(&tv, 0);
tm = gmtime((const time_t *) &tv.tv_sec);
-#if 1
- {
- char Msg[160];
- sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- }
+
+#ifdef ONCORE_VERBOSE_LOAD_ALMANAC
+ oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
if (instance->chan == 12) {
memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
@@ -3302,27 +3607,27 @@ record_clock_stats(&(instance->peer->srcadr), Msg);
Cmd[-2+11] = 0;
Cmd[-2+12] = 0;
Cmd[-2+13] = 0;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb));
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb));
} else {
/* First set GMT offset to zero */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
+ oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
Cmd[-2+4] = tm->tm_mon + 1;
Cmd[-2+5] = tm->tm_mday;
Cmd[-2+6] = (1900+tm->tm_year)/256;
Cmd[-2+7] = (1900+tm->tm_year)%256;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ac));
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ac));
memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
Cmd[-2+4] = tm->tm_hour;
Cmd[-2+5] = tm->tm_min;
Cmd[-2+6] = tm->tm_sec;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Aa));
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa));
}
- record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac");
+ oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac");
}
@@ -3335,18 +3640,23 @@ oncore_print_Cb(
u_char *cp
)
{
-#if 0
+#ifdef ONCORE_VERBOSE_CB
int ii;
- char Msg[160];
+ char Msg[160], Msg2[10];
+
+ oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp),
+ *(cp+1), *(cp+2), *(cp+3));
- printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3));
- printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5));
- for(ii=0; ii<33; ii++)
- printf(" %d", *(cp+ii));
- printf("\n");
+ snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4),
+ *(cp+5));
+ for (ii = 0; ii < 33; ii++) {
+ snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii));
+ strlcat(Msg, Msg2, sizeof(Msg));
+ }
+ oncore_log(instance, LOG_DEBUG, Msg);
- sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5));
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4),
+ *(cp+5));
#endif
}
@@ -3379,12 +3689,12 @@ oncore_print_posn(
struct instance *instance
)
{
- char Msg[120], ew, ns;
+ char ew, ns;
double xd, xm, xs, yd, ym, ys, hm, hft;
int idx, idy, is, imx, imy;
long lat, lon;
- record_clock_stats(&(instance->peer->srcadr), "Posn:");
+ oncore_log(instance, LOG_INFO, "Posn:");
ew = 'E';
lon = instance->ss_long;
if (lon < 0) {
@@ -3404,8 +3714,9 @@ oncore_print_posn(
xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */
yd = lon/3600000.;
- sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO,
+ "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS",
+ ns, xd, ew, yd, hm, hft);
idx = xd;
idy = yd;
@@ -3413,9 +3724,9 @@ oncore_print_posn(
imy = lon%3600000;
xm = imx/60000.;
ym = imy/60000.;
- sprintf(Msg,
- "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO,
+ "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS",
+ ns, idx, xm, ew, idy, ym, hm, hft);
imx = xm;
imy = ym;
@@ -3423,9 +3734,9 @@ oncore_print_posn(
xs = is/1000.;
is = lon%60000;
ys = is/1000.;
- sprintf(Msg,
- "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO,
+ "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS",
+ ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
}
@@ -3436,16 +3747,20 @@ oncore_print_posn(
static void
oncore_sendmsg(
- int fd,
+ struct instance *instance,
u_char *ptr,
size_t len
)
{
+ int fd;
u_char cs = 0;
-#ifdef DEBUG
- if (debug > 4)
- printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
+ fd = instance->ttyfd;
+#ifdef ONCORE_VERBOSE_SENDMSG
+ if (debug > 4) {
+ oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d",
+ ptr[0], ptr[1], (int)len);
+ }
#endif
write(fd, "@@", (size_t) 2);
write(fd, ptr, len);
@@ -3469,10 +3784,10 @@ oncore_set_posn(
will get set ON in @@Ea later */
if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
+ oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
else {
- oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
+ oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
+ oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
}
mode = instance->init_type;
@@ -3483,12 +3798,12 @@ oncore_set_posn(
w32_buf(&Cmd[-2+8], (int) instance->ss_long);
w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
Cmd[-2+16] = 0;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
Cmd[-2+8] = 0;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
/* next set current position */
@@ -3498,28 +3813,28 @@ oncore_set_posn(
w32_buf(&Cmd[-2+8], (int) instance->ss_long);
w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
Cmd[-2+16] = 0;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
} else {
memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
w32_buf(&Cmd[-2+4], (int) instance->ss_long);
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
Cmd[-2+8] = 0;
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
+ oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
}
/* Finally, turn on position hold */
if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
+ oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
else
- oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
+ oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1));
}
}
@@ -3530,32 +3845,30 @@ oncore_set_traim(
struct instance *instance
)
{
- char Msg[160];
-
if (instance->traim_in != -1) /* set in Input */
instance->traim = instance->traim_in;
else
instance->traim = instance->traim_ck;
- sprintf(Msg, "Input says TRAIM = %d", instance->traim_in);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck);
- record_clock_stats(&(instance->peer->srcadr), Msg);
- sprintf(Msg, "Using TRAIM = %d", instance->traim);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_INFO, "Input says TRAIM = %d",
+ instance->traim_in);
+ oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d",
+ instance->traim_id);
+ oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d",
+ instance->traim_ck);
+ oncore_log_f(instance, LOG_INFO, "Using TRAIM = %d",
+ instance->traim);
if (instance->traim_ck == 1 && instance->traim == 0) {
/* if it should be off, and I turned it on during testing,
then turn it off again */
if (instance->chan == 6)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
+ oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
else if (instance->chan == 8)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
+ oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
else /* chan == 12 */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
+ oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
+ oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
}
}
@@ -3574,28 +3887,28 @@ oncore_shmem_get_3D(
instance->shmem_reset = 1;
if (instance->chan == 12) {
if (instance->shmem_Posn == 2)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */
+ oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */
else
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */
+ oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */
} else {
if (instance->saw_At) { /* out of 0D -> 3D mode */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
+ oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0));
if (instance->shmem_Posn == 2) /* 3D -> 2D mode */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
+ oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
} else
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
+ oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
}
} else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
instance->shmem_reset = 0;
if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */
+ oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */
else {
if (instance->saw_At) {
if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
- oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */
+ oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
+ oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */
} else
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
+ oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
}
}
}
@@ -3614,7 +3927,6 @@ oncore_ss(
struct instance *instance
)
{
- char *cp, Msg[160];
double lat, lon, ht;
@@ -3625,15 +3937,14 @@ oncore_ss(
if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) ||
(instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
- record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
+ oncore_log(instance, LOG_INFO, "Now in 0D mode");
if (instance->chan == 12)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
+ oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
else
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
+ oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
- cp = "SSstate = ONCORE_SS_DONE";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
instance->site_survey = ONCORE_SS_DONE;
}
} else {
@@ -3659,22 +3970,22 @@ oncore_ss(
instance->ss_long /= POS_HOLD_AVERAGE;
instance->ss_ht /= POS_HOLD_AVERAGE;
- sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
- instance->ss_lat, instance->ss_long, instance->ss_ht);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
+ instance->ss_lat, instance->ss_long,
+ instance->ss_ht);
lat = instance->ss_lat/3600000.;
lon = instance->ss_long/3600000.;
ht = instance->ss_ht/100;
- sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
- lat, lon, ht);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ oncore_log_f(instance, LOG_NOTICE,
+ "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
+ lat, lon, ht);
oncore_set_posn(instance);
- record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
+ oncore_log(instance, LOG_INFO, "Now in 0D mode");
- cp = "SSstate = ONCORE_SS_DONE";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
instance->site_survey = ONCORE_SS_DONE;
}
}
@@ -3687,10 +3998,9 @@ oncore_wait_almanac(
)
{
if (instance->rsm.bad_almanac) {
-#ifdef DEBUG
- if (debug)
- printf("ONCORE[%d]: waiting for almanac\n", instance->unit);
-#endif
+ instance->counta++;
+ if (instance->counta%5 == 0)
+ oncore_log(instance, LOG_INFO, "Waiting for Almanac");
/*
* If we get here (first time) then we don't have an almanac in memory.
@@ -3707,26 +4017,67 @@ oncore_wait_almanac(
(5sec) and wait for things to settle down */
if (instance->chan == 6)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
+ oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
else if (instance->chan == 8)
- oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
+ oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En));
else if (instance->chan == 12) {
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
+ oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
+ oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
+ oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
}
instance->traim_delay = 1;
- record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC");
+ oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC");
instance->o_state = ONCORE_RUN;
- record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN");
+ oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN");
}
return(0);
}
+static void
+oncore_log (
+ struct instance *instance,
+ int log_level,
+ const char *msg
+ )
+{
+ msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg);
+ mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s",
+ instance->unit, msg);
+}
+
+
+static int
+oncore_log_f(
+ struct instance * instance,
+ int log_level,
+ const char * fmt,
+ ...
+ )
+{
+ va_list ap;
+ int rc;
+ char msg[512];
+
+ va_start(ap, fmt);
+ rc = mvsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ oncore_log(instance, log_level, msg);
+
+#ifdef ONCORE_VERBOSE_ONCORE_LOG
+ instance->max_len = max(strlen(msg), instance->max_len);
+ instance->max_count++;
+ if (instance->max_count % 100 == 0)
+ oncore_log_f(instance, LOG_INFO,
+ "Max Message Length so far is %d",
+ instance->max_len);
+#endif
+ return rc;
+}
+
#else
int refclock_oncore_bs;
-#endif /* REFCLOCK */
+#endif /* REFCLOCK && CLOCK_ONCORE */
diff --git a/contrib/ntp/ntpd/refclock_palisade.c b/contrib/ntp/ntpd/refclock_palisade.c
index adb4659..0520311 100644
--- a/contrib/ntp/ntpd/refclock_palisade.c
+++ b/contrib/ntp/ntpd/refclock_palisade.c
@@ -50,13 +50,28 @@
*
* Version 2.45; July 14, 1999
*
+ *
+ *
+ * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
+ * Contact: Fernando Pablo Hauscarriaga
+ * E-mail: fernandoph@iar.unlp.edu.ar
+ * Home page: www.iar.unlp.edu.ar/~fernandoph
+ * Instituto Argentino de Radioastronomia
+ * www.iar.unlp.edu.ar
+ *
+ * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
+ * now we use mode 2 for decode thunderbolt packets.
+ * Fernando P. Hauscarriaga
+ *
+ * 30/08/09: Added support for Trimble Acutime Gold Receiver.
+ * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
-#if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE))
+#if defined(REFCLOCK) && defined(CLOCK_PALISADE)
#ifdef SYS_WINNT
extern int async_write(int, const void *, unsigned int);
@@ -72,11 +87,11 @@ const int days_of_year [12] = {
#ifdef DEBUG
const char * Tracking_Status[15][15] = {
- { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
- {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
- { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
- { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
- { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
+ { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
+ {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
+ { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
+ { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
+ { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
#endif
/*
@@ -92,7 +107,7 @@ struct refclock refclock_palisade = {
NOFLAGS /* not used */
};
-int day_of_year P((char *dt));
+int day_of_year (char *dt);
/* Extract the clock type from the mode setting */
#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
@@ -100,49 +115,170 @@ int day_of_year P((char *dt));
/* Supported clock types */
#define CLK_TRIMBLE 0 /* Trimble Palisade */
#define CLK_PRAECIS 1 /* Endrun Technologies Praecis */
+#define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */
+#define CLK_ACUTIME 3 /* Trimble Acutime Gold */
+#define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */
int praecis_msg;
static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
+/* These routines are for sending packets to the Thunderbolt receiver
+ * They are taken from Markus Prosch
+ */
+
+#ifdef PALISADE_SENDCMD_RESURRECTED
+/*
+ * sendcmd - Build data packet for sending
+ */
+static void
+sendcmd (
+ struct packettx *buffer,
+ int c
+ )
+{
+ *buffer->data = DLE;
+ *(buffer->data + 1) = (unsigned char)c;
+ buffer->size = 2;
+}
+#endif /* PALISADE_SENDCMD_RESURRECTED */
+
+/*
+ * sendsupercmd - Build super data packet for sending
+ */
+static void
+sendsupercmd (
+ struct packettx *buffer,
+ int c1,
+ int c2
+ )
+{
+ *buffer->data = DLE;
+ *(buffer->data + 1) = (unsigned char)c1;
+ *(buffer->data + 2) = (unsigned char)c2;
+ buffer->size = 3;
+}
+
+/*
+ * sendbyte -
+ */
+static void
+sendbyte (
+ struct packettx *buffer,
+ int b
+ )
+{
+ if (b == DLE)
+ *(buffer->data+buffer->size++) = DLE;
+ *(buffer->data+buffer->size++) = (unsigned char)b;
+}
+
+/*
+ * sendint -
+ */
+static void
+sendint (
+ struct packettx *buffer,
+ int a
+ )
+{
+ sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
+ sendbyte(buffer, (unsigned char)(a & 0xff));
+}
+
+/*
+ * sendetx - Send packet or super packet to the device
+ */
+static int
+sendetx (
+ struct packettx *buffer,
+ int fd
+ )
+{
+ int result;
+
+ *(buffer->data+buffer->size++) = DLE;
+ *(buffer->data+buffer->size++) = ETX;
+ result = write(fd, buffer->data, (unsigned long)buffer->size);
+
+ if (result != -1)
+ return (result);
+ else
+ return (-1);
+}
+
+/*
+ * init_thunderbolt - Prepares Thunderbolt receiver to be used with
+ * NTP (also taken from Markus Prosch).
+ */
+static void
+init_thunderbolt (
+ int fd
+ )
+{
+ struct packettx tx;
+
+ tx.size = 0;
+ tx.data = (u_char *) malloc(100);
+
+ /* set UTC time */
+ sendsupercmd (&tx, 0x8E, 0xA2);
+ sendbyte (&tx, 0x3);
+ sendetx (&tx, fd);
+
+ /* activate packets 0x8F-AB and 0x8F-AC */
+ sendsupercmd (&tx, 0x8F, 0xA5);
+ sendint (&tx, 0x5);
+ sendetx (&tx, fd);
+
+ free(tx.data);
+}
+
+/*
+ * init_acutime - Prepares Acutime Receiver to be used with NTP
+ */
+static void
+init_acutime (
+ int fd
+ )
+{
+ /* Disable all outputs, Enable Event-Polling on PortA so
+ we can ask for time packets */
+ struct packettx tx;
+
+ tx.size = 0;
+ tx.data = (u_char *) malloc(100);
+
+ sendsupercmd(&tx, 0x8E, 0xA5);
+ sendbyte(&tx, 0x02);
+ sendbyte(&tx, 0x00);
+ sendbyte(&tx, 0x00);
+ sendbyte(&tx, 0x00);
+ sendetx(&tx, fd);
+
+ free(tx.data);
+}
+
/*
* palisade_start - open the devices and initialize data for processing
*/
static int
palisade_start (
-#ifdef PALISADE
- unit, peer
- )
- int unit;
- struct peer *peer;
-#else /* ANSI */
int unit,
struct peer *peer
)
-#endif
{
struct palisade_unit *up;
struct refclockproc *pp;
int fd;
char gpsdev[20];
-
struct termios tio;
-#ifdef SYS_WINNT
- (void) sprintf(gpsdev, "COM%d:", unit);
-#else
- (void) sprintf(gpsdev, DEVICE, unit);
-#endif
+
+ snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
+
/*
* Open serial port.
*/
-#if defined PALISADE
- fd = open(gpsdev, O_RDWR
-#ifdef O_NONBLOCK
- | O_NONBLOCK
-#endif
- );
-#else /* NTP 4.x */
fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
-#endif
if (fd <= 0) {
#ifdef DEBUG
printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
@@ -153,87 +289,67 @@ palisade_start (
msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
gpsdev);
-#if defined PALISADE
- tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD);
- tio.c_iflag = (IGNBRK);
- tio.c_oflag = (0);
- tio.c_lflag = (0);
-
- if (cfsetispeed(&tio, SPEED232) == -1) {
- msyslog(LOG_ERR,"Palisade(%d) cfsetispeed(fd, &tio): %m",unit);
-#ifdef DEBUG
- printf("Palisade(%d) cfsetispeed(fd, &tio)\n",unit);
-#endif
- return 0;
- }
- if (cfsetospeed(&tio, SPEED232) == -1) {
-#ifdef DEBUG
- printf("Palisade(%d) cfsetospeed(fd, &tio)\n",unit);
-#endif
- msyslog(LOG_ERR,"Palisade(%d) cfsetospeed(fd, &tio): %m",unit);
- return 0;
- }
-#else /* NTP 4.x */
- if (tcgetattr(fd, &tio) < 0) {
- msyslog(LOG_ERR,
+ if (tcgetattr(fd, &tio) < 0) {
+ msyslog(LOG_ERR,
"Palisade(%d) tcgetattr(fd, &tio): %m",unit);
#ifdef DEBUG
- printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
+ printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
#endif
- return (0);
- }
-
- tio.c_cflag |= (PARENB|PARODD);
- tio.c_iflag &= ~ICRNL;
-#endif /* NTP 4.x */
+ close(fd);
+ return (0);
+ }
- if (tcsetattr(fd, TCSANOW, &tio) == -1) {
- msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
-#ifdef DEBUG
- printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
-#endif
- return 0;
- }
+ tio.c_cflag |= (PARENB|PARODD);
+ tio.c_iflag &= ~ICRNL;
/*
* Allocate and initialize unit structure
*/
- up = (struct palisade_unit *) emalloc(sizeof(struct palisade_unit));
-
- if (!(up)) {
- msyslog(LOG_ERR, "Palisade(%d) emalloc: %m",unit);
-#ifdef DEBUG
- printf("Palisade(%d) emalloc\n",unit);
-#endif
- (void) close(fd);
- return (0);
- }
-
- memset((char *)up, 0, sizeof(struct palisade_unit));
+ up = emalloc_zero(sizeof(*up));
up->type = CLK_TYPE(peer);
switch (up->type) {
- case CLK_TRIMBLE:
- /* Normal mode, do nothing */
- break;
- case CLK_PRAECIS:
- msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled\n",unit);
- break;
- default:
- msyslog(LOG_NOTICE, "Palisade(%d) mode unknown\n",unit);
- break;
+ case CLK_TRIMBLE:
+ /* Normal mode, do nothing */
+ break;
+ case CLK_PRAECIS:
+ msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
+ ,unit);
+ break;
+ case CLK_THUNDERBOLT:
+ msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
+ ,unit);
+ tio.c_cflag = (CS8|CLOCAL|CREAD);
+ break;
+ case CLK_ACUTIME:
+ msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
+ ,unit);
+ break;
+ default:
+ msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
+ break;
+ }
+ if (tcsetattr(fd, TCSANOW, &tio) == -1) {
+ msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
+#ifdef DEBUG
+ printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
+#endif
+ close(fd);
+ free(up);
+ return 0;
}
pp = peer->procptr;
pp->io.clock_recv = palisade_io;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
#ifdef DEBUG
- printf("Palisade(%d) io_addclock\n",unit);
+ printf("Palisade(%d) io_addclock\n",unit);
#endif
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
@@ -241,7 +357,7 @@ palisade_start (
/*
* Initialize miscellaneous variables
*/
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
pp->clockdesc = DESCRIPTION;
peer->precision = PRECISION;
@@ -253,7 +369,12 @@ palisade_start (
up->leap_status = 0;
up->unit = (short) unit;
up->rpt_status = TSIP_PARSED_EMPTY;
- up->rpt_cnt = 0;
+ up->rpt_cnt = 0;
+
+ if (up->type == CLK_THUNDERBOLT)
+ init_thunderbolt(fd);
+ if (up->type == CLK_ACUTIME)
+ init_acutime(fd);
return 1;
}
@@ -264,23 +385,18 @@ palisade_start (
*/
static void
palisade_shutdown (
-#ifdef PALISADE
- unit, peer
- )
- int unit;
- struct peer *peer;
-#else /* ANSI */
int unit,
struct peer *peer
)
-#endif
{
struct palisade_unit *up;
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct palisade_unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -290,29 +406,23 @@ palisade_shutdown (
*/
int
day_of_year (
-#ifdef PALISADE
- dt
- )
- char * dt;
-#else
char * dt
)
-#endif
{
int day, mon, year;
mon = dt[1];
- /* Check month is inside array bounds */
- if ((mon < 1) || (mon > 12))
+ /* Check month is inside array bounds */
+ if ((mon < 1) || (mon > 12))
return -1;
day = dt[0] + days_of_year[mon - 1];
year = getint((u_char *) (dt + 2));
if ( !(year % 4) && ((year % 100) ||
- (!(year % 100) && !(year%400)))
- &&(mon > 2))
- day ++; /* leap year and March or later */
+ (!(year % 100) && !(year%400)))
+ &&(mon > 2))
+ day ++; /* leap year and March or later */
return day;
}
@@ -323,14 +433,8 @@ day_of_year (
*/
int
TSIP_decode (
-#ifdef PALISADE
- peer
- )
- struct peer *peer;
-#else
struct peer *peer
)
-#endif
{
int st;
long secint;
@@ -342,7 +446,7 @@ TSIP_decode (
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct palisade_unit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Check the time packet, decode its contents.
@@ -350,182 +454,436 @@ TSIP_decode (
* proper format, declare bad format and exit.
*/
- if ((up->rpt_buf[0] == (char) 0x41) ||
- (up->rpt_buf[0] == (char) 0x46) ||
- (up->rpt_buf[0] == (char) 0x54) ||
- (up->rpt_buf[0] == (char) 0x4B) ||
- (up->rpt_buf[0] == (char) 0x6D)) {
+ if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
+ if ((up->rpt_buf[0] == (char) 0x41) ||
+ (up->rpt_buf[0] == (char) 0x46) ||
+ (up->rpt_buf[0] == (char) 0x54) ||
+ (up->rpt_buf[0] == (char) 0x4B) ||
+ (up->rpt_buf[0] == (char) 0x6D)) {
- /* standard time packet - GPS time and GPS week number */
+ /* standard time packet - GPS time and GPS week number */
#ifdef DEBUG
printf("Palisade Port B packets detected. Connect to Port A\n");
#endif
- return 0;
+ return 0;
+ }
}
/*
* We cast both to u_char to as 0x8f uses the sign bit on a char
*/
if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
- /*
- * Superpackets
- */
- event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
- if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
- /* Ignore Packet */
+ /*
+ * Superpackets
+ */
+ event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
+ if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
+ /* Ignore Packet */
return 0;
- switch (mb(0) & 0xff) {
- int GPS_UTC_Offset;
- case PACKET_8F0B:
+ switch (mb(0) & 0xff) {
+ int GPS_UTC_Offset;
+ long tow;
- if (up->polled <= 0)
- return 0;
+ case PACKET_8F0B:
- if (up->rpt_cnt != LENCODE_8F0B) /* check length */
- break;
+ if (up->polled <= 0)
+ return 0;
+
+ if (up->rpt_cnt != LENCODE_8F0B) /* check length */
+ break;
#ifdef DEBUG
-if (debug > 1) {
- int ts;
- double lat, lon, alt;
- lat = getdbl((u_char *) &mb(42)) * R2D;
- lon = getdbl((u_char *) &mb(50)) * R2D;
- alt = getdbl((u_char *) &mb(58));
-
- printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
- up->unit, lat,lon,alt);
- printf("TSIP_decode: unit %d: Sats:", up->unit);
- for (st = 66, ts = 0; st <= 73; st++) if (mb(st)) {
- if (mb(st) > 0) ts++;
- printf(" %02d", mb(st));
- }
- printf(" : Tracking %d\n", ts);
- }
+ if (debug > 1) {
+ int ts;
+ double lat, lon, alt;
+ lat = getdbl((u_char *) &mb(42)) * R2D;
+ lon = getdbl((u_char *) &mb(50)) * R2D;
+ alt = getdbl((u_char *) &mb(58));
+
+ printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
+ up->unit, lat,lon,alt);
+ printf("TSIP_decode: unit %d: Sats:",
+ up->unit);
+ for (st = 66, ts = 0; st <= 73; st++)
+ if (mb(st)) {
+ if (mb(st) > 0) ts++;
+ printf(" %02d", mb(st));
+ }
+ printf(" : Tracking %d\n", ts);
+ }
#endif
- GPS_UTC_Offset = getint((u_char *) &mb(16));
- if (GPS_UTC_Offset == 0) { /* Check UTC offset */
+ GPS_UTC_Offset = getint((u_char *) &mb(16));
+ if (GPS_UTC_Offset == 0) { /* Check UTC offset */
#ifdef DEBUG
- printf("TSIP_decode: UTC Offset Unknown\n");
+ printf("TSIP_decode: UTC Offset Unknown\n");
#endif
- break;
- }
+ break;
+ }
- secs = getdbl((u_char *) &mb(3));
- secint = (long) secs;
- secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
+ secs = getdbl((u_char *) &mb(3));
+ secint = (long) secs;
+ secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
- pp->nsec = (long) (secfrac * 1000000000);
+ pp->nsec = (long) (secfrac * 1000000000);
- secint %= 86400; /* Only care about today */
- pp->hour = secint / 3600;
- secint %= 3600;
- pp->minute = secint / 60;
- secint %= 60;
- pp->second = secint % 60;
+ secint %= 86400; /* Only care about today */
+ pp->hour = secint / 3600;
+ secint %= 3600;
+ pp->minute = secint / 60;
+ secint %= 60;
+ pp->second = secint % 60;
- if ((pp->day = day_of_year(&mb(11))) < 0) break;
+ if ((pp->day = day_of_year(&mb(11))) < 0) break;
- pp->year = getint((u_char *) &mb(13));
+ pp->year = getint((u_char *) &mb(13));
#ifdef DEBUG
- if (debug > 1)
- printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02d\n",
- up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
- pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset);
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
+ up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
+ pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset);
#endif
- /* Only use this packet when no
- * 8F-AD's are being received
- */
+ /* Only use this packet when no
+ * 8F-AD's are being received
+ */
- if (up->leap_status) {
- up->leap_status = 0;
- return 0;
- }
+ if (up->leap_status) {
+ up->leap_status = 0;
+ return 0;
+ }
- return 2;
- break;
+ return 2;
+ break;
- case PACKET_NTP:
- /* Palisade-NTP Packet */
+ case PACKET_NTP:
+ /* Palisade-NTP Packet */
- if (up->rpt_cnt != LENCODE_NTP) /* check length */
- break;
+ if (up->rpt_cnt != LENCODE_NTP) /* check length */
+ break;
- up->leap_status = mb(19);
+ up->leap_status = mb(19);
- if (up->polled <= 0)
- return 0;
+ if (up->polled <= 0)
+ return 0;
- /* Check Tracking Status */
- st = mb(18);
- if (st < 0 || st > 14) st = 14;
- if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
+ /* Check Tracking Status */
+ st = mb(18);
+ if (st < 0 || st > 14)
+ st = 14;
+ if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
#ifdef DEBUG
- printf("TSIP_decode: Not Tracking Sats : %s\n",
- *Tracking_Status[st]);
+ printf("TSIP_decode: Not Tracking Sats : %s\n",
+ *Tracking_Status[st]);
#endif
- refclock_report(peer, CEVNT_BADTIME);
- up->polled = -1;
- return 0;
- break;
- }
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+ return 0;
+ break;
+ }
- if (up->leap_status & PALISADE_LEAP_PENDING) {
- if (up->leap_status & PALISADE_UTC_TIME)
- pp->leap = LEAP_ADDSECOND;
- else
- pp->leap = LEAP_DELSECOND;
- }
- else if (up->leap_status)
- pp->leap = LEAP_NOWARNING;
+ up->month = mb(15);
+ if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
+ /* Avoid early announce: https://bugs.ntp.org/2773 */
+ (6 == up->month || 12 == up->month) ) {
+ if (up->leap_status & PALISADE_UTC_TIME)
+ pp->leap = LEAP_ADDSECOND;
+ else
+ pp->leap = LEAP_DELSECOND;
+ }
+ else if (up->leap_status)
+ pp->leap = LEAP_NOWARNING;
- else { /* UTC flag is not set:
- * Receiver may have been reset, and lost
- * its UTC almanac data */
- pp->leap = LEAP_NOTINSYNC;
+ else { /* UTC flag is not set:
+ * Receiver may have been reset, and lost
+ * its UTC almanac data */
+ pp->leap = LEAP_NOTINSYNC;
#ifdef DEBUG
- printf("TSIP_decode: UTC Almanac unavailable: %d\n",
- mb(19));
+ printf("TSIP_decode: UTC Almanac unavailable: %d\n",
+ mb(19));
#endif
- refclock_report(peer, CEVNT_BADTIME);
- up->polled = -1;
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+ return 0;
+ }
+
+ pp->nsec = (long) (getdbl((u_char *) &mb(3))
+ * 1000000000);
+
+ if ((pp->day = day_of_year(&mb(14))) < 0)
+ break;
+ pp->year = getint((u_char *) &mb(16));
+ pp->hour = mb(11);
+ pp->minute = mb(12);
+ pp->second = mb(13);
+ up->month = mb(14); /* Save for LEAP check */
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
+ up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
+ pp->second, pp->nsec, mb(15), mb(14), pp->year,
+ mb(19), *Tracking_Status[st]);
+#endif
+ return 1;
+ break;
+
+ case PACKET_8FAC:
+ if (up->polled <= 0)
+ return 0;
+
+ if (up->rpt_cnt != LENCODE_8FAC)/* check length */
+ break;
+
+#ifdef DEBUG
+ if (debug > 1) {
+ double lat, lon, alt;
+ lat = getdbl((u_char *) &mb(36)) * R2D;
+ lon = getdbl((u_char *) &mb(44)) * R2D;
+ alt = getdbl((u_char *) &mb(52));
+
+ printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
+ up->unit, lat,lon,alt);
+ printf("TSIP_decode: unit %d\n", up->unit);
+ }
+#endif
+ if ( (getint((u_char *) &mb(10)) & 0x80) &&
+ /* Avoid early announce: https://bugs.ntp.org/2773 */
+ (6 == up->month || 12 == up->month) )
+ pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */
+ else
+ pp->leap = LEAP_NOWARNING;
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
+ up->unit, mb(0) & 0xff, pp->leap);
+ if (debug > 1) {
+ printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
+ if (mb(1) == 0x00)
+ printf(" AUTOMATIC\n");
+ if (mb(1) == 0x01)
+ printf(" SINGLE SATELLITE\n");
+ if (mb(1) == 0x03)
+ printf(" HORIZONTAL(2D)\n");
+ if (mb(1) == 0x04)
+ printf(" FULL POSITION(3D)\n");
+ if (mb(1) == 0x05)
+ printf(" DGPR REFERENCE\n");
+ if (mb(1) == 0x06)
+ printf(" CLOCK HOLD(2D)\n");
+ if (mb(1) == 0x07)
+ printf(" OVERDETERMINED CLOCK\n");
+
+ printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
+ if (mb(2) == 0x00)
+ printf(" NORMAL\n");
+ if (mb(2) == 0x01)
+ printf(" POWER-UP\n");
+ if (mb(2) == 0x02)
+ printf(" AUTO HOLDOVER\n");
+ if (mb(2) == 0x03)
+ printf(" MANUAL HOLDOVER\n");
+ if (mb(2) == 0x04)
+ printf(" RECOVERY\n");
+ if (mb(2) == 0x06)
+ printf(" DISCIPLINING DISABLED\n");
+ }
+#endif
return 0;
- }
+ break;
+
+ case PACKET_8FAB:
+ /* Thunderbolt Primary Timing Packet */
+
+ if (up->rpt_cnt != LENCODE_8FAB) /* check length */
+ break;
+
+ if (up->polled <= 0)
+ return 0;
+
+ GPS_UTC_Offset = getint((u_char *) &mb(7));
+
+ if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
+#ifdef DEBUG
+ printf("TSIP_decode: UTC Offset Unknown\n");
+#endif
+ break;
+ }
- pp->nsec = (long) (getdbl((u_char *) &mb(3)) * 1000000000);
- if ((pp->day = day_of_year(&mb(14))) < 0)
+ if ((mb(9) & 0x1d) == 0x0) {
+ /* if we know the GPS time and the UTC offset,
+ we expect UTC timing information !!! */
+
+ pp->leap = LEAP_NOTINSYNC;
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+ return 0;
+ }
+
+ pp->nsec = 0;
+#ifdef DEBUG
+ printf("\nTiming Flags are:\n");
+ printf("Timing flag value is: 0x%X\n", mb(9));
+ if ((mb(9) & 0x01) != 0)
+ printf (" Getting UTC time\n");
+ else
+ printf (" Getting GPS time\n");
+ if ((mb(9) & 0x02) != 0)
+ printf (" PPS is from UTC\n");
+ else
+ printf (" PPS is from GPS\n");
+ if ((mb(9) & 0x04) != 0)
+ printf (" Time is not Set\n");
+ else
+ printf (" Time is Set\n");
+ if ((mb(9) & 0x08) != 0)
+ printf(" I dont have UTC info\n");
+ else
+ printf (" I have UTC info\n");
+ if ((mb(9) & 0x10) != 0)
+ printf (" Time is from USER\n\n");
+ else
+ printf (" Time is from GPS\n\n");
+#endif
+
+ if ((pp->day = day_of_year(&mb(13))) < 0)
+ break;
+ tow = getlong((u_char *) &mb(1));
+#ifdef DEBUG
+ if (debug > 1) {
+ printf("pp->day: %d\n", pp->day);
+ printf("TOW: %ld\n", tow);
+ printf("DAY: %d\n", mb(13));
+ }
+#endif
+ pp->year = getint((u_char *) &mb(15));
+ pp->hour = mb(12);
+ pp->minute = mb(11);
+ pp->second = mb(10);
+
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, pp->nsec, mb(14), mb(13), pp->year);
+#endif
+ return 1;
break;
- pp->year = getint((u_char *) &mb(16));
- pp->hour = mb(11);
- pp->minute = mb(12);
- pp->second = mb(13);
+ default:
+ /* Ignore Packet */
+ return 0;
+ } /* switch */
+ } /* if 8F packets */
+
+ else if (up->rpt_buf[0] == (u_char)0x42) {
+ printf("0x42\n");
+ return 0;
+ }
+ else if (up->rpt_buf[0] == (u_char)0x43) {
+ printf("0x43\n");
+ return 0;
+ }
+ else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
+ printf("Undocumented 0x41 packet on Thunderbolt\n");
+ return 0;
+ }
+ else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
#ifdef DEBUG
- if (debug > 1)
-printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02x %s\n",
- up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
- pp->second, pp->nsec, mb(15), mb(14), pp->year,
- mb(19), *Tracking_Status[st]);
+ printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
+ printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
+ printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
#endif
- return 1;
- break;
+ return 0;
+ }
- default:
- /* Ignore Packet */
+ /* Health Status for Acutime Receiver */
+ else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
+#ifdef DEBUG
+ if (debug > 1)
+ /* Status Codes */
+ switch (mb(0)) {
+ case 0x00:
+ printf ("Doing Position Fixes\n");
+ break;
+ case 0x01:
+ printf ("Do no have GPS time yet\n");
+ break;
+ case 0x03:
+ printf ("PDOP is too high\n");
+ break;
+ case 0x08:
+ printf ("No usable satellites\n");
+ break;
+ case 0x09:
+ printf ("Only 1 usable satellite\n");
+ break;
+ case 0x0A:
+ printf ("Only 2 usable satellites\n");
+ break;
+ case 0x0B:
+ printf ("Only 3 usable satellites\n");
+ break;
+ case 0x0C:
+ printf("The Chosen satellite is unusable\n");
+ break;
+ }
+#endif
+ /* Error Codes */
+ if (mb(1) != 0) {
+
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+#ifdef DEBUG
+ if (debug > 1) {
+ if (mb(1) & 0x01)
+ printf ("Signal Processor Error, reset unit.\n");
+ if (mb(1) & 0x02)
+ printf ("Alignment error, channel or chip 1, reset unit.\n");
+ if (mb(1) & 0x03)
+ printf ("Alignment error, channel or chip 2, reset unit.\n");
+ if (mb(1) & 0x04)
+ printf ("Antenna feed line fault (open or short)\n");
+ if (mb(1) & 0x05)
+ printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
+ }
+#endif
+
+ return 0;
+ }
+ }
+ else if (up->rpt_buf[0] == 0x54)
return 0;
- } /* switch */
- }/* if 8F packets */
+ else if (up->rpt_buf[0] == PACKET_6D) {
+#ifdef DEBUG
+ int sats;
+
+ if ((mb(0) & 0x01) && (mb(0) & 0x02))
+ printf("2d Fix Dimension\n");
+ if (mb(0) & 0x04)
+ printf("3d Fix Dimension\n");
+
+ if (mb(0) & 0x08)
+ printf("Fix Mode is MANUAL\n");
+ else
+ printf("Fix Mode is AUTO\n");
+
+ sats = mb(0) & 0xF0;
+ sats = sats >> 4;
+ printf("Tracking %d Satellites\n", sats);
+#endif
+ return 0;
+ } /* else if not super packet */
refclock_report(peer, CEVNT_BADREPLY);
up->polled = -1;
#ifdef DEBUG
printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
- up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
- event, up->rpt_cnt);
+ up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
+ event, up->rpt_cnt);
#endif
return 0;
}
@@ -536,14 +894,8 @@ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %
static void
palisade_receive (
-#ifdef PALISADE
- peer
- )
- struct peer * peer;
-#else /* ANSI */
struct peer * peer
)
-#endif
{
struct palisade_unit *up;
struct refclockproc *pp;
@@ -552,19 +904,19 @@ palisade_receive (
* Initialize pointers and read the timecode and timestamp.
*/
pp = peer->procptr;
- up = (struct palisade_unit *)pp->unitptr;
+ up = pp->unitptr;
if (! TSIP_decode(peer)) return;
if (up->polled <= 0)
- return; /* no poll pending, already received or timeout */
+ return; /* no poll pending, already received or timeout */
up->polled = 0; /* Poll reply received */
pp->lencode = 0; /* clear time code */
#ifdef DEBUG
if (debug)
printf(
- "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n",
+ "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
up->unit, pp->year, pp->day, pp->hour, pp->minute,
pp->second, pp->nsec);
#endif
@@ -575,23 +927,18 @@ palisade_receive (
* report and process
*/
- (void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld",
- pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->nsec);
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%4d %03d %02d:%02d:%02d.%09ld",
+ pp->year, pp->day,
+ pp->hour,pp->minute, pp->second, pp->nsec);
pp->lencode = 24;
-#ifdef PALISADE
- pp->lasttime = current_time;
-#endif
- if (!refclock_process(pp
-#ifdef PALISADE
- , PALISADE_SAMPLES, PALISADE_SAMPLES * 3 / 5
-#endif
- )) {
+ if (!refclock_process(pp)) {
refclock_report(peer, CEVNT_BADTIME);
#ifdef DEBUG
printf("palisade_receive: unit %d: refclock_process failed!\n",
- up->unit);
+ up->unit);
#endif
return;
}
@@ -600,16 +947,11 @@ palisade_receive (
#ifdef DEBUG
if (debug)
- printf("palisade_receive: unit %d: %s\n",
- up->unit, prettydate(&pp->lastrec));
+ printf("palisade_receive: unit %d: %s\n",
+ up->unit, prettydate(&pp->lastrec));
#endif
pp->lastref = pp->lastrec;
- refclock_receive(peer
-#ifdef PALISADE
- , &pp->offset, 0, pp->dispersion,
- &pp->lastrec, &pp->lastrec, pp->leap
-#endif
- );
+ refclock_receive(peer);
}
@@ -619,38 +961,31 @@ palisade_receive (
*/
static void
palisade_poll (
-#ifdef PALISADE
- unit, peer
- )
- int unit;
- struct peer *peer;
-#else
int unit,
struct peer *peer
)
-#endif
{
struct palisade_unit *up;
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct palisade_unit *)pp->unitptr;
+ up = pp->unitptr;
pp->polls++;
if (up->polled > 0) /* last reply never arrived or error */
- refclock_report(peer, CEVNT_TIMEOUT);
+ refclock_report(peer, CEVNT_TIMEOUT);
up->polled = 2; /* synchronous packet + 1 event */
#ifdef DEBUG
if (debug)
- printf("palisade_poll: unit %d: polling %s\n", unit,
- (pp->sloppyclockflag & CLK_FLAG2) ?
- "synchronous packet" : "event");
+ printf("palisade_poll: unit %d: polling %s\n", unit,
+ (pp->sloppyclockflag & CLK_FLAG2) ?
+ "synchronous packet" : "event");
#endif
if (pp->sloppyclockflag & CLK_FLAG2)
- return; /* using synchronous packet input */
+ return; /* using synchronous packet input */
if(up->type == CLK_PRAECIS) {
if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
@@ -662,11 +997,14 @@ palisade_poll (
}
if (HW_poll(pp) < 0)
- refclock_report(peer, CEVNT_FAULT);
+ refclock_report(peer, CEVNT_FAULT);
}
static void
-praecis_parse(struct recvbuf *rbufp, struct peer *peer)
+praecis_parse (
+ struct recvbuf *rbufp,
+ struct peer *peer
+ )
{
static char buf[100];
static int p = 0;
@@ -692,14 +1030,8 @@ praecis_parse(struct recvbuf *rbufp, struct peer *peer)
static void
palisade_io (
-#ifdef PALISADE
- rbufp
- )
- struct recvbuf *rbufp;
-#else /* ANSI */
struct recvbuf *rbufp
)
-#endif
{
/*
* Initialize pointers and read the timecode and timestamp.
@@ -710,9 +1042,9 @@ palisade_io (
char * c, * d;
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct palisade_unit *)pp->unitptr;
+ up = pp->unitptr;
if(up->type == CLK_PRAECIS) {
if(praecis_msg) {
@@ -748,21 +1080,21 @@ palisade_io (
case TSIP_PARSED_DATA:
if (*c == DLE)
- up->rpt_status = TSIP_PARSED_DLE_2;
+ up->rpt_status = TSIP_PARSED_DLE_2;
else
- mb(up->rpt_cnt++) = *c;
+ mb(up->rpt_cnt++) = *c;
break;
case TSIP_PARSED_DLE_2:
if (*c == DLE) {
up->rpt_status = TSIP_PARSED_DATA;
mb(up->rpt_cnt++) =
- *c;
- }
+ *c;
+ }
else if (*c == ETX)
- up->rpt_status = TSIP_PARSED_FULL;
+ up->rpt_status = TSIP_PARSED_FULL;
else {
- /* error: start new report packet */
+ /* error: start new report packet */
up->rpt_status = TSIP_PARSED_DLE_1;
up->rpt_buf[0] = *c;
}
@@ -771,23 +1103,23 @@ palisade_io (
case TSIP_PARSED_FULL:
case TSIP_PARSED_EMPTY:
default:
- if ( *c != DLE)
- up->rpt_status = TSIP_PARSED_EMPTY;
- else
- up->rpt_status = TSIP_PARSED_DLE_1;
- break;
+ if ( *c != DLE)
+ up->rpt_status = TSIP_PARSED_EMPTY;
+ else
+ up->rpt_status = TSIP_PARSED_DLE_1;
+ break;
}
c++;
if (up->rpt_status == TSIP_PARSED_DLE_1) {
- up->rpt_cnt = 0;
+ up->rpt_cnt = 0;
if (pp->sloppyclockflag & CLK_FLAG2)
- /* stamp it */
- get_systime(&pp->lastrec);
+ /* stamp it */
+ get_systime(&pp->lastrec);
}
else if (up->rpt_status == TSIP_PARSED_EMPTY)
- up->rpt_cnt = 0;
+ up->rpt_cnt = 0;
else if (up->rpt_cnt > BMAX)
up->rpt_status =TSIP_PARSED_EMPTY;
@@ -807,26 +1139,18 @@ palisade_io (
*/
long
HW_poll (
-#ifdef PALISADE
- pp /* pointer to unit structure */
- )
- struct refclockproc * pp; /* pointer to unit structure */
-#else
struct refclockproc * pp /* pointer to unit structure */
)
-#endif
{
int x; /* state before & after RTS set */
struct palisade_unit *up;
- up = (struct palisade_unit *) pp->unitptr;
+ up = pp->unitptr;
/* read the current status, so we put things back right */
if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
-#ifdef DEBUG
- if (debug)
- printf("Palisade HW_poll: unit %d: GET %s\n", up->unit, strerror(errno));
-#endif
+ DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
+ up->unit));
msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
up->unit);
return -1;
@@ -835,10 +1159,13 @@ HW_poll (
x |= TIOCM_RTS; /* turn on RTS */
/* Edge trigger */
+ if (up->type == CLK_ACUTIME)
+ write (pp->io.fd, "", 1);
+
if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
#ifdef DEBUG
- if (debug)
- printf("Palisade HW_poll: unit %d: SET \n", up->unit);
+ if (debug)
+ printf("Palisade HW_poll: unit %d: SET \n", up->unit);
#endif
msyslog(LOG_ERR,
"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
@@ -853,8 +1180,8 @@ HW_poll (
if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
#ifdef DEBUG
- if (debug)
- printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
+ if (debug)
+ printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
#endif
msyslog(LOG_ERR,
"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
@@ -865,91 +1192,68 @@ HW_poll (
return 0;
}
-#if 0 /* unused */
/*
- * this 'casts' a character array into a float
+ * copy/swap a big-endian palisade double into a host double
*/
-float
-getfloat (
-#ifdef PALISADE
- bp
- )
- u_char *bp;
-#else
+static double
+getdbl (
u_char *bp
)
-#endif
{
- float sval;
-#ifdef WORDS_BIGENDIAN
- ((char *) &sval)[0] = *bp++;
- ((char *) &sval)[1] = *bp++;
- ((char *) &sval)[2] = *bp++;
- ((char *) &sval)[3] = *bp++;
+#ifdef WORDS_BIGENDIAN
+ double out;
+
+ memcpy(&out, bp, sizeof(out));
+ return out;
#else
- ((char *) &sval)[3] = *bp++;
- ((char *) &sval)[2] = *bp++;
- ((char *) &sval)[1] = *bp++;
- ((char *) &sval)[0] = *bp;
-#endif /* ! XNTP_BIG_ENDIAN */
- return sval;
-}
+ union {
+ u_char ch[8];
+ u_int32 u32[2];
+ } ui;
+
+ union {
+ double out;
+ u_int32 u32[2];
+ } uo;
+
+ memcpy(ui.ch, bp, sizeof(ui.ch));
+ /* least-significant 32 bits of double from swapped bp[4] to bp[7] */
+ uo.u32[0] = ntohl(ui.u32[1]);
+ /* most-significant 32 bits from swapped bp[0] to bp[3] */
+ uo.u32[1] = ntohl(ui.u32[0]);
+
+ return uo.out;
#endif
+}
/*
- * this 'casts' a character array into a double
+ * copy/swap a big-endian palisade short into a host short
*/
-double
-getdbl (
-#ifdef PALISADE
- bp
- )
- u_char *bp;
-#else
+static short
+getint (
u_char *bp
)
-#endif
{
- double dval;
-#ifdef WORDS_BIGENDIAN
- ((char *) &dval)[0] = *bp++;
- ((char *) &dval)[1] = *bp++;
- ((char *) &dval)[2] = *bp++;
- ((char *) &dval)[3] = *bp++;
- ((char *) &dval)[4] = *bp++;
- ((char *) &dval)[5] = *bp++;
- ((char *) &dval)[6] = *bp++;
- ((char *) &dval)[7] = *bp;
-#else
- ((char *) &dval)[7] = *bp++;
- ((char *) &dval)[6] = *bp++;
- ((char *) &dval)[5] = *bp++;
- ((char *) &dval)[4] = *bp++;
- ((char *) &dval)[3] = *bp++;
- ((char *) &dval)[2] = *bp++;
- ((char *) &dval)[1] = *bp++;
- ((char *) &dval)[0] = *bp;
-#endif /* ! XNTP_BIG_ENDIAN */
- return dval;
+ u_short us;
+
+ memcpy(&us, bp, sizeof(us));
+ return (short)ntohs(us);
}
/*
- * cast a 16 bit character array into a short (16 bit) int
+ * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
*/
-short
-getint (
-#ifdef PALISADE
- bp
- )
- u_char *bp;
-#else
+static int32
+getlong(
u_char *bp
)
-#endif
{
-return (short) (bp[1] + (bp[0] << 8));
+ u_int32 u32;
+
+ memcpy(&u32, bp, sizeof(u32));
+ return (int32)(u_int32)ntohl(u32);
}
-#else
-int refclock_palisade_bs;
-#endif /* REFCLOCK */
+#else /* REFCLOCK && CLOCK_PALISADE*/
+int refclock_palisade_c_notempty;
+#endif
diff --git a/contrib/ntp/ntpd/refclock_palisade.h b/contrib/ntp/ntpd/refclock_palisade.h
index e63f3da..3782a5e 100644
--- a/contrib/ntp/ntpd/refclock_palisade.h
+++ b/contrib/ntp/ntpd/refclock_palisade.h
@@ -50,12 +50,8 @@
*
*/
-#ifndef _REFCLOCK_PALISADE_H
-#define _REFCLOCK_PALISADE_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#ifndef REFCLOCK_PALISADE_H
+#define REFCLOCK_PALISADE_H
#if defined HAVE_SYS_MODEM_H
#include <sys/modem.h>
@@ -71,6 +67,7 @@
# define _SVID3
# endif
# include <termios.h>
+# include <sys/stat.h>
# ifdef TERMIOS_NEEDS__SVID3
# undef _SVID3
# endif
@@ -108,10 +105,23 @@
#define LENCODE_8F0B 74 /* Length of TSIP 8F-0B Packet & header */
#define LENCODE_NTP 22 /* Length of Palisade NTP Packet */
+#define LENCODE_8FAC 68 /* Length of Thunderbolt 8F-AC Position Packet*/
+#define LENCODE_8FAB 17 /* Length of Thunderbolt Primary Timing Packet*/
+
/* Allowed Sub-Packet ID's */
#define PACKET_8F0B 0x0B
#define PACKET_NTP 0xAD
+/* Thunderbolt Packets */
+#define PACKET_8FAC 0xAC /* Supplementary Thunderbolt Time Packet */
+#define PACKET_8FAB 0xAB /* Primary Thunderbolt Time Packet */
+#define PACKET_6D 0x6D /* Supplementary Thunderbolt Tracking Stats */
+#define PACKET_41 0x41 /* Thunderbolt I dont know what this packet is, it's not documented on my manual*/
+
+/* Acutime Packets */
+#define PACKET_41A 0x41 /* GPS time */
+#define PACKET_46 0x46 /* Receiver Health */
+
#define DLE 0x10
#define ETX 0x03
@@ -139,6 +149,16 @@
#define R2D (180.0/GPS_PI)
/*
+ * Structure for build data packets for send (thunderbolt uses it only)
+ * taken from Markus Prosch
+ */
+struct packettx
+{
+ short size;
+ u_char *data;
+};
+
+/*
* Palisade unit control structure.
*/
struct palisade_unit {
@@ -147,24 +167,36 @@ struct palisade_unit {
char leap_status; /* leap second flag */
char rpt_status; /* TSIP Parser State */
short rpt_cnt; /* TSIP packet length so far */
- char rpt_buf[BMAX]; /* packet assembly buffer */
+ char rpt_buf[BMAX]; /* packet assembly buffer */
int type; /* Clock mode type */
+ int month; /* for LEAP filter */
};
/*
* Function prototypes
*/
-static int palisade_start P((int, struct peer *));
-static void palisade_shutdown P((int, struct peer *));
-static void palisade_receive P((struct peer *));
-static void palisade_poll P((int, struct peer *));
-static void palisade_io P((struct recvbuf *));
-int palisade_configure P((int, struct peer *));
-int TSIP_decode P((struct peer *));
-long HW_poll P((struct refclockproc *));
-float getfloat P((u_char *));
-double getdbl P((u_char *));
-short getint P((u_char *));
-
-#endif /* PALISADE_H */
+static int palisade_start (int, struct peer *);
+static void palisade_shutdown (int, struct peer *);
+static void palisade_receive (struct peer *);
+static void palisade_poll (int, struct peer *);
+static void palisade_io (struct recvbuf *);
+int palisade_configure (int, struct peer *);
+int TSIP_decode (struct peer *);
+long HW_poll (struct refclockproc *);
+static double getdbl (u_char *);
+static short getint (u_char *);
+static int32 getlong (u_char *);
+
+
+#ifdef PALISADE_SENDCMD_RESURRECTED
+static void sendcmd (struct packettx *buffer, int c);
+#endif
+static void sendsupercmd (struct packettx *buffer, int c1, int c2);
+static void sendbyte (struct packettx *buffer, int b);
+static void sendint (struct packettx *buffer, int a);
+static int sendetx (struct packettx *buffer, int fd);
+static void init_thunderbolt (int fd);
+static void init_acutime (int fd);
+
+#endif /* REFCLOCK_PALISADE_H */
diff --git a/contrib/ntp/ntpd/refclock_parse.c b/contrib/ntp/ntpd/refclock_parse.c
index 0b0109c..147a462 100644
--- a/contrib/ntp/ntpd/refclock_parse.c
+++ b/contrib/ntp/ntpd/refclock_parse.c
@@ -1,7 +1,7 @@
/*
- * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
+ * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
*
- * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
+ * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
*
* generic reference clock driver for several DCF/GPS/MSF/... receivers
*
@@ -15,8 +15,8 @@
* Currently the STREAMS module is only available for Suns running
* SunOS 4.x and SunOS5.x.
*
- * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org>
- * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
+ * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
+ * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -48,40 +48,42 @@
# include "config.h"
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_PARSE)
/*
* This driver currently provides the support for
- * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF)
- * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF)
- * - Meinberg receiver DCF77 PZF 509 (DCF)
+ * - Meinberg receiver DCF77 PZF535 (TCXO version) (DCF)
+ * - Meinberg receiver DCF77 PZF535 (OCXO version) (DCF)
+ * - Meinberg receiver DCF77 PZF509 (DCF)
* - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF)
* - IGEL CLOCK (DCF)
* - ELV DCF7000 (DCF)
* - Schmid clock (DCF)
* - Conrad DCF77 receiver module (DCF)
* - FAU DCF77 NTP receiver (TimeBrick) (DCF)
- * - WHARTON 400A Series clock (DCF)
+ * - WHARTON 400A Series clock (DCF)
*
- * - Meinberg GPS166/GPS167 (GPS)
+ * - Meinberg GPS receivers (GPS)
* - Trimble (TSIP and TAIP protocol) (GPS)
*
* - RCC8000 MSF Receiver (MSF)
- * - VARITEXT clock (MSF)
+ * - VARITEXT clock (MSF)
*/
/*
* Meinberg receivers are usually connected via a
- * 9600 baud serial line
+ * 9600/7E1 or 19200/8N1 serial line.
*
* The Meinberg GPS receivers also have a special NTP time stamp
* format. The firmware release is Uni-Erlangen.
*
* Meinberg generic receiver setup:
- * output time code every second
- * Baud rate 9600 7E2S
+ * output time code every second
+ * Baud rate 9600 7E2S
*
- * Meinberg GPS16x setup:
+ * Meinberg GPS receiver setup:
* output time code every second
* Baudrate 19200 8N1
*
@@ -89,14 +91,16 @@
* in Meinberg receivers.
*
* Special software versions are only sensible for the
- * GPS 16x family of receivers.
+ * oldest GPS receiver, GPS16x. For newer receiver types
+ * the output string format can be configured at the device,
+ * and the device name is generally GPSxxx instead of GPS16x.
*
* Meinberg can be reached via: http://www.meinberg.de/
*/
#include "ntpd.h"
#include "ntp_refclock.h"
-#include "ntp_unixtime.h" /* includes <sys/time.h> */
+#include "timevalops.h" /* includes <sys/time.h> */
#include "ntp_control.h"
#include "ntp_string.h"
@@ -120,6 +124,7 @@
#endif
#ifdef HAVE_TERMIOS
+# include <termios.h>
# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
# undef HAVE_SYSV_TTYS
@@ -141,6 +146,7 @@
#ifdef HAVE_PPSAPI
# include "ppsapi_timepps.h"
+# include "refclock_atom.h"
#endif
#ifdef PPS
@@ -152,13 +158,13 @@
# endif
#endif
-#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
-#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
+# define BUFFER_SIZE(_BUF, _PTR) ((int)((_BUF) + sizeof(_BUF) - (_PTR)))
+# define BUFFER_SIZES(_BUF, _PTR, _SZ) ((int)((_BUF) + (_SZ) - (_PTR)))
/*
* document type of PPS interfacing - copy of ifdef mechanism in local_input()
*/
-#undef PPS_METHOD
+#undef PPS_METHOD
#ifdef HAVE_PPSAPI
#define PPS_METHOD "PPS API"
@@ -177,6 +183,18 @@
#endif /* TIOCDCDTIMESTAMP */
#endif /* HAVE_PPSAPI */
+/*
+ * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF
+ * then some more parse-specific variables are flagged to be printed with
+ * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF
+ * should be defined as 0.
+ */
+#if 0
+# define COND_DEF DEF // enable this for testing
+#else
+# define COND_DEF 0 // enable this by default
+#endif
+
#include "ntp_io.h"
#include "ntp_stdlib.h"
@@ -188,16 +206,16 @@
#include "ieee754io.h"
#include "recvbuff.h"
-static char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp";
+static char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST";
/**===========================================================================
** external interface to ntp mechanism
**/
-static int parse_start P((int, struct peer *));
-static void parse_shutdown P((int, struct peer *));
-static void parse_poll P((int, struct peer *));
-static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
+static int parse_start (int, struct peer *);
+static void parse_shutdown (int, struct peer *);
+static void parse_poll (int, struct peer *);
+static void parse_control (int, const struct refclockstat *, struct refclockstat *, struct peer *);
struct refclock refclock_parse = {
parse_start,
@@ -231,16 +249,16 @@ struct parseunit; /* to keep inquiring minds happy */
typedef struct bind
{
const char *bd_description; /* name of type of binding */
- int (*bd_init) P((struct parseunit *)); /* initialize */
- void (*bd_end) P((struct parseunit *)); /* end */
- int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */
- int (*bd_disable) P((struct parseunit *)); /* disable */
- int (*bd_enable) P((struct parseunit *)); /* enable */
- int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */
- int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */
- int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */
- void (*bd_receive) P((struct recvbuf *)); /* receive operation */
- int (*bd_io_input) P((struct recvbuf *)); /* input operation */
+ int (*bd_init) (struct parseunit *); /* initialize */
+ void (*bd_end) (struct parseunit *); /* end */
+ int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */
+ int (*bd_disable) (struct parseunit *); /* disable */
+ int (*bd_enable) (struct parseunit *); /* enable */
+ int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */
+ int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */
+ int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */
+ void (*bd_receive) (struct recvbuf *); /* receive operation */
+ int (*bd_io_input) (struct recvbuf *); /* input operation */
} bind_t;
#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
@@ -252,12 +270,11 @@ typedef struct bind
#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
/*
- * io modes
+ * special handling flags
*/
-#define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */
-#define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */
-
-
+#define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */
+#define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */
+ /* trusttime after SYNC was seen */
/**===========================================================================
** error message regression handling
**
@@ -379,7 +396,7 @@ struct parseunit
* PARSE io
*/
bind_t *binding; /* io handling binding */
-
+
/*
* parse state
*/
@@ -405,9 +422,8 @@ struct parseunit
u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
int ppsfd; /* fd to ise for PPS io */
#ifdef HAVE_PPSAPI
- pps_handle_t ppshandle; /* store PPSAPI handle */
- pps_params_t ppsparams; /* current PPS parameters */
int hardppsstate; /* current hard pps state */
+ struct refclock_atom atom; /* PPSAPI structure */
#endif
parsetime_t timedata; /* last (parse module) data */
void *localdata; /* optional local, receiver-specific data */
@@ -423,9 +439,9 @@ struct parseunit
** includes NTP parameters, TTY parameters and IO handling parameters
**/
-static void poll_dpoll P((struct parseunit *));
-static void poll_poll P((struct peer *));
-static int poll_init P((struct parseunit *));
+static void poll_dpoll (struct parseunit *);
+static void poll_poll (struct peer *);
+static int poll_init (struct parseunit *);
typedef struct poll_info
{
@@ -448,23 +464,23 @@ typedef struct poll_info
#define DCF_P_ID "DCFp" /* psuedo random phase shift */
#define GPS_ID "GPS" /* GPS receiver */
-#define NOCLOCK_ROOTDELAY 0.0
-#define NOCLOCK_BASEDELAY 0.0
-#define NOCLOCK_DESCRIPTION 0
+#define NOCLOCK_ROOTDELAY 0.0
+#define NOCLOCK_BASEDELAY 0.0
+#define NOCLOCK_DESCRIPTION 0
#define NOCLOCK_MAXUNSYNC 0
#define NOCLOCK_CFLAG 0
#define NOCLOCK_IFLAG 0
#define NOCLOCK_OFLAG 0
#define NOCLOCK_LFLAG 0
-#define NOCLOCK_ID "TILT"
-#define NOCLOCK_POLL NO_POLL
-#define NOCLOCK_INIT NO_INIT
-#define NOCLOCK_END NO_END
-#define NOCLOCK_DATA NO_LCLDATA
-#define NOCLOCK_FORMAT ""
-#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
-#define NOCLOCK_SAMPLES 0
-#define NOCLOCK_KEEP 0
+#define NOCLOCK_ID "TILT"
+#define NOCLOCK_POLL NO_POLL
+#define NOCLOCK_INIT NO_INIT
+#define NOCLOCK_END NO_END
+#define NOCLOCK_DATA NO_LCLDATA
+#define NOCLOCK_FORMAT ""
+#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
+#define NOCLOCK_SAMPLES 0
+#define NOCLOCK_KEEP 0
#define DCF_TYPE CTL_SST_TS_LF
#define GPS_TYPE CTL_SST_TS_UHF
@@ -534,14 +550,14 @@ typedef struct poll_info
#define DCFPZF535OCXO_FORMAT "Meinberg Standard"
/*
- * Meinberg GPS16X receiver
+ * Meinberg GPS receivers
*/
-static void gps16x_message P((struct parseunit *, parsetime_t *));
-static int gps16x_poll_init P((struct parseunit *));
+static void gps16x_message (struct parseunit *, parsetime_t *);
+static int gps16x_poll_init (struct parseunit *);
#define GPS16X_ROOTDELAY 0.0 /* nothing here */
#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
-#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver"
+#define GPS16X_DESCRIPTION "Meinberg GPS receiver"
#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
* @ 5e-9df/f we have accumulated
* at most an error of 1.73 ms
@@ -677,16 +693,18 @@ static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
* RAWDCF receivers that need to be powered from DTR
* (like Expert mouse clock)
*/
-static int rawdcf_init_1 P((struct parseunit *));
+static int rawdcf_init_1 (struct parseunit *);
#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
+#define RAWDCFDTRSET75_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)"
#define RAWDCFDTRSET_INIT rawdcf_init_1
/*
* RAWDCF receivers that need to be powered from
* DTR CLR and RTS SET
*/
-static int rawdcf_init_2 P((struct parseunit *));
+static int rawdcf_init_2 (struct parseunit *);
#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
+#define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)"
#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
/*
@@ -700,17 +718,17 @@ static int rawdcf_init_2 P((struct parseunit *));
#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
-static int trimbletaip_init P((struct parseunit *));
-static void trimbletaip_event P((struct parseunit *, int));
+static int trimbletaip_init (struct parseunit *);
+static void trimbletaip_event (struct parseunit *, int);
/* query time & UTC correction data */
static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
-static int trimbletsip_init P((struct parseunit *));
-static void trimbletsip_end P((struct parseunit *));
-static void trimbletsip_message P((struct parseunit *, parsetime_t *));
-static void trimbletsip_event P((struct parseunit *, int));
+static int trimbletsip_init (struct parseunit *);
+static void trimbletsip_end (struct parseunit *);
+static void trimbletsip_message (struct parseunit *, parsetime_t *);
+static void trimbletsip_event (struct parseunit *, int);
#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */
#define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME
@@ -741,9 +759,9 @@ static void trimbletsip_event P((struct parseunit *, int));
#define TRIMBLETAIP_INIT trimbletaip_init
#define TRIMBLETSIP_INIT trimbletsip_init
-#define TRIMBLETAIP_EVENT trimbletaip_event
+#define TRIMBLETAIP_EVENT trimbletaip_event
-#define TRIMBLETSIP_EVENT trimbletsip_event
+#define TRIMBLETSIP_EVENT trimbletsip_event
#define TRIMBLETSIP_MESSAGE trimbletsip_message
#define TRIMBLETAIP_END 0
@@ -800,7 +818,7 @@ static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }
#define RCC8000_KEEP 3
/*
- * Hopf Radio clock 6021 Format
+ * Hopf Radio clock 6021 Format
*
*/
#define HOPF6021_ROOTDELAY 0.0
@@ -855,14 +873,43 @@ static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }
#define VARITEXT_SAMPLES 32
#define VARITEXT_KEEP 20
+/*
+ * SEL240x Satellite Sychronized Clock
+ */
+#define SEL240X_POLLRATE 0 /* only true direct polling */
+#define SEL240X_POLLCMD "BUB8"
+#define SEL240X_CMDSIZE 4
+
+static poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE,
+ SEL240X_POLLCMD,
+ SEL240X_CMDSIZE };
+#define SEL240X_FLAGS (PARSE_F_PPSONSECOND)
+#define SEL240X_POLL poll_dpoll
+#define SEL240X_INIT poll_init
+#define SEL240X_END 0
+#define SEL240X_DATA ((void *)(&sel240x_pollinfo))
+#define SEL240X_ROOTDELAY 0.0
+#define SEL240X_BASEDELAY 0.0
+#define SEL240X_ID GPS_ID
+#define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock"
+#define SEL240X_FORMAT "SEL B8"
+#define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */
+#define SEL240X_SPEED (B9600)
+#define SEL240X_CFLAG (CS8|CREAD|CLOCAL)
+#define SEL240X_IFLAG (IGNBRK|IGNPAR)
+#define SEL240X_OFLAG (0)
+#define SEL240X_LFLAG (0)
+#define SEL240X_SAMPLES 5
+#define SEL240X_KEEP 3
+
static struct parse_clockinfo
{
- u_long cl_flags; /* operation flags (io modes) */
- void (*cl_poll) P((struct parseunit *)); /* active poll routine */
- int (*cl_init) P((struct parseunit *)); /* active poll init routine */
- void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */
- void (*cl_end) P((struct parseunit *)); /* active poll end routine */
- void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */
+ u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */
+ void (*cl_poll) (struct parseunit *); /* active poll routine */
+ int (*cl_init) (struct parseunit *); /* active poll init routine */
+ void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */
+ void (*cl_end) (struct parseunit *); /* active poll end routine */
+ void (*cl_message) (struct parseunit *, parsetime_t *); /* process a lower layer message */
void *cl_data; /* local data area for "poll" mechanism */
double cl_rootdelay; /* rootdelay */
double cl_basedelay; /* current offset by which the RS232
@@ -1167,7 +1214,7 @@ static struct parse_clockinfo
},
{ /* mode 12 */
HOPF6021_FLAGS,
- NO_POLL,
+ NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
@@ -1351,6 +1398,122 @@ static struct parse_clockinfo
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
+ { /* mode 20, like mode 14 but driven by 75 baud */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ RAWDCFDTRSET_INIT,
+ NO_EVENT,
+ NO_END,
+ NO_MESSAGE,
+ NO_LCLDATA,
+ RAWDCF_ROOTDELAY,
+ RAWDCF_BASEDELAY,
+ DCF_A_ID,
+ RAWDCFDTRSET75_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ B75,
+ RAWDCF_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG,
+ RAWDCF_SAMPLES,
+ RAWDCF_KEEP
+ },
+ { /* mode 21, like mode 16 but driven by 75 baud
+ - RAWDCF RTS set, DTR clr */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ RAWDCFDTRCLRRTSSET_INIT,
+ NO_EVENT,
+ NO_END,
+ NO_MESSAGE,
+ NO_LCLDATA,
+ RAWDCF_ROOTDELAY,
+ RAWDCF_BASEDELAY,
+ DCF_A_ID,
+ RAWDCFDTRCLRRTSSET75_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ B75,
+ RAWDCF_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG,
+ RAWDCF_SAMPLES,
+ RAWDCF_KEEP
+ },
+ { /* mode 22 - like 2 with POWERUP trust */
+ MBG_FLAGS | PARSE_F_POWERUPTRUST,
+ NO_POLL,
+ NO_INIT,
+ NO_EVENT,
+ NO_END,
+ NO_MESSAGE,
+ NO_LCLDATA,
+ DCFUA31_ROOTDELAY,
+ DCFUA31_BASEDELAY,
+ DCF_A_ID,
+ DCFUA31_DESCRIPTION,
+ DCFUA31_FORMAT,
+ DCF_TYPE,
+ DCFUA31_MAXUNSYNC,
+ DCFUA31_SPEED,
+ DCFUA31_CFLAG,
+ DCFUA31_IFLAG,
+ DCFUA31_OFLAG,
+ DCFUA31_LFLAG,
+ DCFUA31_SAMPLES,
+ DCFUA31_KEEP
+ },
+ { /* mode 23 - like 7 with POWERUP trust */
+ MBG_FLAGS | PARSE_F_POWERUPTRUST,
+ GPS16X_POLL,
+ GPS16X_INIT,
+ NO_EVENT,
+ GPS16X_END,
+ GPS16X_MESSAGE,
+ GPS16X_DATA,
+ GPS16X_ROOTDELAY,
+ GPS16X_BASEDELAY,
+ GPS16X_ID,
+ GPS16X_DESCRIPTION,
+ GPS16X_FORMAT,
+ GPS_TYPE,
+ GPS16X_MAXUNSYNC,
+ GPS16X_SPEED,
+ GPS16X_CFLAG,
+ GPS16X_IFLAG,
+ GPS16X_OFLAG,
+ GPS16X_LFLAG,
+ GPS16X_SAMPLES,
+ GPS16X_KEEP
+ },
+ { /* mode 24 */
+ SEL240X_FLAGS,
+ SEL240X_POLL,
+ SEL240X_INIT,
+ NO_EVENT,
+ SEL240X_END,
+ NO_MESSAGE,
+ SEL240X_DATA,
+ SEL240X_ROOTDELAY,
+ SEL240X_BASEDELAY,
+ SEL240X_ID,
+ SEL240X_DESCRIPTION,
+ SEL240X_FORMAT,
+ GPS_TYPE,
+ SEL240X_MAXUNSYNC,
+ SEL240X_SPEED,
+ SEL240X_CFLAG,
+ SEL240X_IFLAG,
+ SEL240X_OFLAG,
+ SEL240X_LFLAG,
+ SEL240X_SAMPLES,
+ SEL240X_KEEP
+ },
};
static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
@@ -1371,11 +1534,11 @@ static int notice = 0;
#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
-static void parse_event P((struct parseunit *, int));
-static void parse_process P((struct parseunit *, parsetime_t *));
-static void clear_err P((struct parseunit *, u_long));
-static int list_err P((struct parseunit *, u_long));
-static char * l_mktime P((u_long));
+static void parse_event (struct parseunit *, int);
+static void parse_process (struct parseunit *, parsetime_t *);
+static void clear_err (struct parseunit *, u_long);
+static int list_err (struct parseunit *, u_long);
+static char * l_mktime (u_long);
/**===========================================================================
** implementation error message regression module
@@ -1388,7 +1551,7 @@ clear_err(
{
if (lstate == ERR_ALL)
{
- int i;
+ size_t i;
for (i = 0; i < ERR_CNT; i++)
{
@@ -1427,7 +1590,7 @@ list_err(
if (do_it)
err->err_cnt++;
-
+
if (err->err_stage->err_count &&
(err->err_cnt >= err->err_stage->err_count))
{
@@ -1451,7 +1614,7 @@ list_err(
l_mktime(current_time - err->err_started));
err->err_suppressed = 0;
}
-
+
return do_it;
}
@@ -1473,13 +1636,14 @@ mkreadable(
int hex
)
{
+ static const char ellipsis[] = "...";
char *b = buffer;
- char *endb = (char *)0;
+ char *endb = NULL;
if (blen < 4)
- return (char *)0; /* don't bother with mini buffers */
+ return NULL; /* don't bother with mini buffers */
- endb = buffer + blen - 4;
+ endb = buffer + blen - sizeof(ellipsis);
blen--; /* account for '\0' */
@@ -1488,7 +1652,7 @@ mkreadable(
if (!hex && /* no binary only */
(*src != '\\') && /* no plain \ */
(*src != '"') && /* no " */
- isprint((int)*src)) /* only printables */
+ isprint((unsigned char)*src)) /* only printables */
{ /* they are easy... */
*buffer++ = *src++;
blen--;
@@ -1508,21 +1672,21 @@ mkreadable(
{
if (*src == '\\')
{
- strcpy(buffer,"\\\\");
+ memcpy(buffer, "\\\\", 2);
buffer += 2;
blen -= 2;
src++;
}
else
{
- sprintf(buffer, "\\x%02x", *src++);
+ snprintf(buffer, blen, "\\x%02x", *src++);
blen -= 4;
buffer += 4;
}
}
}
if (srclen && !blen && endb) /* overflow - set last chars to ... */
- strcpy(endb, "...");
+ memcpy(endb, ellipsis, sizeof(ellipsis));
}
*buffer = '\0';
@@ -1554,27 +1718,27 @@ mkascii(
* define possible io handling methods
*/
#ifdef STREAM
-static int ppsclock_init P((struct parseunit *));
-static int stream_init P((struct parseunit *));
-static void stream_end P((struct parseunit *));
-static int stream_enable P((struct parseunit *));
-static int stream_disable P((struct parseunit *));
-static int stream_setcs P((struct parseunit *, parsectl_t *));
-static int stream_getfmt P((struct parseunit *, parsectl_t *));
-static int stream_setfmt P((struct parseunit *, parsectl_t *));
-static int stream_timecode P((struct parseunit *, parsectl_t *));
-static void stream_receive P((struct recvbuf *));
+static int ppsclock_init (struct parseunit *);
+static int stream_init (struct parseunit *);
+static void stream_end (struct parseunit *);
+static int stream_enable (struct parseunit *);
+static int stream_disable (struct parseunit *);
+static int stream_setcs (struct parseunit *, parsectl_t *);
+static int stream_getfmt (struct parseunit *, parsectl_t *);
+static int stream_setfmt (struct parseunit *, parsectl_t *);
+static int stream_timecode (struct parseunit *, parsectl_t *);
+static void stream_receive (struct recvbuf *);
#endif
-
-static int local_init P((struct parseunit *));
-static void local_end P((struct parseunit *));
-static int local_nop P((struct parseunit *));
-static int local_setcs P((struct parseunit *, parsectl_t *));
-static int local_getfmt P((struct parseunit *, parsectl_t *));
-static int local_setfmt P((struct parseunit *, parsectl_t *));
-static int local_timecode P((struct parseunit *, parsectl_t *));
-static void local_receive P((struct recvbuf *));
-static int local_input P((struct recvbuf *));
+
+static int local_init (struct parseunit *);
+static void local_end (struct parseunit *);
+static int local_nop (struct parseunit *);
+static int local_setcs (struct parseunit *, parsectl_t *);
+static int local_getfmt (struct parseunit *, parsectl_t *);
+static int local_setfmt (struct parseunit *, parsectl_t *);
+static int local_timecode (struct parseunit *, parsectl_t *);
+static void local_receive (struct recvbuf *);
+static int local_input (struct recvbuf *);
static bind_t io_bindings[] =
{
@@ -1621,34 +1785,21 @@ static bind_t io_bindings[] =
},
{
(char *)0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
}
};
#ifdef STREAM
-#define fix_ts(_X_) \
- if ((&(_X_))->tv.tv_usec >= 1000000) \
- { \
- (&(_X_))->tv.tv_usec -= 1000000; \
- (&(_X_))->tv.tv_sec += 1; \
- }
-
-#define cvt_ts(_X_, _Y_) \
- { \
- l_fp ts; \
- fix_ts((_X_)); \
- if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
- { \
- ERR(ERR_BADDATA) \
- msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
- return; \
- } \
- else \
- { \
- (&(_X_))->fp = ts; \
- } \
- }
-
/*--------------------------------------------------
* ppsclock STREAM init
*/
@@ -1659,7 +1810,7 @@ ppsclock_init(
{
static char m1[] = "ppsclocd";
static char m2[] = "ppsclock";
-
+
/*
* now push the parse streams module
* it will ensure exclusive access to the device
@@ -1748,7 +1899,7 @@ stream_setcs(
)
{
struct strioctl strioc;
-
+
strioc.ic_cmd = PARSEIOC_SETCS;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
@@ -1771,7 +1922,7 @@ stream_enable(
)
{
struct strioctl strioc;
-
+
strioc.ic_cmd = PARSEIOC_ENABLE;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)0;
@@ -1795,7 +1946,7 @@ stream_disable(
)
{
struct strioctl strioc;
-
+
strioc.ic_cmd = PARSEIOC_DISABLE;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)0;
@@ -1820,7 +1971,7 @@ stream_getfmt(
)
{
struct strioctl strioc;
-
+
strioc.ic_cmd = PARSEIOC_GETFMT;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
@@ -1843,7 +1994,7 @@ stream_setfmt(
)
{
struct strioctl strioc;
-
+
strioc.ic_cmd = PARSEIOC_SETFMT;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
@@ -1868,12 +2019,12 @@ stream_timecode(
)
{
struct strioctl strioc;
-
+
strioc.ic_cmd = PARSEIOC_TIMECODE;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
strioc.ic_len = sizeof (*tcl);
-
+
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
ERR(ERR_INTERNAL)
@@ -1892,9 +2043,10 @@ stream_receive(
struct recvbuf *rbufp
)
{
- struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
+ struct parseunit * parse;
parsetime_t parsetime;
+ parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
if (!parse->peer)
return;
@@ -1907,7 +2059,7 @@ stream_receive(
return;
}
clear_err(parse, ERR_BADIO);
-
+
memmove((caddr_t)&parsetime,
(caddr_t)rbufp->recv_buffer,
sizeof(parsetime_t));
@@ -1933,15 +2085,17 @@ stream_receive(
* errors.
*/
- cvt_ts(parsetime.parse_stime, "parse_stime");
+ parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
if (PARSE_TIMECODE(parsetime.parse_state))
{
- cvt_ts(parsetime.parse_time, "parse_time");
+ parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
}
if (PARSE_PPS(parsetime.parse_state))
- cvt_ts(parsetime.parse_ptime, "parse_ptime");
+ {
+ parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
+ }
parse_process(parse, &parsetime);
}
@@ -2038,11 +2192,13 @@ local_input(
struct recvbuf *rbufp
)
{
- struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
+ struct parseunit * parse;
+
int count;
unsigned char *s;
timestamp_t ts;
+ parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
if (!parse->peer)
return 0;
@@ -2069,11 +2225,11 @@ local_input(
{
struct timespec pps_timeout;
pps_info_t pps_info;
-
+
pps_timeout.tv_sec = 0;
pps_timeout.tv_nsec = 0;
- if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info,
+ if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
&pps_timeout) == 0)
{
if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
@@ -2090,9 +2246,9 @@ local_input(
else
pts = pps_info.assert_timestamp;
- parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
+ parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970);
- dtemp = pts.tv_nsec / 1e9;
+ dtemp = (double) pts.tv_nsec / 1e9;
if (dtemp < 0.) {
dtemp += 1;
parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
@@ -2101,9 +2257,9 @@ local_input(
dtemp -= 1;
parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
}
- parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
+ parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC);
- parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
+ parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
#ifdef DEBUG
if (debug > 3)
{
@@ -2145,11 +2301,11 @@ local_input(
#else
#ifdef TIOCDCDTIMESTAMP
struct timeval dcd_time;
-
+
if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
{
l_fp tstmp;
-
+
TVTOTS(&dcd_time, &tstmp);
tstmp.l_ui += JAN_1970;
L_SUB(&ts.fp, &tstmp);
@@ -2217,12 +2373,19 @@ local_input(
sizeof(parsetime_t));
buf->recv_length = sizeof(parsetime_t);
buf->recv_time = rbufp->recv_time;
+#ifndef HAVE_IO_COMPLETION_PORT
buf->srcadr = rbufp->srcadr;
+#endif
buf->dstadr = rbufp->dstadr;
buf->receiver = rbufp->receiver;
buf->fd = rbufp->fd;
buf->X_from_where = rbufp->X_from_where;
+ parse->generic->io.recvcount++;
+ packets_received++;
add_full_recv_buffer(buf);
+#ifdef HAVE_IO_COMPLETION_PORT
+ SetEvent(WaitableIoEventHandle);
+#endif
}
parse_iodone(&parse->parseio);
}
@@ -2248,9 +2411,10 @@ local_receive(
struct recvbuf *rbufp
)
{
- struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
+ struct parseunit * parse;
parsetime_t parsetime;
+ parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
if (!parse->peer)
return;
@@ -2263,7 +2427,7 @@ local_receive(
return;
}
clear_err(parse, ERR_BADIO);
-
+
memmove((caddr_t)&parsetime,
(caddr_t)rbufp->recv_buffer,
sizeof(parsetime_t));
@@ -2312,6 +2476,31 @@ init_iobinding(
** support routines
**/
+static NTP_PRINTF(4, 5) char *
+ap(char *buffer, size_t len, char *pos, const char *fmt, ...)
+{
+ va_list va;
+ int l;
+ size_t rem = len - (pos - buffer);
+
+ if (rem == 0)
+ return pos;
+
+ va_start(va, fmt);
+ l = vsnprintf(pos, rem, fmt, va);
+ va_end(va);
+
+ if (l != -1) {
+ rem--;
+ if (rem >= (size_t)l)
+ pos += l;
+ else
+ pos += rem;
+ }
+
+ return pos;
+}
+
/*--------------------------------------------------
* convert a flag field to a string
*/
@@ -2336,11 +2525,11 @@ parsestate(
{ PARSEB_LEAPADD, "LEAP ADD WARNING" },
{ PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
{ PARSEB_LEAPSECOND, "LEAP SECOND" },
- { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" },
+ { PARSEB_CALLBIT, "CALL BIT" },
{ PARSEB_TIMECODE, "TIME CODE" },
{ PARSEB_PPS, "PPS" },
{ PARSEB_POSITION, "POSITION" },
- { 0 }
+ { 0, NULL }
};
static struct sbits
@@ -2351,14 +2540,13 @@ parsestate(
{
{ PARSEB_S_LEAP, "LEAP INDICATION" },
{ PARSEB_S_PPS, "PPS SIGNAL" },
- { PARSEB_S_ANTENNA, "ANTENNA" },
+ { PARSEB_S_CALLBIT, "CALLBIT" },
{ PARSEB_S_POSITION, "POSITION" },
- { 0 }
+ { 0, NULL }
};
int i;
char *s, *t;
-
*buffer = '\0';
s = t = buffer;
@@ -2368,23 +2556,20 @@ parsestate(
if (flagstrings[i].bit & lstate)
{
if (s != t)
- strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
- strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
- t += strlen(t);
+ t = ap(buffer, size, t, "; ");
+ t = ap(buffer, size, t, "%s", flagstrings[i].name);
}
i++;
}
- if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
+ if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION))
{
if (s != t)
- strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
-
- t += strlen(t);
+ t = ap(buffer, size, t, "; ");
- strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
+ t = ap(buffer, size, t, "(");
- s = t = t + strlen(t);
+ s = t;
i = 0;
while (sflagstrings[i].bit)
@@ -2393,16 +2578,15 @@ parsestate(
{
if (t != s)
{
- strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
- t += 2;
+ t = ap(buffer, size, t, "; ");
}
-
- strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
- t += strlen(t);
+
+ t = ap(buffer, size, t, "%s",
+ sflagstrings[i].name);
}
i++;
}
- strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
+ t = ap(buffer, size, t, ")");
}
return buffer;
}
@@ -2430,10 +2614,12 @@ parsestatus(
{ CVT_BADDATE, "DATE ILLEGAL" },
{ CVT_BADTIME, "TIME ILLEGAL" },
{ CVT_ADDITIONAL, "ADDITIONAL DATA" },
- { 0 }
+ { 0, NULL }
};
int i;
+ char *t;
+ t = buffer;
*buffer = '\0';
i = 0;
@@ -2441,9 +2627,9 @@ parsestatus(
{
if (flagstrings[i].bit & lstate)
{
- if (buffer[0])
- strncat(buffer, "; ", size);
- strncat(buffer, flagstrings[i].name, size);
+ if (t != buffer)
+ t = ap(buffer, size, t, "; ");
+ t = ap(buffer, size, t, "%s", flagstrings[i].name);
}
i++;
}
@@ -2473,12 +2659,12 @@ clockstatus(
{ CEVNT_PROP, "PROPAGATION DELAY" },
{ CEVNT_BADDATE, "ILLEGAL DATE" },
{ CEVNT_BADTIME, "ILLEGAL TIME" },
- { (unsigned)~0L }
+ { (unsigned)~0L, NULL }
};
int i;
i = 0;
- while (flagstrings[i].value != ~0)
+ while (flagstrings[i].value != (u_int)~0)
{
if (flagstrings[i].value == lstate)
{
@@ -2506,10 +2692,11 @@ l_mktime(
char *t;
buffer[0] = '\0';
+ t = buffer;
if ((tmp = delta / (60*60*24)) != 0)
{
- snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
+ t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
delta -= tmp * 60*60*24;
}
@@ -2518,10 +2705,8 @@ l_mktime(
m = delta % 60;
delta /= 60;
- t = buffer + strlen(buffer);
-
- snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
- (int)delta, (int)m, (int)s);
+ t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
+ (int)delta, (int)m, (int)s);
return buffer;
}
@@ -2601,10 +2786,10 @@ parse_shutdown(
struct peer *peer
)
{
- struct parseunit *parse = (struct parseunit *)0;
+ struct parseunit *parse = NULL;
if (peer && peer->procptr)
- parse = (struct parseunit *)peer->procptr->unitptr;
+ parse = peer->procptr->unitptr;
if (!parse)
{
@@ -2612,7 +2797,7 @@ parse_shutdown(
return;
}
- if (!parse->peer)
+ if (!parse->peer)
{
msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
return;
@@ -2621,11 +2806,11 @@ parse_shutdown(
#ifdef HAVE_PPSAPI
if (parse->flags & PARSE_PPSCLOCK)
{
- (void)time_pps_destroy(parse->ppshandle);
+ (void)time_pps_destroy(parse->atom.handle);
}
#endif
if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
- (void)close(parse->ppsfd); /* close separate PPS source */
+ (void)closeserial(parse->ppsfd); /* close separate PPS source */
/*
* print statistics a last time and
@@ -2637,7 +2822,7 @@ parse_shutdown(
{
parse->parse_type->cl_end(parse);
}
-
+
/*
* cleanup before leaving this world
*/
@@ -2650,7 +2835,7 @@ parse_shutdown(
io_closeclock(&parse->generic->io);
free_varlist(parse->kv);
-
+
NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
CLK_UNIT(parse->peer), parse->parse_type->cl_description);
@@ -2676,15 +2861,15 @@ parse_hardpps(
if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
int i = 0;
- if (mode == PARSE_HARDPPS_ENABLE)
+ if (mode == PARSE_HARDPPS_ENABLE)
{
if (parse->flags & PARSE_CLEAR)
i = PPS_CAPTURECLEAR;
else
i = PPS_CAPTUREASSERT;
}
-
- if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i,
+
+ if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
PPS_TSFMT_TSPEC) < 0) {
msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
CLK_UNIT(parse->peer));
@@ -2696,7 +2881,7 @@ parse_hardpps(
* tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
*/
if (mode == PARSE_HARDPPS_ENABLE)
- pps_enable = 1;
+ hardpps_enable = 1;
}
}
@@ -2711,23 +2896,30 @@ parse_ppsapi(
struct parseunit *parse
)
{
- int cap, mode, mode1;
- char *cp;
-
- parse->flags &= ~PARSE_PPSCLOCK;
+ int cap, mode_ppsoffset;
+ const char *cp;
+
+ parse->flags &= (u_char) (~PARSE_PPSCLOCK);
- if (time_pps_getcap(parse->ppshandle, &cap) < 0) {
+ /*
+ * collect PPSAPI offset capability - should move into generic handling
+ */
+ if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
CLK_UNIT(parse->peer));
-
+
return 0;
}
- if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) {
- msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m",
- CLK_UNIT(parse->peer));
+ /*
+ * initialize generic PPSAPI interface
+ *
+ * we leave out CLK_FLAG3 as time_pps_kcbind()
+ * is handled here for now. Ideally this should also
+ * be part of the generic PPSAPI interface
+ */
+ if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
return 0;
- }
/* nb. only turn things on, if someone else has turned something
* on before we get here, leave it alone!
@@ -2735,47 +2927,36 @@ parse_ppsapi(
if (parse->flags & PARSE_CLEAR) {
cp = "CLEAR";
- mode = PPS_CAPTURECLEAR;
- mode1 = PPS_OFFSETCLEAR;
+ mode_ppsoffset = PPS_OFFSETCLEAR;
} else {
cp = "ASSERT";
- mode = PPS_CAPTUREASSERT;
- mode1 = PPS_OFFSETASSERT;
+ mode_ppsoffset = PPS_OFFSETASSERT;
}
msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
CLK_UNIT(parse->peer), cp);
- if (!(mode & cap)) {
- msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)",
- CLK_UNIT(parse->peer), cp, cap);
-
- return 0;
- }
-
- if (!(mode1 & cap)) {
+ if (!(mode_ppsoffset & cap)) {
msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
CLK_UNIT(parse->peer), cp, cap);
- mode1 = 0;
+ mode_ppsoffset = 0;
} else {
- if (mode1 == PPS_OFFSETCLEAR)
- {
- parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust;
- parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
+ if (mode_ppsoffset == PPS_OFFSETCLEAR)
+ {
+ parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
+ parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
}
-
- if (mode1 == PPS_OFFSETASSERT)
- {
- parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust;
- parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
+
+ if (mode_ppsoffset == PPS_OFFSETASSERT)
+ {
+ parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
+ parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
}
}
-
- /* only set what is legal */
- parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
+ parse->atom.pps_params.mode |= mode_ppsoffset;
- if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) {
+ if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
CLK_UNIT(parse->peer));
return 0;
@@ -2817,14 +2998,14 @@ parse_start(
if (!notice)
{
NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
- msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel");
+ msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2015, Frank Kardel");
notice = 1;
}
type = CLK_TYPE(peer);
unit = CLK_UNIT(peer);
- if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
+ if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
unit, CLK_REALTYPE(peer), ncltypes-1);
@@ -2840,12 +3021,11 @@ parse_start(
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
-
- fd232 = open(parsedev, O_RDWR | O_NOCTTY
-#ifdef O_NONBLOCK
- | O_NONBLOCK
+#ifndef O_NONBLOCK
+#define O_NONBLOCK 0
#endif
- , 0777);
+
+ fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
if (fd232 == -1)
{
@@ -2853,9 +3033,7 @@ parse_start(
return 0;
}
- parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
-
- memset((char *)parse, 0, sizeof(struct parseunit));
+ parse = emalloc_zero(sizeof(*parse));
parse->generic = peer->procptr; /* link up */
parse->generic->unitptr = (caddr_t)parse; /* link down */
@@ -2879,9 +3057,9 @@ parse_start(
parse->kv = (struct ctl_var *)0;
clear_err(parse, ERR_ALL);
-
+
parse->parse_type = &parse_clockinfo[type];
-
+
parse->maxunsync = parse->parse_type->cl_maxunsync;
parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
@@ -2894,16 +3072,16 @@ parse_start(
peer->rootdelay = parse->parse_type->cl_rootdelay;
peer->sstclktype = parse->parse_type->cl_type;
peer->precision = sys_precision;
-
+
peer->stratum = STRATUM_REFCLOCK;
if (peer->stratum <= 1)
memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
else
parse->generic->refid = htonl(PARSEHSREFID);
-
+
parse->generic->io.fd = fd232;
-
+
parse->peer = peer; /* marks it also as busy */
/*
@@ -2946,15 +3124,15 @@ parse_start(
}
#endif
- tio.c_cflag = parse_clockinfo[type].cl_cflag;
- tio.c_iflag = parse_clockinfo[type].cl_iflag;
- tio.c_oflag = parse_clockinfo[type].cl_oflag;
- tio.c_lflag = parse_clockinfo[type].cl_lflag;
-
+ tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag;
+ tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag;
+ tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag;
+ tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag;
+
#ifdef HAVE_TERMIOS
- if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
- (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
+ if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) ||
+ (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1))
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
@@ -2969,11 +3147,7 @@ parse_start(
* if the PARSEPPSDEVICE can be opened that will be used
* for PPS else PARSEDEVICE will be used
*/
- parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
-#ifdef O_NONBLOCK
- | O_NONBLOCK
-#endif
- , 0777);
+ parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
if (parse->ppsfd == -1)
{
@@ -3018,7 +3192,7 @@ parse_start(
if (CLK_PPS(parse->peer))
{
int i = 1;
-
+
if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
{
parse->flags |= PARSE_PPSCLOCK;
@@ -3033,7 +3207,7 @@ parse_start(
parse->hardppsstate = PARSE_HARDPPS_DISABLE;
if (CLK_PPS(parse->peer))
{
- if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0)
+ if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
}
@@ -3055,9 +3229,9 @@ parse_start(
/*
* pick correct input machine
*/
- parse->generic->io.srcclock = (caddr_t)parse;
+ parse->generic->io.srcclock = peer;
parse->generic->io.datalen = 0;
-
+
parse->binding = init_iobinding(parse);
if (parse->binding == (bind_t *)0)
@@ -3065,7 +3239,7 @@ parse_start(
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
return 0; /* well, ok - special initialisation broke */
- }
+ }
parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */
@@ -3103,9 +3277,9 @@ parse_start(
parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
return 0; /* well, ok - special initialisation broke */
}
-
- strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
- tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
+
+ strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
+ tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer);
if (!PARSE_SETFMT(parse, &tmp_ctl))
{
@@ -3113,7 +3287,7 @@ parse_start(
parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
return 0; /* well, ok - special initialisation broke */
}
-
+
/*
* get rid of all IO accumulated so far
*/
@@ -3140,7 +3314,7 @@ parse_start(
return 0; /* well, ok - special initialisation broke */
}
}
-
+
/*
* Insert in async io device list.
*/
@@ -3198,15 +3372,15 @@ parse_start(
static void
parse_ctl(
struct parseunit *parse,
- struct refclockstat *in
+ const struct refclockstat *in
)
{
if (in)
{
if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
{
- parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
- (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
+ u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4;
+ parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask);
#if defined(HAVE_PPSAPI)
if (CLK_PPS(parse->peer))
{
@@ -3214,7 +3388,7 @@ parse_ctl(
}
#endif
}
-
+
if (in->haveflags & CLK_HAVETIME1)
{
parse->generic->fudgetime1 = in->fudgetime1;
@@ -3222,11 +3396,11 @@ parse_ctl(
CLK_UNIT(parse->peer),
parse->generic->fudgetime1);
}
-
+
if (in->haveflags & CLK_HAVETIME2)
{
parse->generic->fudgetime2 = in->fudgetime2;
- if (parse->flags & PARSE_TRUSTTIME)
+ if (parse->flags & PARSE_TRUSTTIME)
{
parse->maxunsync = (u_long)ABS(in->fudgetime2);
msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
@@ -3259,7 +3433,7 @@ parse_poll(
struct peer *peer
)
{
- struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
+ struct parseunit *parse = peer->procptr->unitptr;
if (peer != parse->peer)
{
@@ -3274,8 +3448,8 @@ parse_poll(
*/
parse->generic->polls++;
- if (parse->pollneeddata &&
- ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
+ if (parse->pollneeddata &&
+ ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
{
/*
* start worrying when exceeding a poll inteval
@@ -3283,7 +3457,7 @@ parse_poll(
*/
parse->lastmissed = current_time;
parse_event(parse, CEVNT_TIMEOUT);
-
+
ERR(ERR_NODATA)
msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
}
@@ -3311,12 +3485,12 @@ parse_poll(
static void
parse_control(
int unit,
- struct refclockstat *in,
+ const struct refclockstat *in,
struct refclockstat *out,
struct peer *peer
)
{
- struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
+ struct parseunit *parse = peer->procptr->unitptr;
parsectl_t tmpctl;
static char outstatus[400]; /* status output buffer */
@@ -3341,7 +3515,7 @@ parse_control(
* handle changes
*/
parse_ctl(parse, in);
-
+
/*
* supply data
*/
@@ -3388,16 +3562,16 @@ parse_control(
}
start = tt = add_var(&out->kv_list, 128, RO|DEF);
- snprintf(tt, 128, "refclock_time=\"");
- tt += strlen(tt);
+ tt = ap(start, 128, tt, "refclock_time=\"");
if (parse->timedata.parse_time.fp.l_ui == 0)
{
- strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
+ tt = ap(start, 128, tt, "<UNDEFINED>\"");
}
else
{
- snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
+ tt = ap(start, 128, tt, "%s\"",
+ gmprettydate(&parse->timedata.parse_time.fp));
}
if (!PARSE_GETTIMECODE(parse, &tmpctl))
@@ -3408,8 +3582,7 @@ parse_control(
else
{
start = tt = add_var(&out->kv_list, 512, RO|DEF);
- snprintf(tt, 512, "refclock_status=\"");
- tt += strlen(tt);
+ tt = ap(start, 512, tt, "refclock_status=\"");
/*
* copy PPS flags from last read transaction (informational only)
@@ -3417,18 +3590,20 @@ parse_control(
tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
(PARSEB_PPS|PARSEB_S_PPS);
- (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
+ (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
+
+ tt += strlen(tt);
- strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
+ tt = ap(start, 512, tt, "\"");
if (tmpctl.parsegettc.parse_count)
mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
}
-
+
tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
-
+
if (!PARSE_GETFMT(parse, &tmpctl))
{
ERR(ERR_INTERNAL)
@@ -3436,11 +3611,19 @@ parse_control(
}
else
{
- tt = add_var(&out->kv_list, 80, RO|DEF);
- snprintf(tt, 80, "refclock_format=\"");
+ int count = tmpctl.parseformat.parse_count - 1;
+
+ start = tt = add_var(&out->kv_list, 80, RO|DEF);
+ tt = ap(start, 80, tt, "refclock_format=\"");
+
+ if (count > 0) {
+ tt = ap(start, 80, tt, "%*.*s",
+ count,
+ count,
+ tmpctl.parseformat.parse_buffer);
+ }
- strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
- strncat(tt,"\"", 80);
+ tt = ap(start, 80, tt, "\"");
}
/*
@@ -3448,8 +3631,7 @@ parse_control(
*/
start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
- strncpy(tt, "refclock_states=\"", LEN_STATES);
- tt += strlen(tt);
+ tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
for (i = 0; i <= CEVNT_MAX; i++)
{
@@ -3464,7 +3646,7 @@ parse_control(
percent /= 10;
d /= 10;
}
-
+
if (d)
percent = (percent * 10000) / d;
else
@@ -3474,36 +3656,37 @@ parse_control(
{
char item[80];
int count;
-
+
snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
sum ? "; " : "",
(parse->generic->currentstatus == i) ? "*" : "",
clockstatus((unsigned int)i),
l_mktime(s_time),
(int)(percent / 100), (int)(percent % 100));
- if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
+ if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start)))
{
- strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
- tt += count;
+ tt = ap(start, LEN_STATES, tt,
+ "%s", item);
}
sum += s_time;
}
}
-
- snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
-
+
+ tt = ap(start, LEN_STATES, tt,
+ "; running time: %s\"", l_mktime(sum));
+
tt = add_var(&out->kv_list, 32, RO);
snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id);
-
+
tt = add_var(&out->kv_list, 80, RO);
snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description);
tt = add_var(&out->kv_list, 128, RO);
snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
-
+
{
struct ctl_var *k;
-
+
k = parse->kv;
while (k && !(k->flags & EOV))
{
@@ -3511,8 +3694,8 @@ parse_control(
k++;
}
}
-
- out->lencode = strlen(outstatus);
+
+ out->lencode = (u_short) strlen(outstatus);
out->p_lastcode = outstatus;
}
}
@@ -3538,7 +3721,7 @@ parse_event(
if (parse->parse_type->cl_event)
parse->parse_type->cl_event(parse, event);
-
+
if (event == CEVNT_NOMINAL)
{
NLOG(NLOG_CLOCKSTATUS)
@@ -3561,7 +3744,10 @@ parse_process(
{
l_fp off, rectime, reftime;
double fudge;
-
+
+ /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
+ ZERO(off);
+
/*
* check for changes in conversion status
* (only one for each new status !)
@@ -3571,11 +3757,11 @@ parse_process(
(parse->timedata.parse_status != parsetime->parse_status))
{
char buffer[400];
-
+
NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
-
+
if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
{
/*
@@ -3584,7 +3770,7 @@ parse_process(
* the time code might be overwritten by the next packet
*/
parsectl_t tmpctl;
-
+
if (!PARSE_GETTIMECODE(parse, &tmpctl))
{
ERR(ERR_INTERNAL)
@@ -3596,6 +3782,8 @@ parse_process(
msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
}
+ /* copy status to show only changes in case of failures */
+ parse->timedata.parse_status = parsetime->parse_status;
}
}
@@ -3622,7 +3810,7 @@ parse_process(
parse->timedata.parse_ptime = parsetime->parse_ptime;
}
break; /* well, still waiting - timeout is handled at higher levels */
-
+
case CVT_FAIL:
if (parsetime->parse_status & CVT_BADFMT)
{
@@ -3653,7 +3841,7 @@ parse_process(
if (parse->lastformat != parsetime->parse_format)
{
parsectl_t tmpctl;
-
+
tmpctl.parseformat.parse_format = parsetime->parse_format;
if (!PARSE_GETFMT(parse, &tmpctl))
@@ -3681,10 +3869,10 @@ parse_process(
/*
* something happend - except for PPS events
*/
-
+
(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
-
+
NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
CLK_UNIT(parse->peer), tmp2, tmp1);
@@ -3716,7 +3904,7 @@ parse_process(
* for PARSE Meinberg DCF77 receivers the lost synchronisation
* is true as it is the powerup state and the time is taken
* from a crude real time clock chip
- * for the PZF series this is only partly true, as
+ * for the PZF/GPS series this is only partly true, as
* PARSE_POWERUP only means that the pseudo random
* phase shift sequence cannot be found. this is only
* bad, if we have never seen the clock in the SYNC
@@ -3734,11 +3922,14 @@ parse_process(
* interval. fortunately powerdowns last usually longer than 64
* seconds and the receiver is at least 2 minutes in the
* POWERUP or NOSYNC state before switching to SYNC
+ * for GPS receivers this can mean antenna problems and other causes.
+ * the additional grace period can be enables by a clock
+ * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
*/
parse_event(parse, CEVNT_FAULT);
NLOG(NLOG_CLOCKSTATUS)
ERR(ERR_BADSTATUS)
- msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
+ msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
CLK_UNIT(parse->peer));
}
else
@@ -3784,12 +3975,12 @@ parse_process(
}
fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
-
+
if (PARSE_TIMECODE(parsetime->parse_state))
{
rectime = parsetime->parse_stime.fp;
off = reftime = parsetime->parse_time.fp;
-
+
L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
#ifdef DEBUG
@@ -3811,7 +4002,7 @@ parse_process(
/*
* set fudge = 0.0 if already included in PPS time stamps
*/
- if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
+ if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
{
ppsphaseadjust = 0.0;
}
@@ -3830,11 +4021,11 @@ parse_process(
#endif
if (PARSE_TIMECODE(parsetime->parse_state))
{
- if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
- M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
+ if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
+ M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
{
fudge = ppsphaseadjust; /* pick PPS fudge factor */
-
+
/*
* RS232 offsets within [-0.5..0.5[ - take PPS offsets
*/
@@ -3842,16 +4033,16 @@ parse_process(
if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
{
reftime = off = offset;
- if (reftime.l_uf & (unsigned)0x80000000)
+ if (reftime.l_uf & 0x80000000)
reftime.l_ui++;
reftime.l_uf = 0;
-
+
/*
* implied on second offset
*/
off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
- off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
+ off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
}
else
{
@@ -3876,14 +4067,14 @@ parse_process(
*/
off = offset;
reftime = offset;
- if (reftime.l_uf & (unsigned)0x80000000)
+ if (reftime.l_uf & 0x80000000)
reftime.l_ui++;
reftime.l_uf = 0;
/*
* implied on second offset
*/
off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
- off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
+ off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
}
}
else
@@ -3912,7 +4103,7 @@ parse_process(
rectime = reftime;
L_SUB(&rectime, &off); /* just to keep the ntp interface happy */
-
+
#ifdef DEBUG
if (debug > 3)
printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
@@ -3937,20 +4128,21 @@ parse_process(
clear_err(parse, ERR_BADDATA);
clear_err(parse, ERR_NODATA);
clear_err(parse, ERR_INTERNAL);
-
+
/*
* and now stick it into the clock machine
* samples are only valid iff lastsync is not too old and
* we have seen the clock in sync at least once
* after the last time we didn't see an expected data telegram
* at startup being not in sync is also bad just like
- * POWERUP state
+ * POWERUP state unless PARSE_F_POWERUPTRUST is set
* see the clock states section above for more reasoning
*/
- if (((current_time - parse->lastsync) > parse->maxunsync) ||
- (parse->lastsync < parse->lastmissed) ||
+ if (((current_time - parse->lastsync) > parse->maxunsync) ||
+ (parse->lastsync < parse->lastmissed) ||
((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
- PARSE_POWERUP(parsetime->parse_state))
+ (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
+ PARSE_POWERUP(parsetime->parse_state)))
{
parse->generic->leap = LEAP_NOTINSYNC;
parse->lastsync = 0; /* wait for full sync again */
@@ -3983,9 +4175,9 @@ parse_process(
* only good/trusted samples are interesting
*/
#ifdef DEBUG
- if (debug > 2)
- {
- printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
+ if (debug > 2)
+ {
+ printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
CLK_UNIT(parse->peer),
prettydate(&reftime),
prettydate(&rectime),
@@ -3993,23 +4185,26 @@ parse_process(
}
#endif
parse->generic->lastref = reftime;
-
+
refclock_process_offset(parse->generic, reftime, rectime, fudge);
+#ifdef HAVE_PPSAPI
/*
* pass PPS information on to PPS clock
*/
if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
- {
- (void) pps_sample(&parse->timedata.parse_ptime.fp);
+ {
+ parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS);
parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
}
+#endif
} else {
- parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
+ parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
+ parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS);
}
/*
- * ready, unless the machine wants a sample or
+ * ready, unless the machine wants a sample or
* we are in fast startup mode (peer->dist > MAXDISTANCE)
*/
if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
@@ -4021,56 +4216,71 @@ parse_process(
refclock_receive(parse->peer);
}
-
+
/**===========================================================================
** special code for special clocks
**/
static void
mk_utcinfo(
- char *t,
+ char *t, // pointer to the output string buffer
int wnt,
int wnlsf,
int dn,
int dtls,
int dtlsf,
- int size
+ int size // size of the output string buffer
)
{
- l_fp leapdate;
- char *start = t;
-
- snprintf(t, size, "current correction %d sec", dtls);
- t += strlen(t);
-
- if (wnlsf < 990)
- wnlsf += 1024;
-
- if (wnt < 990)
- wnt += 1024;
-
- gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
-
- if ((dtlsf != dtls) &&
- ((wnlsf - wnt) < 52))
- {
- snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
- dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
- }
- else
- {
- snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
- gmprettydate(&leapdate));
- }
+ /*
+ * The week number transmitted by the GPS satellites for the leap date
+ * is truncated to 8 bits only. If the nearest leap second date is off
+ * the current date by more than +/- 128 weeks then conversion to a
+ * calendar date is ambiguous. On the other hand, if a leap second is
+ * currently being announced (i.e. dtlsf != dtls) then the week number
+ * wnlsf is close enough, and we can unambiguously determine the date
+ * for which the leap second is scheduled.
+ */
+ if ( dtlsf != dtls )
+ {
+ time_t t_ls;
+ struct tm *tm;
+ int n = 0;
+
+ if (wnlsf < GPSWRAP)
+ wnlsf += GPSWEEKS;
+
+ if (wnt < GPSWRAP)
+ wnt += GPSWEEKS;
+
+ t_ls = (time_t) wnlsf * SECSPERWEEK
+ + (time_t) dn * SECSPERDAY
+ + GPS_SEC_BIAS - 1;
+
+ tm = gmtime( &t_ls );
+ if (tm == NULL) // gmtime() failed
+ {
+ snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" );
+ return;
+ }
+
+ n += snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s",
+ dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" );
+ n += snprintf( t + n, size - n, " at UTC midnight at the end of %s, %04i-%02i-%02i",
+ daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
+ }
+ else
+ snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls );
+
}
#ifdef CLOCK_MEINBERG
/**===========================================================================
- ** Meinberg GPS166/GPS167 support
+ ** Meinberg GPS receiver support
**/
/*------------------------------------------------------------
- * gps16x_message - process GPS16x messages
+ * gps16x_message - process messages from Meinberg GPS receiver
*/
static void
gps16x_message(
@@ -4082,12 +4292,12 @@ gps16x_message(
{
GPS_MSG_HDR header;
unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
-
+
#ifdef DEBUG
if (debug > 2)
{
char msgbuffer[600];
-
+
mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
CLK_UNIT(parse->peer),
@@ -4096,21 +4306,21 @@ gps16x_message(
}
#endif
get_mbg_header(&bufp, &header);
- if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
- (header.gps_len == 0 ||
- (header.gps_len < sizeof(parsetime->parse_msg) &&
- header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
+ if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
+ (header.len == 0 ||
+ (header.len < sizeof(parsetime->parse_msg) &&
+ header.data_csum == mbg_csum(bufp, header.len))))
{
/*
* clean message
*/
- switch (header.gps_cmd)
+ switch (header.cmd)
{
case GPS_SW_REV:
{
char buffer[64];
SW_REV gps_sw_rev;
-
+
get_mbg_sw_rev(&bufp, &gps_sw_rev);
snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
(gps_sw_rev.code >> 8) & 0xFF,
@@ -4121,54 +4331,56 @@ gps16x_message(
}
break;
- case GPS_STAT:
+ case GPS_BVAR_STAT:
{
static struct state
{
- unsigned short flag; /* status flag */
- unsigned const char *string; /* bit name */
+ BVAR_STAT flag; /* status flag */
+ const char *string; /* bit name */
} states[] =
{
- { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
- { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" },
- { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" },
- { TM_NO_POS, (const unsigned char *)"NO POSITION" },
- { 0, (const unsigned char *)"" }
+ { BVAR_CFGH_INVALID, "Configuration/Health" },
+ { BVAR_ALM_NOT_COMPLETE, "Almanachs" },
+ { BVAR_UTC_INVALID, "UTC Correction" },
+ { BVAR_IONO_INVALID, "Ionospheric Correction" },
+ { BVAR_RCVR_POS_INVALID, "Receiver Position" },
+ { 0, "" }
};
- unsigned short status;
+ BVAR_STAT status;
struct state *s = states;
char buffer[512];
char *p, *b;
-
- status = get_lsb_short(&bufp);
- snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
-
+
+ status = (BVAR_STAT) get_lsb_short(&bufp);
+ p = b = buffer;
+ p = ap(buffer, sizeof(buffer), p,
+ "meinberg_gps_status=\"[0x%04x] ",
+ status);
+
if (status)
{
- p = b = buffer + strlen(buffer);
+ p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: ");
+ b = p;
while (s->flag)
{
if (status & s->flag)
{
if (p != b)
{
- *p++ = ',';
- *p++ = ' ';
+ p = ap(buffer, sizeof(buffer), p, ", ");
}
-
- strncat(p, (const char *)s->string, sizeof(buffer));
+
+ p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
}
s++;
}
-
- *p++ = '"';
- *p = '\0';
+ p = ap(buffer, sizeof(buffer), p, "\"");
}
else
{
- strncat(buffer, "<OK>\"", sizeof(buffer));
+ p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\"");
}
-
+
set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
}
break;
@@ -4177,282 +4389,259 @@ gps16x_message(
{
XYZ xyz;
char buffer[256];
-
+
get_mbg_xyz(&bufp, xyz);
snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
-
+
set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
break;
-
+
case GPS_POS_LLA:
{
LLA lla;
char buffer[256];
-
+
get_mbg_lla(&bufp, lla);
-
+
snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
- mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
+ mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
-
+
set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
break;
-
+
case GPS_TZDL:
break;
-
+
case GPS_PORT_PARM:
break;
-
+
case GPS_SYNTH:
break;
-
+
case GPS_ANT_INFO:
{
ANT_INFO antinfo;
char buffer[512];
- char *p;
-
+ char *p, *q;
+
get_mbg_antinfo(&bufp, &antinfo);
- snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
- p = buffer + strlen(buffer);
-
+ p = buffer;
+ p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
switch (antinfo.status)
{
- case ANT_INVALID:
- strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
- p += strlen(p);
+ case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected
+ p = ap(buffer, sizeof(buffer),
+ p, "<OK>");
break;
-
- case ANT_DISCONN:
- strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
+
+ case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set
+ q = ap(buffer, sizeof(buffer),
+ p, "DISCONNECTED since ");
NLOG(NLOG_CLOCKSTATUS)
ERR(ERR_BADSTATUS)
msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
CLK_UNIT(parse->peer), p);
-
- p += strlen(p);
- mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
+
+ p = q;
+ mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
*p = '\0';
break;
-
- case ANT_RECONN:
- strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
- p += strlen(p);
- mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
- snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
+
+ case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid
+ p = ap(buffer, sizeof(buffer),
+ p, "SYNC AFTER RECONNECT on ");
+ mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0);
+ p = ap(buffer, sizeof(buffer),
+ p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ",
(antinfo.delta_t < 0) ? '-' : '+',
- ABS(antinfo.delta_t) / 10000,
- ABS(antinfo.delta_t) % 10000);
- p += strlen(p);
- mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
+ (long) ABS(antinfo.delta_t) / 10000,
+ (long) ABS(antinfo.delta_t) % 10000);
+ mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
*p = '\0';
break;
-
+
default:
- snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
- p += strlen(p);
+ p = ap(buffer, sizeof(buffer),
+ p, "bad status 0x%04x",
+ antinfo.status);
break;
}
-
- strncat(p, "\"", BUFFER_SIZE(buffer, p));
-
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
+
+ p = ap(buffer, sizeof(buffer), p, "\"");
+
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
break;
-
+
case GPS_UCAP:
break;
-
+
case GPS_CFGH:
{
CFGH cfgh;
char buffer[512];
char *p;
-
+
get_mbg_cfgh(&bufp, &cfgh);
if (cfgh.valid)
{
+ const char *cp;
+ uint16_t tmp_val;
int i;
-
+
p = buffer;
- strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
- p += strlen(p);
+ p = ap(buffer, sizeof(buffer),
+ p, "gps_tot_51=\"");
mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
- strncpy(p, "\"", BUFFER_SIZE(buffer, p));
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
-
+ p = ap(buffer, sizeof(buffer),
+ p, "\"");
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
+
p = buffer;
- strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
- p += strlen(p);
+ p = ap(buffer, sizeof(buffer),
+ p, "gps_tot_63=\"");
mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
- strncpy(p, "\"", BUFFER_SIZE(buffer, p));
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
-
+ p = ap(buffer, sizeof(buffer),
+ p, "\"");
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
+
p = buffer;
- strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
- p += strlen(p);
+ p = ap(buffer, sizeof(buffer),
+ p, "gps_t0a=\"");
mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
- strncpy(p, "\"", BUFFER_SIZE(buffer, p));
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
-
- for (i = MIN_SVNO; i < MAX_SVNO; i++)
+ p = ap(buffer, sizeof(buffer),
+ p, "\"");
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
+
+ for (i = 0; i < N_SVNO_GPS; i++)
{
p = buffer;
- snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
- p += strlen(p);
- switch (cfgh.cfg[i] & 0x7)
- {
- case 0:
- strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
- break;
- case 1:
- strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
- break;
- default:
- strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
- break;
- }
- strncat(p, "\"", BUFFER_SIZE(buffer, p));
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
-
- p = buffer;
- snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
- p += strlen(p);
- switch ((cfgh.health[i] >> 5) & 0x7 )
- {
- case 0:
- strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
- break;
- case 1:
- strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
- break;
- case 2:
- strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
- break;
- case 3:
- strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
- break;
- case 4:
- strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
- break;
- case 5:
- strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
- break;
- case 6:
- strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
- break;
- case 7:
- strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
- break;
+ p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS);
+
+ tmp_val = cfgh.health[i]; /* a 6 bit SV health code */
+ p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val);
+ /* "All Ones" has a special meaning" */
+ if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */
+ cp = "SV UNAVAILABLE";
+ else {
+ /* The MSB contains a summary of the 3 MSBs of the 8 bit health code,
+ * indicating if the data sent by the satellite is OK or not. */
+ p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" );
+
+ /* The 5 LSBs contain the status of the different signals sent by the satellite. */
+ switch (tmp_val & 0x1F)
+ {
+ case 0x00: cp = "SIGNAL OK"; break;
+ /* codes 0x01 through 0x1B indicate that one or more
+ * specific signal components are weak or dead.
+ * We don't decode this here in detail. */
+ case 0x1C: cp = "SV IS TEMP OUT"; break;
+ case 0x1D: cp = "SV WILL BE TEMP OUT"; break;
+ default: cp = "TRANSMISSION PROBLEMS"; break;
+ }
}
-
- p += strlen(p);
-
- switch (cfgh.health[i] & 0x1F)
+ p = ap(buffer, sizeof(buffer), p, "%s)", cp );
+
+ tmp_val = cfgh.cfg[i]; /* a 4 bit SV configuration/type code */
+ p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val);
+ switch (tmp_val & 0x7)
{
- case 0:
- strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
- break;
- case 0x1C:
- strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
- break;
- case 0x1D:
- strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
- break;
- case 0x1E:
- break;
- case 0x1F:
- strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
- break;
- default:
- strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
- break;
+ case 0x00: cp = "(reserved)"; break;
+ case 0x01: cp = "BLOCK II/IIA/IIR"; break;
+ case 0x02: cp = "BLOCK IIR-M"; break;
+ case 0x03: cp = "BLOCK IIF"; break;
+ case 0x04: cp = "BLOCK III"; break;
+ default: cp = "unknown SV type"; break;
}
-
- strncat(p, "\"", sizeof(buffer));
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
+ p = ap(buffer, sizeof(buffer), p, "%s", cp );
+ if (tmp_val & 0x08) /* A-S is on, P-code is encrypted */
+ p = ap( buffer, sizeof(buffer), p, ", A-S on" );
+
+ p = ap(buffer, sizeof(buffer), p, ")\"");
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
}
}
}
break;
-
+
case GPS_ALM:
break;
-
+
case GPS_EPH:
break;
-
+
case GPS_UTC:
{
UTC utc;
char buffer[512];
char *p;
-
+
p = buffer;
-
+
get_mbg_utc(&bufp, &utc);
-
+
if (utc.valid)
{
- strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
- p += strlen(p);
+ p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
- strncat(p, "\"", BUFFER_SIZE(buffer, p));
+ p += strlen(p);
+ p = ap(buffer, sizeof(buffer), p, "\"");
}
else
{
- strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
+ p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
}
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
break;
-
+
case GPS_IONO:
break;
-
+
case GPS_ASCII_MSG:
{
ASCII_MSG gps_ascii_msg;
char buffer[128];
-
+
get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
-
+
if (gps_ascii_msg.valid)
{
char buffer1[128];
mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
-
+
snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
}
else
- strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
-
- set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
+ snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
+
+ set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
-
+
break;
-
+
default:
break;
}
}
else
{
- msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
+ msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), "
+ "data_len = %d, data_csum = 0x%x (expected 0x%x)",
CLK_UNIT(parse->peer),
- header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
- header.gps_len,
- header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
+ header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
+ header.len,
+ header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0)));
}
}
-
+
return;
}
@@ -4464,12 +4653,12 @@ gps16x_poll(
struct peer *peer
)
{
- struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
-
- static GPS_MSG_HDR sequence[] =
+ struct parseunit *parse = peer->procptr->unitptr;
+
+ static GPS_MSG_HDR sequence[] =
{
{ GPS_SW_REV, 0, 0, 0 },
- { GPS_STAT, 0, 0, 0 },
+ { GPS_BVAR_STAT, 0, 0, 0 },
{ GPS_UTC, 0, 0, 0 },
{ GPS_ASCII_MSG, 0, 0, 0 },
{ GPS_ANT_INFO, 0, 0, 0 },
@@ -4478,46 +4667,46 @@ gps16x_poll(
{ GPS_POS_LLA, 0, 0, 0 },
{ (unsigned short)~0, 0, 0, 0 }
};
-
+
int rtc;
unsigned char cmd_buffer[64];
unsigned char *outp = cmd_buffer;
GPS_MSG_HDR *header;
-
+
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
- parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
+ parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
}
- if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
+ if (sequence[parse->localstate].cmd == (unsigned short)~0)
parse->localstate = 0;
-
+
header = sequence + parse->localstate++;
-
+
*outp++ = SOH; /* start command */
-
+
put_mbg_header(&outp, header);
outp = cmd_buffer + 1;
-
- header->gps_hdr_csum = (short)mbg_csum(outp, 6);
+
+ header->hdr_csum = (short)mbg_csum(outp, 6);
put_mbg_header(&outp, header);
-
+
#ifdef DEBUG
if (debug > 2)
{
char buffer[128];
-
+
mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
CLK_UNIT(parse->peer),
parse->localstate - 1,
(int)(outp - cmd_buffer),
- buffer);
+ buffer);
}
#endif
-
- rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
-
+
+ rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
+
if (rtc < 0)
{
ERR(ERR_BADIO)
@@ -4544,7 +4733,7 @@ gps16x_poll_init(
{
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
- parse->peer->action = gps16x_poll;
+ parse->peer->procptr->action = gps16x_poll;
gps16x_poll(parse->peer);
}
@@ -4566,7 +4755,7 @@ gps16x_poll_init(
return 1;
}
#endif /* CLOCK_MEINBERG */
-
+
/**===========================================================================
** clock polling support
**/
@@ -4579,11 +4768,11 @@ poll_dpoll(
struct parseunit *parse
)
{
- int rtc;
+ long rtc;
const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
- int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
+ long ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
- rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
+ rtc = write(parse->generic->io.fd, ps, ct);
if (rtc < 0)
{
ERR(ERR_BADIO)
@@ -4593,7 +4782,7 @@ poll_dpoll(
if (rtc != ct)
{
ERR(ERR_BADIO)
- msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
+ msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
}
clear_err(parse, ERR_BADIO);
}
@@ -4606,14 +4795,14 @@ poll_poll(
struct peer *peer
)
{
- struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
-
+ struct parseunit *parse = peer->procptr->unitptr;
+
if (parse->parse_type->cl_poll)
parse->parse_type->cl_poll(parse);
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
- parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
+ parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
}
}
@@ -4627,13 +4816,13 @@ poll_init(
{
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
- parse->peer->action = poll_poll;
+ parse->peer->procptr->action = poll_poll;
poll_poll(parse->peer);
}
return 0;
}
-
+
/**===========================================================================
** Trimble support
**/
@@ -4663,7 +4852,7 @@ trimbletaip_init(
else
{
tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
-
+
if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
@@ -4682,7 +4871,7 @@ static const char *taipinit[] = {
">FTM00020001<",
(char *)0
};
-
+
static void
trimbletaip_event(
struct parseunit *parse,
@@ -4699,7 +4888,7 @@ trimbletaip_event(
iv = taipinit;
while (*iv)
{
- int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
+ int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv));
if (rtc < 0)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
@@ -4707,7 +4896,7 @@ trimbletaip_event(
}
else
{
- if (rtc != strlen(*iv))
+ if (rtc != (int)strlen(*iv))
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
@@ -4827,19 +5016,19 @@ union uval {
float fv;
double dv;
};
-
+
struct txbuf
{
short idx; /* index to first unused byte */
u_char *txt; /* pointer to actual data buffer */
};
-void sendcmd P((struct txbuf *buf, int c));
-void sendbyte P((struct txbuf *buf, int b));
-void sendetx P((struct txbuf *buf, struct parseunit *parse));
-void sendint P((struct txbuf *buf, int a));
-void sendflt P((struct txbuf *buf, double a));
-
+void sendcmd (struct txbuf *buf, int c);
+void sendbyte (struct txbuf *buf, int b);
+void sendetx (struct txbuf *buf, struct parseunit *parse);
+void sendint (struct txbuf *buf, int a);
+void sendflt (struct txbuf *buf, double a);
+
void
sendcmd(
struct txbuf *buf,
@@ -4851,12 +5040,12 @@ sendcmd(
buf->idx = 2;
}
-void sendcmd P((struct txbuf *buf, int c));
-void sendbyte P((struct txbuf *buf, int b));
-void sendetx P((struct txbuf *buf, struct parseunit *parse));
-void sendint P((struct txbuf *buf, int a));
-void sendflt P((struct txbuf *buf, double a));
-
+void sendcmd (struct txbuf *buf, int c);
+void sendbyte (struct txbuf *buf, int b);
+void sendetx (struct txbuf *buf, struct parseunit *parse);
+void sendint (struct txbuf *buf, int a);
+void sendflt (struct txbuf *buf, double a);
+
void
sendbyte(
struct txbuf *buf,
@@ -4888,18 +5077,18 @@ sendetx(
if (debug > 2)
{
char buffer[256];
-
+
mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
CLK_UNIT(parse->peer),
- buf->idx, buffer);
+ buf->idx, buffer);
}
#endif
clear_err(parse, ERR_BADIO);
}
}
-void
+void
sendint(
struct txbuf *buf,
int a
@@ -4919,7 +5108,7 @@ sendflt(
int i;
union uval uval;
- uval.fv = a;
+ uval.fv = (float) a;
#ifdef WORDS_BIGENDIAN
for (i=0; i<=3; i++)
#else
@@ -4951,12 +5140,12 @@ trimbletsip_setup(
if (t)
t->last_reset = current_time;
-
+
buf.txt = buffer;
-
+
sendcmd(&buf, CMD_CVERSION); /* request software versions */
sendetx(&buf, parse);
-
+
sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */
sendbyte(&buf, 4); /* static */
sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
@@ -4964,25 +5153,25 @@ trimbletsip_setup(
sendflt(&buf, 12.0); /* PDOP mask = 12 */
sendflt(&buf, 8.0); /* PDOP switch level = 8 */
sendetx(&buf, parse);
-
+
sendcmd(&buf, CMD_CMODESEL); /* fix mode select */
sendbyte(&buf, 1); /* time transfer mode */
sendetx(&buf, parse);
-
+
sendcmd(&buf, CMD_CMESSAGE); /* request system message */
sendetx(&buf, parse);
-
+
sendcmd(&buf, CMD_CSUPER); /* superpacket fix */
sendbyte(&buf, 0x2); /* binary mode */
sendetx(&buf, parse);
-
+
sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */
sendbyte(&buf, TRIM_POS_OPT); /* position output */
sendbyte(&buf, 0x00); /* no velocity output */
sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */
sendbyte(&buf, 0x00); /* no raw measurements */
sendetx(&buf, parse);
-
+
sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */
sendetx(&buf, parse);
@@ -5001,12 +5190,12 @@ trimble_check(
struct peer *peer
)
{
- struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
+ struct parseunit *parse = peer->procptr->unitptr;
trimble_t *t = parse->localdata;
u_char buffer[256];
struct txbuf buf;
buf.txt = buffer;
-
+
if (t)
{
if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
@@ -5014,18 +5203,18 @@ trimble_check(
}
poll_poll(parse->peer); /* emit query string and re-arm timer */
-
+
if (t && t->qtracking)
{
u_long oldsats = t->ltrack & ~t->ctrack;
-
+
t->qtracking = 0;
t->ltrack = t->ctrack;
-
+
if (oldsats)
{
int i;
-
+
for (i = 0; oldsats; i++) {
if (oldsats & (1 << i))
{
@@ -5036,7 +5225,7 @@ trimble_check(
oldsats &= ~(1 << i);
}
}
-
+
sendcmd(&buf, CMD_CSTATTRACK);
sendbyte(&buf, 0x00); /* current tracking set */
sendetx(&buf, parse);
@@ -5051,14 +5240,14 @@ trimbletsip_end(
struct parseunit *parse
)
{ trimble_t *t = parse->localdata;
-
+
if (t)
{
free(t);
- parse->localdata = (void *)0;
+ parse->localdata = NULL;
}
- parse->peer->nextaction = 0;
- parse->peer->action = (void (*) P((struct peer *)))0;
+ parse->peer->procptr->nextaction = 0;
+ parse->peer->procptr->action = NULL;
}
/*--------------------------------------------------
@@ -5082,9 +5271,9 @@ trimbletsip_init(
if (!parse->localdata)
{
trimble_t *t;
-
+
t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
-
+
if (t)
{
memset((char *)t, 0, sizeof(trimble_t));
@@ -5092,8 +5281,8 @@ trimbletsip_init(
}
}
- parse->peer->action = trimble_check;
- parse->peer->nextaction = current_time;
+ parse->peer->procptr->action = trimble_check;
+ parse->peer->procptr->nextaction = current_time;
/*
* configure terminal line for ICANON mode with VEOL characters
@@ -5164,7 +5353,7 @@ getflt(
)
{
union uval uval;
-
+
#ifdef WORDS_BIGENDIAN
uval.bd[0] = *bp++;
uval.bd[1] = *bp++;
@@ -5185,7 +5374,7 @@ getdbl(
)
{
union uval uval;
-
+
#ifdef WORDS_BIGENDIAN
uval.bd[0] = *bp++;
uval.bd[1] = *bp++;
@@ -5213,7 +5402,7 @@ getshort(
unsigned char *p
)
{
- return get_msb_short(&p);
+ return (int) get_msb_short(&p);
}
/*--------------------------------------------------
@@ -5230,7 +5419,7 @@ trimbletsip_message(
{
unsigned char *buffer = parsetime->parse_msg;
unsigned int size = parsetime->parse_msglen;
-
+
if ((size < 4) ||
(buffer[0] != DLE) ||
(buffer[size-1] != ETX) ||
@@ -5238,7 +5427,7 @@ trimbletsip_message(
{
#ifdef DEBUG
if (debug > 2) {
- int i;
+ size_t i;
printf("TRIMBLE BAD packet, size %d:\n ", size);
for (i = 0; i < size; i++) {
@@ -5252,16 +5441,16 @@ trimbletsip_message(
}
else
{
- int var_flag;
+ u_short var_flag;
trimble_t *tr = parse->localdata;
unsigned int cmd = buffer[1];
char pbuffer[200];
char *t = pbuffer;
cmd_info_t *s;
-
+
#ifdef DEBUG
if (debug > 3) {
- int i;
+ size_t i;
printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
for (i = 0; i < size; i++) {
@@ -5274,12 +5463,12 @@ trimbletsip_message(
if (tr)
tr->last_msg = current_time;
-
+
s = trimble_convert(cmd, trimble_rcmds);
-
+
if (s)
{
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
+ t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
}
else
{
@@ -5287,47 +5476,43 @@ trimbletsip_message(
return;
}
- var_flag = s->varmode;
+ var_flag = (u_short) s->varmode;
- t += strlen(t);
-
switch(cmd)
{
case CMD_RCURTIME:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
+ t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
getflt((unsigned char *)&mb(6)));
break;
-
+
case CMD_RBEST4:
- strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
- t += strlen(t);
+ t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
switch (mb(0) & 0xF)
{
default:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
+ t = ap(pbuffer, sizeof(pbuffer), t,
+ "0x%x", mb(0) & 0x7);
break;
case 1:
- strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "0D");
break;
-
+
case 3:
- strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "2D");
break;
-
+
case 4:
- strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "3D");
break;
}
- t += strlen(t);
if (mb(0) & 0x10)
- strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
else
- strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
- t += strlen(t);
-
- snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
+ t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
+
+ t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
mb(1), mb(2), mb(3), mb(4),
getflt((unsigned char *)&mb(5)),
getflt((unsigned char *)&mb(9)),
@@ -5335,12 +5520,12 @@ trimbletsip_message(
getflt((unsigned char *)&mb(17)));
break;
-
+
case CMD_RVERSION:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
+ t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
break;
-
+
case CMD_RRECVHEALTH:
{
static const char *msgs[] =
@@ -5354,57 +5539,54 @@ trimbletsip_message(
"<BIT 6>",
"<BIT 7>"
};
-
+
int i, bits;
-
+
switch (mb(0) & 0xFF)
{
default:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
+ t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
break;
case 0x00:
- strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
break;
case 0x01:
- strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
break;
case 0x03:
- strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
break;
case 0x08:
- strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
break;
case 0x09:
- strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
break;
case 0x0A:
- strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
break;
case 0x0B:
- strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
break;
case 0x0C:
- strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
break;
}
- t += strlen(t);
-
bits = mb(1) & 0xFF;
-
+
for (i = 0; i < 8; i++)
if (bits & (0x1<<i))
{
- snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
- t += strlen(t);
+ t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
}
}
break;
-
+
case CMD_RMESSAGE:
mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
break;
-
+
case CMD_RMACHSTAT:
{
static const char *msgs[] =
@@ -5418,59 +5600,56 @@ trimbletsip_message(
"<BIT 6>",
"<BIT 7>"
};
-
+
int i, bits;
- snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
- t += strlen(t);
-
+ t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
bits = mb(1) & 0xFF;
-
+
for (i = 0; i < 8; i++)
if (bits & (0x1<<i))
{
- snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
- t += strlen(t);
+ t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
}
- snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
+ t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
}
break;
-
+
case CMD_ROPERPARAM:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
+ t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
break;
-
+
case CMD_RUTCPARAM:
{
float t0t = getflt((unsigned char *)&mb(14));
- short wnt = getshort((unsigned char *)&mb(18));
- short dtls = getshort((unsigned char *)&mb(12));
- short wnlsf = getshort((unsigned char *)&mb(20));
- short dn = getshort((unsigned char *)&mb(22));
- short dtlsf = getshort((unsigned char *)&mb(24));
+ short wnt = (short) getshort((unsigned char *)&mb(18));
+ short dtls = (short) getshort((unsigned char *)&mb(12));
+ short wnlsf = (short) getshort((unsigned char *)&mb(20));
+ short dn = (short) getshort((unsigned char *)&mb(22));
+ short dtlsf = (short) getshort((unsigned char *)&mb(24));
if ((int)t0t != 0)
- {
- mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
- }
+ {
+ mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
+ }
else
- {
- strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
- }
+ {
+ t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
+ }
}
break;
case CMD_RSAT1BIAS:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
+ t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
break;
case CMD_RIOOPTIONS:
{
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
+ t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
mb(0), mb(1), mb(2), mb(3));
if (mb(0) != TRIM_POS_OPT ||
mb(2) != TRIM_TIME_OPT)
@@ -5479,20 +5658,20 @@ trimbletsip_message(
}
}
break;
-
+
case CMD_RSPOSXYZ:
{
double x = getflt((unsigned char *)&mb(0));
double y = getflt((unsigned char *)&mb(4));
double z = getflt((unsigned char *)&mb(8));
double f = getflt((unsigned char *)&mb(12));
-
+
if (f > 0.0)
- snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
+ t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
x, y, z,
f);
else
- return;
+ return;
}
break;
@@ -5501,14 +5680,14 @@ trimbletsip_message(
double lat = getflt((unsigned char *)&mb(0));
double lng = getflt((unsigned char *)&mb(4));
double f = getflt((unsigned char *)&mb(12));
-
+
if (f > 0.0)
- snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
+ t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
getflt((unsigned char *)&mb(8)));
else
- return;
+ return;
}
break;
@@ -5517,16 +5696,16 @@ trimbletsip_message(
double x = getdbl((unsigned char *)&mb(0));
double y = getdbl((unsigned char *)&mb(8));
double z = getdbl((unsigned char *)&mb(16));
- snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
+ t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
x, y, z);
}
break;
-
+
case CMD_RDOUBLELLA:
{
double lat = getdbl((unsigned char *)&mb(0));
double lng = getdbl((unsigned char *)&mb(8));
- snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
+ t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
getdbl((unsigned char *)&mb(16)));
@@ -5536,108 +5715,97 @@ trimbletsip_message(
case CMD_RALLINVIEW:
{
int i, sats;
-
- strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
- t += strlen(t);
+
+ t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
switch (mb(0) & 0x7)
{
default:
- snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
+ t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
break;
case 3:
- strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "2D");
break;
-
+
case 4:
- strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "3D");
break;
}
- t += strlen(t);
if (mb(0) & 0x8)
- strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
else
- strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
- t += strlen(t);
-
+ t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
+
sats = (mb(0)>>4) & 0xF;
-
- snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
+
+ t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
getflt((unsigned char *)&mb(1)),
getflt((unsigned char *)&mb(5)),
getflt((unsigned char *)&mb(9)),
getflt((unsigned char *)&mb(13)),
sats, (sats == 1) ? "" : "s");
- t += strlen(t);
for (i=0; i < sats; i++)
{
- snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
- t += strlen(t);
+ t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
if (tr)
tr->ctrack |= (1 << (mb(17+i)-1));
}
if (tr)
- { /* mark for tracking status query */
+ { /* mark for tracking status query */
tr->qtracking = 1;
}
}
break;
-
+
case CMD_RSTATTRACK:
{
- snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
- t += strlen(t);
-
+ t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
if (getflt((unsigned char *)&mb(4)) < 0.0)
{
- strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
- var_flag &= ~DEF;
+ t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
+ var_flag &= (u_short)(~DEF);
}
else
- {
- snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
+ {
+ t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
(mb(1) & 0xFF)>>3,
mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
mb(3),
getflt((unsigned char *)&mb(4)),
getflt((unsigned char *)&mb(12)) * RTOD,
getflt((unsigned char *)&mb(16)) * RTOD);
- t += strlen(t);
if (mb(20))
{
- var_flag &= ~DEF;
- strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
+ var_flag &= (u_short)(~DEF);
+ t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
}
- t += strlen(t);
if (mb(22))
{
if (mb(22) == 1)
- strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
else
if (mb(22) == 2)
- strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
}
- t += strlen(t);
if (mb(23))
- strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
}
}
break;
-
+
default:
- strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
break;
}
- t += strlen(t);
- strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
+ t = ap(pbuffer, sizeof(pbuffer), t, "\"");
set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
}
}
-
+
/**============================================================
** RAWDCF support
**/
@@ -5737,13 +5905,16 @@ rawdcf_init_2(
#endif /* DTR initialisation type */
#else /* defined(REFCLOCK) && defined(PARSE) */
-int refclock_parse_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif /* defined(REFCLOCK) && defined(PARSE) */
/*
* History:
*
* refclock_parse.c,v
+ * Revision 4.81 2009/05/01 10:15:29 kardel
+ * use new refclock_ppsapi interface
+ *
* Revision 4.80 2007/08/11 12:06:29 kardel
* update comments wrt/ to PPS
*
@@ -5858,7 +6029,7 @@ int refclock_parse_bs;
* implement fast refclock startup
*
* Revision 4.50 2005/04/16 20:51:35 kardel
- * set pps_enable = 1 when binding a kernel PPS source
+ * set hardpps_enable = 1 when binding a kernel PPS source
*
* Revision 4.49 2005/04/16 17:29:26 kardel
* add non polling clock type 18 for just listenning to Meinberg clocks
diff --git a/contrib/ntp/ntpd/refclock_pcf.c b/contrib/ntp/ntpd/refclock_pcf.c
index d4e9fd1..45b3475 100644
--- a/contrib/ntp/ntpd/refclock_pcf.c
+++ b/contrib/ntp/ntpd/refclock_pcf.c
@@ -38,9 +38,9 @@
/*
* Function prototypes
*/
-static int pcf_start P((int, struct peer *));
-static void pcf_shutdown P((int, struct peer *));
-static void pcf_poll P((int, struct peer *));
+static int pcf_start (int, struct peer *);
+static void pcf_shutdown (int, struct peer *);
+static void pcf_poll (int, struct peer *);
/*
* Transfer vector
@@ -72,10 +72,10 @@ pcf_start(
/*
* Open device file for reading.
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
fd = open(device, O_RDONLY);
if (fd == -1) {
- (void)sprintf(device, OLDDEVICE, unit);
+ snprintf(device, sizeof(device), OLDDEVICE, unit);
fd = open(device, O_RDONLY);
}
#ifdef DEBUG
@@ -88,7 +88,7 @@ pcf_start(
pp = peer->procptr;
pp->io.clock_recv = noentry;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
@@ -118,7 +118,8 @@ pcf_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- (void)close(pp->io.fd);
+ if (NULL != pp)
+ close(pp->io.fd);
}
@@ -139,11 +140,13 @@ pcf_poll(
pp = peer->procptr;
buf[0] = 0;
- if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) {
+ if (read(pp->io.fd, buf, sizeof(buf)) < (ssize_t)sizeof(buf) || buf[0] != 9) {
refclock_report(peer, CEVNT_FAULT);
return;
}
+ ZERO(tm);
+
tm.tm_mday = buf[11] * 10 + buf[10];
tm.tm_mon = buf[13] * 10 + buf[12] - 1;
tm.tm_year = buf[15] * 10 + buf[14];
diff --git a/contrib/ntp/ntpd/refclock_pst.c b/contrib/ntp/ntpd/refclock_pst.c
index 776e28e..39be051 100644
--- a/contrib/ntp/ntpd/refclock_pst.c
+++ b/contrib/ntp/ntpd/refclock_pst.c
@@ -91,10 +91,10 @@ struct pstunit {
/*
* Function prototypes
*/
-static int pst_start P((int, struct peer *));
-static void pst_shutdown P((int, struct peer *));
-static void pst_receive P((struct recvbuf *));
-static void pst_poll P((int, struct peer *));
+static int pst_start (int, struct peer *);
+static void pst_shutdown (int, struct peer *);
+static void pst_receive (struct recvbuf *);
+static void pst_poll (int, struct peer *);
/*
* Transfer vector
@@ -127,29 +127,27 @@ pst_start(
/*
* Open serial port. Use CLK line discipline, if available.
*/
- (void)sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, SPEED232, LDISC_CLK);
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct pstunit *)emalloc(sizeof(struct pstunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct pstunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = pst_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -157,7 +155,6 @@ pst_start(
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, WWVREFID, 4);
- peer->burst = MAXSTAGE;
return (1);
}
@@ -175,9 +172,11 @@ pst_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct pstunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -202,9 +201,9 @@ pst_receive(
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct pstunit *)pp->unitptr;
+ up = pp->unitptr;
up->lastptr += refclock_gtlin(rbufp, up->lastptr, pp->a_lastcode
+ BMAX - 2 - up->lastptr, &trtmp);
*up->lastptr++ = ' ';
@@ -295,13 +294,11 @@ pst_poll(
* becomes unreachable, declare a timeout and keep going.
*/
pp = peer->procptr;
- up = (struct pstunit *)pp->unitptr;
+ up = pp->unitptr;
up->tcswitch = 0;
up->lastptr = pp->a_lastcode;
if (write(pp->io.fd, "QTQDQMT", 6) != 6)
refclock_report(peer, CEVNT_FAULT);
- if (peer->burst > 0)
- return;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
@@ -313,7 +310,6 @@ pst_poll(
printf("pst: timecode %d %s\n", pp->lencode,
pp->a_lastcode);
#endif
- peer->burst = MAXSTAGE;
pp->polls++;
}
diff --git a/contrib/ntp/ntpd/refclock_ripencc.c b/contrib/ntp/ntpd/refclock_ripencc.c
index d9fa204..602ca9d 100644
--- a/contrib/ntp/ntpd/refclock_ripencc.c
+++ b/contrib/ntp/ntpd/refclock_ripencc.c
@@ -90,7 +90,7 @@
#define TSIP_PARSED_DATA 3
#define TSIP_PARSED_DLE_2 4
-#define UTCF_UTC_AVAIL (unsigned char) (1) /* UTC available */
+#define UTCF_UTC_AVAIL (unsigned char) (1) /* UTC available */
#define UTCF_LEAP_SCHD (unsigned char) (1<<4) /* Leap scheduled */
#define UTCF_LEAP_PNDG (unsigned char) (1<<5) /* Leap pending, will occur at end of day */
@@ -109,128 +109,128 @@
/* TSIP packets have the following structure, whether report or command. */
typedef struct {
short
- counter, /* counter */
- len; /* size of buf; < MAX_RPTBUF unsigned chars */
+ counter, /* counter */
+ len; /* size of buf; < MAX_RPTBUF unsigned chars */
unsigned char
- status, /* TSIP packet format/parse status */
- code, /* TSIP code */
- buf[MAX_RPTBUF];/* report or command string */
+ status, /* TSIP packet format/parse status */
+ code, /* TSIP code */
+ buf[MAX_RPTBUF]; /* report or command string */
} TSIPPKT;
/* TSIP binary data structures */
typedef struct {
unsigned char
- t_oa_raw, SV_health;
+ t_oa_raw, SV_health;
float
- e, t_oa, i_0, OMEGADOT, sqrt_A,
- OMEGA_0, omega, M_0, a_f0, a_f1,
- Axis, n, OMEGA_n, ODOT_n, t_zc;
+ e, t_oa, i_0, OMEGADOT, sqrt_A,
+ OMEGA_0, omega, M_0, a_f0, a_f1,
+ Axis, n, OMEGA_n, ODOT_n, t_zc;
short
- weeknum, wn_oa;
+ weeknum, wn_oa;
} ALM_INFO;
-typedef struct { /* Almanac health page (25) parameters */
+typedef struct { /* Almanac health page (25) parameters */
unsigned char
- WN_a, SV_health[32], t_oa;
+ WN_a, SV_health[32], t_oa;
} ALH_PARMS;
-typedef struct { /* Universal Coordinated Time (UTC) parms */
+typedef struct { /* Universal Coordinated Time (UTC) parms */
double
- A_0;
+ A_0;
float
- A_1;
+ A_1;
short
- delta_t_LS;
+ delta_t_LS;
float
- t_ot;
+ t_ot;
short
- WN_t, WN_LSF, DN, delta_t_LSF;
+ WN_t, WN_LSF, DN, delta_t_LSF;
} UTC_INFO;
-typedef struct { /* Ionospheric info (float) */
+typedef struct { /* Ionospheric info (float) */
float
- alpha_0, alpha_1, alpha_2, alpha_3,
- beta_0, beta_1, beta_2, beta_3;
+ alpha_0, alpha_1, alpha_2, alpha_3,
+ beta_0, beta_1, beta_2, beta_3;
} ION_INFO;
-typedef struct { /* Subframe 1 info (float) */
+typedef struct { /* Subframe 1 info (float) */
short
- weeknum;
+ weeknum;
unsigned char
- codeL2, L2Pdata, SVacc_raw, SV_health;
+ codeL2, L2Pdata, SVacc_raw, SV_health;
short
- IODC;
+ IODC;
float
- T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
+ T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
} EPHEM_CLOCK;
-typedef struct { /* Ephemeris info (float) */
+typedef struct { /* Ephemeris info (float) */
unsigned char
- IODE, fit_interval;
+ IODE, fit_interval;
float
- C_rs, delta_n;
+ C_rs, delta_n;
double
- M_0;
+ M_0;
float
- C_uc;
+ C_uc;
double
- e;
+ e;
float
- C_us;
+ C_us;
double
- sqrt_A;
+ sqrt_A;
float
- t_oe, C_ic;
+ t_oe, C_ic;
double
- OMEGA_0;
+ OMEGA_0;
float
- C_is;
+ C_is;
double
- i_0;
+ i_0;
float
- C_rc;
+ C_rc;
double
- omega;
+ omega;
float
- OMEGADOT, IDOT;
+ OMEGADOT, IDOT;
double
- Axis, n, r1me2, OMEGA_n, ODOT_n;
+ Axis, n, r1me2, OMEGA_n, ODOT_n;
} EPHEM_ORBIT;
-typedef struct { /* Navigation data structure */
+typedef struct { /* Navigation data structure */
short
- sv_number; /* SV number (0 = no entry) */
+ sv_number; /* SV number (0 = no entry) */
float
- t_ephem; /* time of ephemeris collection */
+ t_ephem; /* time of ephemeris collection */
EPHEM_CLOCK
- ephclk; /* subframe 1 data */
+ ephclk; /* subframe 1 data */
EPHEM_ORBIT
- ephorb; /* ephemeris data */
+ ephorb; /* ephemeris data */
} NAV_INFO;
typedef struct {
unsigned char
- bSubcode,
- operating_mode,
- dgps_mode,
- dyn_code,
- trackmode;
+ bSubcode,
+ operating_mode,
+ dgps_mode,
+ dyn_code,
+ trackmode;
float
- elev_mask,
- cno_mask,
- dop_mask,
- dop_switch;
+ elev_mask,
+ cno_mask,
+ dop_mask,
+ dop_switch;
unsigned char
- dgps_age_limit;
+ dgps_age_limit;
} TSIP_RCVR_CFG;
#ifdef TRIMBLE_OUTPUT_FUNC
static char
- *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
+ *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12},
*st_baud_text_app [] = {"", "", " 300", " 600", " 1200", " 2400",
- " 4800", " 9600", "19200", "38400"},
+ " 4800", " 9600", "19200", "38400"},
*old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"},
*parity_text [] = {"NONE", "ODD", "EVEN"},
*old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"},
@@ -240,12 +240,12 @@ static char
*rcvr_port_text [] = { "Port A ", "Port B ", "Current Port"},
*dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"},
*NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D",
- "3-D", "", "", "OverDetermined Time"},
+ "3-D", "", "", "OverDetermined Time"},
*PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
*PPSPolarityText[] = {"Positive", "Negative"},
*MaskText[] = { "Almanac ", "Ephemeris", "UTC ", "Iono ",
- "GPS Msg ", "Alm Hlth ", "Time Fix ", "SV Select",
- "Ext Event", "Pos Fix ", "Raw Meas "};
+ "GPS Msg ", "Alm Hlth ", "Time Fix ", "SV Select",
+ "Ext Event", "Pos Fix ", "Raw Meas "};
#endif /* TRIMBLE_OUTPUT_FUNC */
@@ -272,116 +272,116 @@ struct ripencc_unit {
/* prototypes for report parsing primitives */
short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index,
- unsigned char *rx_baud_index, unsigned char *char_format_index,
- unsigned char *stop_bits, unsigned char *tx_mode_index,
- unsigned char *rx_mode_index);
+ unsigned char *rx_baud_index, unsigned char *char_format_index,
+ unsigned char *stop_bits, unsigned char *tx_mode_index,
+ unsigned char *rx_mode_index);
short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
- float *t_zc, float *eccentricity, float *t_oa, float *i_0,
- float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
- float *M_0);
+ float *t_zc, float *eccentricity, float *t_oa, float *i_0,
+ float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
+ float *M_0);
short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
- short *week_num);
+ short *week_num);
short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix);
short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset,
- float *time_of_fix);
+ float *time_of_fix);
short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
- unsigned char *minor_nav_version, unsigned char *nav_day,
- unsigned char *nav_month, unsigned char *nav_year,
- unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
- unsigned char *dsp_day, unsigned char *dsp_month,
- unsigned char *dsp_year);
+ unsigned char *minor_nav_version, unsigned char *nav_day,
+ unsigned char *nav_month, unsigned char *nav_year,
+ unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
+ unsigned char *dsp_day, unsigned char *dsp_month,
+ unsigned char *dsp_year);
short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2);
short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn,
- float *snr);
+ float *snr);
short rpt_0x48 (TSIPPKT *rpt, unsigned char *message);
short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health);
short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt,
- float *clock_bias, float *time_of_fix);
+ float *clock_bias, float *time_of_fix);
short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
- unsigned char *alt_flag);
+ unsigned char *alt_flag);
short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
- unsigned char *status3, unsigned char *status4);
+ unsigned char *status3, unsigned char *status4);
short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
- float *snr_mask, float *dop_mask, float *dop_switch);
+ float *snr_mask, float *dop_mask, float *dop_switch);
short rpt_0x4D (TSIPPKT *rpt, float *osc_offset);
short rpt_0x4E (TSIPPKT *rpt, unsigned char *response);
short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data,
- short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
+ short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset,
- float *time_of_fix);
+ float *time_of_fix);
short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
- unsigned char *time_code, unsigned char *aux_code);
+ unsigned char *time_code, unsigned char *aux_code);
short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
- float *time_of_fix);
+ float *time_of_fix);
short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
- unsigned char *diag_code, short *week_num, float *time_of_fix);
+ unsigned char *diag_code, short *week_num, float *time_of_fix);
short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
- unsigned char *sv_prn, unsigned char *data_length,
- unsigned char *data_packet);
+ unsigned char *sv_prn, unsigned char *data_length,
+ unsigned char *data_packet);
short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
- unsigned char status_code[32]);
+ unsigned char status_code[32]);
short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
- float *signal_level, float *code_phase, float *Doppler,
- double *time_of_fix);
+ float *signal_level, float *code_phase, float *Doppler,
+ double *time_of_fix);
short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
- unsigned char *sv_iode, unsigned char *fit_interval_flag,
- float *time_of_collection, float *time_of_eph, float *sv_accy);
+ unsigned char *sv_iode, unsigned char *fit_interval_flag,
+ float *time_of_collection, float *time_of_eph, float *sv_accy);
short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
- unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
- float *signal_level, float *time_of_last_msmt, float *elev,
- float *azim, unsigned char *old_msmt_flag,
- unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
- unsigned char *data_collect_flag);
+ unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
+ float *signal_level, float *time_of_last_msmt, float *elev,
+ float *azim, unsigned char *old_msmt_flag,
+ unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
+ unsigned char *data_collect_flag);
short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
- unsigned char *ndim, unsigned char sv_prn[], float *pdop,
- float *hdop, float *vdop, float *tdop);
+ unsigned char *ndim, unsigned char sv_prn[], float *pdop,
+ float *hdop, float *vdop, float *tdop);
short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode);
short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias,
- float *time_of_fix);
+ float *time_of_fix);
short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
- double *clock_bias, float *time_of_fix);
+ double *clock_bias, float *time_of_fix);
short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB);
short rpt_0xBC (TSIPPKT *rpt, unsigned char *port_num,
- unsigned char *in_baud, unsigned char *out_baud,
- unsigned char *data_bits, unsigned char *parity,
- unsigned char *stop_bits, unsigned char *flow_control,
- unsigned char *protocols_in, unsigned char *protocols_out,
- unsigned char *reserved);
+ unsigned char *in_baud, unsigned char *out_baud,
+ unsigned char *data_bits, unsigned char *parity,
+ unsigned char *stop_bits, unsigned char *flow_control,
+ unsigned char *protocols_in, unsigned char *protocols_out,
+ unsigned char *reserved);
/* prototypes for superpacket parsers */
short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
- unsigned char *date, unsigned char *month, short *year,
- unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
- float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
- char sv_id[8]);
+ unsigned char *date, unsigned char *month, short *year,
+ unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
+ float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
+ char sv_id[8]);
short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat,
- double *lon, double *alt, double vel_enu[], double *time_of_fix,
- short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
- short sv_IODC[], short *datum_index);
+ double *lon, double *alt, double vel_enu[], double *time_of_fix,
+ short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
+ short sv_IODC[], short *datum_index);
short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
- unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
- unsigned char *bBuildYear, unsigned char *bBuildMonth,
- unsigned char *bBuildDay, unsigned char *bBuildHour,
- float *fOscOffset, unsigned short *iTestCodeId);
+ unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
+ unsigned char *bBuildYear, unsigned char *bBuildMonth,
+ unsigned char *bBuildDay, unsigned char *bBuildHour,
+ float *fOscOffset, unsigned short *iTestCodeId);
short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
- unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
- unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
- unsigned short *iPremiumOptions, unsigned short *iMachineID,
- unsigned short *iKey);
+ unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
+ unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
+ unsigned short *iPremiumOptions, unsigned short *iMachineID,
+ unsigned short *iKey);
short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
- unsigned char *pps_timebase, unsigned char *pos_polarity,
- double *pps_offset, float *bias_unc_threshold);
+ unsigned char *pps_timebase, unsigned char *pos_polarity,
+ double *pps_offset, float *bias_unc_threshold);
short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max);
short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask);
short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask);
short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec,
- unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
- unsigned char *Day, unsigned char *Month, unsigned short *Year,
- unsigned char *Status, unsigned char *Flags);
+ unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
+ unsigned char *Day, unsigned char *Month, unsigned short *Year,
+ unsigned char *Status, unsigned char *Flags);
/**/
/* prototypes for command-encode primitives with suffix convention: */
@@ -390,11 +390,11 @@ void cmd_0x1F (TSIPPKT *cmd);
void cmd_0x26 (TSIPPKT *cmd);
void cmd_0x2F (TSIPPKT *cmd);
void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
- unsigned char time_code, unsigned char opts_code);
+ unsigned char time_code, unsigned char opts_code);
void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn);
void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp,
- unsigned char char_code, unsigned char stopbitcode,
- unsigned char output_mode, unsigned char input_mode);
+ unsigned char char_code, unsigned char stopbitcode,
+ unsigned char output_mode, unsigned char input_mode);
void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ;
/* prototypes 8E commands */
@@ -403,7 +403,7 @@ void cmd_0x8E41q (TSIPPKT *cmd);
void cmd_0x8E42q (TSIPPKT *cmd);
void cmd_0x8E4Aq (TSIPPKT *cmd);
void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase,
- unsigned char Polarity, double PPSOffset, float Uncertainty);
+ unsigned char Polarity, double PPSOffset, float Uncertainty);
void cmd_0x8E4Bq (TSIPPKT *cmd);
void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask);
void cmd_0x8EADq (TSIPPKT *cmd);
@@ -411,33 +411,33 @@ void cmd_0x8EADq (TSIPPKT *cmd);
/* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Trimble parse functions */
-static int parse0x8FAD P((TSIPPKT *, struct peer *));
-static int parse0x8F0B P((TSIPPKT *, struct peer *));
+static int parse0x8FAD (TSIPPKT *, struct peer *);
+static int parse0x8F0B (TSIPPKT *, struct peer *);
#ifdef TRIMBLE_OUTPUT_FUNC
-static int parseany P((TSIPPKT *, struct peer *));
-static void TranslateTSIPReportToText P((TSIPPKT *, char *));
+static int parseany (TSIPPKT *, struct peer *);
+static void TranslateTSIPReportToText (TSIPPKT *, char *);
#endif /* TRIMBLE_OUTPUT_FUNC */
-static int parse0x5C P((TSIPPKT *, struct peer *));
-static int parse0x4F P((TSIPPKT *, struct peer *));
-static void tsip_input_proc P((TSIPPKT *, int));
+static int parse0x5C (TSIPPKT *, struct peer *);
+static int parse0x4F (TSIPPKT *, struct peer *);
+static void tsip_input_proc (TSIPPKT *, int);
/* Trimble helper functions */
-static void bPutFloat P((float *, unsigned char *));
-static void bPutDouble P((double *, unsigned char *));
-static void bPutULong P((unsigned long *, unsigned char *));
-static int print_msg_table_header P((int rptcode, char *HdrStr, int force));
-static char * show_time P((float time_of_week));
+static void bPutFloat (float *, unsigned char *);
+static void bPutDouble (double *, unsigned char *);
+static void bPutULong (unsigned long *, unsigned char *);
+static int print_msg_table_header (int rptcode, char *HdrStr, int force);
+static char * show_time (float time_of_week);
/* RIPE NCC functions */
-static void ripencc_control P((int, struct refclockstat *, struct
- refclockstat *, struct peer *));
-static int ripencc_ppsapi P((struct peer *, int, int));
-static int ripencc_get_pps_ts P((struct ripencc_unit *, l_fp *));
-static int ripencc_start P((int, struct peer *));
-static void ripencc_shutdown P((int, struct peer *));
-static void ripencc_poll P((int, struct peer *));
-static void ripencc_send P((struct peer *, TSIPPKT spt));
-static void ripencc_receive P((struct recvbuf *));
+static void ripencc_control (int, const struct refclockstat *,
+ struct refclockstat *, struct peer *);
+static int ripencc_ppsapi (struct peer *, int, int);
+static int ripencc_get_pps_ts (struct ripencc_unit *, l_fp *);
+static int ripencc_start (int, struct peer *);
+static void ripencc_shutdown (int, struct peer *);
+static void ripencc_poll (int, struct peer *);
+static void ripencc_send (struct peer *, TSIPPKT spt);
+static void ripencc_receive (struct recvbuf *);
/* fill in reflock structure for our clock */
struct refclock refclock_ripencc = {
@@ -471,12 +471,19 @@ ripencc_start(int unit, struct peer *peer)
struct termios tio;
TSIPPKT spt;
+ pp = peer->procptr;
+
/*
* Open serial port
*/
(void)snprintf(device, sizeof(device), DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_RAW)))
+ fd = refclock_open(device, SPEED232, LDISC_RAW);
+ if (fd <= 0) {
+ pp->io.fd = -1;
return (0);
+ }
+
+ pp->io.fd = fd;
/* from refclock_palisade.c */
if (tcgetattr(fd, &tio) < 0) {
@@ -497,23 +504,18 @@ ripencc_start(int unit, struct peer *peer)
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct ripencc_unit *)
- emalloc(sizeof(struct ripencc_unit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct ripencc_unit));
- pp = peer->procptr;
+ up = emalloc_zero(sizeof(*up));
+
pp->io.clock_recv = ripencc_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
- pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ pp->io.fd = -1;
+ close(fd);
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -548,47 +550,47 @@ ripencc_start(int unit, struct peer *peer)
/* i/o opts */ /* trimble manual page A30 */
cmd_0x35s(&spt,
- 0x1C, /* position */
- 0x00, /* velocity */
- 0x05, /* timing */
- 0x0a); /* auxilary */
+ 0x1C, /* position */
+ 0x00, /* velocity */
+ 0x05, /* timing */
+ 0x0a); /* auxilary */
ripencc_send(peer, spt);
/* turn off port A */
cmd_0x3Ds (&spt,
- 0x0B, /* baud_out */
- 0x0B, /* baud_inp */
- 0x07, /* char_code */
- 0x07, /* stopbitcode */
- 0x01, /* output_mode */
- 0x00); /* input_mode */
+ 0x0B, /* baud_out */
+ 0x0B, /* baud_inp */
+ 0x07, /* char_code */
+ 0x07, /* stopbitcode */
+ 0x01, /* output_mode */
+ 0x00); /* input_mode */
ripencc_send(peer, spt);
/* set i/o options */
cmd_0x8E4As (&spt,
- 0x01, /* PPS on */
- 0x01, /* Timebase UTC */
- 0x00, /* polarity positive */
- 0., /* 100 ft. cable XXX make flag */
- 1e-6 * GPS_C); /* turn of biasuncert. > (1us) */
+ 0x01, /* PPS on */
+ 0x01, /* Timebase UTC */
+ 0x00, /* polarity positive */
+ 0., /* 100 ft. cable XXX make flag */
+ 1e-6 * GPS_C); /* turn of biasuncert. > (1us) */
ripencc_send(peer,spt);
/* all outomatic packet output off */
cmd_0x8E4Ds(&spt,
- 0x00000000); /* AutoOutputMask */
+ 0x00000000); /* AutoOutputMask */
ripencc_send(peer, spt);
cmd_0xBBq (&spt,
- 0x00); /* query primary configuration */
+ 0x00); /* query primary configuration */
ripencc_send(peer,spt);
/* query PPS parameters */
- cmd_0x8E4Aq (&spt); /* query PPS params */
+ cmd_0x8E4Aq (&spt); /* query PPS params */
ripencc_send(peer,spt);
/* query survey limit */
- cmd_0x8E4Bq (&spt); /* query survey limit */
+ cmd_0x8E4Bq (&spt); /* query survey limit */
ripencc_send(peer,spt);
#ifdef DEBUG_NCC
@@ -615,7 +617,7 @@ ripencc_start(int unit, struct peer *peer)
static void
ripencc_control(
int unit, /* unit (not used) */
- struct refclockstat *in, /* input parameters (not used) */
+ const struct refclockstat *in, /* input parameters (not used) */
struct refclockstat *out, /* output parameters (not used) */
struct peer *peer /* peer structure pointer */
)
@@ -628,7 +630,7 @@ ripencc_control(
pp = peer->procptr;
ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
- pp->sloppyclockflag & CLK_FLAG3);
+ pp->sloppyclockflag & CLK_FLAG3);
}
@@ -647,10 +649,10 @@ ripencc_ppsapi(
int capability;
pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
+ up = pp->unitptr;
if (time_pps_getcap(up->handle, &capability) < 0) {
msyslog(LOG_ERR,
- "refclock_ripencc: time_pps_getcap failed: %m");
+ "refclock_ripencc: time_pps_getcap failed: %m");
return (0);
}
memset(&up->pps_params, 0, sizeof(pps_params_t));
@@ -660,14 +662,14 @@ ripencc_ppsapi(
up->pps_params.mode = capability & PPS_CAPTUREASSERT;
if (!up->pps_params.mode) {
msyslog(LOG_ERR,
- "refclock_ripencc: invalid capture edge %d",
- !enb_clear);
+ "refclock_ripencc: invalid capture edge %d",
+ !enb_clear);
return (0);
}
up->pps_params.mode |= PPS_TSFMT_TSPEC;
if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
msyslog(LOG_ERR,
- "refclock_ripencc: time_pps_setparams failed: %m");
+ "refclock_ripencc: time_pps_setparams failed: %m");
return (0);
}
if (enb_hardpps) {
@@ -675,10 +677,10 @@ ripencc_ppsapi(
up->pps_params.mode & ~PPS_TSFMT_TSPEC,
PPS_TSFMT_TSPEC) < 0) {
msyslog(LOG_ERR,
- "refclock_ripencc: time_pps_kcbind failed: %m");
+ "refclock_ripencc: time_pps_kcbind failed: %m");
return (0);
}
- pps_enable = 1;
+ hardpps_enable = 1;
}
peer->precision = PPS_PRECISION;
@@ -686,9 +688,9 @@ ripencc_ppsapi(
if (debug) {
time_pps_getparams(up->handle, &up->pps_params);
printf(
- "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
- capability, up->pps_params.api_version,
- up->pps_params.mode, enb_hardpps);
+ "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
+ capability, up->pps_params.api_version,
+ up->pps_params.mode, enb_hardpps);
}
#endif /* DEBUG_NCC */
@@ -713,7 +715,7 @@ ripencc_get_pps_ts(
l_fp tstmp;
#ifdef DEBUG_PPS
- msyslog(LOG_INFO,"ripencc_get_pps_ts\n");
+ msyslog(LOG_INFO,"ripencc_get_pps_ts");
#endif /* DEBUG_PPS */
@@ -726,7 +728,7 @@ ripencc_get_pps_ts(
timeout.tv_nsec = 0;
memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
- &timeout) < 0)
+ &timeout) < 0)
return (0);
if (up->pps_params.mode & PPS_CAPTUREASSERT) {
if (pps_info.assert_sequence ==
@@ -750,8 +752,8 @@ ripencc_get_pps_ts(
tstmp.l_uf = (u_int32)dtemp;
#ifdef DEBUG_PPS
- msyslog(LOG_INFO,"ts.tv_sec: %d\n",(int)ts.tv_sec);
- msyslog(LOG_INFO,"ts.tv_nsec: %ld\n",ts.tv_nsec);
+ msyslog(LOG_INFO,"ts.tv_sec: %d",(int)ts.tv_sec);
+ msyslog(LOG_INFO,"ts.tv_nsec: %ld",ts.tv_nsec);
#endif /* DEBUG_PPS */
*tsptr = tstmp;
@@ -768,14 +770,17 @@ ripencc_shutdown(int unit, struct peer *peer)
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
+ up = pp->unitptr;
- if (up->handle != 0)
- time_pps_destroy(up->handle);
-
- io_closeclock(&pp->io);
+ if (up != NULL) {
+ if (up->handle != 0)
+ time_pps_destroy(up->handle);
+ free(up);
+ }
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
- free(up);
+ return;
}
/*
@@ -793,7 +798,7 @@ ripencc_poll(int unit, struct peer *peer)
fprintf(stderr, "ripencc_poll(%d)\n", unit);
#endif /* DEBUG_NCC */
pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
+ up = pp->unitptr;
if (up->pollcnt == 0)
refclock_report(peer, CEVNT_TIMEOUT);
else
@@ -824,7 +829,7 @@ ripencc_send(struct peer *peer, TSIPPKT spt)
register struct refclockproc *pp;
pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
+ up = pp->unitptr;
if (debug)
printf("ripencc_send(%d, %02X)\n", up->unit, cmd);
}
@@ -843,7 +848,7 @@ ripencc_send(struct peer *peer, TSIPPKT spt)
return;
}
- if (*ip == 0x10) /* byte stuffing */
+ if (*ip == 0x10) /* byte stuffing */
*op++ = 0x10;
*op++ = *ip++;
}
@@ -867,7 +872,7 @@ ripencc_send(struct peer *peer, TSIPPKT spt)
#endif /* DEBUG_RAW */
if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) {
- refclock_report(peer, CEVNT_FAULT);
+ refclock_report(peer, CEVNT_FAULT);
}
}
@@ -884,12 +889,12 @@ ripencc_receive(struct recvbuf *rbufp)
register struct ripencc_unit *up;
register struct refclockproc *pp;
struct peer *peer;
- static TSIPPKT rpt; /* structure for current incoming TSIP report */
- TSIPPKT spt; /* send packet */
+ static TSIPPKT rpt; /* for current incoming TSIP report */
+ TSIPPKT spt; /* send packet */
int ns_since_pps;
int i;
char *cp;
- /* Use these variables to hold data until we decide its worth keeping */
+ /* these variables hold data until we decide it's worth keeping */
char rd_lastcode[BMAX];
l_fp rd_tmp;
u_short rd_lencode;
@@ -899,9 +904,9 @@ ripencc_receive(struct recvbuf *rbufp)
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
+ up = pp->unitptr;
rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
#ifdef DEBUG_RAW
@@ -910,12 +915,14 @@ ripencc_receive(struct recvbuf *rbufp)
#endif /* DEBUG_RAW */
#ifdef DEBUG_RAW
- if (debug) { /* print raw packet */
+ if (debug) { /* print raw packet */
int i;
unsigned char *cp;
printf("ripencc_receive: len %d\n", rbufp->recv_length);
- for (i=1, cp=(char*)&rbufp->recv_space; i <= rbufp->recv_length; i++, cp++) {
+ for (i=1, cp=(char*)&rbufp->recv_space;
+ i <= rbufp->recv_length;
+ i++, cp++) {
printf(" %02X", *cp);
if (i%10 == 0)
printf("\n");
@@ -927,7 +934,7 @@ ripencc_receive(struct recvbuf *rbufp)
cp = (char*) &rbufp->recv_space;
i=rbufp->recv_length;
- while (i--) { /* loop over received chars */
+ while (i--) { /* loop over received chars */
tsip_input_proc(&rpt, (unsigned char) *cp++);
@@ -936,30 +943,32 @@ ripencc_receive(struct recvbuf *rbufp)
switch (rpt.code) {
- case 0x8F: /* superpacket */
+ case 0x8F: /* superpacket */
switch (rpt.buf[0]) {
- case 0xAD: /* UTC Time */
+ case 0xAD: /* UTC Time */
/*
- * When polling on port B the timecode
- * is the time of the previous PPS.
- * If we completed receiving the packet
- * less than 150ms after the turn of the second,
- * it may have the code of the previous second.
- * We do not trust that and simply poll again
- * without even parsing it.
- *
- * More elegant would be to re-schedule the poll,
- * but I do not know (yet) how to do that cleanly.
- *
- */
+ ** When polling on port B the timecode is
+ ** the time of the previous PPS. If we
+ ** completed receiving the packet less than
+ ** 150ms after the turn of the second, it
+ ** may have the code of the previous second.
+ ** We do not trust that and simply poll
+ ** again without even parsing it.
+ **
+ ** More elegant would be to re-schedule the
+ ** poll, but I do not know (yet) how to do
+ ** that cleanly.
+ **
+ */
/* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
/* if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
- ns_since_pps=200;
+ ns_since_pps = 200;
if (up->polled && ns_since_pps < 150) {
- msyslog(LOG_INFO, "%s(): up->polled",__FUNCTION__);
+ msyslog(LOG_INFO, "%s(): up->polled",
+ __FUNCTION__);
ripencc_poll(up->unit, peer);
break;
}
@@ -970,9 +979,9 @@ ripencc_receive(struct recvbuf *rbufp)
* from results.
*/
if (parse0x8FAD(&rpt, peer) < 0) {
- msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
- refclock_report(peer, CEVNT_BADREPLY);
- break;
+ msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
+ refclock_report(peer, CEVNT_BADREPLY);
+ break;
}
/*
* If the PPSAPI is working, rather use its
@@ -985,11 +994,11 @@ ripencc_receive(struct recvbuf *rbufp)
pp->nsec = 0;
}
else
- msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__);
+ msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure",__FUNCTION__);
if (!up->polled) {
- msyslog(LOG_INFO, "%s(): unrequested packet\n",__FUNCTION__);
+ msyslog(LOG_INFO, "%s(): unrequested packet",__FUNCTION__);
/* unrequested packet */
break;
}
@@ -1009,9 +1018,10 @@ ripencc_receive(struct recvbuf *rbufp)
}
/*
- * Process the new sample in the median filter and determine the
- * reference clock offset and dispersion.
- */
+ ** Process the new sample in the median
+ ** filter and determine the reference clock
+ ** offset and dispersion.
+ */
if (!refclock_process(pp)) {
msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__);
refclock_report(peer, CEVNT_BADTIME);
@@ -1021,13 +1031,14 @@ ripencc_receive(struct recvbuf *rbufp)
refclock_receive(peer);
break;
- case 0x0B: /* comprehensive time packet */
+ case 0x0B: /* comprehensive time packet */
parse0x8F0B(&rpt, peer);
break;
- default: /* other superpackets */
+ default: /* other superpackets */
#ifdef DEBUG_NCC
- msyslog(LOG_INFO, "%s(): calling parseany",__FUNCTION__);
+ msyslog(LOG_INFO, "%s(): calling parseany",
+ __FUNCTION__);
#endif /* DEBUG_NCC */
#ifdef TRIMBLE_OUTPUT_FUNC
parseany(&rpt, peer);
@@ -1036,15 +1047,15 @@ ripencc_receive(struct recvbuf *rbufp)
}
break;
- case 0x4F: /* UTC parameters, for leap info */
+ case 0x4F: /* UTC parameters, for leap info */
parse0x4F(&rpt, peer);
break;
- case 0x5C: /* sat tracking data */
+ case 0x5C: /* sat tracking data */
parse0x5C(&rpt, peer);
break;
- default: /* other packets */
+ default: /* other packets */
#ifdef TRIMBLE_OUTPUT_FUNC
parseany(&rpt, peer);
#endif /* TRIMBLE_OUTPUT_FUNC */
@@ -1059,33 +1070,45 @@ ripencc_receive(struct recvbuf *rbufp)
* (so not from parseany)
*/
-void cmd_0x1F (TSIPPKT *cmd)
/* request software versions */
+void
+cmd_0x1F(
+ TSIPPKT *cmd
+ )
{
cmd->len = 0;
cmd->code = 0x1F;
}
-void cmd_0x26 (TSIPPKT *cmd)
/* request receiver health */
+void
+cmd_0x26(
+ TSIPPKT *cmd
+ )
{
cmd->len = 0;
cmd->code = 0x26;
}
-
-
-
-void cmd_0x2F (TSIPPKT *cmd)
/* request UTC params */
+void
+cmd_0x2F(
+ TSIPPKT *cmd
+ )
{
cmd->len = 0;
cmd->code = 0x2F;
}
-void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
- unsigned char time_code, unsigned char opts_code)
/* set serial I/O options */
+void
+cmd_0x35s(
+ TSIPPKT *cmd,
+ unsigned char pos_code,
+ unsigned char vel_code,
+ unsigned char time_code,
+ unsigned char opts_code
+ )
{
cmd->buf[0] = pos_code;
cmd->buf[1] = vel_code;
@@ -1094,24 +1117,34 @@ void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
cmd->len = 4;
cmd->code = 0x35;
}
-void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn)
+
/* request tracking status */
+void
+cmd_0x3C(
+ TSIPPKT *cmd,
+ unsigned char sv_prn
+ )
{
cmd->buf[0] = sv_prn;
cmd->len = 1;
cmd->code = 0x3C;
}
-
-void cmd_0x3Ds (TSIPPKT *cmd,
- unsigned char baud_out, unsigned char baud_inp,
- unsigned char char_code, unsigned char stopbitcode,
- unsigned char output_mode, unsigned char input_mode)
/* set Channel A configuration for dual-port operation */
+void
+cmd_0x3Ds(
+ TSIPPKT *cmd,
+ unsigned char baud_out,
+ unsigned char baud_inp,
+ unsigned char char_code,
+ unsigned char stopbitcode,
+ unsigned char output_mode,
+ unsigned char input_mode
+ )
{
cmd->buf[0] = baud_out; /* XMT baud rate */
cmd->buf[1] = baud_inp; /* RCV baud rate */
- cmd->buf[2] = char_code; /* parity and #bits per byte */
+ cmd->buf[2] = char_code; /* parity and #bits per byte */
cmd->buf[3] = stopbitcode; /* number of stop bits code */
cmd->buf[4] = output_mode; /* Ch. A transmission mode */
cmd->buf[5] = input_mode; /* Ch. A reception mode */
@@ -1121,10 +1154,12 @@ void cmd_0x3Ds (TSIPPKT *cmd,
/* query primary configuration */
-void cmd_0xBBq (TSIPPKT *cmd,
- unsigned char subcode)
+void
+cmd_0xBBq(
+ TSIPPKT *cmd,
+ unsigned char subcode
+ )
{
-
cmd->len = 1;
cmd->code = 0xBB;
cmd->buf[0] = subcode;
@@ -1132,36 +1167,47 @@ void cmd_0xBBq (TSIPPKT *cmd,
/**** Superpackets ****/
-void cmd_0x8E0Bq (TSIPPKT *cmd)
/* 8E-0B to query 8F-0B controls */
+void
+cmd_0x8E0Bq(
+ TSIPPKT *cmd
+ )
{
-
cmd->len = 1;
cmd->code = 0x8E;
cmd->buf[0] = 0x0B;
}
-void cmd_0x8E41q (TSIPPKT *cmd)
/* 8F-41 to query board serial number */
+void
+cmd_0x8E41q(
+ TSIPPKT *cmd
+ )
{
-
cmd->len = 1;
cmd->code = 0x8E;
cmd->buf[0] = 0x41;
}
-void cmd_0x8E42q (TSIPPKT *cmd)
/* 8F-42 to query product serial number */
+void
+cmd_0x8E42q(
+ TSIPPKT *cmd
+ )
{
-
cmd->len = 1;
cmd->code = 0x8E;
cmd->buf[0] = 0x42;
}
-void cmd_0x8E4Aq (TSIPPKT *cmd)
+
+
/* 8F-4A to query PPS parameters */
+void
+cmd_0x8E4Aq(
+ TSIPPKT *cmd
+ )
{
cmd->len = 1;
cmd->code = 0x8E;
@@ -1170,12 +1216,15 @@ void cmd_0x8E4Aq (TSIPPKT *cmd)
/* set i/o options */
-void cmd_0x8E4As (TSIPPKT *cmd,
- unsigned char PPSOnOff,
- unsigned char TimeBase,
- unsigned char Polarity,
- double PPSOffset,
- float Uncertainty)
+void
+cmd_0x8E4As(
+ TSIPPKT *cmd,
+ unsigned char PPSOnOff,
+ unsigned char TimeBase,
+ unsigned char Polarity,
+ double PPSOffset,
+ float Uncertainty
+ )
{
cmd->len = 16;
cmd->code = 0x8E;
@@ -1186,18 +1235,24 @@ void cmd_0x8E4As (TSIPPKT *cmd,
bPutDouble (&PPSOffset, &cmd->buf[4]);
bPutFloat (&Uncertainty, &cmd->buf[12]);
}
-void cmd_0x8E4Bq (TSIPPKT *cmd)
+
/* 8F-4B query survey limit */
+void
+cmd_0x8E4Bq(
+ TSIPPKT *cmd
+ )
{
cmd->len = 1;
cmd->code = 0x8E;
cmd->buf[0] = 0x4B;
}
-
/* poll for UTC superpacket */
-void cmd_0x8EADq (TSIPPKT *cmd)
/* 8E-AD to query 8F-AD controls */
+void
+cmd_0x8EADq(
+ TSIPPKT *cmd
+ )
{
cmd->len = 1;
cmd->code = 0x8E;
@@ -1205,8 +1260,11 @@ void cmd_0x8EADq (TSIPPKT *cmd)
}
/* all outomatic packet output off */
-void cmd_0x8E4Ds (TSIPPKT *cmd,
- unsigned long AutoOutputMask)
+void
+cmd_0x8E4Ds(
+ TSIPPKT *cmd,
+ unsigned long AutoOutputMask
+ )
{
cmd->len = 5;
cmd->code = 0x8E;
@@ -1215,88 +1273,106 @@ void cmd_0x8E4Ds (TSIPPKT *cmd,
}
-
-
-/* for DOS machines, reverse order of bytes as they come through the
- * serial port. */
+/*
+ * for DOS machines, reverse order of bytes as they come through the
+ * serial port.
+ */
#ifdef BYTESWAP
-static short bGetShort (unsigned char *bp)
+static short
+bGetShort(
+ unsigned char *bp
+ )
{
short outval;
- unsigned char *optr;
+ unsigned char *optr;
- optr = (unsigned char*)&outval + 1;
- *optr-- = *bp++;
- *optr = *bp;
+ optr = (unsigned char*)&outval + 1;
+ *optr-- = *bp++;
+ *optr = *bp;
return outval;
}
#ifdef TRIMBLE_OUTPUT_FUNC
-static unsigned short bGetUShort (unsigned char *bp)
+static unsigned short
+bGetUShort(
+ unsigned char *bp
+ )
{
unsigned short outval;
- unsigned char *optr;
+ unsigned char *optr;
- optr = (unsigned char*)&outval + 1;
- *optr-- = *bp++;
- *optr = *bp;
+ optr = (unsigned char*)&outval + 1;
+ *optr-- = *bp++;
+ *optr = *bp;
return outval;
}
-static long bGetLong (unsigned char *bp)
+static long
+bGetLong(
+ unsigned char *bp
+ )
{
long outval;
- unsigned char *optr;
+ unsigned char *optr;
- optr = (unsigned char*)&outval + 3;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
+ optr = (unsigned char*)&outval + 3;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
return outval;
}
-static unsigned long bGetULong (unsigned char *bp)
+static unsigned long
+bGetULong(
+ unsigned char *bp
+ )
{
unsigned long outval;
- unsigned char *optr;
+ unsigned char *optr;
- optr = (unsigned char*)&outval + 3;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
+ optr = (unsigned char*)&outval + 3;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
return outval;
}
#endif /* TRIMBLE_OUTPUT_FUNC */
-static float bGetSingle (unsigned char *bp)
+static float
+bGetSingle(
+ unsigned char *bp
+ )
{
float outval;
- unsigned char *optr;
+ unsigned char *optr;
- optr = (unsigned char*)&outval + 3;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
+ optr = (unsigned char*)&outval + 3;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
return outval;
}
-static double bGetDouble (unsigned char *bp)
+static double
+bGetDouble(
+ unsigned char *bp
+ )
{
double outval;
- unsigned char *optr;
-
- optr = (unsigned char*)&outval + 7;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 7;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
return outval;
}
@@ -1316,43 +1392,52 @@ static double bGetDouble (unsigned char *bp)
#ifdef BYTESWAP
void
-bPutFloat (float *in, unsigned char *out)
+bPutFloat(
+ float *in,
+ unsigned char *out
+ )
{
unsigned char *inptr;
- inptr = (unsigned char*)in + 3;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out = *inptr;
+ inptr = (unsigned char*)in + 3;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out = *inptr;
}
static void
-bPutULong (unsigned long *in, unsigned char *out)
+bPutULong(
+ unsigned long *in,
+ unsigned char *out
+ )
{
unsigned char *inptr;
- inptr = (unsigned char*)in + 3;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out = *inptr;
+ inptr = (unsigned char*)in + 3;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out = *inptr;
}
static void
-bPutDouble (double *in, unsigned char *out)
+bPutDouble(
+ double *in,
+ unsigned char *out
+ )
{
unsigned char *inptr;
- inptr = (unsigned char*)in + 7;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out = *inptr;
+ inptr = (unsigned char*)in + 7;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out = *inptr;
}
#else /* not BYTESWAP */
@@ -1374,9 +1459,10 @@ void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;}
*/
static int
-parse0x8FAD(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
+parse0x8FAD(
+ TSIPPKT *rpt,
+ struct peer *peer
+ )
{
register struct refclockproc *pp;
register struct ripencc_unit *up;
@@ -1403,7 +1489,6 @@ parse0x8FAD(rpt, peer)
return(-1);
}
-
if (bGetDouble(&buf[3]) != 0.0) {
#ifdef DEBUG_NCC
if (debug)
@@ -1412,14 +1497,14 @@ parse0x8FAD(rpt, peer)
return(-1);
}
- hour = (unsigned int) buf[11];
- minute = (unsigned int) buf[12];
- second = (unsigned int) buf[13];
+ hour = (unsigned int) buf[11];
+ minute = (unsigned int) buf[12];
+ second = (unsigned int) buf[13];
day = (unsigned int) buf[14];
month = (unsigned int) buf[15];
year = bGetShort(&buf[16]);
- trackstat = buf[18];
- utcflags = buf[19];
+ trackstat = buf[18];
+ utcflags = buf[19];
sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
@@ -1438,7 +1523,7 @@ parse0x8FAD(rpt, peer)
/* poll for UTC parameters once and then if UTC flag changed */
up = (struct ripencc_unit *) pp->unitptr;
if (utcflags != up->utcflags) {
- TSIPPKT spt; /* local structure for send packet */
+ TSIPPKT spt; /* local structure for send packet */
cmd_0x2F (&spt); /* request UTC params */
ripencc_send(peer,spt);
up->utcflags = utcflags;
@@ -1458,7 +1543,7 @@ parse0x8FAD(rpt, peer)
if (month < 1 || month > 12 || day < 1 || day > 31)
return(-1);
- if (pp->year % 4) {
+ if (pp->year % 4) { /* XXX: use is_leapyear() ? */
if (day > day1tab[month - 1])
return(-1);
for (i = 0; i < month - 1; i++)
@@ -1476,7 +1561,9 @@ parse0x8FAD(rpt, peer)
pp->nsec = 0;
if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0)
- pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND);
+ pp-> leap = (up->leapdelta > 0)
+ ? LEAP_ADDSECOND
+ : LEAP_DELSECOND;
else
pp-> leap = LEAP_NOWARNING;
@@ -1486,13 +1573,15 @@ parse0x8FAD(rpt, peer)
/*
* Parse comprehensive time packet
*
- * 0 = success
+ * 0 = success
* -1 = errors
*/
-int parse0x8F0B(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
+int
+parse0x8F0B(
+ TSIPPKT *rpt,
+ struct peer *peer
+ )
{
register struct refclockproc *pp;
@@ -1539,7 +1628,6 @@ int parse0x8F0B(rpt, peer)
hour = (unsigned int )fmod(tow / 3600., 24.);
}
-
day = (unsigned int) buf[11];
month = (unsigned int) buf[12];
year = bGetShort(&buf[13]);
@@ -1587,9 +1675,10 @@ int parse0x8F0B(rpt, peer)
sprintf(logbuf, "C1 %02d%02d%04d %02d%02d%02d %d %7.0f %.1f %.0f %.1f %d %02d%09.6f %c %02d%09.6f %c %.0f %d %d %d %d %d %d %d %d",
- day, month, year, hour, minute, second, mode, bias, biasunc, rate, rateunc, utcoff,
- lat_deg, lat_min, north_south, lon_deg, lon_min, east_west, alt,
- sv[0], sv[1], sv[2], sv[3], sv[4], sv[5], sv[6], sv[7]);
+ day, month, year, hour, minute, second, mode, bias, biasunc,
+ rate, rateunc, utcoff, lat_deg, lat_min, north_south, lon_deg,
+ lon_min, east_west, alt, sv[0], sv[1], sv[2], sv[3], sv[4],
+ sv[5], sv[6], sv[7]);
#ifdef DEBUG_NCC
if (debug)
@@ -1605,9 +1694,11 @@ int parse0x8F0B(rpt, peer)
/*
* Parse any packet using Trimble machinery
*/
-int parseany(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
+int
+parseany(
+ TSIPPKT *rpt,
+ struct peer *peer
+ )
{
static char logbuf[1024]; /* logging string buffer */
@@ -1631,9 +1722,11 @@ int parseany(rpt, peer)
* -1 = errors
*/
-int parse0x4F(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
+int
+parse0x4F(
+ TSIPPKT *rpt,
+ struct peer *peer
+ )
{
register struct ripencc_unit *up;
@@ -1680,9 +1773,11 @@ int parse0x4F(rpt, peer)
* -1 = errors
*/
-int parse0x5C(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
+int
+parse0x5C(
+ TSIPPKT *rpt,
+ struct peer *peer
+ )
{
unsigned char prn, channel, aqflag, ephstat;
float snr, azinuth, elevation;
@@ -1784,13 +1879,15 @@ int parse0x5C(rpt, peer)
*/
-/**/
-static void tsip_input_proc (
- TSIPPKT *rpt,
- int inbyte)
-/* reads bytes until serial buffer is empty or a complete report
+/*
+ * reads bytes until serial buffer is empty or a complete report
* has been received; end of report is signified by DLE ETX.
*/
+static void
+tsip_input_proc(
+ TSIPPKT *rpt,
+ int inbyte
+ )
{
unsigned char newbyte;
@@ -1799,71 +1896,71 @@ static void tsip_input_proc (
newbyte = (unsigned char)(inbyte);
switch (rpt->status)
{
- case TSIP_PARSED_DLE_1:
+ case TSIP_PARSED_DLE_1:
switch (newbyte)
{
- case 0:
- case ETX:
- /* illegal TSIP IDs */
- rpt->len = 0;
+ case 0:
+ case ETX:
+ /* illegal TSIP IDs */
+ rpt->len = 0;
rpt->status = TSIP_PARSED_EMPTY;
break;
- case DLE:
- /* try normal message start again */
+ case DLE:
+ /* try normal message start again */
rpt->len = 0;
rpt->status = TSIP_PARSED_DLE_1;
break;
- default:
- /* legal TSIP ID; start message */
+ default:
+ /* legal TSIP ID; start message */
rpt->code = newbyte;
- rpt->len = 0;
+ rpt->len = 0;
rpt->status = TSIP_PARSED_DATA;
break;
}
break;
- case TSIP_PARSED_DATA:
+ case TSIP_PARSED_DATA:
switch (newbyte) {
- case DLE:
- /* expect DLE or ETX next */
+ case DLE:
+ /* expect DLE or ETX next */
rpt->status = TSIP_PARSED_DLE_2;
break;
- default:
- /* normal data byte */
+ default:
+ /* normal data byte */
rpt->buf[rpt->len] = newbyte;
rpt->len++;
- /* no change in rpt->status */
+ /* no change in rpt->status */
break;
}
break;
- case TSIP_PARSED_DLE_2:
+ case TSIP_PARSED_DLE_2:
switch (newbyte) {
- case DLE:
- /* normal data byte */
+ case DLE:
+ /* normal data byte */
rpt->buf[rpt->len] = newbyte;
rpt->len++;
rpt->status = TSIP_PARSED_DATA;
break;
- case ETX:
+ case ETX:
/* end of message; return TRUE here. */
rpt->status = TSIP_PARSED_FULL;
break;
- default:
+ default:
/* error: treat as TSIP_PARSED_DLE_1; start new report packet */
rpt->code = newbyte;
- rpt->len = 0;
+ rpt->len = 0;
rpt->status = TSIP_PARSED_DATA;
}
break;
- case TSIP_PARSED_FULL:
- case TSIP_PARSED_EMPTY:
- default:
+ case TSIP_PARSED_FULL:
+ case TSIP_PARSED_EMPTY:
+ default:
switch (newbyte) {
- case DLE:
- /* normal message start */
+ case DLE:
+ /* normal message start */
rpt->len = 0;
rpt->status = TSIP_PARSED_DLE_1;
break;
- default:
+ default:
/* error: ignore newbyte */
rpt->len = 0;
rpt->status = TSIP_PARSED_EMPTY;
@@ -1880,14 +1977,17 @@ static void tsip_input_proc (
#ifdef TRIMBLE_OUTPUT_FUNC
/**/
-short rpt_0x3D (TSIPPKT *rpt,
- unsigned char *tx_baud_index,
- unsigned char *rx_baud_index,
- unsigned char *char_format_index,
- unsigned char *stop_bits,
- unsigned char *tx_mode_index,
- unsigned char *rx_mode_index)
/* Channel A configuration for dual port operation */
+short
+rpt_0x3D(
+ TSIPPKT *rpt,
+ unsigned char *tx_baud_index,
+ unsigned char *rx_baud_index,
+ unsigned char *char_format_index,
+ unsigned char *stop_bits,
+ unsigned char *tx_mode_index,
+ unsigned char *rx_mode_index
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -1903,19 +2003,22 @@ short rpt_0x3D (TSIPPKT *rpt,
}
/**/
-short rpt_0x40 (TSIPPKT *rpt,
- unsigned char *sv_prn,
- short *week_num,
- float *t_zc,
- float *eccentricity,
- float *t_oa,
- float *i_0,
- float *OMEGA_dot,
- float *sqrt_A,
- float *OMEGA_0,
- float *omega,
- float *M_0)
/* almanac data for specified satellite */
+short
+rpt_0x40(
+ TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ short *week_num,
+ float *t_zc,
+ float *eccentricity,
+ float *t_oa,
+ float *i_0,
+ float *OMEGA_dot,
+ float *sqrt_A,
+ float *OMEGA_0,
+ float *omega,
+ float *M_0
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -1935,11 +2038,14 @@ short rpt_0x40 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x41 (TSIPPKT *rpt,
- float *time_of_week,
- float *UTC_offset,
- short *week_num)
/* GPS time */
+short
+rpt_0x41(
+ TSIPPKT *rpt,
+ float *time_of_week,
+ float *UTC_offset,
+ short *week_num
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -1951,10 +2057,13 @@ short rpt_0x41 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x42 (TSIPPKT *rpt,
- float pos_ECEF[3],
- float *time_of_fix)
/* position in ECEF, single precision */
+short
+rpt_0x42(
+ TSIPPKT *rpt,
+ float pos_ECEF[3],
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -1967,11 +2076,14 @@ short rpt_0x42 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x43 (TSIPPKT *rpt,
- float ECEF_vel[3],
- float *freq_offset,
- float *time_of_fix)
/* velocity in ECEF, single precision */
+short
+rpt_0x43(
+ TSIPPKT *rpt,
+ float ECEF_vel[3],
+ float *freq_offset,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -1985,18 +2097,21 @@ short rpt_0x43 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x45 (TSIPPKT *rpt,
- unsigned char *major_nav_version,
- unsigned char *minor_nav_version,
- unsigned char *nav_day,
- unsigned char *nav_month,
- unsigned char *nav_year,
- unsigned char *major_dsp_version,
- unsigned char *minor_dsp_version,
- unsigned char *dsp_day,
- unsigned char *dsp_month,
- unsigned char *dsp_year)
/* software versions */
+short
+rpt_0x45(
+ TSIPPKT *rpt,
+ unsigned char *major_nav_version,
+ unsigned char *minor_nav_version,
+ unsigned char *nav_day,
+ unsigned char *nav_month,
+ unsigned char *nav_year,
+ unsigned char *major_dsp_version,
+ unsigned char *minor_dsp_version,
+ unsigned char *dsp_day,
+ unsigned char *dsp_month,
+ unsigned char *dsp_year
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2015,10 +2130,13 @@ short rpt_0x45 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x46 (TSIPPKT *rpt,
- unsigned char *status1,
- unsigned char *status2)
/* receiver health and status */
+short
+rpt_0x46(
+ TSIPPKT *rpt,
+ unsigned char *status1,
+ unsigned char *status2
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2029,10 +2147,14 @@ short rpt_0x46 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x47 (TSIPPKT *rpt,
- unsigned char *nsvs, unsigned char *sv_prn,
- float *snr)
/* signal levels for all satellites tracked */
+short
+rpt_0x47(
+ TSIPPKT *rpt,
+ unsigned char *nsvs,
+ unsigned char *sv_prn,
+ float *snr
+ )
{
short isv;
unsigned char *buf;
@@ -2047,9 +2169,12 @@ short rpt_0x47 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x48 (TSIPPKT *rpt,
- unsigned char *message)
/* GPS system message */
+short
+rpt_0x48(
+ TSIPPKT *rpt,
+ unsigned char *message
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2060,9 +2185,12 @@ short rpt_0x48 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x49 (TSIPPKT *rpt,
- unsigned char *sv_health)
/* health for all satellites from almanac health page */
+short
+rpt_0x49(
+ TSIPPKT *rpt,
+ unsigned char *sv_health
+ )
{
short i;
unsigned char *buf;
@@ -2073,13 +2201,16 @@ short rpt_0x49 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4A (TSIPPKT *rpt,
- float *lat,
- float *lon,
- float *alt,
- float *clock_bias,
- float *time_of_fix)
/* position in lat-lon-alt, single precision */
+short
+rpt_0x4A(
+ TSIPPKT *rpt,
+ float *lat,
+ float *lon,
+ float *alt,
+ float *clock_bias,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2093,9 +2224,14 @@ short rpt_0x4A (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4A_2 (TSIPPKT *rpt,
- float *alt, float *dummy , unsigned char *alt_flag)
/* reference altitude parameters */
+short
+rpt_0x4A_2(
+ TSIPPKT *rpt,
+ float *alt,
+ float *dummy,
+ unsigned char *alt_flag
+ )
{
unsigned char *buf;
@@ -2108,11 +2244,14 @@ short rpt_0x4A_2 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4B (TSIPPKT *rpt,
- unsigned char *machine_id,
- unsigned char *status3,
- unsigned char *status4)
/* machine ID code, status */
+short
+rpt_0x4B(
+ TSIPPKT *rpt,
+ unsigned char *machine_id,
+ unsigned char *status3,
+ unsigned char *status4
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2124,13 +2263,16 @@ short rpt_0x4B (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4C (TSIPPKT *rpt,
- unsigned char *dyn_code,
- float *el_mask,
- float *snr_mask,
- float *dop_mask,
- float *dop_switch)
/* operating parameters and masks */
+short
+rpt_0x4C(
+ TSIPPKT *rpt,
+ unsigned char *dyn_code,
+ float *el_mask,
+ float *snr_mask,
+ float *dop_mask,
+ float *dop_switch
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2144,9 +2286,12 @@ short rpt_0x4C (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4D (TSIPPKT *rpt,
- float *osc_offset)
/* oscillator offset */
+short
+rpt_0x4D(
+ TSIPPKT *rpt,
+ float *osc_offset
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2156,9 +2301,12 @@ short rpt_0x4D (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4E (TSIPPKT *rpt,
- unsigned char *response)
/* yes/no response to command to set GPS time */
+short
+rpt_0x4E(
+ TSIPPKT *rpt,
+ unsigned char *response
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2168,16 +2316,19 @@ short rpt_0x4E (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x4F (TSIPPKT *rpt,
- double *a0,
- float *a1,
- float *time_of_data,
- short *dt_ls,
- short *wn_t,
- short *wn_lsf,
- short *dn,
- short *dt_lsf)
/* UTC data */
+short
+rpt_0x4F(
+ TSIPPKT *rpt,
+ double *a0,
+ float *a1,
+ float *time_of_data,
+ short *dt_ls,
+ short *wn_t,
+ short *wn_lsf,
+ short *dn,
+ short *dt_lsf
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2195,11 +2346,14 @@ short rpt_0x4F (TSIPPKT *rpt,
}
/**/
-short rpt_0x54 (TSIPPKT *rpt,
- float *clock_bias,
- float *freq_offset,
- float *time_of_fix)
/* clock offset and frequency offset in 1-SV (0-D) mode */
+short
+rpt_0x54(
+ TSIPPKT *rpt,
+ float *clock_bias,
+ float *freq_offset,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2211,12 +2365,15 @@ short rpt_0x54 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x55 (TSIPPKT *rpt,
- unsigned char *pos_code,
- unsigned char *vel_code,
- unsigned char *time_code,
- unsigned char *aux_code)
/* I/O serial options */
+short
+rpt_0x55(
+ TSIPPKT *rpt,
+ unsigned char *pos_code,
+ unsigned char *vel_code,
+ unsigned char *time_code,
+ unsigned char *aux_code
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2229,9 +2386,14 @@ short rpt_0x55 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x56 (TSIPPKT *rpt,
- float vel_ENU[3], float *freq_offset, float *time_of_fix)
/* velocity in east-north-up coordinates */
+short
+rpt_0x56(
+ TSIPPKT *rpt,
+ float vel_ENU[3],
+ float *freq_offset,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2248,11 +2410,15 @@ short rpt_0x56 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x57 (TSIPPKT *rpt,
- unsigned char *source_code, unsigned char *diag_code,
- short *week_num,
- float *time_of_fix)
/* info about last computed fix */
+short
+rpt_0x57(
+ TSIPPKT *rpt,
+ unsigned char *source_code,
+ unsigned char *diag_code,
+ short *week_num,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2265,10 +2431,16 @@ short rpt_0x57 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x58 (TSIPPKT *rpt,
- unsigned char *op_code, unsigned char *data_type, unsigned char *sv_prn,
- unsigned char *data_length, unsigned char *data_packet)
/* GPS system data or acknowledgment of GPS system data load */
+short
+rpt_0x58(
+ TSIPPKT *rpt,
+ unsigned char *op_code,
+ unsigned char *data_type,
+ unsigned char *sv_prn,
+ unsigned char *data_length,
+ unsigned char *data_packet
+ )
{
unsigned char *buf, *buf4;
short dl;
@@ -2294,7 +2466,7 @@ short rpt_0x58 (TSIPPKT *rpt,
*data_length = (unsigned char)dl;
buf4 = &buf[4];
switch (*data_type) {
- case 2:
+ case 2:
/* Almanac */
if (*data_length != sizeof (ALM_INFO)) return TRUE;
alminfo = (ALM_INFO*)data_packet;
@@ -2319,7 +2491,7 @@ short rpt_0x58 (TSIPPKT *rpt,
alminfo->wn_oa = bGetShort(&buf4[64]);
break;
- case 3:
+ case 3:
/* Almanac health page */
if (*data_length != sizeof (ALH_PARMS) + 3) return TRUE;
@@ -2327,7 +2499,7 @@ short rpt_0x58 (TSIPPKT *rpt,
memcpy (data_packet, buf4, dl);
break;
- case 4:
+ case 4:
/* Ionosphere */
if (*data_length != sizeof (ION_INFO) + 8) return TRUE;
ioninfo = (ION_INFO*)data_packet;
@@ -2341,7 +2513,7 @@ short rpt_0x58 (TSIPPKT *rpt,
ioninfo->beta_3 = bGetSingle (&buf4[36]);
break;
- case 5:
+ case 5:
/* UTC */
if (*data_length != sizeof (UTC_INFO) + 13) return TRUE;
utcinfo = (UTC_INFO*)data_packet;
@@ -2355,7 +2527,7 @@ short rpt_0x58 (TSIPPKT *rpt,
utcinfo->delta_t_LSF = bGetShort (&buf4[37]);
break;
- case 6:
+ case 6:
/* Ephemeris */
if (*data_length != sizeof (NAV_INFO) - 1) return TRUE;
@@ -2406,10 +2578,13 @@ short rpt_0x58 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x59 (TSIPPKT *rpt,
- unsigned char *code_type,
- unsigned char status_code[32])
/* satellite enable/disable or health heed/ignore list */
+short
+rpt_0x59(
+ TSIPPKT *rpt,
+ unsigned char *code_type,
+ unsigned char status_code[32]
+ )
{
short iprn;
unsigned char *buf;
@@ -2422,14 +2597,17 @@ short rpt_0x59 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x5A (TSIPPKT *rpt,
- unsigned char *sv_prn,
- float *sample_length,
- float *signal_level,
- float *code_phase,
- float *Doppler,
- double *time_of_fix)
/* raw measurement data - code phase/Doppler */
+short
+rpt_0x5A(
+ TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ float *sample_length,
+ float *signal_level,
+ float *code_phase,
+ float *Doppler,
+ double *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2444,15 +2622,18 @@ short rpt_0x5A (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x5B (TSIPPKT *rpt,
- unsigned char *sv_prn,
- unsigned char *sv_health,
- unsigned char *sv_iode,
- unsigned char *fit_interval_flag,
- float *time_of_collection,
- float *time_of_eph,
- float *sv_accy)
/* satellite ephorb status */
+short
+rpt_0x5B(
+ TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ unsigned char *sv_health,
+ unsigned char *sv_iode,
+ unsigned char *fit_interval_flag,
+ float *time_of_collection,
+ float *time_of_eph,
+ float *sv_accy
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2468,21 +2649,24 @@ short rpt_0x5B (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x5C (TSIPPKT *rpt,
- unsigned char *sv_prn,
- unsigned char *slot,
- unsigned char *chan,
- unsigned char *acq_flag,
- unsigned char *eph_flag,
- float *signal_level,
- float *time_of_last_msmt,
- float *elev,
- float *azim,
- unsigned char *old_msmt_flag,
- unsigned char *integer_msec_flag,
- unsigned char *bad_data_flag,
- unsigned char *data_collect_flag)
/* satellite tracking status */
+short
+rpt_0x5C(
+ TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ unsigned char *slot,
+ unsigned char *chan,
+ unsigned char *acq_flag,
+ unsigned char *eph_flag,
+ float *signal_level,
+ float *time_of_last_msmt,
+ float *elev,
+ float *azim,
+ unsigned char *old_msmt_flag,
+ unsigned char *integer_msec_flag,
+ unsigned char *bad_data_flag,
+ unsigned char *data_collect_flag
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2507,16 +2691,19 @@ short rpt_0x5C (TSIPPKT *rpt,
}
/**/
-short rpt_0x6D (TSIPPKT *rpt,
- unsigned char *manual_mode,
- unsigned char *nsvs,
- unsigned char *ndim,
- unsigned char sv_prn[],
- float *pdop,
- float *hdop,
- float *vdop,
- float *tdop)
/* over-determined satellite selection for position fixes, PDOP, fix mode */
+short
+rpt_0x6D(
+ TSIPPKT *rpt,
+ unsigned char *manual_mode,
+ unsigned char *nsvs,
+ unsigned char *ndim,
+ unsigned char sv_prn[],
+ float *pdop,
+ float *hdop,
+ float *vdop,
+ float *tdop
+ )
{
short islot;
unsigned char *buf;
@@ -2538,9 +2725,12 @@ short rpt_0x6D (TSIPPKT *rpt,
}
/**/
-short rpt_0x82 (TSIPPKT *rpt,
- unsigned char *diff_mode)
/* differential fix mode */
+short
+rpt_0x82(
+ TSIPPKT *rpt,
+ unsigned char *diff_mode
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2550,11 +2740,14 @@ short rpt_0x82 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x83 (TSIPPKT *rpt,
- double ECEF_pos[3],
- double *clock_bias,
- float *time_of_fix)
/* position, ECEF double precision */
+short
+rpt_0x83(
+ TSIPPKT *rpt,
+ double ECEF_pos[3],
+ double *clock_bias,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2568,13 +2761,16 @@ short rpt_0x83 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_0x84 (TSIPPKT *rpt,
- double *lat,
- double *lon,
- double *alt,
- double *clock_bias,
- float *time_of_fix)
/* position, lat-lon-alt double precision */
+short
+rpt_0x84(
+ TSIPPKT *rpt,
+ double *lat,
+ double *lon,
+ double *alt,
+ double *clock_bias,
+ float *time_of_fix
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2588,39 +2784,44 @@ short rpt_0x84 (TSIPPKT *rpt,
return FALSE;
}
-short rpt_Paly0xBB(TSIPPKT *rpt,
- TSIP_RCVR_CFG *TsipxBB)
+short
+rpt_Paly0xBB(
+ TSIPPKT *rpt,
+ TSIP_RCVR_CFG *TsipxBB
+ )
{
-
unsigned char *buf;
buf = rpt->buf;
- /* Palisade is inconsistent with other TSIP, which has a kength of 40 */
+ /* Palisade is inconsistent with other TSIP, which has a length of 40 */
/* if (rpt->len != 40) return TRUE; */
if (rpt->len != 43) return TRUE;
- TsipxBB->bSubcode = buf[0];
- TsipxBB->operating_mode = buf[1] ;
- TsipxBB->dyn_code = buf[3] ;
- TsipxBB->elev_mask = bGetSingle (&buf[5]);
- TsipxBB->cno_mask = bGetSingle (&buf[9]);
- TsipxBB->dop_mask = bGetSingle (&buf[13]);
+ TsipxBB->bSubcode = buf[0];
+ TsipxBB->operating_mode = buf[1];
+ TsipxBB->dyn_code = buf[3];
+ TsipxBB->elev_mask = bGetSingle (&buf[5]);
+ TsipxBB->cno_mask = bGetSingle (&buf[9]);
+ TsipxBB->dop_mask = bGetSingle (&buf[13]);
TsipxBB->dop_switch = bGetSingle (&buf[17]);
return FALSE;
}
-short rpt_0xBC (TSIPPKT *rpt,
- unsigned char *port_num,
- unsigned char *in_baud,
- unsigned char *out_baud,
- unsigned char *data_bits,
- unsigned char *parity,
- unsigned char *stop_bits,
- unsigned char *flow_control,
- unsigned char *protocols_in,
- unsigned char *protocols_out,
- unsigned char *reserved)
/* Receiver serial port configuration */
+short
+rpt_0xBC(
+ TSIPPKT *rpt,
+ unsigned char *port_num,
+ unsigned char *in_baud,
+ unsigned char *out_baud,
+ unsigned char *data_bits,
+ unsigned char *parity,
+ unsigned char *stop_bits,
+ unsigned char *flow_control,
+ unsigned char *protocols_in,
+ unsigned char *protocols_out,
+ unsigned char *reserved
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2642,51 +2843,57 @@ short rpt_0xBC (TSIPPKT *rpt,
/**** Superpackets ****/
-short rpt_0x8F0B(TSIPPKT *rpt,
- unsigned short *event,
- double *tow,
- unsigned char *date,
- unsigned char *month,
- short *year,
- unsigned char *dim_mode,
- short *utc_offset,
- double *bias,
- double *drift,
- float *bias_unc,
- float *dr_unc,
- double *lat,
- double *lon,
- double *alt,
- char sv_id[8])
-{
- short local_index;
- unsigned char *buf;
+short
+rpt_0x8F0B(
+ TSIPPKT *rpt,
+ unsigned short *event,
+ double *tow,
+ unsigned char *date,
+ unsigned char *month,
+ short *year,
+ unsigned char *dim_mode,
+ short *utc_offset,
+ double *bias,
+ double *drift,
+ float *bias_unc,
+ float *dr_unc,
+ double *lat,
+ double *lon,
+ double *alt,
+ char sv_id[8]
+ )
+{
+ short local_index;
+ unsigned char *buf;
buf = rpt->buf;
- if (rpt->len != 74) return TRUE;
- *event = bGetShort(&buf[1]);
- *tow = bGetDouble(&buf[3]);
- *date = buf[11];
- *month = buf[12];
- *year = bGetShort(&buf[13]);
- *dim_mode = buf[15];
- *utc_offset = bGetShort(&buf[16]);
- *bias = bGetDouble(&buf[18]);
- *drift = bGetDouble(&buf[26]);
- *bias_unc = bGetSingle(&buf[34]);
- *dr_unc = bGetSingle(&buf[38]);
- *lat = bGetDouble(&buf[42]);
- *lon = bGetDouble(&buf[50]);
- *alt = bGetDouble(&buf[58]);
-
- for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
- return FALSE;
-}
-
-short rpt_0x8F14 (TSIPPKT *rpt,
- short *datum_idx,
- double datum_coeffs[5])
-/* datum index and coefficients */
+ if (rpt->len != 74) return TRUE;
+ *event = bGetShort(&buf[1]);
+ *tow = bGetDouble(&buf[3]);
+ *date = buf[11];
+ *month = buf[12];
+ *year = bGetShort(&buf[13]);
+ *dim_mode = buf[15];
+ *utc_offset = bGetShort(&buf[16]);
+ *bias = bGetDouble(&buf[18]);
+ *drift = bGetDouble(&buf[26]);
+ *bias_unc = bGetSingle(&buf[34]);
+ *dr_unc = bGetSingle(&buf[38]);
+ *lat = bGetDouble(&buf[42]);
+ *lon = bGetDouble(&buf[50]);
+ *alt = bGetDouble(&buf[58]);
+
+ for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
+ return FALSE;
+}
+
+/* datum index and coefficients */
+short
+rpt_0x8F14(
+ TSIPPKT *rpt,
+ short *datum_idx,
+ double datum_coeffs[5]
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2702,10 +2909,13 @@ short rpt_0x8F14 (TSIPPKT *rpt,
}
-short rpt_0x8F15 (TSIPPKT *rpt,
- short *datum_idx,
- double datum_coeffs[5])
-/* datum index and coefficients */
+/* datum index and coefficients */
+short
+rpt_0x8F15(
+ TSIPPKT *rpt,
+ short *datum_idx,
+ double datum_coeffs[5]
+ )
{
unsigned char *buf;
buf = rpt->buf;
@@ -2723,29 +2933,32 @@ short rpt_0x8F15 (TSIPPKT *rpt,
#define MAX_LONG (2147483648.) /* 2**31 */
-short rpt_0x8F20 (TSIPPKT *rpt,
- unsigned char *info,
- double *lat,
- double *lon,
- double *alt,
- double vel_enu[],
- double *time_of_fix,
- short *week_num,
- unsigned char *nsvs,
- unsigned char sv_prn[],
- short sv_IODC[],
- short *datum_index)
+short
+rpt_0x8F20(
+ TSIPPKT *rpt,
+ unsigned char *info,
+ double *lat,
+ double *lon,
+ double *alt,
+ double vel_enu[],
+ double *time_of_fix,
+ short *week_num,
+ unsigned char *nsvs,
+ unsigned char sv_prn[],
+ short sv_IODC[],
+ short *datum_index
+ )
{
short
- isv;
+ isv;
unsigned char
- *buf, prnx, iode;
+ *buf, prnx, iode;
unsigned long
- ulongtemp;
+ ulongtemp;
long
- longtemp;
+ longtemp;
double
- vel_scale;
+ vel_scale;
buf = rpt->buf;
@@ -2774,24 +2987,27 @@ short rpt_0x8F20 (TSIPPKT *rpt,
for (isv = 0; isv < 8; isv++) {
prnx = buf[32+2*isv];
sv_prn[isv] = (unsigned char)(prnx&0x3F);
- iode = buf[33+2*isv];
+ iode = buf[33+2*isv];
sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8));
}
return FALSE;
}
-short rpt_0x8F41 (TSIPPKT *rpt,
- unsigned char *bSearchRange,
- unsigned char *bBoardOptions,
- unsigned long *iiSerialNumber,
- unsigned char *bBuildYear,
- unsigned char *bBuildMonth,
- unsigned char *bBuildDay,
- unsigned char *bBuildHour,
- float *fOscOffset,
- unsigned short *iTestCodeId)
+short
+rpt_0x8F41(
+ TSIPPKT *rpt,
+ unsigned char *bSearchRange,
+ unsigned char *bBoardOptions,
+ unsigned long *iiSerialNumber,
+ unsigned char *bBuildYear,
+ unsigned char *bBuildMonth,
+ unsigned char *bBuildDay,
+ unsigned char *bBuildHour,
+ float *fOscOffset,
+ unsigned short *iTestCodeId
+ )
{
- if(rpt->len != 17) return FALSE;
+ if (rpt->len != 17) return FALSE;
*bSearchRange = rpt->buf[1];
*bBoardOptions = rpt->buf[2];
*iiSerialNumber = bGetLong(&rpt->buf[3]);
@@ -2805,17 +3021,20 @@ short rpt_0x8F41 (TSIPPKT *rpt,
return TRUE;
}
-short rpt_0x8F42 (TSIPPKT *rpt,
- unsigned char *bProdOptionsPre,
- unsigned char *bProdNumberExt,
- unsigned short *iCaseSerialNumberPre,
- unsigned long *iiCaseSerialNumber,
- unsigned long *iiProdNumber,
- unsigned short *iPremiumOptions,
- unsigned short *iMachineID,
- unsigned short *iKey)
+short
+rpt_0x8F42(
+ TSIPPKT *rpt,
+ unsigned char *bProdOptionsPre,
+ unsigned char *bProdNumberExt,
+ unsigned short *iCaseSerialNumberPre,
+ unsigned long *iiCaseSerialNumber,
+ unsigned long *iiProdNumber,
+ unsigned short *iPremiumOptions,
+ unsigned short *iMachineID,
+ unsigned short *iKey
+ )
{
- if(rpt->len != 19) return FALSE;
+ if (rpt->len != 19) return FALSE;
*bProdOptionsPre = rpt->buf[1];
*bProdNumberExt = rpt->buf[2];
*iCaseSerialNumberPre = bGetShort(&rpt->buf[3]);
@@ -2827,100 +3046,117 @@ short rpt_0x8F42 (TSIPPKT *rpt,
return TRUE;
}
-short rpt_0x8F45(TSIPPKT *rpt,
- unsigned char *bSegMask)
+short
+rpt_0x8F45(
+ TSIPPKT *rpt,
+ unsigned char *bSegMask
+ )
{
- if(rpt->len != 2) return FALSE;
+ if (rpt->len != 2) return FALSE;
*bSegMask = rpt->buf[1];
return TRUE;
}
-short rpt_0x8F4A_16(TSIPPKT *rpt,
- unsigned char *pps_enabled,
- unsigned char *pps_timebase,
- unsigned char *pos_polarity,
- double *pps_offset,
- float *bias_unc_threshold)
/* Stinger PPS definition */
+short
+rpt_0x8F4A_16(
+ TSIPPKT *rpt,
+ unsigned char *pps_enabled,
+ unsigned char *pps_timebase,
+ unsigned char *pos_polarity,
+ double *pps_offset,
+ float *bias_unc_threshold
+ )
{
unsigned char
- *buf;
-
- buf = rpt->buf;
- if (rpt->len != 16) return TRUE;
- *pps_enabled = buf[1];
- *pps_timebase = buf[2];
- *pos_polarity = buf[3];
- *pps_offset = bGetDouble(&buf[4]);
- *bias_unc_threshold = bGetSingle(&buf[12]);
+ *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 16) return TRUE;
+ *pps_enabled = buf[1];
+ *pps_timebase = buf[2];
+ *pos_polarity = buf[3];
+ *pps_offset = bGetDouble(&buf[4]);
+ *bias_unc_threshold = bGetSingle(&buf[12]);
return FALSE;
}
-short rpt_0x8F4B(TSIPPKT *rpt,
- unsigned long *decorr_max)
+short
+rpt_0x8F4B(
+ TSIPPKT *rpt,
+ unsigned long *decorr_max
+ )
{
unsigned char
- *buf;
+ *buf;
- buf = rpt->buf;
- if (rpt->len != 5) return TRUE;
- *decorr_max = bGetLong(&buf[1]);
- return FALSE;
+ buf = rpt->buf;
+ if (rpt->len != 5) return TRUE;
+ *decorr_max = bGetLong(&buf[1]);
+ return FALSE;
}
-short rpt_0x8F4D(TSIPPKT *rpt,
- unsigned long *event_mask)
+short
+rpt_0x8F4D(
+ TSIPPKT *rpt,
+ unsigned long *event_mask
+ )
{
unsigned char
- *buf;
+ *buf;
- buf = rpt->buf;
- if (rpt->len != 5) return TRUE;
- *event_mask = bGetULong (&buf[1]);
- return FALSE;
+ buf = rpt->buf;
+ if (rpt->len != 5) return TRUE;
+ *event_mask = bGetULong (&buf[1]);
+ return FALSE;
}
-short rpt_0x8FA5(TSIPPKT *rpt,
- unsigned char *spktmask)
+short
+rpt_0x8FA5(
+ TSIPPKT *rpt,
+ unsigned char *spktmask
+ )
{
unsigned char
- *buf;
-
- buf = rpt->buf;
- if (rpt->len != 5) return TRUE;
- spktmask[0] = buf[1];
- spktmask[1] = buf[2];
- spktmask[2] = buf[3];
- spktmask[3] = buf[4];
- return FALSE;
-}
-
-short rpt_0x8FAD (TSIPPKT *rpt,
- unsigned short *COUNT,
- double *FracSec,
- unsigned char *Hour,
- unsigned char *Minute,
- unsigned char *Second,
- unsigned char *Day,
- unsigned char *Month,
- unsigned short *Year,
- unsigned char *Status,
- unsigned char *Flags)
-{
+ *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 5) return TRUE;
+ spktmask[0] = buf[1];
+ spktmask[1] = buf[2];
+ spktmask[2] = buf[3];
+ spktmask[3] = buf[4];
+ return FALSE;
+}
+short
+rpt_0x8FAD(
+ TSIPPKT *rpt,
+ unsigned short *COUNT,
+ double *FracSec,
+ unsigned char *Hour,
+ unsigned char *Minute,
+ unsigned char *Second,
+ unsigned char *Day,
+ unsigned char *Month,
+ unsigned short *Year,
+ unsigned char *Status,
+ unsigned char *Flags
+ )
+{
if (rpt->len != 22) return TRUE;
- *COUNT = bGetUShort(&rpt->buf[1]);
- *FracSec = bGetDouble(&rpt->buf[3]);
- *Hour = rpt->buf[11];
- *Minute = rpt->buf[12];
- *Second = rpt->buf[13];
- *Day = rpt->buf[14];
- *Month = rpt->buf[15];
- *Year = bGetUShort(&rpt->buf[16]);
- *Status = rpt->buf[18];
- *Flags = rpt->buf[19];
- return FALSE;
+ *COUNT = bGetUShort(&rpt->buf[1]);
+ *FracSec = bGetDouble(&rpt->buf[3]);
+ *Hour = rpt->buf[11];
+ *Minute = rpt->buf[12];
+ *Second = rpt->buf[13];
+ *Day = rpt->buf[14];
+ *Month = rpt->buf[15];
+ *Year = bGetUShort(&rpt->buf[16]);
+ *Status = rpt->buf[18];
+ *Flags = rpt->buf[19];
+ return FALSE;
}
@@ -2976,31 +3212,34 @@ short rpt_0x8FAD (TSIPPKT *rpt,
/* pbuf is the pointer to the current location of the text output */
static char
- *pbuf;
+*pbuf;
/* keep track of whether the message has been successfully parsed */
static short
- parsed;
+parsed;
/* convert time of week into day-hour-minute-second and print */
-char* show_time (float time_of_week)
+char *
+show_time(
+ float time_of_week
+ )
{
short days, hours, minutes;
float seconds;
double tow = 0;
- static char timestring [80];
+ static char timestring [80];
if (time_of_week == -1.0)
- {
+ {
sprintf(timestring, " <No time yet> ");
}
else if ((time_of_week >= 604800.0) || (time_of_week < 0.0))
- {
+ {
sprintf(timestring, " <Bad time> ");
}
- else
- {
+ else
+ {
if (time_of_week < 604799.9)
tow = time_of_week + .00000001;
seconds = (float)fmod(tow, 60.);
@@ -3008,42 +3247,45 @@ char* show_time (float time_of_week)
hours = (short)fmod(tow / 3600., 24.);
days = (short)(tow / 86400.0);
sprintf(timestring, " %s %02d:%02d:%05.2f ",
- dayname[days], hours, minutes, seconds);
- }
- return timestring;
+ dayname[days], hours, minutes, seconds);
+ }
+ return timestring;
}
/**/
/* 0x3D */
-static void rpt_chan_A_config (TSIPPKT *rpt)
+static void
+rpt_chan_A_config(
+ TSIPPKT *rpt
+ )
{
unsigned char
- tx_baud_index, rx_baud_index,
- char_format_index, stop_bits,
- tx_mode_index, rx_mode_index,
- databits, parity;
+ tx_baud_index, rx_baud_index,
+ char_format_index, stop_bits,
+ tx_mode_index, rx_mode_index,
+ databits, parity;
int
- i, nbaud;
+ i, nbaud;
/* unload rptbuf */
if (rpt_0x3D (rpt,
- &tx_baud_index, &rx_baud_index, &char_format_index,
- &stop_bits, &tx_mode_index, &rx_mode_index)) {
+ &tx_baud_index, &rx_baud_index, &char_format_index,
+ &stop_bits, &tx_mode_index, &rx_mode_index)) {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nChannel A Configuration");
- nbaud = sizeof(old_baudnum);
+ nbaud = sizeof(old_baudnum);
for (i = 0; i < nbaud; ++i) if (tx_baud_index == old_baudnum[i]) break;
pbuf += sprintf(pbuf, "\n Transmit speed: %s at %s",
- old_output_ch[tx_mode_index], st_baud_text_app[i]);
+ old_output_ch[tx_mode_index], st_baud_text_app[i]);
for (i = 0; i < nbaud; ++i) if (rx_baud_index == old_baudnum[i]) break;
pbuf += sprintf(pbuf, "\n Receive speed: %s at %s",
- old_input_ch[rx_mode_index], st_baud_text_app[i]);
+ old_input_ch[rx_mode_index], st_baud_text_app[i]);
databits = (unsigned char)((char_format_index & 0x03) + 5);
@@ -3051,43 +3293,46 @@ static void rpt_chan_A_config (TSIPPKT *rpt)
if (parity > 4) parity = 2;
pbuf += sprintf(pbuf, "\n Character format (bits/char, parity, stop bits): %d-%s-%d",
- databits, old_parity_text[parity], stop_bits);
+ databits, old_parity_text[parity], stop_bits);
}
/**/
/* 0x40 */
-static void rpt_almanac_data_page (TSIPPKT *rpt)
+static void
+rpt_almanac_data_page(
+ TSIPPKT *rpt
+ )
{
unsigned char
- sv_prn;
+ sv_prn;
short
- week_num;
+ week_num;
float
- t_zc,
- eccentricity,
- t_oa,
- i_0,
- OMEGA_dot,
- sqrt_A,
- OMEGA_0,
- omega,
- M_0;
+ t_zc,
+ eccentricity,
+ t_oa,
+ i_0,
+ OMEGA_dot,
+ sqrt_A,
+ OMEGA_0,
+ omega,
+ M_0;
/* unload rptbuf */
if (rpt_0x40 (rpt,
- &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
- &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) {
+ &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
+ &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nAlmanac for SV %02d", sv_prn);
pbuf += sprintf(pbuf, "\n Captured:%15.0f %s",
- t_zc, show_time (t_zc));
+ t_zc, show_time (t_zc));
pbuf += sprintf(pbuf, "\n week:%15d", week_num);
pbuf += sprintf(pbuf, "\n Eccentricity:%15g", eccentricity);
pbuf += sprintf(pbuf, "\n T_oa:%15.0f %s",
- t_oa, show_time (t_oa));
+ t_oa, show_time (t_oa));
pbuf += sprintf(pbuf, "\n i 0:%15g", i_0);
pbuf += sprintf(pbuf, "\n OMEGA dot:%15g", OMEGA_dot);
pbuf += sprintf(pbuf, "\n sqrt A:%15g", sqrt_A);
@@ -3097,12 +3342,15 @@ static void rpt_almanac_data_page (TSIPPKT *rpt)
}
/* 0x41 */
-static void rpt_GPS_time (TSIPPKT *rpt)
+static void
+rpt_GPS_time(
+ TSIPPKT *rpt
+ )
{
float
- time_of_week, UTC_offset;
+ time_of_week, UTC_offset;
short
- week_num;
+ week_num;
/* unload rptbuf */
if (rpt_0x41 (rpt, &time_of_week, &UTC_offset, &week_num)) {
@@ -3111,15 +3359,18 @@ static void rpt_GPS_time (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\nGPS time:%s GPS week: %d UTC offset %.1f",
- show_time(time_of_week), week_num, UTC_offset);
+ show_time(time_of_week), week_num, UTC_offset);
}
/* 0x42 */
-static void rpt_single_ECEF_position (TSIPPKT *rpt)
+static void
+rpt_single_ECEF_position(
+ TSIPPKT *rpt
+ )
{
float
- ECEF_pos[3], time_of_fix;
+ ECEF_pos[3], time_of_fix;
/* unload rptbuf */
if (rpt_0x42 (rpt, ECEF_pos, &time_of_fix)) {
@@ -3128,16 +3379,19 @@ static void rpt_single_ECEF_position (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\nSXYZ: %15.0f %15.0f %15.0f %s",
- ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
- show_time(time_of_fix));
+ ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
+ show_time(time_of_fix));
}
/* 0x43 */
-static void rpt_single_ECEF_velocity (TSIPPKT *rpt)
+static void
+rpt_single_ECEF_velocity(
+ TSIPPKT *rpt
+ )
{
float
- ECEF_vel[3], freq_offset, time_of_fix;
+ ECEF_vel[3], freq_offset, time_of_fix;
/* unload rptbuf */
if (rpt_0x43 (rpt, ECEF_vel, &freq_offset, &time_of_fix)) {
@@ -3146,54 +3400,63 @@ static void rpt_single_ECEF_velocity (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\nVelECEF: %11.3f %11.3f %11.3f %12.3f%s",
- ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
- show_time(time_of_fix));
+ ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
+ show_time(time_of_fix));
}
/* 0x45 */
-static void rpt_SW_version (TSIPPKT *rpt) {
+static void
+rpt_SW_version(
+ TSIPPKT *rpt
+ )
+{
unsigned char
- major_nav_version, minor_nav_version,
- nav_day, nav_month, nav_year,
- major_dsp_version, minor_dsp_version,
- dsp_day, dsp_month, dsp_year;
+ major_nav_version, minor_nav_version,
+ nav_day, nav_month, nav_year,
+ major_dsp_version, minor_dsp_version,
+ dsp_day, dsp_month, dsp_year;
/* unload rptbuf */
if (rpt_0x45 (rpt,
- &major_nav_version, &minor_nav_version,
- &nav_day, &nav_month, &nav_year,
- &major_dsp_version, &minor_dsp_version,
- &dsp_day, &dsp_month, &dsp_year)) {
+ &major_nav_version, &minor_nav_version,
+ &nav_day, &nav_month, &nav_year,
+ &major_dsp_version, &minor_dsp_version,
+ &dsp_day, &dsp_month, &dsp_year)) {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf,
-"\nFW Versions: Nav Proc %2d.%02d %2d/%2d/%2d Sig Proc %2d.%02d %2d/%2d/%2d",
- major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
- major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
+ "\nFW Versions: Nav Proc %2d.%02d %2d/%2d/%2d Sig Proc %2d.%02d %2d/%2d/%2d",
+ major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
+ major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
}
/* 0x46 */
-static void rpt_rcvr_health (TSIPPKT *rpt)
+static void
+rpt_rcvr_health(
+ TSIPPKT *rpt
+ )
{
unsigned char
- status1, status2;
- static char
- *sc_text[] = {
- "Doing position fixes",
- "Don't have GPS time yet",
- "Waiting for almanac collection",
- "DOP too high ",
- "No satellites available",
- "Only 1 satellite available",
- "Only 2 satellites available",
- "Only 3 satellites available",
- "No satellites usable ",
- "Only 1 satellite usable",
- "Only 2 satellites usable",
- "Only 3 satellites usable",
- "Chosen satellite unusable"};
+ status1, status2;
+ const char
+ *text;
+ static const char const
+ *sc_text[] = {
+ "Doing position fixes",
+ "Don't have GPS time yet",
+ "Waiting for almanac collection",
+ "DOP too high ",
+ "No satellites available",
+ "Only 1 satellite available",
+ "Only 2 satellites available",
+ "Only 3 satellites available",
+ "No satellites usable ",
+ "Only 1 satellite usable",
+ "Only 2 satellites usable",
+ "Only 3 satellites usable",
+ "Chosen satellite unusable"};
/* unload rptbuf */
@@ -3203,49 +3466,58 @@ static void rpt_rcvr_health (TSIPPKT *rpt)
return;
}
+ text = (status1 < COUNTOF(sc_text))
+ ? sc_text[status1]
+ : "(out of range)";
pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ",
- sc_text[rpt->buf[0]], status1);
+ text, status1);
pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)",
- (status2 & 0x01)?"No BBRAM":"BBRAM OK",
- (status2 & 0x10)?"No Ant":"Ant OK",
- status2);
+ (status2 & 0x01)?"No BBRAM":"BBRAM OK",
+ (status2 & 0x10)?"No Ant":"Ant OK",
+ status2);
}
/* 0x47 */
-static void rpt_SNR_all_SVs (TSIPPKT *rpt)
+static void
+rpt_SNR_all_SVs(
+ TSIPPKT *rpt
+ )
{
unsigned char
- nsvs, sv_prn[12];
+ nsvs, sv_prn[12];
short
- isv;
+ isv;
float
- snr[12];
+ snr[12];
/* unload rptbuf */
if (rpt_0x47 (rpt, &nsvs, sv_prn, snr))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs);
for (isv = 0; isv < nsvs; isv++)
- {
+ {
pbuf += sprintf(pbuf, "\n SV %02d %6.2f",
- sv_prn[isv], snr[isv]);
+ sv_prn[isv], snr[isv]);
}
}
/* 0x48 */
-static void rpt_GPS_system_message (TSIPPKT *rpt)
+static void
+rpt_GPS_system_message(
+ TSIPPKT *rpt
+ )
{
unsigned char
- message[23];
+ message[23];
/* unload rptbuf */
if (rpt_0x48 (rpt, message))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
@@ -3254,43 +3526,50 @@ static void rpt_GPS_system_message (TSIPPKT *rpt)
}
/* 0x49 */
-static void rpt_almanac_health_page (TSIPPKT *rpt)
+static void
+rpt_almanac_health_page(
+ TSIPPKT *rpt
+ )
{
short
- iprn;
+ iprn;
unsigned char
- sv_health [32];
+ sv_health [32];
/* unload rptbuf */
if (rpt_0x49 (rpt, sv_health))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nAlmanac health page:");
for (iprn = 0; iprn < 32; iprn++)
- {
+ {
if (!(iprn%5)) *pbuf++ = '\n';
pbuf += sprintf(pbuf, " SV%02d %2X",
- (iprn+1) , sv_health[iprn]);
+ (iprn+1) , sv_health[iprn]);
}
}
/* 0x4A */
-static void rpt_single_lla_position (TSIPPKT *rpt) {
+static void
+rpt_single_lla_position(
+ TSIPPKT *rpt
+ )
+{
short
- lat_deg, lon_deg;
+ lat_deg, lon_deg;
float
- lat, lon,
- alt, clock_bias, time_of_fix;
+ lat, lon,
+ alt, clock_bias, time_of_fix;
double lat_min, lon_min;
unsigned char
- north_south, east_west;
+ north_south, east_west;
if (rpt_0x4A (rpt,
- &lat, &lon, &alt, &clock_bias, &time_of_fix))
- {
+ &lat, &lon, &alt, &clock_bias, &time_of_fix))
+ {
parsed = BADLEN_PARSE;
return;
}
@@ -3299,7 +3578,7 @@ static void rpt_single_lla_position (TSIPPKT *rpt) {
lat *= (float)R2D;
north_south = 'N';
if (lat < 0.0)
- {
+ {
north_south = 'S';
lat = -lat;
}
@@ -3309,7 +3588,7 @@ static void rpt_single_lla_position (TSIPPKT *rpt) {
lon *= (float)R2D;
east_west = 'E';
if (lon < 0.0)
- {
+ {
east_west = 'W';
lon = -lon;
}
@@ -3317,136 +3596,152 @@ static void rpt_single_lla_position (TSIPPKT *rpt) {
lon_min = (lon - lon_deg) * 60.0;
pbuf += sprintf(pbuf, "\nSLLA: %4d: %06.3f %c%5d:%06.3f %c%10.2f %12.2f%s",
- lat_deg, lat_min, north_south,
- lon_deg, lon_min, east_west,
- alt, clock_bias,
- show_time(time_of_fix));
+ lat_deg, lat_min, north_south,
+ lon_deg, lon_min, east_west,
+ alt, clock_bias,
+ show_time(time_of_fix));
}
/* 0x4A */
-static void rpt_ref_alt (TSIPPKT *rpt) {
-
+static void
+rpt_ref_alt(
+ TSIPPKT *rpt
+ )
+{
float
- alt, dummy;
+ alt, dummy;
unsigned char
- alt_flag;
+ alt_flag;
- if (rpt_0x4A_2 (rpt,
- &alt, &dummy, &alt_flag))
- {
+ if (rpt_0x4A_2 (rpt, &alt, &dummy, &alt_flag))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nReference Alt: %.1f m; %s",
- alt, alt_flag?"ON":"OFF");
+ alt, alt_flag?"ON":"OFF");
}
/* 0x4B */
-static void rpt_rcvr_id_and_status (TSIPPKT *rpt)
+static void
+rpt_rcvr_id_and_status(
+ TSIPPKT *rpt
+ )
{
unsigned char
- machine_id, status3, status4;
+ machine_id, status3, status4;
/* unload rptbuf */
if (rpt_0x4B (rpt, &machine_id, &status3, &status4))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
- machine_id,
- (status3 & 0x02)?"No RTC":"RTC OK",
- (status3 & 0x08)?"No Alm":"Alm OK",
- status3);
+ machine_id,
+ (status3 & 0x02)?"No RTC":"RTC OK",
+ (status3 & 0x08)?"No Alm":"Alm OK",
+ status3);
}
/* 0x4C */
-static void rpt_operating_parameters (TSIPPKT *rpt)
+static void
+rpt_operating_parameters(
+ TSIPPKT *rpt
+ )
{
unsigned char
- dyn_code;
+ dyn_code;
float
- el_mask, snr_mask, dop_mask, dop_switch;
+ el_mask, snr_mask, dop_mask, dop_switch;
/* unload rptbuf */
if (rpt_0x4C (rpt, &dyn_code, &el_mask,
- &snr_mask, &dop_mask, &dop_switch))
- {
+ &snr_mask, &dop_mask, &dop_switch))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nOperating Parameters:");
pbuf += sprintf(pbuf, "\n Dynamics code = %d %s",
- dyn_code, dyn_text[dyn_code]);
- pbuf += sprintf(pbuf, "\n Elevation mask = %.2fø", el_mask * R2D);
+ dyn_code, dyn_text[dyn_code]);
+ pbuf += sprintf(pbuf, "\n Elevation mask = %.2f", el_mask * R2D);
pbuf += sprintf(pbuf, "\n SNR mask = %.2f", snr_mask);
pbuf += sprintf(pbuf, "\n DOP mask = %.2f", dop_mask);
pbuf += sprintf(pbuf, "\n DOP switch = %.2f", dop_switch);
}
/* 0x4D */
-static void rpt_oscillator_offset (TSIPPKT *rpt)
+static void
+rpt_oscillator_offset(
+ TSIPPKT *rpt
+ )
{
float
- osc_offset;
+ osc_offset;
/* unload rptbuf */
if (rpt_0x4D (rpt, &osc_offset))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM",
- osc_offset, osc_offset/1575.42);
+ osc_offset, osc_offset/1575.42);
}
/* 0x4E */
-static void rpt_GPS_time_set_response (TSIPPKT *rpt)
+static void
+rpt_GPS_time_set_response(
+ TSIPPKT *rpt
+ )
{
-
unsigned char
- response;
+ response;
/* unload rptbuf */
if (rpt_0x4E (rpt, &response))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
switch (response)
- {
- case 'Y':
+ {
+ case 'Y':
pbuf += sprintf(pbuf, "\nTime set accepted");
break;
- case 'N':
+ case 'N':
pbuf += sprintf(pbuf, "\nTime set rejected or not required");
break;
- default:
+ default:
parsed = BADDATA_PARSE;
}
}
/* 0x4F */
-static void rpt_UTC_offset (TSIPPKT *rpt)
+static void
+rpt_UTC_offset(
+ TSIPPKT *rpt
+ )
{
double
- a0;
+ a0;
float
- a1, time_of_data;
+ a1, time_of_data;
short
- dt_ls, wn_t, wn_lsf, dn, dt_lsf;
+ dt_ls, wn_t, wn_lsf, dn, dt_lsf;
/* unload rptbuf */
if (rpt_0x4F (rpt, &a0, &a1, &time_of_data,
- &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) {
+ &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) {
parsed = BADLEN_PARSE;
return;
}
@@ -3464,10 +3759,13 @@ static void rpt_UTC_offset (TSIPPKT *rpt)
/**/
/* 0x54 */
-static void rpt_1SV_bias (TSIPPKT *rpt)
+static void
+rpt_1SV_bias(
+ TSIPPKT *rpt
+ )
{
float
- clock_bias, freq_offset, time_of_fix;
+ clock_bias, freq_offset, time_of_fix;
/* unload rptbuf */
if (rpt_0x54 (rpt, &clock_bias, &freq_offset, &time_of_fix)) {
@@ -3476,25 +3774,28 @@ static void rpt_1SV_bias (TSIPPKT *rpt)
}
pbuf += sprintf (pbuf, "\nTime Fix Clock Bias: %6.2f m Freq Bias: %6.2f m/s%s",
- clock_bias, freq_offset, show_time (time_of_fix));
+ clock_bias, freq_offset, show_time (time_of_fix));
}
/* 0x55 */
-static void rpt_io_opt (TSIPPKT *rpt)
+static void
+rpt_io_opt(
+ TSIPPKT *rpt
+ )
{
unsigned char
- pos_code, vel_code, time_code, aux_code;
+ pos_code, vel_code, time_code, aux_code;
/* unload rptbuf */
if (rpt_0x55 (rpt,
- &pos_code, &vel_code, &time_code, &aux_code)) {
+ &pos_code, &vel_code, &time_code, &aux_code)) {
parsed = BADLEN_PARSE;
return;
}
/* rptbuf unloaded */
pbuf += sprintf(pbuf, "\nI/O Options: %2X %2X %2X %2X",
- pos_code, vel_code, time_code, aux_code);
+ pos_code, vel_code, time_code, aux_code);
if (pos_code & 0x01) {
pbuf += sprintf(pbuf, "\n ECEF XYZ position output");
@@ -3505,16 +3806,16 @@ static void rpt_io_opt (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, (pos_code & 0x04)?
- "\n MSL altitude output (Geoid height) ":
- "\n WGS-84 altitude output");
+ "\n MSL altitude output (Geoid height) ":
+ "\n WGS-84 altitude output");
pbuf += sprintf(pbuf, (pos_code & 0x08)?
- "\n MSL altitude input":
- "\n WGS-84 altitude input");
+ "\n MSL altitude input":
+ "\n WGS-84 altitude input");
pbuf += sprintf(pbuf, (pos_code & 0x10)?
- "\n Double precision":
- "\n Single precision");
+ "\n Double precision":
+ "\n Single precision");
if (pos_code & 0x20) {
pbuf += sprintf(pbuf, "\n All Enabled Superpackets");
@@ -3529,8 +3830,8 @@ static void rpt_io_opt (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, (time_code & 0x01)?
- "\n Time tags in UTC":
- "\n Time tags in GPS time");
+ "\n Time tags in UTC":
+ "\n Time tags in GPS time");
if (time_code & 0x02) {
pbuf += sprintf(pbuf, "\n Fixes delayed to integer seconds");
@@ -3548,9 +3849,9 @@ static void rpt_io_opt (TSIPPKT *rpt)
pbuf += sprintf(pbuf, "\n Minimize measurement propagation");
}
- pbuf += sprintf(pbuf, (time_code & 0x20) ?
- "\n PPS output at all times" :
- "\n PPS output during fixes");
+ pbuf += sprintf(pbuf, (time_code & 0x20) ?
+ "\n PPS output at all times" :
+ "\n PPS output during fixes");
if (aux_code & 0x01) {
pbuf += sprintf(pbuf, "\n Raw measurement output");
@@ -3565,15 +3866,18 @@ static void rpt_io_opt (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, (aux_code & 0x08)?
- "\n Signal Strength Output as dBHz" :
- "\n Signal Strength Output as AMU");
+ "\n Signal Strength Output as dBHz" :
+ "\n Signal Strength Output as AMU");
}
/* 0x56 */
-static void rpt_ENU_velocity (TSIPPKT *rpt)
+static void
+rpt_ENU_velocity(
+ TSIPPKT *rpt
+ )
{
float
- vel_ENU[3], freq_offset, time_of_fix;
+ vel_ENU[3], freq_offset, time_of_fix;
/* unload rptbuf */
if (rpt_0x56 (rpt, vel_ENU, &freq_offset, &time_of_fix)) {
@@ -3582,19 +3886,22 @@ static void rpt_ENU_velocity (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\nVel ENU: %11.3f %11.3f %11.3f %12.3f%s",
- vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
- show_time (time_of_fix));
+ vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
+ show_time (time_of_fix));
}
/* 0x57 */
-static void rpt_last_fix_info (TSIPPKT *rpt)
+static void
+rpt_last_fix_info(
+ TSIPPKT *rpt
+ )
{
unsigned char
- source_code, diag_code;
+ source_code, diag_code;
short
- week_num;
+ week_num;
float
- time_of_fix;
+ time_of_fix;
/* unload rptbuf */
if (rpt_0x57 (rpt, &source_code, &diag_code, &week_num, &time_of_fix)) {
@@ -3603,61 +3910,64 @@ static void rpt_last_fix_info (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\n source code %d; diag code: %2Xh",
- source_code, diag_code);
+ source_code, diag_code);
pbuf += sprintf(pbuf, "\n Time of last fix:%s", show_time(time_of_fix));
pbuf += sprintf(pbuf, "\n Week of last fix: %d", week_num);
}
/* 0x58 */
-static void rpt_GPS_system_data (TSIPPKT *rpt)
+static void
+rpt_GPS_system_data(
+ TSIPPKT *rpt
+ )
{
unsigned char
- iprn,
- op_code, data_type, sv_prn,
- data_length, data_packet[250];
+ iprn,
+ op_code, data_type, sv_prn,
+ data_length, data_packet[250];
ALM_INFO
- *almanac;
+ *almanac;
ALH_PARMS
- *almh;
+ *almh;
UTC_INFO
- *utc;
+ *utc;
ION_INFO
- *ionosphere;
+ *ionosphere;
EPHEM_CLOCK
- *cdata;
+ *cdata;
EPHEM_ORBIT
- *edata;
+ *edata;
NAV_INFO
- *nav_data;
+ *nav_data;
unsigned char
- curr_t_oa;
+ curr_t_oa;
unsigned short
- curr_wn_oa;
+ curr_wn_oa;
static char
- *datname[] =
- {"", "", "Almanac Orbit",
- "Health Page & Ref Time", "Ionosphere", "UTC ",
- "Ephemeris"};
+ *datname[] =
+ {"", "", "Almanac Orbit",
+ "Health Page & Ref Time", "Ionosphere", "UTC ",
+ "Ephemeris"};
/* unload rptbuf */
if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn,
- &data_length, data_packet))
- {
+ &data_length, data_packet))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nSystem data [%d]: %s SV%02d",
- data_type, datname[data_type], sv_prn);
+ data_type, datname[data_type], sv_prn);
switch (op_code)
{
- case 1:
+ case 1:
pbuf += sprintf(pbuf, " Acknowledgment");
break;
- case 2:
+ case 2:
pbuf += sprintf(pbuf, " length = %d bytes", data_length);
switch (data_type) {
- case 2:
+ case 2:
/* Almanac */
if (sv_prn == 0 || sv_prn > 32) {
pbuf += sprintf(pbuf, " Binary PRN invalid");
@@ -3665,57 +3975,57 @@ static void rpt_GPS_system_data (TSIPPKT *rpt)
}
almanac = (ALM_INFO*)data_packet;
pbuf += sprintf(pbuf, "\n t_oa_raw = % -12d SV_hlth = % -12d ",
- almanac->t_oa_raw , almanac->SV_health );
+ almanac->t_oa_raw , almanac->SV_health );
pbuf += sprintf(pbuf, "\n e = % -12g t_oa = % -12g ",
- almanac->e , almanac->t_oa );
+ almanac->e , almanac->t_oa );
pbuf += sprintf(pbuf, "\n i_0 = % -12g OMEGADOT = % -12g ",
- almanac->i_0 , almanac->OMEGADOT );
+ almanac->i_0 , almanac->OMEGADOT );
pbuf += sprintf(pbuf, "\n sqrt_A = % -12g OMEGA_0 = % -12g ",
- almanac->sqrt_A , almanac->OMEGA_0 );
+ almanac->sqrt_A , almanac->OMEGA_0 );
pbuf += sprintf(pbuf, "\n omega = % -12g M_0 = % -12g ",
- almanac->omega , almanac->M_0 );
+ almanac->omega , almanac->M_0 );
pbuf += sprintf(pbuf, "\n a_f0 = % -12g a_f1 = % -12g ",
- almanac->a_f0 , almanac->a_f1 );
+ almanac->a_f0 , almanac->a_f1 );
pbuf += sprintf(pbuf, "\n Axis = % -12g n = % -12g ",
- almanac->Axis , almanac->n );
+ almanac->Axis , almanac->n );
pbuf += sprintf(pbuf, "\n OMEGA_n = % -12g ODOT_n = % -12g ",
- almanac->OMEGA_n , almanac->ODOT_n );
+ almanac->OMEGA_n , almanac->ODOT_n );
pbuf += sprintf(pbuf, "\n t_zc = % -12g weeknum = % -12d ",
- almanac->t_zc , almanac->weeknum );
+ almanac->t_zc , almanac->weeknum );
pbuf += sprintf(pbuf, "\n wn_oa = % -12d", almanac->wn_oa );
break;
- case 3:
+ case 3:
/* Almanac health page */
almh = (ALH_PARMS*)data_packet;
pbuf += sprintf(pbuf, "\n t_oa = %d, wn_oa&0xFF = %d ",
- almh->t_oa, almh->WN_a);
+ almh->t_oa, almh->WN_a);
pbuf += sprintf(pbuf, "\nAlmanac health page:");
for (iprn = 0; iprn < 32; iprn++) {
if (!(iprn%5)) *pbuf++ = '\n';
pbuf += sprintf(pbuf, " SV%02d %2X",
- (iprn+1) , almh->SV_health[iprn]);
+ (iprn+1) , almh->SV_health[iprn]);
}
curr_t_oa = data_packet[34];
curr_wn_oa = (unsigned short)((data_packet[35]<<8) + data_packet[36]);
pbuf += sprintf(pbuf, "\n current t_oa = %d, wn_oa = %d ",
- curr_t_oa, curr_wn_oa);
+ curr_t_oa, curr_wn_oa);
break;
- case 4:
+ case 4:
/* Ionosphere */
ionosphere = (ION_INFO*)data_packet;
pbuf += sprintf(pbuf, "\n alpha_0 = % -12g alpha_1 = % -12g ",
- ionosphere->alpha_0, ionosphere->alpha_1);
+ ionosphere->alpha_0, ionosphere->alpha_1);
pbuf += sprintf(pbuf, "\n alpha_2 = % -12g alpha_3 = % -12g ",
- ionosphere->alpha_2, ionosphere->alpha_3);
+ ionosphere->alpha_2, ionosphere->alpha_3);
pbuf += sprintf(pbuf, "\n beta_0 = % -12g beta_1 = % -12g ",
- ionosphere->beta_0, ionosphere->beta_1);
+ ionosphere->beta_0, ionosphere->beta_1);
pbuf += sprintf(pbuf, "\n beta_2 = % -12g beta_3 = % -12g ",
- ionosphere->beta_2, ionosphere->beta_3);
+ ionosphere->beta_2, ionosphere->beta_3);
break;
- case 5:
+ case 5:
/* UTC */
utc = (UTC_INFO*)data_packet;
pbuf += sprintf(pbuf, "\n A_0 = %g ", utc->A_0);
@@ -3728,7 +4038,7 @@ static void rpt_GPS_system_data (TSIPPKT *rpt)
pbuf += sprintf(pbuf, "\n delta_t_LSF = %d ", utc->delta_t_LSF );
break;
- case 6: /* Ephemeris */
+ case 6: /* Ephemeris */
if (sv_prn == 0 || sv_prn > 32) {
pbuf += sprintf(pbuf, " Binary PRN invalid");
return;
@@ -3736,45 +4046,45 @@ static void rpt_GPS_system_data (TSIPPKT *rpt)
nav_data = (NAV_INFO*)data_packet;
pbuf += sprintf(pbuf, "\n SV_PRN = % -12d . t_ephem = % -12g . ",
- nav_data->sv_number , nav_data->t_ephem );
+ nav_data->sv_number , nav_data->t_ephem );
cdata = &(nav_data->ephclk);
pbuf += sprintf(pbuf,
- "\n weeknum = % -12d . codeL2 = % -12d . L2Pdata = % -12d",
- cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
+ "\n weeknum = % -12d . codeL2 = % -12d . L2Pdata = % -12d",
+ cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
pbuf += sprintf(pbuf,
- "\n SVacc_raw = % -12d .SV_health = % -12d . IODC = % -12d",
- cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
+ "\n SVacc_raw = % -12d .SV_health = % -12d . IODC = % -12d",
+ cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
pbuf += sprintf(pbuf,
- "\n T_GD = % -12g . t_oc = % -12g . a_f2 = % -12g",
- cdata->T_GD, cdata->t_oc, cdata->a_f2 );
+ "\n T_GD = % -12g . t_oc = % -12g . a_f2 = % -12g",
+ cdata->T_GD, cdata->t_oc, cdata->a_f2 );
pbuf += sprintf(pbuf,
- "\n a_f1 = % -12g . a_f0 = % -12g . SVacc = % -12g",
- cdata->a_f1, cdata->a_f0, cdata->SVacc );
+ "\n a_f1 = % -12g . a_f0 = % -12g . SVacc = % -12g",
+ cdata->a_f1, cdata->a_f0, cdata->SVacc );
edata = &(nav_data->ephorb);
pbuf += sprintf(pbuf,
- "\n IODE = % -12d .fit_intvl = % -12d . C_rs = % -12g",
- edata->IODE, edata->fit_interval, edata->C_rs );
+ "\n IODE = % -12d .fit_intvl = % -12d . C_rs = % -12g",
+ edata->IODE, edata->fit_interval, edata->C_rs );
pbuf += sprintf(pbuf,
- "\n delta_n = % -12g . M_0 = % -12g . C_uc = % -12g",
- edata->delta_n, edata->M_0, edata->C_uc );
+ "\n delta_n = % -12g . M_0 = % -12g . C_uc = % -12g",
+ edata->delta_n, edata->M_0, edata->C_uc );
pbuf += sprintf(pbuf,
- "\n ecc = % -12g . C_us = % -12g . sqrt_A = % -12g",
- edata->e, edata->C_us, edata->sqrt_A );
+ "\n ecc = % -12g . C_us = % -12g . sqrt_A = % -12g",
+ edata->e, edata->C_us, edata->sqrt_A );
pbuf += sprintf(pbuf,
- "\n t_oe = % -12g . C_ic = % -12g . OMEGA_0 = % -12g",
- edata->t_oe, edata->C_ic, edata->OMEGA_0 );
+ "\n t_oe = % -12g . C_ic = % -12g . OMEGA_0 = % -12g",
+ edata->t_oe, edata->C_ic, edata->OMEGA_0 );
pbuf += sprintf(pbuf,
- "\n C_is = % -12g . i_0 = % -12g . C_rc = % -12g",
- edata->C_is, edata->i_0, edata->C_rc );
+ "\n C_is = % -12g . i_0 = % -12g . C_rc = % -12g",
+ edata->C_is, edata->i_0, edata->C_rc );
pbuf += sprintf(pbuf,
- "\n omega = % -12g . OMEGADOT = % -12g . IDOT = % -12g",
- edata->omega, edata->OMEGADOT, edata->IDOT );
+ "\n omega = % -12g . OMEGADOT = % -12g . IDOT = % -12g",
+ edata->omega, edata->OMEGADOT, edata->IDOT );
pbuf += sprintf(pbuf,
- "\n Axis = % -12g . n = % -12g . r1me2 = % -12g",
- edata->Axis, edata->n, edata->r1me2 );
+ "\n Axis = % -12g . n = % -12g . r1me2 = % -12g",
+ edata->Axis, edata->n, edata->r1me2 );
pbuf += sprintf(pbuf,
- "\n OMEGA_n = % -12g . ODOT_n = % -12g",
- edata->OMEGA_n, edata->ODOT_n );
+ "\n OMEGA_n = % -12g . ODOT_n = % -12g",
+ edata->OMEGA_n, edata->ODOT_n );
break;
}
}
@@ -3782,173 +4092,191 @@ static void rpt_GPS_system_data (TSIPPKT *rpt)
/* 0x59: */
-static void rpt_SVs_enabled (TSIPPKT *rpt)
+static void
+rpt_SVs_enabled(
+ TSIPPKT *rpt
+ )
{
unsigned char
- numsvs,
- code_type,
- status_code[32];
+ numsvs,
+ code_type,
+ status_code[32];
short
- iprn;
+ iprn;
/* unload rptbuf */
if (rpt_0x59 (rpt, &code_type, status_code))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
- switch (code_type)
- {
- case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
- case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
- default: return;
- }
- numsvs = 0;
- for (iprn=0; iprn<32; iprn++)
- {
- if (status_code[iprn])
- {
- pbuf += sprintf(pbuf, " %02d", iprn+1);
- numsvs++;
- }
- }
- if (numsvs == 0) pbuf += sprintf(pbuf, "None");
+ switch (code_type)
+ {
+ case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
+ case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
+ default: return;
+ }
+ numsvs = 0;
+ for (iprn = 0; iprn < 32; iprn++)
+ {
+ if (status_code[iprn])
+ {
+ pbuf += sprintf(pbuf, " %02d", iprn+1);
+ numsvs++;
+ }
+ }
+ if (numsvs == 0) pbuf += sprintf(pbuf, "None");
}
/* 0x5A */
-static void rpt_raw_msmt (TSIPPKT *rpt)
+static void
+rpt_raw_msmt(
+ TSIPPKT *rpt
+ )
{
unsigned char
- sv_prn;
+ sv_prn;
float
- sample_length, signal_level, code_phase, Doppler;
+ sample_length, signal_level, code_phase, Doppler;
double
- time_of_fix;
+ time_of_fix;
/* unload rptbuf */
if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level,
- &code_phase, &Doppler, &time_of_fix))
- {
+ &code_phase, &Doppler, &time_of_fix))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\n %02d %5.0f %7.1f %10.2f %10.2f %12.3f %s",
- sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
- show_time ((float)time_of_fix));
+ sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
+ show_time ((float)time_of_fix));
}
/* 0x5B */
-static void rpt_SV_ephemeris_status (TSIPPKT *rpt)
+static void
+rpt_SV_ephemeris_status(
+ TSIPPKT *rpt
+ )
{
unsigned char
- sv_prn, sv_health, sv_iode, fit_interval_flag;
+ sv_prn, sv_health, sv_iode, fit_interval_flag;
float
- time_of_collection, time_of_eph, sv_accy;
+ time_of_collection, time_of_eph, sv_accy;
/* unload rptbuf */
if (rpt_0x5B (rpt, &sv_prn, &sv_health, &sv_iode, &fit_interval_flag,
- &time_of_collection, &time_of_eph, &sv_accy))
- {
+ &time_of_collection, &time_of_eph, &sv_accy))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\n SV%02d %s %2Xh %2Xh ",
- sv_prn, show_time (time_of_collection), sv_health, sv_iode);
+ sv_prn, show_time (time_of_collection), sv_health, sv_iode);
/* note: cannot use show_time twice in same call */
pbuf += sprintf(pbuf, "%s %1d %4.1f",
- show_time (time_of_eph), fit_interval_flag, sv_accy);
+ show_time (time_of_eph), fit_interval_flag, sv_accy);
}
/* 0x5C */
-static void rpt_SV_tracking_status (TSIPPKT *rpt)
+static void
+rpt_SV_tracking_status(
+ TSIPPKT *rpt
+ )
{
unsigned char
- sv_prn, chan, slot, acq_flag, eph_flag,
- old_msmt_flag, integer_msec_flag, bad_data_flag,
- data_collect_flag;
+ sv_prn, chan, slot, acq_flag, eph_flag,
+ old_msmt_flag, integer_msec_flag, bad_data_flag,
+ data_collect_flag;
float
- signal_level, time_of_last_msmt,
- elev, azim;
+ signal_level, time_of_last_msmt,
+ elev, azim;
/* unload rptbuf */
if (rpt_0x5C (rpt,
- &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
- &signal_level, &time_of_last_msmt, &elev, &azim,
- &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
- &data_collect_flag))
- {
+ &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
+ &signal_level, &time_of_last_msmt, &elev, &azim,
+ &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
+ &data_collect_flag))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf,
-"\n SV%2d %1d %1d %1d %4.1f %s %5.1f %5.1f",
- sv_prn, chan,
- acq_flag, eph_flag, signal_level,
- show_time(time_of_last_msmt),
- elev*R2D, azim*R2D);
+ "\n SV%2d %1d %1d %1d %4.1f %s %5.1f %5.1f",
+ sv_prn, chan,
+ acq_flag, eph_flag, signal_level,
+ show_time(time_of_last_msmt),
+ elev*R2D, azim*R2D);
}
/**/
/* 0x6D */
-static void rpt_allSV_selection (TSIPPKT *rpt)
+static void
+rpt_allSV_selection(
+ TSIPPKT *rpt
+ )
{
unsigned char
- manual_mode, nsvs, sv_prn[8], ndim;
+ manual_mode, nsvs, sv_prn[8], ndim;
short
- islot;
+ islot;
float
- pdop, hdop, vdop, tdop;
+ pdop, hdop, vdop, tdop;
/* unload rptbuf */
if (rpt_0x6D (rpt,
- &manual_mode, &nsvs, &ndim, sv_prn,
- &pdop, &hdop, &vdop, &tdop))
- {
+ &manual_mode, &nsvs, &ndim, sv_prn,
+ &pdop, &hdop, &vdop, &tdop))
+ {
parsed = BADLEN_PARSE;
return;
}
switch (ndim)
- {
- case 0:
+ {
+ case 0:
pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs);
- break;
- case 1:
+ break;
+ case 1:
pbuf += sprintf(pbuf, "\nMode: One-SV Timing:");
- break;
- case 3: case 4:
+ break;
+ case 3: case 4:
pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:",
- manual_mode ? 'M' : 'A', ndim - 1, nsvs);
- break;
- case 5:
+ manual_mode ? 'M' : 'A', ndim - 1, nsvs);
+ break;
+ case 5:
pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs);
- break;
- default:
+ break;
+ default:
pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim);
- break;
- }
+ break;
+ }
for (islot = 0; islot < nsvs; islot++)
- {
+ {
if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]);
}
- if (ndim == 3 || ndim == 4)
- {
+ if (ndim == 3 || ndim == 4)
+ {
pbuf += sprintf(pbuf, "; DOPs: P %.1f H %.1f V %.1f T %.1f",
- pdop, hdop, vdop, tdop);
- }
+ pdop, hdop, vdop, tdop);
+ }
}
/**/
/* 0x82 */
-static void rpt_DGPS_position_mode (TSIPPKT *rpt)
+static void
+rpt_DGPS_position_mode(
+ TSIPPKT *rpt
+ )
{
unsigned char
- diff_mode;
+ diff_mode;
/* unload rptbuf */
if (rpt_0x82 (rpt, &diff_mode)) {
@@ -3957,49 +4285,54 @@ static void rpt_DGPS_position_mode (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\nFix is%s DGPS-corrected (%s mode) (%d)",
- (diff_mode&1) ? "" : " not",
- (diff_mode&2) ? "auto" : "manual",
- diff_mode);
+ (diff_mode&1) ? "" : " not",
+ (diff_mode&2) ? "auto" : "manual",
+ diff_mode);
}
/* 0x83 */
-static void rpt_double_ECEF_position (TSIPPKT *rpt)
+static void
+rpt_double_ECEF_position(
+ TSIPPKT *rpt
+ )
{
-
double
- ECEF_pos[3], clock_bias;
+ ECEF_pos[3], clock_bias;
float
- time_of_fix;
+ time_of_fix;
/* unload rptbuf */
if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nDXYZ:%12.2f %13.2f %13.2f %12.2f%s",
- ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
- show_time(time_of_fix));
+ ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
+ show_time(time_of_fix));
}
/* 0x84 */
-static void rpt_double_lla_position (TSIPPKT *rpt)
+static void
+rpt_double_lla_position(
+ TSIPPKT *rpt
+ )
{
short
- lat_deg, lon_deg;
+ lat_deg, lon_deg;
double
- lat, lon, lat_min, lon_min,
- alt, clock_bias;
+ lat, lon, lat_min, lon_min,
+ alt, clock_bias;
float
- time_of_fix;
+ time_of_fix;
unsigned char
- north_south, east_west;
+ north_south, east_west;
/* unload rptbuf */
if (rpt_0x84 (rpt,
- &lat, &lon, &alt, &clock_bias, &time_of_fix))
- {
+ &lat, &lon, &alt, &clock_bias, &time_of_fix))
+ {
parsed = BADLEN_PARSE;
return;
}
@@ -4024,14 +4357,17 @@ static void rpt_double_lla_position (TSIPPKT *rpt)
lon_deg = (short)lon;
lon_min = (lon - lon_deg) * 60.0;
pbuf += sprintf(pbuf, "\nDLLA: %2d:%08.5f %c; %3d:%08.5f %c; %10.2f %12.2f%s",
- lat_deg, lat_min, north_south,
- lon_deg, lon_min, east_west,
- alt, clock_bias,
- show_time(time_of_fix));
+ lat_deg, lat_min, north_south,
+ lon_deg, lon_min, east_west,
+ alt, clock_bias,
+ show_time(time_of_fix));
}
/* 0xBB */
-static void rpt_complete_rcvr_config (TSIPPKT *rpt)
+static void
+rpt_complete_rcvr_config(
+ TSIPPKT *rpt
+ )
{
TSIP_RCVR_CFG TsipxBB ;
/* unload rptbuf */
@@ -4042,49 +4378,52 @@ static void rpt_complete_rcvr_config (TSIPPKT *rpt)
}
pbuf += sprintf(pbuf, "\n operating mode: %s",
- NavModeText0xBB[TsipxBB.operating_mode]);
+ NavModeText0xBB[TsipxBB.operating_mode]);
pbuf += sprintf(pbuf, "\n dynamics: %s",
- dyn_text[TsipxBB.dyn_code]);
+ dyn_text[TsipxBB.dyn_code]);
pbuf += sprintf(pbuf, "\n elev angle mask: %g deg",
- TsipxBB.elev_mask * R2D);
+ TsipxBB.elev_mask * R2D);
pbuf += sprintf(pbuf, "\n SNR mask: %g AMU",
- TsipxBB.cno_mask);
+ TsipxBB.cno_mask);
pbuf += sprintf(pbuf, "\n DOP mask: %g",
- TsipxBB.dop_mask);
+ TsipxBB.dop_mask);
pbuf += sprintf(pbuf, "\n DOP switch: %g",
- TsipxBB.dop_switch);
+ TsipxBB.dop_switch);
return ;
}
/* 0xBC */
-static void rpt_rcvr_serial_port_config (TSIPPKT *rpt)
+static void
+rpt_rcvr_serial_port_config(
+ TSIPPKT *rpt
+ )
{
unsigned char
- port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
- protocols_in, protocols_out, reserved;
+ port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
+ protocols_in, protocols_out, reserved;
unsigned char known;
/* unload rptbuf */
if (rpt_0xBC (rpt, &port_num, &in_baud, &out_baud, &data_bits, &parity,
- &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) {
+ &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) {
parsed = BADLEN_PARSE;
return;
}
/* rptbuf unloaded */
pbuf += sprintf(pbuf, "\n RECEIVER serial port %s config:",
- rcvr_port_text[port_num]);
+ rcvr_port_text[port_num]);
pbuf += sprintf(pbuf, "\n I/O Baud %s/%s, %d - %s - %d",
- st_baud_text_app[in_baud],
- st_baud_text_app[out_baud],
- data_bits+5,
- parity_text[parity],
- stop_bits=1);
+ st_baud_text_app[in_baud],
+ st_baud_text_app[out_baud],
+ data_bits+5,
+ parity_text[parity],
+ stop_bits=1);
pbuf += sprintf(pbuf, "\n Input protocols: ");
known = FALSE;
if (protocols_in&B_TSIP)
- {
+ {
pbuf += sprintf(pbuf, "%s ", protocols_in_text[1]);
known = TRUE;
}
@@ -4093,98 +4432,101 @@ static void rpt_rcvr_serial_port_config (TSIPPKT *rpt)
pbuf += sprintf(pbuf, "\n Output protocols: ");
known = FALSE;
if (protocols_out&B_TSIP)
- {
+ {
pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]);
known = TRUE;
}
if (protocols_out&B_NMEA)
- {
+ {
pbuf += sprintf(pbuf, "%s ", protocols_out_text[2]);
known = TRUE;
}
if (known == FALSE) pbuf += sprintf(pbuf, "No known");
reserved = reserved;
- }
+}
/* 0x8F */
/* 8F0B */
-static void rpt_8F0B(TSIPPKT *rpt)
+static void
+rpt_8F0B(
+ TSIPPKT *rpt
+ )
{
const char
- *oprtng_dim[7] = {
- "horizontal (2-D)",
- "full position (3-D)",
- "single satellite (0-D)",
- "automatic",
- "N/A",
- "N/A",
- "overdetermined clock"};
- char
- sv_id[8];
- unsigned char
- month,
- date,
- dim_mode,
- north_south,
- east_west;
- unsigned short
- event;
- short
- utc_offset,
- year,
- local_index;
+ *oprtng_dim[7] = {
+ "horizontal (2-D)",
+ "full position (3-D)",
+ "single satellite (0-D)",
+ "automatic",
+ "N/A",
+ "N/A",
+ "overdetermined clock"};
+ char
+ sv_id[8];
+ unsigned char
+ month,
+ date,
+ dim_mode,
+ north_south,
+ east_west;
+ unsigned short
+ event;
short
- lat_deg,
- lon_deg;
- float
- bias_unc,
- dr_unc;
- double
- tow,
- bias,
- drift,
- lat,
- lon,
- alt,
- lat_min,
- lon_min;
- int
- numfix,
- numnotfix;
+ utc_offset,
+ year,
+ local_index;
+ short
+ lat_deg,
+ lon_deg;
+ float
+ bias_unc,
+ dr_unc;
+ double
+ tow,
+ bias,
+ drift,
+ lat,
+ lon,
+ alt,
+ lat_min,
+ lon_min;
+ int
+ numfix,
+ numnotfix;
if (rpt_0x8F0B(rpt,
- &event,
- &tow,
- &date,
- &month,
- &year,
- &dim_mode,
- &utc_offset,
- &bias,
- &drift,
- &bias_unc,
- &dr_unc,
- &lat,
- &lon,
- &alt,
- sv_id))
- {
+ &event,
+ &tow,
+ &date,
+ &month,
+ &year,
+ &dim_mode,
+ &utc_offset,
+ &bias,
+ &drift,
+ &bias_unc,
+ &dr_unc,
+ &lat,
+ &lon,
+ &alt,
+ sv_id))
+ {
parsed = BADLEN_PARSE;
return;
}
if (event == 0)
- {
- pbuf += sprintf(pbuf, "\nNew partial+full meas");
+ {
+ pbuf += sprintf(pbuf, "\nNew partial+full meas");
}
- else
- {
+ else
+ {
pbuf += sprintf(pbuf, "\nEvent count: %5d", event);
- }
+ }
pbuf += sprintf(pbuf, "\nGPS time : %s %2d/%2d/%2d (DMY)",
- show_time(tow), date, month, year);
+ show_time(tow), date, month, year);
pbuf += sprintf(pbuf, "\nMode : %s", oprtng_dim[dim_mode]);
pbuf += sprintf(pbuf, "\nUTC offset: %2d", utc_offset);
pbuf += sprintf(pbuf, "\nClock Bias: %6.2f m", bias);
@@ -4195,24 +4537,24 @@ static void rpt_8F0B(TSIPPKT *rpt)
lat *= R2D; /* convert from radians to degrees */
lon *= R2D;
if (lat < 0.0)
- {
+ {
north_south = 'S';
lat = -lat;
}
- else
- {
+ else
+ {
north_south = 'N';
}
lat_deg = (short)lat;
lat_min = (lat - lat_deg) * 60.0;
if (lon < 0.0)
- {
+ {
east_west = 'W';
lon = -lon;
}
- else
- {
+ else
+ {
east_west = 'E';
}
@@ -4223,79 +4565,85 @@ static void rpt_8F0B(TSIPPKT *rpt)
pbuf += sprintf(pbuf, " %5d %6.3f %c", lon_deg, lon_min, east_west);
pbuf += sprintf(pbuf, " %10.2f", alt);
- numfix = numnotfix = 0;
+ numfix = numnotfix = 0;
for (local_index=0; local_index<8; local_index++)
- {
+ {
if (sv_id[local_index] < 0) numnotfix++;
if (sv_id[local_index] > 0) numfix++;
- }
- if (numfix > 0)
- {
+ }
+ if (numfix > 0)
+ {
pbuf += sprintf(pbuf, "\nSVs used in fix : ");
for (local_index=0; local_index<8; local_index++)
- {
+ {
if (sv_id[local_index] > 0)
- {
- pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
- }
- }
- }
- if (numnotfix > 0)
- {
+ {
+ pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
+ }
+ }
+ }
+ if (numnotfix > 0)
+ {
pbuf += sprintf(pbuf, "\nOther SVs tracked: ");
for (local_index=0; local_index<8; local_index++)
- {
+ {
if (sv_id[local_index] < 0)
- {
- pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
- }
- }
- }
+ {
+ pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
+ }
+ }
+ }
}
/* 0x8F14 */
-static void rpt_8F14 (TSIPPKT *rpt)
/* Datum parameters */
+static void
+rpt_8F14(
+ TSIPPKT *rpt
+ )
{
double
- datum_coeffs[5];
+ datum_coeffs[5];
short
- datum_idx;
+ datum_idx;
/* unload rptbuf */
if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs))
- {
+ {
parsed = BADLEN_PARSE;
return;
}
if (datum_idx == -1)
- {
- pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
+ {
+ pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
pbuf += sprintf(pbuf, "\n dx = %6.1f", datum_coeffs[0]);
pbuf += sprintf(pbuf, "\n dy = %6.1f", datum_coeffs[1]);
pbuf += sprintf(pbuf, "\n dz = %6.1f", datum_coeffs[2]);
pbuf += sprintf(pbuf, "\n a-axis = %10.3f", datum_coeffs[3]);
pbuf += sprintf(pbuf, "\n e-squared = %16.14f", datum_coeffs[4]);
- }
- else if (datum_idx == 0)
- {
- pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
- }
- else
- {
- pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
- }
+ }
+ else if (datum_idx == 0)
+ {
+ pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
+ }
}
/* 0x8F15 */
-static void rpt_8F15 (TSIPPKT *rpt)
/* Datum parameters */
+static void
+rpt_8F15(
+ TSIPPKT *rpt
+ )
{
double
- datum_coeffs[5];
+ datum_coeffs[5];
short
- datum_idx;
+ datum_idx;
/* unload rptbuf */
if (rpt_0x8F15 (rpt, &datum_idx, datum_coeffs)) {
@@ -4304,22 +4652,22 @@ static void rpt_8F15 (TSIPPKT *rpt)
}
if (datum_idx == -1)
- {
- pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
+ {
+ pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
pbuf += sprintf(pbuf, "\n dx = %6.1f", datum_coeffs[0]);
pbuf += sprintf(pbuf, "\n dy = %6.1f", datum_coeffs[1]);
pbuf += sprintf(pbuf, "\n dz = %6.1f", datum_coeffs[2]);
pbuf += sprintf(pbuf, "\n a-axis = %10.3f", datum_coeffs[3]);
pbuf += sprintf(pbuf, "\n e-squared = %16.14f", datum_coeffs[4]);
- }
- else if (datum_idx == 0)
- {
- pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
- }
- else
- {
- pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
- }
+ }
+ else if (datum_idx == 0)
+ {
+ pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
+ }
}
/* 0x8F20 */
@@ -4327,72 +4675,75 @@ static void rpt_8F15 (TSIPPKT *rpt)
#define INFO_2D 0x04
#define INFO_ALTSET 0x08
#define INFO_FILTERED 0x10
-static void rpt_8F20 (TSIPPKT *rpt)
+static void
+rpt_8F20(
+ TSIPPKT *rpt
+ )
{
unsigned char
- info, nsvs, sv_prn[32];
+ info, nsvs, sv_prn[32];
short
- week_num, datum_index, sv_IODC[32];
+ week_num, datum_index, sv_IODC[32];
double
- lat, lon, alt, time_of_fix;
+ lat, lon, alt, time_of_fix;
double
- londeg, latdeg, vel[3];
+ londeg, latdeg, vel[3];
short
- isv;
- char
- datum_string[20];
+ isv;
+ char
+ datum_string[20];
/* unload rptbuf */
if (rpt_0x8F20 (rpt,
- &info, &lat, &lon, &alt, vel,
- &time_of_fix,
- &week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
+ &info, &lat, &lon, &alt, vel,
+ &time_of_fix,
+ &week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
{
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf,
- "\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds) FixType: %s%s%s",
- week_num,
- dayname[(short)(time_of_fix/86400.0)],
- (short)fmod(time_of_fix/3600., 24.),
- (short)fmod(time_of_fix/60., 60.),
- fmod(time_of_fix, 60.),
- (char)rpt->buf[29], /* UTC offset */
- (info & INFO_DGPS)?"Diff":"",
- (info & INFO_2D)?"2D":"3D",
- (info & INFO_FILTERED)?"-Filtrd":"");
-
- if (datum_index > 0)
- {
+ "\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds) FixType: %s%s%s",
+ week_num,
+ dayname[(short)(time_of_fix/86400.0)],
+ (short)fmod(time_of_fix/3600., 24.),
+ (short)fmod(time_of_fix/60., 60.),
+ fmod(time_of_fix, 60.),
+ (char)rpt->buf[29], /* UTC offset */
+ (info & INFO_DGPS)?"Diff":"",
+ (info & INFO_2D)?"2D":"3D",
+ (info & INFO_FILTERED)?"-Filtrd":"");
+
+ if (datum_index > 0)
+ {
sprintf(datum_string, "Datum%3d", datum_index);
- }
- else if (datum_index)
- {
+ }
+ else if (datum_index)
+ {
sprintf(datum_string, "Unknown ");
- }
- else
- {
+ }
+ else
+ {
sprintf(datum_string, "WGS-84");
- }
+ }
/* convert from radians to degrees */
latdeg = R2D * fabs(lat);
londeg = R2D * fabs(lon);
pbuf += sprintf(pbuf,
- "\n Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
- (short)latdeg, fmod (latdeg, 1.)*60.0,
- (lat<0.0)?'S':'N',
- (short)londeg, fmod (londeg, 1.)*60.0,
- (lon<0.0)?'W':'E',
- alt,
- datum_string);
+ "\n Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
+ (short)latdeg, fmod (latdeg, 1.)*60.0,
+ (lat<0.0)?'S':'N',
+ (short)londeg, fmod (londeg, 1.)*60.0,
+ (lon<0.0)?'W':'E',
+ alt,
+ datum_string);
pbuf += sprintf(pbuf,
- "\n Vel: %9.3f E %9.3f N %9.3f U (m/sec)",
- vel[0], vel[1], vel[2]);
+ "\n Vel: %9.3f E %9.3f N %9.3f U (m/sec)",
+ vel[0], vel[1], vel[2]);
pbuf += sprintf(pbuf,
- "\n SVs: ");
+ "\n SVs: ");
for (isv = 0; isv < nsvs; isv++) {
pbuf += sprintf(pbuf, " %02d", sv_prn[isv]);
}
@@ -4404,361 +4755,394 @@ static void rpt_8F20 (TSIPPKT *rpt)
}
/* 0x8F41 */
-static void rpt_8F41(TSIPPKT *rpt)
+static void
+rpt_8F41(
+ TSIPPKT *rpt
+ )
{
unsigned char
- bSearchRange,
- bBoardOptions,
- bBuildYear,
- bBuildMonth,
- bBuildDay,
- bBuildHour;
+ bSearchRange,
+ bBoardOptions,
+ bBuildYear,
+ bBuildMonth,
+ bBuildDay,
+ bBuildHour;
float
- fOscOffset;
+ fOscOffset;
unsigned short
- iTestCodeId;
+ iTestCodeId;
unsigned long
- iiSerialNumber;
-
- if (!rpt_0x8F41(rpt,
- &bSearchRange,
- &bBoardOptions,
- &iiSerialNumber,
- &bBuildYear,
- &bBuildMonth,
- &bBuildDay,
- &bBuildHour,
- &fOscOffset,
- &iTestCodeId))
- {
+ iiSerialNumber;
+
+ if (!rpt_0x8F41(rpt,
+ &bSearchRange,
+ &bBoardOptions,
+ &iiSerialNumber,
+ &bBuildYear,
+ &bBuildMonth,
+ &bBuildDay,
+ &bBuildHour,
+ &fOscOffset,
+ &iTestCodeId))
+ {
parsed = BADLEN_PARSE;
- return;
- }
-
- pbuf += sprintf(pbuf, "\n search range: %d",
- bSearchRange);
- pbuf += sprintf(pbuf, "\n board options: %d",
- bBoardOptions);
- pbuf += sprintf(pbuf, "\n board serial #: %ld",
- iiSerialNumber);
- pbuf += sprintf(pbuf, "\n build date/hour: %02d/%02d/%02d %02d:00",
- bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
- pbuf += sprintf(pbuf, "\n osc offset: %.3f PPM (%.0f Hz)",
- fOscOffset/1575.42, fOscOffset);
- pbuf += sprintf(pbuf, "\n test code: %d",
- iTestCodeId);
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n search range: %d",
+ bSearchRange);
+ pbuf += sprintf(pbuf, "\n board options: %d",
+ bBoardOptions);
+ pbuf += sprintf(pbuf, "\n board serial #: %ld",
+ iiSerialNumber);
+ pbuf += sprintf(pbuf, "\n build date/hour: %02d/%02d/%02d %02d:00",
+ bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
+ pbuf += sprintf(pbuf, "\n osc offset: %.3f PPM (%.0f Hz)",
+ fOscOffset/1575.42, fOscOffset);
+ pbuf += sprintf(pbuf, "\n test code: %d",
+ iTestCodeId);
}
/* 0x8F42 */
-static void rpt_8F42(TSIPPKT *rpt)
+static void
+rpt_8F42(
+ TSIPPKT *rpt
+ )
{
unsigned char
- bProdOptionsPre,
- bProdNumberExt;
+ bProdOptionsPre,
+ bProdNumberExt;
unsigned short
- iCaseSerialNumberPre,
- iPremiumOptions,
- iMachineID,
- iKey;
+ iCaseSerialNumberPre,
+ iPremiumOptions,
+ iMachineID,
+ iKey;
unsigned long
- iiCaseSerialNumber,
- iiProdNumber;
-
- if (!rpt_0x8F42(rpt,
- &bProdOptionsPre,
- &bProdNumberExt,
- &iCaseSerialNumberPre,
- &iiCaseSerialNumber,
- &iiProdNumber,
- &iPremiumOptions,
- &iMachineID,
- &iKey))
- {
+ iiCaseSerialNumber,
+ iiProdNumber;
+
+ if (!rpt_0x8F42(rpt,
+ &bProdOptionsPre,
+ &bProdNumberExt,
+ &iCaseSerialNumberPre,
+ &iiCaseSerialNumber,
+ &iiProdNumber,
+ &iPremiumOptions,
+ &iMachineID,
+ &iKey))
+ {
parsed = BADLEN_PARSE;
- return;
- }
+ return;
+ }
pbuf += sprintf(pbuf, "\nProduct ID 8F42");
- pbuf += sprintf(pbuf, "\n extension: %d", bProdNumberExt);
- pbuf += sprintf(pbuf, "\n case serial # prefix: %d", iCaseSerialNumberPre);
- pbuf += sprintf(pbuf, "\n case serial #: %ld", iiCaseSerialNumber);
- pbuf += sprintf(pbuf, "\n prod. #: %ld", iiProdNumber);
+ pbuf += sprintf(pbuf, "\n extension: %d", bProdNumberExt);
+ pbuf += sprintf(pbuf, "\n case serial # prefix: %d", iCaseSerialNumberPre);
+ pbuf += sprintf(pbuf, "\n case serial #: %ld", iiCaseSerialNumber);
+ pbuf += sprintf(pbuf, "\n prod. #: %ld", iiProdNumber);
pbuf += sprintf(pbuf, "\n premium options: %Xh", iPremiumOptions);
- pbuf += sprintf(pbuf, "\n machine ID: %d", iMachineID);
- pbuf += sprintf(pbuf, "\n key: %Xh", iKey);
+ pbuf += sprintf(pbuf, "\n machine ID: %d", iMachineID);
+ pbuf += sprintf(pbuf, "\n key: %Xh", iKey);
}
/* 0x8F45 */
-static void rpt_8F45(TSIPPKT *rpt)
+static void
+rpt_8F45(
+ TSIPPKT *rpt
+ )
{
- unsigned char bSegMask;
+ unsigned char bSegMask;
- if (!rpt_0x8F45(rpt,
- &bSegMask))
- {
+ if (!rpt_0x8F45(rpt,
+ &bSegMask))
+ {
parsed = BADLEN_PARSE;
return;
}
pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask);
}
-static void rpt_8F4A(TSIPPKT *rpt)
/* Stinger PPS def */
+static void
+rpt_8F4A(
+ TSIPPKT *rpt
+ )
{
unsigned char
- pps_enabled,
- pps_timebase,
- pps_polarity;
- float
- bias_unc_threshold;
- double
- pps_offset;
+ pps_enabled,
+ pps_timebase,
+ pps_polarity;
+ float
+ bias_unc_threshold;
+ double
+ pps_offset;
if (rpt_0x8F4A_16 (rpt,
- &pps_enabled,
- &pps_timebase,
- &pps_polarity,
- &pps_offset,
- &bias_unc_threshold))
- {
- parsed = BADLEN_PARSE;
- return;
- }
+ &pps_enabled,
+ &pps_timebase,
+ &pps_polarity,
+ &pps_offset,
+ &bias_unc_threshold))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
pbuf += sprintf(pbuf, "\nPPS is %s", pps_enabled?"enabled":"disabled");
- pbuf += sprintf(pbuf, "\n timebase: %s", PPSTimeBaseText[pps_timebase]);
- pbuf += sprintf(pbuf, "\n polarity: %s", PPSPolarityText[pps_polarity]);
- pbuf += sprintf(pbuf, "\n offset: %.1f ns, ", pps_offset*1.e9);
- pbuf += sprintf(pbuf, "\n biasunc: %.1f ns", bias_unc_threshold/GPS_C*1.e9);
+ pbuf += sprintf(pbuf, "\n timebase: %s", PPSTimeBaseText[pps_timebase]);
+ pbuf += sprintf(pbuf, "\n polarity: %s", PPSPolarityText[pps_polarity]);
+ pbuf += sprintf(pbuf, "\n offset: %.1f ns, ", pps_offset*1.e9);
+ pbuf += sprintf(pbuf, "\n biasunc: %.1f ns", bias_unc_threshold/GPS_C*1.e9);
}
-static void rpt_8F4B(TSIPPKT *rpt)
/* fast-SA decorrolation time for self-survey */
+static void
+rpt_8F4B(
+ TSIPPKT *rpt
+ )
{
unsigned long
- decorr_max;
+ decorr_max;
- if (rpt_0x8F4B(rpt, &decorr_max))
- {
+ if (rpt_0x8F4B(rpt, &decorr_max))
+ {
parsed = BADLEN_PARSE;
- return;
- }
+ return;
+ }
- pbuf += sprintf(pbuf,
- "\nMax # of position fixes for self-survey : %ld",
- decorr_max);
+ pbuf += sprintf(pbuf,
+ "\nMax # of position fixes for self-survey : %ld",
+ decorr_max);
}
-static void rpt_8F4D(TSIPPKT *rpt)
+static void
+rpt_8F4D(
+ TSIPPKT *rpt
+ )
{
static char
- *linestart;
+ *linestart;
unsigned long
- OutputMask;
- static unsigned long
- MaskBit[] = {
- 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
- 0x00000100L, 0x00000800L, 0x00001000L,
- 0x40000000L, 0x80000000L};
- int
- ichoice,
- numchoices;
-
- if (rpt_0x8F4D(rpt, &OutputMask))
- {
+ OutputMask;
+ static unsigned long
+ MaskBit[] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
+ 0x00000020,
+ 0x00000100L, 0x00000800L, 0x00001000L,
+ 0x40000000L, 0x80000000L};
+ int
+ ichoice,
+ numchoices;
+
+ if (rpt_0x8F4D(rpt, &OutputMask))
+ {
parsed = BADLEN_PARSE;
- return;
- }
-
- pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
- (unsigned char)(OutputMask>>24),
- (unsigned char)(OutputMask>>16),
- (unsigned char)(OutputMask>>8),
- (unsigned char)OutputMask);
-
- numchoices = sizeof(MaskText)/sizeof(char*);
- pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
- linestart = pbuf;
- for (ichoice=0; ichoice<numchoices; ichoice++)
- {
- if (OutputMask&MaskBit[ichoice])
- {
- pbuf += sprintf(pbuf, "%s %s",
- (pbuf==linestart)?"\n ":",",
- MaskText[ichoice]);
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
+ (unsigned char)(OutputMask>>24),
+ (unsigned char)(OutputMask>>16),
+ (unsigned char)(OutputMask>>8),
+ (unsigned char)OutputMask);
+
+ numchoices = sizeof(MaskText)/sizeof(char*);
+ pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
+ linestart = pbuf;
+ for (ichoice = 0; ichoice < numchoices; ichoice++)
+ {
+ if (OutputMask&MaskBit[ichoice])
+ {
+ pbuf += sprintf(pbuf, "%s %s",
+ (pbuf==linestart)?"\n ":",",
+ MaskText[ichoice]);
if (pbuf-linestart > 60) linestart = pbuf;
- }
- }
-
- pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
- linestart = pbuf;
- for (ichoice=0; ichoice<numchoices; ichoice++)
- {
- if (OutputMask&MaskBit[ichoice]) continue;
+ }
+ }
+
+ pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
+ linestart = pbuf;
+ for (ichoice = 0; ichoice < numchoices; ichoice++)
+ {
+ if (OutputMask&MaskBit[ichoice]) continue;
pbuf += sprintf(pbuf, "%s %s",
- (pbuf==linestart)?"\n ":",",
- MaskText[ichoice]);
+ (pbuf==linestart)?"\n ":",",
+ MaskText[ichoice]);
if (pbuf-linestart > 60) linestart = pbuf;
- }
+ }
}
-static void rpt_8FA5(TSIPPKT *rpt)
+static void
+rpt_8FA5(
+ TSIPPKT *rpt
+ )
{
unsigned char
- spktmask[4];
+ spktmask[4];
- if (rpt_0x8FA5(rpt, spktmask))
- {
+ if (rpt_0x8FA5(rpt, spktmask))
+ {
parsed = BADLEN_PARSE;
- return;
- }
-
- pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
- spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
-
- if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n PPS 8F-0B");
- if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n Event 8F-0B");
- if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n PPS 8F-AD");
- if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n Event 8F-AD");
- if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n ppos Fix 8F-20");
-}
-
-static void rpt_8FAD (TSIPPKT *rpt)
-{
- unsigned short
- Count,
- Year;
- double
- FracSec;
- unsigned char
- Hour,
- Minute,
- Second,
- Day,
- Month,
- Status,
- Flags;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
+ spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
+
+ if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n PPS 8F-0B");
+ if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n Event 8F-0B");
+ if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n PPS 8F-AD");
+ if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n Event 8F-AD");
+ if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n ppos Fix 8F-20");
+}
+
+static void
+rpt_8FAD(
+ TSIPPKT *rpt
+ )
+{
+ unsigned short
+ Count,
+ Year;
+ double
+ FracSec;
+ unsigned char
+ Hour,
+ Minute,
+ Second,
+ Day,
+ Month,
+ Status,
+ Flags;
static char* Status8FADText[] = {
- "CODE_DOING_FIXES",
- "CODE_GOOD_1_SV",
- "CODE_APPX_1SV",
- "CODE_NEED_TIME",
- "CODE_NEED_INITIALIZATION",
- "CODE_PDOP_HIGH",
- "CODE_BAD_1SV",
- "CODE_0SVS",
- "CODE_1SV",
- "CODE_2SVS",
- "CODE_3SVS",
- "CODE_NO_INTEGRITY",
- "CODE_DCORR_GEN",
- "CODE_OVERDET_CLK",
- "Invalid Status"},
- *LeapStatusText[] = {
- " UTC Avail", " ", " ", " ",
- " Scheduled", " Pending", " Warning", " In Progress"};
- int i;
+ "CODE_DOING_FIXES",
+ "CODE_GOOD_1_SV",
+ "CODE_APPX_1SV",
+ "CODE_NEED_TIME",
+ "CODE_NEED_INITIALIZATION",
+ "CODE_PDOP_HIGH",
+ "CODE_BAD_1SV",
+ "CODE_0SVS",
+ "CODE_1SV",
+ "CODE_2SVS",
+ "CODE_3SVS",
+ "CODE_NO_INTEGRITY",
+ "CODE_DCORR_GEN",
+ "CODE_OVERDET_CLK",
+ "Invalid Status"},
+ *LeapStatusText[] = {
+ " UTC Avail", " ", " ", " ",
+ " Scheduled", " Pending", " Warning", " In Progress"};
+ int i;
if (rpt_0x8FAD (rpt,
- &Count,
- &FracSec,
- &Hour,
- &Minute,
- &Second,
- &Day,
- &Month,
- &Year,
- &Status,
- &Flags))
- {
+ &Count,
+ &FracSec,
+ &Hour,
+ &Minute,
+ &Second,
+ &Day,
+ &Month,
+ &Year,
+ &Status,
+ &Flags))
+ {
parsed = BADLEN_PARSE;
return;
- }
+ }
pbuf += sprintf(pbuf, "\n8FAD Count: %d Status: %s",
- Count, Status8FADText[Status]);
-
- pbuf += sprintf(pbuf, "\n Leap Flags:");
- if (Flags)
- {
- for (i=0; i<8; i++)
- {
- if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
- }
- }
- else
- {
- pbuf += sprintf(pbuf, " UTC info not available");
- }
+ Count, Status8FADText[Status]);
+
+ pbuf += sprintf(pbuf, "\n Leap Flags:");
+ if (Flags)
+ {
+ for (i=0; i<8; i++)
+ {
+ if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
+ }
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, " UTC info not available");
+ }
pbuf += sprintf(pbuf, "\n %02d/%02d/%04d (DMY) %02d:%02d:%02d.%09ld UTC",
- Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
+ Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
}
-int print_msg_table_header (int rptcode, char *HdrStr, int force)
+int
+print_msg_table_header(
+ int rptcode,
+ char *HdrStr,
+ int force
+ )
{
/* force header is to help auto-output function */
/* last_rptcode is to determine whether to print a header */
/* for the first occurrence of a series of reports */
static int
- last_rptcode = 0;
- int
- numchars;
+ last_rptcode = 0;
+ int
+ numchars;
- numchars = 0;
+ numchars = 0;
if (force || rptcode!=last_rptcode)
- {
+ {
/* supply a header in console output */
- switch (rptcode)
+ switch (rptcode)
{
- case 0x5A:
+ case 0x5A:
numchars = sprintf(HdrStr, "\nRaw Measurement Data");
numchars += sprintf(HdrStr+numchars,
- "\n SV Sample SNR Code Phase Doppler Seconds Time of Meas");
+ "\n SV Sample SNR Code Phase Doppler Seconds Time of Meas");
break;
- case 0x5B:
+ case 0x5B:
numchars = sprintf(HdrStr, "\nEphemeris Status");
numchars += sprintf(HdrStr+numchars,
- "\n SV Time collected Health IODE t oe Fit URA");
+ "\n SV Time collected Health IODE t oe Fit URA");
break;
- case 0x5C:
+ case 0x5C:
numchars = sprintf(HdrStr, "\nTracking Info");
numchars += sprintf(HdrStr+numchars,
- "\n SV C Acq Eph SNR Time of Meas Elev Azim ");
+ "\n SV C Acq Eph SNR Time of Meas Elev Azim ");
break;
- }
+ }
}
last_rptcode = rptcode;
- return (short)numchars;
+ return (short)numchars;
}
-static void unknown_rpt (TSIPPKT *rpt)
+static void
+unknown_rpt(
+ TSIPPKT *rpt
+ )
{
int i;
/* app-specific rpt packets */
if (parsed == BADLEN_PARSE)
- {
+ {
pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length",
- rpt->code, rpt->len);
- }
+ rpt->code, rpt->len);
+ }
if (parsed == BADID_PARSE)
- {
+ {
pbuf += sprintf(pbuf,
- "\nTSIP report packet ID %2Xh, length %d: translation not supported",
- rpt->code, rpt->len);
- }
+ "\nTSIP report packet ID %2Xh, length %d: translation not supported",
+ rpt->code, rpt->len);
+ }
if (parsed == BADDATA_PARSE)
- {
+ {
pbuf += sprintf(pbuf,
- "\nTSIP report packet ID %2Xh, length %d: data content incorrect",
- rpt->code, rpt->len);
- }
+ "\nTSIP report packet ID %2Xh, length %d: data content incorrect",
+ rpt->code, rpt->len);
+ }
for (i = 0; i < rpt->len; i++) {
if ((i % 20) == 0) *pbuf++ = '\n';
@@ -4766,96 +5150,101 @@ static void unknown_rpt (TSIPPKT *rpt)
}
}
/**/
+
/*
** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit()
*/
-void TranslateTSIPReportToText (TSIPPKT *rpt, char *TextOutputBuffer)
+void
+TranslateTSIPReportToText(
+ TSIPPKT *rpt,
+ char *TextOutputBuffer
+ )
{
/* pbuf is the pointer to the current location of the text output */
pbuf = TextOutputBuffer;
- /* keep track of whether the message has been successfully parsed */
+ /* keep track of whether the message has been successfully parsed */
parsed = GOOD_PARSE;
/* print a header if this is the first of a series of messages */
pbuf += print_msg_table_header (rpt->code, pbuf, FALSE);
- /* process incoming TSIP report according to code */
+ /* process incoming TSIP report according to code */
switch (rpt->code)
- {
- case 0x3D: rpt_chan_A_config (rpt); break;
- case 0x40: rpt_almanac_data_page (rpt); break;
- case 0x41: rpt_GPS_time (rpt); break;
- case 0x42: rpt_single_ECEF_position (rpt); break;
- case 0x43: rpt_single_ECEF_velocity (rpt); break;
- case 0x45: rpt_SW_version (rpt); break;
- case 0x46: rpt_rcvr_health (rpt); break;
- case 0x47: rpt_SNR_all_SVs (rpt); break;
- case 0x48: rpt_GPS_system_message (rpt); break;
- case 0x49: rpt_almanac_health_page (rpt); break;
- case 0x4A: switch (rpt->len) {
- /*
- ** special case (=slip-up) in the TSIP protocol;
- ** parsing method depends on length
- */
- case 20: rpt_single_lla_position (rpt); break;
- case 9: rpt_ref_alt (rpt); break;
+ {
+ case 0x3D: rpt_chan_A_config (rpt); break;
+ case 0x40: rpt_almanac_data_page (rpt); break;
+ case 0x41: rpt_GPS_time (rpt); break;
+ case 0x42: rpt_single_ECEF_position (rpt); break;
+ case 0x43: rpt_single_ECEF_velocity (rpt); break;
+ case 0x45: rpt_SW_version (rpt); break;
+ case 0x46: rpt_rcvr_health (rpt); break;
+ case 0x47: rpt_SNR_all_SVs (rpt); break;
+ case 0x48: rpt_GPS_system_message (rpt); break;
+ case 0x49: rpt_almanac_health_page (rpt); break;
+ case 0x4A: switch (rpt->len) {
+ /*
+ ** special case (=slip-up) in the TSIP protocol;
+ ** parsing method depends on length
+ */
+ case 20: rpt_single_lla_position (rpt); break;
+ case 9: rpt_ref_alt (rpt); break;
} break;
- case 0x4B: rpt_rcvr_id_and_status (rpt);break;
- case 0x4C: rpt_operating_parameters (rpt); break;
- case 0x4D: rpt_oscillator_offset (rpt); break;
- case 0x4E: rpt_GPS_time_set_response (rpt); break;
- case 0x4F: rpt_UTC_offset (rpt); break;
- case 0x54: rpt_1SV_bias (rpt); break;
- case 0x55: rpt_io_opt (rpt); break;
- case 0x56: rpt_ENU_velocity (rpt); break;
- case 0x57: rpt_last_fix_info (rpt); break;
- case 0x58: rpt_GPS_system_data (rpt); break;
- case 0x59: rpt_SVs_enabled (rpt); break;
- case 0x5A: rpt_raw_msmt (rpt); break;
- case 0x5B: rpt_SV_ephemeris_status (rpt); break;
- case 0x5C: rpt_SV_tracking_status (rpt); break;
- case 0x6D: rpt_allSV_selection (rpt); break;
- case 0x82: rpt_DGPS_position_mode (rpt); break;
- case 0x83: rpt_double_ECEF_position (rpt); break;
- case 0x84: rpt_double_lla_position (rpt); break;
- case 0xBB: rpt_complete_rcvr_config (rpt); break;
- case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
-
- case 0x8F: switch (rpt->buf[0])
- {
- /* superpackets; parsed according to subcodes */
- case 0x0B: rpt_8F0B(rpt); break;
- case 0x14: rpt_8F14(rpt); break;
- case 0x15: rpt_8F15(rpt); break;
- case 0x20: rpt_8F20(rpt); break;
- case 0x41: rpt_8F41(rpt); break;
- case 0x42: rpt_8F42(rpt); break;
- case 0x45: rpt_8F45(rpt); break;
- case 0x4A: rpt_8F4A(rpt); break;
- case 0x4B: rpt_8F4B(rpt); break;
- case 0x4D: rpt_8F4D(rpt); break;
- case 0xA5: rpt_8FA5(rpt); break;
- case 0xAD: rpt_8FAD(rpt); break;
- default: parsed = BADID_PARSE; break;
+ case 0x4B: rpt_rcvr_id_and_status (rpt);break;
+ case 0x4C: rpt_operating_parameters (rpt); break;
+ case 0x4D: rpt_oscillator_offset (rpt); break;
+ case 0x4E: rpt_GPS_time_set_response (rpt); break;
+ case 0x4F: rpt_UTC_offset (rpt); break;
+ case 0x54: rpt_1SV_bias (rpt); break;
+ case 0x55: rpt_io_opt (rpt); break;
+ case 0x56: rpt_ENU_velocity (rpt); break;
+ case 0x57: rpt_last_fix_info (rpt); break;
+ case 0x58: rpt_GPS_system_data (rpt); break;
+ case 0x59: rpt_SVs_enabled (rpt); break;
+ case 0x5A: rpt_raw_msmt (rpt); break;
+ case 0x5B: rpt_SV_ephemeris_status (rpt); break;
+ case 0x5C: rpt_SV_tracking_status (rpt); break;
+ case 0x6D: rpt_allSV_selection (rpt); break;
+ case 0x82: rpt_DGPS_position_mode (rpt); break;
+ case 0x83: rpt_double_ECEF_position (rpt); break;
+ case 0x84: rpt_double_lla_position (rpt); break;
+ case 0xBB: rpt_complete_rcvr_config (rpt); break;
+ case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
+
+ case 0x8F: switch (rpt->buf[0])
+ {
+ /* superpackets; parsed according to subcodes */
+ case 0x0B: rpt_8F0B(rpt); break;
+ case 0x14: rpt_8F14(rpt); break;
+ case 0x15: rpt_8F15(rpt); break;
+ case 0x20: rpt_8F20(rpt); break;
+ case 0x41: rpt_8F41(rpt); break;
+ case 0x42: rpt_8F42(rpt); break;
+ case 0x45: rpt_8F45(rpt); break;
+ case 0x4A: rpt_8F4A(rpt); break;
+ case 0x4B: rpt_8F4B(rpt); break;
+ case 0x4D: rpt_8F4D(rpt); break;
+ case 0xA5: rpt_8FA5(rpt); break;
+ case 0xAD: rpt_8FAD(rpt); break;
+ default: parsed = BADID_PARSE; break;
}
break;
- default: parsed = BADID_PARSE; break;
+ default: parsed = BADID_PARSE; break;
}
if (parsed != GOOD_PARSE)
{
- /*
- **The message has TSIP structure (DLEs, etc.)
- ** but could not be parsed by above routines
- */
+ /*
+ **The message has TSIP structure (DLEs, etc.)
+ ** but could not be parsed by above routines
+ */
unknown_rpt (rpt);
}
- /* close TextOutputBuffer */
- pbuf = '\0';
+ /* close TextOutputBuffer */
+ pbuf = '\0';
}
#endif /* TRIMBLE_OUTPUT_FUNC */
diff --git a/contrib/ntp/ntpd/refclock_shm.c b/contrib/ntp/ntpd/refclock_shm.c
index 7be263d..6ab5d02 100644
--- a/contrib/ntp/ntpd/refclock_shm.c
+++ b/contrib/ntp/ntpd/refclock_shm.c
@@ -1,5 +1,5 @@
/*
- * refclock_shm - clock driver for utc via shared memory
+ * refclock_shm - clock driver for utc via shared memory
* - under construction -
* To add new modes: Extend or union the shmTime-struct. Do not
* extend/shrink size, because otherwise existing implementations
@@ -11,21 +11,24 @@
# include <config.h>
#endif
+#include "ntp_types.h"
+
#if defined(REFCLOCK) && defined(CLOCK_SHM)
#include "ntpd.h"
-#undef fileno
+#undef fileno
#include "ntp_io.h"
-#undef fileno
+#undef fileno
#include "ntp_refclock.h"
-#undef fileno
-#include "ntp_unixtime.h"
-#undef fileno
+#undef fileno
+#include "timespecops.h"
+#undef fileno
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
-#undef fileno
+#undef fileno
#include <ctype.h>
-#undef fileno
+#undef fileno
#ifndef SYS_WINNT
# include <sys/ipc.h>
@@ -35,9 +38,13 @@
# include <stdio.h>
#endif
+#ifdef HAVE_STDATOMIC_H
+# include <stdatomic.h>
+#endif /* HAVE_STDATOMIC_H */
+
/*
* This driver supports a reference clock attached thru shared memory
- */
+ */
/*
* SHM interface definitions
@@ -49,11 +56,20 @@
#define NSAMPLES 3 /* stages of median filter */
/*
+ * Mode flags
+ */
+#define SHM_MODE_PRIVATE 0x0001
+
+/*
* Function prototypes
*/
-static int shm_start (int, struct peer *);
-static void shm_shutdown (int, struct peer *);
-static void shm_poll (int unit, struct peer *);
+static int shm_start (int unit, struct peer *peer);
+static void shm_shutdown (int unit, struct peer *peer);
+static void shm_poll (int unit, struct peer *peer);
+static void shm_timer (int unit, struct peer *peer);
+static void shm_clockstats (int unit, struct peer *peer);
+static void shm_control (int unit, const struct refclockstat * in_st,
+ struct refclockstat * out_st, struct peer *peer);
/*
* Transfer vector
@@ -61,98 +77,138 @@ static void shm_poll (int unit, struct peer *);
struct refclock refclock_shm = {
shm_start, /* start up driver */
shm_shutdown, /* shut down driver */
- shm_poll, /* transmit poll message */
- noentry, /* not used */
- noentry, /* initialize driver (not used) */
- noentry, /* not used */
- NOFLAGS /* not used */
+ shm_poll, /* transmit poll message */
+ shm_control, /* control settings */
+ noentry, /* not used: init */
+ noentry, /* not used: buginfo */
+ shm_timer, /* once per second */
};
+
struct shmTime {
- int mode; /* 0 - if valid set
- * use values,
+ int mode; /* 0 - if valid is set:
+ * use values,
* clear valid
- * 1 - if valid set
+ * 1 - if valid is set:
* if count before and after read of values is equal,
- * use values
+ * use values
* clear valid
*/
- int count;
- time_t clockTimeStampSec;
- int clockTimeStampUSec;
- time_t receiveTimeStampSec;
- int receiveTimeStampUSec;
- int leap;
- int precision;
- int nsamples;
- int valid;
- int dummy[10];
+ volatile int count;
+ time_t clockTimeStampSec;
+ int clockTimeStampUSec;
+ time_t receiveTimeStampSec;
+ int receiveTimeStampUSec;
+ int leap;
+ int precision;
+ int nsamples;
+ volatile int valid;
+ unsigned clockTimeStampNSec; /* Unsigned ns timestamps */
+ unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */
+ int dummy[8];
};
-struct shmTime *getShmTime(int);
+struct shmunit {
+ struct shmTime *shm; /* pointer to shared memory segment */
+ int forall; /* access for all UIDs? */
+
+ /* debugging/monitoring counters - reset when printed */
+ int ticks; /* number of attempts to read data*/
+ int good; /* number of valid samples */
+ int notready; /* number of peeks without data ready */
+ int bad; /* number of invalid samples */
+ int clash; /* number of access clashes while reading */
+
+ time_t max_delta; /* difference limit */
+ time_t max_delay; /* age/stale limit */
+};
+
+
+static struct shmTime*
+getShmTime(
+ int unit,
+ int/*BOOL*/ forall
+ )
+{
+ struct shmTime *p = NULL;
-struct shmTime *getShmTime (int unit) {
#ifndef SYS_WINNT
- int shmid=0;
- assert (unit<10); /* MAXUNIT is 4, so should never happen */
- shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
- IPC_CREAT|(unit<2?0700:0777));
- if (shmid==-1) { /*error */
- msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
- return 0;
+ int shmid;
+
+ /* 0x4e545030 is NTP0.
+ * Big units will give non-ascii but that's OK
+ * as long as everybody does it the same way.
+ */
+ shmid=shmget(0x4e545030 + unit, sizeof (struct shmTime),
+ IPC_CREAT | (forall ? 0666 : 0600));
+ if (shmid == -1) { /* error */
+ msyslog(LOG_ERR, "SHM shmget (unit %d): %m", unit);
+ return NULL;
}
- else { /* no error */
- struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
- if ((int)(long)p==-1) { /* error */
- msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno));
- return 0;
- }
- return p;
+ p = (struct shmTime *)shmat (shmid, 0, 0);
+ if (p == (struct shmTime *)-1) { /* error */
+ msyslog(LOG_ERR, "SHM shmat (unit %d): %m", unit);
+ return NULL;
}
+
+ return p;
#else
- char buf[10];
- LPSECURITY_ATTRIBUTES psec=0;
- HANDLE shmid=0;
+
+ static const char * nspref[2] = { "Local", "Global" };
+ char buf[20];
+ LPSECURITY_ATTRIBUTES psec = 0;
+ HANDLE shmid = 0;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
- sprintf (buf,"NTP%d",unit);
- if (unit>=2) { /* world access */
+ unsigned int numch;
+
+ numch = snprintf(buf, sizeof(buf), "%s\\NTP%d",
+ nspref[forall != 0], (unit & 0xFF));
+ if (numch >= sizeof(buf)) {
+ msyslog(LOG_ERR, "SHM name too long (unit %d)", unit);
+ return NULL;
+ }
+ if (forall) { /* world access */
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
- msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit);
- return 0;
+ msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m", unit);
+ return NULL;
}
- if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
- msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
- return 0;
+ if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) {
+ msyslog(LOG_ERR, "SHM SetSecurityDescriptorDacl (unit %d): %m", unit);
+ return NULL;
}
- sa.nLength=sizeof (SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor=&sd;
- sa.bInheritHandle=0;
- psec=&sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = &sd;
+ sa.bInheritHandle = FALSE;
+ psec = &sa;
}
- shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
- 0, sizeof (struct shmTime),buf);
- if (!shmid) { /*error*/
- char buf[1000];
+ shmid = CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
+ 0, sizeof (struct shmTime), buf);
+ if (shmid == NULL) { /*error*/
+ char buf[1000];
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
0, GetLastError (), 0, buf, sizeof (buf), 0);
- msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf);
- return 0;
+ msyslog(LOG_ERR, "SHM CreateFileMapping (unit %d): %s", unit, buf);
+ return NULL;
}
- else {
- struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
- FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
- if (p==0) { /*error*/
- char buf[1000];
- FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
- 0, GetLastError (), 0, buf, sizeof (buf), 0);
- msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf);
- return 0;
- }
- return p;
+ p = (struct shmTime *)MapViewOfFile(shmid, FILE_MAP_WRITE, 0, 0,
+ sizeof (struct shmTime));
+ if (p == NULL) { /*error*/
+ char buf[1000];
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, GetLastError (), 0, buf, sizeof (buf), 0);
+ msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s", unit, buf);
+ return NULL;
}
+
+ return p;
#endif
+
+ /* NOTREACHED */
+ ENSURE(!"getShmTime(): Not reached.");
}
+
+
/*
* shm_start - attach to shared memory
*/
@@ -162,33 +218,74 @@ shm_start(
struct peer *peer
)
{
- struct refclockproc *pp;
- pp = peer->procptr;
+ struct refclockproc * const pp = peer->procptr;
+ struct shmunit * const up = emalloc_zero(sizeof(*up));
+
pp->io.clock_recv = noentry;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = -1;
- pp->unitptr = (caddr_t)getShmTime(unit);
+
+ up->forall = (unit >= 2) && !(peer->ttl & SHM_MODE_PRIVATE);
+
+ up->shm = getShmTime(unit, up->forall);
/*
* Initialize miscellaneous peer variables
*/
memcpy((char *)&pp->refid, REFID, 4);
- if (pp->unitptr!=0) {
- ((struct shmTime*)pp->unitptr)->precision=PRECISION;
- peer->precision = ((struct shmTime*)pp->unitptr)->precision;
- ((struct shmTime*)pp->unitptr)->valid=0;
- ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES;
+ if (up->shm != 0) {
+ pp->unitptr = up;
+ up->shm->precision = PRECISION;
+ peer->precision = up->shm->precision;
+ up->shm->valid = 0;
+ up->shm->nsamples = NSAMPLES;
pp->clockdesc = DESCRIPTION;
- return (1);
- }
- else {
+ /* items to be changed later in 'shm_control()': */
+ up->max_delay = 5;
+ up->max_delta = 4*3600;
+ return 1;
+ } else {
+ free(up);
+ pp->unitptr = NULL;
return 0;
}
}
/*
+ * shm_control - configure flag1/time2 params
+ *
+ * These are not yet available during 'shm_start', so we have to do any
+ * pre-computations we want to avoid during regular poll/timer callbacks
+ * in this callback.
+ */
+static void
+shm_control(
+ int unit,
+ const struct refclockstat * in_st,
+ struct refclockstat * out_st,
+ struct peer * peer
+ )
+{
+ struct refclockproc * const pp = peer->procptr;
+ struct shmunit * const up = pp->unitptr;
+
+ UNUSED_ARG(unit);
+ UNUSED_ARG(in_st);
+ UNUSED_ARG(out_st);
+ if (NULL == up)
+ return;
+ if (pp->sloppyclockflag & CLK_FLAG1)
+ up->max_delta = 0;
+ else if (pp->fudgetime2 < 1. || pp->fudgetime2 > 86400.)
+ up->max_delta = 4*3600;
+ else
+ up->max_delta = (time_t)floor(pp->fudgetime2 + 0.5);
+}
+
+
+/*
* shm_shutdown - shut down the clock
*/
static void
@@ -197,17 +294,23 @@ shm_shutdown(
struct peer *peer
)
{
- register struct shmTime *up;
- struct refclockproc *pp;
+ struct refclockproc * const pp = peer->procptr;
+ struct shmunit * const up = pp->unitptr;
- pp = peer->procptr;
- up = (struct shmTime *)pp->unitptr;
+ UNUSED_ARG(unit);
+ if (NULL == up)
+ return;
#ifndef SYS_WINNT
- /* HMS: shmdt()wants char* or const void * */
- (void) shmdt (up);
+
+ /* HMS: shmdt() wants char* or const void * */
+ (void)shmdt((char *)up->shm);
+
#else
- UnmapViewOfFile (up);
+
+ UnmapViewOfFile(up->shm);
+
#endif
+ free(up);
}
@@ -220,93 +323,340 @@ shm_poll(
struct peer *peer
)
{
- register struct shmTime *up;
- struct refclockproc *pp;
+ struct refclockproc * const pp = peer->procptr;
+ struct shmunit * const up = pp->unitptr;
+ int major_error;
- /*
- * This is the main routine. It snatches the time from the shm
- * board and tacks on a local timestamp.
- */
- pp = peer->procptr;
- up = (struct shmTime*)pp->unitptr;
- if (up==0) { /* try to map again - this may succeed if meanwhile some-
- body has ipcrm'ed the old (unaccessible) shared mem
- segment */
- pp->unitptr = (caddr_t)getShmTime(unit);
- up = (struct shmTime*)pp->unitptr;
- }
- if (up==0) {
+ pp->polls++;
+
+ /* get dominant reason if we have no samples at all */
+ major_error = max(up->notready, up->bad);
+ major_error = max(major_error, up->clash);
+
+ /*
+ * Process median filter samples. If none received, see what
+ * happened, tell the core and keep going.
+ */
+ if (pp->coderecv != pp->codeproc) {
+ /* have some samples, everything OK */
+ pp->lastref = pp->lastrec;
+ refclock_receive(peer);
+ } else if (NULL == up->shm) { /* is this possible at all? */
+ /* we're out of business without SHM access */
refclock_report(peer, CEVNT_FAULT);
- return;
+ } else if (major_error == up->clash) {
+ /* too many collisions is like a bad signal */
+ refclock_report(peer, CEVNT_PROP);
+ } else if (major_error == up->bad) {
+ /* too much stale/bad/garbled data */
+ refclock_report(peer, CEVNT_BADREPLY);
+ } else {
+ /* in any other case assume it's just a timeout */
+ refclock_report(peer, CEVNT_TIMEOUT);
+ }
+ /* shm_clockstats() clears the tallies, so it must be last... */
+ shm_clockstats(unit, peer);
+}
+
+
+enum segstat_t {
+ OK, NO_SEGMENT, NOT_READY, BAD_MODE, CLASH
+};
+
+struct shm_stat_t {
+ int status;
+ int mode;
+ struct timespec tvc, tvr, tvt;
+ int precision;
+ int leap;
+};
+
+static inline void memory_barrier(void)
+{
+#ifdef HAVE_ATOMIC_THREAD_FENCE
+ atomic_thread_fence(memory_order_seq_cst);
+#endif /* HAVE_ATOMIC_THREAD_FENCE */
+}
+
+static enum segstat_t shm_query(volatile struct shmTime *shm_in, struct shm_stat_t *shm_stat)
+/* try to grab a sample from the specified SHM segment */
+{
+ volatile struct shmTime shmcopy, *shm = shm_in;
+ volatile int cnt;
+
+ unsigned int cns_new, rns_new;
+
+ /*
+ * This is the main routine. It snatches the time from the shm
+ * board and tacks on a local timestamp.
+ */
+ if (shm == NULL) {
+ shm_stat->status = NO_SEGMENT;
+ return NO_SEGMENT;
+ }
+
+ /*@-type@*//* splint is confused about struct timespec */
+ shm_stat->tvc.tv_sec = shm_stat->tvc.tv_nsec = 0;
+ {
+ time_t now;
+
+ time(&now);
+ shm_stat->tvc.tv_sec = now;
+ }
+
+ /* relying on word access to be atomic here */
+ if (shm->valid == 0) {
+ shm_stat->status = NOT_READY;
+ return NOT_READY;
+ }
+
+ cnt = shm->count;
+
+ /*
+ * This is proof against concurrency issues if either
+ * (a) the memory_barrier() call works on this host, or
+ * (b) memset compiles to an uninterruptible single-instruction bitblt.
+ */
+ memory_barrier();
+ memcpy((void *)&shmcopy, (void *)shm, sizeof(struct shmTime));
+ shm->valid = 0;
+ memory_barrier();
+
+ /*
+ * Clash detection in case neither (a) nor (b) was true.
+ * Not supported in mode 0, and word access to the count field
+ * must be atomic for this to work.
+ */
+ if (shmcopy.mode > 0 && cnt != shm->count) {
+ shm_stat->status = CLASH;
+ return shm_stat->status;
+ }
+
+ shm_stat->status = OK;
+ shm_stat->mode = shmcopy.mode;
+
+ switch (shmcopy.mode) {
+ case 0:
+ shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec;
+ shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000;
+ rns_new = shmcopy.receiveTimeStampNSec;
+ shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec;
+ shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000;
+ cns_new = shmcopy.clockTimeStampNSec;
+
+ /* Since the following comparisons are between unsigned
+ ** variables they are always well defined, and any
+ ** (signed) underflow will turn into very large unsigned
+ ** values, well above the 1000 cutoff.
+ **
+ ** Note: The usecs *must* be a *truncated*
+ ** representation of the nsecs. This code will fail for
+ ** *rounded* usecs, and the logic to deal with
+ ** wrap-arounds in the presence of rounded values is
+ ** much more convoluted.
+ */
+ if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000)
+ && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) {
+ shm_stat->tvt.tv_nsec = cns_new;
+ shm_stat->tvr.tv_nsec = rns_new;
}
- if (up->valid) {
- struct timeval tvr;
- struct timeval tvt;
- struct tm *t;
- int ok=1;
- tvr.tv_sec = 0;
- tvr.tv_usec = 0;
- tvt.tv_sec = 0;
- tvt.tv_usec = 0;
- switch (up->mode) {
- case 0: {
- tvr.tv_sec=up->receiveTimeStampSec;
- tvr.tv_usec=up->receiveTimeStampUSec;
- tvt.tv_sec=up->clockTimeStampSec;
- tvt.tv_usec=up->clockTimeStampUSec;
- }
- break;
- case 1: {
- int cnt=up->count;
- tvr.tv_sec=up->receiveTimeStampSec;
- tvr.tv_usec=up->receiveTimeStampUSec;
- tvt.tv_sec=up->clockTimeStampSec;
- tvt.tv_usec=up->clockTimeStampUSec;
- ok=(cnt==up->count);
- }
- break;
- default:
- msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode);
- }
- up->valid=0;
- if (ok) {
- time_t help; /* XXX NetBSD has incompatible tv_sec */
-
- TVTOTS(&tvr,&pp->lastrec);
- pp->lastrec.l_ui += JAN_1970;
- /* pp->lasttime = current_time; */
- pp->polls++;
- help = tvt.tv_sec;
- t = gmtime (&help);
- pp->day=t->tm_yday+1;
- pp->hour=t->tm_hour;
- pp->minute=t->tm_min;
- pp->second=t->tm_sec;
- pp->nsec=tvt.tv_usec * 1000;
- peer->precision=up->precision;
- pp->leap=up->leap;
- }
- else {
- refclock_report(peer, CEVNT_FAULT);
- msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
+ /* At this point shm_stat->tvr and shm_stat->tvt contain valid ns-level
+ ** timestamps, possibly generated by extending the old
+ ** us-level timestamps
+ */
+ break;
+
+ case 1:
+
+ shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec;
+ shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000;
+ rns_new = shmcopy.receiveTimeStampNSec;
+ shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec;
+ shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000;
+ cns_new = shmcopy.clockTimeStampNSec;
+
+ /* See the case above for an explanation of the
+ ** following test.
+ */
+ if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000)
+ && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) {
+ shm_stat->tvt.tv_nsec = cns_new;
+ shm_stat->tvr.tv_nsec = rns_new;
+ }
+ /* At this point shm_stat->tvr and shm_stat->tvt contains valid ns-level
+ ** timestamps, possibly generated by extending the old
+ ** us-level timestamps
+ */
+ break;
+
+ default:
+ shm_stat->status = BAD_MODE;
+ break;
+ }
+ /*@-type@*/
+
+ /*
+ * leap field is not a leap offset but a leap notification code.
+ * The values are magic numbers used by NTP and set by GPSD, if at all, in
+ * the subframe code.
+ */
+ shm_stat->leap = shmcopy.leap;
+ shm_stat->precision = shmcopy.precision;
+
+ return shm_stat->status;
+}
+
+/*
+ * shm_timer - called once every second.
+ *
+ * This tries to grab a sample from the SHM segment, filtering bad ones
+ */
+static void
+shm_timer(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct refclockproc * const pp = peer->procptr;
+ struct shmunit * const up = pp->unitptr;
+
+ volatile struct shmTime *shm;
+
+ l_fp tsrcv;
+ l_fp tsref;
+ int c;
+
+ /* for formatting 'a_lastcode': */
+ struct calendar cd;
+ time_t tt;
+ vint64 ts;
+
+ enum segstat_t status;
+ struct shm_stat_t shm_stat;
+
+ up->ticks++;
+ if ((shm = up->shm) == NULL) {
+ /* try to map again - this may succeed if meanwhile some-
+ body has ipcrm'ed the old (unaccessible) shared mem segment */
+ shm = up->shm = getShmTime(unit, up->forall);
+ if (shm == NULL) {
+ DPRINTF(1, ("%s: no SHM segment\n",
+ refnumtoa(&peer->srcadr)));
return;
}
}
- else {
- refclock_report(peer, CEVNT_TIMEOUT);
- /*
- msyslog (LOG_NOTICE, "SHM: no new value found in shared memory");
- */
+
+ /* query the segment, atomically */
+ status = shm_query(shm, &shm_stat);
+
+ switch (status) {
+ case OK:
+ DPRINTF(2, ("%s: SHM type %d sample\n",
+ refnumtoa(&peer->srcadr), shm_stat.mode));
+ break;
+ case NO_SEGMENT:
+ /* should never happen, but is harmless */
+ return;
+ case NOT_READY:
+ DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr)));
+ up->notready++;
+ return;
+ case BAD_MODE:
+ DPRINTF(1, ("%s: SHM type blooper, mode=%d\n",
+ refnumtoa(&peer->srcadr), shm->mode));
+ up->bad++;
+ msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",
+ shm->mode);
+ return;
+ case CLASH:
+ DPRINTF(1, ("%s: type 1 access clash\n",
+ refnumtoa(&peer->srcadr)));
+ msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
+ up->clash++;
+ return;
+ default:
+ DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n",
+ refnumtoa(&peer->srcadr)));
+ msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status");
+ up->bad++;
+ return;
+ }
+
+
+ /* format the last time code in human-readable form into
+ * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible
+ * tv_sec". I can't find a base for this claim, but we can work
+ * around that potential problem. BTW, simply casting a pointer
+ * is a receipe for disaster on some architectures.
+ */
+ tt = (time_t)shm_stat.tvt.tv_sec;
+ ts = time_to_vint64(&tt);
+ ntpcal_time_to_date(&cd, &ts);
+
+ /* add ntpq -c cv timecode in ISO 8601 format */
+ c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ",
+ cd.year, cd.month, cd.monthday,
+ cd.hour, cd.minute, cd.second,
+ (long)shm_stat.tvt.tv_nsec);
+ pp->lencode = (c < sizeof(pp->a_lastcode)) ? c : 0;
+
+ /* check 1: age control of local time stamp */
+ tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec;
+ if (tt < 0 || tt > up->max_delay) {
+ DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n",
+ refnumtoa(&peer->srcadr), (long long)tt));
+ up->bad++;
+ msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds",
+ (long long)tt);
return;
}
- if (!refclock_process(pp)) {
- refclock_report(peer, CEVNT_BADTIME);
+
+ /* check 2: delta check */
+ tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec);
+ if (tt < 0)
+ tt = -tt;
+ if (up->max_delta > 0 && tt > up->max_delta) {
+ DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n",
+ refnumtoa(&peer->srcadr), (long long)tt));
+ up->bad++;
+ msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n",
+ (long long)tt);
return;
}
- pp->lastref = pp->lastrec;
- refclock_receive(peer);
+
+ /* if we really made it to this point... we're winners! */
+ DPRINTF(2, ("%s: SHM feeding data\n",
+ refnumtoa(&peer->srcadr)));
+ tsrcv = tspec_stamp_to_lfp(shm_stat.tvr);
+ tsref = tspec_stamp_to_lfp(shm_stat.tvt);
+ pp->leap = shm_stat.leap;
+ peer->precision = shm_stat.precision;
+ refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1);
+ up->good++;
+}
+
+/*
+ * shm_clockstats - dump and reset counters
+ */
+static void shm_clockstats(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct refclockproc * const pp = peer->procptr;
+ struct shmunit * const up = pp->unitptr;
+
+ UNUSED_ARG(unit);
+ if (pp->sloppyclockflag & CLK_FLAG4) {
+ mprintf_clock_stats(
+ &peer->srcadr, "%3d %3d %3d %3d %3d",
+ up->ticks, up->good, up->notready,
+ up->bad, up->clash);
+ }
+ up->ticks = up->good = up->notready = up->bad = up->clash = 0;
}
#else
-int refclock_shm_bs;
+NONEMPTY_TRANSLATION_UNIT
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_tpro.c b/contrib/ntp/ntpd/refclock_tpro.c
index 3c42568..ac511bb 100644
--- a/contrib/ntp/ntpd/refclock_tpro.c
+++ b/contrib/ntp/ntpd/refclock_tpro.c
@@ -42,9 +42,9 @@ struct tprounit {
/*
* Function prototypes
*/
-static int tpro_start P((int, struct peer *));
-static void tpro_shutdown P((int, struct peer *));
-static void tpro_poll P((int unit, struct peer *));
+static int tpro_start (int, struct peer *);
+static void tpro_shutdown (int, struct peer *);
+static void tpro_poll (int unit, struct peer *);
/*
* Transfer vector
@@ -77,7 +77,7 @@ tpro_start(
/*
* Open TPRO device
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
fd = open(device, O_RDONLY | O_NDELAY, 0777);
if (fd == -1) {
msyslog(LOG_ERR, "tpro_start: open of %s: %m", device);
@@ -87,23 +87,18 @@ tpro_start(
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct tprounit *) emalloc(sizeof(struct tprounit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct tprounit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = noentry;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous peer variables
*/
peer->precision = PRECISION;
- peer->burst = NSTAGE;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, REFID, 4);
return (1);
@@ -123,9 +118,10 @@ tpro_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct tprounit *)pp->unitptr;
+ up = pp->unitptr;
io_closeclock(&pp->io);
- free(up);
+ if (NULL != up)
+ free(up);
}
@@ -147,7 +143,7 @@ tpro_poll(
* board and tacks on a local timestamp.
*/
pp = peer->procptr;
- up = (struct tprounit *)pp->unitptr;
+ up = pp->unitptr;
tp = &up->tprodata;
if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) {
@@ -163,20 +159,20 @@ tpro_poll(
* proper format, we declare bad format and exit. Note: we
* can't use the sec/usec conversion produced by the driver,
* since the year may be suspect. All format error checking is
- * done by the sprintf() and sscanf() routines.
+ * done by the snprintf() and sscanf() routines.
*
* Note that the refclockproc usec member has now become nsec.
* We could either multiply the read-in usec value by 1000 or
* we could pad the written string appropriately and read the
* resulting value in already scaled.
*/
- sprintf(pp->a_lastcode,
- "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
- tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1,
- tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100,
- tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1,
- tp->status);
- pp->lencode = strlen(pp->a_lastcode);
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
+ tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1,
+ tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100,
+ tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1,
+ tp->status);
+ pp->lencode = strlen(pp->a_lastcode);
#ifdef DEBUG
if (debug)
printf("tpro: time %s timecode %d %s\n",
@@ -198,17 +194,13 @@ tpro_poll(
refclock_report(peer, CEVNT_BADTIME);
return;
}
- if (peer->burst > 0)
- return;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
}
- refclock_receive(peer);
pp->lastref = pp->lastrec;
record_clock_stats(&peer->srcadr, pp->a_lastcode);
refclock_receive(peer);
- peer->burst = NSTAGE;
}
#else
diff --git a/contrib/ntp/ntpd/refclock_trak.c b/contrib/ntp/ntpd/refclock_trak.c
deleted file mode 100644
index 3a4a54e..0000000
--- a/contrib/ntp/ntpd/refclock_trak.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * refclock_trak - clock driver for the TRAK 8810 GPS Station Clock
- *
- * Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp>
- * original version Dec, 1993
- * revised version Sep, 1994 for ntp3.4e or later
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#if defined(REFCLOCK) && defined(CLOCK_TRAK) && defined(PPS)
-
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_refclock.h"
-#include "ntp_stdlib.h"
-#include "ntp_unixtime.h"
-
-#include <stdio.h>
-#include <ctype.h>
-
-#ifdef HAVE_SYS_TERMIOS_H
-# include <sys/termios.h>
-#endif
-#ifdef HAVE_SYS_PPSCLOCK_H
-# include <sys/ppsclock.h>
-#endif
-
-/*
- * This driver supports the TRAK 8810/8820 GPS Station Clock. The claimed
- * accuracy at the 1-pps output is 200-300 ns relative to the broadcast
- * signal; however, in most cases the actual accuracy is limited by the
- * precision of the timecode and the latencies of the serial interface
- * and operating system.
- *
- * For best accuracy, this radio requires the LDISC_ACTS line
- * discipline, which captures a timestamp at the '*' on-time character
- * of the timecode. Using this discipline the jitter is in the order of
- * 1 ms and systematic error about 0.5 ms. If unavailable, the buffer
- * timestamp is used, which is captured at the \r ending the timecode
- * message. This introduces a systematic error of 23 character times, or
- * about 24 ms at 9600 bps, together with a jitter well over 8 ms on Sun
- * IPC-class machines.
- *
- * Using the memus, the radio should be set for 9600 bps, one stop bit
- * and no parity. It should be set to operate in computer (no echo)
- * mode. The timecode format includes neither the year nor leap-second
- * warning. No provisions are included in this preliminary version of
- * the driver to read and record detailed internal radio status.
- *
- * In operation, this driver sends a RQTS\r request to the radio at
- * initialization in order to put it in continuous time output mode. The
- * radio then sends the following message once each second:
- *
- * *RQTS U,ddd:hh:mm:ss.0,q<cr><lf>
- *
- * on-time = '*' * ddd = day of year
- * hh:mm:ss = hours, minutes, seconds
- * q = quality indicator (phase error), 0-6:
- * 0 > 20 us
- * 6 > 10 us
- * 5 > 1 us
- * 4 > 100 ns
- * 3 > 10 ns
- * 2 < 10 ns
- *
- * The alarm condition is indicated by '0' at Q, which means the radio
- * has a phase error than 20 usec relative to the broadcast time. The
- * absence of year, DST and leap-second warning in this format is also
- * alarming.
- *
- * The continuous time mode is disabled using the RQTX<cr> request,
- * following which the radio sends a RQTX DONE<cr><lf> response. In the
- * normal mode, other control and status requests are effective,
- * including the leap-second status request RQLS<cr>. The radio responds
- * wtih RQLS yy,mm,dd<cr><lf>, where yy,mm,dd are the year, month and
- * day. Presumably, this gives the epoch of the next leap second,
- * RQLS 00,00,00 if none is specified in the GPS message. Specified in
- * this form, the information is generally useless and is ignored by
- * the driver.
- *
- * Fudge Factors
- *
- * There are no special fudge factors other than the generic.
- */
-
-/*
- * Interface definitions
- */
-#define DEVICE "/dev/trak%d" /* device name and unit */
-#define SPEED232 B9600 /* uart speed (9600 baud) */
-#define PRECISION (-20) /* precision assumed (about 1 us) */
-#define REFID "GPS\0" /* reference ID */
-#define DESCRIPTION "TRACK 8810/8820 Station Clock" /* WRU */
-
-#define LENTRAK 24 /* timecode length */
-#define C_CTO "RQTS\r" /* start continuous time output */
-
-/*
- * Unit control structure
- */
-struct trakunit {
- int polled; /* poll message flag */
- l_fp tstamp; /* timestamp of last poll */
-};
-
-/*
- * Function prototypes
- */
-static int trak_start P((int, struct peer *));
-static void trak_shutdown P((int, struct peer *));
-static void trak_receive P((struct recvbuf *));
-static void trak_poll P((int, struct peer *));
-
-/*
- * Transfer vector
- */
-struct refclock refclock_trak = {
- trak_start, /* start up driver */
- trak_shutdown, /* shut down driver */
- trak_poll, /* transmit poll message */
- noentry, /* not used (old trak_control) */
- noentry, /* initialize driver (not used) */
- noentry, /* not used (old trak_buginfo) */
- NOFLAGS /* not used */
-};
-
-
-/*
- * trak_start - open the devices and initialize data for processing
- */
-static int
-trak_start(
- int unit,
- struct peer *peer
- )
-{
- register struct trakunit *up;
- struct refclockproc *pp;
- int fd;
- char device[20];
-
- /*
- * Open serial port. The LDISC_ACTS line discipline inserts a
- * timestamp following the "*" on-time character of the
- * timecode.
- */
- (void)sprintf(device, DEVICE, unit);
- if (
-#ifdef PPS
- !(fd = refclock_open(device, SPEED232, LDISC_CLK))
-#else
- !(fd = refclock_open(device, SPEED232, 0))
-#endif /* PPS */
- )
- return (0);
-
- /*
- * Allocate and initialize unit structure
- */
- if (!(up = (struct trakunit *)
- emalloc(sizeof(struct trakunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct trakunit));
- pp = peer->procptr;
- pp->io.clock_recv = trak_receive;
- pp->io.srcclock = (caddr_t)peer;
- pp->io.datalen = 0;
- pp->io.fd = fd;
- if (!io_addclock(&pp->io)) {
- (void) close(fd);
- free(up);
- return (0);
- }
- pp->unitptr = (caddr_t)up;
-
- /*
- * Initialize miscellaneous variables
- */
- peer->precision = PRECISION;
- pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
- up->polled = 0;
-
- /*
- * Start continuous time output. If something breaks, fold the
- * tent and go home.
- */
- if (write(pp->io.fd, C_CTO, sizeof(C_CTO)) != sizeof(C_CTO)) {
- refclock_report(peer, CEVNT_FAULT);
- (void) close(fd);
- free(up);
- return (0);
- }
- return (1);
-}
-
-
-/*
- * trak_shutdown - shut down the clock
- */
-static void
-trak_shutdown(
- int unit,
- struct peer *peer
- )
-{
- register struct trakunit *up;
- struct refclockproc *pp;
-
- pp = peer->procptr;
- up = (struct trakunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
-}
-
-
-/*
- * trak_receive - receive data from the serial interface
- */
-static void
-trak_receive(
- struct recvbuf *rbufp
- )
-{
- register struct trakunit *up;
- struct refclockproc *pp;
- struct peer *peer;
- l_fp trtmp;
- char *dpt, *dpend;
- char qchar;
-#ifdef PPS
- struct ppsclockev ppsev;
- int request;
-#ifdef HAVE_CIOGETEV
- request = CIOGETEV;
-#endif
-#ifdef HAVE_TIOCGPPSEV
- request = TIOCGPPSEV;
-#endif
-#endif /* PPS */
-
- /*
- * Initialize pointers and read the timecode and timestamp. We
- * then chuck out everything, including runts, except one
- * message each poll interval.
- */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct trakunit *)pp->unitptr;
- pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX,
- &pp->lastrec);
-
- /*
- * We get a buffer and timestamp following the '*' on-time
- * character. If a valid timestamp, we use that in place of the
- * buffer timestamp and edit out the timestamp for prettyprint
- * billboards.
- */
- dpt = pp->a_lastcode;
- dpend = dpt + pp->lencode;
- if (*dpt == '*' && buftvtots(dpt + 1, &trtmp)) {
- if (trtmp.l_i == pp->lastrec.l_i || trtmp.l_i ==
- pp->lastrec.l_i + 1) {
- pp->lastrec = trtmp;
- dpt += 9;
- while (dpt < dpend) {
- *(dpt - 8) = *dpt;
- ++dpt;
- }
- }
- }
- if (up->polled == 0) return;
- up->polled = 0;
-#ifndef PPS
- get_systime(&up->tstamp);
-#endif
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
-#ifdef DEBUG
- if (debug)
- printf("trak: timecode %d %s\n", pp->lencode,
- pp->a_lastcode);
-#endif
-
- /*
- * We get down to business, check the timecode format and decode
- * its contents. If the timecode has invalid length or is not in
- * proper format, we declare bad format and exit.
- */
- if (pp->lencode < LENTRAK) {
- refclock_report(peer, CEVNT_BADREPLY);
- return;
- }
-
- /*
- * Timecode format: "*RQTS U,ddd:hh:mm:ss.0,q"
- */
- if (sscanf(pp->a_lastcode, "*RQTS U,%3d:%2d:%2d:%2d.0,%c",
- &pp->day, &pp->hour, &pp->minute, &pp->second, &qchar) != 5) {
- refclock_report(peer, CEVNT_BADREPLY);
- return;
- }
-
- /*
- * Decode quality and leap characters. If unsynchronized, set
- * the leap bits accordingly and exit.
- */
- if (qchar == '0') {
- pp->leap = LEAP_NOTINSYNC;
- return;
- }
-#ifdef PPS
- if(ioctl(fdpps,request,(caddr_t) &ppsev) >=0) {
- ppsev.tv.tv_sec += (u_int32) JAN_1970;
- TVTOTS(&ppsev.tv,&up->tstamp);
- }
-#endif /* PPS */
- /* record the last ppsclock event time stamp */
- pp->lastrec = up->tstamp;
- if (!refclock_process(pp)) {
- refclock_report(peer, CEVNT_BADTIME);
- return;
- }
- pp->lastref = pp->lastrec;
- refclock_receive(peer);
-}
-
-
-/*
- * trak_poll - called by the transmit procedure
- */
-static void
-trak_poll(
- int unit,
- struct peer *peer
- )
-{
- register struct trakunit *up;
- struct refclockproc *pp;
-
- /*
- * We don't really do anything here, except arm the receiving
- * side to capture a sample and check for timeouts.
- */
- pp = peer->procptr;
- up = (struct trakunit *)pp->unitptr;
- if (up->polled)
- refclock_report(peer, CEVNT_TIMEOUT);
- pp->polls++;
- up->polled = 1;
-}
-
-#else
-int refclock_trak_bs;
-#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_true.c b/contrib/ntp/ntpd/refclock_true.c
index dd355d9..67ba6df 100644
--- a/contrib/ntp/ntpd/refclock_true.c
+++ b/contrib/ntp/ntpd/refclock_true.c
@@ -1,9 +1,8 @@
/*
- * refclock_true - clock driver for the Kinemetrics Truetime receivers
+ * refclock_true - clock driver for the Kinemetrics/TrueTime receivers
* Receiver Version 3.0C - tested plain, with CLKLDISC
- * Developement work being done:
- * - Properly handle varying satellite positions (more acurately)
- * - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers
+ * Development work being done:
+ * - Support TL-3 WWV TOD receiver
*/
#ifdef HAVE_CONFIG_H
@@ -12,14 +11,20 @@
#if defined(REFCLOCK) && defined(CLOCK_TRUETIME)
+#include <stdio.h>
+#include <ctype.h>
+
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
-#include <stdio.h>
-#include <ctype.h>
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets) async_write(fd, data, octets)
+#endif
/* This should be an atom clock but those are very hard to build.
*
@@ -44,10 +49,11 @@
/*
* Support for Kinemetrics Truetime Receivers
- * GOES
- * GPS/TM-TMD
- * XL-DC (a 151-602-210, reported by the driver as a GPS/TM-TMD)
- * GPS-800 TCU (an 805-957 with the RS232 Talker/Listener module)
+ * GOES: (468-DC, usable with GPS->GOES converting antenna)
+ * GPS/TM-TMD:
+ * XL-DC: (a 151-602-210, reported by the driver as a GPS/TM-TMD)
+ * GPS-800 TCU: (an 805-957 with the RS232 Talker/Listener module)
+ * TL-3: 3 channel WWV/H receiver w/ IRIG and RS-232 outputs
* OM-DC: getting stale ("OMEGA")
*
* Most of this code is originally from refclock_wwvb.c with thanks.
@@ -65,15 +71,18 @@
* ? +/- 1 milliseconds # +/- 100 microseconds
* * +/- 10 microseconds . +/- 1 microsecond
* space less than 1 microsecond
+ * TL-3 Receiver: (default quality codes for TL-3)
+ * ? unknown quality (receiver is unlocked)
+ * space +/- 5 milliseconds
* OM-DC OMEGA Receiver: (default quality codes for OMEGA)
* WARNING OMEGA navigation system is no longer existent
* > >+- 5 seconds
* ? >+/- 500 milliseconds # >+/- 50 milliseconds
* * >+/- 5 milliseconds . >+/- 1 millisecond
* A-H less than 1 millisecond. Character indicates which station
- * is being received as follows:
- * A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
- * E = La Reunion, F = Argentina, G = Australia, H = Japan.
+ * is being received as follows:
+ * A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
+ * E = La Reunion, F = Argentina, G = Australia, H = Japan.
*
* The carriage return start bit begins on 0 seconds and extends to 1 bit time.
*
@@ -97,16 +106,27 @@
* This corrects the 4 milliseconds advance and 8 milliseconds retard
* needed. The software will ask the clock which satellite it sees.
*
- * Ntp.conf parameters:
- * time1 - offset applied to samples when reading WEST satellite (default = 0)
- * time2 - offset applied to samples when reading EAST satellite (default = 0)
- * val1 - stratum to assign to this clock (default = 0)
- * val2 - refid assigned to this clock (default = "TRUE", see below)
- * flag1 - will silence the clock side of ntpd, just reading the clock
- * without trying to write to it. (default = 0)
- * flag2 - generate a debug file /tmp/true%d.
- * flag3 - enable ppsclock streams module
- * flag4 - use the PCL-720 (BSD/OS only)
+ * Notes on the TrueTime TimeLink TL-3 WWV TOD receiver:
+ *
+ * This clock may be polled, or send one timecode per second.
+ * That mode may be toggled via the front panel ("C" mode), or controlled
+ * from the RS-232 port. Send the receiver "ST1" to turn it on, and
+ * "ST0" to turn it off. Send "QV" to get the firmware revision (useful
+ * for identifying this model.)
+ *
+ * Note that it can take several polling cycles, especially if the receiver
+ * was in the continuous timecode mode. (It can be slow to leave that mode.)
+ *
+ * ntp.conf parameters:
+ * time1 - offset applied to samples when reading WEST satellite (default = 0)
+ * time2 - offset applied to samples when reading EAST satellite (default = 0)
+ * stratum - stratum to assign to this clock (default = 0)
+ * refid - refid assigned to this clock (default = "TRUE", see below)
+ * flag1 - will silence the clock side of ntpd, just reading the clock
+ * without trying to write to it. (default = 0)
+ * flag2 - generate a debug file /tmp/true%d.
+ * flag3 - enable ppsclock streams module
+ * flag4 - use the PCL-720 (BSD/OS only)
*/
@@ -133,19 +153,19 @@
* used by the state machine
*/
enum true_event {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
- e_Poll, e_Location, e_TS, e_Max};
+ e_TL3, e_Poll, e_Location, e_TS, e_Max};
const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite",
- "Poll", "Location", "TS"};
+ "TL3", "Poll", "Location", "TS"};
#define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?")
enum true_state {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES,
- s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
+ s_InqTL3, s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES",
- "Init", "F18", "F50", "Start", "Auto"};
+ "InqTL3", "Init", "F18", "F50", "Start", "Auto"};
#define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?")
-enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max};
-const char *types[] = {"unknown", "goes", "tm", "tcu", "omega"};
+enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_tl3, t_Max};
+const char *types[] = {"unknown", "goes", "tm", "tcu", "omega", "tl3"};
#define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?")
/*
@@ -167,15 +187,15 @@ struct true_unit {
/*
* Function prototypes
*/
-static int true_start P((int, struct peer *));
-static void true_shutdown P((int, struct peer *));
-static void true_receive P((struct recvbuf *));
-static void true_poll P((int, struct peer *));
-static void true_send P((struct peer *, const char *));
-static void true_doevent P((struct peer *, enum true_event));
+static int true_start (int, struct peer *);
+static void true_shutdown (int, struct peer *);
+static void true_receive (struct recvbuf *);
+static void true_poll (int, struct peer *);
+static void true_send (struct peer *, const char *);
+static void true_doevent (struct peer *, enum true_event);
#ifdef CLOCK_PPS720
-static u_long true_sample720 P((void));
+static u_long true_sample720 (void);
#endif
/*
@@ -195,6 +215,7 @@ struct refclock refclock_true = {
#if !defined(__STDC__)
# define true_debug (void)
#else
+NTP_PRINTF(2, 3)
static void
true_debug(struct peer *peer, const char *fmt, ...)
{
@@ -205,36 +226,40 @@ true_debug(struct peer *peer, const char *fmt, ...)
va_start(ap, fmt);
pp = peer->procptr;
- up = (struct true_unit *)pp->unitptr;
+ up = pp->unitptr;
want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
now_debugging = (up->debug != NULL);
if (want_debugging != now_debugging)
{
if (want_debugging) {
- char filename[40];
- int fd;
-
- snprintf(filename, sizeof(filename), "/tmp/true%d.debug", up->unit);
- fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
- if (fd >= 0 && (up->debug = fdopen(fd, "r+"))) {
+ char filename[40];
+ int fd;
+
+ snprintf(filename, sizeof(filename),
+ "/tmp/true%d.debug", up->unit);
+ fd = open(filename, O_CREAT | O_WRONLY | O_EXCL,
+ 0600);
+ if (fd >= 0 && (up->debug = fdopen(fd, "w"))) {
#ifdef HAVE_SETVBUF
- static char buf[BUFSIZ];
- setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
+ static char buf[BUFSIZ];
+
+ setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
#else
- setlinebuf(up->debug);
+ setlinebuf(up->debug);
#endif
- }
- } else {
- fclose(up->debug);
- up->debug = NULL;
- }
+ }
+ } else {
+ fclose(up->debug);
+ up->debug = NULL;
+ }
}
if (up->debug) {
fprintf(up->debug, "true%d: ", up->unit);
vfprintf(up->debug, fmt, ap);
}
+ va_end(ap);
}
#endif /*STDC*/
@@ -255,44 +280,51 @@ true_start(
/*
* Open serial port
*/
- (void)snprintf(device, sizeof(device), DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
- return (0);
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, SPEED232, LDISC_CLK);
+ if (fd <= 0)
+ return 0;
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct true_unit *)
- emalloc(sizeof(struct true_unit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct true_unit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = true_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
*/
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
+ memcpy(&pp->refid, REFID, 4);
up->pollcnt = 2;
up->type = t_unknown;
up->state = s_Base;
+
+ /*
+ * Send a CTRL-C character at the start,
+ * just in case the clock is already
+ * sending timecodes
+ */
+ true_send(peer, "\03\r");
+
true_doevent(peer, e_Init);
+
return (1);
}
+
/*
* true_shutdown - shut down the clock
*/
@@ -306,9 +338,11 @@ true_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct true_unit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (pp->io.fd != -1)
+ io_closeclock(&pp->io);
+ if (up != NULL)
+ free(up);
}
@@ -327,33 +361,34 @@ true_receive(
char synced;
int i;
int lat, lon, off; /* GOES Satellite position */
- /* Use these variable to hold data until we decide its worth keeping */
- char rd_lastcode[BMAX];
- l_fp rd_tmp;
- u_short rd_lencode;
+ /* These variables hold data until we decide to keep it */
+ char rd_lastcode[BMAX];
+ l_fp rd_tmp;
+ u_short rd_lencode;
/*
* Get the clock this applies to and pointers to the data.
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct true_unit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Read clock output. Automatically handles STREAMS, CLKLDISC.
*/
- rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
- rd_lastcode[rd_lencode] = '\0';
+ rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
+ rd_lastcode[rd_lencode] = '\0';
/*
* There is a case where <cr><lf> generates 2 timestamps.
*/
- if (rd_lencode == 0)
- return;
- pp->lencode = rd_lencode;
- strcpy(pp->a_lastcode, rd_lastcode);
- pp->lastrec = rd_tmp;
- true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode);
+ if (rd_lencode == 0)
+ return;
+ pp->lencode = rd_lencode;
+ strlcpy(pp->a_lastcode, rd_lastcode, sizeof(pp->a_lastcode));
+ pp->lastrec = rd_tmp;
+ true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode,
+ pp->lencode);
up->pollcnt = 2;
record_clock_stats(&peer->srcadr, pp->a_lastcode);
@@ -424,24 +459,37 @@ true_receive(
*/
if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
switch (i) {
- case 50:
+ case 50:
true_doevent(peer, e_F50);
break;
- case 51:
+ case 51:
true_doevent(peer, e_F51);
break;
- default:
+ default:
true_debug(peer, "got F%02d - ignoring\n", i);
break;
}
return;
}
+ /*
+ * Timecode: "VER xx.xx"
+ * (from a TL3 when sent "QV", so id's it during initialization.)
+ */
+ if (pp->a_lastcode[0] == 'V' && pp->a_lastcode[1] == 'E' &&
+ pp->a_lastcode[2] == 'R' && pp->a_lastcode[6] == '.') {
+ true_doevent(peer, e_TL3);
+ NLOG(NLOG_CLOCKSTATUS) {
+ msyslog(LOG_INFO, "TL3: %s", pp->a_lastcode);
+ }
+ return;
+ }
+
/*
* Timecode: " TRUETIME Mk III" or " TRUETIME XL"
* (from a TM/TMD/XL clock during initialization.)
*/
- if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
+ if (strncmp(pp->a_lastcode, " TRUETIME Mk III ", 17) == 0 ||
strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
true_doevent(peer, e_F18);
NLOG(NLOG_CLOCKSTATUS) {
@@ -452,8 +500,8 @@ true_receive(
/*
* Timecode: "N03726428W12209421+000033"
- * 1 2
- * 0123456789012345678901234
+ * 1 2
+ * index 0123456789012345678901234
* (from a TCU during initialization)
*/
if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
@@ -467,6 +515,8 @@ true_receive(
}
/*
* Timecode: "ddd:hh:mm:ssQ"
+ * 1 2
+ * index 0123456789012345678901234
* (from all clocks supported by this driver.)
*/
if (pp->a_lastcode[3] == ':' &&
@@ -480,10 +530,11 @@ true_receive(
* Adjust the synchronize indicator according to timecode
* say were OK, and then say not if we really are not OK
*/
- if (synced == '>' || synced == '#' || synced == '?')
- pp->leap = LEAP_NOTINSYNC;
+ if (synced == '>' || synced == '#' || synced == '?'
+ || synced == 'X')
+ pp->leap = LEAP_NOTINSYNC;
else
- pp->leap = LEAP_NOWARNING;
+ pp->leap = LEAP_NOWARNING;
true_doevent(peer, e_TS);
@@ -535,9 +586,15 @@ true_receive(
* want one when polled. If we havn't been polled, bail out.
*/
if (!up->polled)
- return;
+ return;
+
+ /* We only call doevent if additional things need be done
+ * at poll interval. Currently, its only for GOES. We also
+ * call it for clock unknown so that it gets logged.
+ */
+ if (up->type == t_goes || up->type == t_unknown)
+ true_doevent(peer, e_Poll);
- true_doevent(peer, e_Poll);
if (!refclock_process(pp)) {
refclock_report(peer, CEVNT_BADTIME);
return;
@@ -546,7 +603,7 @@ true_receive(
* If clock is good we send a NOMINAL message so that
* any previous BAD messages are nullified
*/
- pp->lastref = pp->lastrec;
+ pp->lastref = pp->lastrec;
refclock_receive(peer);
refclock_report(peer, CEVNT_NOMINAL);
@@ -580,13 +637,13 @@ true_send(
pp = peer->procptr;
if (!(pp->sloppyclockflag & CLK_FLAG1)) {
- register int len = strlen(cmd);
+ int len = strlen(cmd);
true_debug(peer, "Send '%s'\n", cmd);
if (write(pp->io.fd, cmd, (unsigned)len) != len)
- refclock_report(peer, CEVNT_FAULT);
+ refclock_report(peer, CEVNT_FAULT);
else
- pp->polls++;
+ pp->polls++;
}
}
@@ -604,7 +661,7 @@ true_doevent(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct true_unit *)pp->unitptr;
+ up = pp->unitptr;
if (event != e_TS) {
NLOG(NLOG_CLOCKSTATUS) {
msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
@@ -616,176 +673,233 @@ true_doevent(
true_debug(peer, "clock %s, state %s, event %s\n",
typeStr(up->type), stateStr(up->state), eventStr(event));
switch (up->type) {
- case t_goes:
+ case t_goes:
switch (event) {
- case e_Init: /* FALLTHROUGH */
- case e_Satellite:
+ case e_Init: /* FALLTHROUGH */
+ case e_Satellite:
/*
* Switch back to on-second time codes and return.
*/
true_send(peer, "C");
up->state = s_Start;
break;
- case e_Poll:
+ case e_Poll:
/*
* After each poll, check the station (satellite).
*/
true_send(peer, "P");
/* No state change needed. */
break;
- default:
+ default:
break;
}
/* FALLTHROUGH */
- case t_omega:
+ case t_omega:
switch (event) {
- case e_Init:
+ case e_Init:
true_send(peer, "C");
up->state = s_Start;
break;
- case e_TS:
+ case e_TS:
if (up->state != s_Start && up->state != s_Auto) {
true_send(peer, "\03\r");
break;
}
up->state = s_Auto;
break;
- default:
+ default:
break;
}
break;
- case t_tm:
+ case t_tm:
switch (event) {
- case e_Init:
+ case e_Init:
true_send(peer, "F18\r");
up->state = s_Init;
break;
- case e_F18:
+ case e_F18:
true_send(peer, "F50\r");
+ /*
+ * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
+ * (from a TM/TMD/XL clock during initialization.)
+ */
+ if ( strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
+ strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
+ true_doevent(peer, e_F18);
+ NLOG(NLOG_CLOCKSTATUS) {
+ msyslog(LOG_INFO, "TM/TMD/XL: %s",
+ pp->a_lastcode);
+ }
+ return;
+ }
up->state = s_F18;
break;
- case e_F50:
+ case e_F50:
true_send(peer, "F51\r");
up->state = s_F50;
break;
- case e_F51:
+ case e_F51:
true_send(peer, "F08\r");
up->state = s_Start;
break;
- case e_TS:
+ case e_TS:
if (up->state != s_Start && up->state != s_Auto) {
true_send(peer, "\03\r");
break;
}
up->state = s_Auto;
break;
- default:
+ default:
break;
}
break;
- case t_tcu:
+ case t_tcu:
switch (event) {
- case e_Init:
+ case e_Init:
true_send(peer, "MD3\r"); /* GPS Synch'd Gen. */
true_send(peer, "TSU\r"); /* UTC, not GPS. */
true_send(peer, "AU\r"); /* Auto Timestamps. */
up->state = s_Start;
break;
- case e_TS:
+ case e_TS:
if (up->state != s_Start && up->state != s_Auto) {
true_send(peer, "\03\r");
break;
}
up->state = s_Auto;
break;
- default:
+ default:
break;
}
break;
- case t_unknown:
+ case t_tl3:
+ switch (event) {
+ case e_Init:
+ true_send(peer, "ST1"); /* Turn on continuous stream */
+ break;
+ case e_TS:
+ up->state = s_Auto;
+ break;
+ default:
+ break;
+ }
+ break;
+ case t_unknown:
+ if (event == e_Poll)
+ break;
switch (up->state) {
- case s_Base:
+ case s_Base:
if (event != e_Init)
abort();
true_send(peer, "P\r");
up->state = s_InqGOES;
break;
- case s_InqGOES:
+ case s_InqGOES:
switch (event) {
- case e_Satellite:
+ case e_Satellite:
up->type = t_goes;
true_doevent(peer, e_Init);
break;
- case e_Init: /*FALLTHROUGH*/
- case e_Huh: /*FALLTHROUGH*/
- case e_TS:
+ case e_Init: /*FALLTHROUGH*/
+ case e_Huh:
+ case e_TS:
+ true_send(peer, "ST0"); /* turn off TL3 auto */
+ sleep(1); /* wait for it */
+ up->state = s_InqTL3;
+ true_send(peer, "QV"); /* see if its a TL3 */
+ break;
+ default:
+ abort();
+ }
+ break;
+ case s_InqTL3:
+ switch (event) {
+ case e_TL3:
+ up->type = t_tl3;
+ up->state = s_Auto; /* Inq side-effect. */
+ true_send(peer, "ST1"); /* Turn on 1/sec data */
+ break;
+ case e_Init: /*FALLTHROUGH*/
+ case e_Huh:
up->state = s_InqOmega;
true_send(peer, "C\r");
break;
+ case e_TS:
+ up->type = t_tl3; /* Already sending data */
+ up->state = s_Auto;
+ break;
default:
- abort();
+ msyslog(LOG_INFO,
+ "TRUE: TL3 init fellthrough! (%d)", event);
+ break;
}
break;
- case s_InqOmega:
+ case s_InqOmega:
switch (event) {
- case e_TS:
+ case e_TS:
up->type = t_omega;
up->state = s_Auto; /* Inq side-effect. */
break;
- case e_Init: /*FALLTHROUGH*/
- case e_Huh:
+ case e_Init: /*FALLTHROUGH*/
+ case e_Huh:
up->state = s_InqTM;
true_send(peer, "F18\r");
break;
- default:
+ default:
abort();
}
break;
- case s_InqTM:
+ case s_InqTM:
switch (event) {
- case e_F18:
+ case e_F18:
up->type = t_tm;
true_doevent(peer, e_Init);
break;
- case e_Init: /*FALLTHROUGH*/
- case e_Huh:
+ case e_Init: /*FALLTHROUGH*/
+ case e_Huh:
true_send(peer, "PO\r");
up->state = s_InqTCU;
break;
- default:
- abort();
+ default:
+ msyslog(LOG_INFO,
+ "TRUE: TM/TMD init fellthrough!");
+ break;
}
break;
- case s_InqTCU:
+ case s_InqTCU:
switch (event) {
- case e_Location:
+ case e_Location:
up->type = t_tcu;
true_doevent(peer, e_Init);
break;
- case e_Init: /*FALLTHROUGH*/
- case e_Huh:
+ case e_Init: /*FALLTHROUGH*/
+ case e_Huh:
up->state = s_Base;
sleep(1); /* XXX */
break;
- default:
- abort();
+ default:
+ msyslog(LOG_INFO,
+ "TRUE: TCU init fellthrough!");
+ break;
}
break;
/*
* An expedient hack to prevent lint complaints,
* these don't actually need to be used here...
*/
- case s_Init:
- case s_F18:
- case s_F50:
- case s_Start:
- case s_Auto:
- case s_Max:
- msyslog(LOG_INFO, "TRUE: state %s is unexpected!", stateStr(up->state));
+ case s_Init:
+ case s_F18:
+ case s_F50:
+ case s_Start:
+ case s_Auto:
+ case s_Max:
+ msyslog(LOG_INFO, "TRUE: state %s is unexpected!",
+ stateStr(up->state));
}
break;
- default:
- abort();
+ default:
+ msyslog(LOG_INFO, "TRUE: cannot identify refclock!");
+ abort();
/* NOTREACHED */
}
@@ -825,10 +939,10 @@ true_poll(
* The next time a timecode comes in, it will be fed back.
*/
pp = peer->procptr;
- up = (struct true_unit *)pp->unitptr;
- if (up->pollcnt > 0)
- up->pollcnt--;
- else {
+ up = pp->unitptr;
+ if (up->pollcnt > 0) {
+ up->pollcnt--;
+ } else {
true_doevent(peer, e_Init);
refclock_report(peer, CEVNT_TIMEOUT);
}
diff --git a/contrib/ntp/ntpd/refclock_tsyncpci.c b/contrib/ntp/ntpd/refclock_tsyncpci.c
new file mode 100644
index 0000000..e70a7cf
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_tsyncpci.c
@@ -0,0 +1,912 @@
+/*******************************************************************************
+*
+* Module : refclock_tsyncpci.c
+* Date : 09/08/08
+* Purpose : Implements a reference clock driver for the NTP daemon. This
+* reference clock driver provides a means to communicate with
+* the Spectracom TSYNC PCI timing devices and use them as a time
+* source.
+*
+* (C) Copyright 2008 Spectracom Corporation
+*
+* This software is provided by Spectracom Corporation 'as is' and
+* any express or implied warranties, including, but not limited to, the
+* implied warranties of merchantability and fitness for a particular purpose
+* are disclaimed. In no event shall Spectracom Corporation be liable
+* for any direct, indirect, incidental, special, exemplary, or consequential
+* damages (including, but not limited to, procurement of substitute goods
+* or services; loss of use, data, or profits; or business interruption)
+* however caused and on any theory of liability, whether in contract, strict
+* liability, or tort (including negligence or otherwise) arising in any way
+* out of the use of this software, even if advised of the possibility of
+* such damage.
+*
+* This software is released for distribution according to the NTP copyright
+* and license contained in html/copyright.html of NTP source.
+*
+*******************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(REFCLOCK) && defined(CLOCK_TSYNCPCI)
+
+#include <asm/ioctl.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <netinet/in.h>
+
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
+#include "ntp_calendar.h"
+
+
+/*******************************************************************************
+**
+** This driver supports the Spectracom TSYNC PCI GPS receiver. It requires
+** that the tsyncpci.o device driver be installed and loaded.
+**
+*******************************************************************************/
+
+#define TSYNC_PCI_REVISION "1.11"
+
+/*
+** TPRO interface definitions
+*/
+#define DEVICE "/dev/tsyncpci" /* device name */
+#define PRECISION (-20) /* precision assumed (1 us) */
+#define DESCRIPTION "Spectracom TSYNC-PCI" /* WRU */
+
+#define SECONDS_1900_TO_1970 (2208988800U)
+
+#define TSYNC_REF_IID (0x2500) // SS CAI, REF IID
+#define TSYNC_REF_DEST_ID (0x0001) // KTS Firmware
+#define TSYNC_REF_IN_PYLD_OFF (0)
+#define TSYNC_REF_IN_LEN (0)
+#define TSYNC_REF_OUT_PYLD_OFF (0)
+#define TSYNC_REF_OUT_LEN (8)
+#define TSYNC_REF_MAX_OUT_LEN (16)
+#define TSYNC_REF_PYLD_LEN (TSYNC_REF_IN_LEN + \
+ TSYNC_REF_MAX_OUT_LEN)
+#define TSYNC_REF_LEN (4)
+#define TSYNC_REF_LOCAL ("LOCL")
+
+#define TSYNC_TMSCL_IID (0x2301) // CS CAI, TIMESCALE IID
+#define TSYNC_TMSCL_DEST_ID (0x0001) // KTS Firmware
+#define TSYNC_TMSCL_IN_PYLD_OFF (0)
+#define TSYNC_TMSCL_IN_LEN (0)
+#define TSYNC_TMSCL_OUT_PYLD_OFF (0)
+#define TSYNC_TMSCL_OUT_LEN (4)
+#define TSYNC_TMSCL_MAX_OUT_LEN (12)
+#define TSYNC_TMSCL_PYLD_LEN (TSYNC_TMSCL_IN_LEN + \
+ TSYNC_TMSCL_MAX_OUT_LEN)
+
+#define TSYNC_LEAP_IID (0x2307) // CS CAI, LEAP SEC IID
+#define TSYNC_LEAP_DEST_ID (0x0001) // KTS Firmware
+#define TSYNC_LEAP_IN_PYLD_OFF (0)
+#define TSYNC_LEAP_IN_LEN (0)
+#define TSYNC_LEAP_OUT_PYLD_OFF (0)
+#define TSYNC_LEAP_OUT_LEN (28)
+#define TSYNC_LEAP_MAX_OUT_LEN (36)
+#define TSYNC_LEAP_PYLD_LEN (TSYNC_LEAP_IN_LEN + \
+ TSYNC_LEAP_MAX_OUT_LEN)
+
+// These define the base date/time of the system clock. The system time will
+// be tracked as the number of seconds from this date/time.
+#define TSYNC_TIME_BASE_YEAR (1970) // earliest acceptable year
+
+#define TSYNC_LCL_STRATUM (0)
+
+/*
+** TSYNC Time Scales type
+*/
+typedef enum
+{
+ TIME_SCALE_UTC = 0, // Universal Coordinated Time
+ TIME_SCALE_TAI = 1, // International Atomic Time
+ TIME_SCALE_GPS = 2, // Global Positioning System
+ TIME_SCALE_LOCAL = 3, // UTC w/local rules for time zone and DST
+ NUM_TIME_SCALES = 4, // Number of time scales
+
+ TIME_SCALE_MAX = 15 // Maximum number of timescales
+
+} TIME_SCALE;
+
+/*
+** TSYNC Board Object
+*/
+typedef struct BoardObj {
+
+ int file_descriptor;
+ unsigned short devid;
+ unsigned short options;
+ unsigned char firmware[5];
+ unsigned char FPGA[5];
+ unsigned char driver[7];
+
+} BoardObj;
+
+/*
+** TSYNC Time Object
+*/
+typedef struct TimeObj {
+
+ unsigned char syncOption; /* -M option */
+ unsigned int secsDouble; /* seconds floating pt */
+ unsigned char seconds; /* seconds whole num */
+ unsigned char minutes;
+ unsigned char hours;
+ unsigned short days;
+ unsigned short year;
+ unsigned short flags; /* bit 2 SYNC, bit 1 TCODE; all others 0 */
+
+} TimeObj;
+
+/*
+** NTP Time Object
+*/
+typedef struct NtpTimeObj {
+
+ TimeObj timeObj;
+ struct timeval tv;
+ unsigned int refId;
+
+} NtpTimeObj;
+/*
+** TSYNC Supervisor Reference Object
+*/
+typedef struct ReferenceObj {
+
+ char time[TSYNC_REF_LEN];
+ char pps[TSYNC_REF_LEN];
+
+} ReferenceObj;
+
+/*
+** TSYNC Seconds Time Object
+*/
+typedef struct SecTimeObj
+{
+ unsigned int seconds;
+ unsigned int ns;
+}
+SecTimeObj;
+
+/*
+** TSYNC DOY Time Object
+*/
+typedef struct DoyTimeObj
+{
+ unsigned int year;
+ unsigned int doy;
+ unsigned int hour;
+ unsigned int minute;
+ unsigned int second;
+ unsigned int ns;
+}
+DoyTimeObj;
+
+/*
+** TSYNC Leap Second Object
+*/
+typedef struct LeapSecondObj
+{
+ int offset;
+ DoyTimeObj utcDate;
+}
+LeapSecondObj;
+
+/*
+ * structures for ioctl interactions with driver
+ */
+#define DI_PAYLOADS_STARTER_LENGTH 4
+typedef struct ioctl_trans_di {
+
+ // input parameters
+ uint16_t dest;
+ uint16_t iid;
+
+ uint32_t inPayloadOffset;
+ uint32_t inLength;
+ uint32_t outPayloadOffset;
+ uint32_t maxOutLength;
+
+ // output parameters
+ uint32_t actualOutLength;
+ int32_t status;
+
+ // Input and output
+
+ // The payloads field MUST be last in ioctl_trans_di.
+ uint8_t payloads[DI_PAYLOADS_STARTER_LENGTH];
+
+}ioctl_trans_di;
+
+/*
+ * structure for looking up a reference ID from a reference name
+ */
+typedef struct
+{
+ const char* pRef; // KTS Reference Name
+ const char* pRefId; // NTP Reference ID
+
+} RefIdLookup;
+
+/*
+ * unit control structure
+ */
+typedef struct {
+ uint32_t refPrefer; // Reference prefer flag
+ uint32_t refId; // Host peer reference ID
+ uint8_t refStratum; // Host peer reference stratum
+
+} TsyncUnit;
+
+/*
+** Function prototypes
+*/
+static void tsync_poll (int unit, struct peer *);
+static void tsync_shutdown (int, struct peer *);
+static int tsync_start (int, struct peer *);
+
+/*
+** Helper functions
+*/
+static void ApplyTimeOffset (DoyTimeObj* pDt, int off);
+static void SecTimeFromDoyTime (SecTimeObj* pSt, DoyTimeObj* pDt);
+static void DoyTimeFromSecTime (DoyTimeObj* pDt, SecTimeObj* pSt);
+
+/*
+** Transfer vector
+*/
+struct refclock refclock_tsyncpci = {
+ tsync_start, /* start up driver */
+ tsync_shutdown, /* shut down driver */
+ tsync_poll, /* transmit poll message */
+ noentry, /* not used (old tsync_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old tsync_buginfo) */
+ NOFLAGS /* not used */
+};
+
+/*
+ * Reference ID lookup table
+ */
+static RefIdLookup RefIdLookupTbl[] =
+{
+ {"gps", "GPS"},
+ {"ir", "IRIG"},
+ {"hvq", "HVQ"},
+ {"frq", "FREQ"},
+ {"mdm", "ACTS"},
+ {"epp", "PPS"},
+ {"ptp", "PTP"},
+ {"asc", "ATC"},
+ {"hst0", "USER"},
+ {"hst", TSYNC_REF_LOCAL},
+ {"self", TSYNC_REF_LOCAL},
+ {NULL, NULL}
+};
+
+/*******************************************************************************
+** IOCTL DEFINITIONS
+*******************************************************************************/
+#define IOCTL_TPRO_ID 't'
+#define IOCTL_TPRO_OPEN _IOWR(IOCTL_TPRO_ID, 0, BoardObj)
+#define IOCTL_TPRO_GET_NTP_TIME _IOWR(IOCTL_TPRO_ID, 25, NtpTimeObj)
+#define IOCTL_TSYNC_GET _IOWR(IOCTL_TPRO_ID, 26, ioctl_trans_di)
+
+/******************************************************************************
+ *
+ * Function: tsync_start()
+ * Description: Used to intialize the Spectracom TSYNC reference driver.
+ *
+ * Parameters:
+ * IN: unit - not used.
+ * *peer - pointer to this reference clock's peer structure
+ * Returns: 0 - unsuccessful
+ * 1 - successful
+ *
+*******************************************************************************/
+static int tsync_start(int unit, struct peer *peer)
+{
+ struct refclockproc *pp;
+ TsyncUnit *up;
+
+
+ /*
+ ** initialize reference clock and peer parameters
+ */
+ pp = peer->procptr;
+ pp->clockdesc = DESCRIPTION;
+ pp->io.clock_recv = noentry;
+ pp->io.srcclock = peer;
+ pp->io.datalen = 0;
+ peer->precision = PRECISION;
+
+ // Allocate and initialize unit structure
+ if (!(up = (TsyncUnit*)emalloc(sizeof(TsyncUnit))))
+ {
+ return (0);
+ }
+
+ // Store reference preference
+ up->refPrefer = peer->flags & FLAG_PREFER;
+
+ // Initialize reference stratum level and ID
+ up->refStratum = STRATUM_UNSPEC;
+ strncpy((char *)&up->refId, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
+
+ // Attach unit structure
+ pp->unitptr = (caddr_t)up;
+
+ /* Declare our refId as local in the beginning because we do not know
+ * what our actual refid is yet.
+ */
+ strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
+
+ return (1);
+
+} /* End - tsync_start() */
+
+/*******************************************************************************
+**
+** Function: tsync_shutdown()
+** Description: Handles anything related to shutting down the reference clock
+** driver. Nothing at this point in time.
+**
+** Parameters:
+** IN: unit - not used.
+** *peer - pointer to this reference clock's peer structure
+** Returns: none.
+**
+*******************************************************************************/
+static void tsync_shutdown(int unit, struct peer *peer)
+{
+
+} /* End - tsync_shutdown() */
+
+/******************************************************************************
+ *
+ * Function: tsync_poll()
+ * Description: Retrieve time from the TSYNC device.
+ *
+ * Parameters:
+ * IN: unit - not used.
+ * *peer - pointer to this reference clock's peer structure
+ * Returns: none.
+ *
+*******************************************************************************/
+static void tsync_poll(int unit, struct peer *peer)
+{
+ char device[32];
+ struct refclockproc *pp;
+ struct calendar jt;
+ TsyncUnit *up;
+ unsigned char synch;
+ double seconds;
+ int err;
+ int err1;
+ int err2;
+ int err3;
+ int i;
+ int j;
+ unsigned int itAllocationLength;
+ unsigned int itAllocationLength1;
+ unsigned int itAllocationLength2;
+ NtpTimeObj TimeContext;
+ BoardObj hBoard;
+ char timeRef[TSYNC_REF_LEN + 1];
+ char ppsRef [TSYNC_REF_LEN + 1];
+ TIME_SCALE tmscl = TIME_SCALE_UTC;
+ LeapSecondObj leapSec;
+ ioctl_trans_di *it;
+ ioctl_trans_di *it1;
+ ioctl_trans_di *it2;
+ l_fp offset;
+ l_fp ltemp;
+ ReferenceObj * pRefObj;
+
+
+ /* Construct the device name */
+ sprintf(device, "%s%d", DEVICE, (int)peer->refclkunit);
+
+ printf("Polling device number %d...\n", (int)peer->refclkunit);
+
+ /* Open the TSYNC device */
+ hBoard.file_descriptor = open(device, O_RDONLY | O_NDELAY, 0777);
+
+ /* If error opening TSYNC device... */
+ if (hBoard.file_descriptor < 0)
+ {
+ msyslog(LOG_ERR, "Couldn't open device");
+ return;
+ }
+
+ /* If error while initializing the board... */
+ if (ioctl(hBoard.file_descriptor, IOCTL_TPRO_OPEN, &hBoard) < 0)
+ {
+ msyslog(LOG_ERR, "Couldn't initialize device");
+ close(hBoard.file_descriptor);
+ return;
+ }
+
+ /* Allocate memory for ioctl message */
+ itAllocationLength =
+ (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
+ TSYNC_REF_IN_LEN + TSYNC_REF_MAX_OUT_LEN;
+
+ it = (ioctl_trans_di*)alloca(itAllocationLength);
+ if (it == NULL) {
+ msyslog(LOG_ERR, "Couldn't allocate transaction memory - Reference");
+ return;
+ }
+
+ /* Build SS_GetRef ioctl message */
+ it->dest = TSYNC_REF_DEST_ID;
+ it->iid = TSYNC_REF_IID;
+ it->inPayloadOffset = TSYNC_REF_IN_PYLD_OFF;
+ it->inLength = TSYNC_REF_IN_LEN;
+ it->outPayloadOffset = TSYNC_REF_OUT_PYLD_OFF;
+ it->maxOutLength = TSYNC_REF_MAX_OUT_LEN;
+ it->actualOutLength = 0;
+ it->status = 0;
+ memset(it->payloads, 0, TSYNC_REF_MAX_OUT_LEN);
+
+ /* Read the reference from the TSYNC-PCI device */
+ err = ioctl(hBoard.file_descriptor,
+ IOCTL_TSYNC_GET,
+ (char *)it);
+
+ /* Allocate memory for ioctl message */
+ itAllocationLength1 =
+ (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
+ TSYNC_TMSCL_IN_LEN + TSYNC_TMSCL_MAX_OUT_LEN;
+
+ it1 = (ioctl_trans_di*)alloca(itAllocationLength1);
+ if (it1 == NULL) {
+ msyslog(LOG_ERR, "Couldn't allocate transaction memory - Time Scale");
+ return;
+ }
+
+ /* Build CS_GetTimeScale ioctl message */
+ it1->dest = TSYNC_TMSCL_DEST_ID;
+ it1->iid = TSYNC_TMSCL_IID;
+ it1->inPayloadOffset = TSYNC_TMSCL_IN_PYLD_OFF;
+ it1->inLength = TSYNC_TMSCL_IN_LEN;
+ it1->outPayloadOffset = TSYNC_TMSCL_OUT_PYLD_OFF;
+ it1->maxOutLength = TSYNC_TMSCL_MAX_OUT_LEN;
+ it1->actualOutLength = 0;
+ it1->status = 0;
+ memset(it1->payloads, 0, TSYNC_TMSCL_MAX_OUT_LEN);
+
+ /* Read the Time Scale info from the TSYNC-PCI device */
+ err1 = ioctl(hBoard.file_descriptor,
+ IOCTL_TSYNC_GET,
+ (char *)it1);
+
+ /* Allocate memory for ioctl message */
+ itAllocationLength2 =
+ (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
+ TSYNC_LEAP_IN_LEN + TSYNC_LEAP_MAX_OUT_LEN;
+
+ it2 = (ioctl_trans_di*)alloca(itAllocationLength2);
+ if (it2 == NULL) {
+ msyslog(LOG_ERR, "Couldn't allocate transaction memory - Leap Second");
+ return;
+ }
+
+ /* Build CS_GetLeapSec ioctl message */
+ it2->dest = TSYNC_LEAP_DEST_ID;
+ it2->iid = TSYNC_LEAP_IID;
+ it2->inPayloadOffset = TSYNC_LEAP_IN_PYLD_OFF;
+ it2->inLength = TSYNC_LEAP_IN_LEN;
+ it2->outPayloadOffset = TSYNC_LEAP_OUT_PYLD_OFF;
+ it2->maxOutLength = TSYNC_LEAP_MAX_OUT_LEN;
+ it2->actualOutLength = 0;
+ it2->status = 0;
+ memset(it2->payloads, 0, TSYNC_LEAP_MAX_OUT_LEN);
+
+ /* Read the leap seconds info from the TSYNC-PCI device */
+ err2 = ioctl(hBoard.file_descriptor,
+ IOCTL_TSYNC_GET,
+ (char *)it2);
+
+ pp = peer->procptr;
+ up = (TsyncUnit*)pp->unitptr;
+
+ /* Read the time from the TSYNC-PCI device */
+ err3 = ioctl(hBoard.file_descriptor,
+ IOCTL_TPRO_GET_NTP_TIME,
+ (char *)&TimeContext);
+
+ /* Close the TSYNC device */
+ close(hBoard.file_descriptor);
+
+ // Check for errors
+ if ((err < 0) ||(err1 < 0) || (err2 < 0) || (err3 < 0) ||
+ (it->status != 0) || (it1->status != 0) || (it2->status != 0) ||
+ (it->actualOutLength != TSYNC_REF_OUT_LEN) ||
+ (it1->actualOutLength != TSYNC_TMSCL_OUT_LEN) ||
+ (it2->actualOutLength != TSYNC_LEAP_OUT_LEN)) {
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ }
+
+ // Extract reference identifiers from ioctl payload
+ memset(timeRef, '\0', sizeof(timeRef));
+ memset(ppsRef, '\0', sizeof(ppsRef));
+ pRefObj = (void *)it->payloads;
+ memcpy(timeRef, pRefObj->time, TSYNC_REF_LEN);
+ memcpy(ppsRef, pRefObj->pps, TSYNC_REF_LEN);
+
+ // Extract the Clock Service Time Scale and convert to correct byte order
+ memcpy(&tmscl, ((TIME_SCALE*)(it1->payloads)), sizeof(tmscl));
+ tmscl = ntohl(tmscl);
+
+ // Extract leap second info from ioctl payload and perform byte swapping
+ for (i = 0; i < (sizeof(leapSec) / 4); i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ ((unsigned char*)&leapSec)[(i * 4) + j] =
+ ((unsigned char*)(it2->payloads))[(i * 4) + (3 - j)];
+ }
+ }
+
+ // Determine time reference ID from reference name
+ for (i = 0; RefIdLookupTbl[i].pRef != NULL; i++)
+ {
+ // Search RefID table
+ if (strstr(timeRef, RefIdLookupTbl[i].pRef) != NULL)
+ {
+ // Found the matching string
+ break;
+ }
+ }
+
+ // Determine pps reference ID from reference name
+ for (j = 0; RefIdLookupTbl[j].pRef != NULL; j++)
+ {
+ // Search RefID table
+ if (strstr(ppsRef, RefIdLookupTbl[j].pRef) != NULL)
+ {
+ // Found the matching string
+ break;
+ }
+ }
+
+ // Determine synchronization state from flags
+ synch = (TimeContext.timeObj.flags == 0x4) ? 1 : 0;
+
+ // Pull seconds information from time object
+ seconds = (double) (TimeContext.timeObj.secsDouble);
+ seconds /= (double) 1000000.0;
+
+ /*
+ ** Convert the number of microseconds to double and then place in the
+ ** peer's last received long floating point format.
+ */
+ DTOLFP(((double)TimeContext.tv.tv_usec / 1000000.0), &pp->lastrec);
+
+ /*
+ ** The specTimeStamp is the number of seconds since 1/1/1970, while the
+ ** peer's lastrec time should be compatible with NTP which is seconds since
+ ** 1/1/1900. So Add the number of seconds between 1900 and 1970 to the
+ ** specTimeStamp and place in the peer's lastrec long floating point struct.
+ */
+ pp->lastrec.Ul_i.Xl_ui += (unsigned int)TimeContext.tv.tv_sec +
+ SECONDS_1900_TO_1970;
+
+ pp->polls++;
+
+ /*
+ ** set the reference clock object
+ */
+ sprintf(pp->a_lastcode, "%03d %02d:%02d:%02.6f",
+ TimeContext.timeObj.days, TimeContext.timeObj.hours,
+ TimeContext.timeObj.minutes, seconds);
+
+ pp->lencode = strlen (pp->a_lastcode);
+ pp->day = TimeContext.timeObj.days;
+ pp->hour = TimeContext.timeObj.hours;
+ pp->minute = TimeContext.timeObj.minutes;
+ pp->second = (int) seconds;
+ seconds = (seconds - (double) (pp->second / 1.0)) * 1000000000;
+ pp->nsec = (long) seconds;
+
+ /*
+ ** calculate year start
+ */
+ jt.year = TimeContext.timeObj.year;
+ jt.yearday = 1;
+ jt.monthday = 1;
+ jt.month = 1;
+ jt.hour = 0;
+ jt.minute = 0;
+ jt.second = 0;
+ pp->yearstart = caltontp(&jt);
+
+ // Calculate and report reference clock offset
+ offset.l_ui = (long)(((pp->day - 1) * 24) + pp->hour + GMT);
+ offset.l_ui = (offset.l_ui * 60) + (long)pp->minute;
+ offset.l_ui = (offset.l_ui * 60) + (long)pp->second;
+ offset.l_ui = offset.l_ui + (long)pp->yearstart;
+ offset.l_uf = 0;
+ DTOLFP(pp->nsec / 1e9, &ltemp);
+ L_ADD(&offset, &ltemp);
+ refclock_process_offset(pp, offset, pp->lastrec,
+ pp->fudgetime1);
+
+ // KTS in sync
+ if (synch) {
+ // Subtract leap second info by one second to determine effective day
+ ApplyTimeOffset(&(leapSec.utcDate), -1);
+
+ // If there is a leap second today and the KTS is using a time scale
+ // which handles leap seconds then
+ if ((tmscl != TIME_SCALE_GPS) && (tmscl != TIME_SCALE_TAI) &&
+ (leapSec.utcDate.year == (unsigned int)TimeContext.timeObj.year) &&
+ (leapSec.utcDate.doy == (unsigned int)TimeContext.timeObj.days))
+ {
+ // If adding a second
+ if (leapSec.offset == 1)
+ {
+ pp->leap = LEAP_ADDSECOND;
+ }
+ // Else if removing a second
+ else if (leapSec.offset == -1)
+ {
+ pp->leap = LEAP_DELSECOND;
+ }
+ // Else report no leap second pending (no handling of offsets
+ // other than +1 or -1)
+ else
+ {
+ pp->leap = LEAP_NOWARNING;
+ }
+ }
+ // Else report no leap second pending
+ else
+ {
+ pp->leap = LEAP_NOWARNING;
+ }
+
+ peer->leap = pp->leap;
+ refclock_report(peer, CEVNT_NOMINAL);
+
+ // If reference name reported, then not in holdover
+ if ((RefIdLookupTbl[i].pRef != NULL) &&
+ (RefIdLookupTbl[j].pRef != NULL))
+ {
+ // Determine if KTS being synchronized by host (identified as
+ // "LOCL")
+ if ((strcmp(RefIdLookupTbl[i].pRefId, TSYNC_REF_LOCAL) == 0) ||
+ (strcmp(RefIdLookupTbl[j].pRefId, TSYNC_REF_LOCAL) == 0))
+ {
+ // Clear prefer flag
+ peer->flags &= ~FLAG_PREFER;
+
+ // Set reference clock stratum level as unusable
+ pp->stratum = STRATUM_UNSPEC;
+ peer->stratum = pp->stratum;
+
+ // If a valid peer is available
+ if ((sys_peer != NULL) && (sys_peer != peer))
+ {
+ // Store reference peer stratum level and ID
+ up->refStratum = sys_peer->stratum;
+ up->refId = addr2refid(&sys_peer->srcadr);
+ }
+ }
+ else
+ {
+ // Restore prefer flag
+ peer->flags |= up->refPrefer;
+
+ // Store reference stratum as local clock
+ up->refStratum = TSYNC_LCL_STRATUM;
+ strncpy((char *)&up->refId, RefIdLookupTbl[j].pRefId,
+ TSYNC_REF_LEN);
+
+ // Set reference clock stratum level as local clock
+ pp->stratum = TSYNC_LCL_STRATUM;
+ peer->stratum = pp->stratum;
+ }
+
+ // Update reference name
+ strncpy((char *)&pp->refid, RefIdLookupTbl[j].pRefId,
+ TSYNC_REF_LEN);
+ peer->refid = pp->refid;
+ }
+ // Else in holdover
+ else
+ {
+ // Restore prefer flag
+ peer->flags |= up->refPrefer;
+
+ // Update reference ID to saved ID
+ pp->refid = up->refId;
+ peer->refid = pp->refid;
+
+ // Update stratum level to saved stratum level
+ pp->stratum = up->refStratum;
+ peer->stratum = pp->stratum;
+ }
+ }
+ // Else KTS not in sync
+ else {
+ // Place local identifier in peer RefID
+ strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
+ peer->refid = pp->refid;
+
+ // Report not in sync
+ pp->leap = LEAP_NOTINSYNC;
+ peer->leap = pp->leap;
+ }
+
+ if (pp->coderecv == pp->codeproc) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ return;
+ }
+
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
+ refclock_receive(peer);
+
+ /* Increment the number of times the reference has been polled */
+ pp->polls++;
+
+} /* End - tsync_poll() */
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Function: ApplyTimeOffset
+// Description: The ApplyTimeOffset function adds an offset (in seconds) to a
+// specified date and time. The specified date and time is passed
+// back after being modified.
+//
+// Assumptions: 1. Every fourth year is a leap year. Therefore, this function
+// is only accurate through Feb 28, 2100.
+////////////////////////////////////////////////////////////////////////////////
+void ApplyTimeOffset(DoyTimeObj* pDt, int off)
+{
+ SecTimeObj st; // Time, in seconds
+
+
+ // Convert date and time to seconds
+ SecTimeFromDoyTime(&st, pDt);
+
+ // Apply offset
+ st.seconds = (int)((signed long long)st.seconds + (signed long long)off);
+
+ // Convert seconds to date and time
+ DoyTimeFromSecTime(pDt, &st);
+
+} // End ApplyTimeOffset
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Function: SecTimeFromDoyTime
+// Description: The SecTimeFromDoyTime function converts a specified date
+// and time into a count of seconds since the base time. This
+// function operates across the range Base Time to Max Time for
+// the system.
+//
+// Assumptions: 1. A leap year is any year evenly divisible by 4. Therefore,
+// this function is only accurate through Feb 28, 2100.
+// 2. Conversion does not account for leap seconds.
+////////////////////////////////////////////////////////////////////////////////
+void SecTimeFromDoyTime(SecTimeObj* pSt, DoyTimeObj* pDt)
+{
+ unsigned int yrs; // Years
+ unsigned int lyrs; // Leap years
+
+
+ // Start with accumulated time of 0
+ pSt->seconds = 0;
+
+ // Calculate the number of years and leap years
+ yrs = pDt->year - TSYNC_TIME_BASE_YEAR;
+ lyrs = (yrs + 1) / 4;
+
+ // Convert leap years and years
+ pSt->seconds += lyrs * SECSPERLEAPYEAR;
+ pSt->seconds += (yrs - lyrs) * SECSPERYEAR;
+
+ // Convert days, hours, minutes and seconds
+ pSt->seconds += (pDt->doy - 1) * SECSPERDAY;
+ pSt->seconds += pDt->hour * SECSPERHR;
+ pSt->seconds += pDt->minute * SECSPERMIN;
+ pSt->seconds += pDt->second;
+
+ // Copy the subseconds count
+ pSt->ns = pDt->ns;
+
+} // End SecTimeFromDoyTime
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Function: DoyTimeFromSecTime
+// Description: The DoyTimeFromSecTime function converts a specified count
+// of seconds since the start of our base time into a SecTimeObj
+// structure.
+//
+// Assumptions: 1. A leap year is any year evenly divisible by 4. Therefore,
+// this function is only accurate through Feb 28, 2100.
+// 2. Conversion does not account for leap seconds.
+////////////////////////////////////////////////////////////////////////////////
+void DoyTimeFromSecTime(DoyTimeObj* pDt, SecTimeObj* pSt)
+{
+ signed long long secs; // Seconds accumulator variable
+ unsigned int yrs; // Years accumulator variable
+ unsigned int doys; // Days accumulator variable
+ unsigned int hrs; // Hours accumulator variable
+ unsigned int mins; // Minutes accumulator variable
+
+
+ // Convert the seconds count into a signed 64-bit number for calculations
+ secs = (signed long long)(pSt->seconds);
+
+ // Calculate the number of 4 year chunks
+ yrs = (unsigned int)((secs /
+ ((SECSPERYEAR * 3) + SECSPERLEAPYEAR)) * 4);
+ secs %= ((SECSPERYEAR * 3) + SECSPERLEAPYEAR);
+
+ // If there is at least a normal year worth of time left
+ if (secs >= SECSPERYEAR)
+ {
+ // Increment the number of years and subtract a normal year of time
+ yrs++;
+ secs -= SECSPERYEAR;
+ }
+
+ // If there is still at least a normal year worth of time left
+ if (secs >= SECSPERYEAR)
+ {
+ // Increment the number of years and subtract a normal year of time
+ yrs++;
+ secs -= SECSPERYEAR;
+ }
+
+ // If there is still at least a leap year worth of time left
+ if (secs >= SECSPERLEAPYEAR)
+ {
+ // Increment the number of years and subtract a leap year of time
+ yrs++;
+ secs -= SECSPERLEAPYEAR;
+ }
+
+ // Calculate the day of year as the number of days left, then add 1
+ // because months start on the 1st.
+ doys = (unsigned int)((secs / SECSPERDAY) + 1);
+ secs %= SECSPERDAY;
+
+ // Calculate the hour
+ hrs = (unsigned int)(secs / SECSPERHR);
+ secs %= SECSPERHR;
+
+ // Calculate the minute
+ mins = (unsigned int)(secs / SECSPERMIN);
+ secs %= SECSPERMIN;
+
+ // Fill in the doytime structure
+ pDt->year = yrs + TSYNC_TIME_BASE_YEAR;
+ pDt->doy = doys;
+ pDt->hour = hrs;
+ pDt->minute = mins;
+ pDt->second = (unsigned int)secs;
+ pDt->ns = pSt->ns;
+
+} // End DoyTimeFromSecTime
+
+#else
+int refclock_tsyncpci_bs;
+#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_tt560.c b/contrib/ntp/ntpd/refclock_tt560.c
index f3d7bc1..171ba5c 100644
--- a/contrib/ntp/ntpd/refclock_tt560.c
+++ b/contrib/ntp/ntpd/refclock_tt560.c
@@ -47,9 +47,9 @@ typedef union byteswap_u
/*
* Function prototypes
*/
-static int tt560_start P((int, struct peer *));
-static void tt560_shutdown P((int, struct peer *));
-static void tt560_poll P((int unit, struct peer *));
+static int tt560_start (int, struct peer *);
+static void tt560_shutdown (int, struct peer *);
+static void tt560_poll (int unit, struct peer *);
/*
* Transfer vector
@@ -76,14 +76,14 @@ tt560_start(
{
register struct tt560unit *up;
struct refclockproc *pp;
- char device[20];
- int fd;
- caddr_t membase;
+ char device[20];
+ int fd;
+ caddr_t membase;
/*
* Open TT560 device
*/
- (void)sprintf(device, DEVICE, unit);
+ snprintf(device, sizeof(device), DEVICE, unit);
fd = open(device, O_RDWR);
if (fd == -1) {
msyslog(LOG_ERR, "tt560_start: open of %s: %m", device);
@@ -123,7 +123,6 @@ tt560_start(
* Initialize miscellaneous peer variables
*/
peer->precision = PRECISION;
- peer->burst = NSTAGE;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, REFID, 4);
return (1);
@@ -195,9 +194,9 @@ tt560_poll(
* proper format, we declare bad format and exit. Note: we
* can't use the sec/usec conversion produced by the driver,
* since the year may be suspect. All format error checking is
- * done by the sprintf() and sscanf() routines.
+ * done by the snprintf() and sscanf() routines.
*/
- sprintf(pp->a_lastcode,
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
"%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
tp->hun_day, tp->tens_day, tp->unit_day,
tp->tens_hour, tp->unit_hour,
@@ -227,15 +226,12 @@ tt560_poll(
refclock_report(peer, CEVNT_BADTIME);
return;
}
- if (peer->burst > 0)
- return;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
}
record_clock_stats(&peer->srcadr, pp->a_lastcode);
refclock_receive(peer);
- peer->burst = NSTAGE;
}
/******************************************************************
diff --git a/contrib/ntp/ntpd/refclock_ulink.c b/contrib/ntp/ntpd/refclock_ulink.c
index d7a62fe..d8f24a5 100644
--- a/contrib/ntp/ntpd/refclock_ulink.c
+++ b/contrib/ntp/ntpd/refclock_ulink.c
@@ -2,23 +2,6 @@
* refclock_ulink - clock driver for Ultralink WWVB receiver
*/
-/***********************************************************************
- * *
- * Copyright (c) David L. Mills 1992-1998 *
- * *
- * Permission to use, copy, modify, and distribute this software and *
- * its documentation for any purpose and without fee is hereby *
- * granted, provided that the above copyright notice appears in all *
- * copies and that both the copyright notice and this permission *
- * notice appear in supporting documentation, and that the name *
- * University of Delaware not be used in advertising or publicity *
- * pertaining to distribution of the software without specific, *
- * written prior permission. The University of Delaware makes no *
- * representations about the suitability this software for any *
- * purpose. It is provided "as is" without express or implied *
- * warranty. *
- **********************************************************************/
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -106,10 +89,10 @@ struct ulinkunit {
/*
* Function prototypes
*/
-static int ulink_start P((int, struct peer *));
-static void ulink_shutdown P((int, struct peer *));
-static void ulink_receive P((struct recvbuf *));
-static void ulink_poll P((int, struct peer *));
+static int ulink_start (int, struct peer *);
+static void ulink_shutdown (int, struct peer *);
+static void ulink_receive (struct recvbuf *);
+static void ulink_poll (int, struct peer *);
/*
* Transfer vector
@@ -142,36 +125,33 @@ ulink_start(
/*
* Open serial port. Use CLK line discipline, if available.
*/
- (void)sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, SPEED232, LDISC_CLK);
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct ulinkunit *)
- emalloc(sizeof(struct ulinkunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct ulinkunit));
+ up = emalloc(sizeof(struct ulinkunit));
+ memset(up, 0, sizeof(struct ulinkunit));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
pp->io.clock_recv = ulink_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
*/
peer->precision = PRECISION;
- peer->burst = NSTAGE;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, REFID, 4);
return (1);
@@ -191,9 +171,11 @@ ulink_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct ulinkunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (pp->io.fd != -1)
+ io_closeclock(&pp->io);
+ if (up != NULL)
+ free(up);
}
@@ -209,21 +191,21 @@ ulink_receive(
struct refclockproc *pp;
struct peer *peer;
- l_fp trtmp; /* arrival timestamp */
- int quality; /* quality indicator */
- int temp; /* int temp */
- char syncchar; /* synchronization indicator */
- char leapchar; /* leap indicator */
- char modechar; /* model 320 mode flag */
- char siglchar; /* model difference between 33x/325 */
+ l_fp trtmp; /* arrival timestamp */
+ int quality = INT_MAX; /* quality indicator */
+ int temp; /* int temp */
+ char syncchar; /* synchronization indicator */
+ char leapchar; /* leap indicator */
+ char modechar; /* model 320 mode flag */
+ char siglchar; /* model difference between 33x/325 */
char char_quality[2]; /* temp quality flag */
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct ulinkunit *)pp->unitptr;
+ up = pp->unitptr;
temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
/*
@@ -571,8 +553,6 @@ ulink_poll(
else
pp->polls++;
- if (peer->burst > 0)
- return;
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
@@ -580,7 +560,6 @@ ulink_poll(
pp->lastref = pp->lastrec;
refclock_receive(peer);
record_clock_stats(&peer->srcadr, pp->a_lastcode);
- peer->burst = NSTAGE;
}
diff --git a/contrib/ntp/ntpd/refclock_wwv.c b/contrib/ntp/ntpd/refclock_wwv.c
index b7e0d9a..79c0afd 100644
--- a/contrib/ntp/ntpd/refclock_wwv.c
+++ b/contrib/ntp/ntpd/refclock_wwv.c
@@ -39,11 +39,12 @@
* tuned automatically using this program as propagation conditions
* change throughout the weasons, both day and night.
*
- * The driver receives, demodulates and decodes the radio signals when
- * connected to the audio codec of a workstation running Solaris, SunOS
- * FreeBSD or Linux, and with a little help, other workstations with
- * similar codecs or sound cards. In this implementation, only one audio
- * driver and codec can be supported on a single machine.
+ * The driver requires an audio codec or sound card with sampling rate 8
+ * kHz and mu-law companding. This is the same standard as used by the
+ * telephone industry and is supported by most hardware and operating
+ * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this
+ * implementation, only one audio driver and codec can be supported on a
+ * single machine.
*
* The demodulation and decoding algorithms used in this driver are
* based on those developed for the TAPR DSP93 development board and the
@@ -62,12 +63,16 @@
*
* Fudge factors
*
- * Fudge flag4 causes the dubugging output described above to be
+ * Fudge flag4 causes the debugging output described above to be
* recorded in the clockstats file. Fudge flag2 selects the audio input
* port, where 0 is the mike port (default) and 1 is the line-in port.
* It does not seem useful to select the compact disc player port. Fudge
* flag3 enables audio monitoring of the input signal. For this purpose,
* the monitor gain is set to a default value.
+ *
+ * CEVNT_BADTIME invalid date or time
+ * CEVNT_PROP propagation failure - no stations heard
+ * CEVNT_TIMEOUT timeout (see newgame() below)
*/
/*
* General definitions. These ordinarily do not need to be changed.
@@ -76,8 +81,8 @@
#define AUDIO_BUFSIZ 320 /* audio buffer size (50 ms) */
#define PRECISION (-10) /* precision assumed (about 1 ms) */
#define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */
-#define SECOND 8000 /* second epoch (sample rate) (Hz) */
-#define MINUTE (SECOND * 60) /* minute epoch */
+#define WWV_SEC 8000 /* second epoch (sample rate) (Hz) */
+#define WWV_MIN (WWV_SEC * 60) /* minute epoch */
#define OFFSET 128 /* companded sample offset */
#define SIZE 256 /* decompanding table size */
#define MAXAMP 6000. /* max signal level reference */
@@ -92,6 +97,7 @@
#define TCKSIZ (TCKCYC * MS) /* tick filter size */
#define NCHAN 5 /* number of radio channels */
#define AUDIO_PHI 5e-6 /* dispersion growth factor */
+#define TBUF 128 /* max monitor line length */
/*
* Tunable parameters. The DGAIN parameter can be changed to fit the
@@ -102,12 +108,10 @@
* radio is not tunable, the DCHAN parameter can be changed to fit the
* expected best propagation frequency: higher if further from the
* transmitter, lower if nearer. The compromise value works for the US
- * right coast. The FREQ_OFFSET parameter can be used as a frequency
- * vernier to correct codec requency if greater than MAXFREQ.
+ * right coast.
*/
#define DCHAN 3 /* default radio channel (15 Mhz) */
#define DGAIN 5. /* subcarrier gain */
-#define FREQ_OFFSET 0. /* codec frequency correction (PPM) */
/*
* General purpose status bits (status)
@@ -133,6 +137,7 @@
#define FGATE 0x0010 /* frequency gate */
#define DGATE 0x0020 /* data pulse amplitude error */
#define BGATE 0x0040 /* data pulse width error */
+#define METRIC 0x0080 /* one or more stations heard */
#define LEPSEC 0x1000 /* leap minute */
/*
@@ -150,10 +155,10 @@
* These bits indicate various alarm conditions, which are decoded to
* form the quality character included in the timecode.
*/
-#define CMPERR 1 /* digit or misc bit compare error */
-#define LOWERR 2 /* low bit or digit amplitude or SNR */
-#define NINERR 4 /* less than nine digits in minute */
-#define SYNERR 8 /* not tracking second sync */
+#define CMPERR 0x1 /* digit or misc bit compare error */
+#define LOWERR 0x2 /* low bit or digit amplitude or SNR */
+#define NINERR 0x4 /* less than nine digits in minute */
+#define SYNERR 0x8 /* not tracking second sync */
/*
* Watchcat timeouts (watch)
@@ -196,10 +201,10 @@
* Tone frequency definitions. The increments are for 4.5-deg sine
* table.
*/
-#define MS (SECOND / 1000) /* samples per millisecond */
-#define IN100 ((100 * 80) / SECOND) /* 100 Hz increment */
-#define IN1000 ((1000 * 80) / SECOND) /* 1000 Hz increment */
-#define IN1200 ((1200 * 80) / SECOND) /* 1200 Hz increment */
+#define MS (WWV_SEC / 1000) /* samples per millisecond */
+#define IN100 ((100 * 80) / WWV_SEC) /* 100 Hz increment */
+#define IN1000 ((1000 * 80) / WWV_SEC) /* 1000 Hz increment */
+#define IN1200 ((1200 * 80) / WWV_SEC) /* 1200 Hz increment */
/*
* Acquisition and tracking time constants
@@ -225,15 +230,21 @@
#define SECWAR 0x40 /* 3 leap second warning */
/*
- * The on-time synchronization point for the driver is the second epoch
- * sync pulse produced by the FIR matched filters. As the 5-ms delay of
- * these filters is compensated, the program delay is 1.1 ms due to the
- * 600-Hz IIR bandpass filter. The measured receiver delay is 4.7 ms and
- * the codec delay less than 0.2 ms. The additional propagation delay
- * specific to each receiver location can be programmed in the fudge
- * time1 and time2 values for WWV and WWVH, respectively.
+ * The on-time synchronization point is the positive-going zero crossing
+ * of the first cycle of the 5-ms second pulse. The IIR baseband filter
+ * phase delay is 0.91 ms, while the receiver delay is approximately 4.7
+ * ms at 1000 Hz. The fudge value -0.45 ms due to the codec and other
+ * causes was determined by calibrating to a PPS signal from a GPS
+ * receiver. The additional propagation delay specific to each receiver
+ * location can be programmed in the fudge time1 and time2 values for
+ * WWV and WWVH, respectively.
+ *
+ * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are
+ * generally within .02 ms short-term with .02 ms jitter. The long-term
+ * offsets vary up to 0.3 ms due to ionosperhic layer height variations.
+ * The processor load due to the driver is 5.8 percent.
*/
-#define PDELAY (.0011 + .0047 + .0002) /* net system delay (s) */
+#define PDELAY ((.91 + 4.7 - 0.45) / 1000) /* system delay (s) */
/*
* Table of sine values at 4.5-degree increments. This is used by the
@@ -365,7 +376,7 @@ struct progx progx[] = {
};
/*
- * BCD coefficients for maximum likelihood digit decode
+ * BCD coefficients for maximum-likelihood digit decode
*/
#define P15 1. /* max positive number */
#define N15 -1. /* max negative number */
@@ -447,14 +458,13 @@ char dstcod[] = {
/*
* The decoding matrix consists of nine row vectors, one for each digit
* of the timecode. The digits are stored from least to most significant
- * order. The maximum likelihood timecode is formed from the digits
- * corresponding to the maximum likelihood values reading in the
+ * order. The maximum-likelihood timecode is formed from the digits
+ * corresponding to the maximum-likelihood values reading in the
* opposite order: yy ddd hh:mm.
*/
struct decvec {
int radix; /* radix (3, 4, 6, 10) */
int digit; /* current clock digit */
- int mldigit; /* maximum likelihood digit */
int count; /* match count */
double digprb; /* max digit probability */
double digsnr; /* likelihood function (dB) */
@@ -503,6 +513,7 @@ struct wwvunit {
l_fp tick; /* audio sample increment */
double phase, freq; /* logical clock phase and frequency */
double monitor; /* audio monitor point */
+ double pdelay; /* propagation delay (s) */
#ifdef ICOM
int fd_icom; /* ICOM file descriptor */
#endif /* ICOM */
@@ -513,7 +524,7 @@ struct wwvunit {
* Audio codec variables
*/
double comp[SIZE]; /* decompanding table */
- int port; /* codec port */
+ int port; /* codec port */
int gain; /* codec gain */
int mongain; /* codec monitor gain */
int clipcnt; /* sample clipped count */
@@ -568,32 +579,32 @@ struct wwvunit {
/*
* Function prototypes
*/
-static int wwv_start P((int, struct peer *));
-static void wwv_shutdown P((int, struct peer *));
-static void wwv_receive P((struct recvbuf *));
-static void wwv_poll P((int, struct peer *));
+static int wwv_start (int, struct peer *);
+static void wwv_shutdown (int, struct peer *);
+static void wwv_receive (struct recvbuf *);
+static void wwv_poll (int, struct peer *);
/*
* More function prototypes
*/
-static void wwv_epoch P((struct peer *));
-static void wwv_rf P((struct peer *, double));
-static void wwv_endpoc P((struct peer *, int));
-static void wwv_rsec P((struct peer *, double));
-static void wwv_qrz P((struct peer *, struct sync *, int));
-static void wwv_corr4 P((struct peer *, struct decvec *,
- double [], double [][4]));
-static void wwv_gain P((struct peer *));
-static void wwv_tsec P((struct peer *));
-static int timecode P((struct wwvunit *, char *));
-static double wwv_snr P((double, double));
-static int carry P((struct decvec *));
-static int wwv_newchan P((struct peer *));
-static void wwv_newgame P((struct peer *));
-static double wwv_metric P((struct sync *));
-static void wwv_clock P((struct peer *));
+static void wwv_epoch (struct peer *);
+static void wwv_rf (struct peer *, double);
+static void wwv_endpoc (struct peer *, int);
+static void wwv_rsec (struct peer *, double);
+static void wwv_qrz (struct peer *, struct sync *, int);
+static void wwv_corr4 (struct peer *, struct decvec *,
+ double [], double [][4]);
+static void wwv_gain (struct peer *);
+static void wwv_tsec (struct peer *);
+static int timecode (struct wwvunit *, char *, size_t);
+static double wwv_snr (double, double);
+static int carry (struct decvec *);
+static int wwv_newchan (struct peer *);
+static void wwv_newgame (struct peer *);
+static double wwv_metric (struct sync *);
+static void wwv_clock (struct peer *);
#ifdef ICOM
-static int wwv_qsy P((struct peer *, int));
+static int wwv_qsy (struct peer *, int);
#endif /* ICOM */
static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */
@@ -648,15 +659,10 @@ wwv_start(
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) {
- close(fd);
- return (0);
- }
- memset(up, 0, sizeof(struct wwvunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
pp->io.clock_recv = wwv_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
@@ -664,6 +670,7 @@ wwv_start(
free(up);
return (0);
}
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -682,10 +689,10 @@ wwv_start(
for (i = 3; i < OFFSET; i++) {
up->comp[i] = up->comp[i - 1] + step;
up->comp[OFFSET + i] = -up->comp[i];
- if (i % 16 == 0)
- step *= 2.;
+ if (i % 16 == 0)
+ step *= 2.;
}
- DTOLFP(1. / SECOND, &up->tick);
+ DTOLFP(1. / WWV_SEC, &up->tick);
/*
* Initialize the decoding matrix with the radix for each digit
@@ -705,7 +712,9 @@ wwv_start(
/*
* Initialize autotune if available. Note that the ICOM select
* code must be less than 128, so the high order bit can be used
- * to select the line speed 0 (9600 bps) or 1 (1200 bps).
+ * to select the line speed 0 (9600 bps) or 1 (1200 bps). Note
+ * we don't complain if the ICOM device is not there; but, if it
+ * is, the radio better be working.
*/
temp = 0;
#ifdef DEBUG
@@ -719,25 +728,14 @@ wwv_start(
else
up->fd_icom = icom_init("/dev/icom", B9600,
temp);
- if (up->fd_icom < 0) {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "icom: %m");
- up->errflg = CEVNT_FAULT;
- }
}
if (up->fd_icom > 0) {
if (wwv_qsy(peer, DCHAN) != 0) {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "icom: radio not found");
- up->errflg = CEVNT_FAULT;
+ msyslog(LOG_NOTICE, "icom: radio not found");
close(up->fd_icom);
up->fd_icom = 0;
} else {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "icom: autotune enabled");
+ msyslog(LOG_NOTICE, "icom: autotune enabled");
}
}
#endif /* ICOM */
@@ -763,7 +761,7 @@ wwv_shutdown(
struct wwvunit *up;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
if (up == NULL)
return;
@@ -801,15 +799,15 @@ wwv_receive(
int bufcnt; /* buffer counter */
l_fp ltemp;
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Main loop - read until there ain't no more. Note codec
* samples are bit-inverted.
*/
- DTOLFP((double)rbufp->recv_length / SECOND, &ltemp);
+ DTOLFP((double)rbufp->recv_length / WWV_SEC, &ltemp);
L_SUB(&rbufp->recv_time, &ltemp);
up->timestamp = rbufp->recv_time;
dpt = rbufp->recv_buffer;
@@ -837,8 +835,7 @@ wwv_receive(
* per second, which results in a frequency change of
* 125 PPM.
*/
- up->phase += up->freq / SECOND;
- up->phase += FREQ_OFFSET / 1e6;
+ up->phase += (up->freq + clock_codec) / WWV_SEC;
if (up->phase >= .5) {
up->phase -= 1.;
} else if (up->phase < -.5) {
@@ -883,9 +880,7 @@ wwv_poll(
struct wwvunit *up;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
- if (pp->coderecv == pp->codeproc)
- up->errflg = CEVNT_TIMEOUT;
+ up = pp->unitptr;
if (up->errflg)
refclock_report(peer, up->errflg);
up->errflg = 0;
@@ -969,18 +964,17 @@ wwv_rf(
static double hsiamp; /* wwvh I tick amplitude */
static double hsqamp; /* wwvh Q tick amplitude */
- static double epobuf[SECOND]; /* second sync comb filter */
+ static double epobuf[WWV_SEC]; /* second sync comb filter */
static double epomax, nxtmax; /* second sync amplitude buffer */
static int epopos; /* epoch second sync position buffer */
static int iniflg; /* initialization flag */
- int pdelay; /* propagation delay (samples) */
int epoch; /* comb filter index */
double dtemp;
int i;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
if (!iniflg) {
iniflg = 1;
@@ -1012,7 +1006,7 @@ wwv_rf(
* compensate for the radio audio response at 100 Hz.
*
* Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB
- * passband ripple, -50 dB stopband ripple.
+ * passband ripple, -50 dB stopband ripple, phase delay 0.97 ms.
*/
data = (lpf[4] = lpf[3]) * 8.360961e-01;
data += (lpf[3] = lpf[2]) * -3.481740e+00;
@@ -1056,7 +1050,7 @@ wwv_rf(
* tones and most of the noise and voice modulation components.
*
* Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB
- * passband ripple, -50 dB stopband ripple.
+ * passband ripple, -50 dB stopband ripple, phase delay 0.91 ms.
*/
syncx = (bpf[8] = bpf[7]) * 4.897278e-01;
syncx += (bpf[7] = bpf[6]) * -2.765914e+00;
@@ -1097,8 +1091,8 @@ wwv_rf(
* while the second counter (epoch) counts the samples in the
* second.
*/
- up->mphase = (up->mphase + 1) % MINUTE;
- epoch = up->mphase % SECOND;
+ up->mphase = (up->mphase + 1) % WWV_MIN;
+ epoch = up->mphase % WWV_SEC;
/*
* WWV
@@ -1126,7 +1120,7 @@ wwv_rf(
sp = &up->mitig[up->achan].wwv;
sp->amp = sqrt(ciamp * ciamp + cqamp * cqamp) / SYNCYC;
if (!(up->status & MSYNC))
- wwv_qrz(peer, sp, (int)(pp->fudgetime1 * SECOND));
+ wwv_qrz(peer, sp, (int)(pp->fudgetime1 * WWV_SEC));
/*
* WWVH
@@ -1154,7 +1148,7 @@ wwv_rf(
rp = &up->mitig[up->achan].wwvh;
rp->amp = sqrt(hiamp * hiamp + hqamp * hqamp) / SYNCYC;
if (!(up->status & MSYNC))
- wwv_qrz(peer, rp, (int)(pp->fudgetime2 * SECOND));
+ wwv_qrz(peer, rp, (int)(pp->fudgetime2 * WWV_SEC));
jptr = (jptr + 1) % SYNSIZ;
kptr = (kptr + 1) % TCKSIZ;
@@ -1174,10 +1168,6 @@ wwv_rf(
*/
if (!wwv_newchan(peer))
up->watch = 0;
-#ifdef ICOM
- if (up->fd_icom > 0)
- wwv_qsy(peer, up->dchan);
-#endif /* ICOM */
} else {
/*
@@ -1186,9 +1176,9 @@ wwv_rf(
* don't miss a beat.
*/
if (up->status & LEPSEC) {
- up->mphase -= SECOND;
+ up->mphase -= WWV_SEC;
if (up->mphase < 0)
- up->mphase += MINUTE;
+ up->mphase += WWV_MIN;
}
}
}
@@ -1212,8 +1202,9 @@ wwv_rf(
wwv_epoch(peer);
} else if (up->sptr != NULL) {
sp = up->sptr;
- if (sp->metric >= TTHR && epoch == sp->mepoch % SECOND) {
- up->rsec = (60 - sp->mepoch / SECOND) % 60;
+ if (sp->metric >= TTHR && epoch == sp->mepoch % WWV_SEC)
+ {
+ up->rsec = (60 - sp->mepoch / WWV_SEC) % 60;
up->rphase = 0;
up->status |= MSYNC;
up->watch = 0;
@@ -1232,18 +1223,14 @@ wwv_rf(
* provides a resolution of one sample (125 us). The filters run
* only if the station has been reliably determined.
*/
- if (up->status & SELV) {
- pdelay = (int)(pp->fudgetime1 * SECOND);
+ if (up->status & SELV)
mfsync = sqrt(csiamp * csiamp + csqamp * csqamp) /
TCKCYC;
- } else if (up->status & SELH) {
- pdelay = (int)(pp->fudgetime2 * SECOND);
+ else if (up->status & SELH)
mfsync = sqrt(hsiamp * hsiamp + hsqamp * hsqamp) /
TCKCYC;
- } else {
- pdelay = 0;
+ else
mfsync = 0;
- }
/*
* Enhance the seconds sync pulse using a 1-s (8000-sample) comb
@@ -1265,15 +1252,15 @@ wwv_rf(
epopos = epoch;
j = epoch - 6 * MS;
if (j < 0)
- j += SECOND;
+ j += WWV_SEC;
nxtmax = fabs(epobuf[j]);
}
if (epoch == 0) {
up->epomax = epomax;
up->eposnr = wwv_snr(epomax, nxtmax);
- epopos -= pdelay + TCKCYC * MS;
+ epopos -= TCKCYC * MS;
if (epopos < 0)
- epopos += SECOND;
+ epopos += WWV_SEC;
wwv_endpoc(peer, epopos);
if (!(up->status & SSYNC))
up->alarm |= SYNERR;
@@ -1313,11 +1300,11 @@ wwv_qrz(
{
struct refclockproc *pp;
struct wwvunit *up;
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
long epoch;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Find the sample with peak amplitude, which defines the minute
@@ -1326,7 +1313,7 @@ wwv_qrz(
*/
epoch = up->mphase - pdelay - SYNSIZ;
if (epoch < 0)
- epoch += MINUTE;
+ epoch += WWV_MIN;
if (sp->amp > sp->maxeng) {
sp->maxeng = sp->amp;
sp->pos = epoch;
@@ -1343,15 +1330,15 @@ wwv_qrz(
if (up->mphase == 0) {
sp->synmax = sp->maxeng;
sp->synsnr = wwv_snr(sp->synmax, (sp->noieng -
- sp->synmax) / MINUTE);
+ sp->synmax) / WWV_MIN);
if (sp->count == 0)
sp->lastpos = sp->pos;
- epoch = (sp->pos - sp->lastpos) % MINUTE;
+ epoch = (sp->pos - sp->lastpos) % WWV_MIN;
sp->reach <<= 1;
if (sp->reach & (1 << AMAX))
sp->count--;
if (sp->synmax > ATHR && sp->synsnr > ASNR) {
- if (abs(epoch) < AWND * MS) {
+ if (labs(epoch) < AWND * MS) {
sp->reach |= 1;
sp->count++;
sp->mepoch = sp->lastpos = sp->pos;
@@ -1364,11 +1351,11 @@ wwv_qrz(
else
sp->metric = wwv_metric(sp);
if (pp->sloppyclockflag & CLK_FLAG4) {
- sprintf(tbuf,
- "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %4ld %4ld",
+ snprintf(tbuf, sizeof(tbuf),
+ "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %ld %ld",
up->status, up->gain, sp->refid,
sp->reach & 0xffff, sp->metric, sp->synmax,
- sp->synsnr, sp->pos % SECOND, epoch);
+ sp->synsnr, sp->pos % WWV_SEC, epoch);
record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
if (debug)
@@ -1413,15 +1400,15 @@ wwv_endpoc(
static int avgcnt; /* averaging interval counter */
static int avginc; /* averaging ratchet */
static int iniflg; /* initialization flag */
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
double dtemp;
int tmp2;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
if (!iniflg) {
iniflg = 1;
- memset((char *)epoch_mf, 0, sizeof(epoch_mf));
+ ZERO(epoch_mf);
}
/*
@@ -1475,7 +1462,7 @@ wwv_endpoc(
* interval while the comb filter charges up and noise
* dissapates..
*/
- tmp2 = (tepoch - xepoch) % SECOND;
+ tmp2 = (tepoch - xepoch) % WWV_SEC;
if (tmp2 == 0) {
syncnt++;
if (syncnt > SCMP && up->status & MSYNC && (up->status &
@@ -1489,9 +1476,9 @@ wwv_endpoc(
mepoch = xepoch;
syncnt = 0;
}
- if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & MSYNC))
- {
- sprintf(tbuf,
+ if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
+ MSYNC)) {
+ snprintf(tbuf, sizeof(tbuf),
"wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d",
up->status, up->gain, tepoch, up->epomax,
up->eposnr, tmp2, avgcnt, syncnt,
@@ -1551,16 +1538,16 @@ wwv_endpoc(
* to zero; if it decrements to -3, the interval is halved and
* the counter set to zero.
*/
- dtemp = (mepoch - zepoch) % SECOND;
+ dtemp = (mepoch - zepoch) % WWV_SEC;
if (up->status & FGATE) {
- if (abs(dtemp) < MAXFREQ * MINAVG) {
+ if (fabs(dtemp) < MAXFREQ * MINAVG) {
up->freq += (dtemp / 2.) / ((mcount - zcount) *
FCONST);
if (up->freq > MAXFREQ)
up->freq = MAXFREQ;
else if (up->freq < -MAXFREQ)
up->freq = -MAXFREQ;
- if (abs(dtemp) < MAXFREQ * MINAVG / 2.) {
+ if (fabs(dtemp) < MAXFREQ * MINAVG / 2.) {
if (avginc < 3) {
avginc++;
} else {
@@ -1582,11 +1569,11 @@ wwv_endpoc(
}
}
if (pp->sloppyclockflag & CLK_FLAG4) {
- sprintf(tbuf,
+ snprintf(tbuf, sizeof(tbuf),
"wwv2 %04x %5.0f %5.1f %5d %4d %4d %4d %4.0f %7.2f",
up->status, up->epomax, up->eposnr, mepoch,
up->avgint, maxrun, mcount - zcount, dtemp,
- up->freq * 1e6 / SECOND);
+ up->freq * 1e6 / WWV_SEC);
record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
if (debug)
@@ -1634,7 +1621,7 @@ wwv_epoch(
static double sigmin, sigzer, sigone, engmax, engmin;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Find the maximum minute sync pulse energy for both the
@@ -1708,7 +1695,7 @@ wwv_epoch(
* next pulse.
*/
up->rphase++;
- if (up->mphase % SECOND == up->repoch) {
+ if (up->mphase % WWV_SEC == up->repoch) {
up->status &= ~(DGATE | BGATE);
engmin = sqrt(up->irig * up->irig + up->qrig *
up->qrig);
@@ -1768,14 +1755,14 @@ wwv_rsec(
struct wwvunit *up;
struct chan *cp;
struct sync *sp, *rp;
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
int sw, arg, nsec;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
if (!iniflg) {
iniflg = 1;
- memset((char *)bitvec, 0, sizeof(bitvec));
+ ZERO(bitvec);
}
/*
@@ -1869,7 +1856,7 @@ wwv_rsec(
}
rp->metric = wwv_metric(rp);
if (pp->sloppyclockflag & CLK_FLAG4) {
- sprintf(tbuf,
+ snprintf(tbuf, sizeof(tbuf),
"wwv5 %04x %3d %4d %.0f/%.1f %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f",
up->status, up->gain, up->yepoch,
up->epomax, up->eposnr, up->datsig,
@@ -1887,35 +1874,28 @@ wwv_rsec(
up->errcnt = up->digcnt = up->alarm = 0;
/*
- * We now begin the minute scan. If not yet synchronized
- * to a station, restart if the units digit has not been
- * found within the DATA timeout (15 m) or if not
- * synchronized within the SYNCH timeout (40 m). After
- * synchronizing to a station, restart if no stations
- * are found within the PANIC timeout (2 days).
+ * If synchronized to a station, restart if no stations
+ * have been heard within the PANIC timeout (2 days). If
+ * not and the minute digit has been found, restart if
+ * not synchronized withing the SYNCH timeout (40 m). If
+ * not, restart if the unit digit has not been found
+ * within the DATA timeout (15 m).
*/
if (up->status & INSYNC) {
if (up->watch > PANIC) {
wwv_newgame(peer);
return;
}
- } else {
- if (!(up->status & DSYNC)) {
- if (up->watch > DATA) {
- wwv_newgame(peer);
- return;
- }
- }
+ } else if (up->status & DSYNC) {
if (up->watch > SYNCH) {
wwv_newgame(peer);
return;
}
+ } else if (up->watch > DATA) {
+ wwv_newgame(peer);
+ return;
}
wwv_newchan(peer);
-#ifdef ICOM
- if (up->fd_icom > 0)
- wwv_qsy(peer, up->dchan);
-#endif /* ICOM */
break;
/*
@@ -1987,7 +1967,7 @@ wwv_rsec(
/*
* Save the data channel gain, then QSY to the probe channel and
- * dim the seconds comb filters. The newchan() routine will
+ * dim the seconds comb filters. The www_newchan() routine will
* light them back up.
*/
case MSC21: /* 58 */
@@ -2041,7 +2021,7 @@ wwv_rsec(
}
if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
DSYNC)) {
- sprintf(tbuf,
+ snprintf(tbuf, sizeof(tbuf),
"wwv3 %2d %04x %3d %4d %5.0f %5.1f %5.0f %5.1f %5.0f",
nsec, up->status, up->gain, up->yepoch, up->epomax,
up->eposnr, up->datsig, up->datsnr, bit);
@@ -2075,7 +2055,7 @@ wwv_clock(
l_fp offset; /* offset in NTP seconds */
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
if (!(up->status & SSYNC))
up->alarm |= SYNERR;
if (up->digcnt < 9)
@@ -2107,11 +2087,12 @@ wwv_clock(
pp->disp = 0;
pp->lastref = up->timestamp;
refclock_process_offset(pp, offset,
- up->timestamp, PDELAY);
+ up->timestamp, PDELAY + up->pdelay);
refclock_receive(peer);
}
}
- pp->lencode = timecode(up, pp->a_lastcode);
+ pp->lencode = timecode(up, pp->a_lastcode,
+ sizeof(pp->a_lastcode));
record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
if (debug)
@@ -2122,12 +2103,12 @@ wwv_clock(
/*
- * wwv_corr4 - determine maximum likelihood digit
+ * wwv_corr4 - determine maximum-likelihood digit
*
* This routine correlates the received digit vector with the BCD
* coefficient vectors corresponding to all valid digits at the given
* position in the decoding matrix. The maximum value corresponds to the
- * maximum likelihood digit, while the ratio of this value to the next
+ * maximum-likelihood digit, while the ratio of this value to the next
* lower value determines the likelihood function. Note that, if the
* digit is invalid, the likelihood vector is averaged toward a miss.
*/
@@ -2143,12 +2124,12 @@ wwv_corr4(
struct wwvunit *up;
double topmax, nxtmax; /* metrics */
double acc; /* accumulator */
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
int mldigit; /* max likelihood digit */
int i, j;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Correlate digit vector with each BCD coefficient vector. If
@@ -2176,9 +2157,9 @@ wwv_corr4(
vp->digsnr = wwv_snr(topmax, nxtmax);
/*
- * The current maximum likelihood digit is compared to the last
- * maximum likelihood digit. If different, the compare counter
- * and maximum likelihood digit are reset. When the compare
+ * The current maximum-likelihood digit is compared to the last
+ * maximum-likelihood digit. If different, the compare counter
+ * and maximum-likelihood digit are reset. When the compare
* counter reaches the BCMP threshold (3), the digit is assumed
* correct. When the compare counter of all nine digits have
* reached threshold, the clock is assumed correct.
@@ -2188,34 +2169,31 @@ wwv_corr4(
* not considered correct until all nine clock digits have
* reached threshold. This is intended as eye candy, but avoids
* mistakes when the signal is low and the SNR is very marginal.
- * once correctly set, the maximum likelihood digit is ignored
- * on the assumption the clock will always be correct unless for
- * some reason it drifts to a different second.
*/
- vp->mldigit = mldigit;
if (vp->digprb < BTHR || vp->digsnr < BSNR) {
- vp->count = 0;
up->status |= BGATE;
} else {
- up->status |= DSYNC;
if (vp->digit != mldigit) {
- vp->count = 0;
up->alarm |= CMPERR;
- if (!(up->status & INSYNC))
+ if (vp->count > 0)
+ vp->count--;
+ if (vp->count == 0)
vp->digit = mldigit;
} else {
if (vp->count < BCMP)
vp->count++;
- else
+ if (vp->count == BCMP) {
+ up->status |= DSYNC;
up->digcnt++;
+ }
}
}
if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
INSYNC)) {
- sprintf(tbuf,
+ snprintf(tbuf, sizeof(tbuf),
"wwv4 %2d %04x %3d %4d %5.0f %2d %d %d %d %5.0f %5.1f",
up->rsec - 1, up->status, up->gain, up->yepoch,
- up->epomax, vp->radix, vp->digit, vp->mldigit,
+ up->epomax, vp->radix, vp->digit, mldigit,
vp->count, vp->digprb, vp->digsnr);
record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
@@ -2244,7 +2222,7 @@ wwv_tsec(
int temp;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Advance minute unit of the day. Don't propagate carries until
@@ -2326,7 +2304,7 @@ wwv_tsec(
* This routine rotates a likelihood vector one position and increments
* the clock digit modulo the radix. It returns the new clock digit or
* zero if a carry occurred. Once synchronized, the clock digit will
- * match the maximum likelihood digit corresponding to that position.
+ * match the maximum-likelihood digit corresponding to that position.
*/
static int
carry(
@@ -2420,16 +2398,14 @@ wwv_newchan(
struct wwvunit *up;
struct sync *sp, *rp;
double rank, dtemp;
- int i, j;
+ int i, j, rval;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Search all five station pairs looking for the channel with
- * maximum metric. If no station is found above thresholds, tune
- * to WWV on 15 MHz, set the reference ID to NONE and wait for
- * hotter ions.
+ * maximum metric.
*/
sp = NULL;
j = 0;
@@ -2453,39 +2429,57 @@ wwv_newchan(
/*
* If the strongest signal is less than the MTHR threshold (13),
- * we are beneath the waves, so squelch the second sync. If the
- * strongest signal is greater than the threshold, tune to that
- * frequency and transmitter QTH.
+ * we are beneath the waves, so squelch the second sync and
+ * advance to the next station. This makes sure all stations are
+ * scanned when the ions grow dim. If the strongest signal is
+ * greater than the threshold, tune to that frequency and
+ * transmitter QTH.
*/
+ up->status &= ~(SELV | SELH);
if (rank < MTHR) {
up->dchan = (up->dchan + 1) % NCHAN;
- up->status &= ~(SELV | SELH);
- return (FALSE);
+ if (up->status & METRIC) {
+ up->status &= ~METRIC;
+ refclock_report(peer, CEVNT_PROP);
+ }
+ rval = FALSE;
+ } else {
+ up->dchan = j;
+ up->sptr = sp;
+ memcpy(&pp->refid, sp->refid, 4);
+ peer->refid = pp->refid;
+ up->status |= METRIC;
+ if (sp->select & SELV) {
+ up->status |= SELV;
+ up->pdelay = pp->fudgetime1;
+ } else if (sp->select & SELH) {
+ up->status |= SELH;
+ up->pdelay = pp->fudgetime2;
+ } else {
+ up->pdelay = 0;
+ }
+ rval = TRUE;
}
- up->dchan = j;
- up->status |= SELV | SELH;
- up->sptr = sp;
- memcpy(&pp->refid, sp->refid, 4);
- peer->refid = pp->refid;
- return (TRUE);
+#ifdef ICOM
+ if (up->fd_icom > 0)
+ wwv_qsy(peer, up->dchan);
+#endif /* ICOM */
+ return (rval);
}
/*
* wwv_newgame - reset and start over
*
- * There are four conditions resulting in a new game:
- *
- * 1 During initial acquisition (MSYNC dark) going 6 minutes (ACQSN)
- * without reliably finding the minute pulse (MSYNC lit).
+ * There are three conditions resulting in a new game:
*
- * 2 After finding the minute pulse (MSYNC lit), going 15 minutes
+ * 1 After finding the minute pulse (MSYNC lit), going 15 minutes
* (DATA) without finding the unit seconds digit.
*
- * 3 After finding good data (DATA lit), going more than 40 minutes
+ * 2 After finding good data (DSYNC lit), going more than 40 minutes
* (SYNCH) without finding station sync (INSYNC lit).
*
- * 4 After finding station sync (INSYNC lit), going more than 2 days
+ * 3 After finding station sync (INSYNC lit), going more than 2 days
* (PANIC) without finding any station.
*/
static void
@@ -2499,12 +2493,14 @@ wwv_newgame(
int i;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Initialize strategic values. Note we set the leap bits
* NOTINSYNC and the refid "NONE".
*/
+ if (up->status)
+ up->errflg = CEVNT_TIMEOUT;
peer->leap = LEAP_NOTINSYNC;
up->watch = up->status = up->alarm = 0;
up->avgint = MINAVG;
@@ -2514,24 +2510,23 @@ wwv_newgame(
/*
* Initialize the station processes for audio gain, select bit,
* station/frequency identifier and reference identifier. Start
- * probing at the next channel after the data channel.
+ * probing at the strongest channel or the default channel if
+ * nothing heard.
*/
memset(up->mitig, 0, sizeof(up->mitig));
for (i = 0; i < NCHAN; i++) {
cp = &up->mitig[i];
cp->gain = up->gain;
cp->wwv.select = SELV;
- sprintf(cp->wwv.refid, "WV%.0f", floor(qsy[i]));
+ snprintf(cp->wwv.refid, sizeof(cp->wwv.refid), "WV%.0f",
+ floor(qsy[i]));
cp->wwvh.select = SELH;
- sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i]));
+ snprintf(cp->wwvh.refid, sizeof(cp->wwvh.refid), "WH%.0f",
+ floor(qsy[i]));
}
- up->dchan = (DCHAN + NCHAN - 1) % NCHAN;;
+ up->dchan = (DCHAN + NCHAN - 1) % NCHAN;
wwv_newchan(peer);
- up->achan = up->schan = up->dchan;
-#ifdef ICOM
- if (up->fd_icom > 0)
- wwv_qsy(peer, up->dchan);
-#endif /* ICOM */
+ up->schan = up->dchan;
}
/*
@@ -2577,7 +2572,7 @@ wwv_qsy(
struct wwvunit *up;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
if (up->fd_icom > 0) {
up->mitig[up->achan].gain = up->gain;
rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
@@ -2618,7 +2613,8 @@ wwv_qsy(
static int
timecode(
struct wwvunit *up, /* driver structure pointer */
- char *ptr /* target string */
+ char * tc, /* target string */
+ size_t tcsiz /* target max chars */
)
{
struct sync *sp;
@@ -2643,20 +2639,23 @@ timecode(
dut = up->misc & 0x7;
if (!(up->misc & DUTS))
dut = -dut;
- sprintf(ptr, "%c%1X", synchar, up->alarm);
- sprintf(cptr, " %4d %03d %02d:%02d:%02d %c%c %+d",
- year, day, hour, minute, second, leapchar, dst, dut);
- strcat(ptr, cptr);
+ snprintf(tc, tcsiz, "%c%1X", synchar, up->alarm);
+ snprintf(cptr, sizeof(cptr),
+ " %4d %03d %02d:%02d:%02d %c%c %+d",
+ year, day, hour, minute, second, leapchar, dst, dut);
+ strlcat(tc, cptr, tcsiz);
/*
* Specific variable-format fields
*/
sp = up->sptr;
- sprintf(cptr, " %d %d %s %.0f %d %.1f %d", up->watch,
- up->mitig[up->dchan].gain, sp->refid, sp->metric,
- up->errcnt, up->freq / SECOND * 1e6, up->avgint);
- strcat(ptr, cptr);
- return (strlen(ptr));
+ snprintf(cptr, sizeof(cptr), " %d %d %s %.0f %d %.1f %d",
+ up->watch, up->mitig[up->dchan].gain, sp->refid,
+ sp->metric, up->errcnt, up->freq / WWV_SEC * 1e6,
+ up->avgint);
+ strlcat(tc, cptr, tcsiz);
+
+ return strlen(tc);
}
@@ -2668,7 +2667,8 @@ timecode(
* there are no clips, the gain is bumped up; if there are more than
* MAXCLP clips (100), it is bumped down. The decoder is relatively
* insensitive to amplitude, so this crudity works just peachy. The
- * input port is set and the error flag is cleared, mostly to be ornery.
+ * routine also jiggles the input port and selectively mutes the
+ * monitor.
*/
static void
wwv_gain(
@@ -2679,7 +2679,7 @@ wwv_gain(
struct wwvunit *up;
pp = peer->procptr;
- up = (struct wwvunit *)pp->unitptr;
+ up = pp->unitptr;
/*
* Apparently, the codec uses only the high order bits of the
diff --git a/contrib/ntp/ntpd/refclock_wwvb.c b/contrib/ntp/ntpd/refclock_wwvb.c
index 7bddd3a..75897fc 100644
--- a/contrib/ntp/ntpd/refclock_wwvb.c
+++ b/contrib/ntp/ntpd/refclock_wwvb.c
@@ -17,6 +17,11 @@
#include <stdio.h>
#include <ctype.h>
+#ifdef HAVE_PPSAPI
+#include "ppsapi_timepps.h"
+#include "refclock_atom.h"
+#endif /* HAVE_PPSAPI */
+
/*
* This driver supports the Spectracom Model 8170 and Netclock/2 WWVB
* Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB
@@ -49,7 +54,7 @@
* hh:mm:ss = hours, minutes, seconds
* i = synchronization flag (' ' = in synch, '?' = out of synch)
*
- * The alarm condition is indicated by other than ' ' at a, which occurs
+ * The alarm condition is indicated by other than ' ' at i, which occurs
* during initial synchronization and when received signal is lost for
* about ten hours.
*
@@ -64,7 +69,7 @@
* ddd = day of year
* hh:mm:ss.fff = hours, minutes, seconds, milliseconds
*
- * The alarm condition is indicated by other than ' ' at a, which occurs
+ * The alarm condition is indicated by other than ' ' at i, which occurs
* during initial synchronization and when received signal is lost for
* about ten hours. The unlock condition is indicated by other than ' '
* at q.
@@ -84,6 +89,16 @@
* makes no attempt to correct for the intrinsic jitter of the radio
* itself, which is a known problem with the older radios.
*
+ * PPS Signal Processing
+ *
+ * When PPS signal processing is enabled, and when the system clock has
+ * been set by this or another driver and the PPS signal offset is
+ * within 0.4 s of the system clock offset, the PPS signal replaces the
+ * timecode for as long as the PPS signal is active. If for some reason
+ * the PPS signal fails for one or more poll intervals, the driver
+ * reverts to the timecode. If the timecode fails for one or more poll
+ * intervals, the PPS signal is disconnected.
+ *
* Fudge Factors
*
* This driver can retrieve a table of quality data maintained
@@ -100,20 +115,28 @@
#define DEVICE "/dev/wwvb%d" /* device name and unit */
#define SPEED232 B9600 /* uart speed (9600 baud) */
#define PRECISION (-13) /* precision assumed (about 100 us) */
+#define PPS_PRECISION (-13) /* precision assumed (about 100 us) */
#define REFID "WWVB" /* reference ID */
#define DESCRIPTION "Spectracom WWVB/GPS Receiver" /* WRU */
#define LENWWVB0 22 /* format 0 timecode length */
-#define LENWWVB1 22 /* format 1 timecode length */
#define LENWWVB2 24 /* format 2 timecode length */
-#define LENWWVB3 29 /* format 3 timecode length */
+#define LENWWVB3 29 /* format 3 timecode length */
#define MONLIN 15 /* number of monitoring lines */
/*
* WWVB unit control structure
*/
struct wwvbunit {
- l_fp laststamp; /* last receive timestamp */
+#ifdef HAVE_PPSAPI
+ struct refclock_atom atom; /* PPSAPI structure */
+ int ppsapi_tried; /* attempt PPSAPI once */
+ int ppsapi_lit; /* time_pps_create() worked */
+ int tcount; /* timecode sample counter */
+ int pcount; /* PPS sample counter */
+#endif /* HAVE_PPSAPI */
+ l_fp laststamp; /* last <CR> timestamp */
+ int prev_eol_cr; /* was last EOL <CR> (not <LF>)? */
u_char lasthour; /* last hour (for monitor) */
u_char linect; /* count ignored lines (for monitor */
};
@@ -121,11 +144,18 @@ struct wwvbunit {
/*
* Function prototypes
*/
-static int wwvb_start P((int, struct peer *));
-static void wwvb_shutdown P((int, struct peer *));
-static void wwvb_receive P((struct recvbuf *));
-static void wwvb_poll P((int, struct peer *));
-static void wwvb_timer P((int, struct peer *));
+static int wwvb_start (int, struct peer *);
+static void wwvb_shutdown (int, struct peer *);
+static void wwvb_receive (struct recvbuf *);
+static void wwvb_poll (int, struct peer *);
+static void wwvb_timer (int, struct peer *);
+#ifdef HAVE_PPSAPI
+static void wwvb_control (int, const struct refclockstat *,
+ struct refclockstat *, struct peer *);
+#define WWVB_CONTROL wwvb_control
+#else
+#define WWVB_CONTROL noentry
+#endif /* HAVE_PPSAPI */
/*
* Transfer vector
@@ -134,7 +164,7 @@ struct refclock refclock_wwvb = {
wwvb_start, /* start up driver */
wwvb_shutdown, /* shut down driver */
wwvb_poll, /* transmit poll message */
- noentry, /* not used (old wwvb_control) */
+ WWVB_CONTROL, /* fudge set/change notification */
noentry, /* initialize driver (not used) */
noentry, /* not used (old wwvb_buginfo) */
wwvb_timer /* called once per second */
@@ -158,37 +188,34 @@ wwvb_start(
/*
* Open serial port. Use CLK line discipline, if available.
*/
- sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, SPEED232, LDISC_CLK);
+ if (fd <= 0)
return (0);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct wwvbunit *)
- emalloc(sizeof(struct wwvbunit)))) {
- close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct wwvbunit));
+ up = emalloc_zero(sizeof(*up));
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
pp->io.clock_recv = wwvb_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
*/
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
+ memcpy(&pp->refid, REFID, 4);
return (1);
}
@@ -202,13 +229,15 @@ wwvb_shutdown(
struct peer *peer
)
{
- register struct wwvbunit *up;
- struct refclockproc *pp;
+ struct refclockproc * pp;
+ struct wwvbunit * up;
pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
}
@@ -237,9 +266,9 @@ wwvb_receive(
/*
* Initialize pointers and read the timecode and timestamp
*/
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
+ up = pp->unitptr;
temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
/*
@@ -251,13 +280,37 @@ wwvb_receive(
* reading precision is only to the millisecond. Thus, unless
* you have a PPS gadget and don't have to have the year, format
* 0 provides the lowest jitter.
+ * Save the timestamp of each <CR> in up->laststamp. Lines with
+ * no characters occur for every <LF>, and for some <CR>s when
+ * format 0 is used. Format 0 starts and ends each cycle with a
+ * <CR><LF> pair, format 2 starts each cycle with its only pair.
+ * The preceding <CR> is the on-time character for both formats.
+ * The timestamp provided with non-empty lines corresponds to
+ * the <CR> following the timecode, which is ultimately not used
+ * with format 0 and is used for the following timecode for
+ * format 2.
*/
if (temp == 0) {
- up->laststamp = trtmp;
+ if (up->prev_eol_cr) {
+ DPRINTF(2, ("wwvb: <LF> @ %s\n",
+ prettydate(&trtmp)));
+ } else {
+ up->laststamp = trtmp;
+ DPRINTF(2, ("wwvb: <CR> @ %s\n",
+ prettydate(&trtmp)));
+ }
+ up->prev_eol_cr = !up->prev_eol_cr;
return;
}
pp->lencode = temp;
pp->lastrec = up->laststamp;
+ up->laststamp = trtmp;
+ up->prev_eol_cr = TRUE;
+ DPRINTF(2, ("wwvb: code @ %s\n"
+ " using %s minus one char\n",
+ prettydate(&trtmp), prettydate(&pp->lastrec)));
+ if (L_ISZERO(&pp->lastrec))
+ return;
/*
* We get down to business, check the timecode format and decode
@@ -277,9 +330,11 @@ wwvb_receive(
if (sscanf(pp->a_lastcode,
"%c %3d %2d:%2d:%2d%c%cTZ=%2d",
&syncchar, &pp->day, &pp->hour, &pp->minute,
- &pp->second, &tmpchar, &dstchar, &tz) == 8)
+ &pp->second, &tmpchar, &dstchar, &tz) == 8) {
pp->nsec = 0;
break;
+ }
+ goto bad_format;
case LENWWVB2:
@@ -289,14 +344,19 @@ wwvb_receive(
"%c%c %2d %3d %2d:%2d:%2d.%3ld %c",
&syncchar, &qualchar, &pp->year, &pp->day,
&pp->hour, &pp->minute, &pp->second, &pp->nsec,
- &leapchar) == 9)
+ &leapchar) == 9) {
pp->nsec *= 1000000;
break;
+ }
+ goto bad_format;
case LENWWVB3:
- /*
+ /*
* Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#"
+ * WARNING: Undocumented, and the on-time character # is
+ * not yet handled correctly by this driver. It may be
+ * as simple as compensating for an additional 1/960 s.
*/
if (sscanf(pp->a_lastcode,
"0003%c %4d%2d%2d %2d%2d%2d+0000%c%c",
@@ -307,8 +367,10 @@ wwvb_receive(
pp->nsec = 0;
break;
}
+ goto bad_format;
default:
+ bad_format:
/*
* Unknown format: If dumping internal table, record
@@ -333,28 +395,28 @@ wwvb_receive(
*/
switch (qualchar) {
- case ' ':
+ case ' ':
pp->disp = .001;
pp->lastref = pp->lastrec;
break;
- case 'A':
+ case 'A':
pp->disp = .01;
break;
- case 'B':
+ case 'B':
pp->disp = .1;
break;
- case 'C':
+ case 'C':
pp->disp = .5;
break;
- case 'D':
+ case 'D':
pp->disp = MAXDISPERSE;
break;
- default:
+ default:
pp->disp = MAXDISPERSE;
refclock_report(peer, CEVNT_BADREPLY);
break;
@@ -368,12 +430,16 @@ wwvb_receive(
/*
* Process the new sample in the median filter and determine the
- * timecode timestamp.
+ * timecode timestamp, but only if the PPS is not in control.
*/
- if (!refclock_process(pp))
+#ifdef HAVE_PPSAPI
+ up->tcount++;
+ if (peer->flags & FLAG_PPS)
+ return;
+
+#endif /* HAVE_PPSAPI */
+ if (!refclock_process_f(pp, pp->fudgetime2))
refclock_report(peer, CEVNT_BADTIME);
- if (peer->disp > MAXDISTANCE)
- refclock_receive(peer);
}
@@ -389,6 +455,9 @@ wwvb_timer(
register struct wwvbunit *up;
struct refclockproc *pp;
char pollchar; /* character sent to clock */
+#ifdef DEBUG
+ l_fp now;
+#endif
/*
* Time to poll the clock. The Spectracom clock responds to a
@@ -398,13 +467,26 @@ wwvb_timer(
* the clock; all others just listen in.
*/
pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
+ up = pp->unitptr;
if (up->linect > 0)
pollchar = 'R';
else
pollchar = 'T';
if (write(pp->io.fd, &pollchar, 1) != 1)
refclock_report(peer, CEVNT_FAULT);
+#ifdef DEBUG
+ get_systime(&now);
+ if (debug)
+ printf("%c poll at %s\n", pollchar, prettydate(&now));
+#endif
+#ifdef HAVE_PPSAPI
+ if (up->ppsapi_lit &&
+ refclock_pps(peer, &up->atom, pp->sloppyclockflag) > 0) {
+ up->pcount++,
+ peer->flags |= FLAG_PPS;
+ peer->precision = PPS_PRECISION;
+ }
+#endif /* HAVE_PPSAPI */
}
@@ -425,7 +507,7 @@ wwvb_poll(
* are received, declare a timeout and keep going.
*/
pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
+ up = pp->unitptr;
pp->polls++;
/*
@@ -435,16 +517,29 @@ wwvb_poll(
if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour <
(int)up->lasthour)
up->linect = MONLIN;
- up->lasthour = pp->hour;
+ up->lasthour = (u_char)pp->hour;
/*
* Process median filter samples. If none received, declare a
* timeout and keep going.
*/
+#ifdef HAVE_PPSAPI
+ if (up->pcount == 0) {
+ peer->flags &= ~FLAG_PPS;
+ peer->precision = PRECISION;
+ }
+ if (up->tcount == 0) {
+ pp->coderecv = pp->codeproc;
+ refclock_report(peer, CEVNT_TIMEOUT);
+ return;
+ }
+ up->pcount = up->tcount = 0;
+#else /* HAVE_PPSAPI */
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
return;
}
+#endif /* HAVE_PPSAPI */
refclock_receive(peer);
record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
@@ -454,6 +549,55 @@ wwvb_poll(
#endif
}
+
+/*
+ * wwvb_control - fudge parameters have been set or changed
+ */
+#ifdef HAVE_PPSAPI
+static void
+wwvb_control(
+ int unit,
+ const struct refclockstat *in_st,
+ struct refclockstat *out_st,
+ struct peer *peer
+ )
+{
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = pp->unitptr;
+
+ if (!(pp->sloppyclockflag & CLK_FLAG1)) {
+ if (!up->ppsapi_tried)
+ return;
+ up->ppsapi_tried = 0;
+ if (!up->ppsapi_lit)
+ return;
+ peer->flags &= ~FLAG_PPS;
+ peer->precision = PRECISION;
+ time_pps_destroy(up->atom.handle);
+ up->atom.handle = 0;
+ up->ppsapi_lit = 0;
+ return;
+ }
+
+ if (up->ppsapi_tried)
+ return;
+ /*
+ * Light up the PPSAPI interface.
+ */
+ up->ppsapi_tried = 1;
+ if (refclock_ppsapi(pp->io.fd, &up->atom)) {
+ up->ppsapi_lit = 1;
+ return;
+ }
+
+ msyslog(LOG_WARNING, "%s flag1 1 but PPSAPI fails",
+ refnumtoa(&peer->srcadr));
+}
+#endif /* HAVE_PPSAPI */
+
#else
int refclock_wwvb_bs;
#endif /* REFCLOCK */
diff --git a/contrib/ntp/ntpd/refclock_zyfer.c b/contrib/ntp/ntpd/refclock_zyfer.c
index 44f2c4d..7b79da3 100644
--- a/contrib/ntp/ntpd/refclock_zyfer.c
+++ b/contrib/ntp/ntpd/refclock_zyfer.c
@@ -19,7 +19,9 @@
#include <stdio.h>
#include <ctype.h>
-#ifdef HAVE_SYS_TERMIOS_H
+#if defined(HAVE_TERMIOS_H)
+# include <termios.h>
+#elif defined(HAVE_SYS_TERMIOS_H)
# include <sys/termios.h>
#endif
#ifdef HAVE_SYS_PPSCLOCK_H
@@ -97,10 +99,10 @@ struct zyferunit {
/*
* Function prototypes
*/
-static int zyfer_start P((int, struct peer *));
-static void zyfer_shutdown P((int, struct peer *));
-static void zyfer_receive P((struct recvbuf *));
-static void zyfer_poll P((int, struct peer *));
+static int zyfer_start (int, struct peer *);
+static void zyfer_shutdown (int, struct peer *);
+static void zyfer_receive (struct recvbuf *);
+static void zyfer_poll (int, struct peer *);
/*
* Transfer vector
@@ -134,32 +136,30 @@ zyfer_start(
* Open serial port.
* Something like LDISC_ACTS that looked for ! would be nice...
*/
- (void)sprintf(device, DEVICE, unit);
- if ( !(fd = refclock_open(device, SPEED232, LDISC_RAW)) )
- return (0);
+ snprintf(device, sizeof(device), DEVICE, unit);
+ fd = refclock_open(device, SPEED232, LDISC_RAW);
+ if (fd <= 0)
+ return (0);
msyslog(LOG_NOTICE, "zyfer(%d) fd: %d dev <%s>", unit, fd, device);
/*
* Allocate and initialize unit structure
*/
- if (!(up = (struct zyferunit *)
- emalloc(sizeof(struct zyferunit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct zyferunit));
+ up = emalloc(sizeof(struct zyferunit));
+ memset(up, 0, sizeof(struct zyferunit));
pp = peer->procptr;
pp->io.clock_recv = zyfer_receive;
- pp->io.srcclock = (caddr_t)peer;
+ pp->io.srcclock = peer;
pp->io.datalen = 0;
pp->io.fd = fd;
if (!io_addclock(&pp->io)) {
- (void) close(fd);
+ close(fd);
+ pp->io.fd = -1;
free(up);
return (0);
}
- pp->unitptr = (caddr_t)up;
+ pp->unitptr = up;
/*
* Initialize miscellaneous variables
@@ -187,9 +187,11 @@ zyfer_shutdown(
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct zyferunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ up = pp->unitptr;
+ if (pp->io.fd != -1)
+ io_closeclock(&pp->io);
+ if (up != NULL)
+ free(up);
}
@@ -208,20 +210,10 @@ zyfer_receive(
int tfom; /* Time Figure Of Merit */
int omode; /* Operation mode */
u_char *p;
-#ifdef PPS
- struct ppsclockev ppsev;
- int request;
-#ifdef HAVE_CIOGETEV
- request = CIOGETEV;
-#endif
-#ifdef HAVE_TIOCGPPSEV
- request = TIOCGPPSEV;
-#endif
-#endif /* PPS */
- peer = (struct peer *)rbufp->recv_srcclock;
+ peer = rbufp->recv_peer;
pp = peer->procptr;
- up = (struct zyferunit *)pp->unitptr;
+ up = pp->unitptr;
p = (u_char *) &rbufp->recv_space;
/*
* If lencode is 0:
@@ -290,14 +282,7 @@ zyfer_receive(
pp->leap = LEAP_NOTINSYNC;
return;
}
-#ifdef PPS
- if(ioctl(fdpps,request,(caddr_t) &ppsev) >=0) {
- ppsev.tv.tv_sec += (u_int32) JAN_1970;
- TVTOTS(&ppsev.tv,&up->tstamp);
- }
- /* record the last ppsclock event time stamp */
- pp->lastrec = up->tstamp;
-#endif /* PPS */
+
if (!refclock_process(pp)) {
refclock_report(peer, CEVNT_BADTIME);
return;
@@ -332,7 +317,7 @@ zyfer_poll(
* side to capture a sample and check for timeouts.
*/
pp = peer->procptr;
- up = (struct zyferunit *)pp->unitptr;
+ up = pp->unitptr;
if (!up->pollcnt)
refclock_report(peer, CEVNT_TIMEOUT);
else
OpenPOWER on IntegriCloud