From 118e757284cbb8fc4f43a713e892b41504b50a5f Mon Sep 17 00:00:00 2001 From: roberto Date: Tue, 20 Jul 2004 15:01:56 +0000 Subject: Virgin import of ntpd 4.2.0 --- contrib/ntp/ntpd/Makefile.am | 28 +- contrib/ntp/ntpd/Makefile.in | 941 ++++--- contrib/ntp/ntpd/check_y2k.c | 3 + contrib/ntp/ntpd/cmd_args.c | 131 +- contrib/ntp/ntpd/ntp_config.c | 781 +++--- contrib/ntp/ntpd/ntp_control.c | 315 ++- contrib/ntp/ntpd/ntp_crypto.c | 4833 ++++++++++++++++++++++---------- contrib/ntp/ntpd/ntp_filegen.c | 8 +- contrib/ntp/ntpd/ntp_intres.c | 110 +- contrib/ntp/ntpd/ntp_io.c | 1933 ++++++++----- contrib/ntp/ntpd/ntp_loopfilter.c | 312 ++- contrib/ntp/ntpd/ntp_monitor.c | 144 +- contrib/ntp/ntpd/ntp_peer.c | 209 +- contrib/ntp/ntpd/ntp_proto.c | 2561 ++++++++++------- contrib/ntp/ntpd/ntp_refclock.c | 144 +- contrib/ntp/ntpd/ntp_request.c | 1143 +++++--- contrib/ntp/ntpd/ntp_restrict.c | 724 +++-- contrib/ntp/ntpd/ntp_timer.c | 88 +- contrib/ntp/ntpd/ntp_util.c | 420 ++- contrib/ntp/ntpd/ntpd.c | 248 +- contrib/ntp/ntpd/ntpsim.c | 368 +++ contrib/ntp/ntpd/refclock_acts.c | 5 +- contrib/ntp/ntpd/refclock_arbiter.c | 3 +- contrib/ntp/ntpd/refclock_arc.c | 372 ++- contrib/ntp/ntpd/refclock_as2201.c | 5 +- contrib/ntp/ntpd/refclock_atom.c | 28 +- contrib/ntp/ntpd/refclock_bancomm.c | 3 +- contrib/ntp/ntpd/refclock_chronolog.c | 4 +- contrib/ntp/ntpd/refclock_chu.c | 487 ++-- contrib/ntp/ntpd/refclock_conf.c | 2 +- contrib/ntp/ntpd/refclock_datum.c | 2 + contrib/ntp/ntpd/refclock_dumbclock.c | 20 +- contrib/ntp/ntpd/refclock_fg.c | 12 +- contrib/ntp/ntpd/refclock_gpsvme.c | 13 +- contrib/ntp/ntpd/refclock_heath.c | 68 +- contrib/ntp/ntpd/refclock_hopfpci.c | 21 +- contrib/ntp/ntpd/refclock_hopfser.c | 22 +- contrib/ntp/ntpd/refclock_hpgps.c | 1 + contrib/ntp/ntpd/refclock_irig.c | 363 ++- contrib/ntp/ntpd/refclock_jjy.c | 22 +- contrib/ntp/ntpd/refclock_jupiter.c | 1192 ++++---- contrib/ntp/ntpd/refclock_leitch.c | 1 + contrib/ntp/ntpd/refclock_local.c | 131 +- contrib/ntp/ntpd/refclock_msfees.c | 4 +- contrib/ntp/ntpd/refclock_mx4200.c | 26 +- contrib/ntp/ntpd/refclock_neoclock4x.c | 580 ++-- contrib/ntp/ntpd/refclock_nmea.c | 32 +- contrib/ntp/ntpd/refclock_oncore.c | 3901 ++++++++++++++++---------- contrib/ntp/ntpd/refclock_palisade.c | 87 +- contrib/ntp/ntpd/refclock_palisade.h | 1 + contrib/ntp/ntpd/refclock_parse.c | 36 +- contrib/ntp/ntpd/refclock_pcf.c | 5 +- contrib/ntp/ntpd/refclock_pst.c | 44 +- contrib/ntp/ntpd/refclock_ripencc.c | 10 +- contrib/ntp/ntpd/refclock_shm.c | 13 +- contrib/ntp/ntpd/refclock_tpro.c | 10 +- contrib/ntp/ntpd/refclock_trak.c | 1 + contrib/ntp/ntpd/refclock_true.c | 4 +- contrib/ntp/ntpd/refclock_ulink.c | 13 +- contrib/ntp/ntpd/refclock_usno.c | 5 +- contrib/ntp/ntpd/refclock_wwv.c | 2143 +++++++------- contrib/ntp/ntpd/refclock_wwvb.c | 37 +- 62 files changed, 15602 insertions(+), 9571 deletions(-) create mode 100644 contrib/ntp/ntpd/ntpsim.c (limited to 'contrib/ntp/ntpd') diff --git a/contrib/ntp/ntpd/Makefile.am b/contrib/ntp/ntpd/Makefile.am index 94dfd09..0fa4e21 100644 --- a/contrib/ntp/ntpd/Makefile.am +++ b/contrib/ntp/ntpd/Makefile.am @@ -1,31 +1,39 @@ #AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies AUTOMAKE_OPTIONS = ../util/ansi2knr -bin_PROGRAMS = ntpd -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/librsaref -# LDADD might need RESLIB and ADJLIB -LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@ +bin_PROGRAMS = ntpd @MAKE_NTPDSIM@ +noinst_LIBRARIES = libntpd.a +INCLUDES = -I$(top_srcdir)/include -I../include +# LDADD might need RESLIB and ADJLIB. +# If LIBPARSE, we need libntpd.a 2wagain afterwards... +LDADD = version.o libntpd.a @LIBPARSE@ libntpd.a # 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 +ntpd_LDADD = $(LDADD) ../libntp/libntp.a -lm @LCRYPTO@ +ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a -lm @LCRYPTO@ +ntpdsim_CFLAGS = $(CFLAGS) -DSIM +check_y2k_LDADD = $(LDADD) ../libntp/libntp.a DISTCLEANFILES = .version version.c #EXTRA_DIST = ntpd.mak ETAGS_ARGS = Makefile.am ### Y2Kfixes check_PROGRAMS = @MAKE_CHECK_Y2K@ -EXTRA_PROGRAMS = check_y2k +EXTRA_PROGRAMS = check_y2k ntpdsim 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 jupiter.h map_vme.c ntp_config.c ntp_control.c \ +ntpd_SOURCES = cmd_args.c ntp_config.c ntp_io.c ntpd.c +ntpdsim_SOURCES = $(ntpd_SOURCES) ntpsim.c +libntpd_a_SOURCES = jupiter.h map_vme.c ntp_control.c \ ntp_crypto.c ntp_filegen.c \ - ntp_intres.c ntp_io.c ntp_loopfilter.c ntp_monitor.c ntp_peer.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 ntpd.c \ + ntp_restrict.c ntp_timer.c ntp_util.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 \ @@ -47,6 +55,6 @@ $(PROGRAMS): $(LDADD) ../libparse/libparse.a: cd ../libparse && $(MAKE) -version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ @LIBRSAREF@ Makefile +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 diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in index 2622b3b..eef0774 100644 --- a/contrib/ntp/ntpd/Makefile.in +++ b/contrib/ntp/ntpd/Makefile.in @@ -1,6 +1,7 @@ -# Makefile.in generated automatically by automake 1.5 from Makefile.am. +# Makefile.in generated by automake 1.7.7 from Makefile.am. +# @configure_input@ -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 # Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -13,82 +14,79 @@ @SET_MAKE@ -#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies - -SHELL = @SHELL@ - srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -mandir = @mandir@ -includedir = @includedir@ -oldincludedir = /usr/include pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. -ACLOCAL = @ACLOCAL@ -AUTOCONF = @AUTOCONF@ -AUTOMAKE = @AUTOMAKE@ -AUTOHEADER = @AUTOHEADER@ - +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) -transform = @program_transform_name@ +transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : -build_alias = @build_alias@ build_triplet = @build@ -host_alias = @host_alias@ host_triplet = @host@ -target_alias = @target_alias@ target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ -AUTOKEY = @AUTOKEY@ +ARLIB_DIR = @ARLIB_DIR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ +CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHUTEST = @CHUTEST@ CLKTEST = @CLKTEST@ CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ DCFD = @DCFD@ +DEFS = @DEFS@ DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ EF_LIBS = @EF_LIBS@ EF_PROGS = @EF_PROGS@ +EGREP = @EGREP@ EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCRYPTO = @LCRYPTO@ LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ LIBPARSE = @LIBPARSE@ -LIBRSAREF = @LIBRSAREF@ +LIBS = @LIBS@ LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ MAKE_ADJTIMED = @MAKE_ADJTIMED@ MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBNTPSIM = @MAKE_LIBNTPSIM@ MAKE_LIBPARSE = @MAKE_LIBPARSE@ MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ -MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPDSIM = @MAKE_NTPDSIM@ MAKE_NTPTIME = @MAKE_NTPTIME@ -MAKE_NTP_GENKEYS = @MAKE_NTP_GENKEYS@ +MAKE_NTP_KEYGEN = @MAKE_NTP_KEYGEN@ MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_SNTP = @MAKE_SNTP@ MAKE_TICKADJ = @MAKE_TICKADJ@ MAKE_TIMETRIM = @MAKE_TIMETRIM@ OBJEXT = @OBJEXT@ @@ -96,45 +94,97 @@ OPENSSL = @OPENSSL@ OPENSSL_INC = @OPENSSL_INC@ OPENSSL_LIB = @OPENSSL_LIB@ PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_PERL = @PATH_PERL@ +PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SH = @PATH_SH@ PROPDELAY = @PROPDELAY@ RANLIB = @RANLIB@ -RSADIR = @RSADIR@ -RSAOBJS = @RSAOBJS@ -RSAREF = @RSAREF@ -RSASRCS = @RSASRCS@ +READLINE_LIBS = @READLINE_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ TESTDCF = @TESTDCF@ U = @U@ VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__include = @am__include@ +am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies AUTOMAKE_OPTIONS = ../util/ansi2knr -bin_PROGRAMS = ntpd -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/librsaref -# LDADD might need RESLIB and ADJLIB -LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@ +bin_PROGRAMS = ntpd @MAKE_NTPDSIM@ +noinst_LIBRARIES = libntpd.a +INCLUDES = -I$(top_srcdir)/include -I../include +# LDADD might need RESLIB and ADJLIB. +# If LIBPARSE, we need libntpd.a 2wagain afterwards... +LDADD = version.o libntpd.a @LIBPARSE@ libntpd.a # 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 +ntpd_LDADD = $(LDADD) ../libntp/libntp.a -lm @LCRYPTO@ +ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a -lm @LCRYPTO@ +ntpdsim_CFLAGS = $(CFLAGS) -DSIM +check_y2k_LDADD = $(LDADD) ../libntp/libntp.a DISTCLEANFILES = .version version.c #EXTRA_DIST = ntpd.mak ETAGS_ARGS = Makefile.am ### Y2Kfixes check_PROGRAMS = @MAKE_CHECK_Y2K@ -EXTRA_PROGRAMS = check_y2k +EXTRA_PROGRAMS = check_y2k ntpdsim +# 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 jupiter.h map_vme.c ntp_config.c ntp_control.c \ +ntpd_SOURCES = cmd_args.c ntp_config.c ntp_io.c ntpd.c +ntpdsim_SOURCES = $(ntpd_SOURCES) ntpsim.c +libntpd_a_SOURCES = jupiter.h map_vme.c ntp_control.c \ ntp_crypto.c ntp_filegen.c \ - ntp_intres.c ntp_io.c ntp_loopfilter.c ntp_monitor.c ntp_peer.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 ntpd.c \ + ntp_restrict.c ntp_timer.c ntp_util.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 \ @@ -149,122 +199,143 @@ ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.c ntp_control.c \ refclock_zyfer.c refclock_ripencc.c refclock_neoclock4x.c subdir = ntpd +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = -EXTRA_PROGRAMS = check_y2k$(EXEEXT) -bin_PROGRAMS = ntpd$(EXEEXT) +LIBRARIES = $(noinst_LIBRARIES) + +libntpd_a_AR = $(AR) cru +libntpd_a_LIBADD = +am_libntpd_a_OBJECTS = map_vme$U.$(OBJEXT) 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_msfees$U.$(OBJEXT) refclock_mx4200$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_ptbacts$U.$(OBJEXT) refclock_shm$U.$(OBJEXT) \ + refclock_tpro$U.$(OBJEXT) refclock_trak$U.$(OBJEXT) \ + refclock_true$U.$(OBJEXT) refclock_tt560$U.$(OBJEXT) \ + refclock_ulink$U.$(OBJEXT) refclock_usno$U.$(OBJEXT) \ + refclock_wwv$U.$(OBJEXT) refclock_wwvb$U.$(OBJEXT) \ + refclock_zyfer$U.$(OBJEXT) refclock_ripencc$U.$(OBJEXT) \ + refclock_neoclock4x$U.$(OBJEXT) +libntpd_a_OBJECTS = $(am_libntpd_a_OBJECTS) +EXTRA_PROGRAMS = check_y2k$(EXEEXT) ntpdsim$(EXEEXT) +bin_PROGRAMS = ntpd$(EXEEXT) @MAKE_NTPDSIM@ check_PROGRAMS = @MAKE_CHECK_Y2K@ PROGRAMS = $(bin_PROGRAMS) check_y2k_SOURCES = check_y2k.c check_y2k_OBJECTS = check_y2k$U.$(OBJEXT) -check_y2k_LDADD = $(LDADD) -check_y2k_DEPENDENCIES = version.o ../libntp/libntp.a +check_y2k_DEPENDENCIES = version.o libntpd.a libntpd.a \ + ../libntp/libntp.a check_y2k_LDFLAGS = -am_ntpd_OBJECTS = cmd_args$U.$(OBJEXT) map_vme$U.$(OBJEXT) \ - ntp_config$U.$(OBJEXT) ntp_control$U.$(OBJEXT) \ - ntp_crypto$U.$(OBJEXT) ntp_filegen$U.$(OBJEXT) \ - ntp_intres$U.$(OBJEXT) ntp_io$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) ntpd$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_msfees$U.$(OBJEXT) \ - refclock_mx4200$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_ptbacts$U.$(OBJEXT) \ - refclock_shm$U.$(OBJEXT) refclock_tpro$U.$(OBJEXT) \ - refclock_trak$U.$(OBJEXT) refclock_true$U.$(OBJEXT) \ - refclock_tt560$U.$(OBJEXT) refclock_ulink$U.$(OBJEXT) \ - refclock_usno$U.$(OBJEXT) refclock_wwv$U.$(OBJEXT) \ - refclock_wwvb$U.$(OBJEXT) refclock_zyfer$U.$(OBJEXT) \ - refclock_ripencc$U.$(OBJEXT) refclock_neoclock4x$U.$(OBJEXT) +am_ntpd_OBJECTS = cmd_args$U.$(OBJEXT) ntp_config$U.$(OBJEXT) \ + ntp_io$U.$(OBJEXT) ntpd$U.$(OBJEXT) ntpd_OBJECTS = $(am_ntpd_OBJECTS) -ntpd_DEPENDENCIES = version.o ../libntp/libntp.a +ntpd_DEPENDENCIES = version.o libntpd.a libntpd.a ../libntp/libntp.a ntpd_LDFLAGS = +am__objects_1 = ntpdsim-cmd_args$U.$(OBJEXT) \ + ntpdsim-ntp_config$U.$(OBJEXT) ntpdsim-ntp_io$U.$(OBJEXT) \ + ntpdsim-ntpd$U.$(OBJEXT) +am_ntpdsim_OBJECTS = $(am__objects_1) ntpdsim-ntpsim$U.$(OBJEXT) +ntpdsim_OBJECTS = $(am_ntpdsim_OBJECTS) +ntpdsim_DEPENDENCIES = version.o libntpd.a libntpd.a \ + ../libntp/libntpsim.a +ntpdsim_LDFLAGS = -DEFS = @DEFS@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ depcomp = $(SHELL) $(top_srcdir)/depcomp -@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/check_y2k$U.Po $(DEPDIR)/cmd_args$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/map_vme$U.Po $(DEPDIR)/ntp_config$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_control$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_crypto$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_filegen$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_intres$U.Po $(DEPDIR)/ntp_io$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_loopfilter$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_monitor$U.Po $(DEPDIR)/ntp_peer$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_proto$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_refclock$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_request$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_restrict$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntp_timer$U.Po $(DEPDIR)/ntp_util$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/ntpd$U.Po $(DEPDIR)/refclock_acts$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_arbiter$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_arc$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_as2201$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_atom$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_bancomm$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_chronolog$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_chu$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_conf$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_datum$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_dumbclock$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_fg$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_gpsvme$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_heath$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_hopfpci$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_hopfser$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_hpgps$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_irig$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_jjy$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_jupiter$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_leitch$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_local$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_msfees$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_mx4200$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_neoclock4x$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_nmea$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_oncore$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_palisade$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_parse$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_pcf$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_pst$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_ptbacts$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_ripencc$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_shm$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_tpro$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_trak$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_true$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_tt560$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_ulink$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_usno$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_wwv$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_wwvb$U.Po \ -@AMDEP_TRUE@ $(DEPDIR)/refclock_zyfer$U.Po +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/check_y2k$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/cmd_args$U.Po ./$(DEPDIR)/map_vme$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_config$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_control$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_crypto$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_filegen$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_intres$U.Po ./$(DEPDIR)/ntp_io$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_loopfilter$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_monitor$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_peer$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_proto$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_refclock$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_request$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_restrict$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_timer$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntp_util$U.Po ./$(DEPDIR)/ntpd$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-cmd_args$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntp_config$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntp_io$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntpd$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntpsim$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_acts$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_arbiter$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_arc$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_as2201$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_atom$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_bancomm$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_chronolog$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_chu$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_conf$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_datum$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_dumbclock$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_fg$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_gpsvme$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_heath$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_hopfpci$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_hopfser$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_hpgps$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_irig$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_jjy$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_jupiter$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_leitch$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_local$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_msfees$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_mx4200$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_neoclock4x$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_nmea$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_oncore$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_palisade$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_parse$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_pcf$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_pst$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_ptbacts$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_ripencc$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_shm$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_tpro$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_trak$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_true$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_tt560$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_ulink$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_usno$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_wwv$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_wwvb$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/refclock_zyfer$U.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -DIST_SOURCES = check_y2k.c $(ntpd_SOURCES) -DIST_COMMON = Makefile.am Makefile.in -SOURCES = check_y2k.c $(ntpd_SOURCES) +DIST_SOURCES = $(libntpd_a_SOURCES) check_y2k.c $(ntpd_SOURCES) \ + $(ntpdsim_SOURCES) +DIST_COMMON = $(srcdir)/Makefile.in Makefile.am +SOURCES = $(libntpd_a_SOURCES) check_y2k.c $(ntpd_SOURCES) $(ntpdsim_SOURCES) all: all-am @@ -274,9 +345,17 @@ $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && \ $(AUTOMAKE) --gnu ntpd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && \ - CONFIG_HEADERS= CONFIG_LINKS= \ - CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +AR = ar + +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 +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(bindir) @@ -284,16 +363,16 @@ install-binPROGRAMS: $(bin_PROGRAMS) p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ - f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f"; \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f; \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ else :; fi; \ done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ rm -f $(DESTDIR)$(bindir)/$$f; \ done @@ -309,6 +388,9 @@ check_y2k$(EXEEXT): $(check_y2k_OBJECTS) $(check_y2k_DEPENDENCIES) ntpd$(EXEEXT): $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES) @rm -f ntpd$(EXEEXT) $(LINK) $(ntpd_LDFLAGS) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS) +ntpdsim$(EXEEXT): $(ntpdsim_OBJECTS) $(ntpdsim_DEPENDENCIES) + @rm -f ntpdsim$(EXEEXT) + $(LINK) $(ntpdsim_LDFLAGS) $(ntpdsim_OBJECTS) $(ntpdsim_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) core *.core @@ -321,287 +403,442 @@ ANSI2KNR = ../util/ansi2knr cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr mostlyclean-kr: - -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)/map_vme$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)/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_msfees$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_ptbacts$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_trak$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_usno$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@ - -distclean-depend: - -rm -rf $(DEPDIR) + -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)/map_vme$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)/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-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_msfees$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_ptbacts$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_trak$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_usno$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@ .c.o: -@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ - $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$< +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< .c.obj: -@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ - $(COMPILE) -c `cygpath -w $<` -CCDEPMODE = @CCDEPMODE@ +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +ntpdsim-cmd_args$U.o: cmd_args$U.c +@am__fastdepCC_TRUE@ if $(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" \ +@am__fastdepCC_TRUE@ -c -o ntpdsim-cmd_args$U.o `test -f 'cmd_args$U.c' || echo '$(srcdir)/'`cmd_args$U.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo" "$(DEPDIR)/ntpdsim-cmd_args$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmd_args$U.c' object='ntpdsim-cmd_args$U.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-cmd_args$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-cmd_args$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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 + +ntpdsim-cmd_args$U.obj: cmd_args$U.c +@am__fastdepCC_TRUE@ if $(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" \ +@am__fastdepCC_TRUE@ -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@ then mv -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo" "$(DEPDIR)/ntpdsim-cmd_args$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmd_args$U.c' object='ntpdsim-cmd_args$U.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-cmd_args$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-cmd_args$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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` + +ntpdsim-ntp_config$U.o: ntp_config$U.c +@am__fastdepCC_TRUE@ if $(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" \ +@am__fastdepCC_TRUE@ -c -o ntpdsim-ntp_config$U.o `test -f 'ntp_config$U.c' || echo '$(srcdir)/'`ntp_config$U.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_config$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_config$U.c' object='ntpdsim-ntp_config$U.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_config$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_config$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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 + +ntpdsim-ntp_config$U.obj: ntp_config$U.c +@am__fastdepCC_TRUE@ if $(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" \ +@am__fastdepCC_TRUE@ -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@ then mv -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_config$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_config$U.c' object='ntpdsim-ntp_config$U.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_config$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_config$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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` + +ntpdsim-ntp_io$U.o: ntp_io$U.c +@am__fastdepCC_TRUE@ if $(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" \ +@am__fastdepCC_TRUE@ -c -o ntpdsim-ntp_io$U.o `test -f 'ntp_io$U.c' || echo '$(srcdir)/'`ntp_io$U.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_io$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_io$U.c' object='ntpdsim-ntp_io$U.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_io$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_io$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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 + +ntpdsim-ntp_io$U.obj: ntp_io$U.c +@am__fastdepCC_TRUE@ if $(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" \ +@am__fastdepCC_TRUE@ -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@ then mv -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_io$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_io$U.c' object='ntpdsim-ntp_io$U.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_io$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_io$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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` + +ntpdsim-ntpd$U.o: ntpd$U.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" \ +@am__fastdepCC_TRUE@ -c -o ntpdsim-ntpd$U.o `test -f 'ntpd$U.c' || echo '$(srcdir)/'`ntpd$U.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" "$(DEPDIR)/ntpdsim-ntpd$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd$U.c' object='ntpdsim-ntpd$U.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpd$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpd$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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 + +ntpdsim-ntpd$U.obj: ntpd$U.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" \ +@am__fastdepCC_TRUE@ -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@ then mv -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" "$(DEPDIR)/ntpdsim-ntpd$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd$U.c' object='ntpdsim-ntpd$U.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpd$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpd$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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` + +ntpdsim-ntpsim$U.o: ntpsim$U.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" \ +@am__fastdepCC_TRUE@ -c -o ntpdsim-ntpsim$U.o `test -f 'ntpsim$U.c' || echo '$(srcdir)/'`ntpsim$U.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" "$(DEPDIR)/ntpdsim-ntpsim$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpsim$U.c' object='ntpdsim-ntpsim$U.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpsim$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpsim$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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 + +ntpdsim-ntpsim$U.obj: ntpsim$U.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" \ +@am__fastdepCC_TRUE@ -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@ then mv -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" "$(DEPDIR)/ntpdsim-ntpsim$U.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpsim$U.c' object='ntpdsim-ntpsim$U.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpsim$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpsim$U.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(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` 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) > check_y2k_.c || rm -f check_y2k_.c + $(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) > cmd_args_.c || rm -f cmd_args_.c + $(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 $@ map_vme_.c: map_vme.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/map_vme.c; then echo $(srcdir)/map_vme.c; else echo map_vme.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > map_vme_.c || rm -f map_vme_.c + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/map_vme.c; then echo $(srcdir)/map_vme.c; else echo map_vme.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) > ntp_config_.c || rm -f ntp_config_.c + $(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) > ntp_control_.c || rm -f ntp_control_.c + $(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) > ntp_crypto_.c || rm -f ntp_crypto_.c + $(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) > ntp_filegen_.c || rm -f ntp_filegen_.c + $(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) > ntp_intres_.c || rm -f ntp_intres_.c + $(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) > ntp_io_.c || rm -f ntp_io_.c + $(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) > ntp_loopfilter_.c || rm -f ntp_loopfilter_.c + $(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) > ntp_monitor_.c || rm -f ntp_monitor_.c + $(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) > ntp_peer_.c || rm -f ntp_peer_.c + $(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) > ntp_proto_.c || rm -f ntp_proto_.c + $(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) > ntp_refclock_.c || rm -f ntp_refclock_.c + $(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) > ntp_request_.c || rm -f ntp_request_.c + $(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) > ntp_restrict_.c || rm -f ntp_restrict_.c + $(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) > ntp_timer_.c || rm -f ntp_timer_.c + $(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) > ntp_util_.c || rm -f ntp_util_.c + $(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) > ntpd_.c || rm -f ntpd_.c + $(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 $@ +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) > refclock_acts_.c || rm -f refclock_acts_.c + $(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) > refclock_arbiter_.c || rm -f refclock_arbiter_.c + $(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) > refclock_arc_.c || rm -f refclock_arc_.c + $(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) > refclock_as2201_.c || rm -f refclock_as2201_.c + $(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) > refclock_atom_.c || rm -f refclock_atom_.c + $(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) > refclock_bancomm_.c || rm -f refclock_bancomm_.c + $(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) > refclock_chronolog_.c || rm -f refclock_chronolog_.c + $(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) > refclock_chu_.c || rm -f refclock_chu_.c + $(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) > refclock_conf_.c || rm -f refclock_conf_.c + $(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) > refclock_datum_.c || rm -f refclock_datum_.c + $(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) > refclock_dumbclock_.c || rm -f refclock_dumbclock_.c + $(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) > refclock_fg_.c || rm -f refclock_fg_.c + $(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) > refclock_gpsvme_.c || rm -f refclock_gpsvme_.c + $(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) > refclock_heath_.c || rm -f refclock_heath_.c + $(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) > refclock_hopfpci_.c || rm -f refclock_hopfpci_.c + $(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) > refclock_hopfser_.c || rm -f refclock_hopfser_.c + $(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) > refclock_hpgps_.c || rm -f refclock_hpgps_.c + $(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) > refclock_irig_.c || rm -f refclock_irig_.c + $(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) > refclock_jjy_.c || rm -f refclock_jjy_.c + $(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) > refclock_jupiter_.c || rm -f refclock_jupiter_.c + $(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) > refclock_leitch_.c || rm -f refclock_leitch_.c + $(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) > refclock_local_.c || rm -f refclock_local_.c + $(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_msfees_.c: refclock_msfees.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_msfees.c; then echo $(srcdir)/refclock_msfees.c; else echo refclock_msfees.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_msfees_.c || rm -f refclock_msfees_.c + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_msfees.c; then echo $(srcdir)/refclock_msfees.c; else echo refclock_msfees.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) > refclock_mx4200_.c || rm -f refclock_mx4200_.c + $(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) > refclock_neoclock4x_.c || rm -f refclock_neoclock4x_.c + $(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) > refclock_nmea_.c || rm -f refclock_nmea_.c + $(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) > refclock_oncore_.c || rm -f refclock_oncore_.c + $(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) > refclock_palisade_.c || rm -f refclock_palisade_.c + $(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) > refclock_parse_.c || rm -f refclock_parse_.c + $(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) > refclock_pcf_.c || rm -f refclock_pcf_.c + $(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) > refclock_pst_.c || rm -f refclock_pst_.c + $(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_ptbacts_.c: refclock_ptbacts.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ptbacts.c; then echo $(srcdir)/refclock_ptbacts.c; else echo refclock_ptbacts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_ptbacts_.c || rm -f refclock_ptbacts_.c + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ptbacts.c; then echo $(srcdir)/refclock_ptbacts.c; else echo refclock_ptbacts.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) > refclock_ripencc_.c || rm -f refclock_ripencc_.c + $(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) > refclock_shm_.c || rm -f refclock_shm_.c + $(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) > refclock_tpro_.c || rm -f refclock_tpro_.c + $(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_trak_.c: refclock_trak.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_trak.c; then echo $(srcdir)/refclock_trak.c; else echo refclock_trak.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_trak_.c || rm -f refclock_trak_.c + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_trak.c; then echo $(srcdir)/refclock_trak.c; else echo refclock_trak.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) > refclock_true_.c || rm -f refclock_true_.c + $(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) > refclock_tt560_.c || rm -f refclock_tt560_.c + $(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) > refclock_ulink_.c || rm -f refclock_ulink_.c + $(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_usno_.c: refclock_usno.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_usno.c; then echo $(srcdir)/refclock_usno.c; else echo refclock_usno.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_usno_.c || rm -f refclock_usno_.c + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_usno.c; then echo $(srcdir)/refclock_usno.c; else echo refclock_usno.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) > refclock_wwv_.c || rm -f refclock_wwv_.c + $(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) > refclock_wwvb_.c || rm -f refclock_wwvb_.c + $(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) > refclock_zyfer_.c || rm -f refclock_zyfer_.c + $(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) cmd_args_.$(OBJEXT) map_vme_.$(OBJEXT) \ ntp_config_.$(OBJEXT) ntp_control_.$(OBJEXT) ntp_crypto_.$(OBJEXT) \ ntp_filegen_.$(OBJEXT) ntp_intres_.$(OBJEXT) ntp_io_.$(OBJEXT) \ ntp_loopfilter_.$(OBJEXT) ntp_monitor_.$(OBJEXT) ntp_peer_.$(OBJEXT) \ ntp_proto_.$(OBJEXT) ntp_refclock_.$(OBJEXT) ntp_request_.$(OBJEXT) \ ntp_restrict_.$(OBJEXT) ntp_timer_.$(OBJEXT) ntp_util_.$(OBJEXT) \ -ntpd_.$(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_gpsvme_.$(OBJEXT) refclock_heath_.$(OBJEXT) \ -refclock_hopfpci_.$(OBJEXT) refclock_hopfser_.$(OBJEXT) \ -refclock_hpgps_.$(OBJEXT) refclock_irig_.$(OBJEXT) \ -refclock_jjy_.$(OBJEXT) refclock_jupiter_.$(OBJEXT) \ -refclock_leitch_.$(OBJEXT) refclock_local_.$(OBJEXT) \ -refclock_msfees_.$(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_ptbacts_.$(OBJEXT) \ -refclock_ripencc_.$(OBJEXT) refclock_shm_.$(OBJEXT) \ -refclock_tpro_.$(OBJEXT) refclock_trak_.$(OBJEXT) \ -refclock_true_.$(OBJEXT) refclock_tt560_.$(OBJEXT) \ -refclock_ulink_.$(OBJEXT) refclock_usno_.$(OBJEXT) \ -refclock_wwv_.$(OBJEXT) refclock_wwvb_.$(OBJEXT) \ -refclock_zyfer_.$(OBJEXT) : $(ANSI2KNR) +ntpd_.$(OBJEXT) ntpsim_.$(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_gpsvme_.$(OBJEXT) \ +refclock_heath_.$(OBJEXT) refclock_hopfpci_.$(OBJEXT) \ +refclock_hopfser_.$(OBJEXT) refclock_hpgps_.$(OBJEXT) \ +refclock_irig_.$(OBJEXT) refclock_jjy_.$(OBJEXT) \ +refclock_jupiter_.$(OBJEXT) refclock_leitch_.$(OBJEXT) \ +refclock_local_.$(OBJEXT) refclock_msfees_.$(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_ptbacts_.$(OBJEXT) refclock_ripencc_.$(OBJEXT) \ +refclock_shm_.$(OBJEXT) refclock_tpro_.$(OBJEXT) \ +refclock_trak_.$(OBJEXT) refclock_true_.$(OBJEXT) \ +refclock_tt560_.$(OBJEXT) refclock_ulink_.$(OBJEXT) \ +refclock_usno_.$(OBJEXT) refclock_wwv_.$(OBJEXT) \ +refclock_wwvb_.$(OBJEXT) refclock_zyfer_.$(OBJEXT) : $(ANSI2KNR) uninstall-info-am: +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(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; } \ END { for (i in files) print i; }'`; \ - mkid -fID $$unique $(LISP) + mkid -fID $$unique TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(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; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ - || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique GTAGS: - here=`CDPATH=: && cd $(top_builddir) && pwd` \ + here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH - + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) top_distdir = .. distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) distdir: $(DISTFILES) - @for file in $(DISTFILES); do \ - if test -f $$file; then d=.; else d=$(srcdir); fi; \ + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - $(mkinstalldirs) "$(distdir)/$$dir"; \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ fi; \ if test -d $$d/$$file; then \ - cp -pR $$d/$$file $(distdir) \ - || exit 1; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ @@ -612,11 +849,10 @@ check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am -all-am: Makefile $(PROGRAMS) +all-am: Makefile $(LIBRARIES) $(PROGRAMS) installdirs: $(mkinstalldirs) $(DESTDIR)$(bindir) - install: install-am install-exec: install-exec-am install-data: install-data-am @@ -628,6 +864,7 @@ install-am: all-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: @@ -635,7 +872,7 @@ mostlyclean-generic: clean-generic: distclean-generic: - -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]* + -rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @@ -644,12 +881,14 @@ maintainer-clean-generic: clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ - mostlyclean-am + clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-depend \ - distclean-generic distclean-tags +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags dvi: dvi-am @@ -670,6 +909,8 @@ install-man: installcheck-am: maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -677,19 +918,27 @@ mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + uninstall-am: uninstall-binPROGRAMS uninstall-info-am -.PHONY: GTAGS all all-am check check-am check-local clean \ - clean-binPROGRAMS clean-checkPROGRAMS clean-generic distclean \ - distclean-compile distclean-depend distclean-generic \ - distclean-tags distdir dvi dvi-am info info-am install \ - install-am install-binPROGRAMS install-data install-data-am \ - install-exec install-exec-am install-info install-info-am \ - install-man install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-kr tags uninstall uninstall-am \ - uninstall-binPROGRAMS uninstall-info-am +.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-kr pdf pdf-am ps ps-am tags \ + uninstall uninstall-am uninstall-binPROGRAMS uninstall-info-am check-local: @MAKE_CHECK_Y2K@ @@ -703,7 +952,7 @@ $(PROGRAMS): $(LDADD) ../libparse/libparse.a: cd ../libparse && $(MAKE) -version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ @LIBRSAREF@ Makefile +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 # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/contrib/ntp/ntpd/check_y2k.c b/contrib/ntp/ntpd/check_y2k.c index f0f4480..6b83115 100644 --- a/contrib/ntp/ntpd/check_y2k.c +++ b/contrib/ntp/ntpd/check_y2k.c @@ -45,6 +45,9 @@ # if !defined(VMS) /*wjm*/ # include # endif /* VMS */ +# if HAVE_SYS_SIGNAL_H +# include +# endif /* HAVE_SYS_SIGNAL_H */ # include # ifdef HAVE_SYS_IOCTL_H # include diff --git a/contrib/ntp/ntpd/cmd_args.c b/contrib/ntp/ntpd/cmd_args.c index 9f61b4a..3ed9b66 100644 --- a/contrib/ntp/ntpd/cmd_args.c +++ b/contrib/ntp/ntpd/cmd_args.c @@ -9,13 +9,21 @@ #include "ntp_stdlib.h" #include "ntp_cmdargs.h" +#ifdef SIM +#include "ntpsim.h" +#endif /* SIM */ + /* * Definitions of things either imported from or exported to outside */ extern char const *progname; -int listen_to_virtual_ips = 0; +int listen_to_virtual_ips = 1; + +#ifdef SYS_WINNT +extern BOOL NoWinService; +#endif -static const char *ntp_options = "aAbc:dD:f:gk:l:LmnN:p:P:qr:s:t:v:V:x"; +static const char *ntp_options = "aAbB:c:C:dD:f:gi:k:l:LmnNO:p:P:qr:s:S:t:T:W:u:v:V:xY:Z:-:"; #ifdef HAVE_NETINFO extern int check_netinfo; @@ -72,18 +80,23 @@ getstartup( case 'd': case 'D': msyslog(LOG_ERR, "ntpd not compiled with -DDEBUG option - no DEBUG support"); - fprintf(stderr, "ntpd not compiled with -DDEBUG option - no DEBUG support"); + fprintf(stderr, "ntpd not compiled with -DDEBUG option - no DEBUG support\n"); ++errflg; break; #endif case 'L': - listen_to_virtual_ips = 1; + listen_to_virtual_ips = 0; break; case 'l': { FILE *new_file; - new_file = fopen(ntp_optarg, "a"); + if(strcmp(ntp_optarg, "stderr") == 0) + new_file = stderr; + else if(strcmp(ntp_optarg, "stdout") == 0) + new_file = stdout; + else + new_file = fopen(ntp_optarg, "a"); if (new_file != NULL) { NLOG(NLOG_SYSINFO) msyslog(LOG_NOTICE, "logging to file %s", ntp_optarg); @@ -104,16 +117,38 @@ getstartup( case 'n': case 'q': ++nofork; +#ifdef SYS_WINNT + NoWinService = TRUE; +#endif break; case 'N': - priority_done = strcmp(ntp_optarg, "high"); + priority_done = 0; break; case '?': ++errflg; break; + case '-': + if ( ! strcmp(ntp_optarg, "version") ) { + printf("%.80s: %.80s\n", progname, Version); + exit(0); + } else if ( ! strcmp(ntp_optarg, "help") ) { + /* usage(); */ + /* exit(0); */ + ++errflg; + } else if ( ! strcmp(ntp_optarg, "copyright") ) { + printf("unknown\n"); + exit(0); + } else { + fprintf(stderr, "%.80s: Error unknown argument '--%.80s'\n", + progname, + ntp_optarg); + exit(12); + } + break; + default: break; } @@ -126,6 +161,9 @@ getstartup( #if defined(HAVE_SCHED_SETSCHEDULER) (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); #endif +#ifdef HAVE_CLOCKCTL + (void) fprintf(stderr, "\t\t[ -u user[:group] ] [ -i chrootdir ]\n"); +#endif exit(2); } ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */ @@ -152,6 +190,7 @@ getCmdOpts( ) { extern char *config_file; + struct sockaddr_in inaddrntp; int errflg; int c; @@ -171,15 +210,15 @@ getCmdOpts( while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) { switch (c) { case 'a': - proto_config(PROTO_AUTHENTICATE, 1, 0.); + proto_config(PROTO_AUTHENTICATE, 1, 0., NULL); break; case 'A': - proto_config(PROTO_AUTHENTICATE, 0, 0.); + proto_config(PROTO_AUTHENTICATE, 0, 0., NULL); break; case 'b': - proto_config(PROTO_BROADCLIENT, 1, 0.); + proto_config(PROTO_BROADCLIENT, 1, 0., NULL); break; case 'c': @@ -214,6 +253,16 @@ getCmdOpts( allow_panic = TRUE; break; + case 'i': +#ifdef HAVE_CLOCKCTL + if (!ntp_optarg) + errflg++; + else + chrootdir = ntp_optarg; + break; +#else + errflg++; +#endif case 'k': getauthkeys(ntp_optarg); break; @@ -223,7 +272,10 @@ getCmdOpts( break; case 'm': - proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP), 0.); + inaddrntp.sin_family = AF_INET; + inaddrntp.sin_port = htons(NTP_PORT); + inaddrntp.sin_addr.s_addr = htonl(INADDR_NTP); + proto_config(PROTO_MULTICAST_ADD, 0, 0., (struct sockaddr_storage*)&inaddrntp); sys_bclient = 1; break; @@ -259,11 +311,24 @@ getCmdOpts( "command line broadcast delay value %s undecodable", ntp_optarg); } else { - proto_config(PROTO_BROADDELAY, 0, tmp); + proto_config(PROTO_BROADDELAY, 0, tmp, NULL); } } while (0); break; + case 'u': +#ifdef HAVE_CLOCKCTL + user = malloc(strlen(ntp_optarg) + 1); + if ((user == NULL) || (ntp_optarg == NULL)) + errflg++; + (void)strncpy(user, ntp_optarg, strlen(ntp_optarg) + 1); + group = rindex(user, ':'); + if (group) + *group++ = '\0'; /* get rid of the ':' */ +#else + errflg++; +#endif + break; case 's': stats_config(STATS_STATSDIR, ntp_optarg); break; @@ -286,13 +351,50 @@ getCmdOpts( case 'v': case 'V': set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, - RW | ((c == 'V') ? DEF : 0)); + (u_short) (RW | ((c == 'V') ? DEF : 0))); break; case 'x': - allow_step = FALSE; + clock_max = 600; break; +#ifdef SIM + case 'B': + sscanf(ntp_optarg, "%lf", &ntp_node.bdly); + break; + + case 'C': + sscanf(ntp_optarg, "%lf", &ntp_node.snse); + break; + + case 'H': + sscanf(ntp_optarg, "%lf", &ntp_node.slew); + break; + + case 'O': + sscanf(ntp_optarg, "%lf", &ntp_node.clk_time); + break; + case 'S': + sscanf(ntp_optarg, "%lf", &ntp_node.sim_time); + break; + + case 'T': + sscanf(ntp_optarg, "%lf", &ntp_node.ferr); + break; + + case 'W': + sscanf(ntp_optarg, "%lf", &ntp_node.fnse); + break; + + case 'Y': + sscanf(ntp_optarg, "%lf", &ntp_node.ndly); + break; + + case 'Z': + sscanf(ntp_optarg, "%lf", &ntp_node.pdly); + break; + +#endif /* SIM */ default: errflg++; break; @@ -307,6 +409,9 @@ getCmdOpts( #if defined(HAVE_SCHED_SETSCHEDULER) (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); #endif +#ifdef HAVE_CLOCKCTL + (void) fprintf(stderr, "\t\t[ -u user[:group] ] [ -i chrootdir ]\n"); +#endif exit(2); } return; diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c index 660d2c5..f1428b1 100644 --- a/contrib/ntp/ntpd/ntp_config.c +++ b/contrib/ntp/ntpd/ntp_config.c @@ -18,10 +18,6 @@ #include "ntp_config.h" #include "ntp_cmdargs.h" -#ifdef PUBKEY -# include "ntp_crypto.h" -#endif /* PUBKEY */ - #include #include #ifdef HAVE_SYS_PARAM_H @@ -42,6 +38,8 @@ extern HANDLE ResolverThreadHandle; #endif /* SYS_WINNT */ +#include + extern int priority_done; /* @@ -51,43 +49,6 @@ extern int priority_done; * Lines are considered terminated when a '#' is encountered. Blank * lines are ignored. */ - -/* - * We understand the following configuration entries and defaults. - * - * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] - * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] - * broadcast [ addr ] [ version 3 ] [ key 0 ] [ ttl 1 ] - * broadcastclient - * multicastclient [ 224.0.1.1 ] - * manycastclient [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] - * manycastserver [ 224.0.1.1 ] - * broadcastdelay 0.0102 - * restrict [ addr ] [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery - * driftfile file_name - * keys file_name - * publickey file_name - * privatekey file_name - * statsdir /var/NTP/ - * filegen peerstats [ file peerstats ] [ type day ] [ link ] - * clientlimit [ n ] - * clientperiod [ 3600 ] - * trustedkey [ key ] - * requestkey [ key] - * controlkey [ key ] - * trap [ addr ] - * fudge [ addr ] [ stratum ] [ refid ] ... - * pidfile [ ] - * setvar [ ] - * logfile logfile - * logconfig [+|-|=][{sync|sys|peer|clock}{{,all}{info|statistics|events|status}}]... - * enable auth|bclient|pll|kernel|monitor|stats|calibrate - * disable auth|bclient|pll|kernel|monitor|stats|calibrate - * phone ... - * pps device [assert|clear] [hardpps] - * priority high|normal - */ - /* * Translation table - keywords to function index */ @@ -100,16 +61,14 @@ struct keyword { * Command keywords */ static struct keyword keywords[] = { - { "authenticate", CONFIG_AUTHENTICATE }, { "automax", CONFIG_AUTOMAX }, { "broadcast", CONFIG_BROADCAST }, { "broadcastclient", CONFIG_BROADCASTCLIENT }, { "broadcastdelay", CONFIG_BDELAY }, - { "clientlimit", CONFIG_CLIENTLIMIT }, - { "clientperiod", CONFIG_CLIENTPERIOD }, -#ifdef PUBKEY + { "calldelay", CONFIG_CDELAY}, +#ifdef OPENSSL { "crypto", CONFIG_CRYPTO }, -#endif /* PUBKEY */ +#endif /* OPENSSL */ { "controlkey", CONFIG_CONTROLKEY }, { "disable", CONFIG_DISABLE }, { "driftfile", CONFIG_DRIFTFILE }, @@ -118,9 +77,7 @@ static struct keyword keywords[] = { { "fudge", CONFIG_FUDGE }, { "includefile", CONFIG_INCLUDEFILE }, { "keys", CONFIG_KEYS }, -#ifdef PUBKEY { "keysdir", CONFIG_KEYSDIR }, -#endif /* PUBKEY */ { "logconfig", CONFIG_LOGCONFIG }, { "logfile", CONFIG_LOGFILE }, { "manycastclient", CONFIG_MANYCASTCLIENT }, @@ -129,7 +86,7 @@ static struct keyword keywords[] = { { "peer", CONFIG_PEER }, { "phone", CONFIG_PHONE }, { "pidfile", CONFIG_PIDFILE }, - { "pps", CONFIG_PPS }, + { "discard", CONFIG_DISCARD }, { "requestkey", CONFIG_REQUESTKEY }, { "restrict", CONFIG_RESTRICT }, { "revoke", CONFIG_REVOKE }, @@ -137,9 +94,12 @@ static struct keyword keywords[] = { { "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 } }; @@ -156,9 +116,6 @@ static struct keyword mod_keywords[] = { { "mode", CONF_MOD_MODE }, /* refclocks */ { "noselect", CONF_MOD_NOSELECT }, { "prefer", CONF_MOD_PREFER }, -#ifdef PUBKEY - { "publickey", CONF_MOD_PUBLICKEY }, -#endif /* PUBKEY */ { "ttl", CONF_MOD_TTL }, /* NTP peers */ { "version", CONF_MOD_VERSION }, { "", CONFIG_UNKNOWN } @@ -208,7 +165,6 @@ static struct keyword fudge_keywords[] = { { "", CONFIG_UNKNOWN } }; - /* * "filegen" modifier keywords */ @@ -252,12 +208,12 @@ static struct keyword flags_keywords[] = { }; /* - * "pps" modifier keywords + * "discard" modifier keywords */ -static struct keyword pps_keywords[] = { - { "assert", CONF_PPS_ASSERT }, - { "clear", CONF_PPS_CLEAR }, - { "hardpps", CONF_PPS_HARDPPS }, +static struct keyword discard_keywords[] = { + { "average", CONF_DISCARD_AVERAGE }, + { "minimum", CONF_DISCARD_MINIMUM }, + { "monitor", CONF_DISCARD_MONITOR }, { "", CONFIG_UNKNOWN } }; @@ -269,25 +225,51 @@ static struct keyword tinker_keywords[] = { { "panic", CONF_CLOCK_PANIC }, { "dispersion", CONF_CLOCK_PHI }, { "stepout", CONF_CLOCK_MINSTEP }, - { "minpoll", CONF_CLOCK_MINPOLL }, { "allan", CONF_CLOCK_ALLAN }, { "huffpuff", CONF_CLOCK_HUFFPUFF }, + { "freq", CONF_CLOCK_FREQ }, { "", CONFIG_UNKNOWN } }; -#ifdef PUBKEY +/* + * "tos" modifier keywords + */ +static struct keyword tos_keywords[] = { + { "minclock", CONF_TOS_MINCLOCK }, + { "minsane", CONF_TOS_MINSANE }, + { "floor", CONF_TOS_FLOOR }, + { "ceiling", CONF_TOS_CEILING }, + { "cohort", CONF_TOS_COHORT }, + { "", CONFIG_UNKNOWN } +}; + +#ifdef OPENSSL /* * "crypto" modifier keywords */ static struct keyword crypto_keywords[] = { - { "dh", CONF_CRYPTO_DH }, - { "flags", CONF_CRYPTO_FLAGS }, + { "cert", CONF_CRYPTO_CERT }, + { "gqpar", CONF_CRYPTO_GQPAR }, + { "host", CONF_CRYPTO_RSA }, + { "iffpar", CONF_CRYPTO_IFFPAR }, { "leap", CONF_CRYPTO_LEAP }, - { "privatekey", CONF_CRYPTO_PRIVATEKEY }, - { "publickey", CONF_CRYPTO_PUBLICKEY }, + { "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 } }; -#endif /* PUBKEY */ /* * "logconfig" building blocks @@ -345,6 +327,7 @@ static struct masks logcfg_item[] = { * 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 */ @@ -358,9 +341,8 @@ static char res_file[MAX_PATH]; */ char const *progname; char sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */ +char *keysdir = NTP_KEYSDIR; /* crypto keys directory */ char pps_device[MAXPPS + 1]; /* PPS device name */ -int pps_assert; -int pps_hardpps; #if defined(HAVE_SCHED_SETSCHEDULER) int config_priority_override = 0; int config_priority; @@ -403,13 +385,13 @@ static void free_netinfo_config P((struct netinfo_config_state *)); static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *)); #endif static int gettokens P((FILE *, char *, char **, int *)); -static int matchkey P((char *, struct keyword *)); -static int getnetnum P((const char *, struct sockaddr_in *, int)); +static int matchkey P((char *, struct keyword *, int)); +static int getnetnum P((const char *, struct sockaddr_storage *, int)); static void save_resolve P((char *, int, int, int, int, u_int, int, keyid_t, u_char *)); static void do_resolve_internal P((void)); static void abort_resolve P((void)); -#if !defined(VMS) +#if !defined(VMS) && !defined(SYS_WINNT) static RETSIGTYPE catchchild P((int)); #endif /* VMS */ @@ -490,6 +472,7 @@ getconfig( register int i; int c; int errflg; + int istart; int peerversion; int minpoll; int maxpoll; @@ -501,14 +484,14 @@ getconfig( u_long fudgeflag; u_int peerflags; int hmode; - struct sockaddr_in peeraddr; - struct sockaddr_in maskaddr; + 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; + int ntokens = 0; int tok = CONFIG_UNKNOWN; struct interface *localaddr; struct refclockstat clock_stat; @@ -627,7 +610,20 @@ getconfig( break; } - if (!getnetnum(tokens[1], &peeraddr, 0)) { + istart = 1; + memset((char *)&peeraddr, 0, sizeof(peeraddr)); + 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; + } + + if (!getnetnum(tokens[istart], &peeraddr, 0)) { errflg = -1; } else { errflg = 0; @@ -639,7 +635,7 @@ getconfig( ISBADADR(&peeraddr)) { msyslog(LOG_ERR, "attempt to configure invalid address %s", - ntoa(&peeraddr)); + stoa(&peeraddr)); break; } /* @@ -647,23 +643,45 @@ getconfig( * address for server/peer! * and unicast address for manycastclient! */ - if (((tok == CONFIG_SERVER) || - (tok == CONFIG_PEER)) && + if (peeraddr.ss_family == AF_INET) { + if (((tok == CONFIG_SERVER) || + (tok == CONFIG_PEER)) && #ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && + !ISREFCLOCKADR(&peeraddr) && #endif - IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - ntoa(&peeraddr)); - break; + 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; + } } - if ((tok == CONFIG_MANYCASTCLIENT) && - !IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - ntoa(&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; + } } } @@ -671,11 +689,12 @@ getconfig( minpoll = NTP_MINDPOLL; maxpoll = NTP_MAXDPOLL; peerkey = 0; - peerkeystr = "*"; + peerkeystr = (u_char *)"*"; peerflags = 0; ttl = 0; - for (i = 2; i < ntokens; i++) - switch (matchkey(tokens[i], mod_keywords)) { + 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, @@ -752,43 +771,34 @@ getconfig( case CONF_MOD_IBURST: peerflags |= FLAG_IBURST; break; -#ifdef AUTOKEY +#ifdef OPENSSL case CONF_MOD_SKEY: peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; break; - -#ifdef PUBKEY - case CONF_MOD_PUBLICKEY: - if (i >= ntokens - 1) { - msyslog(LOG_ERR, - "Public key file name required"); - errflg = 1; - break; - } - peerflags |= FLAG_SKEY | - FLAG_AUTHENABLE; - peerkeystr = tokens[++i]; - break; -#endif /* PUBKEY */ -#endif /* AUTOKEY */ +#endif /* OPENSSL */ case CONF_MOD_TTL: if (i >= ntokens-1) { - msyslog(LOG_ERR, - "ttl: argument required"); - errflg = 1; - break; + 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; case CONF_MOD_MODE: if (i >= ntokens-1) { - msyslog(LOG_ERR, - "mode: argument required"); - errflg = 1; - break; + msyslog(LOG_ERR, + "mode: argument required"); + errflg = 1; + break; } ttl = atoi(tokens[++i]); break; @@ -798,17 +808,22 @@ getconfig( break; } if (minpoll > maxpoll) { - msyslog(LOG_ERR, "config error: minpoll > maxpoll"); + msyslog(LOG_ERR, + "config error: minpoll > maxpoll"); errflg = 1; } if (errflg == 0) { - if (peer_config(&peeraddr, any_interface, hmode, - peerversion, minpoll, maxpoll, peerflags, - ttl, peerkey, peerkeystr) == 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", - ntoa(&peeraddr)); + stoa(&peeraddr)); } + if (tok == CONFIG_MANYCASTCLIENT) + proto_config(PROTO_MULTICAST_ADD, + 0, 0., &peeraddr); } else if (errflg == -1) { save_resolve(tokens[1], hmode, peerversion, @@ -910,48 +925,63 @@ getconfig( break; case CONFIG_BROADCASTCLIENT: - proto_config(PROTO_BROADCLIENT, 1, 0.); + proto_config(PROTO_BROADCLIENT, 1, 0., NULL); break; - + case CONFIG_MULTICASTCLIENT: case CONFIG_MANYCASTSERVER: if (ntokens > 1) { - for (i = 1; i < ntokens; i++) { + istart = 1; + memset((char *)&peeraddr, 0, sizeof(peeraddr)); + 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)) proto_config(PROTO_MULTICAST_ADD, - peeraddr.sin_addr.s_addr, 0.); + 0, 0., &peeraddr); } } else proto_config(PROTO_MULTICAST_ADD, - htonl(INADDR_NTP), 0.); + 0, 0., NULL); if (tok == CONFIG_MULTICASTCLIENT) sys_bclient = 1; else if (tok == CONFIG_MANYCASTSERVER) sys_manycastserver = 1; break; - case CONFIG_AUTHENTICATE: - errflg = 0; + case CONFIG_KEYS: if (ntokens >= 2) { - if (STREQ(tokens[1], "yes")) - proto_config(PROTO_AUTHENTICATE, 1, 0.); - else if (STREQ(tokens[1], "no")) - proto_config(PROTO_AUTHENTICATE, 0, 0.); - else - errflg++; - } else { - errflg++; + getauthkeys(tokens[1]); } - - if (errflg) - msyslog(LOG_ERR, - "should be `authenticate yes|no'"); break; - case CONFIG_KEYS: - if (ntokens >= 2) { - getauthkeys(tokens[1]); + case CONFIG_KEYSDIR: + if (ntokens < 2) { + msyslog(LOG_ERR, + "Keys directory name required"); + break; } + keysdir = emalloc(strlen(tokens[1]) + 1); + strcpy(keysdir, tokens[1]); break; case CONFIG_TINKER: @@ -959,8 +989,7 @@ getconfig( int temp; double ftemp; - temp = matchkey(tokens[i++], - tinker_keywords); + temp = matchkey(tokens[i++], tinker_keywords, 1); if (i > ntokens - 1) { msyslog(LOG_ERR, "tinker: missing argument"); @@ -969,6 +998,7 @@ getconfig( } sscanf(tokens[i], "%lf", &ftemp); switch(temp) { + case CONF_CLOCK_MAX: loop_config(LOOP_MAX, ftemp); break; @@ -985,10 +1015,6 @@ getconfig( loop_config(LOOP_MINSTEP, ftemp); break; - case CONF_CLOCK_MINPOLL: - loop_config(LOOP_MINPOLL, ftemp); - break; - case CONF_CLOCK_ALLAN: loop_config(LOOP_ALLAN, ftemp); break; @@ -996,14 +1022,96 @@ getconfig( case CONF_CLOCK_HUFFPUFF: loop_config(LOOP_HUFFPUFF, ftemp); break; + + case CONF_CLOCK_FREQ: + loop_config(LOOP_FREQ, ftemp); + break; } } break; -#ifdef AUTOKEY + case CONFIG_TOS: + for (i = 1; i < ntokens; i++) { + int temp; + double ftemp; + + temp = matchkey(tokens[i++], tos_keywords, 1); + if (i > ntokens - 1) { + msyslog(LOG_ERR, + "tinker: missing argument"); + errflg++; + break; + } + sscanf(tokens[i], "%lf", &ftemp); + switch(temp) { + + case CONF_TOS_MINCLOCK: + proto_config(PROTO_MINCLOCK, 0, ftemp, NULL); + break; + + case CONF_TOS_MINSANE: + proto_config(PROTO_MINSANE, 0, ftemp, NULL); + break; + + case CONF_TOS_FLOOR: + proto_config(PROTO_FLOOR, 0, ftemp, NULL); + break; + + case CONF_TOS_CEILING: + proto_config(PROTO_CEILING, 0, ftemp, NULL); + break; + + case CONF_TOS_COHORT: + proto_config(PROTO_COHORT, 0, ftemp, NULL); + break; + } + } + 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; + } + break; + + case CONFIG_DISCARD: + for (i = 1; i < ntokens; i++) { + int temp; + + 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++]); + break; + + case CONF_DISCARD_MINIMUM: + res_min_interval = atoi(tokens[i++]); + break; + + case CONF_DISCARD_MONITOR: + mon_age = atoi(tokens[i++]); + break; + + default: + msyslog(LOG_ERR, + "discard: unknown keyword"); + break; + } + } + break; + +#ifdef OPENSSL case CONFIG_REVOKE: if (ntokens >= 2) - sys_revoke = 1 << max(atoi(tokens[1]), 10); + sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE); break; case CONFIG_AUTOMAX: @@ -1011,25 +1119,16 @@ getconfig( sys_automax = 1 << max(atoi(tokens[1]), 10); break; -#ifdef PUBKEY - case CONFIG_KEYSDIR: - if (ntokens < 2) { - msyslog(LOG_ERR, - "Keys directory name required"); - break; - } - crypto_config(CRYPTO_CONF_KEYS, tokens[1]); - break; - case CONFIG_CRYPTO: if (ntokens == 1) { - crypto_config(CRYPTO_CONF_FLAGS , "0"); + crypto_config(CRYPTO_CONF_NONE, NULL); break; } for (i = 1; i < ntokens; i++) { int temp; - temp = matchkey(tokens[i++], crypto_keywords); + temp = matchkey(tokens[i++], + crypto_keywords, 1); if (i > ntokens - 1) { msyslog(LOG_ERR, "crypto: missing argument"); @@ -1037,48 +1136,88 @@ getconfig( break; } switch(temp) { - case CONF_CRYPTO_FLAGS: - crypto_config(CRYPTO_CONF_FLAGS, tokens[i]); + + case CONF_CRYPTO_CERT: + crypto_config(CRYPTO_CONF_CERT, + tokens[i]); break; - case CONF_CRYPTO_LEAP: - crypto_config(CRYPTO_CONF_LEAP, tokens[i]); + case CONF_CRYPTO_RSA: + crypto_config(CRYPTO_CONF_PRIV, + tokens[i]); break; - case CONF_CRYPTO_DH: - crypto_config(CRYPTO_CONF_DH, tokens[i]); + case CONF_CRYPTO_IFFPAR: + crypto_config(CRYPTO_CONF_IFFPAR, + tokens[i]); break; - case CONF_CRYPTO_PRIVATEKEY: - crypto_config(CRYPTO_CONF_PRIV, tokens[i]); + case CONF_CRYPTO_GQPAR: + crypto_config(CRYPTO_CONF_GQPAR, + tokens[i]); break; - case CONF_CRYPTO_PUBLICKEY: - crypto_config(CRYPTO_CONF_PUBL, tokens[i]); + case CONF_CRYPTO_MVPAR: + crypto_config(CRYPTO_CONF_MVPAR, + tokens[i]); break; - case CONF_CRYPTO_CERT: - crypto_config(CRYPTO_CONF_CERT, tokens[i]); + case CONF_CRYPTO_LEAP: + crypto_config(CRYPTO_CONF_LEAP, + tokens[i]); + break; + + case CONF_CRYPTO_PW: + crypto_config(CRYPTO_CONF_PW, + tokens[i]); + break; + + case CONF_CRYPTO_RAND: + crypto_config(CRYPTO_CONF_RAND, + tokens[i]); + break; + + case CONF_CRYPTO_SIGN: + crypto_config(CRYPTO_CONF_SIGN, + tokens[i]); break; default: - msyslog(LOG_ERR, "crypto: unknown keyword"); + msyslog(LOG_ERR, + "crypto: unknown keyword"); break; } } break; -#endif /* PUBKEY */ -#endif /* AUTOKEY */ +#endif /* OPENSSL */ case CONFIG_RESTRICT: if (ntokens < 2) { msyslog(LOG_ERR, "restrict requires an address"); break; } - if (STREQ(tokens[1], "default")) - peeraddr.sin_addr.s_addr = htonl(INADDR_ANY); - else if (!getnetnum(tokens[1], &peeraddr, 1)) - break; + istart = 1; + memset((char *)&peeraddr, 0, sizeof(peeraddr)); + 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; + } + + /* + * Assume default means an IPv4 address, except + * if forced by a -4 or -6. + */ + if (STREQ(tokens[istart], "default")) { + if (peeraddr.ss_family == 0) + peeraddr.ss_family = AF_INET; + } else if (!getnetnum(tokens[istart], &peeraddr, 1)) + break; /* * Use peerversion as flags, peerkey as mflags. Ick. @@ -1086,9 +1225,10 @@ getconfig( peerversion = 0; peerkey = 0; errflg = 0; - maskaddr.sin_addr.s_addr = ~(u_int32)0; - for (i = 2; i < ntokens; i++) { - switch (matchkey(tokens[i], res_keywords)) { + 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, @@ -1154,8 +1294,8 @@ getconfig( break; } } - if (SRCADR(&peeraddr) == htonl(INADDR_ANY)) - maskaddr.sin_addr.s_addr = 0; + if (SOCKNUL(&peeraddr)) + ANYSOCK(&maskaddr); if (!errflg) hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr, (int)peerkey, peerversion); @@ -1170,11 +1310,23 @@ getconfig( "broadcastdelay value %s undecodable", tokens[1]); } else { - proto_config(PROTO_BROADDELAY, 0, tmp); + proto_config(PROTO_BROADDELAY, 0, tmp, NULL); } } break; + case CONFIG_CDELAY: + if (ntokens >= 2) { + u_long ui; + + if (sscanf(tokens[1], "%ld", &ui) != 1) + msyslog(LOG_ERR, + "illegal value - line ignored"); + else + proto_config(PROTO_CALLDELAY, ui, 0, NULL); + } + break; + case CONFIG_TRUSTEDKEY: for (i = 1; i < ntokens; i++) { keyid_t tkey; @@ -1232,7 +1384,20 @@ getconfig( "no address for trap command, line ignored"); break; } - if (!getnetnum(tokens[1], &peeraddr, 1)) + istart = 1; + memset((char *)&peeraddr, 0, sizeof(peeraddr)); + 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; + } + + if (!getnetnum(tokens[istart], &peeraddr, 1)) break; /* @@ -1241,8 +1406,9 @@ getconfig( errflg = 0; peerversion = 0; localaddr = 0; - for (i = 2; i < ntokens-1; i++) - switch (matchkey(tokens[i], trap_keywords)) { + 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, @@ -1268,6 +1434,9 @@ getconfig( break; } + memset((char *)&maskaddr, 0, + sizeof(maskaddr)); + maskaddr.ss_family = peeraddr.ss_family; if (!getnetnum(tokens[++i], &maskaddr, 1)) { errflg = 1; @@ -1278,7 +1447,7 @@ getconfig( if (localaddr == NULL) { msyslog(LOG_ERR, "can't find interface with address %s", - ntoa(&maskaddr)); + stoa(&maskaddr)); errflg = 1; } break; @@ -1290,16 +1459,16 @@ getconfig( if (!errflg) { if (peerversion != 0) - peeraddr.sin_port = htons( (u_short) peerversion); + ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion); else - peeraddr.sin_port = htons(TRAPPORT); + ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT); if (localaddr == NULL) - localaddr = any_interface; + localaddr = ANY_INTERFACE_CHOOSE(&peeraddr); if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION)) msyslog(LOG_ERR, "can't set trap for %s, no resources", - ntoa(&peeraddr)); + stoa(&peeraddr)); } break; @@ -1309,13 +1478,14 @@ getconfig( "no address for fudge command, line ignored"); break; } + memset((char *)&peeraddr, 0, sizeof(peeraddr)); if (!getnetnum(tokens[1], &peeraddr, 1)) break; if (!ISREFCLOCKADR(&peeraddr)) { msyslog(LOG_ERR, "%s is inappropriate address for the fudge command, line ignored", - ntoa(&peeraddr)); + stoa(&peeraddr)); break; } @@ -1324,13 +1494,13 @@ getconfig( errflg = 0; for (i = 2; i < ntokens-1; i++) { switch (c = matchkey(tokens[i], - fudge_keywords)) { + 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", - ntoa(&peeraddr)); + stoa(&peeraddr)); errflg = i; break; } @@ -1342,7 +1512,7 @@ getconfig( &clock_stat.fudgetime2) != 1) { msyslog(LOG_ERR, "fudge %s time2 value in error", - ntoa(&peeraddr)); + stoa(&peeraddr)); errflg = i; break; } @@ -1355,7 +1525,7 @@ getconfig( { msyslog(LOG_ERR, "fudge %s stratum value in error", - ntoa(&peeraddr)); + stoa(&peeraddr)); errflg = i; break; } @@ -1379,7 +1549,7 @@ getconfig( || fudgeflag > 1) { msyslog(LOG_ERR, "fudge %s flag value in error", - ntoa(&peeraddr)); + stoa(&peeraddr)); errflg = i; break; } @@ -1475,7 +1645,8 @@ getconfig( errflg = 0; for (i = 2; i < ntokens; i++) { - switch (matchkey(tokens[i], filegen_keywords)) { + switch (matchkey(tokens[i], + filegen_keywords, 1)) { case CONF_FGEN_FILE: if (i >= ntokens - 1) { msyslog(LOG_ERR, @@ -1494,7 +1665,8 @@ getconfig( errflg = i; break; } - peerkey = matchkey(tokens[++i], fgen_types); + peerkey = matchkey(tokens[++i], + fgen_types, 1); if (peerkey == CONFIG_UNKNOWN) { msyslog(LOG_ERR, "filegen %s unknown type \"%s\"", @@ -1532,55 +1704,12 @@ getconfig( "no value for setvar command - line ignored"); } else { set_sys_var(tokens[1], strlen(tokens[1])+1, - RW | + (u_short) (RW | ((((ntokens > 2) && !strcmp(tokens[2], "default"))) ? DEF - : 0)); - } - break; - - case CONFIG_CLIENTLIMIT: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no value for clientlimit command - line ignored"); - } else { - u_long ui; - - if (!atouint(tokens[1], &ui) || !ui) { - msyslog(LOG_ERR, - "illegal value for clientlimit command - line ignored"); - } else { - char bp[80]; - -#ifdef DEBUG - if (debug) - sprintf(bp, "client_limit=%lu", ui); -#endif - set_sys_var(bp, strlen(bp)+1, RO); - client_limit = ui; - } - } - break; - - case CONFIG_CLIENTPERIOD: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no value for clientperiod command - line ignored"); - } else { - u_long ui; - - if (!atouint(tokens[1], &ui) || ui < 64) { - msyslog(LOG_ERR, - "illegal value for clientperiod command - line ignored"); - } else { - char bp[80]; - - sprintf(bp, "client_limit_period=%ld", ui); - set_sys_var(bp, strlen(bp)+1, RO); - client_limit_period = ui; - } + : 0))); } break; @@ -1588,7 +1717,7 @@ getconfig( for (i = 1; i < ntokens; i++) { int flag; - flag = matchkey(tokens[i], flags_keywords); + flag = matchkey(tokens[i], flags_keywords, 1); if (flag == CONFIG_UNKNOWN) { msyslog(LOG_ERR, "enable unknown flag %s", @@ -1596,7 +1725,7 @@ getconfig( errflg = 1; break; } - proto_config(flag, 1, 0.); + proto_config(flag, 1, 0., NULL); } break; @@ -1604,7 +1733,7 @@ getconfig( for (i = 1; i < ntokens; i++) { int flag; - flag = matchkey(tokens[i], flags_keywords); + flag = matchkey(tokens[i], flags_keywords, 1); if (flag == CONFIG_UNKNOWN) { msyslog(LOG_ERR, "disable unknown flag %s", @@ -1612,7 +1741,7 @@ getconfig( errflg = 1; break; } - proto_config(flag, 0, 0.); + proto_config(flag, 0, 0., NULL); } break; @@ -1624,38 +1753,14 @@ getconfig( sys_phone[i - 1][0] = '\0'; break; - case CONFIG_PPS: - if (ntokens < 2) { - msyslog(LOG_ERR, - "pps missing device name"); - break; - } - (void)strncpy(pps_device, tokens[1], MAXPPS); - for (i = 2; i < ntokens; i++) { - int flag; + case CONFIG_ADJ: { + double ftemp; - flag = matchkey(tokens[i], pps_keywords); - switch(flag) { - case CONF_PPS_ASSERT: - pps_assert = 0; - break; - case CONF_PPS_CLEAR: - pps_assert = 1; - break; - case CONF_PPS_HARDPPS: - pps_hardpps = 1; - break; - default: - msyslog(LOG_ERR, - "pps unknown flag %s", - tokens[i]); - errflg = 1; - break; - } - if(errflg) - break; + sscanf(tokens[1], "%lf", &ftemp); + proto_config(PROTO_ADJ, 0, ftemp, NULL); } break; + } } if (fp[0]) @@ -1680,7 +1785,7 @@ getconfig( for (i = 0; i < 8; i++) for (j = 1; j < 100; ++j) { - rankey[i] = RANDOM & 0xff; + rankey[i] = (char) (RANDOM & 0xff); if (rankey[i] != 0) break; } rankey[8] = 0; @@ -1697,10 +1802,12 @@ getconfig( #endif /* !defined(VMS) && !defined(SYS_VXWORKS) */ if (res_fp != NULL) { - /* - * Need name resolution - */ - do_resolve_internal(); + if (call_resolver) { + /* + * Need name resolution + */ + do_resolve_internal(); + } } } @@ -1801,7 +1908,7 @@ gettokens_netinfo ( for (index = 0; index < namelist.ni_namelist_len; index++) { char *value = namelist.ni_namelist_val[index]; - if (! (val_list[index] = (char*)malloc(strlen(value+1)))) + if (! (val_list[index] = (char*)malloc(strlen(value)+1))) { msyslog(LOG_ERR, "out of memory while configuring"); break; } strcpy(val_list[index], value); @@ -1921,7 +2028,7 @@ gettokens ( * Return the match */ *ntokens = ntok + 1; - ntok = matchkey(tokenlist[0], keywords); + ntok = matchkey(tokenlist[0], keywords, 1); if (ntok == CONFIG_UNKNOWN) goto again; return ntok; @@ -1935,14 +2042,16 @@ gettokens ( static int matchkey( register char *word, - register struct keyword *keys + register struct keyword *keys, + int complain ) { for (;;) { if (keys->keytype == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "configure: keyword \"%s\" unknown, line ignored", - word); + if (complain) + msyslog(LOG_ERR, + "configure: keyword \"%s\" unknown, line ignored", + word); return CONFIG_UNKNOWN; } if (STRSAME(word, keys->text)) @@ -1958,77 +2067,53 @@ matchkey( static int getnetnum( const char *num, - struct sockaddr_in *addr, + struct sockaddr_storage *addr, int complain ) { - register const char *cp; - register char *bp; - register int i; - register int temp; - char buf[80]; /* will core dump on really stupid stuff */ - u_int32 netnum; - - /* XXX ELIMINATE replace with decodenetnum */ - cp = num; - netnum = 0; - for (i = 0; i < 4; i++) { - bp = buf; - while (isdigit((int)*cp)) - *bp++ = *cp++; - if (bp == buf) - break; + struct addrinfo hints; + struct addrinfo *ptr; - if (i < 3) { - if (*cp++ != '.') - break; - } else if (*cp != '\0') - break; + /* 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; - *bp = '\0'; - temp = atoi(buf); - if (temp > 255) - break; - netnum <<= 8; - netnum += temp; + hints.ai_socktype = SOCK_DGRAM; #ifdef DEBUG if (debug > 3) - printf("getnetnum %s step %d buf %s temp %d netnum %lu\n", - num, i, buf, temp, (u_long)netnum); + printf("getaddrinfo %s\n", num); #endif - } - - if (i < 4) { + if (getaddrinfo(num, "ntp", &hints, &ptr)!=0) { if (complain) msyslog(LOG_ERR, - "getnetnum: \"%s\" invalid host number, line ignored", + "getaddrinfo: \"%s\" invalid host address, line ignored", num); #ifdef DEBUG if (debug > 3) printf( - "getnetnum: \"%s\" invalid host number, line ignored\n", - num); + "getaddrinfo: \"%s\" invalid host address%s.\n", + num, (complain) + ? ", line ignored" + : ""); #endif return 0; } - /* - * make up socket address. Clear it out for neatness. - */ - memset((void *)addr, 0, sizeof(struct sockaddr_in)); - addr->sin_family = AF_INET; - addr->sin_port = htons(NTP_PORT); - addr->sin_addr.s_addr = htonl(netnum); + memcpy(addr, ptr->ai_addr, ptr->ai_addrlen); #ifdef DEBUG if (debug > 1) - printf("getnetnum given %s, got %s (%lx)\n", - num, ntoa(addr), (u_long)netnum); + printf("getnetnum given %s, got %s \n", + num, stoa(addr)); #endif + freeaddrinfo(ptr); return 1; } -#if !defined(VMS) +#if !defined(VMS) && !defined(SYS_WINNT) /* * catchchild - receive the resolver's exit status */ @@ -2072,8 +2157,7 @@ save_resolve( #else /* no /tmp directory under NT */ { - DWORD len; - if(!(len = GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) { + if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) { msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m"); return; } @@ -2211,7 +2295,7 @@ do_resolve_internal(void) */ closelog(); - kill_asyncio(); + kill_asyncio(0); (void) signal_no_reset(SIGCHLD, SIG_DFL); @@ -2266,13 +2350,14 @@ do_resolve_internal(void) */ DWORD dwThreadId; fflush(stdout); - if (!(ResolverThreadHandle = CreateThread( - NULL, /* no security attributes */ - 0, /* use default stack size */ + 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 */ + 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"); abort_resolve(); } diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c index d7109ca..0ac0404 100644 --- a/contrib/ntp/ntpd/ntp_control.c +++ b/contrib/ntp/ntpd/ntp_control.c @@ -18,10 +18,6 @@ #include #include -#ifdef PUBKEY -#include "ntp_crypto.h" -#endif /* PUBKEY */ - /* * Structure to hold request procedure information */ @@ -46,7 +42,9 @@ struct ctl_proc { * Request processing routines */ static void ctl_error P((int)); +#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 *, @@ -56,7 +54,7 @@ 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)); +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)); @@ -74,7 +72,7 @@ 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_in *, +static struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *, struct interface *)); static struct ctl_proc control_codes[] = { @@ -114,16 +112,16 @@ static struct ctl_var sys_var[] = { { CS_VERSION, RO, "version" }, /* 17 */ { CS_STABIL, RO, "stability" }, /* 18 */ { CS_VARLIST, RO, "sys_var_list" }, /* 19 */ -#ifdef PUBKEY +#ifdef OPENSSL { CS_FLAGS, RO, "flags" }, /* 20 */ { CS_HOST, RO, "hostname" }, /* 21 */ - { CS_PUBLIC, RO, "publickey" }, /* 22 */ - { CS_CERTIF, RO, "certificate" }, /* 23 */ - { CS_DHPARAMS, RO, "params" }, /* 24 */ - { CS_REVTIME, RO, "refresh" }, /* 25 */ - { CS_LEAPTAB, RO, "leapseconds" }, /* 26 */ - { CS_TAI, RO, "tai"}, /* 27 */ -#endif /* PUBKEY */ + { CS_PUBLIC, RO, "hostkey" }, /* 22 */ + { CS_CERTIF, RO, "cert" }, /* 23 */ + { CS_REVTIME, RO, "refresh" }, /* 24 */ + { CS_LEAPTAB, RO, "leapseconds" }, /* 25 */ + { CS_TAI, RO, "tai" }, /* 26 */ + { CS_DIGEST, RO, "signature" }, /* 27 */ +#endif /* OPENSSL */ { 0, EOV, "" } /* 28 */ }; @@ -152,14 +150,15 @@ static u_char def_sys_var[] = { CS_DRIFT, CS_JITTER, CS_STABIL, -#ifdef PUBKEY - CS_FLAGS, +#ifdef OPENSSL CS_HOST, - CS_CERTIF, - CS_DHPARAMS, + CS_DIGEST, + CS_FLAGS, + CS_PUBLIC, CS_REVTIME, CS_LEAPTAB, -#endif /* PUBKEY */ + CS_CERTIF, +#endif /* OPENSSL */ 0 }; @@ -205,20 +204,18 @@ static struct ctl_var peer_var[] = { { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ { CP_FLASH, RO, "flash" }, /* 35 */ { CP_TTL, RO, "ttl" }, /* 36 */ - { CP_TTLMAX, RO, "ttlmax" }, /* 37 */ + { CP_RANK, RO, "rank" }, /* 37 */ { CP_VARLIST, RO, "peer_var_list" }, /* 38 */ -#ifdef PUBKEY - { CP_FLAGS, RO, "flags" }, /* 38 */ - { CP_HOST, RO, "hostname" }, /* 39 */ - { CP_PUBLIC, RO, "publickey" }, /* 40 */ - { CP_CERTIF, RO, "certificate" }, /* 41 */ - { CP_SESKEY, RO, "pcookie" }, /* 42 */ - { CP_SASKEY, RO, "hcookie" }, /* 43 */ - { CP_INITSEQ, RO, "initsequence" }, /* 44 */ - { CP_INITKEY, RO, "initkey" }, /* 45 */ - { CP_INITTSP, RO, "timestamp" }, /* 46 */ -#endif /* PUBKEY */ - { 0, EOV, "" } /* 47 */ +#ifdef OPENSSL + { CP_FLAGS, RO, "flags" }, /* 39 */ + { CP_HOST, RO, "hostname" }, /* 40 */ + { CP_INITSEQ, RO, "initsequence" }, /* 41 */ + { CP_INITKEY, RO, "initkey" }, /* 42 */ + { CP_INITTSP, RO, "timestamp" }, /* 43 */ + { CP_DIGEST, RO, "signature" }, /* 44 */ + { CP_IDENT, RO, "identity" }, /* 45 */ +#endif /* OPENSSL */ + { 0, EOV, "" } /* 39/46 */ }; @@ -245,7 +242,6 @@ static u_char def_peer_var[] = { CP_FLASH, CP_KEYID, CP_TTL, - CP_TTLMAX, CP_OFFSET, CP_DELAY, CP_DISPERSION, @@ -257,13 +253,13 @@ static u_char def_peer_var[] = { CP_FILTDELAY, CP_FILTOFFSET, CP_FILTERROR, -#ifdef PUBKEY - CP_FLAGS, +#ifdef OPENSSL CP_HOST, - CP_CERTIF, - CP_SESKEY, + CP_DIGEST, + CP_FLAGS, + CP_IDENT, CP_INITSEQ, -#endif /* PUBKEY */ +#endif /* OPENSSL */ 0 }; @@ -450,7 +446,7 @@ static u_char * datapt; static u_char * dataend; static int datalinelen; static int datanotbinflag; -static struct sockaddr_in *rmt_addr; +static struct sockaddr_storage *rmt_addr; static struct interface *lcl_inter; static u_char res_authenticate; @@ -735,14 +731,16 @@ ctlpeerstatus( /* * ctlclkstatus - return a status word for this clock */ +#ifdef REFCLOCK static u_short ctlclkstatus( struct refclockstat *this_clock ) { - return ((u_short)(this_clock->currentstatus) << 8) | - (u_short)(this_clock->lastevent); + return ((u_short)(((this_clock->currentstatus) << 8) | + (this_clock->lastevent))); } +#endif /* @@ -1074,12 +1072,13 @@ ctl_putts( /* - * ctl_putadr - write a dotted quad IP address into the response + * ctl_putadr - write an IP address into the response */ static void ctl_putadr( const char *tag, - u_int32 addr + u_int32 addr32, + struct sockaddr_storage* addr ) { register char *cp; @@ -1092,7 +1091,10 @@ ctl_putadr( *cp++ = *cq++; *cp++ = '='; - cq = numtoa(addr); + if (addr == NULL) + cq = numtoa(addr32); + else + cq = stoa(addr); while (*cq != '\0') *cp++ = *cq++; ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); @@ -1139,7 +1141,6 @@ ctl_putarray( register const char *cq; char buffer[200]; int i; - cp = buffer; cq = tag; while (*cq != '\0') @@ -1166,9 +1167,11 @@ ctl_putsys( ) { l_fp tmp; -#ifdef HAVE_UNAME char str[256]; -#endif +#ifdef OPENSSL + struct cert_info *cp; + char cbuf[256]; +#endif /* OPENSSL */ switch (varid) { @@ -1195,8 +1198,8 @@ ctl_putsys( break; case CS_REFID: - if (sys_stratum > 1) - ctl_putadr(sys_var[CS_REFID].text, sys_refid); + if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC) + ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL); else ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid); @@ -1254,8 +1257,7 @@ ctl_putsys( ctl_putstr(sys_var[CS_SYSTEM].text, str_system, sizeof(str_system) - 1); #else - (void)strcpy(str, utsnamebuf.sysname); - (void)strcat(str, utsnamebuf.release); + sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release); ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str)); #endif /* HAVE_UNAME */ break; @@ -1333,37 +1335,50 @@ ctl_putsys( } break; -#ifdef PUBKEY +#ifdef OPENSSL case CS_FLAGS: - if (crypto_flags) - ctl_puthex(sys_var[CS_FLAGS].text, - crypto_flags); + if (crypto_flags) { + ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags); + } + break; + + case CS_DIGEST: + 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, + strlen(str)); + } break; case CS_HOST: - ctl_putstr(sys_var[CS_HOST].text, sys_hostname, - strlen(sys_hostname)); - if (host.fstamp != 0) - ctl_putuint(sys_var[CS_PUBLIC].text, - ntohl(host.fstamp)); + if (sys_hostname != NULL) + ctl_putstr(sys_var[CS_HOST].text, sys_hostname, + strlen(sys_hostname)); break; case CS_CERTIF: - if (certif.fstamp != 0) - ctl_putuint(sys_var[CS_CERTIF].text, - ntohl(certif.fstamp)); + for (cp = cinfo; cp != NULL; cp = cp->link) { + sprintf(cbuf, "%s %s 0x%x %u", cp->subject, + cp->issuer, cp->flags, + ntohl(cp->cert.fstamp)); + ctl_putstr(sys_var[CS_CERTIF].text, cbuf, + strlen(cbuf)); + } break; - case CS_DHPARAMS: - if (dhparam.fstamp != 0) - ctl_putuint(sys_var[CS_DHPARAMS].text, - ntohl(dhparam.fstamp)); + case CS_PUBLIC: + if (hostval.fstamp != 0) + ctl_putuint(sys_var[CS_PUBLIC].text, + ntohl(hostval.fstamp)); break; case CS_REVTIME: - if (host.tstamp != 0) + if (hostval.tstamp != 0) ctl_putuint(sys_var[CS_REVTIME].text, - ntohl(host.tstamp)); + ntohl(hostval.tstamp)); break; case CS_LEAPTAB: @@ -1373,7 +1388,7 @@ ctl_putsys( if (sys_tai != 0) ctl_putuint(sys_var[CS_TAI].text, sys_tai); break; -#endif /* PUBKEY */ +#endif /* OPENSSL */ } } @@ -1387,6 +1402,11 @@ ctl_putpeer( struct peer *peer ) { +#ifdef OPENSSL + char str[256]; + struct autokey *ap; +#endif /* OPENSSL */ + switch (varid) { case CP_CONFIG: @@ -1405,24 +1425,24 @@ ctl_putpeer( break; case CP_SRCADR: - ctl_putadr(peer_var[CP_SRCADR].text, - peer->srcadr.sin_addr.s_addr); + ctl_putadr(peer_var[CP_SRCADR].text, 0, + &peer->srcadr); break; case CP_SRCPORT: ctl_putuint(peer_var[CP_SRCPORT].text, - ntohs(peer->srcadr.sin_port)); + ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port)); break; case CP_DSTADR: - ctl_putadr(peer_var[CP_DSTADR].text, - peer->dstadr->sin.sin_addr.s_addr); + ctl_putadr(peer_var[CP_DSTADR].text, 0, + &(peer->dstadr->sin)); break; case CP_DSTPORT: ctl_putuint(peer_var[CP_DSTPORT].text, (u_long)(peer->dstadr ? - ntohs(peer->dstadr->sin.sin_port) : 0)); + ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0)); break; case CP_LEAP: @@ -1461,16 +1481,22 @@ ctl_putpeer( break; case CP_REFID: - if (peer->stratum > 1) { - if (peer->flags & FLAG_REFCLOCK) - ctl_putadr(peer_var[CP_REFID].text, - peer->srcadr.sin_addr.s_addr); + if (peer->flags & FLAG_REFCLOCK) { + if (peer->stratum > 0 && peer->stratum < + STRATUM_UNSPEC) + ctl_putadr(peer_var[CP_REFID].text, + peer->refid, NULL); else - ctl_putadr(peer_var[CP_REFID].text, - peer->refid); + ctl_putid(peer_var[CP_REFID].text, + (char *)&peer->refid); } else { - ctl_putid(peer_var[CP_REFID].text, - (char *)&peer->refid); + 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); } break; @@ -1499,21 +1525,17 @@ ctl_putpeer( break; case CP_TTL: - if (!(peer->cast_flags & MDF_ACAST)) - break; - ctl_putint(peer_var[CP_TTL].text, peer->ttl); - break; - - case CP_TTLMAX: - if (!(peer->cast_flags & (MDF_MCAST | MDF_ACAST))) - break; - ctl_putint(peer_var[CP_TTLMAX].text, peer->ttlmax); + ctl_putint(peer_var[CP_TTL].text, sys_ttl[peer->ttl]); break; case CP_VALID: ctl_putuint(peer_var[CP_VALID].text, peer->unreach); break; + case CP_RANK: + ctl_putuint(peer_var[CP_RANK].text, peer->rank); + break; + case CP_TIMER: ctl_putuint(peer_var[CP_TIMER].text, peer->nextdate - current_time); @@ -1607,47 +1629,44 @@ ctl_putpeer( ctl_putdata(buf, (unsigned)(s - buf), 0); } break; -#ifdef PUBKEY +#ifdef OPENSSL case CP_FLAGS: if (peer->crypto) ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto); break; - case CP_HOST: - if (peer->keystr != NULL) - ctl_putstr(peer_var[CP_HOST].text, peer->keystr, - strlen(peer->keystr)); - if (peer->pubkey.fstamp != 0) - ctl_putuint(peer_var[CP_PUBLIC].text, - peer->pubkey.fstamp); + case CP_DIGEST: + if (peer->crypto) { + const EVP_MD *dp; + + 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)); + } break; - case CP_CERTIF: - if (peer->certif.fstamp != 0) - ctl_putuint(peer_var[CP_CERTIF].text, - peer->certif.fstamp); + case CP_HOST: + if (peer->subject != NULL) + ctl_putstr(peer_var[CP_HOST].text, peer->subject, + strlen(peer->subject)); break; - case CP_SESKEY: - if (peer->pcookie.key != 0) - ctl_puthex(peer_var[CP_SESKEY].text, - peer->pcookie.key); - if (peer->hcookie != 0) - ctl_puthex(peer_var[CP_SASKEY].text, - peer->hcookie); + case CP_IDENT: + if (peer->issuer != NULL) + ctl_putstr(peer_var[CP_IDENT].text, peer->issuer, + strlen(peer->issuer)); break; case CP_INITSEQ: - if (peer->recauto.key == 0) + if ((ap = (struct autokey *)peer->recval.ptr) == NULL) break; - ctl_putint(peer_var[CP_INITSEQ].text, - peer->recauto.seq); - ctl_puthex(peer_var[CP_INITKEY].text, - peer->recauto.key); + ctl_putint(peer_var[CP_INITSEQ].text, ap->seq); + ctl_puthex(peer_var[CP_INITKEY].text, ap->key); ctl_putuint(peer_var[CP_INITTSP].text, - peer->recauto.tstamp); + ntohl(peer->recval.tstamp)); break; -#endif /* PUBKEY */ +#endif /* OPENSSL */ } } @@ -1717,7 +1736,7 @@ ctl_putclock( if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) { if (clock_stat->fudgeval1 > 1) ctl_putadr(clock_var[CC_FUDGEVAL2].text, - (u_int32)clock_stat->fudgeval2); + (u_int32)clock_stat->fudgeval2, NULL); else ctl_putid(clock_var[CC_FUDGEVAL2].text, (char *)&clock_stat->fudgeval2); @@ -1876,7 +1895,7 @@ ctl_getitem( numctlbadpkts++; msyslog(LOG_WARNING, "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n", - inet_ntoa(rmt_addr->sin_addr), ntohs(rmt_addr->sin_port) + stoa(rmt_addr), SRCPORT(rmt_addr) ); return (0); } @@ -1884,10 +1903,10 @@ ctl_getitem( if (cp < reqend) cp++; *tp-- = '\0'; - while (tp > buf) { - *tp-- = '\0'; + while (tp >= buf) { if (!isspace((int)(*tp))) break; + *tp-- = '\0'; } reqpt = cp; *data = buf; @@ -2130,7 +2149,7 @@ write_variables( register struct ctl_var *v; register int ext_var; char *valuep; - long val; + long val = 0; /* * If he's trying to write into a peer tell him no way @@ -2434,7 +2453,7 @@ unset_trap( */ int ctlsettrap( - struct sockaddr_in *raddr, + struct sockaddr_storage *raddr, struct interface *linter, int traptype, int version @@ -2539,7 +2558,7 @@ ctlsettrap( tptouse->tr_sequence = 1; tptouse->tr_addr = *raddr; tptouse->tr_localaddr = linter; - tptouse->tr_version = version; + tptouse->tr_version = (u_char) version; tptouse->tr_flags = TRAP_INUSE; if (traptype == TRAP_TYPE_CONFIG) tptouse->tr_flags |= TRAP_CONFIGURED; @@ -2555,7 +2574,7 @@ ctlsettrap( */ int ctlclrtrap( - struct sockaddr_in *raddr, + struct sockaddr_storage *raddr, struct interface *linter, int traptype ) @@ -2580,18 +2599,18 @@ ctlclrtrap( */ static struct ctl_trap * ctlfindtrap( - struct sockaddr_in *raddr, + struct sockaddr_storage *raddr, struct interface *linter ) { register struct ctl_trap *tp; for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { - if (tp->tr_flags & TRAP_INUSE && NSRCADR(raddr) == - NSRCADR(&tp->tr_addr) && NSRCPORT(raddr) == - NSRCPORT(&tp->tr_addr) && linter == - tp->tr_localaddr) - return (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; } @@ -2612,7 +2631,7 @@ report_event( * Record error code in proper spots, but have mercy on the * log file. */ - if (!(err & PEER_EVENT)) { + 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) { @@ -2634,10 +2653,10 @@ report_event( #ifdef REFCLOCK if (ISREFCLOCKADR(&peer->srcadr)) - src = refnumtoa(peer->srcadr.sin_addr.s_addr); + src = refnumtoa(&peer->srcadr); else #endif - src = ntoa(&peer->srcadr); + src = stoa(&peer->srcadr); peer->last_event = (u_char)(err & ~PEER_EVENT); if (peer->num_events < CTL_PEER_MAXEVENTS) @@ -2690,10 +2709,10 @@ report_event( * variables. Don't send crypto strings. */ for (i = 1; i <= CS_MAXCODE; i++) { -#ifdef PUBKEY +#ifdef OPENSSL if (i > CS_VARLIST) continue; -#endif /* PUBKEY */ +#endif /* OPENSSL */ ctl_putsys(i); } #ifdef REFCLOCK @@ -2719,7 +2738,7 @@ report_event( strlen(kv->text), 0); free_varlist(clock_stat.kv_list); } -#endif /*REFCLOCK*/ +#endif /* REFCLOCK */ } else { rpkt.associd = htons(peer->associd); rpkt.status = htons(ctlpeerstatus(peer)); @@ -2727,12 +2746,13 @@ report_event( /* * Dump it all. Later, maybe less. */ - for (i = 1; i <= CP_MAXCODE; i++) -#ifdef PUBKEY + for (i = 1; i <= CP_MAXCODE; i++) { +#ifdef OPENSSL if (i > CP_VARLIST) continue; -#endif /* PUBKEY */ +#endif /* OPENSSL */ ctl_putpeer(i, peer); + } #ifdef REFCLOCK /* * for clock exception events: add clock variables to @@ -2758,7 +2778,7 @@ report_event( strlen(kv->text), 0); free_varlist(clock_stat.kv_list); } -#endif /*REFCLOCK*/ +#endif /* REFCLOCK */ } /* @@ -2812,7 +2832,7 @@ char * add_var( struct ctl_var **kv, u_long size, - int def + u_short def ) { register u_long c; @@ -2841,7 +2861,7 @@ set_var( struct ctl_var **kv, const char *data, u_long size, - int def + u_short def ) { register struct ctl_var *k; @@ -2852,7 +2872,8 @@ set_var( if (!data || !size) return; - if ((k = *kv)) { + k = *kv; + if (k != NULL) { while (!(k->flags & EOV)) { s = data; t = k->text; @@ -2887,7 +2908,7 @@ void set_sys_var( char *data, u_long size, - int def + u_short def ) { set_var(&ext_sys_var, data, size, def); diff --git a/contrib/ntp/ntpd/ntp_crypto.c b/contrib/ntp/ntpd/ntp_crypto.c index 19f902a..3e67703 100644 --- a/contrib/ntp/ntpd/ntp_crypto.c +++ b/contrib/ntp/ntpd/ntp_crypto.c @@ -5,136 +5,167 @@ #include #endif -#ifdef AUTOKEY +#ifdef OPENSSL #include #include +#include #include #include #include "ntpd.h" #include "ntp_stdlib.h" +#include "ntp_unixtime.h" #include "ntp_string.h" -#include "ntp_crypto.h" + +#include "openssl/asn1_mac.h" +#include "openssl/bn.h" +#include "openssl/err.h" +#include "openssl/evp.h" +#include "openssl/pem.h" +#include "openssl/rand.h" +#include "openssl/x509v3.h" #ifdef KERNEL_PLL #include "ntp_syscall.h" #endif /* KERNEL_PLL */ /* - * Extension field message formats - * - * +-------+-------+ +-------+-------+ +-------+-------+ - * 0 | 3 | len | | 2,4 | len | | 5-9 | len | - * +-------+-------+ +-------+-------+ +-------+-------+ - * 1 | assocID | | assocID | | assocID | - * +---------------+ +---------------+ +---------------+ - * 2 | timestamp | | timestamp | | timestamp | - * +---------------+ +---------------+ +---------------+ - * 3 | final seq | | cookie/flags | | filestamp | - * +---------------+ +---------------+ +---------------+ - * 4 | final key | | signature len | | value len | - * +---------------+ +---------------+ +---------------+ - * 5 | signature len | | | | | - * +---------------+ = signature = = value = - * 6 | | | | | | - * = signature = +---------------+ +---------------+ - * 7 | | CRYPTO_ASSOC rsp | signature len | - * +---------------+ CRYPTO_PRIV rsp +---------------+ - * CRYPTO_AUTO rsp | | - * = signature = - * | | - * +---------------+ - * CRYPTO_DHPAR rsp - * CRYPTO_DH rsp - * CRYPTO_NAME rsp - * CRYPTO_CERT rsp - * CRYPTO_TAI rsp - * - * CRYPTO_STAT 1 - offer/select - * CRYPTO_ASSOC 2 20 association ID - * CRYPTO_AUTO 3 88 autokey values - * CRYPTO_PRIV 4 84 cookie value - * CRYPTO_DHPAR 5 220 agreement parameters - * CRYPTO_DH 6 152 public value - * CRYPTO_NAME 7 460 host name/public key - * CRYPTO_CERT 8 ? certificate - * CRYPTO_TAI 9 144 leapseconds table - * - * Note: requests carry the association ID of the receiver; responses - * carry the association ID of the sender. + * Extension field message format + * + * These are always signed and saved before sending in network byte + * order. They must be converted to and from host byte order for + * processing. + * + * +-------+-------+ + * | op | len | <- extension pointer + * +-------+-------+ + * | assocID | + * +---------------+ + * | timestamp | <- value pointer + * +---------------+ + * | filestamp | + * +---------------+ + * | value len | + * +---------------+ + * | | + * = value = + * | | + * +---------------+ + * | signature len | + * +---------------+ + * | | + * = signature = + * | | + * +---------------+ + * + * The CRYPTO_RESP bit is set to 0 for requests, 1 for responses. + * Requests carry the association ID of the receiver; responses carry + * the association ID of the sender. Some messages include only the + * operation/length and association ID words and so have length 8 + * octets. Ohers include the value structure and associated value and + * signature fields. These messages include the timestamp, filestamp, + * value and signature words and so have length at least 24 octets. The + * signature and/or value fields can be empty, in which case the + * respective length words are zero. An empty value with nonempty + * signature is syntactically valid, but semantically questionable. + * + * The filestamp represents the time when a cryptographic data file such + * as a public/private key pair is created. It follows every reference + * depending on that file and serves as a means to obsolete earlier data + * of the same type. The timestamp represents the time when the + * cryptographic data of the message were last signed. Creation of a + * cryptographic data file or signing a message can occur only when the + * 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. */ /* - * Minimum sizes of fields + * Cryptodefines */ -#define COOKIE_LEN (5 * 4) -#define AUTOKEY_LEN (6 * 4) -#define VALUE_LEN (6 * 4) +#define TAI_1972 10 /* initial TAI offset (s) */ +#define MAX_LEAP 100 /* max UTC leapseconds (s) */ +#define VALUE_LEN (6 * 4) /* min response field length */ +#define YEAR (60 * 60 * 24 * 365) /* seconds in year */ /* - * Global cryptodata in host byte order. + * Global cryptodata in host byte order */ -u_int crypto_flags; /* status word */ +u_int32 crypto_flags = 0x0; /* status word */ u_int sys_tai; /* current UTC offset from TAI */ -#ifdef PUBKEY -/* - * Cryptodefines - */ -#define TAI_1972 10 /* initial TAI offset */ -#define MAX_LEAP 100 /* max UTC leapseconds */ -#define MAX_LINLEN 1024 /* max line */ -#define MAX_KEYLEN 1024 /* max key */ -#define MAX_ENCLEN (ENCODED_CONTENT_LEN(1024)) /* max enc key */ - /* - * Private cryptodata in network byte order. + * Global cryptodata in network byte order */ -static R_RSA_PRIVATE_KEY private_key; /* private key */ -static R_RSA_PUBLIC_KEY public_key; /* public key */ -static R_DH_PARAMS dh_params; /* agreement parameters */ -static u_char *dh_private; /* private value */ -static u_int dh_keyLen; /* private value length */ -static char *keysdir = NTP_KEYSDIR; /* crypto keys directory */ -static char *private_key_file = NULL; /* private key file */ -static char *public_key_file = NULL; /* public key file */ -static char *certif_file = NULL; /* certificate file */ -static char *dh_params_file = NULL; /* agreement parameters file */ -static char *tai_leap_file = NULL; /* leapseconds file */ +struct cert_info *cinfo = NULL; /* certificate info/value */ +struct value hostval; /* host value */ +struct value pubkey; /* public key */ +struct value tai_leap; /* leapseconds table */ /* - * Global cryptodata in network byte order + * Private cryptodata in host byte order */ -struct value host; /* host name/public key */ -struct value certif; /* certificate */ -struct value dhparam; /* agreement parameters */ -struct value dhpub; /* public value */ -struct value tai_leap; /* leapseconds table */ +static char *passwd = NULL; /* private key password */ +static EVP_PKEY *host_pkey = NULL; /* host key */ +static EVP_PKEY *sign_pkey = NULL; /* sign key */ +static EVP_PKEY *iffpar_pkey = NULL; /* IFF parameters */ +static EVP_PKEY *gqpar_pkey = NULL; /* GQ parameters */ +static EVP_PKEY *mvpar_pkey = NULL; /* MV parameters */ +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 *iffpar_file = NULL; /* IFF parameters file */ +static char *gqpar_file = NULL; /* GQ parameters file */ +static char *mvpar_file = NULL; /* MV parameters file */ +static char *cert_file = NULL; /* certificate file */ +static char *leap_file = NULL; /* leapseconds file */ +static tstamp_t if_fstamp = 0; /* IFF file stamp */ +static tstamp_t gq_fstamp = 0; /* GQ file stamp */ +static tstamp_t mv_fstamp = 0; /* MV file stamp */ /* * Cryptotypes */ -static u_int crypto_rsa P((char *, u_char *, u_int)); -static void crypto_cert P((char *)); -static void crypto_dh P((char *)); +static int crypto_verify P((struct exten *, struct value *, + struct peer *)); +static int crypto_encrypt P((struct exten *, struct value *, + keyid_t *)); +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 *)); -#endif /* PUBKEY */ -/* - * Autokey protocol status codes - */ -#define RV_OK 0 /* success */ -#define RV_LEN 1 /* invalid field length */ -#define RV_TSP 2 /* invalid timestamp */ -#define RV_FSP 3 /* invalid filestamp */ -#define RV_PUB 4 /* missing public key */ -#define RV_KEY 5 /* invalid RSA modulus */ -#define RV_SIG 6 /* invalid signature length */ -#define RV_DH 7 /* invalid agreement parameters */ -#define RV_FIL 8 /* missing or corrupted key file */ -#define RV_DAT 9 /* missing or corrupted data */ -#define RV_DEC 10 /* PEM decoding error */ -#define RV_DUP 11 /* duplicate flags */ -#define RV_VN 12 /* incorrect version */ +#ifdef SYS_WINNT +int +readlink(char * link, char * file, int len) { + return (-1); +} +#endif /* * session_key - generate session key @@ -143,43 +174,61 @@ static void crypto_tai P((char *)); * destination address, key ID and private value. The value of the * 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 */ -keyid_t /* returns next key ID */ +keyid_t session_key( - struct sockaddr_in *srcadr, /* source address */ - struct sockaddr_in *dstadr, /* destination address */ - keyid_t keyno, /* key ID */ - keyid_t private, /* private value */ - u_long lifetime /* key lifetime */ + struct sockaddr_storage *srcadr, /* source address */ + struct sockaddr_storage *dstadr, /* destination address */ + keyid_t keyno, /* key ID */ + keyid_t private, /* private value */ + u_long lifetime /* key lifetime */ ) { - MD5_CTX ctx; /* MD5 context */ - keyid_t keyid; /* key identifer */ - u_int32 header[4]; /* data in network byte order */ - u_char digest[16]; /* message digest */ + EVP_MD_CTX ctx; /* message digest context */ + u_char dgst[EVP_MAX_MD_SIZE]; /* message digest */ + keyid_t keyid; /* key identifer */ + u_int32 header[10]; /* data in network byte order */ + u_int hdlen, len; /* * Generate the session key and key ID. If the lifetime is * greater than zero, install the key and call it trusted. */ - header[0] = srcadr->sin_addr.s_addr; - header[1] = dstadr->sin_addr.s_addr; - header[2] = htonl(keyno); - header[3] = htonl(private); - MD5Init(&ctx); - MD5Update(&ctx, (u_char *)header, sizeof(header)); - MD5Final(digest, &ctx); - memcpy(&keyid, digest, 4); + hdlen = 0; + switch(srcadr->ss_family) { + case AF_INET: + header[0] = ((struct sockaddr_in *)srcadr)->sin_addr.s_addr; + header[1] = ((struct sockaddr_in *)dstadr)->sin_addr.s_addr; + header[2] = htonl(keyno); + header[3] = htonl(private); + hdlen = 4 * sizeof(u_int32); + break; + case AF_INET6: + memcpy(&header[0], &GET_INADDR6(*srcadr), + sizeof(struct in6_addr)); + memcpy(&header[4], &GET_INADDR6(*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_DigestUpdate(&ctx, (u_char *)header, hdlen); + EVP_DigestFinal(&ctx, dgst, &len); + memcpy(&keyid, dgst, 4); keyid = ntohl(keyid); if (lifetime != 0) { - MD5auth_setkey(keyno, digest, 16); + MD5auth_setkey(keyno, dgst, len); authtrust(keyno, lifetime); } #ifdef DEBUG if (debug > 1) printf( "session_key: %s > %s %08x %08x hash %08x life %lu\n", - numtoa(header[0]), numtoa(header[1]), keyno, + stoa(srcadr), stoa(dstadr), keyno, private, keyid, lifetime); #endif return (keyid); @@ -201,26 +250,22 @@ make_keylist( struct interface *dstadr /* interface */ ) { + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; /* NTP timestamp */ struct autokey *ap; /* autokey pointer */ - keyid_t keyid; /* next key ID */ - keyid_t cookie; /* private value */ - l_fp tstamp; /* NTP timestamp */ - u_long ltemp; - int i; -#ifdef PUBKEY - R_SIGNATURE_CTX ctx; /* signature context */ - int rval; /* return value */ - u_int len; -#endif /* PUBKEY */ + struct value *vp; /* value pointer */ + keyid_t keyid = 0; /* next key ID */ + keyid_t cookie; /* private value */ + u_long lifetime; + u_int len; + int i; /* * Allocate the key list if necessary. */ - L_CLR(&tstamp); - if (sys_leap != LEAP_NOTINSYNC) - get_systime(&tstamp); + tstamp = crypto_time(); if (peer->keylist == NULL) - peer->keylist = (keyid_t *)emalloc(sizeof(keyid_t) * + peer->keylist = emalloc(sizeof(keyid_t) * NTP_MAXSESSION); /* @@ -243,55 +288,57 @@ make_keylist( * included in the hash is zero if broadcast mode, the peer * cookie if client mode or the host cookie if symmetric modes. */ - ltemp = min(sys_automax, NTP_MAXSESSION * (1 << (peer->kpoll))); - peer->hcookie = session_key(&dstadr->sin, &peer->srcadr, 0, - sys_private, 0); + lifetime = min(sys_automax, (unsigned long) NTP_MAXSESSION * (1 <<(peer->kpoll))); if (peer->hmode == MODE_BROADCAST) cookie = 0; else - cookie = peer->pcookie.key; + cookie = peer->pcookie; for (i = 0; i < NTP_MAXSESSION; i++) { peer->keylist[i] = keyid; peer->keynumber = i; keyid = session_key(&dstadr->sin, &peer->srcadr, keyid, - cookie, ltemp); - ltemp -= 1 << peer->kpoll; + cookie, lifetime); + lifetime -= 1 << peer->kpoll; if (auth_havekey(keyid) || keyid <= NTP_MAXKEY || - ltemp <= (1 << (peer->kpoll))) + lifetime <= (unsigned long)(1 << (peer->kpoll))) break; } /* * Save the last session key ID, sequence number and timestamp, * then sign these values for later retrieval by the clients. Be - * careful not to use invalid key media. + * careful not to use invalid key media. Use the public values + * timestamp as filestamp. */ - ap = &peer->sndauto; - ap->tstamp = htonl(tstamp.l_ui); + vp = &peer->sndval; + if (vp->ptr == NULL) + vp->ptr = emalloc(sizeof(struct autokey)); + ap = (struct autokey *)vp->ptr; ap->seq = htonl(peer->keynumber); ap->key = htonl(keyid); - ap->siglen = 0; -#if DEBUG + vp->tstamp = htonl(tstamp); + vp->fstamp = hostval.tstamp; + vp->vallen = htonl(sizeof(struct autokey)); + vp->siglen = 0; + if (vp->tstamp != 0) { + 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)) + vp->siglen = htonl(len); + else + msyslog(LOG_ERR, "make_keys %s\n", + ERR_error_string(ERR_get_error(), NULL)); + peer->flags |= FLAG_ASSOC; + } +#ifdef DEBUG if (debug) - printf("make_keys: %d %08x %08x ts %u poll %d\n", + printf("make_keys: %d %08x %08x ts %u fs %u poll %d\n", ntohl(ap->seq), ntohl(ap->key), cookie, - ntohl(ap->tstamp), peer->kpoll); + ntohl(vp->tstamp), ntohl(vp->fstamp), peer->kpoll); #endif -#ifdef PUBKEY - if(!crypto_flags) - return; - if (ap->sig == NULL) - ap->sig = emalloc(private_key.bits / 8); - EVP_SignInit(&ctx, DA_MD5); - EVP_SignUpdate(&ctx, (u_char *)ap, 12); - rval = EVP_SignFinal(&ctx, ap->sig, &len, &private_key); - if (rval != RV_OK) - msyslog(LOG_ERR, "crypto: keylist signature fails %x", - rval); - else - ap->siglen = htonl(len); - peer->flags |= FLAG_ASSOC; -#endif /* PUBKEY */ } @@ -303,688 +350,778 @@ make_keylist( * extension field values only if the field has proper format and * length, the timestamp and filestamp are valid and the signature has * valid length and is verified. There are a few cases where some values - * are believed even if the signature fails, but only if the authentic + * are believed even if the signature fails, but only if the proventic * bit is not set. */ -void +int crypto_recv( struct peer *peer, /* peer structure pointer */ struct recvbuf *rbufp /* packet buffer pointer */ ) { - u_int32 *pkt; /* packet pointer */ - struct autokey *ap; /* autokey pointer */ - struct cookie *cp; /* cookie pointer */ - int has_mac; /* length of MAC field */ - int authlen; /* offset of MAC field */ - int len; /* extension field length */ - u_int code; /* extension field opcode */ - tstamp_t tstamp; /* timestamp */ - int i, rval; - u_int temp; -#ifdef PUBKEY - R_SIGNATURE_CTX ctx; /* signature context */ - struct value *vp; /* value pointer */ - u_char dh_key[MAX_KEYLEN]; /* agreed key */ - R_RSA_PUBLIC_KEY *kp; /* temporary public key pointer */ - tstamp_t fstamp; /* filestamp */ - u_int32 *pp; /* packet pointer */ - u_int rsalen = sizeof(R_RSA_PUBLIC_KEY) - sizeof(u_int) + 4; - u_int bits; - int j; + const EVP_MD *dp; /* message digest algorithm */ + u_int32 *pkt; /* receive packet pointer */ + struct autokey *ap, *bp; /* autokey pointer */ + struct exten *ep, *fp; /* extension pointers */ + 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 */ + u_int vallen = 0; /* value length */ + X509 *cert; /* X509 certificate */ + char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ + keyid_t cookie; /* crumbles */ + int rval = XEVNT_OK; + u_char *ptr; + u_int32 temp32; #ifdef KERNEL_PLL #if NTP_API > 3 struct timex ntv; /* kernel interface structure */ #endif /* NTP_API */ #endif /* KERNEL_PLL */ -#endif /* PUBKEY */ /* * Initialize. Note that the packet has already been checked for - * valid format and extension field lengths. We first extract - * the field length, command code and timestamp in host byte - * order. These are used with all commands and modes. We discard - * old timestamps and filestamps; but, for duplicate timestamps - * we discard only if the authentic bit is set. Cute. + * valid format and extension field lengths. First extract the + * field length, command code and association ID in host byte + * order. These are used with all commands and modes. Then check + * the version number, which must be 2, and length, which must + * be at least 8 for requests and VALUE_LEN (24) for responses. + * Packets that fail either test sink without a trace. The + * association ID is saved only if nonzero. */ - pkt = (u_int32 *)&rbufp->recv_pkt; authlen = LEN_PKT_NOMAC; while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) { - i = authlen / 4; - len = ntohl(pkt[i]) & 0xffff; - code = (ntohl(pkt[i]) >> 16) & 0xffff; - temp = (code >> 8) & 0x3f; - if (temp != CRYPTO_VN) { - sys_unknownversion++; -#ifdef DEBUG - if (debug) - printf( - "crypto_recv: incorrect version %d should be %d\n", - temp, CRYPTO_VN); -#endif - return; - } - tstamp = ntohl(pkt[i + 2]); + 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]); + rval = XEVNT_OK; #ifdef DEBUG if (debug) printf( - "crypto_recv: ext offset %d len %d code %x assocID %d\n", - authlen, len, code, (u_int32)ntohl(pkt[i + - 1])); + "crypto_recv: flags 0x%x ext offset %d len %u code %x assocID %d\n", + peer->crypto, authlen, len, code >> 16, + associd); #endif + + /* + * Check version number and field length. If bad, + * quietly ignore the packet. + */ + if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8 || + (len < VALUE_LEN && (code & CRYPTO_RESP))) { + sys_unknownversion++; + 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); + } switch (code) { /* - * Install association ID and status word. + * Install status word, host name, signature scheme and + * association ID. In OpenSSL the signature algorithm is + * bound to the digest algorithm, so the NID completely + * defines the signature scheme. Note the request and + * response are identical, but neither is validated by + * signature. The request is processed here only in + * symmetric modes. The server name field would be + * useful to implement access controls in future. */ + case CRYPTO_ASSOC: + + /* + * Pass the extension field to the transmit + * side. + */ + fp = emalloc(len); + memcpy(fp, ep, len); + temp32 = CRYPTO_RESP; + fp->opcode |= htonl(temp32); + peer->cmmd = fp; + /* fall through */ + case CRYPTO_ASSOC | CRYPTO_RESP: - cp = (struct cookie *)&pkt[i + 2]; - temp = ntohl(cp->key); - if (len < COOKIE_LEN) { - rval = RV_LEN; - } else if (tstamp == 0) { - rval = RV_TSP; - } else { - if (!peer->crypto) - peer->crypto = temp; - if (ntohl(pkt[i + 1]) != 0) - peer->assoc = ntohl(pkt[i + 1]); - rval = RV_OK; + + /* + * Discard the message if it has already been + * stored or the server is not synchronized. + */ + if (peer->crypto || !fstamp) + break; + + if (len < VALUE_LEN + vallen) { + rval = XEVNT_LEN; + break; + } + + /* + * 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 + * has IFF or GC or both, the server must have + * the same one or both. Otherwise, the default + * TC scheme is used. + */ + if (crypto_flags & CRYPTO_FLAG_PRIV) { + if (!(fstamp & CRYPTO_FLAG_PRIV)) + rval = XEVNT_KEY; + else + fstamp |= CRYPTO_FLAG_VALID | + CRYPTO_FLAG_VRFY; + } else if (crypto_flags & CRYPTO_FLAG_MASK && + !(crypto_flags & fstamp & + CRYPTO_FLAG_MASK)) { + rval = XEVNT_KEY; } + + /* + * Discard the message if identity error. + */ + if (rval != XEVNT_OK) + break; + + /* + * Discard the message if the host name length + * is unreasonable or the signature digest NID + * is not supported. + */ + temp32 = (fstamp >> 16) & 0xffff; + dp = + (const EVP_MD *)EVP_get_digestbynid(temp32); + if (vallen == 0 || vallen > MAXHOSTNAME) + rval = XEVNT_LEN; + else if (dp == NULL) + rval = XEVNT_MD; + if (rval != XEVNT_OK) + break; + + /* + * Save status word, host name and message + * digest/signature type. If PC identity, be + * sure not to sign the certificate. + */ + if (crypto_flags & CRYPTO_FLAG_PRIV) + fstamp |= CRYPTO_FLAG_SIGN; + peer->crypto = fstamp; + peer->digest = dp; + 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; + sprintf(statstr, + "flags 0x%x host %s signature %s", fstamp, + peer->subject, OBJ_nid2ln(temp32)); + record_crypto_stats(&peer->srcadr, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_recv: verify %d flags 0x%x ts %u\n", - rval, temp, tstamp); + printf("crypto_recv: %s\n", statstr); #endif break; /* - * Install autokey values in broadcast client and - * symmetric modes. + * Decode X509 certificate in ASN.1 format and extract + * the data containing, among other things, subject + * name and public key. In the default identification + * scheme, the certificate trail is followed to a self + * signed trusted certificate. */ - case CRYPTO_AUTO | CRYPTO_RESP: - if (!(peer->flags & FLAG_AUTOKEY) && - ntohl(pkt[i + 1]) != 0) - peer->assoc = ntohl(pkt[i + 1]); - ap = (struct autokey *)&pkt[i + 2]; -#ifdef PUBKEY - temp = ntohl(ap->siglen); - kp = (R_RSA_PUBLIC_KEY *)peer->pubkey.ptr; - if (len < AUTOKEY_LEN) { - rval = RV_LEN; - } else if (tstamp == 0 || tstamp < - peer->recauto.tstamp || (tstamp == - peer->recauto.tstamp && (peer->flags & - FLAG_AUTOKEY))) { - rval = RV_TSP; - } else if (!crypto_flags) { - rval = RV_OK; - } else if (kp == NULL) { - rval = RV_PUB; - } else if (temp != kp->bits / 8) { - rval = RV_SIG; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)ap, - 12); - rval = EVP_VerifyFinal(&ctx, - (u_char *)ap->pkt, temp, kp); + case CRYPTO_CERT | CRYPTO_RESP: + + /* + * Discard the message if invalid or identity + * already confirmed. + */ + if (peer->crypto & CRYPTO_FLAG_VRFY) + break; + + if ((rval = crypto_verify(ep, NULL, peer)) != + XEVNT_OK) + break; + + /* + * Scan the certificate list to delete old + * versions and link the newest version first on + * the list. + */ + if ((rval = cert_install(ep, peer)) != 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 group key in + * the first certificate received. However, note + * that this certificate might not be signed by + * the server, so we can't check the + * signature/digest NID. + */ + if (peer->pkey == NULL) { + ptr = (u_char *)cinfo->cert.ptr; + cert = d2i_X509(NULL, &ptr, + ntohl(cinfo->cert.vallen)); + peer->pkey = X509_get_pubkey(cert); + X509_free(cert); } -#else /* PUBKEY */ - if (tstamp < peer->recauto.tstamp || (tstamp == - peer->recauto.tstamp && (peer->flags & - FLAG_AUTOKEY))) - rval = RV_TSP; - else - rval = RV_OK; -#endif /* PUBKEY */ + peer->flash &= ~TEST10; + temp32 = cinfo->nid; + sprintf(statstr, "cert %s 0x%x %s (%u) fs %u", + cinfo->subject, cinfo->flags, + OBJ_nid2ln(temp32), temp32, + ntohl(ep->fstamp)); + record_crypto_stats(&peer->srcadr, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_recv: verify %x autokey %d %08x ts %u (%u)\n", - rval, ntohl(ap->seq), - ntohl(ap->key), tstamp, - peer->recauto.tstamp); + printf("crypto_recv: %s\n", statstr); #endif - if (rval != RV_OK) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x autokey %d %08x ts %u (%u)\n", - rval, ntohl(ap->seq), - ntohl(ap->key), tstamp, - peer->recauto.tstamp); - break; - } - peer->flags |= FLAG_AUTOKEY; - peer->flash &= ~TEST10; - peer->assoc = ntohl(pkt[i + 1]); - peer->recauto.tstamp = tstamp; - peer->recauto.seq = ntohl(ap->seq); - peer->recauto.key = ntohl(ap->key); - peer->pkeyid = peer->recauto.key; break; /* - * Install session cookie in client mode. Use this also - * in symmetric modes for test when rsaref20 has not - * been installed. + * 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 + * server contain the same secret group key. */ - case CRYPTO_PRIV: - peer->cmmd = ntohl(pkt[i]); - /* fall through */ + case CRYPTO_IFF | CRYPTO_RESP: - case CRYPTO_PRIV | CRYPTO_RESP: - cp = (struct cookie *)&pkt[i + 2]; -#ifdef PUBKEY - temp = ntohl(cp->siglen); - kp = (R_RSA_PUBLIC_KEY *)peer->pubkey.ptr; - if (len < COOKIE_LEN) { - rval = RV_LEN; - } else if (tstamp == 0 || tstamp < - peer->pcookie.tstamp || (tstamp == - peer->pcookie.tstamp && (peer->flags & - FLAG_AUTOKEY))) { - rval = RV_TSP; - } else if (!crypto_flags) { - rval = RV_OK; - } else if (kp == NULL) { - rval = RV_PUB; - } else if (temp != kp->bits / 8) { - rval = RV_SIG; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)cp, 8); - rval = EVP_VerifyFinal(&ctx, - (u_char *)cp->pkt, temp, kp); - } -#else /* PUBKEY */ - if (tstamp <= peer->pcookie.tstamp || (tstamp == - peer->pcookie.tstamp && (peer->flags & - FLAG_AUTOKEY))) - rval = RV_TSP; - else - rval = RV_OK; -#endif /* PUBKEY */ + /* + * Discard the message if invalid or identity + * already confirmed. + */ + if (peer->crypto & CRYPTO_FLAG_VRFY) + break; + + if ((rval = crypto_verify(ep, NULL, peer)) != + XEVNT_OK) + break; /* - * Tricky here. If in client mode, use the - * server cookie; otherwise, use EXOR of both - * peer cookies. We call this Daffy-Hooligan - * agreement. + * If the the challenge matches the response, + * the certificate public key, as well as the + * server public key, signatyre 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. */ - if (peer->hmode == MODE_CLIENT) - temp = ntohl(cp->key); - else - temp = ntohl(cp->key) ^ peer->hcookie; + if ((rval = crypto_iff(ep, peer)) != XEVNT_OK) + break; + + peer->crypto |= CRYPTO_FLAG_VRFY | + CRYPTO_FLAG_PROV; + peer->flash &= ~TEST10; + sprintf(statstr, "iff fs %u", + ntohl(ep->fstamp)); + record_crypto_stats(&peer->srcadr, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_recv: verify %x cookie %08x ts %u (%u)\n", - rval, temp, tstamp, - peer->pcookie.tstamp); + printf("crypto_recv: %s\n", statstr); #endif - if (rval != RV_OK) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x cookie %08x ts %u (%u)\n", - rval, temp, tstamp, - peer->pcookie.tstamp); - peer->cmmd |= CRYPTO_ERROR; - break; - } - if (!(peer->cast_flags & MDF_BCLNT)) - peer->flags |= FLAG_AUTOKEY; - peer->flash &= ~TEST10; - peer->assoc = ntohl(pkt[i + 1]); - peer->pcookie.tstamp = tstamp; - if (temp != peer->pcookie.key) { - peer->pcookie.key = temp; - key_expire(peer); - } break; /* - * The following commands and responses work only when - * public-key cryptography has been configured. If - * configured, but disabled due to no crypto command in - * the configuration file, they are ignored. - */ -#ifdef PUBKEY - /* - * Install public key and host name. + * Guillou-Quisquater (GQ) identity scheme. This scheme + * is designed for use with public certificates carrying + * the GQ public key in an extension field. 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 group key and the server has the matching GQ + * private key. */ - case CRYPTO_NAME | CRYPTO_RESP: - if (!crypto_flags) + case CRYPTO_GQ | CRYPTO_RESP: + + /* + * Discard the message if invalid or identity + * already confirmed. + */ + if (peer->crypto & CRYPTO_FLAG_VRFY) break; - vp = (struct value *)&pkt[i + 2]; - fstamp = ntohl(vp->fstamp); - temp = ntohl(vp->vallen); - j = i + 5 + ntohl(vp->vallen) / 4; - bits = ntohl(pkt[i + 5]); - if (len < VALUE_LEN) { - rval = RV_LEN; - } else if (temp < rsalen || bits < - MIN_RSA_MODULUS_BITS || bits > - MAX_RSA_MODULUS_BITS) { - rval = RV_KEY; - } else if (ntohl(pkt[j]) != bits / 8) { - rval = RV_SIG; - } else if (tstamp == 0 || tstamp < - peer->pubkey.tstamp || (tstamp == - peer->pubkey.tstamp && (peer->flags & - FLAG_AUTOKEY))) { - rval = RV_TSP; - } else if (tstamp < peer->pubkey.fstamp || - fstamp < peer->pubkey.fstamp) { - rval = RV_FSP; - } else if (fstamp == peer->pubkey.fstamp && - (peer->flags & FLAG_AUTOKEY)) { - rval = RV_FSP; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)vp, - temp + 12); - kp = emalloc(sizeof(R_RSA_PUBLIC_KEY)); - kp->bits = bits; - memcpy(kp->modulus, &pkt[i + 6], - rsalen - 4); - rval = EVP_VerifyFinal(&ctx, - (u_char *)&pkt[j + 1], - ntohl(pkt[j]), kp); - if (rval != 0) { - free(kp); - } else { - j = i + 5 + rsalen / 4; - peer->pubkey.ptr = (u_char *)kp; - temp = strlen((char *)&pkt[j]); - peer->keystr = emalloc(temp + - 1); - strcpy(peer->keystr, - (char *)&pkt[j]); - peer->pubkey.tstamp = tstamp; - peer->pubkey.fstamp = fstamp; - peer->flash &= ~TEST10; - if (!(peer->crypto & - CRYPTO_FLAG_CERT)) - peer->flags |= - FLAG_PROVEN; - } - } + + 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 + * all verified at the same time. The server is + * declared trusted, so we skip further + * certificate stages and move immediately to + * the cookie stage. + */ + if ((rval = crypto_gq(ep, peer)) != XEVNT_OK) + break; + + peer->crypto |= CRYPTO_FLAG_VRFY | + CRYPTO_FLAG_PROV; + peer->flash &= ~TEST10; + sprintf(statstr, "gq fs %u", + ntohl(ep->fstamp)); + record_crypto_stats(&peer->srcadr, statstr); #ifdef DEBUG if (debug) - - printf( - "crypto_recv: verify %x host %s ts %u fs %u\n", - rval, (char *)&pkt[i + 5 + rsalen / - 4], tstamp, fstamp); + printf("crypto_recv: %s\n", statstr); #endif - if (rval != RV_OK) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x host %s ts %u fs %u\n", - rval, (char *)&pkt[i + 5 + - rsalen / 4], tstamp, - fstamp); - } break; /* - * Install certificate. + * MV */ - case CRYPTO_CERT | CRYPTO_RESP: - if (!crypto_flags) + case CRYPTO_MV | CRYPTO_RESP: + + /* + * Discard the message if invalid or identity + * already confirmed. + */ + if (peer->crypto & CRYPTO_FLAG_VRFY) break; - vp = (struct value *)&pkt[i + 2]; - fstamp = ntohl(vp->fstamp); - temp = ntohl(vp->vallen); - kp = (R_RSA_PUBLIC_KEY *)peer->pubkey.ptr; - j = i + 5 + temp / 4; - if (len < VALUE_LEN) { - rval = RV_LEN; - } else if (kp == NULL) { - rval = RV_PUB; - } else if (ntohl(pkt[j]) != kp->bits / 8) { - rval = RV_SIG; - } else if (tstamp == 0) { - rval = RV_TSP; - } else if (tstamp < - ntohl(peer->certif.fstamp) || fstamp < - ntohl(peer->certif.fstamp)) { - rval = RV_FSP; - } else if (fstamp == - ntohl(peer->certif.fstamp) && (peer->flags & - FLAG_AUTOKEY)) { - peer->crypto &= ~CRYPTO_FLAG_CERT; - rval = RV_FSP; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)vp, - temp + 12); - rval = EVP_VerifyFinal(&ctx, - (u_char *)&pkt[j + 1], - ntohl(pkt[j]), kp); - } + + 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 + * all verified at the same time. The server is + * declared trusted, so we skip further + * certificate stages and move immediately to + * the cookie stage. + */ + if ((rval = crypto_mv(ep, peer)) != XEVNT_OK) + break; + + peer->crypto |= CRYPTO_FLAG_VRFY | + CRYPTO_FLAG_PROV; + peer->flash &= ~TEST10; + sprintf(statstr, "mv fs %u", + ntohl(ep->fstamp)); + record_crypto_stats(&peer->srcadr, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_recv: verify %x certificate %u ts %u fs %u\n", - rval, temp, tstamp, fstamp); + printf("crypto_recv: %s\n", statstr); #endif + break; + + /* + * X509 certificate sign response. Validate the + * certificate signed by the server and install. Later + * this can be provided to clients of this server in + * lieu of the self signed certificate in order to + * validate the public key. + */ + case CRYPTO_SIGN | CRYPTO_RESP: /* - * If the peer data are newer than the host - * data, replace the host data. Otherwise, - * wait for the peer to fetch the host data. + * Discard the message if invalid or identity + * not confirmed. */ - if (rval != RV_OK || temp == 0) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x certificate %u ts %u fs %u\n", - rval, temp, tstamp, fstamp); + if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + break; + + if ((rval = crypto_verify(ep, NULL, peer)) != + XEVNT_OK) break; - } - peer->flash &= ~TEST10; - peer->flags |= FLAG_PROVEN; - peer->crypto &= ~CRYPTO_FLAG_CERT; /* - * Initialize agreement parameters and extension - * field in network byte order. Note the private - * key length is set arbitrarily at half the - * prime length. + * Scan the certificate list to delete old + * versions and link the newest version first on + * the list. */ - peer->certif.tstamp = vp->tstamp; - peer->certif.fstamp = vp->fstamp; - peer->certif.vallen = vp->vallen; - if (peer->certif.ptr == NULL) - free(peer->certif.ptr); - peer->certif.ptr = emalloc(temp); - memcpy(peer->certif.ptr, vp->pkt, temp); - crypto_agree(); + if ((rval = cert_install(ep, peer)) != XEVNT_OK) break; + + peer->crypto |= CRYPTO_FLAG_SIGN; + peer->flash &= ~TEST10; + temp32 = cinfo->nid; + sprintf(statstr, "sign %s 0x%x %s (%u) fs %u", + cinfo->issuer, cinfo->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 break; /* - * Install agreement parameters in symmetric modes. + * Cookie request in symmetric modes. Roll a random + * cookie and install in symmetric mode. Encrypt for the + * response, which is transmitted later. */ - case CRYPTO_DHPAR | CRYPTO_RESP: - if (!crypto_flags) + case CRYPTO_COOK: + + /* + * Discard the message if invalid or identity + * not confirmed. + */ + if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + 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 &= ~TEST10; break; - vp = (struct value *)&pkt[i + 2]; - fstamp = ntohl(vp->fstamp); - temp = ntohl(vp->vallen); - kp = (R_RSA_PUBLIC_KEY *)peer->pubkey.ptr; - j = i + 5 + temp / 4; - if (len < VALUE_LEN) { - rval = RV_LEN; - } else if (kp == NULL) { - rval = RV_PUB; - } else if (ntohl(pkt[j]) != kp->bits / 8) { - rval = RV_SIG; - } else if (tstamp == 0) { - rval = RV_TSP; - } else if (tstamp < ntohl(dhparam.fstamp) || - fstamp < ntohl(dhparam.fstamp)) { - rval = RV_FSP; - } else if (fstamp == ntohl(dhparam.fstamp) && - (peer->flags & FLAG_AUTOKEY)) { - peer->crypto &= ~CRYPTO_FLAG_DH; - rval = RV_FSP; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)vp, - temp + 12); - rval = EVP_VerifyFinal(&ctx, - (u_char *)&pkt[j + 1], - ntohl(pkt[j]), kp); } + + /* + * 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 &= ~TEST10; + sprintf(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: verify %x parameters %u ts %u fs %u\n", - rval, temp, tstamp, fstamp); + printf("crypto_recv: %s\n", statstr); #endif + break; + + /* + * Cookie response in client and symmetric modes. If the + * cookie bit is set, the working cookie is the EXOR of + * the current and new values. + */ + case CRYPTO_COOK | CRYPTO_RESP: /* - * If the peer data are newer than the host - * data, replace the host data. Otherwise, - * wait for the peer to fetch the host data. + * Discard the message if invalid or identity + * not confirmed or signature not verified with + * respect to the cookie values. */ - if (rval != RV_OK || temp == 0) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x parameters %u ts %u fs %u\n", - rval, temp, tstamp, fstamp); + if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + break; + + if ((rval = crypto_verify(ep, &peer->cookval, + peer)) != XEVNT_OK) break; - } - peer->flash &= ~TEST10; - crypto_flags |= CRYPTO_FLAG_DH; - peer->crypto &= ~CRYPTO_FLAG_DH; /* - * Initialize agreement parameters and extension - * field in network byte order. Note the private - * key length is set arbitrarily at half the - * prime length. + * Decrypt the cookie, hunting all the time for + * errors. */ - dhparam.tstamp = vp->tstamp; - dhparam.fstamp = vp->fstamp; - dhparam.vallen = vp->vallen; - if (dhparam.ptr != NULL) - free(dhparam.ptr); - pp = emalloc(temp); - dhparam.ptr = (u_char *)pp; - memcpy(pp, vp->pkt, temp); - dh_params.primeLen = ntohl(*pp++); - dh_params.prime = (u_char *)pp; - pp += dh_params.primeLen / 4; - dh_params.generatorLen = ntohl(*pp++); - dh_params.generator = (u_char *)pp; - dh_keyLen = dh_params.primeLen / 2; - if (dh_private != NULL) - free(dh_private); - dh_private = emalloc(dh_keyLen); - if (dhparam.sig == NULL) - dhparam.sig = emalloc(private_key.bits / - 8); + if (vallen == (u_int) EVP_PKEY_size(host_pkey)) { + RSA_private_decrypt(vallen, + (u_char *)ep->pkt, + (u_char *)&temp32, + host_pkey->pkey.rsa, + RSA_PKCS1_OAEP_PADDING); + cookie = ntohl(temp32); + } else { + rval = XEVNT_CKY; + break; + } /* - * Initialize public value extension field. + * Install cookie values and light the cookie + * bit. If this is not broadcast client mode, we + * are done here. */ - dhpub.tstamp = vp->tstamp; - dhpub.fstamp = vp->fstamp; - dhpub.vallen = htonl(dh_params.primeLen); - if (dhpub.ptr != NULL) - free(dhpub.ptr); - dhpub.ptr = emalloc(dh_params.primeLen); - if (dhpub.sig == NULL) - dhpub.sig = emalloc(private_key.bits / - 8); - crypto_agree(); + key_expire(peer); + peer->cookval.tstamp = ep->tstamp; + peer->cookval.fstamp = ep->fstamp; + if (peer->crypto & CRYPTO_FLAG_AGREE) + peer->pcookie ^= 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->flash &= ~TEST10; + sprintf(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 break; /* - * Verify public value and compute agreed key in - * symmetric modes. + * Install autokey values in broadcast client and + * symmetric modes. We have to do this every time the + * sever/peer cookie changes or a new keylist is + * rolled. Ordinarily, this is automatic as this message + * is piggybacked on the first NTP packet sent upon + * either of these events. Note that a broadcast client + * or symmetric peer can receive this response without a + * matching request. */ - case CRYPTO_DH: - peer->cmmd = ntohl(pkt[i]); - if (!crypto_flags) - peer->cmmd |= CRYPTO_ERROR; - /* fall through */ + case CRYPTO_AUTO | CRYPTO_RESP: - case CRYPTO_DH | CRYPTO_RESP: - if (!crypto_flags) + /* + * Discard the message if invalid or identity + * not confirmed or signature not verified with + * respect to the receive autokey values. + */ + if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + break; + + if ((rval = crypto_verify(ep, &peer->recval, + peer)) != XEVNT_OK) break; - vp = (struct value *)&pkt[i + 2]; - fstamp = ntohl(vp->fstamp); - temp = ntohl(vp->vallen); - kp = (R_RSA_PUBLIC_KEY *)peer->pubkey.ptr; - j = i + 5 + temp / 4; - if (len < VALUE_LEN) { - rval = RV_LEN; - } else if (temp != dh_params.primeLen) { - rval = RV_DH; - } else if (kp == NULL) { - rval = RV_PUB; - } else if (ntohl(pkt[j]) != kp->bits / 8) { - rval = RV_SIG; - } else if (tstamp == 0 || tstamp < - peer->pcookie.tstamp || (tstamp == - peer->pcookie.tstamp && (peer->flags & - FLAG_AUTOKEY))) { - rval = RV_TSP; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)vp, - temp + 12); - rval = EVP_VerifyFinal(&ctx, - (u_char *)&pkt[j + 1], - ntohl(pkt[j]), kp); - } /* - * Run the agreement algorithm and stash the key - * value. We use only the first u_int32 for the - * host cookie. Wasteful. If the association ID - * is zero, the other guy hasn't seen us as - * synchronized, in which case both of us should - * be using a zero cookie. + * Install autokey values and light the + * autokey bit. This is not hard. */ - if (rval != RV_OK) { - temp = 0; - } else if (fstamp > dhparam.fstamp) { - crypto_flags &= ~CRYPTO_FLAG_DH; - rval = RV_FSP; - } else { - rval = R_ComputeDHAgreedKey(dh_key, - (u_char *)&pkt[i + 5], dh_private, - dh_keyLen, &dh_params); - temp = ntohl(*(u_int32 *)dh_key); - } + if (peer->recval.ptr == NULL) + peer->recval.ptr = + emalloc(sizeof(struct autokey)); + bp = (struct autokey *)peer->recval.ptr; + peer->recval.tstamp = ep->tstamp; + peer->recval.fstamp = ep->fstamp; + ap = (struct autokey *)ep->pkt; + bp->seq = ntohl(ap->seq); + bp->key = ntohl(ap->key); + peer->pkeyid = bp->key; + peer->crypto |= CRYPTO_FLAG_AUTO; + peer->flash &= ~TEST10; + sprintf(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: verify %x agreement %08x ts %u (%u) fs %u\n", - rval, temp, tstamp, - peer->pcookie.tstamp, fstamp); + printf("crypto_recv: %s\n", statstr); #endif - if (rval != RV_OK) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x agreement %08x ts %u (%u) fs %u\n", - rval, temp, tstamp, - peer->pcookie.tstamp, - fstamp); - peer->cmmd |= CRYPTO_ERROR; - break; - } - peer->flash &= ~TEST10; - peer->flags &= ~FLAG_AUTOKEY; - peer->assoc = ntohl(pkt[i + 1]); - peer->pcookie.tstamp = tstamp; - if (temp != peer->pcookie.key) { - peer->pcookie.key = temp; - key_expire(peer); - } break; /* - * Install leapseconds table. + * 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. */ - case CRYPTO_TAI | CRYPTO_RESP: - if (!crypto_flags) + case CRYPTO_TAI: + + /* + * Discard the message if invalid or identity + * not confirmed. + */ + if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + break; + + if ((rval = crypto_verify(ep, NULL, peer)) != + XEVNT_OK) + 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 &= ~TEST10; break; - vp = (struct value *)&pkt[i + 2]; - fstamp = ntohl(vp->fstamp); - temp = ntohl(vp->vallen); - kp = (R_RSA_PUBLIC_KEY *)peer->pubkey.ptr; - j = i + 5 + temp / 4; - if (len < VALUE_LEN) { - rval = RV_LEN; - } if (kp == NULL) { - rval = RV_PUB; - } else if (ntohl(pkt[j]) != kp->bits / 8) { - rval = RV_SIG; - } else if (tstamp == 0) { - rval = RV_TSP; - } else if (tstamp < ntohl(tai_leap.fstamp) || - fstamp < ntohl(tai_leap.fstamp)) { - rval = RV_FSP; - } else if (fstamp == ntohl(tai_leap.fstamp) && - (peer->flags & FLAG_AUTOKEY)) { - peer->crypto &= ~CRYPTO_FLAG_TAI; - rval = RV_FSP; - } else { - EVP_VerifyInit(&ctx, DA_MD5); - EVP_VerifyUpdate(&ctx, (u_char *)vp, - temp + 12); - rval = EVP_VerifyFinal(&ctx, - (u_char *)&pkt[j + 1], - ntohl(pkt[j]), kp); } -#ifdef DEBUG - if (debug) - printf( - "crypto_recv: verify %x leapseconds %u ts %u fs %u\n", - rval, temp, tstamp, fstamp); -#endif + /* fall through */ + + case CRYPTO_TAI | CRYPTO_RESP: /* - * If the peer data are newer than the host - * data, replace the host data. Otherwise, - * wait for the peer to fetch the host data. + * Discard the message if invalid or identity + * not confirmed or signature not verified with + * respect to the leapsecond table values. */ - if (rval != RV_OK || temp == 0) { - if (rval != RV_TSP) - msyslog(LOG_ERR, - "crypto: %x leapseconds %u ts %u fs %u\n", - rval, temp, tstamp, fstamp); + if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + break; + + if ((rval = crypto_verify(ep, &peer->tai_leap, + peer)) != XEVNT_OK) break; + + /* + * Initialize peer variables, leapseconds + * structure and extension field in network byte + * order. Since a filestamp may have changed, + * recompute the signatures. + */ + 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(); + sys_tai = vallen / 4 + TAI_1972 - 1; } - peer->flash &= ~TEST10; crypto_flags |= CRYPTO_FLAG_TAI; - peer->crypto &= ~CRYPTO_FLAG_TAI; - sys_tai = temp / 4 + TAI_1972 - 1; + peer->crypto |= CRYPTO_FLAG_LEAP; + peer->flash &= ~TEST10; #ifdef KERNEL_PLL #if NTP_API > 3 + /* + * If the kernel cooperates, initialize the + * current TAI offset. + */ ntv.modes = MOD_TAI; ntv.constant = sys_tai; (void)ntp_adjtime(&ntv); #endif /* NTP_API */ #endif /* KERNEL_PLL */ - - /* - * Initialize leapseconds table and extension - * field in network byte order. - */ - tai_leap.tstamp = vp->tstamp; - tai_leap.fstamp = vp->fstamp; - tai_leap.vallen = vp->vallen; - if (tai_leap.ptr == NULL) - free(tai_leap.ptr); - tai_leap.ptr = emalloc(temp); - memcpy(tai_leap.ptr, vp->pkt, temp); - if (tai_leap.sig == NULL) - tai_leap.sig = - emalloc(private_key.bits / 8); - crypto_agree(); + sprintf(statstr, "leap %u ts %u fs %u", + vallen, ntohl(ep->tstamp), + ntohl(ep->fstamp)); + record_crypto_stats(&peer->srcadr, statstr); +#ifdef DEBUG + if (debug) + printf("crypto_recv: %s\n", statstr); +#endif break; -#endif /* PUBKEY */ /* - * For other requests, save the request code for later; - * for unknown responses or errors, just ignore for now. + * 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. */ - default: - if (code & (CRYPTO_RESP | CRYPTO_ERROR)) + case CRYPTO_IFF: + case CRYPTO_GQ: + case CRYPTO_MV: + case CRYPTO_SIGN: + if (len < VALUE_LEN) { + rval = XEVNT_LEN; break; - peer->cmmd = ntohl(pkt[i]); - break; + } + /* 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. + */ + default: + if (code & (CRYPTO_RESP | CRYPTO_ERROR)) { + rval = XEVNT_LEN; + } else if ((rval = crypto_verify(ep, NULL, + peer)) == XEVNT_OK) { + fp = emalloc(len); + memcpy(fp, ep, len); + temp32 = CRYPTO_RESP; + fp->opcode |= htonl(temp32); + peer->cmmd = fp; + } + } + + /* + * We log everything except length/format 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. + */ + if (rval != XEVNT_OK) { + sprintf(statstr, + "error %x opcode %x ts %u fs %u", rval, + code, tstamp, fstamp); + if (rval > XEVNT_TSP) + record_crypto_stats(&peer->srcadr, + statstr); + report_event(rval, peer); +#ifdef DEBUG + if (debug) + printf("crypto_recv: %s\n", statstr); +#endif + break; } authlen += len; } + return (rval); } @@ -992,255 +1129,248 @@ crypto_recv( * crypto_xmit - construct extension fields * * This routine is called both when an association is configured and - * when one is not. The only case where this matters now is to retrieve - * the autokey information, in which case the caller has to provide the + * when one is not. The only case where this matters is to retrieve the + * autokey information, in which case the caller has to provide the * association ID to match the association. + * + * Returns length of extension field. */ -int /* return length of extension field */ +int crypto_xmit( - u_int32 *xpkt, /* packet pointer */ - int start, /* offset to extension field */ - u_int code, /* extension field code */ - keyid_t cookie, /* session cookie */ - u_int associd /* association ID */ + struct pkt *xpkt, /* transmit packet pointer */ + struct sockaddr_storage *srcadr_sin, /* active runway */ + int start, /* offset to extension field */ + struct exten *ep, /* extension pointer */ + keyid_t cookie /* session cookie */ ) { + u_int32 *pkt; /* packet pointer */ struct peer *peer; /* peer structure pointer */ - struct autokey *ap; /* autokey pointer */ - struct cookie *cp; /* cookie pointer */ - int len; /* extension field length */ - u_int opcode; /* extension field opcode */ - int i; -#ifdef PUBKEY - R_SIGNATURE_CTX ctx; /* signature context */ - struct value *vp; /* value pointer */ - int rval; /* return value */ - u_int temp; - int j; -#endif /* PUBKEY */ + u_int opcode; /* extension field opcode */ + struct exten *fp; /* extension pointers */ + struct cert_info *cp; /* certificate info/value pointer */ + char certname[MAXHOSTNAME + 1]; /* subject name buffer */ + char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ + u_int vallen; + u_int len; + struct value vtemp; + associd_t associd; + int rval; + keyid_t tcookie; /* * Generate the requested extension field request code, length - * and association ID. Note that several extension fields are - * used with and without public-key cryptography. If public-key - * cryptography has not been configured, we do the same thing, - * but leave off the signature. - */ - i = start / 4; - opcode = code; - xpkt[i + 1] = htonl(associd); + * and association ID. If this is a response and the host is not + * synchronized, light the error bit and go home. + */ + pkt = (u_int32 *)xpkt + start / 4; + fp = (struct exten *)pkt; + opcode = ntohl(ep->opcode); + associd = (associd_t) ntohl(ep->associd); + fp->associd = htonl(associd); len = 8; - switch (opcode) { + rval = XEVNT_OK; + switch (opcode & 0xffff0000) { /* - * Send association ID, timestamp and status word. + * Send association request and response with status word and + * host name. Note, this message is not signed and the filestamp + * contains only the status word. We check at this point whether + * the identity schemes are compatible to save tears later on. */ case CRYPTO_ASSOC | CRYPTO_RESP: - cp = (struct cookie *)&xpkt[i + 2]; -#ifdef PUBKEY - cp->tstamp = host.tstamp; -#else - cp->tstamp = 0; -#endif /* PUBKEY */ - cp->key = htonl(crypto_flags); - cp->siglen = 0; - len += 12; + case CRYPTO_ASSOC: + len += crypto_send(fp, &hostval); + if (crypto_time() == 0) + fp->fstamp = 0; + else + fp->fstamp = htonl(crypto_flags); break; /* - * Find peer and send autokey data and signature in broadcast - * server and symmetric modes. If no association is found, - * either the server has restarted with new associations or some - * perp has replayed an old message. + * Send certificate request. Use the values from the extension + * field. */ - case CRYPTO_AUTO | CRYPTO_RESP: - peer = findpeerbyassoc(associd); - if (peer == NULL) { + case CRYPTO_CERT: + memset(&vtemp, 0, sizeof(vtemp)); + vtemp.tstamp = ep->tstamp; + vtemp.fstamp = ep->fstamp; + vtemp.vallen = ep->vallen; + vtemp.ptr = (unsigned char *)ep->pkt; + len += crypto_send(fp, &vtemp); + break; + + /* + * Send certificate response or sign request. Use the values + * from the certificate. If the request contains no subject + * name, assume the name of this host. This is for backwards + * compatibility. Light the error bit if no certificate with + * the given subject name is found. Of course, private + * certificates are never sent. + */ + case CRYPTO_SIGN: + case CRYPTO_CERT | CRYPTO_RESP: + vallen = ntohl(ep->vallen); + if (vallen == 8) { + strcpy(certname, sys_hostname); + } else if (vallen == 0 || vallen > MAXHOSTNAME) { opcode |= CRYPTO_ERROR; break; + + } else { + memcpy(certname, ep->pkt, vallen); + certname[vallen] = '\0'; } - peer->flags &= ~FLAG_ASSOC; - ap = (struct autokey *)&xpkt[i + 2]; - ap->tstamp = peer->sndauto.tstamp; - ap->seq = peer->sndauto.seq; - ap->key = peer->sndauto.key; - ap->siglen = peer->sndauto.siglen; - len += 16; -#ifdef PUBKEY - if (!crypto_flags) - break; - temp = ntohl(ap->siglen); - if (temp != 0) - memcpy(ap->pkt, peer->sndauto.sig, temp); - len += temp; -#endif /* PUBKEY */ + for (cp = cinfo; cp != NULL; cp = cp->link) { + if (cp->flags & CERT_PRIV) + continue; + if (strcmp(certname, cp->subject) == 0) { + len += crypto_send(fp, &cp->cert); + break; + } + } + if (cp == NULL) + opcode |= CRYPTO_ERROR; break; /* - * Send peer cookie and signature in server mode. + * Send challenge in Schnorr (IFF) identity scheme. */ - case CRYPTO_PRIV: - case CRYPTO_PRIV | CRYPTO_RESP: - cp = (struct cookie *)&xpkt[i + 2]; - cp->key = htonl(cookie); - cp->siglen = 0; - len += 12; -#ifdef PUBKEY - cp->tstamp = host.tstamp; - if (!crypto_flags) - break; - EVP_SignInit(&ctx, DA_MD5); - EVP_SignUpdate(&ctx, (u_char *)cp, 8); - rval = EVP_SignFinal(&ctx, (u_char *)cp->pkt, &temp, - &private_key); - if (rval != RV_OK) { - msyslog(LOG_ERR, - "crypto: cookie signature fails %x", rval); + case CRYPTO_IFF: + if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { + opcode |= CRYPTO_ERROR; break; } - cp->siglen = htonl(temp); - len += temp; -#endif /* PUBKEY */ + if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); break; -#ifdef PUBKEY /* - * The following commands and responses work only when public- - * key cryptography has been configured. If configured, but - * disabled due to no crypto command in the configuration file, - * they are ignored and an error response is returned. + * Send response in Schnorr (IFF) identity scheme. */ + case CRYPTO_IFF | CRYPTO_RESP: + if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); + break; + /* - * Send certificate, timestamp and signature. + * Send challenge in Guillou-Quisquater (GQ) identity scheme. */ - case CRYPTO_CERT | CRYPTO_RESP: - if (!crypto_flags) { + case CRYPTO_GQ: + if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { opcode |= CRYPTO_ERROR; break; } - vp = (struct value *)&xpkt[i + 2]; - vp->tstamp = certif.tstamp; - vp->fstamp = certif.fstamp; - vp->vallen = 0; - len += 12; - temp = ntohl(certif.vallen); - if (temp == 0) - break; - vp->vallen = htonl(temp); - memcpy(vp->pkt, certif.ptr, temp); - len += temp; - j = i + 5 + temp / 4; - temp = public_key.bits / 8; - xpkt[j++] = htonl(temp); - memcpy(&xpkt[j], certif.sig, temp); - len += temp + 4; + if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); + break; + + /* + * Send response in Guillou-Quisquater (GQ) identity scheme. + */ + case CRYPTO_GQ | CRYPTO_RESP: + if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); break; /* - * Send agreement parameters, timestamp and signature. + * Send challenge in MV identity scheme. */ - case CRYPTO_DHPAR | CRYPTO_RESP: - if (!crypto_flags) { + case CRYPTO_MV: + if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { opcode |= CRYPTO_ERROR; break; } - vp = (struct value *)&xpkt[i + 2]; - vp->tstamp = dhparam.tstamp; - vp->fstamp = dhparam.fstamp; - vp->vallen = 0; - len += 12; - temp = ntohl(dhparam.vallen); - if (temp == 0) - break; - vp->vallen = htonl(temp); - memcpy(vp->pkt, dhparam.ptr, temp); - len += temp; - j = i + 5 + temp / 4; - temp = public_key.bits / 8; - xpkt[j++] = htonl(temp); - memcpy(&xpkt[j], dhparam.sig, temp); - len += temp + 4; + if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); + break; + + /* + * Send response in MV identity scheme. + */ + case CRYPTO_MV | CRYPTO_RESP: + if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); break; /* - * Send public value, timestamp and signature. + * Send certificate sign response. The integrity of the request + * certificate has already been verified on the receive side. + * Sign the response using the local server key. Use the + * filestamp from the request and use the timestamp as the + * current time. Light the error bit if the certificate is + * invalid or contains an unverified signature. */ - case CRYPTO_DH: - case CRYPTO_DH | CRYPTO_RESP: - if (!crypto_flags) { + case CRYPTO_SIGN | CRYPTO_RESP: + if ((rval = cert_sign(ep, &vtemp)) == XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); + break; + + /* + * Send public key and signature. Use the values from the public + * key. + */ + case CRYPTO_COOK: + len += crypto_send(fp, &pubkey); + break; + + /* + * Encrypt and send cookie and signature. Light the error bit if + * anything goes wrong. + */ + case CRYPTO_COOK | CRYPTO_RESP: + if ((opcode & 0xffff) < VALUE_LEN) { opcode |= CRYPTO_ERROR; break; } - vp = (struct value *)&xpkt[i + 2]; - vp->tstamp = dhpub.tstamp; - vp->fstamp = dhpub.fstamp; - vp->vallen = 0; - len += 12; - temp = ntohl(dhpub.vallen); - if (temp == 0) - break; - vp->vallen = htonl(temp); - memcpy(vp->pkt, dhpub.ptr, temp); - len += temp; - j = i + 5 + temp / 4; - temp = public_key.bits / 8; - xpkt[j++] = htonl(temp); - memcpy(&xpkt[j], dhpub.sig, temp); - len += temp + 4; + if (PKT_MODE(xpkt->li_vn_mode) == MODE_SERVER) { + tcookie = cookie; + } else { + if ((peer = findpeerbyassoc(associd)) == NULL) { + opcode |= CRYPTO_ERROR; + break; + } + tcookie = peer->pcookie; + } + if ((rval = crypto_encrypt(ep, &vtemp, &tcookie)) == + XEVNT_OK) + len += crypto_send(fp, &vtemp); + value_free(&vtemp); break; /* - * Send public key, host name, timestamp and signature. + * Find peer and send autokey data and signature in broadcast + * server and symmetric modes. Use the values in the autokey + * structure. If no association is found, either the server has + * restarted with new associations or some perp has replayed an + * old message, in which case light the error bit. */ - case CRYPTO_NAME | CRYPTO_RESP: - if (!crypto_flags) { + case CRYPTO_AUTO | CRYPTO_RESP: + if ((peer = findpeerbyassoc(associd)) == NULL) { opcode |= CRYPTO_ERROR; break; } - vp = (struct value *)&xpkt[i + 2]; - vp->tstamp = host.tstamp; - vp->fstamp = host.fstamp; - vp->vallen = 0; - len += 12; - temp = ntohl(host.vallen); - if (temp == 0) - break; - vp->vallen = htonl(temp); - memcpy(vp->pkt, host.ptr, temp); - len += temp; - j = i + 5 + temp / 4; - temp = public_key.bits / 8; - xpkt[j++] = htonl(temp); - memcpy(&xpkt[j], host.sig, temp); - len += temp + 4; + peer->flags &= ~FLAG_ASSOC; + len += crypto_send(fp, &peer->sndval); break; /* - * Send leapseconds table, timestamp and signature. + * Send leapseconds table and signature. Use the values from the + * tai structure. If no table has been loaded, just send a + * request. */ + case CRYPTO_TAI: case CRYPTO_TAI | CRYPTO_RESP: - if (!crypto_flags) { - opcode |= CRYPTO_ERROR; - break; - } - vp = (struct value *)&xpkt[i + 2]; - vp->tstamp = tai_leap.tstamp; - vp->fstamp = tai_leap.fstamp; - vp->vallen = 0; - len += 12; - temp = ntohl(tai_leap.vallen); - if (temp == 0) - break; - vp->vallen = htonl(temp); - memcpy(vp->pkt, tai_leap.ptr, temp); - len += temp; - j = i + 5 + temp / 4; - temp = public_key.bits / 8; - xpkt[j++] = htonl(temp); - memcpy(&xpkt[j], tai_leap.sig, temp); - len += temp + 4; + if (crypto_flags & CRYPTO_FLAG_TAI) + len += crypto_send(fp, &tai_leap); break; -#endif /* PUBKEY */ /* * Default - Fall through for requests; for unknown responses, @@ -1249,626 +1379,2226 @@ crypto_xmit( default: if (opcode & CRYPTO_RESP) opcode |= CRYPTO_ERROR; - break; } /* - * Round up the field length to a multiple of 8 octets and save - * the request code and length. + * We ignore length/format errors and duplicates. Other errors + * are reported to the log and deny further service. To really + * persistent rascals we toss back a kiss-of-death grenade. */ - len = ((len + 7) / 8) * 8; - if (len >= 4) { - xpkt[i] = htonl((u_int32)((opcode << 16) | len)); + if (rval > XEVNT_TSP) { + opcode |= CRYPTO_ERROR; + sprintf(statstr, "error %x opcode %x", rval, opcode); + record_crypto_stats(srcadr_sin, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_xmit: ext offset %d len %d code %x assocID %d\n", - start, len, code, associd); + printf("crypto_xmit: %s\n", statstr); #endif } + + /* + * 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: ext offset %d len %u code %x assocID %d\n", + start, len, opcode>> 16, associd); +#endif return (len); } -#ifdef PUBKEY + /* - * crypto_setup - load private key, public key, optional agreement - * parameters and optional leapseconds table, then initialize extension - * fields for later signatures. + * crypto_verify - parse and verify the extension field and value + * + * Returns + * XEVNT_OK success + * XEVNT_LEN bad field format or length + * XEVNT_TSP bad timestamp + * XEVNT_FSP bad filestamp + * XEVNT_PUB bad or missing public key + * XEVNT_SGL bad signature length + * XEVNT_SIG signature not verified */ -void -crypto_setup(void) +static int +crypto_verify( + struct exten *ep, /* extension pointer */ + struct value *vp, /* value pointer */ + struct peer *peer /* peer structure pointer */ + ) { - char filename[MAXFILENAME]; - u_int fstamp; /* filestamp */ - u_int len, temp; - u_int32 *pp; + EVP_PKEY *pkey; /* server public key */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; /* timestamp */ + tstamp_t fstamp; /* filestamp */ + u_int vallen; /* value length */ + u_int siglen; /* signature length */ + u_int opcode, len; + int rval; + int i; /* - * Initialize structures. + * We require valid opcode and field length, timestamp, + * filestamp, public key, digest, signature length and + * signature, where relevant. Note that preliminary length + * checks are done in the main loop. */ - memset(&private_key, 0, sizeof(private_key)); - memset(&public_key, 0, sizeof(public_key)); - memset(&certif, 0, sizeof(certif)); - memset(&dh_params, 0, sizeof(dh_params)); - memset(&host, 0, sizeof(host)); - memset(&dhparam, 0, sizeof(dhparam)); - memset(&dhpub, 0, sizeof(dhpub)); - memset(&tai_leap, 0, sizeof(tai_leap)); - if (!crypto_flags) - return; + 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. + */ + if (opcode & CRYPTO_ERROR) + return (XEVNT_LEN); + if (opcode & CRYPTO_RESP) { + if (len < VALUE_LEN) + return (XEVNT_LEN); + } else { + if (len < VALUE_LEN) + return (XEVNT_OK); + } + /* + * 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. If a request and a previous request of + * the same type is pending, discard the previous request. If a + * request but no signature, there is no need for further + * checking. + */ + vallen = ntohl(ep->vallen); + if (len < ((VALUE_LEN + vallen + 3) / 4) * 4) + return (XEVNT_LEN); + + i = (vallen + 3) / 4; + siglen = ntohl(ep->pkt[i++]); + if (len < VALUE_LEN + vallen + siglen) + return (XEVNT_LEN); + + if (!(opcode & CRYPTO_RESP)) { + if (peer->cmmd != NULL) { + if ((opcode | CRYPTO_RESP) == + (ntohl(peer->cmmd->opcode) & 0xffff0000)) { + free(peer->cmmd); + peer->cmmd = NULL; + } else { + return (XEVNT_LEN); + } + } + if (siglen == 0) + return (XEVNT_OK); + } /* - * Load required private key from file, default "ntpkey". + * We have a signature. Check for valid timestamp and filestamp. + * The timestamp must not precede the filestamp. The timestamp + * and filestamp must not precede the corresponding values in + * the value structure. 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. */ - if (private_key_file == NULL) - private_key_file = "ntpkey"; - host.fstamp = htonl(crypto_rsa(private_key_file, - (u_char *)&private_key, sizeof(R_RSA_PRIVATE_KEY))); + rval = XEVNT_OK; + if (crypto_flags & peer->crypto & CRYPTO_FLAG_PRIV) + pkey = sign_pkey; + else + pkey = peer->pkey; + tstamp = ntohl(ep->tstamp); + fstamp = ntohl(ep->fstamp); + if (tstamp == 0 || tstamp < fstamp) { + rval = XEVNT_TSP; + } else if (vp != NULL && (tstamp < ntohl(vp->tstamp) || + (tstamp == ntohl(vp->tstamp) && (peer->crypto & + CRYPTO_FLAG_AUTO)))) { + rval = XEVNT_TSP; + } else if (vp != NULL && (tstamp < ntohl(vp->fstamp) || fstamp < + ntohl(vp->fstamp))) { + rval = XEVNT_FSP; /* - * Load required public key from file, default - * "ntpkey_host", where "host" is the canonical name of this - * machine. + * If a public key and digest is present, and if valid key + * length, check for valid signature. Note that the first valid + * signature lights the proventic bit. */ - if (public_key_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_%s", - sys_hostname); - public_key_file = emalloc(strlen(filename) + 1); - strcpy(public_key_file, filename); + } else if (pkey == NULL || peer->digest == NULL) { + /* fall through */ + } else if (siglen != (u_int) EVP_PKEY_size(pkey)) { + rval = XEVNT_SGL; + } else { + EVP_VerifyInit(&ctx, peer->digest); + EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + + 12); + if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen, + pkey)) { + if (peer->crypto & CRYPTO_FLAG_VRFY) + peer->crypto |= CRYPTO_FLAG_PROV; + } else { + rval = XEVNT_SIG; + } } - fstamp = htonl(crypto_rsa(public_key_file, - (u_char *)&public_key, sizeof(R_RSA_PUBLIC_KEY))); - if (fstamp != host.fstamp || strstr(public_key_file, - sys_hostname) == NULL) { - msyslog(LOG_ERR, - "crypto: public/private key files mismatch"); - exit (-1); +#ifdef DEBUG + if (debug > 1) + printf( + "crypto_recv: verify %x vallen %u siglen %u ts %u fs %u\n", + rval, vallen, siglen, tstamp, fstamp); +#endif + return (rval); +} + + +/* + * crypto_encrypt - construct encrypted cookie and signature from + * extension field and cookie + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_CKY bad or missing cookie + */ +static int +crypto_encrypt( + struct exten *ep, /* extension pointer */ + struct value *vp, /* value pointer */ + keyid_t *cookie /* server cookie */ + ) +{ + EVP_PKEY *pkey; /* public key */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; /* NTP timestamp */ + u_int32 temp32; + u_int len; + u_char *ptr; + + /* + * Extract the public key from the request. + */ + len = ntohl(ep->vallen); + ptr = (u_char *)ep->pkt; + pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len); + if (pkey == NULL) { + msyslog(LOG_ERR, "crypto_encrypt %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); } - crypto_flags |= CRYPTO_FLAG_RSA; /* - * Assemble public key and host name in network byte order. - * These data will later be signed and sent in response to - * a client request. Note that the modulus must be a u_int32 in - * network byte order independent of the host order or u_int - * size. + * Encrypt the cookie, encode in ASN.1 and sign. */ - strcpy(filename, sys_hostname); - for (len = strlen(filename) + 1; len % 4 != 0; len++) - filename[len - 1] = 0; - temp = sizeof(R_RSA_PUBLIC_KEY) - sizeof(u_int) + 4; - host.vallen = htonl(temp + len); - pp = emalloc(temp + len); - host.ptr = (u_char *)pp; - *pp++ = htonl(public_key.bits); - memcpy(pp--, public_key.modulus, temp - 4); - pp += temp / 4; - memcpy(pp, filename, len); - host.sig = emalloc(private_key.bits / 8); + tstamp = crypto_time(); + memset(vp, 0, sizeof(struct value)); + vp->tstamp = htonl(tstamp); + vp->fstamp = hostval.tstamp; + len = EVP_PKEY_size(pkey); + vp->vallen = htonl(len); + vp->ptr = emalloc(len); + 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", + ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(pkey); + return (XEVNT_CKY); + } + EVP_PKEY_free(pkey); + vp->siglen = 0; + if (tstamp == 0) + return (XEVNT_OK); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_ident - construct extension field for identity scheme + * + * This routine determines which identity scheme is in use and + * constructs an extension field for that scheme. + */ +u_int +crypto_ident( + struct peer *peer /* peer structure pointer */ + ) +{ + char filename[MAXFILENAME + 1]; /* - * Load optional certificate from file, default "ntpkey_certif". - * If the file is missing or defective, the values can later be - * retrieved from a server. + * 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. */ - if (certif_file == NULL) - snprintf(filename, MAXFILENAME, "ntpkey_certif_%s", + if (peer->crypto & CRYPTO_FLAG_VRFY) + return (0); + + 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); + } + if (peer->crypto & CRYPTO_FLAG_IFF) { + snprintf(filename, MAXFILENAME, "ntpkey_iff_%s", + peer->issuer); + peer->ident_pkey = crypto_key(filename, &peer->fstamp); + if (peer->ident_pkey != NULL) + return (CRYPTO_IFF); + + snprintf(filename, MAXFILENAME, "ntpkey_iff_%s", sys_hostname); - certif_file = emalloc(strlen(filename) + 1); - strcpy(certif_file, filename); - crypto_cert(certif_file); + peer->ident_pkey = crypto_key(filename, &peer->fstamp); + if (peer->ident_pkey != NULL) + return (CRYPTO_IFF); + } + 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); + } /* - * Load optional agreement parameters from file, default - * "ntpkey_dh". If the file is missing or defective, the values - * can later be retrieved from a server. + * No compatible identity scheme is available. Use the default + * TC scheme. */ - if (dh_params_file == NULL) - dh_params_file = "ntpkey_dh"; - crypto_dh(dh_params_file); + msyslog(LOG_INFO, + "crypto_ident: no compatible identity scheme found"); + return (0); +} + + +/* + * crypto_args - construct extension field from arguments + * + * This routine creates an extension field with current timestamps and + * specified opcode, association ID and optional string. Note that the + * extension field is created here, but freed after the crypto_xmit() + * call in the protocol module. + * + * Returns extension field pointer (no errors). + */ +struct exten * +crypto_args( + struct peer *peer, /* peer structure pointer */ + u_int opcode, /* operation code */ + char *str /* argument string */ + ) +{ + tstamp_t tstamp; /* NTP timestamp */ + struct exten *ep; /* extension field pointer */ + u_int len; /* extension field length */ + + tstamp = crypto_time(); + len = sizeof(struct exten); + if (str != NULL) + len += strlen(str); + ep = emalloc(len); + memset(ep, 0, len); + ep->opcode = htonl(opcode + len); /* - * Load optional leapseconds from file, default "ntpkey_leap". - * If the file is missing or defective, the values can later be - * retrieved from a server. + * If a response, send our ID; if a request, send the + * responder's ID. */ - if (tai_leap_file == NULL) - tai_leap_file = "ntpkey_leap"; - crypto_tai(tai_leap_file); + if (opcode & CRYPTO_RESP) + ep->associd = htonl(peer->associd); + else + ep->associd = htonl(peer->assoc); + ep->tstamp = htonl(tstamp); + ep->fstamp = hostval.tstamp; + ep->vallen = 0; + if (str != NULL) { + ep->vallen = htonl(strlen(str)); + memcpy((char *)ep->pkt, str, strlen(str)); + } else { + ep->pkt[0] = peer->associd; + } + return (ep); } /* - * crypto_agree - compute new public value and sign extension fields. + * 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. */ -void -crypto_agree(void) +u_int +crypto_send( + struct exten *ep, /* extension field pointer */ + struct value *vp /* value pointer */ + ) { - R_RANDOM_STRUCT randomstr; /* wiggle bits */ - R_SIGNATURE_CTX ctx; /* signature context */ - l_fp lstamp; /* NTP time */ - tstamp_t tstamp; /* seconds timestamp */ - u_int len, temp; - int rval, i; + u_int len, temp32; + int i; /* - * Sign host name and timestamps, but only if the clock is - * synchronized. + * Copy data. If the data field is empty or zero length, encode + * an empty value with length zero. */ - if (sys_leap == LEAP_NOTINSYNC) - return; - get_systime(&lstamp); - tstamp = lstamp.l_ui; - host.tstamp = htonl(tstamp); - if (!crypto_flags) + 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 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; + return (len); +} + + +/* + * crypto_update - compute new public value and sign extension fields + * + * This routine runs periodically, like once a day, and when something + * changes. It updates the timestamps on three value structures and one + * value structure list, then signs all the structures: + * + * hostval host name (not signed) + * pubkey public key + * cinfo certificate info/value list + * tai_leap leapseconds file + * + * 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. + * + * Returns void (no errors) + */ +void +crypto_update(void) +{ + EVP_MD_CTX ctx; /* message digest context */ + struct cert_info *cp, *cpn, **zp; /* certificate info/value */ + char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ + tstamp_t tstamp; /* NTP timestamp */ + u_int len; + + if ((tstamp = crypto_time()) == 0) return; - EVP_SignInit(&ctx, DA_MD5); - EVP_SignUpdate(&ctx, (u_char *)&host, 12); - EVP_SignUpdate(&ctx, host.ptr, ntohl(host.vallen)); - rval = EVP_SignFinal(&ctx, host.sig, &len, &private_key); - if (rval != RV_OK || len != private_key.bits / 8) { - msyslog(LOG_ERR, "crypto: host signature fails %x", - rval); - exit (-1); - } - host.siglen = ntohl(len); + hostval.tstamp = htonl(tstamp); /* - * Sign certificate and timestamps. + * Sign public key and timestamps. The filestamp is derived from + * the host key file extension from wherever the file was + * generated. */ - if (certif.vallen != 0) { - certif.tstamp = htonl(tstamp); - EVP_SignInit(&ctx, DA_MD5); - EVP_SignUpdate(&ctx, (u_char *)&certif, 12); - EVP_SignUpdate(&ctx, certif.ptr, - ntohl(certif.vallen)); - rval = EVP_SignFinal(&ctx, certif.sig, &len, - &private_key); - if (rval != RV_OK || len != private_key.bits / 8) { - msyslog(LOG_ERR, - "crypto: certificate signature fails %x", - rval); - exit (-1); - } - certif.siglen = ntohl(len); + if (pubkey.vallen != 0) { + pubkey.tstamp = hostval.tstamp; + pubkey.siglen = 0; + if (pubkey.sig == NULL) + pubkey.sig = emalloc(sign_siglen); + 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)) + pubkey.siglen = htonl(len); } /* - * Sign agreement parameters and timestamps. + * Sign certificates and timestamps. The filestamp is derived + * from the certificate file extension from wherever the file + * was generated. At the same time expired certificates are + * expunged. */ - if (dhparam.vallen != 0) { - dhparam.tstamp = htonl(tstamp); - EVP_SignInit(&ctx, DA_MD5); - EVP_SignUpdate(&ctx, (u_char *)&dhparam, 12); - EVP_SignUpdate(&ctx, dhparam.ptr, - ntohl(dhparam.vallen)); - rval = EVP_SignFinal(&ctx, dhparam.sig, &len, - &private_key); - if (rval != RV_OK || len != private_key.bits / 8) { - msyslog(LOG_ERR, - "crypto: parameters signature fails %x", - rval); - exit (-11); - } - dhparam.siglen = ntohl(len); - - /* - * Compute public value. - */ - R_RandomInit(&randomstr); - R_GetRandomBytesNeeded(&len, &randomstr); - for (i = 0; i < len; i++) { - temp = RANDOM; - R_RandomUpdate(&randomstr, (u_char *)&temp, 1); - } - rval = R_SetupDHAgreement(dhpub.ptr, dh_private, - dh_keyLen, &dh_params, &randomstr); - if (rval != RV_OK) { - msyslog(LOG_ERR, - "crypto: invalid public value"); - exit (-1); - } - - /* - * Sign public value and timestamps. - */ - dhpub.tstamp = htonl(tstamp); - EVP_SignInit(&ctx, DA_MD5); - EVP_SignUpdate(&ctx, (u_char *)&dhpub, 12); - EVP_SignUpdate(&ctx, dhpub.ptr, ntohl(dhpub.vallen)); - rval = EVP_SignFinal(&ctx, dhpub.sig, &len, - &private_key); - if (rval != RV_OK || len != private_key.bits / 8) { - msyslog(LOG_ERR, - "crypto: public value signature fails %x", - rval); - exit (-1); + zp = &cinfo; + for (cp = cinfo; cp != NULL; cp = cpn) { + cpn = cp->link; + if (tstamp > cp->last) { + *zp = cpn; + cert_free(cp); + } else { + cp->cert.tstamp = hostval.tstamp; + cp->cert.siglen = 0; + if (cp->cert.sig == NULL) + cp->cert.sig = emalloc(sign_siglen); + EVP_SignInit(&ctx, sign_digest); + 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)) + cp->cert.siglen = htonl(len); + zp = &cp->link; } - dhpub.siglen = ntohl(len); } /* - * Sign leapseconds table and timestamps. + * Sign leapseconds table and timestamps. The filestamp is + * derived from the leapsecond file extension from wherever the + * file was generated. */ if (tai_leap.vallen != 0) { - tai_leap.tstamp = htonl(tstamp); - EVP_SignInit(&ctx, DA_MD5); + 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)); - rval = EVP_SignFinal(&ctx, tai_leap.sig, &len, - &private_key); - if (rval != RV_OK || len != private_key.bits / 8) { - msyslog(LOG_ERR, - "crypto: leapseconds signature fails %x", - rval); - exit (-1); - } - tai_leap.siglen = ntohl(len); + if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey)) + tai_leap.siglen = htonl(len); } + sprintf(statstr, "update ts %u", ntohl(hostval.tstamp)); + record_crypto_stats(NULL, statstr); #ifdef DEBUG if (debug) - printf( - "cypto_agree: ts %u host %u par %u pub %u leap %u\n", - tstamp, ntohl(host.fstamp), ntohl(dhparam.fstamp), - ntohl(dhpub.fstamp), ntohl(tai_leap.fstamp)); + printf("crypto_update: %s\n", statstr); #endif } /* - * crypto_rsa - read RSA key, decode and check for errors. + * value_free - free value structure components. + * + * Returns void (no errors) + */ +void +value_free( + struct value *vp /* value structure */ + ) +{ + if (vp->ptr != NULL) + free(vp->ptr); + if (vp->sig != NULL) + free(vp->sig); + memset(vp, 0, sizeof(struct value)); +} + + +/* + * crypto_time - returns current NTP time in seconds. + */ +tstamp_t +crypto_time() +{ + l_fp tstamp; /* NTP time */ L_CLR(&tstamp); + + L_CLR(&tstamp); + if (sys_leap != LEAP_NOTINSYNC) + get_systime(&tstamp); + return (tstamp.l_ui); +} + + +/* + * asn2ntp - convert ASN1_TIME time structure to NTP time in seconds. */ -static u_int -crypto_rsa( - char *cp, /* file name */ - u_char *key, /* key pointer */ - u_int keylen /* key length */ +u_long +asn2ntp ( + ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ ) { - FILE *str; /* file handle */ - u_char buf[MAX_LINLEN]; /* file line buffer */ - u_char encoded_key[MAX_ENCLEN]; /* encoded key buffer */ - char filename[MAXFILENAME]; /* name of parameter file */ - char linkname[MAXFILENAME]; /* file link (for filestamp) */ - u_int fstamp; /* filestamp */ - u_int bits, len; - char *rptr; - int rval; + char *v; /* pointer to ASN1_TIME string */ + struct tm tm; /* used to convert to NTP time */ /* - * Open the file and discard comment lines. If the first - * character of the file name is not '/', prepend the keys - * directory string. + * Extract time string YYMMDDHHMMSSZ from ASN1 time structure. + * 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 (*cp == '/') - strcpy(filename, cp); - else - snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); - str = fopen(filename, "r"); - if (str == NULL) { - msyslog(LOG_ERR, "crypto: RSA file %s not found", - filename); - exit (-1); + 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); +} + + +/* + * bigdig() - compute a BIGNUM MD5 hash of a BIGNUM number. + */ +static int +bighash( + BIGNUM *bn, /* BIGNUM * from */ + BIGNUM *bk /* BIGNUM * to */ + ) +{ + EVP_MD_CTX ctx; /* message digest context */ + u_char dgst[EVP_MAX_MD_SIZE]; /* message digest */ + u_char *ptr; /* a BIGNUM as binary string */ + u_int len; + + len = BN_num_bytes(bn); + ptr = emalloc(len); + BN_bn2bin(bn, ptr); + EVP_DigestInit(&ctx, EVP_md5()); + EVP_DigestUpdate(&ctx, ptr, len); + EVP_DigestFinal(&ctx, dgst, &len); + BN_bin2bn(dgst, len, bk); + return (1); +} + + +/* + *********************************************************************** + * * + * The following routines implement the Schnorr (IFF) identity scheme * + * * + *********************************************************************** + * + * 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. + * + * 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. + * + * 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 + * matches hash(x), 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. + * + * crypto_alice - construct Alice's challenge in IFF scheme + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_ID bad or missing identity parameters + */ +static int +crypto_alice( + struct peer *peer, /* peer pointer */ + struct value *vp /* value pointer */ + ) +{ + DSA *dsa; /* IFF parameters */ + BN_CTX *bctx; /* BIGNUM context */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; + u_int len; + + /* + * The identity parameters must have correct format and content. + */ + if (peer->ident_pkey == NULL) + return (XEVNT_ID); + if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) { + msyslog(LOG_INFO, "crypto_alice: defective key"); + return (XEVNT_PUB); } /* - * Ignore initial comments and empty lines. + * 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. */ - while ((rptr = fgets(buf, MAX_LINLEN - 1, str)) != NULL) { - len = strlen(buf); - if (len < 1) - continue; - if (*buf == '#' || *buf == '\r' || *buf == '\0') - continue; - break; + 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 */ + 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)); + vp->tstamp = htonl(tstamp); + vp->fstamp = htonl(peer->fstamp); + vp->vallen = htonl(len); + vp->ptr = emalloc(len); + BN_bn2bin(peer->iffval, vp->ptr); + vp->siglen = 0; + if (tstamp == 0) + return (XEVNT_OK); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_bob - construct Bob's response to Alice's challenge + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + */ +static int +crypto_bob( + struct exten *ep, /* extension pointer */ + struct value *vp /* value pointer */ + ) +{ + DSA *dsa; /* IFF parameters */ + DSA_SIG *sdsa; /* DSA signature context fake */ + BN_CTX *bctx; /* BIGNUM context */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; /* NTP timestamp */ + BIGNUM *bn, *bk, *r; + u_char *ptr; + u_int len; + + /* + * If the IFF parameters are not valid, something awful + * happened or we are being tormented. + */ + if (!(crypto_flags & CRYPTO_FLAG_IFF)) { + msyslog(LOG_INFO, "crypto_bob: scheme unavailable"); + return (XEVNT_PUB); + } + dsa = iffpar_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_bob %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); + } + + /* + * Bob rolls random k (0 < k < q), computes y = k + b r mod q + * and x = g^k mod p, then sends (y, hash(x)) to Alice. + */ + bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new(); + sdsa = DSA_SIG_new(); + BN_rand(bk, len * 8, -1, 1); /* k */ + BN_mod_mul(bn, dsa->priv_key, r, dsa->q, bctx); /* b r mod q */ + BN_add(bn, bn, bk); + BN_mod(bn, bn, dsa->q, bctx); /* k + b r mod q */ + sdsa->r = BN_dup(bn); + BN_mod_exp(bk, dsa->g, bk, dsa->p, bctx); /* g^k mod p */ + bighash(bk, bk); + sdsa->s = BN_dup(bk); + BN_CTX_free(bctx); + BN_free(r); BN_free(bn); BN_free(bk); + + /* + * Encode the values in ASN.1 and sign. + */ + tstamp = crypto_time(); + memset(vp, 0, sizeof(struct value)); + vp->tstamp = htonl(tstamp); + vp->fstamp = htonl(if_fstamp); + len = i2d_DSA_SIG(sdsa, NULL); + if (len <= 0) { + msyslog(LOG_ERR, "crypto_bob %s\n", + ERR_error_string(ERR_get_error(), NULL)); + DSA_SIG_free(sdsa); + return (XEVNT_PUB); + } + 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); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_iff - verify Bob's response to Alice's challenge + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_FSP bad filestamp + * XEVNT_ID bad or missing identity parameters + */ +int +crypto_iff( + struct exten *ep, /* extension pointer */ + struct peer *peer /* peer structure pointer */ + ) +{ + DSA *dsa; /* IFF parameters */ + BN_CTX *bctx; /* BIGNUM context */ + DSA_SIG *sdsa; /* DSA parameters */ + BIGNUM *bn, *bk; + u_int len; + const u_char *ptr; + int temp; + + /* + * If the IFF parameters are not valid or no challenge was sent, + * something awful happened or we are being tormented. + */ + if (peer->ident_pkey == NULL) { + msyslog(LOG_INFO, "crypto_iff: scheme unavailable"); + return (XEVNT_PUB); + } + if (ntohl(ep->fstamp) != peer->fstamp) { + msyslog(LOG_INFO, "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"); + return (XEVNT_PUB); + } + if (peer->iffval == NULL) { + msyslog(LOG_INFO, "crypto_iff: missing challenge"); + return (XEVNT_PUB); + } + + /* + * Extract the k + b r and g^k values from the response. + */ + bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new(); + len = ntohl(ep->vallen); + ptr = (const u_char *)ep->pkt; + if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) { + msyslog(LOG_ERR, "crypto_iff %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); + } + + /* + * Compute g^(k + b r) g^(q - b)r mod p. + */ + BN_mod_exp(bn, dsa->pub_key, peer->iffval, dsa->p, bctx); + BN_mod_exp(bk, dsa->g, sdsa->r, dsa->p, bctx); + BN_mod_mul(bn, bn, bk, dsa->p, bctx); + + /* + * Verify the hash of the result matches hash(x). + */ + bighash(bn, bn); + temp = BN_cmp(bn, sdsa->s); + BN_free(bn); BN_free(bk); BN_CTX_free(bctx); + BN_free(peer->iffval); + peer->iffval = NULL; + DSA_SIG_free(sdsa); + if (temp == 0) + return (XEVNT_OK); + else + return (XEVNT_ID); +} + + +/* + *********************************************************************** + * * + * The following routines implement the Guillou-Quisquater (GQ) * + * identity scheme * + * * + *********************************************************************** + * + * 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 + * 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 + * scheme. 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 same modulus n + * and some random b as the group key. These values are computed and + * distributed in advance via secret means, although only the group key + * b is truly secret. Each has a private random private key u and public + * key (u^-1)^b, although not necessarily the same ones. Bob and Alice + * can regenerate the key pair from time to time without affecting + * operations. The public key is conveyed on the certificate in an + * extension field; the private key is never revealed. + * + * Alice rolls new random challenge r and sends to Bob in the GQ + * request message. Bob rolls new random k, then computes y = k u^r mod + * n and x = k^b mod n 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 y^b v^r mod n. After a bit + * of algebra, this simplifies to k^b. If the hash of this result + * matches hash(x), 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. + * + * crypto_alice2 - construct Alice's challenge in GQ scheme + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_ID bad or missing identity parameters + */ +static int +crypto_alice2( + struct peer *peer, /* peer pointer */ + struct value *vp /* value pointer */ + ) +{ + RSA *rsa; /* GQ parameters */ + BN_CTX *bctx; /* BIGNUM context */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; + u_int len; + + /* + * The identity parameters must have correct format and content. + */ + if (peer->ident_pkey == NULL) + return (XEVNT_ID); + if ((rsa = peer->ident_pkey->pkey.rsa) == NULL) { + msyslog(LOG_INFO, "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. + */ + bctx = BN_CTX_new(); + len = BN_num_bytes(rsa->n); + if (peer->iffval != NULL) + BN_free(peer->iffval); + peer->iffval = BN_new(); + BN_rand(peer->iffval, len * 8, -1, 1); /* r mod n */ + 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)); + vp->tstamp = htonl(tstamp); + vp->fstamp = htonl(peer->fstamp); + vp->vallen = htonl(len); + vp->ptr = emalloc(len); + BN_bn2bin(peer->iffval, vp->ptr); + vp->siglen = 0; + if (tstamp == 0) + return (XEVNT_OK); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_bob2 - construct Bob's response to Alice's challenge + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + */ +static int +crypto_bob2( + struct exten *ep, /* extension pointer */ + struct value *vp /* value pointer */ + ) +{ + RSA *rsa; /* GQ parameters */ + DSA_SIG *sdsa; /* DSA parameters */ + BN_CTX *bctx; /* BIGNUM context */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; /* NTP timestamp */ + BIGNUM *r, *k, *g, *y; + u_char *ptr; + u_int len; + + /* + * If the GQ parameters are not valid, something awful + * happened or we are being tormented. + */ + if (!(crypto_flags & CRYPTO_FLAG_GQ)) { + msyslog(LOG_INFO, "crypto_bob2: scheme unavailable"); + return (XEVNT_PUB); + } + rsa = gqpar_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", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); + } + + /* + * Bob rolls random k (0 < k < n), computes y = k u^r mod n and + * x = k^b mod n, then sends (y, hash(x)) to Alice. + */ + bctx = BN_CTX_new(); k = BN_new(); g = BN_new(); y = BN_new(); + sdsa = DSA_SIG_new(); + BN_rand(k, len * 8, -1, 1); /* k */ + BN_mod(k, k, rsa->n, bctx); + BN_mod_exp(y, rsa->p, r, rsa->n, bctx); /* u^r mod n */ + BN_mod_mul(y, k, y, rsa->n, bctx); /* k u^r mod n */ + sdsa->r = BN_dup(y); + BN_mod_exp(g, k, rsa->e, rsa->n, bctx); /* k^b mod n */ + bighash(g, g); + sdsa->s = BN_dup(g); + BN_CTX_free(bctx); + BN_free(r); BN_free(k); BN_free(g); BN_free(y); + + /* + * Encode the values in ASN.1 and sign. + */ + 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", + ERR_error_string(ERR_get_error(), NULL)); + DSA_SIG_free(sdsa); + return (XEVNT_PUB); + } + 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); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_gq - verify Bob's response to Alice's challenge + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_FSP bad filestamp + * XEVNT_ID bad or missing identity parameters + */ +int +crypto_gq( + struct exten *ep, /* extension pointer */ + struct peer *peer /* peer structure pointer */ + ) +{ + RSA *rsa; /* GQ parameters */ + BN_CTX *bctx; /* BIGNUM context */ + DSA_SIG *sdsa; /* RSA signature context fake */ + BIGNUM *y, *v; + const u_char *ptr; + u_int len; + int temp; + + /* + * If the GQ parameters are not valid or no challenge was sent, + * something awful happened or we are being tormented. + */ + if (peer->ident_pkey == NULL) { + msyslog(LOG_INFO, "crypto_gq: scheme unavailable"); + return (XEVNT_PUB); + } + if (ntohl(ep->fstamp) != peer->fstamp) { + msyslog(LOG_INFO, "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"); + return (XEVNT_PUB); + } + if (peer->iffval == NULL) { + msyslog(LOG_INFO, "crypto_gq: missing challenge"); + return (XEVNT_PUB); + } + + /* + * Extract the y = k u^r and hash(x = k^b) values from the + * response. + */ + bctx = BN_CTX_new(); y = BN_new(); v = BN_new(); + len = ntohl(ep->vallen); + ptr = (const u_char *)ep->pkt; + if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) { + msyslog(LOG_ERR, "crypto_gq %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); + } + + /* + * Compute v^r y^b mod n. + */ + 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 */ + BN_mod_mul(y, v, y, rsa->n, bctx); /* v^r y^b mod n */ + + /* + * Verify the hash of the result matches hash(x). + */ + bighash(y, y); + temp = BN_cmp(y, sdsa->s); + BN_CTX_free(bctx); BN_free(y); BN_free(v); + BN_free(peer->iffval); + peer->iffval = NULL; + DSA_SIG_free(sdsa); + if (temp == 0) + return (XEVNT_OK); + else + return (XEVNT_ID); +} + + +/* + *********************************************************************** + * * + * The following routines implement the Mu-Varadharajan (MV) identity * + * 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 + * separate decryption key for each client. It operated something like a + * pay-per-view satellite broadcasting system where the session key is + * encrypted by the broadcaster and the decryption keys are held in a + * tamperproof set-top box. + * + * The MV parameters and private encryption key hide in a DSA cuckoo + * structure which uses the same parameters, but generated in a + * different way. The values are used in an encryption scheme similar to + * El Gamal cryptography and a polynomial formed from the expansion of + * product terms (x - x[j]), as described in Mu, Y., and V. + * 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. + * + * 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 + * polynomial of order n. The product terms (x - x[j]) are expanded to + * form coefficients a[i] mod q (i = 0...n) in powers of x. These are + * used as exponents of the generator g mod p to generate the private + * encryption key A. The pair (gbar, ghat) of public server keys and the + * 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. + * + * 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 + * 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. + * + * 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). + * + * 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 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. + * + * 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 identity parameters + */ +static int +crypto_alice3( + struct peer *peer, /* peer pointer */ + struct value *vp /* value pointer */ + ) +{ + DSA *dsa; /* MV parameters */ + BN_CTX *bctx; /* BIGNUM context */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; + u_int len; + + /* + * The identity parameters must have correct format and content. + */ + if (peer->ident_pkey == NULL) + return (XEVNT_ID); + if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) { + msyslog(LOG_INFO, "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. + */ + 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 */ + 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)); + vp->tstamp = htonl(tstamp); + vp->fstamp = htonl(peer->fstamp); + vp->vallen = htonl(len); + vp->ptr = emalloc(len); + BN_bn2bin(peer->iffval, vp->ptr); + vp->siglen = 0; + if (tstamp == 0) + return (XEVNT_OK); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_bob3 - construct Bob's response to Alice's challenge + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + */ +static int +crypto_bob3( + struct exten *ep, /* extension pointer */ + struct value *vp /* value pointer */ + ) +{ + DSA *dsa; /* MV parameters */ + DSA *sdsa; /* DSA signature context fake */ + BN_CTX *bctx; /* BIGNUM context */ + EVP_MD_CTX ctx; /* signature context */ + tstamp_t tstamp; /* NTP timestamp */ + BIGNUM *r, *k, *u; + u_char *ptr; + u_int len; + + /* + * If the MV parameters are not valid, something awful + * happened or we are being tormented. + */ + if (!(crypto_flags & CRYPTO_FLAG_MV)) { + msyslog(LOG_INFO, "crypto_bob3: scheme unavailable"); + return (XEVNT_PUB); + } + dsa = mvpar_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", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); + } + + /* + * 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. + */ + bctx = BN_CTX_new(); k = BN_new(); u = BN_new(); + sdsa = DSA_new(); + sdsa->p = BN_new(); sdsa->q = BN_new(); sdsa->g = BN_new(); + while (1) { + BN_rand(k, BN_num_bits(dsa->q), 0, 0); + BN_mod(k, k, dsa->q, bctx); + BN_gcd(u, k, dsa->q, bctx); + 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(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); + + /* + * Encode the values in ASN.1 and sign. + */ + tstamp = crypto_time(); + memset(vp, 0, sizeof(struct value)); + vp->tstamp = htonl(tstamp); + vp->fstamp = htonl(mv_fstamp); + len = i2d_DSAparams(sdsa, NULL); + if (len <= 0) { + msyslog(LOG_ERR, "crypto_bob3 %s\n", + ERR_error_string(ERR_get_error(), NULL)); + DSA_free(sdsa); + return (XEVNT_PUB); + } + vp->vallen = htonl(len); + ptr = emalloc(len); + vp->ptr = ptr; + i2d_DSAparams(sdsa, &ptr); + DSA_free(sdsa); + vp->siglen = 0; + if (tstamp == 0) + return (XEVNT_OK); + 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)) + vp->siglen = htonl(len); + return (XEVNT_OK); +} + + +/* + * crypto_mv - verify Bob's response to Alice's challenge + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_FSP bad filestamp + * XEVNT_ID bad or missing identity parameters + */ +int +crypto_mv( + struct exten *ep, /* extension pointer */ + struct peer *peer /* peer structure pointer */ + ) +{ + DSA *dsa; /* MV parameters */ + DSA *sdsa; /* DSA parameters */ + BN_CTX *bctx; /* BIGNUM context */ + BIGNUM *k, *u, *v; + u_int len; + const u_char *ptr; + int temp; + + /* + * If the MV parameters are not valid or no challenge was sent, + * something awful happened or we are being tormented. + */ + if (peer->ident_pkey == NULL) { + msyslog(LOG_INFO, "crypto_mv: scheme unavailable"); + return (XEVNT_PUB); + } + if (ntohl(ep->fstamp) != peer->fstamp) { + msyslog(LOG_INFO, "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"); + return (XEVNT_PUB); + } + if (peer->iffval == NULL) { + msyslog(LOG_INFO, "crypto_mv: missing challenge"); + return (XEVNT_PUB); + } + + /* + * Extract the (hash(y), gbar, 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; + if ((sdsa = d2i_DSAparams(NULL, &ptr, len)) == NULL) { + msyslog(LOG_ERR, "crypto_mv %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_PUB); + } + + /* + * Compute (gbar^xhat ghat^xbar)^-1 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); + + /* + * The result should match the hash of r mod p. + */ + bighash(v, v); + temp = BN_cmp(v, sdsa->p); + BN_CTX_free(bctx); BN_free(k); BN_free(u); BN_free(v); + BN_free(peer->iffval); + peer->iffval = NULL; + DSA_free(sdsa); + if (temp == 0) + return (XEVNT_OK); + else + return (XEVNT_ID); +} + + +/* + *********************************************************************** + * * + * The following routines are used to manipulate certificates * + * * + *********************************************************************** + */ +/* + * 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: invalid 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: expired %s", + ret->subject); + 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 and update value structure. + * + * The certificate request is a copy of the client certificate, which + * includes the version number, subject name and public key of the + * client. The resulting certificate includes these values plus the + * serial number, issuer name and validity interval of the server. The + * validity interval extends from the current time to the same time one + * year hence. For NTP purposes, it is convenient to use the NTP seconds + * of the current time as the serial number. + * + * Returns + * XEVNT_OK success + * XEVNT_PUB bad or missing public key + * XEVNT_CRT bad or missing certificate + * XEVNT_VFY certificate not verified + */ +static int +cert_sign( + struct exten *ep, /* extension field pointer */ + struct value *vp /* value pointer */ + ) +{ + X509 *req; /* X509 certificate request */ + X509 *cert; /* X509 certificate */ + X509_EXTENSION *ext; /* certificate extension */ + ASN1_INTEGER *serial; /* serial number */ + X509_NAME *subj; /* distinguished (common) name */ + EVP_PKEY *pkey; /* public key */ + EVP_MD_CTX ctx; /* message digest context */ + tstamp_t tstamp; /* NTP timestamp */ + u_int len; + u_char *ptr; + int i, temp; + + /* + * Decode ASN.1 objects and construct certificate structure. + */ + tstamp = crypto_time(); + if (tstamp == 0) + return (XEVNT_TSP); + + ptr = (u_char *)ep->pkt; + if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) { + msyslog(LOG_ERR, "cert_sign %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (XEVNT_CRT); + } + /* + * Extract public key and check for errors. + */ + if ((pkey = X509_get_pubkey(req)) == NULL) { + msyslog(LOG_ERR, "cert_sign %s\n", + ERR_error_string(ERR_get_error(), NULL)); + X509_free(req); + return (XEVNT_PUB); + } + + /* + * Generate X509 certificate signed by this server. For this + * prupose the issuer name is the server name. Also copy any + * extensions that might be present. + */ + cert = X509_new(); + X509_set_version(cert, X509_get_version(req)); + serial = ASN1_INTEGER_new(); + ASN1_INTEGER_set(serial, tstamp); + X509_set_serialNumber(cert, serial); + X509_gmtime_adj(X509_get_notBefore(cert), 0L); + X509_gmtime_adj(X509_get_notAfter(cert), YEAR); + subj = X509_get_issuer_name(cert); + X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, + (unsigned char *) sys_hostname, strlen(sys_hostname), -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); + } + X509_free(req); + + /* + * Sign and verify the certificate. + */ + X509_sign(cert, sign_pkey, sign_digest); + if (!X509_verify(cert, sign_pkey)) { + printf("cert_sign\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + X509_free(cert); + return (XEVNT_VFY); + } + len = i2d_X509(cert, NULL); + + /* + * Build and sign the value structure. We have to sign it here, + * since the response has to be returned right away. This is a + * clogging hazard. + */ + memset(vp, 0, sizeof(struct value)); + vp->tstamp = htonl(tstamp); + vp->fstamp = ep->fstamp; + vp->vallen = htonl(len); + vp->ptr = emalloc(len); + ptr = vp->ptr; + i2d_X509(cert, &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); +#ifdef DEBUG + if (debug > 1) + X509_print_fp(stdout, cert); +#endif + X509_free(cert); + return (XEVNT_OK); +} + + +/* + * 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 (!X509_verify(cert, pkey)) + return (XEVNT_VFY); + cinf->flags |= CERT_SIGN; + X509_free(cert); + return (XEVNT_OK); +} + + +/* + * cert - install certificate in certificate list + * + * 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. + * + * Returns + * XEVNT_OK success + * XEVNT_PER certificate expired + * XEVNT_CRT bad or missing certificate + */ +int +cert_install( + struct exten *ep, /* cert info/value */ + struct peer *peer /* peer structure */ + ) +{ + struct cert_info *cp, *xp, *yp, **zp; + int rval; + tstamp_t tstamp; + + /* + * Parse and validate the signed certificate. If valid, + * construct the info/value structure; otherwise, scamper home. + * Note this allows a certificate not-before time to be in the + * future, but not a not-after time to be in the past. + */ + if ((cp = cert_parse((u_char *)ep->pkt, ntohl(ep->vallen), + ntohl(ep->fstamp))) == NULL) + return (XEVNT_CRT); + + tstamp = crypto_time(); + if (tstamp > cp->last) { + cert_free(cp); + return (XEVNT_PER); + } + + /* + * 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 filetsamp, discard + * the new one and leave the building. + */ + rval = XEVNT_OK; + 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_TSP); + } + break; + } + zp = &xp->link; } + yp->link = cinfo; + cinfo = yp; /* - * We are rather paranoid here, since an intruder might cause a - * coredump by infiltrating a naughty key. The line must contain - * a single integer followed by a PEM encoded, null-terminated - * string. - */ - if (rptr == NULL) - rval = RV_DAT; - else if (sscanf(buf, "%d %s", &bits, encoded_key) != 2) - rval = RV_DAT; - else if (R_DecodePEMBlock(&buf[sizeof(u_int)], &len, - encoded_key, strlen(encoded_key))) - rval = RV_DEC; - else if ((len += sizeof(u_int)) != keylen) - rval = RV_KEY; - else if (bits < MIN_RSA_MODULUS_BITS || bits > - MAX_RSA_MODULUS_BITS) - rval = RV_KEY; - else - rval = RV_OK; - if (rval != RV_OK) { - fclose(str); - msyslog(LOG_ERR, "crypto: RSA file %s error %x", cp, - rval); - exit (-1); + * Scan the certificate list to see if Y is signed by X. + */ + for (yp = cinfo; yp != NULL; yp = yp->link) { + for (xp = cinfo; xp != NULL; xp = xp->link) { + if (yp->flags & CERT_ERROR) + continue; + + /* + * If issuer Y matches subject X and signature Y + * is valid using public key X, then Y is valid. + */ + if (strcmp(yp->issuer, xp->subject) != 0) + continue; + + if (cert_valid(yp, xp->pkey) != XEVNT_OK) { + yp->flags |= CERT_ERROR; + continue; + } + xp->flags |= CERT_SIGN; + + /* + * 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)) + continue; + + yp->flags |= CERT_TRUST; + + /* + * 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; + + 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; + + /* + * 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; + + peer->crypto |= CRYPTO_FLAG_VRFY; + } } - fclose(str); - *(u_int *)buf = bits; - memcpy(key, buf, keylen); /* - * Extract filestamp if present. + * That was awesome. Now update the timestamps and signatures. */ - rval = readlink(filename, linkname, MAXFILENAME - 1); - if (rval > 0) { - linkname[rval] = '\0'; - rptr = strrchr(linkname, '.'); - } else { - rptr = strrchr(filename, '.'); - } - if (rptr != NULL) - sscanf(++rptr, "%u", &fstamp); - else - fstamp = 0; -#ifdef DEBUG - if (debug) - printf( - "crypto_rsa: key file %s link %d fs %u modulus %d\n", - cp, rval, fstamp, bits); -#endif - return (fstamp); + crypto_update(); + return (rval); } /* - * crypto_cert - read certificate + * cert_free - free certificate information structure */ -static void -crypto_cert( - char *cp /* file name */ +void +cert_free( + struct cert_info *cinf /* certificate info/value structure */ + ) +{ + if (cinf->pkey != NULL) + EVP_PKEY_free(cinf->pkey); + if (cinf->subject != NULL) + free(cinf->subject); + if (cinf->issuer != NULL) + free(cinf->issuer); + if (cinf->grpkey != NULL) + 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. + */ +static EVP_PKEY * +crypto_key( + char *cp, /* file name */ + tstamp_t *fstamp /* filestamp */ ) { - u_char buf[5000]; /* file line buffer */ - char filename[MAXFILENAME]; /* name of certificate file */ - char linkname[MAXFILENAME]; /* file link (for filestamp) */ - u_int fstamp; /* filestamp */ - u_int32 *pp; - u_int len; - char *rptr; - int rval, fd; + FILE *str; /* file handle */ + EVP_PKEY *pkey = NULL; /* public/private key */ + char filename[MAXFILENAME]; /* name of key file */ + char linkname[MAXFILENAME]; /* filestamp buffer) */ + char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ + char *ptr; /* - * 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. + * 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); else snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); - fd = open(filename, O_RDONLY, 0777); - if (fd <= 0) { - msyslog(LOG_INFO, - "crypto: certificate file %s not found", - filename); - return; - } + str = fopen(filename, "r"); + if (str == NULL) + return (NULL); /* - * We are rather paranoid here, since an intruder might cause a - * coredump by infiltrating naughty values. + * Read the filestamp, which is contained in the first line. */ - rval = RV_OK; - len = read(fd, buf, 5000); - close(fd); - if (rval != RV_OK) { - msyslog(LOG_ERR, - "crypto: certificate file %s error %d", cp, - rval); - exit (-1); + if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { + msyslog(LOG_ERR, "crypto_key: no data %s\n", + filename); + return (NULL); + } + if ((ptr = strrchr(ptr, '.')) == NULL) { + msyslog(LOG_ERR, "crypto_key: no filestamp %s\n", + filename); + return (NULL); + } + if (sscanf(++ptr, "%u", fstamp) != 1) { + msyslog(LOG_ERR, "crypto_key: invalid timestamp %s\n", + filename); + return (NULL); } /* - * The extension field entry consists of the raw certificate. + * Read and decrypt PEM-encoded private key. */ - certif.vallen = htonl(200); /* xxxxxxxxxxxxxxxxxx */ - pp = emalloc(len); - certif.ptr = (u_char *)pp; - memcpy(pp, buf, len); - certif.sig = emalloc(private_key.bits / 8); - crypto_flags |= CRYPTO_FLAG_CERT; + pkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); + fclose(str); + if (pkey == NULL) { + msyslog(LOG_ERR, "crypto_key %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (NULL); + } /* - * Extract filestamp if present. + * Leave tracks in the cryptostats. */ - rval = readlink(filename, linkname, MAXFILENAME - 1); - if (rval > 0) { - linkname[rval] = '\0'; - rptr = strrchr(linkname, '.'); - } else { - rptr = strrchr(filename, '.'); - } - if (rptr != NULL) - sscanf(++rptr, "%u", &fstamp); - else - fstamp = 0; - certif.fstamp = htonl(fstamp); + if ((ptr = strrchr(linkname, '\n')) != NULL) + *ptr = '\0'; + sprintf(statstr, "%s mod %d", &linkname[2], + EVP_PKEY_size(pkey) * 8); + record_crypto_stats(NULL, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_cert: certif file %s link %d fs %u len %d\n", - cp, rval, fstamp, len); + printf("crypto_key: %s\n", statstr); + if (debug > 1) { + if (EVP_MD_type(pkey) == EVP_PKEY_DSA) + DSA_print_fp(stdout, pkey->pkey.dsa, 0); + else + RSA_print_fp(stdout, pkey->pkey.rsa, 0); + } #endif + return (pkey); } /* - * crypto_dh - read agreement parameters, decode and check for errors. + * crypto_cert - load certificate from file + * + * This routine loads a 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. + * + * Returns certificate info/value pointer if valid, NULL if not. */ -static void -crypto_dh( - char *cp /* file name */ +static struct cert_info * /* certificate information */ +crypto_cert( + char *cp /* file name */ ) { - FILE *str; /* file handle */ - u_char buf[MAX_LINLEN]; /* file line buffer */ - u_char encoded_key[MAX_ENCLEN]; /* encoded key buffer */ - u_char prime[MAX_KEYLEN]; /* decoded prime */ - u_char generator[MAX_KEYLEN]; /* decode generator */ - u_int primelen; /* prime length (octets) */ - u_int generatorlen; /* generator length (octets) */ - char filename[MAXFILENAME]; /* name of parameter file */ - char linkname[MAXFILENAME]; /* file link (for filestamp) */ - u_int fstamp; /* filestamp */ - u_int32 *pp; - u_int len; - char *rptr; - int rval; + struct cert_info *ret; /* certificate information */ + FILE *str; /* file handle */ + char filename[MAXFILENAME]; /* name of certificate file */ + char linkname[MAXFILENAME]; /* filestamp buffer */ + char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ + tstamp_t fstamp; /* filestamp */ + long len; + char *ptr; + char *name, *header; + u_char *data; /* - * 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. + * Open the certificate 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); else snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); str = fopen(filename, "r"); - if (str == NULL) { - msyslog(LOG_INFO, - "crypto: parameters file %s not found", filename); - return; - } + if (str == NULL) + return (NULL); /* - * Ignore initial comments and empty lines. + * Read the filestamp, which is contained in the first line. */ - while ((rptr = fgets(buf, MAX_LINLEN - 1, str)) != NULL) { - if (strlen(buf) < 1) - continue; - if (*buf == '#' || *buf == '\r' || *buf == '\0') - continue; - break; + if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { + msyslog(LOG_ERR, "crypto_cert: no data %s\n", + filename); + return (NULL); } - - /* - * We are rather paranoid here, since an intruder might cause a - * coredump by infiltrating a naughty key. There must be two - * lines; the first contains the prime, the second the - * generator. Each line must contain a single integer followed - * by a PEM encoded, null-terminated string. - */ - if (rptr == NULL) - rval = RV_DAT; - else if (sscanf(buf, "%u %s", &primelen, encoded_key) != 2) - rval = RV_DAT; - else if (primelen > MAX_KEYLEN) - rval = RV_KEY; - else if (R_DecodePEMBlock(prime, &len, encoded_key, - strlen(encoded_key))) - rval = RV_DEC; - else if (primelen != len || primelen > - DECODED_CONTENT_LEN(strlen(encoded_key))) - rval = RV_DAT; - else if (fscanf(str, "%u %s", &generatorlen, encoded_key) != 2) - rval = RV_DAT; - else if (generatorlen > MAX_KEYLEN) - rval = RV_KEY; - else if (R_DecodePEMBlock(generator, &len, encoded_key, - strlen(encoded_key))) - rval = RV_DEC; - else if (generatorlen != len || generatorlen > - DECODED_CONTENT_LEN(strlen(encoded_key))) - rval = RV_DAT; - else - rval = RV_OK; - if (rval != RV_OK) { - msyslog(LOG_ERR, - "crypto: parameters file %s error %x", cp, - rval); - exit (-1); + if ((ptr = strrchr(ptr, '.')) == NULL) { + msyslog(LOG_ERR, "crypto_cert: no filestamp %s\n", + filename); + return (NULL); + } + if (sscanf(++ptr, "%u", &fstamp) != 1) { + msyslog(LOG_ERR, "crypto_cert: invalid filestamp %s\n", + filename); + return (NULL); } - fclose(str); - - /* - * Initialize agreement parameters and extension field in - * network byte order. Note the private key length is set - * arbitrarily at half the prime length. - */ - len = 4 + primelen + 4 + generatorlen; - dhparam.vallen = htonl(len); - pp = emalloc(len); - dhparam.ptr = (u_char *)pp; - *pp++ = htonl(primelen); - memcpy(pp, prime, primelen); - dh_params.prime = (u_char *)pp; - pp += primelen / 4; - *pp++ = htonl(generatorlen); - memcpy(pp, &generator, generatorlen); - dh_params.generator = (u_char *)pp; - - dh_params.primeLen = primelen; - dh_params.generatorLen = generatorlen; - dh_keyLen = primelen / 2; - dh_private = emalloc(dh_keyLen); - dhparam.sig = emalloc(private_key.bits / 8); - crypto_flags |= CRYPTO_FLAG_DH; /* - * Initialize public value extension field. + * Read PEM-encoded certificate and install. */ - dhpub.vallen = htonl(dh_params.primeLen); - dhpub.ptr = emalloc(dh_params.primeLen); - dhpub.sig = emalloc(private_key.bits / 8); + if (!PEM_read(str, &name, &header, &data, &len)) { + msyslog(LOG_ERR, "crypto_cert %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (NULL); + } + free(header); + if (strcmp(name, "CERTIFICATE") !=0) { + msyslog(LOG_INFO, "crypto_cert: wrong PEM type %s", + name); + free(name); + free(data); + return (NULL); + } + free(name); /* - * Extract filestamp if present. + * Parse certificate and generate info/value structure. */ - rval = readlink(filename, linkname, MAXFILENAME - 1); - if (rval > 0) { - linkname[rval] = '\0'; - rptr = strrchr(linkname, '.'); - } else { - rptr = strrchr(filename, '.'); - } - if (rptr != NULL) - sscanf(++rptr, "%u", &fstamp); - else - fstamp = 0; - dhparam.fstamp = htonl(fstamp); - dhpub.fstamp = htonl(fstamp); + ret = cert_parse(data, len, fstamp); + free(data); + if (ret == NULL) + return (NULL); + if ((ptr = strrchr(linkname, '\n')) != NULL) + *ptr = '\0'; + sprintf(statstr, "%s 0x%x len %lu", &linkname[2], ret->flags, + len); + record_crypto_stats(NULL, statstr); #ifdef DEBUG if (debug) - printf( - "crypto_dh: pars file %s link %d fs %u prime %u gen %u\n", - cp, rval, fstamp, dh_params.primeLen, - dh_params.generatorLen); + printf("crypto_cert: %s\n", statstr); #endif + return (ret); } /* - * crypto_tai - read leapseconds table and check for errors. + * 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 */ + char *cp /* file name */ ) { - FILE *str; /* file handle */ - u_char buf[MAX_LINLEN]; /* file line buffer */ - u_int leapsec[MAX_LEAP]; /* NTP time at leaps */ - u_int offset; /* offset at leap (s) */ - char filename[MAXFILENAME]; /* name of leapseconds file */ - char linkname[MAXFILENAME]; /* file link (for filestamp) */ - u_int fstamp; /* filestamp */ - u_int32 *pp; - u_int len; - char *rptr; - int rval, i; + FILE *str; /* file handle */ + char buf[NTP_MAXSTRLEN]; /* file line buffer */ + u_int leapsec[MAX_LEAP]; /* NTP time at leaps */ + u_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; + char *ptr; + int rval, i; #ifdef KERNEL_PLL #if NTP_API > 3 struct timex ntv; /* kernel interface structure */ @@ -1886,13 +3616,24 @@ crypto_tai( strcpy(filename, cp); else snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); - str = fopen(filename, "r"); - if (str == NULL) { - msyslog(LOG_INFO, - "crypto: leapseconds file %s not found", - filename); + if ((str = fopen(filename, "r")) == NULL) return; + + /* + * Extract filestamp if present. + */ + rval = readlink(filename, linkname, MAXFILENAME - 1); + if (rval > 0) { + linkname[rval] = '\0'; + ptr = strrchr(linkname, '.'); + } else { + ptr = strrchr(filename, '.'); } + if (ptr != NULL) + sscanf(++ptr, "%u", &fstamp); + else + fstamp = 0; + tai_leap.fstamp = htonl(fstamp); /* * We are rather paranoid here, since an intruder might cause a @@ -1905,10 +3646,9 @@ crypto_tai( * 1972 plus one second for each succeeding insertion. */ i = 0; - rval = RV_OK; while (i < MAX_LEAP) { - rptr = fgets(buf, MAX_LINLEN - 1, str); - if (rptr == NULL) + ptr = fgets(buf, NTP_MAXSTRLEN - 1, str); + if (ptr == NULL) break; if (strlen(buf) < 1) continue; @@ -1916,16 +3656,15 @@ crypto_tai( continue; if (sscanf(buf, "%u %u", &leapsec[i], &offset) != 2) continue; - if (i != offset - TAI_1972) { - rval = RV_DAT; + if (i != (int)(offset - TAI_1972)) { break; } i++; } fclose(str); - if (rval != RV_OK || i == 0) { - msyslog(LOG_ERR, - "crypto: leapseconds file %s error %d", cp, + if (ptr != NULL) { + msyslog(LOG_INFO, + "crypto_tai: leapseconds file %s error %d", cp, rval); exit (-1); } @@ -1937,12 +3676,11 @@ crypto_tai( */ len = i * 4; tai_leap.vallen = htonl(len); - pp = emalloc(len); - tai_leap.ptr = (u_char *)pp; + ptr = emalloc(len); + tai_leap.ptr = (unsigned char *) ptr; for (; i >= 0; i--) { - *pp++ = htonl(leapsec[i]); + *ptr++ = (char) htonl(leapsec[i]); } - tai_leap.sig = emalloc(private_key.bits / 8); crypto_flags |= CRYPTO_FLAG_TAI; sys_tai = len / 4 + TAI_1972 - 1; #ifdef KERNEL_PLL @@ -1950,109 +3688,344 @@ crypto_tai( ntv.modes = MOD_TAI; ntv.constant = sys_tai; if (ntp_adjtime(&ntv) == TIME_ERROR) - msyslog(LOG_ERR, - "crypto: kernel TAI update failed"); + msyslog(LOG_INFO, + "crypto_tai: kernel TAI update failed"); #endif /* NTP_API */ #endif /* KERNEL_PLL */ + sprintf(statstr, "%s link %d fs %u offset %u", cp, rval, fstamp, + ntohl(tai_leap.vallen) / 4 + TAI_1972 - 1); + record_crypto_stats(NULL, statstr); +#ifdef DEBUG + if (debug) + printf("crypto_tai: %s\n", statstr); +#endif +} + +/* + * crypto_setup - load keys, certificate and leapseconds table + * + * 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. + */ +void +crypto_setup(void) +{ + EVP_PKEY *pkey; /* private/public key pair */ + char filename[MAXFILENAME]; /* file name buffer */ + l_fp seed; /* crypto PRNG seed as NTP timestamp */ + tstamp_t fstamp; /* filestamp */ + tstamp_t sstamp; /* sign filestamp */ + u_int len, bytes; + u_char *ptr; /* - * Extract filestamp if present. + * Initialize structures. */ - rval = readlink(filename, linkname, MAXFILENAME - 1); - if (rval > 0) { - linkname[rval] = '\0'; - rptr = strrchr(linkname, '.'); - } else { - rptr = strrchr(filename, '.'); + if (!crypto_flags) + 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)); + + /* + * Load required random seed file and seed the random number + * generator. Be default, it is found 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); + } + } 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); } - if (rptr != NULL) - sscanf(++rptr, "%u", &fstamp); - else - fstamp = 0; - tai_leap.fstamp = htonl(fstamp); + 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); + } + get_systime(&seed); + 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_". It + * also becomes the default sign key. + */ + 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) { + msyslog(LOG_ERR, + "crypto_setup: host key file %s not found or corrupt", + host_file); + exit (-1); + } + host_pkey = pkey; + sign_pkey = pkey; + sstamp = fstamp; + hostval.fstamp = htonl(fstamp); + if (EVP_MD_type(host_pkey) != 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 = (unsigned char *) sys_hostname; + + /* + * Construct public key extension field for agreement scheme. + */ + len = i2d_PublicKey(host_pkey, NULL); + ptr = emalloc(len); + pubkey.ptr = ptr; + i2d_PublicKey(host_pkey, &ptr); + pubkey.vallen = htonl(len); + pubkey.fstamp = hostval.fstamp; + + /* + * Load optional sign key from file "ntpkey_sign_". If + * loaded, 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); + + /* + * Load optional IFF parameters from file + * "ntpkey_iff_". + */ + 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_". + */ + if (gqpar_file == NULL) { + snprintf(filename, MAXFILENAME, "ntpkey_gq_%s", + sys_hostname); + gqpar_file = emalloc(strlen(filename) + 1); + strcpy(gqpar_file, filename); + } + gqpar_pkey = crypto_key(gqpar_file, &gq_fstamp); + if (gqpar_pkey != NULL) + crypto_flags |= CRYPTO_FLAG_GQ; + + /* + * Load optional MV parameters from file "ntpkey_mv_". + */ + if (mvpar_file == NULL) { + snprintf(filename, MAXFILENAME, "ntpkey_mv_%s", + sys_hostname); + mvpar_file = emalloc(strlen(filename) + 1); + strcpy(mvpar_file, filename); + } + mvpar_pkey = crypto_key(mvpar_file, &mv_fstamp); + if (mvpar_pkey != NULL) + crypto_flags |= CRYPTO_FLAG_MV; + + /* + * Load required certificate from file "ntpkey_cert_". + */ + 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); + } + + /* + * 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. + */ + 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); + } + + /* + * It the certificate is trusted, the subject must be the same + * as the issuer, in other words it must be self signed. + */ + if (cinfo->flags & CERT_PRIV && 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; + + /* + * Load optional leapseconds table from file "ntpkey_leap". If + * the file is missing or defective, the values can later be + * retrieved from a server. + */ + if (leap_file == NULL) + leap_file = "ntpkey_leap"; + crypto_tai(leap_file); #ifdef DEBUG if (debug) printf( - "crypto_tai: leapseconds file %s link %d fs %u offset %u\n", - cp, rval, fstamp, ntohl(tai_leap.vallen) / 4 + - TAI_1972); + "crypto_setup: flags 0x%x host %s signature %s\n", + crypto_flags, sys_hostname, OBJ_nid2ln(cinfo->nid)); #endif } /* - * crypto_config - configure crypto data from crypto configuration - * command. + * crypto_config - configure data from crypto configuration command. */ void crypto_config( - int item, /* configuration item */ - char *cp /* file name */ + int item, /* configuration item */ + char *cp /* file name */ ) { switch (item) { /* - * Initialize flags + * Set random seed file name. + */ + case CRYPTO_CONF_RAND: + rand_file = emalloc(strlen(cp) + 1); + strcpy(rand_file, cp); + break; + + /* + * Set private key password. */ - case CRYPTO_CONF_FLAGS: - sscanf(cp, "%x", &crypto_flags); + case CRYPTO_CONF_PW: + passwd = emalloc(strlen(cp) + 1); + strcpy(passwd, cp); break; /* - * Set private key file name. + * Set host file name. */ case CRYPTO_CONF_PRIV: - private_key_file = emalloc(strlen(cp) + 1); - strcpy(private_key_file, cp); + host_file = emalloc(strlen(cp) + 1); + strcpy(host_file, cp); break; /* - * Set public key file name. + * Set sign key file name. */ - case CRYPTO_CONF_PUBL: - public_key_file = emalloc(strlen(cp) + 1); - strcpy(public_key_file, cp); + case CRYPTO_CONF_SIGN: + sign_file = emalloc(strlen(cp) + 1); + strcpy(sign_file, cp); break; /* - * Set certificate file name. + * Set iff parameters file name. */ - case CRYPTO_CONF_CERT: - certif_file = emalloc(strlen(cp) + 1); - strcpy(certif_file, cp); + case CRYPTO_CONF_IFFPAR: + iffpar_file = emalloc(strlen(cp) + 1); + strcpy(iffpar_file, cp); break; /* - * Set agreement parameter file name. + * Set gq parameters file name. */ - case CRYPTO_CONF_DH: - dh_params_file = emalloc(strlen(cp) + 1); - strcpy(dh_params_file, cp); + case CRYPTO_CONF_GQPAR: + gqpar_file = emalloc(strlen(cp) + 1); + strcpy(gqpar_file, cp); break; /* - * Set leapseconds table file name. + * Set mv parameters file name. */ - case CRYPTO_CONF_LEAP: - tai_leap_file = emalloc(strlen(cp) + 1); - strcpy(tai_leap_file, cp); + case CRYPTO_CONF_MVPAR: + mvpar_file = emalloc(strlen(cp) + 1); + strcpy(mvpar_file, cp); + break; + + /* + * Set certificate file name. + */ + case CRYPTO_CONF_CERT: + cert_file = emalloc(strlen(cp) + 1); + strcpy(cert_file, cp); break; /* - * Set crypto keys directory. + * Set leapseconds file name. */ - case CRYPTO_CONF_KEYS: - keysdir = emalloc(strlen(cp) + 1); - strcpy(keysdir, cp); + case CRYPTO_CONF_LEAP: + leap_file = emalloc(strlen(cp) + 1); + strcpy(leap_file, cp); break; } crypto_flags |= CRYPTO_FLAG_ENAB; } # else int ntp_crypto_bs_pubkey; -# endif /* PUBKEY */ -#else -int ntp_crypto_bs_autokey; -#endif /* AUTOKEY */ +# endif /* OPENSSL */ diff --git a/contrib/ntp/ntpd/ntp_filegen.c b/contrib/ntp/ntpd/ntp_filegen.c index bcf3f9c..59a1d91 100644 --- a/contrib/ntp/ntpd/ntp_filegen.c +++ b/contrib/ntp/ntpd/ntp_filegen.c @@ -214,7 +214,7 @@ filegen_open( * * If the file was open before keep the previous generation. * This will cause output to end up in the 'wrong' file, - * but I think this is still better than loosing output + * but I think this is still better than losing output * * ignore errors due to missing directories */ @@ -316,7 +316,7 @@ filegen_setup( case FILEGEN_MONTH: caljulian(now, &cal); - cal.yearday -= cal.monthday - 1; + cal.yearday = (u_short) (cal.yearday - cal.monthday + 1); cal.monthday = 1; cal.hour = cal.minute = cal.second = 0; new_gen = caltontp(&cal); @@ -378,8 +378,8 @@ filegen_config( gen->basename = (char*)emalloc(strlen(basename) + 1); strcpy(gen->basename, basename); } - gen->type = type; - gen->flag = flag; + gen->type = (u_char) type; + gen->flag = (u_char) flag; /* * make filegen use the new settings diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c index b6cd45b..7f27f21 100644 --- a/contrib/ntp/ntpd/ntp_intres.c +++ b/contrib/ntp/ntpd/ntp_intres.c @@ -50,8 +50,10 @@ 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 @@ -123,8 +125,7 @@ static int resolve_value; /* next value of resolve timer */ /* * File descriptor for ntp request code. */ -static int sockfd = -1; - +static SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */ /* stuff to be filled in by caller */ @@ -410,6 +411,8 @@ addentry( ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); ce->ce_name = cp; ce->ce_peeraddr = 0; + ce->ce_peeraddr6 = in6addr_any; + ANYSOCK(&ce->peer_store); ce->ce_hmode = (u_char)mode; ce->ce_version = (u_char)version; ce->ce_minpoll = (u_char)minpoll; @@ -446,18 +449,18 @@ findhostaddr( struct conf_entry *entry ) { - struct hostent *hp; - struct in_addr in; + struct addrinfo *addr; + int error; checkparent(); /* make sure our guy is still running */ - if (entry->ce_name && entry->ce_peeraddr) { + 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 && !entry->ce_peeraddr) { + if (entry->ce_name == NULL && !SOCKNUL(&entry->peer_store)) { msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!"); return 0; } @@ -468,20 +471,33 @@ findhostaddr( msyslog(LOG_INFO, "findhostaddr: Resolving <%s>", entry->ce_name); #endif /* DEBUG */ - hp = gethostbyname(entry->ce_name); + error = getaddrinfo(entry->ce_name, NULL, NULL, &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 { #ifdef DEBUG if (debug > 2) - msyslog(LOG_INFO, "findhostaddr: Resolving %x>", - entry->ce_peeraddr); + msyslog(LOG_INFO, "findhostaddr: Resolving %s>", + stoa(&entry->peer_store)); #endif - in.s_addr = entry->ce_peeraddr; - hp = gethostbyaddr((const char *)&in, - sizeof entry->ce_peeraddr, - AF_INET); + 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 (hp == NULL) { + if (error != 0) { /* * If the resolver is in use, see if the failure is * temporary. If so, return success. @@ -496,29 +512,11 @@ findhostaddr( if (debug > 2) msyslog(LOG_INFO, "findhostaddr: name resolved."); #endif - /* - * Use the first address. We don't have any way to tell - * preferences and older gethostbyname() implementations - * only return one. - */ - memmove((char *)&(entry->ce_peeraddr), - (char *)hp->h_addr, - sizeof(struct in_addr)); - if (entry->ce_keystr[0] == '*') - strncpy((char *)&(entry->ce_keystr), hp->h_name, - MAXFILENAME); - } else { - char *cp; - size_t s; #ifdef DEBUG if (debug > 2) msyslog(LOG_INFO, "findhostaddr: address resolved."); #endif - s = strlen(hp->h_name) + 1; - cp = (char *)emalloc(s); - strcpy(cp, hp->h_name); - entry->ce_name = cp; } return (1); @@ -531,22 +529,26 @@ findhostaddr( static void openntp(void) { - struct sockaddr_in saddr; + struct addrinfo hints; + struct addrinfo *addrResult; if (sockfd >= 0) return; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if (getaddrinfo(NULL, "ntp", &hints, &addrResult)!=0) { + msyslog(LOG_ERR, "getaddrinfo failed: %m"); + exit(1); + } + sockfd = socket(addrResult->ai_family, addrResult->ai_socktype, 0); + if (sockfd == -1) { msyslog(LOG_ERR, "socket() failed: %m"); exit(1); } - memset((char *)&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = htons(NTP_PORT); /* trash */ - saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */ - /* * Make the socket non-blocking. We'll wait with select() */ @@ -575,12 +577,11 @@ openntp(void) } } #endif /* SYS_WINNT */ - - - if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + if (connect(sockfd, addrResult->ai_addr, addrResult->ai_addrlen) == -1) { msyslog(LOG_ERR, "openntp: connect() failed: %m"); exit(1); } + freeaddrinfo(addrResult); } @@ -711,7 +712,8 @@ request( if (n < 0) { - msyslog(LOG_ERR, "select() fails: %m"); + if (errno != EINTR) + msyslog(LOG_ERR, "select() fails: %m"); return 0; } else if (n == 0) @@ -832,32 +834,32 @@ request( case INFO_ERR_IMPL: msyslog(LOG_ERR, - "server reports implementation mismatch!!"); + "ntpd reports implementation mismatch!"); return 0; case INFO_ERR_REQ: msyslog(LOG_ERR, - "server claims configuration request is unknown"); + "ntpd says configuration request is unknown!"); return 0; case INFO_ERR_FMT: msyslog(LOG_ERR, - "server indicates a format error occurred(!!)"); + "ntpd indicates a format error occurred!"); return 0; case INFO_ERR_NODATA: msyslog(LOG_ERR, - "server indicates no data available (shouldn't happen)"); + "ntpd indicates no data available!"); return 0; case INFO_ERR_AUTH: msyslog(LOG_ERR, - "server returns a permission denied error"); + "ntpd returns a permission denied error!"); return 0; default: msyslog(LOG_ERR, - "server returns unknown error code %d", n); + "ntpd returns unknown error code %d!", n); return 0; } } @@ -1029,10 +1031,10 @@ doconfigure( #ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, - "doconfigure: <%s> has peeraddr %#x", - ce->ce_name, ce->ce_peeraddr); + "doconfigure: <%s> has peeraddr %s", + ce->ce_name, stoa(&ce->peer_store)); #endif - if (dores && ce->ce_peeraddr == 0) { + if (dores && !SOCKNUL(&(ce->peer_store))) { if (!findhostaddr(ce)) { msyslog(LOG_ERR, "couldn't resolve `%s', giving up on it", @@ -1044,7 +1046,7 @@ doconfigure( } } - if (ce->ce_peeraddr != 0) { + if (!SOCKNUL(&ce->peer_store)) { if (request(&ce->ce_config)) { ceremove = ce; ce = ceremove->ce_next; diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c index ef0c146..9f2acea 100644 --- a/contrib/ntp/ntpd/ntp_io.c +++ b/contrib/ntp/ntpd/ntp_io.c @@ -14,6 +14,17 @@ #include "ntp_refclock.h" #include "ntp_if.h" #include "ntp_stdlib.h" +#include "ntp.h" + +/* Don't include ISC's version of IPv6 variables and structures */ +#define ISC_IPV6_H 1 +#include +#include +#include + +#ifdef SIM +#include "ntpsim.h" +#endif #include #include @@ -43,46 +54,20 @@ extern int listen_to_virtual_ips; -#if _BSDI_VERSION >= 199510 -# include +#if defined(SYS_WINNT) +#include +#include +/* + * 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 -#if defined(VMS) /* most likely UCX-specific */ - -#include - -/* "un*x"-compatible names for some items in UCX$INETDEF.H */ -#define ifreq IFREQDEF -#define ifr_name IFR$T_NAME -#define ifr_addr IFR$R_DUMMY.IFR$T_ADDR -#define ifr_broadaddr IFR$R_DUMMY.IFR$T_BROADADDR -#define ifr_flags IFR$R_DUMMY.IFR$R_DUMMY_1_OVRL.IFR$W_FLAGS -#define IFF_UP IFR$M_IFF_UP -#define IFF_BROADCAST IFR$M_IFF_BROADCAST -#define IFF_LOOPBACK IFR$M_IFF_LOOPBACK - -#endif /* VMS */ - - -#if defined(VMS) || defined(SYS_WINNT) -/* structure used in SIOCGIFCONF request (after [KSR] OSF/1) */ -struct ifconf { - int ifc_len; /* size of buffer */ - union { - caddr_t ifcu_buf; - struct ifreq *ifcu_req; - } ifc_ifcu; -}; -#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ -#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ - -#endif /* VMS */ - -#if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL) -# if defined(SYS_AIX) && defined(_IO) /* XXX Identify AIX some other way */ -# undef _IO -# endif -# include #endif /* @@ -118,10 +103,15 @@ u_long io_timereset; /* time counters were reset */ /* * Interface stuff */ -struct interface *any_interface; /* default interface */ -struct interface *loopback_interface; /* loopback interface */ -struct interface inter_list[MAXINTERFACES]; -int ninterfaces; +struct interface *any_interface; /* default ipv4 interface */ +struct interface *any6_interface; /* default ipv6 interface */ +struct interface *loopback_interface; /* loopback ipv4 interface */ +struct interface *loopback6_interface; /* loopback ipv6 interface */ +struct interface inter_list[MAXINTERFACES]; /* Interface list */ +int ninterfaces; /* Total number of interfaces */ +int nwilds; /* Total number of wildcard intefaces */ +int wildipv4 = -1; /* Index into inter_list for IPv4 wildcard */ +int wildipv6 = -1; /* Index into inter_list for IPv6 wildcard */ #ifdef REFCLOCK /* @@ -131,18 +121,94 @@ int ninterfaces; 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 */ fd_set activefds; int maxactivefd; -static int create_sockets P((u_int)); -static int open_socket P((struct sockaddr_in *, int, int)); -static void close_socket P((int)); -static void close_file P((int)); +static int create_sockets P((u_short)); +static SOCKET open_socket P((struct sockaddr_storage *, int, int)); +static void close_socket P((SOCKET)); +#ifdef REFCLOCK +static void close_file P((SOCKET)); +#endif static char * fdbits P((int, fd_set *)); +static void set_reuseaddr P((int)); + +typedef struct vsock vsock_t; + +struct vsock { + SOCKET fd; + ISC_LINK(vsock_t) link; +}; + +ISC_LIST(vsock_t) sockets_list; + +typedef struct remaddr remaddr_t; + +struct remaddr { + struct sockaddr_storage addr; + int if_index; + ISC_LINK(remaddr_t) link; +}; + +ISC_LIST(remaddr_t) remoteaddr_list; + +void add_socket_to_list P((SOCKET)); +void delete_socket_from_list P((SOCKET)); +void add_addr_to_list P((struct sockaddr_storage *, int)); +void delete_addr_from_list P((struct sockaddr_storage *)); +int find_addr_in_list P((struct sockaddr_storage *)); +int create_wildcards P((u_short)); +isc_boolean_t address_okay P((isc_interface_t *)); +void convert_isc_if P((isc_interface_t *, struct interface *, u_short)); +#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. + */ +isc_result_t +connection_reset_fix(SOCKET fd) { + DWORD dwBytesReturned = 0; + BOOL bNewBehavior = FALSE; + DWORD status; + + if(isc_win32os_majorversion() < 5) + return (ISC_R_SUCCESS); /* NT 4.0 has no problem */ + + /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */ + status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior, + sizeof(bNewBehavior), NULL, 0, + &dwBytesReturned, NULL, NULL); + if (status != SOCKET_ERROR) + return (ISC_R_SUCCESS); + else + return (ISC_R_UNEXPECTED); +} +#endif /* * init_io - initialize I/O data structures and call socket creation routine */ @@ -150,8 +216,6 @@ void init_io(void) { #ifdef SYS_WINNT - WORD wVersionRequested; - WSADATA wsaData; init_transmitbuff(); #endif /* SYS_WINNT */ @@ -165,7 +229,8 @@ init_io(void) packets_sent = packets_notsent = 0; handler_calls = handler_pkts = 0; io_timereset = 0; - loopback_interface = 0; + loopback_interface = NULL; + loopback6_interface = NULL; #ifdef REFCLOCK refio = 0; @@ -176,14 +241,17 @@ init_io(void) #endif #ifdef SYS_WINNT - wVersionRequested = MAKEWORD(1,1); - if (WSAStartup(wVersionRequested, &wsaData)) + if (!Win32InitSockets()) { - msyslog(LOG_ERR, "No useable winsock.dll: %m"); + netsyslog(LOG_ERR, "No useable winsock.dll: %m"); exit(1); } #endif /* SYS_WINNT */ + ISC_LIST_INIT(sockets_list); + + ISC_LIST_INIT(remoteaddr_list); + /* * Create the sockets */ @@ -197,456 +265,274 @@ init_io(void) #endif } -/* - * create_sockets - create a socket for each interface plus a default - * socket for when we don't know where to send - */ -static int -create_sockets( - u_int port - ) -{ -#if _BSDI_VERSION >= 199510 - int i, j; - struct ifaddrs *ifaddrs, *ifap; - struct sockaddr_in resmask; -#if _BSDI_VERSION < 199701 - struct ifaddrs *lp; - int num_if; -#endif -#else /* _BSDI_VERSION >= 199510 */ -# ifdef STREAMS_TLI - struct strioctl ioc; -# endif /* STREAMS_TLI */ - char buf[MAXINTERFACES*sizeof(struct ifreq)]; - struct ifconf ifc; - struct ifreq ifreq, *ifr; - int n, i, j, vs, size = 0; - struct sockaddr_in resmask; -#endif /* _BSDI_VERSION >= 199510 */ +int +create_wildcards(u_short port) { -#ifdef DEBUG - if (debug) - printf("create_sockets(%d)\n", ntohs( (u_short) port)); -#endif + int idx = 0; + /* + * create pseudo-interface with wildcard IPv4 address + */ + inter_list[idx].sin.ss_family = AF_INET; + ((struct sockaddr_in*)&inter_list[idx].sin)->sin_addr.s_addr = htonl(INADDR_ANY); + ((struct sockaddr_in*)&inter_list[idx].sin)->sin_port = port; + (void) strncpy(inter_list[idx].name, "wildcard", sizeof(inter_list[idx].name)); + inter_list[idx].mask.ss_family = AF_INET; + ((struct sockaddr_in*)&inter_list[idx].mask)->sin_addr.s_addr = htonl(~(u_int32)0); + inter_list[idx].bfd = INVALID_SOCKET; + inter_list[idx].num_mcast = 0; + inter_list[idx].received = 0; + inter_list[idx].sent = 0; + inter_list[idx].notsent = 0; + inter_list[idx].flags = INT_BROADCAST; + any_interface = &inter_list[idx]; +#if defined(MCAST) + /* + * enable possible multicast reception on the broadcast socket + */ + inter_list[idx].bcast.ss_family = AF_INET; + ((struct sockaddr_in*)&inter_list[idx].bcast)->sin_port = port; + ((struct sockaddr_in*)&inter_list[idx].bcast)->sin_addr.s_addr = htonl(INADDR_ANY); +#endif /* MCAST */ + wildipv4 = idx; + idx++; +#ifdef HAVE_IPV6 /* - * create pseudo-interface with wildcard address + * create pseudo-interface with wildcard IPv6 address */ - inter_list[0].sin.sin_family = AF_INET; - inter_list[0].sin.sin_port = port; - inter_list[0].sin.sin_addr.s_addr = htonl(INADDR_ANY); - (void) strncpy(inter_list[0].name, "wildcard", - sizeof(inter_list[0].name)); - inter_list[0].mask.sin_addr.s_addr = htonl(~ (u_int32)0); - inter_list[0].received = 0; - inter_list[0].sent = 0; - inter_list[0].notsent = 0; - inter_list[0].flags = INT_BROADCAST; - any_interface = &inter_list[0]; - -#if _BSDI_VERSION >= 199510 -#if _BSDI_VERSION >= 199701 - if (getifaddrs(&ifaddrs) < 0) - { - msyslog(LOG_ERR, "getifaddrs: %m"); - exit(1); + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + inter_list[idx].sin.ss_family = AF_INET6; + ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_addr = in6addr_any; + ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_port = port; + (void) strncpy(inter_list[idx].name, "wildcard", sizeof(inter_list[idx].name)); + inter_list[idx].mask.ss_family = AF_INET6; + memset(&((struct sockaddr_in6*)&inter_list[idx].mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr)); + inter_list[idx].bfd = INVALID_SOCKET; + inter_list[idx].num_mcast = 0; + inter_list[idx].received = 0; + inter_list[idx].sent = 0; + inter_list[idx].notsent = 0; + inter_list[idx].flags = 0; + any6_interface = &inter_list[idx]; + wildipv6 = idx; + idx++; } - i = 1; - for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) -#else - if (getifaddrs(&ifaddrs, &num_if) < 0) - { - msyslog(LOG_ERR, "create_sockets: getifaddrs() failed: %m"); - exit(1); - } +#endif + return (idx); +} - i = 1; +isc_boolean_t +address_okay(isc_interface_t *isc_if) { - for (ifap = ifaddrs, lp = ifap + num_if; ifap < lp; ifap++) +#ifdef DEBUG + if (debug > 2) + printf("address_okay: listen Virtual: %d, IF name: %s, Up Flag: %d\n", + listen_to_virtual_ips, isc_if->name, (isc_if->flags & INTERFACE_F_UP)); #endif - { - struct sockaddr_in *sin; - if (!ifap->ifa_addr) - continue; + if (listen_to_virtual_ips == 0 && (strchr(isc_if->name, (int)':') != NULL)) + return (ISC_FALSE); - if (ifap->ifa_addr->sa_family != AF_INET) - continue; + /* XXXPDM This should be fixed later, but since we may not have set + * the UP flag, we at least get to use the interface. + * The UP flag is not always set so we don't do this right now. + */ +/* if ((isc_if->flags & INTERFACE_F_UP) == 0) + return (ISC_FALSE); +*/ + return (ISC_TRUE); +} +void +convert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port) { + + if(isc_if->af == AF_INET) { + itf->sin.ss_family = (u_short) isc_if->af; + strcpy(itf->name, isc_if->name); + 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) { + 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; + } - if ((ifap->ifa_flags & IFF_UP) == 0) - continue; + 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; - if (debug) - printf("after getifaddrs(), considering %s (%s)\n", - ifap->ifa_name, - inet_ntoa(((struct sockaddr_in *)ifap->ifa_addr)->sin_addr)); - - if (ifap->ifa_flags & IFF_LOOPBACK) { - sin = (struct sockaddr_in *)ifap->ifa_addr; - if (ntohl(sin->sin_addr.s_addr) != 0x7f000001 && - !listen_to_virtual_ips) - continue; - } - inter_list[i].flags = 0; - if (ifap->ifa_flags & IFF_BROADCAST) - inter_list[i].flags |= INT_BROADCAST; - strcpy(inter_list[i].name, ifap->ifa_name); - sin = (struct sockaddr_in *)ifap->ifa_addr; - inter_list[i].sin = *sin; - inter_list[i].sin.sin_port = port; - if (ifap->ifa_flags & IFF_LOOPBACK) { - inter_list[i].flags = INT_LOOPBACK; - if (loopback_interface == NULL - || ntohl(sin->sin_addr.s_addr) != 0x7f000001) - loopback_interface = &inter_list[i]; - } - if (inter_list[i].flags & INT_BROADCAST) { - sin = (struct sockaddr_in *)ifap->ifa_broadaddr; - inter_list[i].bcast = *sin; - inter_list[i].bcast.sin_port = port; - } - if (ifap->ifa_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) { - inter_list[i].mask.sin_addr.s_addr = 0xffffffff; - } else { - sin = (struct sockaddr_in *)ifap->ifa_netmask; - inter_list[i].mask = *sin; + if (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback_interface == NULL)) + { + loopback_interface = itf; } - inter_list[i].mask.sin_family = AF_INET; - inter_list[i].mask.sin_len = sizeof *sin; - - /* - * look for an already existing source interface address. If - * the machine has multiple point to point interfaces, then - * the local address may appear more than once. - * - * A second problem exists if we have two addresses on - * the same network (via "ifconfig alias ..."). Don't - * make two xntp interfaces for the two aliases on the - * one physical interface. -wsr - */ - for (j=0; j < i; j++) - if ((inter_list[j].sin.sin_addr.s_addr & - inter_list[j].mask.sin_addr.s_addr) == - (inter_list[i].sin.sin_addr.s_addr & - inter_list[i].mask.sin_addr.s_addr)) - { - if (inter_list[j].flags & INT_LOOPBACK) - inter_list[j] = inter_list[i]; - break; - } - if (j == i) - i++; - if (i > MAXINTERFACES) - break; } - free(ifaddrs); -#else /* _BSDI_VERSION >= 199510 */ -# ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG - if ((vs = open("/dev/ip", O_RDONLY)) < 0) - { - msyslog(LOG_ERR, "create_sockets: open(/dev/ip) failed: %m"); - exit(1); - } -# else /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ - if ( - (vs = socket(AF_INET, SOCK_DGRAM, 0)) -# ifndef SYS_WINNT - < 0 -# else /* SYS_WINNT */ - == INVALID_SOCKET -# endif /* SYS_WINNT */ - ) { - msyslog(LOG_ERR, "create_sockets: socket(AF_INET, SOCK_DGRAM) failed: %m"); - exit(1); +#ifdef HAVE_IPV6 + else if (isc_if->af == AF_INET6) { + itf->sin.ss_family = (u_short) isc_if->af; + strcpy(itf->name, isc_if->name); + memcpy(&(((struct sockaddr_in6 *)&itf->sin)->sin6_addr), + &(isc_if->address.type.in6), + sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)&itf->sin)->sin6_port = port; + + 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; + + if (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback6_interface == NULL)) + { + loopback6_interface = itf; + } } -# endif /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ +#endif /* HAVE_IPV6 */ - i = 1; -# if !defined(SYS_WINNT) - ifc.ifc_len = sizeof(buf); -# endif -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFCONF; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)buf; - ioc.ic_len = sizeof(buf); - if(ioctl(vs, I_STR, &ioc) < 0 || - ioc.ic_len < sizeof(struct ifreq)) - { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFCONF) failed: %m - exiting"); - exit(1); - } -# ifdef SIZE_RETURNED_IN_BUFFER - ifc.ifc_len = ioc.ic_len - sizeof(int); - ifc.ifc_buf = buf + sizeof(int); -# else /* not SIZE_RETURNED_IN_BUFFER */ - ifc.ifc_len = ioc.ic_len; - ifc.ifc_buf = buf; -# endif /* not SIZE_RETURNED_IN_BUFFER */ - -# else /* not STREAMS_TLI */ - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; -# ifndef SYS_WINNT - if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) -# else - if (WSAIoctl(vs, SIO_GET_INTERFACE_LIST, 0, 0, ifc.ifc_buf, ifc.ifc_len, &ifc.ifc_len, 0, 0) == SOCKET_ERROR) -# endif /* SYS_WINNT */ -{ - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFCONF) failed: %m - exiting"); - exit(1); + /* 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; } +/* + * create_sockets - create a socket for each interface plus a default + * socket for when we don't know where to send + */ +static int +create_sockets( + u_short port + ) +{ + struct sockaddr_storage resmask; + int i; + 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 idx = 0; -# endif /* not STREAMS_TLI */ +#ifdef DEBUG + if (debug) + printf("create_sockets(%d)\n", ntohs( (u_short) port)); +#endif + + if (isc_net_probeipv6() == ISC_R_SUCCESS) + scan_ipv6 = ISC_TRUE; +#ifdef HAVE_IPV6 + else + netsyslog(LOG_ERR, "no IPv6 interfaces found"); +#endif - for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0; - ifr = (struct ifreq *)((char *)ifr + size)) + if (isc_net_probeipv4() == ISC_R_SUCCESS) + scan_ipv4 = ISC_TRUE; + else + netsyslog(LOG_ERR, "no IPv4 interfaces found"); + + nwilds = create_wildcards(port); + idx = nwilds; + + result = isc_interfaceiter_create(mctx, &iter); + if (result != ISC_R_SUCCESS) + return (result); + + for (result = isc_interfaceiter_first(iter); + result == ISC_R_SUCCESS; + result = isc_interfaceiter_next(iter)) { - size = sizeof(*ifr); + isc_interface_t isc_if; + unsigned int family; -# ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) - size += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); -# endif - n -= size; + result = isc_interfaceiter_current(iter, &isc_if); + if (result != ISC_R_SUCCESS) + break; -# if !defined(SYS_WINNT) - /* Exclude logical interfaces (indicated by ':' in the interface name) */ - if (debug) - printf("interface <%s> ", ifr->ifr_name); - if ((listen_to_virtual_ips == 0) - && (strchr(ifr->ifr_name, (int)':') != NULL)) { - if (debug) - printf("ignored\n"); + /* See if we have a valid family to use */ + family = isc_if.address.family; + if (family != AF_INET && family != AF_INET6) continue; - } - if (debug) - printf("OK\n"); - - if ( -# ifdef VMS /* VMS+UCX */ - (((struct sockaddr *)&(ifr->ifr_addr))->sa_family != AF_INET) -# else - (ifr->ifr_addr.sa_family != AF_INET) -# endif /* VMS+UCX */ - ) { - if (debug) - printf("ignoring %s - not AF_INET\n", - ifr->ifr_name); + if (scan_ipv4 == ISC_FALSE && family == AF_INET) continue; - } -# endif /* SYS_WINNT */ - ifreq = *ifr; - inter_list[i].flags = 0; - /* is it broadcast capable? */ -# ifndef SYS_WINNT -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFFLAGS; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if(ioctl(vs, I_STR, &ioc)) { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFFLAGS) failed: %m"); - continue; - } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { - if (errno != ENXIO) - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFFLAGS) failed: %m"); + if (scan_ipv6 == ISC_FALSE && family == AF_INET6) continue; - } -# endif /* not STREAMS_TLI */ - if ((ifreq.ifr_flags & IFF_UP) == 0) { - if (debug) - printf("ignoring %s - interface not UP\n", - ifr->ifr_name); - continue; - } - inter_list[i].flags = 0; - if (ifreq.ifr_flags & IFF_BROADCAST) - inter_list[i].flags |= INT_BROADCAST; -# endif /* not SYS_WINNT */ -# if !defined(SUN_3_3_STINKS) - if ( -# if defined(IFF_LOCAL_LOOPBACK) /* defined(SYS_HPUX) && (SYS_HPUX < 8) */ - (ifreq.ifr_flags & IFF_LOCAL_LOOPBACK) -# elif defined(IFF_LOOPBACK) - (ifreq.ifr_flags & IFF_LOOPBACK) -# else /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ - /* test against 127.0.0.1 (yuck!!) */ - ((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr == inet_addr("127.0.0.1")) -# endif /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ - ) - { -# ifndef SYS_WINNT - inter_list[i].flags |= INT_LOOPBACK; -# endif /* not SYS_WINNT */ - if (loopback_interface == 0) - { - loopback_interface = &inter_list[i]; - } - } -# endif /* not SUN_3_3_STINKS */ -#if 0 -# ifndef SYS_WINNT -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFADDR; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if (ioctl(vs, I_STR, &ioc)) - { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFADDR) failed: %m"); - continue; + /* Check to see if we are going to use the interface */ + if (address_okay(&isc_if) == ISC_TRUE) { + convert_isc_if(&isc_if, &inter_list[idx], port); + inter_list[idx].fd = INVALID_SOCKET; + inter_list[idx].bfd = INVALID_SOCKET; + inter_list[idx].num_mcast = 0; + inter_list[idx].received = 0; + inter_list[idx].sent = 0; + inter_list[idx].notsent = 0; + idx++; } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) - { - if (errno != ENXIO) - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFADDR) failed: %m"); - continue; - } -# endif /* not STREAMS_TLI */ -# endif /* not SYS_WINNT */ -#endif /* 0 */ -# if defined(SYS_WINNT) - {int TODO_FillInTheNameWithSomeThingReasonble;} -# else - (void)strncpy(inter_list[i].name, ifreq.ifr_name, - sizeof(inter_list[i].name)); -# endif - inter_list[i].sin = *(struct sockaddr_in *)&ifr->ifr_addr; - inter_list[i].sin.sin_family = AF_INET; - inter_list[i].sin.sin_port = port; - -# if defined(SUN_3_3_STINKS) - /* - * Oh, barf! I'm too disgusted to even explain this - */ - if (SRCADR(&inter_list[i].sin) == 0x7f000001) - { - inter_list[i].flags |= INT_LOOPBACK; - if (loopback_interface == 0) - loopback_interface = &inter_list[i]; - } -# endif /* SUN_3_3_STINKS */ -# if !defined SYS_WINNT && !defined SYS_CYGWIN32 /* no interface flags on NT */ - if (inter_list[i].flags & INT_BROADCAST) { -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFBRDADDR; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if(ioctl(vs, I_STR, &ioc)) { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFBRDADDR) failed: %m"); - exit(1); - } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFBRDADDR) failed: %m"); - exit(1); - } -# endif /* not STREAMS_TLI */ - -# ifndef ifr_broadaddr - inter_list[i].bcast = - *(struct sockaddr_in *)&ifreq.ifr_addr; -# else - inter_list[i].bcast = - *(struct sockaddr_in *)&ifreq.ifr_broadaddr; -# endif /* ifr_broadaddr */ - inter_list[i].bcast.sin_family = AF_INET; - inter_list[i].bcast.sin_port = port; - } - -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFNETMASK; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if(ioctl(vs, I_STR, &ioc)) { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFNETMASK) failed: %m"); - exit(1); - } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFNETMASK) failed: %m"); - exit(1); - } -# endif /* not STREAMS_TLI */ - inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr; -# else - /* winnt here */ - inter_list[i].bcast = ifreq.ifr_broadaddr; - inter_list[i].bcast.sin_family = AF_INET; - inter_list[i].bcast.sin_port = port; - inter_list[i].mask = ifreq.ifr_mask; -# endif /* not SYS_WINNT */ - - /* - * look for an already existing source interface address. If - * the machine has multiple point to point interfaces, then - * the local address may appear more than once. - */ - for (j=0; j < i; j++) - if (inter_list[j].sin.sin_addr.s_addr == - inter_list[i].sin.sin_addr.s_addr) { - break; - } - if (j == i) - i++; - if (i > MAXINTERFACES) - break; } - closesocket(vs); -#endif /* _BSDI_VERSION >= 199510 */ + isc_interfaceiter_destroy(&iter); - ninterfaces = i; + ninterfaces = idx; + /* + * I/O Completion Ports don't care about the select and FD_SET + */ +#ifndef HAVE_IO_COMPLETION_PORT maxactivefd = 0; FD_ZERO(&activefds); +#endif for (i = 0; i < ninterfaces; i++) { inter_list[i].fd = open_socket(&inter_list[i].sin, inter_list[i].flags & INT_BROADCAST, 0); - } - - /* - * Now that we have opened all the sockets, turn off the reuse flag for - * security. - */ - for (i = 0; i < ninterfaces; i++) { - int off = 0; - - /* - * if inter_list[ n ].fd is -1, we might have a adapter - * configured but not present - */ - if ( inter_list[ i ].fd != -1 ) { - if (setsockopt(inter_list[i].fd, SOL_SOCKET, - SO_REUSEADDR, (char *)&off, - sizeof(off))) { - msyslog(LOG_ERR, "create_sockets: setsockopt(SO_REUSEADDR,off) failed: %m"); - } + if (inter_list[i].bfd != INVALID_SOCKET) + msyslog(LOG_INFO, "Listening on interface %s, %s#%d", + inter_list[i].name, + stoa((&inter_list[i].sin)), + NTP_PORT); + if ((inter_list[i].flags & INT_BROADCAST) && + inter_list[i].bfd != INVALID_SOCKET) + msyslog(LOG_INFO, "Listening on broadcast address %s#%d", + stoa((&inter_list[i].bcast)), + NTP_PORT); +#if defined (HAVE_IO_COMPLETION_PORT) + if (inter_list[i].fd != INVALID_SOCKET) { + io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); } +#endif } -#if defined(MCAST) /* - * enable possible multicast reception on the broadcast socket + * Now that we have opened all the sockets, turn off the reuse + * flag for security. */ - inter_list[0].bcast.sin_addr.s_addr = htonl(INADDR_ANY); - inter_list[0].bcast.sin_family = AF_INET; - inter_list[0].bcast.sin_port = port; -#endif /* MCAST */ + set_reuseaddr(0); /* * Blacklist all bound interface addresses + * Wildcard interfaces are ignored. */ - resmask.sin_addr.s_addr = ~ (u_int32)0; - for (i = 1; i < ninterfaces; i++) + + for (i = nwilds; i < ninterfaces; i++) { + SET_HOSTMASK(&resmask, inter_list[i].sin.ss_family); hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); + } + + /* + * Calculate the address hash for each interface address. + */ + for (i = 0; i < ninterfaces; i++) { + inter_list[i].addr_refid = addr2refid(&inter_list[i].sin); + } + + #ifdef DEBUG if (debug > 1) { printf("create_sockets: ninterfaces=%d\n", ninterfaces); @@ -659,20 +545,15 @@ create_sockets( inter_list[i].flags); /* Leave these as three printf calls. */ printf(" sin=%s", - inet_ntoa((inter_list[i].sin.sin_addr))); + stoa((&inter_list[i].sin))); if (inter_list[i].flags & INT_BROADCAST) printf(" bcast=%s,", - inet_ntoa((inter_list[i].bcast.sin_addr))); + stoa((&inter_list[i].bcast))); printf(" mask=%s\n", - inet_ntoa((inter_list[i].mask.sin_addr))); + stoa((&inter_list[i].mask))); } } #endif -#if defined (HAVE_IO_COMPLETION_PORT) - for (i = 0; i < ninterfaces; i++) { - io_completion_port_add_socket(&inter_list[i]); - } -#endif return ninterfaces; } @@ -684,10 +565,19 @@ io_setbclient(void) { int i; - for (i = 1; i < ninterfaces; i++) { +#ifdef OPEN_BCAST_SOCKET + set_reuseaddr(1); +#endif + for (i = nwilds; i < ninterfaces; i++) { + /* Only IPv4 addresses are valid for broadcast */ + if (inter_list[i].bcast.ss_family != AF_INET) + continue; + + /* Is this a broadcast address? */ if (!(inter_list[i].flags & INT_BROADCAST)) continue; + /* Do we already have the broadcast address open? */ if (inter_list[i].flags & INT_BCASTOPEN) continue; @@ -697,8 +587,54 @@ io_setbclient(void) #ifdef OPEN_BCAST_SOCKET /* Was: !SYS_DOMAINOS && !SYS_LINUX */ inter_list[i].bfd = open_socket(&inter_list[i].bcast, INT_BROADCAST, 1); - inter_list[i].flags |= INT_BCASTOPEN; + if (inter_list[i].bfd != INVALID_SOCKET) { + inter_list[i].flags |= INT_BCASTOPEN; +#if defined (HAVE_IO_COMPLETION_PORT) + io_completion_port_add_socket(inter_list[i].bfd, &inter_list[i]); +#endif + } +#ifdef DEBUG + if (debug) { + if (inter_list[i].bfd != INVALID_SOCKET) + printf("io_setbclient: Opened broadcast client on interface %d, socket: %d\n", + i, inter_list[i].bfd); + else + printf("io_setbclient: Unable to Open broadcast client on interface %d\n", + i); + } +#endif +#endif + } +#ifdef OPEN_BCAST_SOCKET + set_reuseaddr(0); +#endif +#ifdef DEBUG + if (debug) + printf("io_setbclient: Opened broadcast clients\n"); #endif +} + +/* + * set_reuseaddr() - set/clear REUSEADDR on all sockets + * NB possible hole - should we be doing this on broadcast + * fd's also? + */ +static void +set_reuseaddr(int flag) { + int i; + + for (i=0; i < ninterfaces; i++) { + /* + * if inter_list[ n ].fd is -1, we might have a adapter + * configured but not present + */ + if (inter_list[i].fd != INVALID_SOCKET) { + if (setsockopt(inter_list[i].fd, SOL_SOCKET, + SO_REUSEADDR, (char *)&flag, + sizeof(flag))) { + netsyslog(LOG_ERR, "set_reuseaddr: setsockopt(SO_REUSEADDR, %s) failed: %m", flag ? "on" : "off"); + } + } } } @@ -708,83 +644,196 @@ io_setbclient(void) */ void io_multicast_add( - u_int32 addr + struct sockaddr_storage addr ) { #ifdef MCAST struct ip_mreq mreq; int i = ninterfaces; /* Use the next interface */ - u_int32 haddr = ntohl(addr); + u_int32 haddr = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); struct in_addr iaddr; - int s; + SOCKET s; struct sockaddr_in *sinp; - iaddr.s_addr = addr; - if (!IN_CLASSD(haddr)) { - msyslog(LOG_ERR, - "multicast address %s not class D", - inet_ntoa(iaddr)); - return; - } - for (i = 0; i < ninterfaces; i++) { - /* Already have this address */ - if (inter_list[i].sin.sin_addr.s_addr == addr) +#ifdef HAVE_IPV6 + struct ipv6_mreq mreq6; + struct in6_addr iaddr6; + struct sockaddr_in6 *sin6p; +#endif /* HAVE_IPV6 */ + + switch (addr.ss_family) + { + case AF_INET : + iaddr = (((struct sockaddr_in*)&addr)->sin_addr); + if (!IN_CLASSD(haddr)) { + netsyslog(LOG_ERR, + "multicast address %s not class D", + inet_ntoa(iaddr)); return; - /* found a free slot */ - if (inter_list[i].sin.sin_addr.s_addr == 0 && - inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && - inter_list[i].flags == 0) + } + for (i = nwilds; i < ninterfaces; i++) { + /* Be sure it's the correct family */ + if (inter_list[i].sin.ss_family != AF_INET) + continue; + /* Already have this address */ + if (SOCKCMP(&inter_list[i].sin, &addr)) + return; + /* found a free slot */ + if (SOCKNUL(&inter_list[i].sin) && + inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && + inter_list[i].flags == 0) + break; + } + sinp = (struct sockaddr_in*)&(inter_list[i].sin); + memset((char *)&mreq, 0, sizeof(mreq)); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + sinp->sin_family = AF_INET; + sinp->sin_addr = iaddr; + sinp->sin_port = htons(NTP_PORT); + + /* + * Try opening a socket for the specified class D address. This + * works under SunOS 4.x, but not OSF1 .. :-( + */ + set_reuseaddr(1); + s = open_socket((struct sockaddr_storage*)sinp, 0, 1); + set_reuseaddr(0); + if (s == INVALID_SOCKET) { + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + if (wildipv4 >= 0) { + i = wildipv4; + /* HACK ! -- stuff in an address */ + inter_list[i].bcast = addr; + netsyslog(LOG_ERR, + "...multicast address %s using wildcard socket", + inet_ntoa(iaddr)); + } else { + netsyslog(LOG_ERR, + "No wildcard socket available to use for address %s", + inet_ntoa(iaddr)); + return; + } + } else { + inter_list[i].fd = s; + inter_list[i].bfd = INVALID_SOCKET; + (void) strncpy(inter_list[i].name, "multicast", + sizeof(inter_list[i].name)); + ((struct sockaddr_in*)&inter_list[i].mask)->sin_addr.s_addr = htonl(~(u_int32)0); +#if defined (HAVE_IO_COMPLETION_PORT) + io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); +#endif + } + + /* + * enable reception of multicast packets + */ + mreq.imr_multiaddr = iaddr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + netsyslog(LOG_ERR, + "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", + mreq.imr_multiaddr.s_addr, + mreq.imr_interface.s_addr, inet_ntoa(iaddr)); + inter_list[i].flags |= INT_MULTICAST; + inter_list[i].num_mcast++; + if (i >= ninterfaces) + ninterfaces = i+1; + + add_addr_to_list(&addr, i); break; - } - sinp = &(inter_list[i].sin); - memset((char *)&mreq, 0, sizeof(mreq)); - memset((char *)&inter_list[i], 0, sizeof inter_list[0]); - sinp->sin_family = AF_INET; - sinp->sin_addr = iaddr; - sinp->sin_port = htons(123); - /* - * Try opening a socket for the specified class D address. This - * works under SunOS 4.x, but not OSF1 .. :-( - */ - s = open_socket(sinp, 0, 1); - if (s < 0) { - memset((char *)&inter_list[i], 0, sizeof inter_list[0]); - i = 0; - /* HACK ! -- stuff in an address */ - inter_list[i].bcast.sin_addr.s_addr = addr; - msyslog(LOG_ERR, - "...multicast address %s using wildcard socket", - inet_ntoa(iaddr)); - } else { - inter_list[i].fd = s; - inter_list[i].bfd = -1; - (void) strncpy(inter_list[i].name, "multicast", - sizeof(inter_list[i].name)); - inter_list[i].mask.sin_addr.s_addr = htonl(~(u_int32)0); +#ifdef HAVE_IPV6 + case AF_INET6 : + + iaddr6 = ((struct sockaddr_in6*)&addr)->sin6_addr; + if (!IN6_IS_ADDR_MULTICAST(&iaddr6)) { + netsyslog(LOG_ERR, + "address %s not IPv6 multicast address", + stoa(&addr)); + return; + } + for (i = nwilds; i < ninterfaces; i++) { + /* Be sure it's the correct family */ + if(inter_list[i].sin.ss_family != AF_INET6) + continue; + /* Already have this address */ + if (SOCKCMP(&inter_list[i].sin, &addr)) + return; + /* found a free slot */ + if (SOCKNUL(&inter_list[i].sin) && + inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && + inter_list[i].flags == 0) + break; + } + sin6p = (struct sockaddr_in6*)&inter_list[i].sin; + memset((char *)&mreq6, 0, sizeof(mreq6)); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + sin6p->sin6_family = AF_INET6; + sin6p->sin6_addr = iaddr6; + sin6p->sin6_port = htons(NTP_PORT); + + /* + * Try opening a socket for the specified class D address. This + * works under SunOS 4.x, but not OSF1 .. :-( + */ + set_reuseaddr(1); + s = open_socket((struct sockaddr_storage*)sin6p, 0, 1); + set_reuseaddr(0); + if(s == INVALID_SOCKET){ + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + if (wildipv6 >= 0) { + i = wildipv6; + /* HACK ! -- stuff in an address */ + inter_list[i].bcast = addr; + netsyslog(LOG_ERR, + "...multicast address %s using wildcard socket", + stoa(&addr)); + } else { + netsyslog(LOG_ERR, + "No wildcard socket available to use for address %s", + stoa(&addr)); + return; + } + } else { + inter_list[i].fd = s; + inter_list[i].bfd = INVALID_SOCKET; + (void)strncpy(inter_list[i].name, "multicast", + sizeof(inter_list[i].name)); + memset(&(((struct sockaddr_in6*)&inter_list[i].mask)->sin6_addr), 1, sizeof(struct in6_addr)); +#if defined (HAVE_IO_COMPLETION_PORT) + io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); +#endif + } + + /* + * enable reception of multicast packets + */ + mreq6.ipv6mr_multiaddr = iaddr6; + mreq6.ipv6mr_interface = 0; + if(setsockopt(inter_list[i].fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *)&mreq6, sizeof(mreq6)) == -1) + netsyslog(LOG_ERR, + "setsockopt IPV6_JOIN_GROUP fails: %m on interface %d(%s)", + mreq6.ipv6mr_interface, stoa(&addr)); + inter_list[i].flags |= INT_MULTICAST; + inter_list[i].num_mcast++; + if(i >= ninterfaces) + ninterfaces = i+1; + + add_addr_to_list(&addr, i); + break; +#endif /* HAVE_IPV6 */ } - /* - * enable reception of multicast packets - */ - mreq.imr_multiaddr = iaddr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) == -1) - msyslog(LOG_ERR, - "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", - mreq.imr_multiaddr.s_addr, - mreq.imr_interface.s_addr, inet_ntoa(iaddr)); - inter_list[i].flags |= INT_MULTICAST; - if (i >= ninterfaces) - ninterfaces = i+1; +#ifdef DEBUG + if (debug) + printf("io_multicast_add %s\n", stoa(&addr)); +#endif #else /* MCAST */ - struct in_addr iaddr; - - iaddr.s_addr = addr; - msyslog(LOG_ERR, + netsyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support", - inet_ntoa(iaddr)); + stoa(&addr)); #endif /* MCAST */ } @@ -796,12 +845,12 @@ io_unsetbclient(void) { int i; - for (i = 1; i < ninterfaces; i++) + for (i = nwilds; i < ninterfaces; i++) { if (!(inter_list[i].flags & INT_BCASTOPEN)) continue; close_socket(inter_list[i].bfd); - inter_list[i].bfd = -1; + inter_list[i].bfd = INVALID_SOCKET; inter_list[i].flags &= ~INT_BCASTOPEN; } } @@ -812,57 +861,125 @@ io_unsetbclient(void) */ void io_multicast_del( - u_int32 addr + struct sockaddr_storage addr ) { #ifdef MCAST int i; struct ip_mreq mreq; - u_int32 haddr = ntohl(addr); - struct sockaddr_in sinaddr; + u_int32 haddr; - if (!IN_CLASSD(haddr)) - { - sinaddr.sin_addr.s_addr = addr; - msyslog(LOG_ERR, - "invalid multicast address %s", ntoa(&sinaddr)); - return; - } +#ifdef HAVE_IPV6 + struct ipv6_mreq mreq6; + struct in6_addr haddr6; +#endif /* HAVE_IPV6 */ - /* - * Disable reception of multicast packets - */ - mreq.imr_multiaddr.s_addr = addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - for (i = 0; i < ninterfaces; i++) + switch (addr.ss_family) { - if (!(inter_list[i].flags & INT_MULTICAST)) - continue; - if (!(inter_list[i].fd < 0)) - continue; - if (addr != inter_list[i].sin.sin_addr.s_addr) - continue; - if (i != 0) + case AF_INET : + + haddr = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); + + if (!IN_CLASSD(haddr)) { - /* we have an explicit fd, so we can close it */ - close_socket(inter_list[i].fd); - memset((char *)&inter_list[i], 0, sizeof inter_list[0]); - inter_list[i].fd = -1; - inter_list[i].bfd = -1; + netsyslog(LOG_ERR, + "invalid multicast address %s", stoa(&addr)); + return; } - else + + /* + * Disable reception of multicast packets + */ + mreq.imr_multiaddr = ((struct sockaddr_in*)&addr)->sin_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + for (i = 0; i < ninterfaces; i++) { - /* We are sharing "any address" port :-( Don't close it! */ - if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) == -1) - msyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m"); - /* This is **WRONG** -- there may be others ! */ - /* There should be a count of users ... */ - inter_list[i].flags &= ~INT_MULTICAST; + /* Be sure it's the correct family */ + if (inter_list[i].sin.ss_family != AF_INET) + continue; + if (!(inter_list[i].flags & INT_MULTICAST)) + continue; + if (!(inter_list[i].fd < 0)) + continue; + if (!SOCKCMP(&addr, &inter_list[i].sin)) + continue; + if (i != wildipv4) + { + /* we have an explicit fd, so we can close it */ + close_socket(inter_list[i].fd); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + inter_list[i].fd = INVALID_SOCKET; + inter_list[i].bfd = INVALID_SOCKET; + } + else + { + /* We are sharing "any address" port :-( Don't close it! */ + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + netsyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails on address: %s %m", + stoa(&addr)); + inter_list[i].num_mcast--; + /* If there are none left negate the Multicast flag */ + if(inter_list[i].num_mcast == 0) + inter_list[i].flags &= ~INT_MULTICAST; + } } - } + break; + +#ifdef HAVE_IPV6 + case AF_INET6 : + haddr6 = ((struct sockaddr_in6*)&addr)->sin6_addr; + + if (!IN6_IS_ADDR_MULTICAST(&haddr6)) + { + netsyslog(LOG_ERR, + "invalid multicast address %s", stoa(&addr)); + return; + } + + /* + * Disable reception of multicast packets + */ + mreq6.ipv6mr_multiaddr = ((struct sockaddr_in6*)&addr)->sin6_addr; + mreq6.ipv6mr_interface = 0; + for (i = 0; i < ninterfaces; i++) + { + /* Be sure it's the correct family */ + if (inter_list[i].sin.ss_family != AF_INET6) + continue; + if (!(inter_list[i].flags & INT_MULTICAST)) + continue; + if (!(inter_list[i].fd < 0)) + continue; + if (!SOCKCMP(&addr, &inter_list[i].sin)) + continue; + if (i != wildipv6) + { + /* we have an explicit fd, so we can close it */ + close_socket(inter_list[i].fd); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + inter_list[i].fd = INVALID_SOCKET; + inter_list[i].bfd = INVALID_SOCKET; + } + else + { + /* We are sharing "any address" port :-( Don't close it! */ + if (setsockopt(inter_list[i].fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *)&mreq6, sizeof(mreq6)) == -1) + netsyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails on address %s: %m", + stoa(&addr)); + /* If there are none left negate the Multicast flag */ + if(inter_list[i].num_mcast == 0) + inter_list[i].flags &= ~INT_MULTICAST; + } + } + break; +#endif /* HAVE_IPV6 */ + }/* switch */ + delete_addr_from_list(&addr); + #else /* not MCAST */ - msyslog(LOG_ERR, "this function requires multicast kernel"); + netsyslog(LOG_ERR, "this function requires multicast kernel"); #endif /* not MCAST */ } @@ -870,87 +987,163 @@ io_multicast_del( /* * open_socket - open a socket, returning the file descriptor */ -static int + +static SOCKET open_socket( - struct sockaddr_in *addr, + struct sockaddr_storage *addr, int flags, int turn_off_reuse ) { - int fd; + int errval; + SOCKET fd; int on = 1, off = 0; #if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS) int tos; #endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ + if ((addr->ss_family == AF_INET6) && (isc_net_probeipv6() != ISC_R_SUCCESS)) + return (INVALID_SOCKET); + /* create a datagram (UDP) socket */ - if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) #ifndef SYS_WINNT - < 0 + if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) < 0) { + errval = errno; + if(addr->ss_family == AF_INET) + netsyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed on address %s: %m", + stoa(addr)); + else if(addr->ss_family == AF_INET6) + netsyslog(LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed on address %s: %m", + stoa(addr)); + if (errval == EPROTONOSUPPORT || errval == EAFNOSUPPORT || + errval == EPFNOSUPPORT) + return (INVALID_SOCKET); + exit(1); + /*NOTREACHED*/ + } #else - == INVALID_SOCKET -#endif /* SYS_WINNT */ - ) - { - msyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m"); + if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) == INVALID_SOCKET) { + errval = WSAGetLastError(); + if(addr->ss_family == AF_INET) + netsyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed on address %s: %m", + stoa(addr)); + else if(addr->ss_family == AF_INET6) + netsyslog(LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed on address %s: %m", + stoa(addr)); + if (errval == WSAEPROTONOSUPPORT || errval == WSAEAFNOSUPPORT || + errval == WSAEPFNOSUPPORT) + return (INVALID_SOCKET); exit(1); /*NOTREACHED*/ } + if (connection_reset_fix(fd) != ISC_R_SUCCESS) { + netsyslog(LOG_ERR, "connection_reset_fix(fd) failed on address %s: %m", + stoa(addr)); + } + +#endif /* SYS_WINNT */ /* set SO_REUSEADDR since we will be binding the same port number on each interface */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) { - msyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m"); + netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails on address %s: %m", + stoa(addr)); } #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) - { - msyslog(LOG_ERR, "setsockopt IPTOS_LOWDELAY on fails: %m"); - } + if (addr->ss_family == AF_INET) + 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)); + } + +#if defined(IPV6_V6ONLY) + if (addr->ss_family == AF_INET6) + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, + (char*)&on, sizeof(on))) + { + netsyslog(LOG_ERR, "setsockopt IPV6_V6ONLY on fails on address %s: %m", + stoa(addr)); + } +#else /* IPV6_V6ONLY */ +#if defined(IPV6_BINDV6ONLY) + if (addr->ss_family == AF_INET6) + 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 /* IPV6_V6ONLY */ + #endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ /* * bind the local address. */ - if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + if (bind(fd, (struct sockaddr *)addr, SOCKLEN(addr)) < 0) { char buff[160]; - sprintf(buff, - "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m", - fd, addr->sin_family, (int)ntohs(addr->sin_port), - ntoa(addr), - IN_CLASSD(ntohl(addr->sin_addr.s_addr)), flags); - msyslog(LOG_ERR, buff); + + if(addr->ss_family == AF_INET) + sprintf(buff, + "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m", + fd, addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), + stoa(addr), + IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), flags); + else if(addr->ss_family == AF_INET6) + sprintf(buff, + "bind() fd %d, family %d, port %d, addr %s, in6_is_addr_multicast=%d flags=%d fails: %%m", + fd, addr->ss_family, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), + stoa(addr), + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), flags); + else return INVALID_SOCKET; + + netsyslog(LOG_ERR, buff); closesocket(fd); /* - * soft fail if opening a class D address + * soft fail if opening a multicast address */ - if (IN_CLASSD(ntohl(addr->sin_addr.s_addr))) - return -1; + if(addr->ss_family == AF_INET){ + if(IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr))) + return (INVALID_SOCKET); + } + else { + if(IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) + return (INVALID_SOCKET); + } #if 0 exit(1); #else - return -1; + return INVALID_SOCKET; #endif } #ifdef DEBUG if (debug) printf("bind() fd %d, family %d, port %d, addr %s, flags=%d\n", fd, - addr->sin_family, - (int)ntohs(addr->sin_port), - ntoa(addr), + addr->ss_family, + (int)ntohs(((struct sockaddr_in*)addr)->sin_port), + stoa(addr), flags); #endif + + /* + * I/O Completion Ports don't care about the select and FD_SET + */ +#ifndef HAVE_IO_COMPLETION_PORT if (fd > maxactivefd) maxactivefd = fd; FD_SET(fd, &activefds); - +#endif + add_socket_to_list(fd); /* * set non-blocking, */ @@ -967,43 +1160,46 @@ open_socket( #if defined(O_NONBLOCK) /* POSIX */ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + netsyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(FNDELAY) if (fcntl(fd, F_SETFL, FNDELAY) < 0) { - msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + netsyslog(LOG_ERR, "fcntl(FNDELAY) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(O_NDELAY) /* generally the same as FNDELAY */ if (fcntl(fd, F_SETFL, O_NDELAY) < 0) { - msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m"); + netsyslog(LOG_ERR, "fcntl(O_NDELAY) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(FIONBIO) - if ( # if defined(VMS) - (ioctl(fd,FIONBIO,&1) < 0) + if (ioctl(fd,FIONBIO,&on) < 0) # elif defined(SYS_WINNT) - (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) + if (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) # else - (ioctl(fd,FIONBIO,&on) < 0) + if (ioctl(fd,FIONBIO,&on) < 0) # endif - ) { - msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + netsyslog(LOG_ERR, "ioctl(FIONBIO) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(FIOSNBIO) if (ioctl(fd,FIOSNBIO,&on) < 0) { - msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + netsyslog(LOG_ERR, "ioctl(FIOSNBIO) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } @@ -1025,7 +1221,8 @@ open_socket( if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&off, sizeof(off))) { - msyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m"); + netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails on address %s: %m", + stoa(addr)); } #ifdef SO_BROADCAST @@ -1035,7 +1232,8 @@ open_socket( if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on))) { - msyslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); + netsyslog(LOG_ERR, "setsockopt(SO_BROADCAST) on address %s: %m", + stoa(addr)); } } #endif /* SO_BROADCAST */ @@ -1057,21 +1255,29 @@ open_socket( */ static void close_socket( - int fd + SOCKET fd ) { - int i, newmax; + SOCKET i, newmax; (void) closesocket(fd); + + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT FD_CLR( (u_int) fd, &activefds); - if (fd >= maxactivefd) { + if (fd == maxactivefd) { newmax = 0; for (i = 0; i < maxactivefd; i++) if (FD_ISSET(i, &activefds)) newmax = i; maxactivefd = newmax; } +#endif + delete_socket_from_list(fd); + } @@ -1079,24 +1285,33 @@ close_socket( * close_file - close a file and remove from the activefd list * added 1/31/1997 Greg Schueman for Windows NT portability */ +#ifdef REFCLOCK static void close_file( - int fd + SOCKET fd ) { int i, newmax; (void) close(fd); + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT FD_CLR( (u_int) fd, &activefds); - if (fd >= maxactivefd) { + if (fd == maxactivefd) { newmax = 0; for (i = 0; i < maxactivefd; i++) if (FD_ISSET(i, &activefds)) newmax = i; maxactivefd = newmax; } +#endif + delete_socket_from_list(fd); + } +#endif /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ @@ -1107,7 +1322,7 @@ close_file( */ void sendpkt( - struct sockaddr_in *dest, + struct sockaddr_storage *dest, struct interface *inter, int ttl, struct pkt *pkt, @@ -1120,7 +1335,7 @@ sendpkt( #endif /* SYS_WINNT */ /* - * Send error cache. Empty slots have port == 0 + * Send error caches. Empty slots have port == 0 * Set ERRORCACHESIZE to 0 to disable */ struct cache { @@ -1128,57 +1343,121 @@ sendpkt( struct in_addr addr; }; +#ifdef HAVE_IPV6 + struct cache6 { + u_short port; + struct in6_addr addr; + }; +#endif /* HAVE_IPV6 */ + #ifndef ERRORCACHESIZE #define ERRORCACHESIZE 8 #endif #if ERRORCACHESIZE > 0 static struct cache badaddrs[ERRORCACHESIZE]; +#ifdef HAVE_IPV6 + static struct cache6 badaddrs6[ERRORCACHESIZE]; +#endif /* HAVE_IPV6 */ #else #define badaddrs ((struct cache *)0) /* Only used in empty loops! */ +#ifdef HAVE_IPV6 +#define badaddrs6 ((struct cache6 *)0) /* Only used in empty loops! */ +#endif /* HAVE_IPV6 */ #endif #ifdef DEBUG if (debug > 1) printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n", (ttl >= 0) ? "\tMCAST\t*****" : "", - inter->fd, ntoa(dest), - ntoa(&inter->sin), ttl, len); + inter->fd, stoa(dest), + stoa(&inter->sin), ttl, len); #endif #ifdef MCAST - /* - * for the moment we use the bcast option to set multicast ttl - */ - if (ttl > 0 && ttl != inter->last_ttl) { - char mttl = ttl; + + switch (inter->sin.ss_family) { + + case AF_INET : /* - * set the multicast ttl for outgoing packets + * for the moment we use the bcast option to set multicast ttl + */ + if (ttl > 0 && ttl != inter->last_ttl) { + + /* + * set the multicast ttl for outgoing packets + */ + if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, + (char *) &ttl, sizeof(ttl)) != 0) { + netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails on address %s: %m", + stoa(&inter->sin)); + } + else + inter->last_ttl = ttl; + } + break; + +#ifdef HAVE_IPV6 + case AF_INET6 : + + /* + * for the moment we use the bcast option to set + * multicast max hops */ - if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, - &mttl, sizeof(mttl)) == -1) - msyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m"); - else - inter->last_ttl = ttl; + if (ttl > 0 && ttl != inter->last_ttl) { + + /* + * set the multicast ttl for outgoing packets + */ + if (setsockopt(inter->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &ttl, sizeof(ttl)) == -1) + netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails on address %s: %m", + stoa(&inter->sin)); + else + inter->last_ttl = ttl; + } + break; +#endif /* HAVE_IPV6 */ + + default : + exit(1); + } + + #endif /* MCAST */ for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs[slot].port == dest->sin_port && - badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr) - break; + if(dest->ss_family == AF_INET) { + if (badaddrs[slot].port == ((struct sockaddr_in*)dest)->sin_port && + badaddrs[slot].addr.s_addr == ((struct sockaddr_in*)dest)->sin_addr.s_addr) + break; + } +#ifdef HAVE_IPV6 + else if (dest->ss_family == AF_INET6) { + if (badaddrs6[slot].port == ((struct sockaddr_in6*)dest)->sin6_port && + badaddrs6[slot].addr.s6_addr == ((struct sockaddr_in6*)dest)->sin6_addr.s6_addr) + break; + } +#endif /* HAVE_IPV6 */ + else exit(1); /* address family not supported yet */ #if defined(HAVE_IO_COMPLETION_PORT) err = io_completion_port_sendto(inter, pkt, len, dest); if (err != ERROR_SUCCESS) #else - cc = sendto(inter->fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest, - sizeof(struct sockaddr_in)); +#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) + err = WSAGetLastError(); if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) #else if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) @@ -1187,14 +1466,37 @@ sendpkt( /* * Remember this, if there's an empty slot */ - for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs[slot].port == 0) - { - badaddrs[slot].port = dest->sin_port; - badaddrs[slot].addr = dest->sin_addr; - break; - } - msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + switch (dest->ss_family) { + + 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; + } + break; + +#ifdef HAVE_IPV6 + 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 /* HAVE_IPV6 */ + + default : + exit(1); + } + + netsyslog(LOG_ERR, "sendto(%s): %m", stoa(dest)); } } else @@ -1206,8 +1508,17 @@ sendpkt( */ if (slot >= 0) { - msyslog(LOG_INFO, "Connection re-established to %s", ntoa(dest)); - badaddrs[slot].port = 0; + netsyslog(LOG_INFO, "Connection re-established to %s", stoa(dest)); + switch (dest->ss_family) { + case AF_INET : + badaddrs[slot].port = 0; + break; +#ifdef HAVE_IPV6 + case AF_INET6 : + badaddrs6[slot].port = 0; + break; +#endif /* HAVE_IPV6 */ + } } } } @@ -1249,7 +1560,7 @@ input_handler( register int i, n; register struct recvbuf *rb; register int doing; - register int fd; + register SOCKET fd; struct timeval tvzero; int fromlen; l_fp ts; /* Timestamp at BOselect() gob */ @@ -1315,14 +1626,17 @@ input_handler( if (rb->recv_length == -1) { - msyslog(LOG_ERR, "clock read fd %d: %m", fd); + netsyslog(LOG_ERR, "clock read fd %d: %m", fd); freerecvbuf(rb); goto select_again; } /* - * Got one. Mark how and when it got here, - * put it on the full list and do bookkeeping. + * Got one. Mark how + * and when it got here, + * put it on the full + * list and do + * bookkeeping. */ rb->recv_srcclock = rp->srcclock; rb->dstadr = 0; @@ -1333,13 +1647,25 @@ input_handler( if (rp->io_input) { /* - * have direct input routine for refclocks + * have direct + * input routine + * for refclocks */ if (rp->io_input(rb) == 0) { /* - * data was consumed - nothing to pass up - * into block input machine + * data + * was + * consumed + * - + * nothing + * to + * pass + * up + * into + * block + * input + * machine */ freerecvbuf(rb); #if 1 @@ -1360,7 +1686,8 @@ input_handler( #endif /* REFCLOCK */ /* - * Loop through the interfaces looking for data to read. + * Loop through the interfaces looking for data + * to read. */ for (i = ninterfaces - 1; (i >= 0) && (n > 0); i--) { @@ -1382,9 +1709,12 @@ input_handler( n--; /* - * Get a buffer and read the frame. If we - * haven't got a buffer, or this is received - * on the wild card socket, just dump the + * Get a buffer and read + * the frame. If we + * haven't got a buffer, + * or this is received + * on the wild card + * socket, just dump the * packet. */ if ( @@ -1395,23 +1725,24 @@ input_handler( */ (free_recvbuffs() == 0) #else - ((i == 0) || (free_recvbuffs() == 0)) + ((i == wildipv4) || (i == wildipv6)|| + (free_recvbuffs() == 0)) #endif ) { char buf[RX_BUFF_SIZE]; - struct sockaddr from; + struct sockaddr_storage from; fromlen = sizeof from; - (void) recvfrom(fd, buf, sizeof(buf), 0, &from, &fromlen); + (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen); #ifdef DEBUG if (debug) printf("%s on %d(%lu) fd=%d from %s\n", (i) ? "drop" : "ignore", i, free_recvbuffs(), fd, - inet_ntoa(((struct sockaddr_in *) &from)->sin_addr)); + stoa(&from)); #endif - if (i == 0) + if (i == wildipv4 || i == wildipv6) packets_ignored++; else packets_dropped++; @@ -1420,7 +1751,7 @@ input_handler( rb = get_free_recv_buffer(); - fromlen = sizeof(struct sockaddr_in); + fromlen = sizeof(struct sockaddr_storage); rb->recv_length = recvfrom(fd, (char *)&rb->recv_space, sizeof(rb->recv_space), 0, @@ -1439,8 +1770,8 @@ input_handler( } else if (rb->recv_length < 0) { - msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", - inet_ntoa(rb->recv_srcadr.sin_addr), fd); + netsyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", + stoa(&rb->recv_srcadr), fd); #ifdef DEBUG if (debug) printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); @@ -1449,12 +1780,18 @@ input_handler( continue; } #ifdef DEBUG - if (debug > 2) - printf("input_handler: if=%d fd=%d length %d from %08lx %s\n", - i, fd, rb->recv_length, - (u_long)ntohl(rb->recv_srcadr.sin_addr.s_addr) & - 0x00000000ffffffff, - inet_ntoa(rb->recv_srcadr.sin_addr)); + if (debug > 2) { + if(rb->recv_srcadr.ss_family == AF_INET) + printf("input_handler: if=%d fd=%d length %d from %08lx %s\n", + i, fd, rb->recv_length, + (u_long)ntohl(((struct sockaddr_in*)&rb->recv_srcadr)->sin_addr.s_addr) & + 0x00000000ffffffff, + stoa(&rb->recv_srcadr)); + else + printf("input_handler: if=%d fd=%d length %d from %s\n", + i, fd, rb->recv_length, + stoa(&rb->recv_srcadr)); + } #endif /* @@ -1467,7 +1804,7 @@ input_handler( rb->receiver = receive; add_full_recv_buffer(rb); - + inter_list[i].received++; packets_received++; goto select_again; @@ -1491,19 +1828,20 @@ input_handler( if (select_count == 0) /* We really had nothing to do */ { if (debug) - msyslog(LOG_DEBUG, "input_handler: select() returned 0"); + netsyslog(LOG_DEBUG, "input_handler: select() returned 0"); --handler_count; return; } /* We've done our work */ get_systime(&ts_e); /* - * (ts_e - ts) is the amount of time we spent processing - * this gob of file descriptors. Log it. + * (ts_e - ts) is the amount of time we spent + * processing this gob of file descriptors. Log + * it. */ L_SUB(&ts_e, &ts); if (debug > 3) - msyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); + netsyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); /* just bail. */ --handler_count; @@ -1516,8 +1854,11 @@ input_handler( /* * extended FAU debugging output */ - msyslog(LOG_ERR, "select(%d, %s, 0L, 0L, &0.000000) error: %m", - maxactivefd+1, fdbits(maxactivefd, &activefds)); + 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; @@ -1526,7 +1867,7 @@ input_handler( if ( (FD_ISSET(j, &fds) && (read(j, &b, 0) == -1)) ) - msyslog(LOG_ERR, "Bad file descriptor %d", j); + netsyslog(LOG_ERR, "Bad file descriptor %d", j); } --handler_count; return; @@ -1538,70 +1879,91 @@ input_handler( } #endif - /* * findinterface - find interface corresponding to address */ struct interface * findinterface( - struct sockaddr_in *addr + struct sockaddr_storage *addr ) { - int s, rtn, i; - struct sockaddr_in saddr; - int saddrlen = sizeof(saddr); - u_int32 xaddr; - + SOCKET s; + int rtn, i; + struct sockaddr_storage saddr; + int saddrlen = SOCKLEN(addr); /* * This is considerably hoke. We open a socket, connect to it * and slap a getsockname() on it. If anything breaks, as it * probably will in some j-random knockoff, we just return the * wildcard interface. */ - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = addr->sin_addr.s_addr; - saddr.sin_port = htons(2000); - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - return (any_interface); - - rtn = connect(s, (struct sockaddr *)&saddr, sizeof(saddr)); + 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)); + 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_in*)&saddr)->sin_port = htons(2000); + s = socket(addr->ss_family, SOCK_DGRAM, 0); + if (s == INVALID_SOCKET) + return ANY_INTERFACE_CHOOSE(addr); + + rtn = connect(s, (struct sockaddr *)&saddr, SOCKLEN(&saddr)); +#ifndef SYS_WINNT if (rtn < 0) - return (any_interface); +#else + if (rtn == SOCKET_ERROR) +#endif + { + closesocket(s); + return ANY_INTERFACE_CHOOSE(addr); + } rtn = getsockname(s, (struct sockaddr *)&saddr, &saddrlen); + closesocket(s); +#ifndef SYS_WINNT if (rtn < 0) - return (any_interface); - - close(s); - xaddr = NSRCADR(&saddr); - for (i = 1; i < ninterfaces; i++) { +#else + if (rtn == SOCKET_ERROR) +#endif + return ANY_INTERFACE_CHOOSE(addr); + for (i = 0; i < ninterfaces; i++) { + /* + * First look if is the the correct family + */ + if(inter_list[i].sin.ss_family != saddr.ss_family) + continue; /* * We match the unicast address only. */ - if (NSRCADR(&inter_list[i].sin) == xaddr) + if (SOCKCMP(&inter_list[i].sin, &saddr)) return (&inter_list[i]); } - return (any_interface); + return ANY_INTERFACE_CHOOSE(addr); } - /* * findbcastinter - find broadcast interface corresponding to address */ struct interface * findbcastinter( - struct sockaddr_in *addr + struct sockaddr_storage *addr ) { #if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT)) register int i; - register u_int32 xaddr; - - xaddr = NSRCADR(addr); - for (i = 1; i < ninterfaces; i++) { + + i = find_addr_in_list(addr); + if(i >= 0) + return (&inter_list[i]); + for (i = 0; i < ninterfaces; i++) { + /* + * First look if this is the correct family + */ + if(inter_list[i].sin.ss_family != addr->ss_family) + continue; /* * We match only those interfaces marked as * broadcastable and either the explicit broadcast @@ -1610,15 +1972,23 @@ findbcastinter( */ if (!(inter_list[i].flags & INT_BROADCAST)) continue; - if (NSRCADR(&inter_list[i].bcast) == xaddr) - return (&inter_list[i]); - if ((NSRCADR(&inter_list[i].sin) & - NSRCADR(&inter_list[i].mask)) == (xaddr & - NSRCADR(&inter_list[i].mask))) - return (&inter_list[i]); + if(addr->ss_family == AF_INET) { + if (SOCKCMP(&inter_list[i].bcast, addr)) + return (&inter_list[i]); + if ((NSRCADR(&inter_list[i].sin) & + NSRCADR(&inter_list[i].mask)) == (NSRCADR(addr) & + NSRCADR(&inter_list[i].mask))) + return (&inter_list[i]); + } + else if(addr->ss_family == AF_INET6) { + if (SOCKCMP(&inter_list[i].bcast, addr)) + return (&inter_list[i]); + if (SOCKCMP(netof(&inter_list[i].sin), netof(addr))) + return (&inter_list[i]); + } } #endif /* SIOCGIFCONF */ - return (any_interface); + return ANY_INTERFACE_CHOOSE(addr); } @@ -1659,9 +2029,14 @@ io_addclock_simple( rio->next = refio; refio = rio; + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT if (rio->fd > maxactivefd) maxactivefd = rio->fd; FD_SET(rio->fd, &activefds); +#endif UNBLOCKIO(); return 1; } @@ -1693,16 +2068,21 @@ io_addclock( # elif defined(HAVE_IO_COMPLETION_PORT) if (io_completion_port_add_clock_io(rio)) { + add_socket_to_list(rio->fd); refio = rio->next; UNBLOCKIO(); return 0; } # endif + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT if (rio->fd > maxactivefd) maxactivefd = rio->fd; FD_SET(rio->fd, &activefds); - +#endif UNBLOCKIO(); return 1; } @@ -1751,12 +2131,127 @@ io_closeclock( } #endif /* REFCLOCK */ + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT void -kill_asyncio(void) +kill_asyncio( + int startfd + ) { - int i; + SOCKET i; BLOCKIO(); - for (i = 0; i <= maxactivefd; i++) + for (i = startfd; i <= maxactivefd; i++) (void)close_socket(i); } +#else +/* + * 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. + */ +void +kill_asyncio(int startfd) +{ + vsock_t *lsock; + vsock_t *next; + + BLOCKIO(); + + lsock = ISC_LIST_HEAD(sockets_list); + while (lsock != NULL) { + next = ISC_LIST_NEXT(lsock, link); + close_socket(lsock->fd); + lsock = next; + } + +} +#endif +/* + * Add and delete functions for the list of open sockets + */ +void +add_socket_to_list(SOCKET fd){ + vsock_t *lsock = malloc(sizeof(vsock_t)); + lsock->fd = fd; + + ISC_LIST_APPEND(sockets_list, lsock, link); +} +void +delete_socket_from_list(SOCKET fd) { + + vsock_t *next; + vsock_t *lsock = ISC_LIST_HEAD(sockets_list); + + while(lsock != NULL) { + next = ISC_LIST_NEXT(lsock, link); + if(lsock->fd == fd) { + ISC_LIST_DEQUEUE(sockets_list, lsock, link); + free(lsock); + break; + } + else + lsock = next; + } +} +void +add_addr_to_list(struct sockaddr_storage *addr, int if_index){ + remaddr_t *laddr = malloc(sizeof(remaddr_t)); + memcpy(&laddr->addr, addr, sizeof(addr)); + laddr->if_index = if_index; + + ISC_LIST_APPEND(remoteaddr_list, laddr, link); +#ifdef DEBUG + if (debug) + printf("Added addr %s to list of addresses\n", + stoa(addr)); +#endif + + +} +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(remoteaddr_list, laddr, link); + free(laddr); + break; + } + else + laddr = next; + } +#ifdef DEBUG + if (debug) + printf("Deleted addr %s from list of addresses\n", + stoa(addr)); +#endif +} +int +find_addr_in_list(struct sockaddr_storage *addr) { + + remaddr_t *next; + remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list); +#ifdef DEBUG + if (debug) + printf("Finding addr %s in list of addresses\n", + stoa(addr)); +#endif + + while(laddr != NULL) { + next = ISC_LIST_NEXT(laddr, link); + if(SOCKCMP(&laddr->addr, addr)) { + return (laddr->if_index); + break; + } + else + laddr = next; + } + return (-1); /* Not found */ +} diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c index 1d24897..99d1cc4 100644 --- a/contrib/ntp/ntpd/ntp_loopfilter.c +++ b/contrib/ntp/ntpd/ntp_loopfilter.c @@ -1,6 +1,8 @@ /* * ntp_loopfilter.c - implements the NTP loop filter algorithm * + * ATTENTION: Get approval from Dave Mills on all changes to this file! + * */ #ifdef HAVE_CONFIG_H # include @@ -32,18 +34,17 @@ * included to protect against timewarps, timespikes and general mayhem. * All units are in s and s/s, unless noted otherwise. */ -#define CLOCK_MAX .128 /* default step offset (s) */ -#define CLOCK_PANIC 1000. /* default panic offset (s) */ +#define CLOCK_MAX .128 /* default step threshold (s) */ +#define CLOCK_MINSTEP 900. /* default stepout threshold (s) */ +#define CLOCK_PANIC 1000. /* default panic threshold (s) */ #define CLOCK_PHI 15e-6 /* max frequency error (s/s) */ -#define SHIFT_PLL 4 /* PLL loop gain (shift) */ +#define CLOCK_PLL 16. /* PLL loop gain */ #define CLOCK_FLL 8. /* FLL loop gain */ #define CLOCK_AVG 4. /* parameter averaging constant */ -#define CLOCK_MINSEC 256. /* min FLL update interval (s) */ -#define CLOCK_MINSTEP 900. /* step-change timeout (s) */ -#define CLOCK_DAY 86400. /* one day of seconds (s) */ +#define CLOCK_ALLAN 1500. /* compromise Allan intercept (s) */ +#define CLOCK_DAY 86400. /* one day in seconds (s) */ #define CLOCK_LIMIT 30 /* poll-adjust threshold */ #define CLOCK_PGATE 4. /* poll-adjust gate */ -#define CLOCK_ALLAN 10 /* min Allan intercept (log2 s) */ #define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */ /* @@ -108,22 +109,11 @@ /* * Program variables that can be tinkered. */ -double clock_max = CLOCK_MAX; /* max offset before step (s) */ -double clock_panic = CLOCK_PANIC; /* max offset before panic (s) */ +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_phi = CLOCK_PHI; /* dispersion rate (s/s) */ -double clock_minstep = CLOCK_MINSTEP; /* step timeout (s) */ -u_char allan_xpt = CLOCK_ALLAN; /* minimum Allan intercept (log2 s) */ - -/* - * Hybrid PLL/FLL parameters. These were chosen by experiment using a - * MatLab program. The parameters were fudged to match a pure PLL at - * poll intervals of 64 s and lower and a pure FLL at poll intervals of - * 4096 s and higher. Between these extremes the parameters were chosen - * as a geometric series of intervals while holding the overshoot to - * less than 5 percent. - */ -static double fll[] = {0., 1./64, 1./32, 1./16, 1./8, 1./4, 1.}; -static double pll[] = {1., 1.4, 2., 2.8, 4.1, 7., 12.}; +double allan_xpt = CLOCK_ALLAN; /* Allan intercept (s) */ /* * Program variables @@ -132,7 +122,7 @@ static double clock_offset; /* clock offset adjustment (s) */ double drift_comp; /* clock frequency (s/s) */ double clock_stability; /* clock stability (s/s) */ u_long pps_control; /* last pps sample time */ -static void rstclock P((int, double, double)); /* transition function */ +static void rstclock P((int, u_long, double)); /* transition function */ #ifdef KERNEL_PLL struct timex ntv; /* kernel API parameters */ @@ -149,17 +139,15 @@ int kern_enable; /* kernel support enabled */ int pps_enable; /* kernel PPS discipline enabled */ int ext_enable; /* external clock enabled */ int pps_stratum; /* pps stratum */ -int allow_step = TRUE; /* allow step correction */ int allow_panic = FALSE; /* allow panic correction */ int mode_ntpdate = FALSE; /* exit on first clock set */ /* * Clock state machine variables */ -u_char sys_minpoll = NTP_MINDPOLL; /* min sys poll interval (log2 s) */ u_char sys_poll = NTP_MINDPOLL; /* system poll interval (log2 s) */ int state; /* clock discipline state */ -int tc_counter; /* poll-adjust counter */ +int tc_counter; /* hysteresis counter */ u_long last_time; /* time of last clock update (s) */ double last_offset; /* last clock offset (s) */ double sys_jitter; /* system RMS jitter (s) */ @@ -200,6 +188,9 @@ init_loopfilter(void) /* * local_clock - the NTP logical clock loop filter. Returns 1 if the * clock was stepped, 0 if it was slewed and -1 if it is hopeless. + * + * LOCKCLOCK: The only thing this routine does is set the + * sys_rootdispersion variable equal to the peer dispersion. */ int local_clock( @@ -208,14 +199,13 @@ local_clock( double epsil /* jittter (square s*s) */ ) { - double mu; /* interval since last update (s) */ + u_long mu; /* interval since last update (s) */ double oerror; /* previous error estimate */ double flladj; /* FLL frequency adjustment (ppm) */ double plladj; /* PLL frequency adjustment (ppm) */ double clock_frequency; /* clock frequency adjustment (ppm) */ double dtemp, etemp; /* double temps */ int retval; /* return value */ - int i; /* * If the loop is opened, monitor and record the offsets @@ -224,9 +214,14 @@ local_clock( #ifdef DEBUG if (debug) printf( - "local_clock: assocID %d off %.6f jit %.6f sta %d\n", + "local_clock: assocID %d offset %.9f jitter %.9f state %d\n", peer->associd, fp_offset, SQRT(epsil), state); #endif +#ifdef LOCKCLOCK + sys_rootdispersion = peer->rootdispersion; + return (0); + +#else /* LOCKCLOCK */ if (!ntp_enable) { record_loop_stats(fp_offset, drift_comp, SQRT(epsil), clock_stability, sys_poll); @@ -262,19 +257,16 @@ local_clock( * so the termination comments print directly to the console. */ if (mode_ntpdate) { - if (allow_step && fabs(fp_offset) > clock_max && - clock_max > 0) { + if (fabs(fp_offset) > clock_max && clock_max > 0) { step_systime(fp_offset); - NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) - msyslog(LOG_NOTICE, "time reset %.6f s", + msyslog(LOG_NOTICE, "time reset %+.6f s", fp_offset); - printf("ntpd: time reset %.6fs\n", fp_offset); + printf("ntpd: time set %+.6fs\n", fp_offset); } else { adj_systime(fp_offset); - NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) - msyslog(LOG_NOTICE, "time slew %.6f s", + msyslog(LOG_NOTICE, "time slew %+.6f s", fp_offset); - printf("ntpd: time slew %.6fs\n", fp_offset); + printf("ntpd: time slew %+.6fs\n", fp_offset); } record_loop_stats(fp_offset, drift_comp, SQRT(epsil), clock_stability, sys_poll); @@ -289,9 +281,12 @@ local_clock( * get here again. */ if (state == S_NSET) { - step_systime(fp_offset); - NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) - msyslog(LOG_NOTICE, "time set %.6f s", fp_offset); + if (fabs(fp_offset) > clock_max && clock_max > 0) { + step_systime(fp_offset); + msyslog(LOG_NOTICE, "time reset %+.6f s", + fp_offset); + reinit_timer(); + } rstclock(S_FREQ, peer->epoch, 0); return (1); } @@ -396,20 +391,12 @@ local_clock( * reset or shaken, but never stirred. */ default: - if (allow_step) { - step_systime(fp_offset); - NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) - msyslog(LOG_NOTICE, "time reset %.6f s", - fp_offset); - rstclock(S_TSET, peer->epoch, 0); - retval = 1; - } else { - NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) - msyslog(LOG_NOTICE, "time slew %.6f s", - fp_offset); - rstclock(S_FREQ, peer->epoch, - fp_offset); - } + step_systime(fp_offset); + msyslog(LOG_NOTICE, "time reset %+.6f s", + fp_offset); + reinit_timer(); + rstclock(S_TSET, peer->epoch, 0); + retval = 1; break; } } else { @@ -449,58 +436,52 @@ local_clock( /* * We come here in the normal case for linear phase and - * frequency adjustments. If the offset exceeds the - * previous time error estimate by CLOCK_SGATE and the - * interval since the last update is less than twice the - * poll interval, consider the update a popcorn spike - * and ignore it. + * frequency adjustments. 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.. */ default: allow_panic = FALSE; - if (fabs(fp_offset - last_offset) > - CLOCK_SGATE * oerror && mu < - ULOGTOD(sys_poll + 1)) { + dtemp = fabs(fp_offset - last_offset); +/* + if (dtemp > CLOCK_SGATE * oerror && mu < + (u_long) ULOGTOD(sys_poll + 1)) { #ifdef DEBUG if (debug) printf( "local_clock: popcorn %.6f %.6f\n", - fabs(fp_offset - - last_offset), CLOCK_SGATE * - oerror); + dtemp, oerror); #endif last_offset = fp_offset; return (0); } +*/ /* - * Compute the FLL and PLL frequency adjustments - * conditioned on intricate weighting factors. - * The gain factors depend on the poll interval - * and Allan intercept. For the FLL, the - * averaging interval is clamped to a minimum of - * 1024 s and the gain increased in stages from - * zero for poll intervals below half the Allan - * intercept to unity above twice the Allan - * intercept. For the PLL, the averaging - * interval is clamped not to exceed the poll - * interval. No gain factor is necessary, since - * the frequency steering above the Allan - * intercept is negligible. Particularly for the - * PLL, these measures allow oversampling, but - * not undersampling and insure stability even - * when the rules of fair engagement are broken. + * The FLL and PLL frequency gain constants + * depend on the poll interval and Allan + * intercept. The PLL constant is calculated + * throughout the poll interval range, but the + * update interval is clamped so as not to + * exceed the poll interval. The FLL gain is + * zero below one-half the Allan intercept and + * unity at MAXPOLL. It decreases as 1 / + * (MAXPOLL + 1 - poll interval) in a feeble + * effort to match the loop stiffness to the + * Allan wobble. Particularly for the PLL, these + * measures allow oversampling, but not + * undersampling and insure stability even when + * the rules of fair engagement are broken. */ - i = sys_poll - allan_xpt + 4; - if (i < 0) - i = 0; - else if (i > 6) - i = 6; - etemp = fll[i]; - dtemp = max(mu, ULOGTOD(allan_xpt)); - flladj = (fp_offset - clock_offset) * etemp / - (dtemp * CLOCK_FLL); - dtemp = ULOGTOD(SHIFT_PLL + 2 + sys_poll); - etemp = min(mu, ULOGTOD(sys_poll)); + if (ULOGTOD(sys_poll) > allan_xpt / 2) { + dtemp = NTP_MAXPOLL + 1 - sys_poll; + flladj = (fp_offset - clock_offset) / + (max(mu, allan_xpt) * dtemp); + } + etemp = min(mu, (u_long)ULOGTOD(sys_poll)); + dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll); plladj = fp_offset * etemp / (dtemp * dtemp); last_time = peer->epoch; last_offset = clock_offset = fp_offset; @@ -508,7 +489,7 @@ local_clock( } } -#if defined(KERNEL_PLL) +#ifdef KERNEL_PLL /* * This code segment works when clock adjustments are made using * precision time kernel support and the ntp_adjtime() system @@ -607,10 +588,17 @@ local_clock( */ if (ntp_adjtime(&ntv) == TIME_ERROR) { if (ntv.status != pll_status) - msyslog(LOG_ERR, - "kernel time discipline status change %x", + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_NOTICE, + "kernel time sync disabled %04x", ntv.status); ntv.status &= ~(STA_PPSFREQ | STA_PPSTIME); + } else { + if (ntv.status != pll_status) + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_NOTICE, + "kernel time sync enabled %04x", + ntv.status); } pll_status = ntv.status; if (pll_nano) @@ -640,15 +628,23 @@ local_clock( * drift_comp is a sham and used only for updating the drift * file and for billboard eye candy. */ - etemp = clock_frequency + flladj + plladj; - drift_comp += etemp; - if (drift_comp > NTP_MAXFREQ) + dtemp = clock_frequency + flladj + plladj; + etemp = drift_comp + dtemp; + if (etemp > NTP_MAXFREQ) drift_comp = NTP_MAXFREQ; - else if (drift_comp <= -NTP_MAXFREQ) + else if (etemp <= -NTP_MAXFREQ) drift_comp = -NTP_MAXFREQ; - dtemp = SQUARE(clock_stability); - etemp = SQUARE(etemp) - dtemp; - clock_stability = SQRT(dtemp + etemp / CLOCK_AVG); + else + drift_comp = etemp; + if (fabs(etemp) > NTP_MAXFREQ) + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_NOTICE, + "frequency error %.0f PPM exceeds tolerance %.0f PPM", + etemp * 1e6, NTP_MAXFREQ * 1e6); + + etemp = SQUARE(clock_stability); + dtemp = SQUARE(dtemp); + clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG); /* * In SYNC state, adjust the poll interval. The trick here is to @@ -660,7 +656,7 @@ local_clock( * helps calm the dance. Works best using burst mode. */ if (state == S_SYNC) { - if (sys_jitter / ULOGTOD(sys_poll) > clock_stability && + if (sys_jitter > ULOGTOD(sys_poll) * clock_stability && fabs(clock_offset) < CLOCK_PGATE * sys_jitter) { tc_counter += sys_poll; if (tc_counter > CLOCK_LIMIT) { @@ -685,33 +681,38 @@ local_clock( /* * Update the system time variables. */ - dtemp = peer->disp + sys_jitter; - if ((peer->flags & FLAG_REFCLOCK) == 0 && dtemp < MINDISPERSE) + dtemp = peer->disp + (current_time - peer->epoch) * clock_phi + + sys_jitter + fabs(last_offset); + if (!(peer->flags & FLAG_REFCLOCK) && dtemp < MINDISPERSE) dtemp = MINDISPERSE; sys_rootdispersion = peer->rootdispersion + dtemp; record_loop_stats(last_offset, drift_comp, sys_jitter, clock_stability, sys_poll); + #ifdef DEBUG if (debug) printf( - "local_clock: mu %.0f noi %.3f stb %.3f pol %d cnt %d\n", - mu, sys_jitter * 1e6, clock_stability * 1e6, sys_poll, + "local_clock: mu %lu rootjit %.6f stab %.3f poll %d count %d\n", + mu, dtemp, clock_stability * 1e6, sys_poll, tc_counter); #endif /* DEBUG */ return (retval); +#endif /* LOCKCLOCK */ } /* * 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. */ void adj_host_clock( void ) { - double adjustment; - int i; + double adjustment; /* * Update the dispersion since the last update. In contrast to @@ -725,24 +726,23 @@ adj_host_clock( */ sys_rootdispersion += clock_phi; +#ifndef LOCKCLOCK /* * Declare PPS kernel unsync if the pps signal has not been * heard for a few minutes. */ if (pps_control && current_time - pps_control > PPS_MAXAGE) { if (pps_control) - NLOG(NLOG_SYSEVENT) /* conditional if clause */ - msyslog(LOG_INFO, "pps sync disabled"); + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_NOTICE, "pps sync disabled"); pps_control = 0; } - if (!ntp_enable) - return; /* - * If the phase-lock loop is implemented in the kernel, we - * have no business going further. + * If NTP is disabled or ntpdate mode enabled or the kernel + * discipline enabled, we have no business going further. */ - if (pll_control && kern_enable) + if (!ntp_enable || mode_ntpdate || (pll_control && kern_enable)) return; /* @@ -759,19 +759,13 @@ adj_host_clock( } /* - * This ugly bit of business is necessary in order to move the - * pole frequency higher in FLL mode. This is necessary for loop - * stability. + * Implement the phase and frequency adjustments. Note the + * black art formerly practiced here has been whitewashed. */ - i = sys_poll - allan_xpt + 4; - if (i < 0) - i = 0; - else if (i > 6) - i = 6; - adjustment = clock_offset / (pll[i] * ULOGTOD(SHIFT_PLL + - sys_poll)); + adjustment = clock_offset / (CLOCK_PLL * ULOGTOD(sys_poll)); clock_offset -= adjustment; adj_systime(adjustment + drift_comp); +#endif /* LOCKCLOCK */ } @@ -781,7 +775,7 @@ adj_host_clock( static void rstclock( int trans, /* new state */ - double epoch, /* last time */ + u_long epoch, /* last time */ double offset /* last offset */ ) { @@ -790,6 +784,11 @@ rstclock( state = trans; last_time = epoch; last_offset = clock_offset = offset; +#ifdef DEBUG + if (debug) + printf("local_clock: at %lu state %d\n", last_time, + trans); +#endif } @@ -815,6 +814,8 @@ huffpuff() /* * loop_config - configure the loop filter + * + * LOCKCLOCK: The LOOP_DRIFTINIT and LOOP_DRIFTCOMP cases are no-ops. */ void loop_config( @@ -828,6 +829,7 @@ loop_config( case LOOP_DRIFTINIT: +#ifndef LOCKCLOCK #ifdef KERNEL_PLL /* * Assume the kernel supports the ntp_adjtime() syscall. @@ -836,7 +838,15 @@ loop_config( * behind. While at it, ask to set nanosecond mode. If * the kernel agrees, rejoice; othewise, it does only * microseconds. + * + * Call out the safety patrol. If ntpdate mode or if the + * step threshold has been changed by the -x option or + * tinker command, kernel discipline is unsafe, so don't + * do any of this stuff. */ + if (mode_ntpdate || clock_max != CLOCK_MAX) + break; + pll_control = 1; memset(&ntv, 0, sizeof(ntv)); #ifdef STA_NANO @@ -879,27 +889,31 @@ loop_config( if (pll_status & STA_CLK) ext_enable = 1; #endif /* STA_NANO */ - msyslog(LOG_NOTICE, - "kernel time discipline status %04x", + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_INFO, + "kernel time sync status %04x", pll_status); } #endif /* KERNEL_PLL */ +#endif /* LOCKCLOCK */ break; case LOOP_DRIFTCOMP: +#ifndef LOCKCLOCK /* - * Initialize the kernel frequency and clamp to - * reasonable value. Also set the initial state to - * S_FSET to indicated the frequency has been - * initialized from the previously saved drift file. + * 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. */ - rstclock(S_FSET, current_time, 0); - drift_comp = freq; - if (drift_comp > NTP_MAXFREQ) - drift_comp = NTP_MAXFREQ; - if (drift_comp < -NTP_MAXFREQ) - drift_comp = -NTP_MAXFREQ; + if (freq <= NTP_MAXFREQ && freq >= -NTP_MAXFREQ) { + drift_comp = freq; + rstclock(S_FSET, current_time, 0); + } else { + drift_comp = 0; + } #ifdef KERNEL_PLL /* @@ -921,6 +935,7 @@ loop_config( (void)ntp_adjtime(&ntv); } #endif /* KERNEL_PLL */ +#endif /* LOCKCLOCK */ break; /* @@ -930,7 +945,7 @@ loop_config( clock_max = freq; break; - case LOOP_PANIC: /* panic exit threshold */ + case LOOP_PANIC: /* panic threshold */ clock_panic = freq; break; @@ -942,16 +957,8 @@ loop_config( clock_minstep = freq; break; - case LOOP_MINPOLL: /* ephemeral association poll */ - if (freq < NTP_MINPOLL) - freq = NTP_MINPOLL; - sys_minpoll = (u_char)freq; - break; - - case LOOP_ALLAN: /* minimum Allan intercept */ - if (freq < CLOCK_ALLAN) - freq = CLOCK_ALLAN; - allan_xpt = (u_char)freq; + case LOOP_ALLAN: /* Allan intercept */ + allan_xpt = freq; break; case LOOP_HUFFPUFF: /* huff-n'-puff filter length */ @@ -964,6 +971,11 @@ loop_config( sys_huffpuff[i] = 1e9; sys_mindly = 1e9; break; + + case LOOP_FREQ: /* initial frequency */ + drift_comp = freq / 1e6; + rstclock(S_FSET, current_time, 0); + break; } } diff --git a/contrib/ntp/ntpd/ntp_monitor.c b/contrib/ntp/ntpd/ntp_monitor.c index 8526aac..6b288fc 100644 --- a/contrib/ntp/ntpd/ntp_monitor.c +++ b/contrib/ntp/ntpd/ntp_monitor.c @@ -1,7 +1,6 @@ /* - * ntp_monitor.c - monitor who is using the ntpd server + * ntp_monitor - monitor ntpd statistics */ - #ifdef HAVE_CONFIG_H # include #endif @@ -18,30 +17,29 @@ #endif /* - * I'm still not sure I like what I've done here. It certainly consumes + * 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. * - * 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. + * 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 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. + * 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 + * 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. * - * Memory is usually allocated by grabbing a big chunk of new memory - * and cutting it up into littler pieces. The exception to this when we - * hit the memory limit. Then we free memory by grabbing entries off - * the tail for the MRU list, unlinking from the hash table, and + * Memory is usually allocated by grabbing a big chunk of new memory and + * cutting it up into littler pieces. The exception to this when we hit + * the memory limit. Then we free memory by grabbing entries off the + * 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 @@ -62,31 +60,31 @@ */ #define MON_HASH_SIZE 128 #define MON_HASH_MASK (MON_HASH_SIZE-1) -#define MON_HASH(addr) ((int)(ntohl((addr)) & MON_HASH_MASK)) +#define MON_HASH(addr) sock_hash(addr) /* * 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. + * for the hash and count tables is only allocated if monitoring is + * turned on. */ -static struct mon_data *mon_hash[MON_HASH_SIZE]; /* array of list ptrs */ -struct mon_data mon_mru_list; -struct mon_data mon_fifo_list; +static struct mon_data *mon_hash[MON_HASH_SIZE]; /* list ptrs */ +struct mon_data mon_mru_list; + /* * List of free structures structures, and counters of free and total * structures. The free structures are linked with the hash_next field. */ -static struct mon_data *mon_free; /* the free list or null if none */ - -static int mon_total_mem; /* total number of structures allocated */ -static int mon_mem_increments; /* number of times we've called malloc() */ +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() */ /* * 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; +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 *)); @@ -106,9 +104,8 @@ init_mon(void) mon_total_mem = 0; mon_mem_increments = 0; mon_free = NULL; - memset((char *)&mon_hash[0], 0, sizeof mon_hash); - memset((char *)&mon_mru_list, 0, sizeof mon_mru_list); - memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list); + memset(&mon_hash[0], 0, sizeof mon_hash); + memset(&mon_mru_list, 0, sizeof mon_mru_list); } @@ -126,7 +123,7 @@ mon_start( return; } if (mode == MON_OFF) - return; /* Ooops.. */ + return; if (!mon_have_memory) { mon_total_mem = 0; @@ -138,10 +135,6 @@ mon_start( mon_mru_list.mru_next = &mon_mru_list; mon_mru_list.mru_prev = &mon_mru_list; - - mon_fifo_list.fifo_next = &mon_fifo_list; - mon_fifo_list.fifo_prev = &mon_fifo_list; - mon_enabled = mode; } @@ -182,9 +175,6 @@ mon_stop( mon_mru_list.mru_next = &mon_mru_list; mon_mru_list.mru_prev = &mon_mru_list; - - mon_fifo_list.fifo_next = &mon_fifo_list; - mon_fifo_list.fifo_prev = &mon_fifo_list; } @@ -198,31 +188,34 @@ ntp_monitor( { register struct pkt *pkt; register struct mon_data *md; - register u_long netnum; + struct sockaddr_storage addr; register int hash; register int mode; if (mon_enabled == MON_OFF) - return; + return; pkt = &rbufp->recv_pkt; - netnum = NSRCADR(&rbufp->recv_srcadr); - hash = MON_HASH(netnum); + memset(&addr, 0, sizeof(addr)); + memcpy(&addr, &(rbufp->recv_srcadr), sizeof(addr)); + hash = MON_HASH(&addr); mode = PKT_MODE(pkt->li_vn_mode); - md = mon_hash[hash]; while (md != NULL) { - if (md->rmtadr == netnum && - /* ?? md->interface == rbufp->dstadr && ?? */ - md->mode == (u_char)mode) { + + /* + * Match address only to conserve MRU size. + */ + if (SOCKCMP(&md->rmtadr, &addr)) { + md->drop_count = current_time - md->lasttime; md->lasttime = current_time; md->count++; - md->version = PKT_VERSION(pkt->li_vn_mode); md->rmtport = NSRCPORT(&rbufp->recv_srcadr); + md->mode = (u_char) mode; + md->version = PKT_VERSION(pkt->li_vn_mode); /* - * Shuffle him to the head of the - * mru list. What a crock. + * Shuffle to the head of the MRU list. */ md->mru_next->mru_prev = md->mru_prev; md->mru_prev->mru_next = md->mru_next; @@ -230,7 +223,6 @@ ntp_monitor( md->mru_prev = &mon_mru_list; mon_mru_list.mru_next->mru_prev = md; mon_mru_list.mru_next = md; - return; } md = md->hash_next; @@ -242,24 +234,21 @@ ntp_monitor( * or from the tail of the MRU list. */ if (mon_free == NULL && mon_total_mem >= MAXMONMEM) { + /* - * Get it from MRU list + * Preempt from the MRU list if old enough. */ md = mon_mru_list.mru_prev; + if (((u_long)RANDOM & 0xffffffff) / FRAC > + (double)(current_time - md->lasttime) / mon_age) + return; + md->mru_prev->mru_next = &mon_mru_list; mon_mru_list.mru_prev = md->mru_prev; - remove_from_hash(md); - - /* - * Get it from FIFO list - */ - md->fifo_prev->fifo_next = md->fifo_next; - md->fifo_next->fifo_prev = md->fifo_prev; - } else { - if (mon_free == NULL) /* if free list empty */ - mon_getmoremem(); /* then get more */ + if (mon_free == NULL) + mon_getmoremem(); md = mon_free; mon_free = md->hash_next; } @@ -267,36 +256,30 @@ ntp_monitor( /* * Got one, initialize it */ - md->lasttime = md->firsttime = current_time; - md->lastdrop = 0; + md->avg_interval = 0; + md->lasttime = current_time; md->count = 1; - md->rmtadr = netnum; + 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 = ((rbufp->dstadr->flags & INT_MULTICAST) && - rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd == - md->interface->bfd ? MDF_BCAST : MDF_UCAST; + md->cast_flags = (u_char)(((rbufp->dstadr->flags & INT_MULTICAST) && + rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd == + md->interface->bfd ? MDF_BCAST : MDF_UCAST); /* - * Drop him into front of the hash table. - * Also put him on top of the MRU list - * and at bottom of FIFO list + * 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; - - md->fifo_prev = mon_fifo_list.fifo_prev; - md->fifo_next = &mon_fifo_list; - mon_fifo_list.fifo_prev->fifo_next = md; - mon_fifo_list.fifo_prev = md; } @@ -310,10 +293,10 @@ mon_getmoremem(void) register int i; struct mon_data *freedata; /* 'old' free list (null) */ - md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data)); + 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++; @@ -323,7 +306,6 @@ mon_getmoremem(void) * md now points at the last. Link in the rest of the chain. */ md->hash_next = freedata; - mon_total_mem += MONMEMINC; mon_mem_increments++; } @@ -336,7 +318,7 @@ remove_from_hash( register int hash; register struct mon_data *md_prev; - hash = MON_HASH(md->rmtadr); + hash = MON_HASH(&md->rmtadr); if (mon_hash[hash] == md) { mon_hash[hash] = md->hash_next; } else { diff --git a/contrib/ntp/ntpd/ntp_peer.c b/contrib/ntp/ntpd/ntp_peer.c index b164181..cf8a600 100644 --- a/contrib/ntp/ntpd/ntp_peer.c +++ b/contrib/ntp/ntpd/ntp_peer.c @@ -10,9 +10,9 @@ #include "ntpd.h" #include "ntp_stdlib.h" -#ifdef AUTOKEY -#include "ntp_crypto.h" -#endif /* AUTOKEY */ +#ifdef OPENSSL +#include "openssl/rand.h" +#endif /* OPENSSL */ /* * Table of valid association combinations @@ -181,7 +181,7 @@ getmorepeermem(void) */ struct peer * findexistingpeer( - struct sockaddr_in *addr, + struct sockaddr_storage *addr, struct peer *start_peer, int mode ) @@ -198,7 +198,7 @@ findexistingpeer( peer = start_peer->next; while (peer != 0) { - if (NSRCADR(addr) == NSRCADR(&peer->srcadr) + if (SOCKCMP(addr, &peer->srcadr) && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) { if (mode == -1) return (peer); @@ -216,7 +216,7 @@ findexistingpeer( */ struct peer * findpeer( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *dstadr, int fd, int pkt_mode, @@ -228,11 +228,11 @@ findpeer( findpeer_calls++; hash = HASH_ADDR(srcadr); - for (peer = peer_hash[hash]; peer != 0; peer = peer->next) { - if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr) + for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) { + if (SOCKCMP(srcadr, &peer->srcadr) && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) { - /* + /* * if the association matching rules determine * that this is not a valid combination, then * look for the next valid peer association. @@ -312,7 +312,13 @@ clear_all(void) for (n = 0; n < HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; - peer_clear(peer); + if (peer->flags & FLAG_CONFIG) { + if (!(peer->cast_flags & (MDF_ACAST | + MDF_MCAST | MDF_BCAST))) + peer_clear(peer, "STEP"); + } else { + unpeer(peer); + } } } #ifdef DEBUG @@ -331,14 +337,26 @@ unpeer( ) { int hash; - - peer_associations--; +#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\n", peer_to_remove->associd, peer_associations); #endif - peer_clear(peer_to_remove); + peer_clear(peer_to_remove, "NULL"); hash = HASH_ADDR(&peer_to_remove->srcadr); peer_hash_count[hash]--; peer_demobilizations++; @@ -362,7 +380,7 @@ unpeer( if (peer == 0) { peer_hash_count[hash]++; msyslog(LOG_ERR, "peer struct for %s not in table!", - ntoa(&peer->srcadr)); + stoa(&peer->srcadr)); } else { peer->next = peer_to_remove->next; } @@ -386,7 +404,7 @@ unpeer( assoc_hash_count[hash]++; msyslog(LOG_ERR, "peer struct for %s not in association table!", - ntoa(&peer->srcadr)); + stoa(&peer->srcadr)); } else { peer->ass_next = peer_to_remove->ass_next; } @@ -394,6 +412,7 @@ unpeer( peer_to_remove->next = peer_free; peer_free = peer_to_remove; peer_free_count++; + peer_associations--; } @@ -402,7 +421,7 @@ unpeer( */ struct peer * peer_config( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *dstadr, int hmode, int version, @@ -415,7 +434,7 @@ peer_config( ) { register struct peer *peer; - u_int cast_flags; + u_char cast_flags; /* * First search from the beginning for an association with given @@ -440,22 +459,39 @@ peer_config( switch (hmode) { case MODE_BROADCAST: - if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) - cast_flags = MDF_MCAST; - else - cast_flags = MDF_BCAST; - break; + 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; + } case MODE_CLIENT: - if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) - cast_flags = MDF_ACAST; - else - cast_flags = MDF_UCAST; - break; + 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; + } default: cast_flags = MDF_UCAST; - break; } /* @@ -464,24 +500,26 @@ peer_config( */ if (peer != 0) { peer->hmode = (u_char)hmode; - peer->version = (u_char)version; - peer->minpoll = (u_char)minpoll; - peer->maxpoll = (u_char)maxpoll; - peer->hpoll = peer->kpoll = peer->minpoll; - peer->ppoll = peer->maxpoll; + 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->ttlmax = ttl; + 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. + * variables. If emulating ntpdate, force iburst. */ + if (mode_ntpdate) + flags |= FLAG_IBURST; peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, flags | FLAG_CONFIG, cast_flags, ttl, key); return (peer); @@ -493,20 +531,23 @@ peer_config( */ struct peer * newpeer( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *dstadr, int hmode, int version, int minpoll, int maxpoll, u_int flags, - u_int cast_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 */ /* * Allocate a new peer structure. Some dirt here, since some of @@ -521,6 +562,13 @@ newpeer( memset((char *)peer, 0, sizeof(struct peer)); /* + * Assign an association ID and increment the system variable. + */ + peer->associd = current_association_ID; + if (++current_association_ID == 0) + ++current_association_ID; + + /* * 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 @@ -530,9 +578,15 @@ newpeer( */ if (ISREFCLOCKADR(srcadr)) peer->dstadr = loopback_interface; - else if (cast_flags & MDF_BCLNT) + else if (cast_flags & (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) { peer->dstadr = findbcastinter(srcadr); - else if (dstadr != any_interface) + /* + * If it was a multicast packet, findbcastinter() may not + * find it, so try a little harder. + */ + if (peer->dstadr == ANY_INTERFACE_CHOOSE(srcadr)) + peer->dstadr = findinterface(srcadr); + } else if (dstadr != NULL && dstadr != ANY_INTERFACE_CHOOSE(srcadr)) peer->dstadr = dstadr; else peer->dstadr = findinterface(srcadr); @@ -541,23 +595,27 @@ newpeer( peer->version = (u_char)version; peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll); peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll); - peer->flags = flags | (key > NTP_MAXKEY ? FLAG_SKEY : 0); + peer->flags = flags; + if (key != 0) + peer->flags |= FLAG_AUTHENABLE; + if (key > NTP_MAXKEY) + peer->flags |= FLAG_SKEY; peer->cast_flags = cast_flags; - peer->ttlmax = ttl; + peer->ttl = (u_char)ttl; peer->keyid = key; peer->precision = sys_precision; - peer_clear(peer); + if (cast_flags & MDF_ACAST) + peer_clear(peer, "ACST"); + else if (cast_flags & MDF_MCAST) + peer_clear(peer, "MCST"); + else if (cast_flags & MDF_BCAST) + peer_clear(peer, "BCST"); + else + peer_clear(peer, "INIT"); if (mode_ntpdate) peer_ntpdate++; /* - * Assign an association ID and increment the system variable. - */ - peer->associd = current_association_ID; - if (++current_association_ID == 0) - ++current_association_ID; - - /* * Note time on statistics timers. */ peer->timereset = current_time; @@ -594,14 +652,25 @@ newpeer( 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); +#ifdef DEBUG + if (debug) + printf("peer: %s\n", statstr); +#endif + } +#endif /* OPENSSL */ #ifdef DEBUG if (debug) printf( - "newpeer: %s->%s mode %d vers %d poll %d %d flags %x %x ttl %d key %08x\n", - ntoa(&peer->dstadr->sin), ntoa(&peer->srcadr), + "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->ttlmax, peer->keyid); + peer->ttl, peer->keyid); #endif return (peer); } @@ -612,7 +681,7 @@ newpeer( */ int peer_unconfig( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *dstadr, int mode ) @@ -681,6 +750,7 @@ peer_reset( peer->oldpkt = 0; peer->seldisptoolarge = 0; peer->selbroken = 0; + peer->rank = 0; peer->timereset = current_time; } @@ -700,7 +770,7 @@ peer_all_reset(void) } -#ifdef AUTOKEY +#ifdef OPENSSL /* * expire_all - flush all crypto data and update timestamps. */ @@ -718,30 +788,29 @@ expire_all(void) * everything. Then, recompute and sign the agreement public * value, if present. */ + if (!crypto_flags) + return; for (n = 0; n < HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; - if (peer->cast_flags & MDF_ACAST) { - peer_clear(peer); -#ifdef AUTOKEY - } else { + if (!(peer->flags & FLAG_SKEY)) { + continue; + } else if (peer->cast_flags & MDF_ACAST) { + peer_clear(peer, "ACST"); + } else if (peer->hmode == MODE_ACTIVE || + peer->hmode == MODE_PASSIVE) { key_expire(peer); - peer->pcookie.tstamp = 0; -#endif /* AUTOKEY */ + peer->crypto &= ~(CRYPTO_FLAG_AUTO | + CRYPTO_FLAG_AGREE); } } } - sys_private = (u_int32)RANDOM & 0xffffffff; -#ifdef PUBKEY - crypto_agree(); -#endif /* PUBKEY */ -#ifdef DEBUG - if (debug) - printf("expire_all: at %lu\n", current_time); -#endif + RAND_bytes((u_char *)&sys_private, 4); + crypto_update(); + resetmanycast(); } -#endif /* AUTOKEY */ +#endif /* OPENSSL */ /* @@ -804,7 +873,7 @@ resetmanycast(void) peer->next) { if (peer->cast_flags & MDF_ACAST) { peer->ttl = 0; - poll_update(peer, peer->hpoll); + poll_update(peer, 0); } } } diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c index fc95016..451bc9a 100644 --- a/contrib/ntp/ntpd/ntp_proto.c +++ b/contrib/ntp/ntpd/ntp_proto.c @@ -1,5 +1,8 @@ /* * ntp_proto.c - NTP version 4 protocol machinery + * + * ATTENTION: Get approval from Dave Mills on all changes to this file! + * */ #ifdef HAVE_CONFIG_H #include @@ -10,7 +13,6 @@ #include "ntp_unixtime.h" #include "ntp_control.h" #include "ntp_string.h" -#include "ntp_crypto.h" #include @@ -32,45 +34,61 @@ s_char sys_precision; /* local clock precision */ double sys_rootdelay; /* roundtrip delay to primary source */ double sys_rootdispersion; /* dispersion to primary source */ u_int32 sys_refid; /* reference source for local clock */ +u_int32 sys_peer_refid; /* hashed refid of our current peer */ 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_peer; /* our current peer */ struct peer *sys_prefer; /* our cherished peer */ -#ifdef AUTOKEY +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 /* AUTOKEY */ +#endif /* OPENSSL */ /* * Nonspecified system state variables. */ -int sys_bclient; /* we set our time to broadcasts */ -double sys_bdelay; /* broadcast client default delay */ +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 u_long sys_authdly[2]; /* authentication delay shift reg */ static u_char leap_consensus; /* consensus of survivor leap bits */ -static double sys_selerr; /* select error (squares) */ +static double sys_selerr; /* select error (squares) */ static double sys_syserr; /* system error (squares) */ keyid_t sys_private; /* private value for session seed */ int sys_manycastserver; /* respond to manycast client pkts */ -u_int sys_survivors; /* truest of the truechimers */ int peer_ntpdate; /* active peers in ntpdate mode */ -#ifdef AUTOKEY +int sys_survivors; /* truest of the truechimers */ +#ifdef OPENSSL char *sys_hostname; /* gethostname() name */ -#endif /* AUTOKEY */ +#endif /* OPENSSL */ + +/* + * TOS and multicast mapping stuff + */ +int sys_floor = 1; /* cluster stratum floor */ +int sys_ceiling = STRATUM_UNSPEC; /* cluster stratum ceiling*/ +int sys_minsane = 1; /* minimum candidates */ +int sys_minclock = NTP_MINCLOCK; /* minimum survivors */ +int sys_cohort = 0; /* cohort switch */ +int sys_ttlmax; /* max ttl mapping vector index */ +u_char sys_ttl[MAX_TTL]; /* ttl mapping vector */ /* * Statistics counters */ -u_long sys_stattime; /* time when we started recording */ -u_long sys_badstratum; /* packets with invalid stratum */ -u_long sys_oldversionpkt; /* old version packets received */ -u_long sys_newversionpkt; /* new version packets received */ -u_long sys_unknownversion; /* don't know version packets */ -u_long sys_badlength; /* packets with bad length */ +u_long sys_stattime; /* time since reset */ +u_long sys_received; /* packets received */ u_long sys_processed; /* packets processed */ -u_long sys_badauth; /* packets dropped because of auth */ -u_long sys_limitrejected; /* pkts rejected due to client count per net */ +u_long sys_newversionpkt; /* current version */ +u_long sys_oldversionpkt; /* recent version */ +u_long sys_unknownversion; /* invalid version */ +u_long sys_restricted; /* access denied */ +u_long sys_badlength; /* bad length or format */ +u_long sys_badauth; /* bad authentication */ +u_long sys_limitrejected; /* rate exceeded */ static double root_distance P((struct peer *)); static double clock_combine P((struct peer **, int)); @@ -78,7 +96,7 @@ static void peer_xmit P((struct peer *)); static void fast_xmit P((struct recvbuf *, int, keyid_t, int)); static void clock_update P((void)); int default_get_precision P((void)); - +static int peer_unfit P((struct peer *)); /* * transmit - Transmit Procedure. See Section 3.4.2 of the @@ -89,180 +107,193 @@ transmit( struct peer *peer /* peer structure pointer */ ) { - int hpoll; + int hpoll; + + /* + * The polling state machine. There are two kinds of machines, + * those that never expect a reply (broadcast and manycast + * server modes) and those that do (all other modes). The dance + * is intricate... + */ hpoll = peer->hpoll; - if (peer->burst == 0) { - u_char oreach; + if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) { /* - * The polling state machine. There are two kinds of - * machines, those that never expect a reply (broadcast - * and manycast server modes) and those that do (all - * other modes). The dance is intricate... + * In broadcast mode the poll interval is fixed + * at minpoll. */ - if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) { + hpoll = peer->minpoll; + } else if (peer->cast_flags & MDF_ACAST) { - /* - * In broadcast mode the poll interval is fixed - * at minpoll and the ttl at ttlmax. - */ - hpoll = peer->minpoll; - peer->ttl = peer->ttlmax; -#ifdef AUTOKEY - } else if (peer->cast_flags & MDF_ACAST) { + /* + * In manycast mode we start with the minpoll interval + * and ttl. However, the actual poll interval is eight + * times the nominal poll interval shown here. If fewer + * than sys_minclock servers are found, the ttl is + * increased by one and we try again. If this continues + * to the max ttl, the poll interval is bumped by one + * and we try again. If at least sys_minclock servers + * are found, the poll interval increases with the + * system poll interval to the max and we continue + * indefinately. However, about once per day when the + * agreement parameters are refreshed, the manycast + * clients are reset and we start from the beginning. + * This is to catch and clamp the ttl to the lowest + * practical value and avoid knocking on spurious doors. + */ + if (sys_survivors < sys_minclock && peer->ttl < + sys_ttlmax) + peer->ttl++; + hpoll = sys_poll; + } else { - /* - * In manycast mode we start with the minpoll - * interval and ttl. However, the actual poll - * interval is eight times the nominal poll - * interval shown here. If fewer than three - * servers are found, the ttl is increased by - * one and we try again. If this continues to - * the max ttl, the poll interval is bumped by - * one and we try again. If at least three - * servers are found, the poll interval - * increases with the system poll interval to - * the max and we continue indefinately. - * However, about once per day when the - * agreement parameters are refreshed, the - * manycast clients are reset and we start from - * the beginning. This is to catch and clamp the - * ttl to the lowest practical value and avoid - * knocking on spurious doors. - */ - if (sys_survivors < NTP_MINCLOCK && peer->ttl < - peer->ttlmax) - peer->ttl++; - hpoll = sys_poll; -#endif /* AUTOKEY */ - } else { + /* + * For associations expecting a reply, the watchdog + * counter is bumped by one if the peer has not been + * heard since the previous poll. If the counter reaches + * the max, the poll interval is doubled and the peer is + * demobilized if not configured. + */ + peer->unreach++; + if (peer->unreach >= NTP_UNREACH) { + hpoll++; + if (peer->flags & FLAG_CONFIG) { - /* - * For associations expecting a reply, the - * watchdog counter is bumped by one if the peer - * has not been heard since the previous poll. - * If the counter reaches the max, the peer is - * demobilized if not configured and just - * cleared if it is, but in this case the poll - * interval is bumped by one. - */ - if (peer->unreach < NTP_UNREACH) { - peer->unreach++; - } else if (!(peer->flags & FLAG_CONFIG)) { + /* + * If nothing is likely to change in + * future, flash the access denied bit + * so we won't bother the dude again. + */ + if (memcmp((char *)&peer->refid, + "DENY", 4) == 0 || + memcmp((char *)&peer->refid, + "CRYP", 4) == 0) + peer->flash |= TEST4; + } else { unpeer(peer); - clock_select(); return; - - } else { - peer_clear(peer); - hpoll++; } } - oreach = peer->reach; - peer->reach <<= 1; - if (peer->reach == 0) { + if (peer->burst == 0) { + u_char oreach; - /* - * If this association has become unreachable, - * clear it and raise a trap. - */ - if (oreach != 0) { - report_event(EVNT_UNREACH, peer); - peer->timereachable = current_time; - if (!(peer->flags & FLAG_CONFIG)) { - unpeer(peer); + oreach = peer->reach; + peer->reach <<= 1; + peer->hyst *= HYST_TC; + if (peer->reach == 0) { + + /* + * If this association has become + * unreachable, clear it and raise a + * trap. + */ + if (oreach != 0) { + report_event(EVNT_UNREACH, + peer); + peer->timereachable = + current_time; + if (peer->flags & FLAG_CONFIG) { + peer_clear(peer, + "INIT"); + } else { + unpeer(peer); + return; + } + } + if (peer->flags & FLAG_IBURST) + peer->burst = NTP_BURST; + } else { + /* + * Here the peer is reachable. If it has + * not been heard for three consecutive + * polls, stuff the clock filter. Next, + * determine the poll interval. If the + * peer is unfit for synchronization, + * increase it by one; otherwise, use + * the system poll interval. + */ + if (!(peer->reach & 0x07)) { + clock_filter(peer, 0., 0., + MAXDISPERSE); clock_select(); - return; - } else { - peer_clear(peer); - hpoll = peer->minpoll; } + if (peer_unfit(peer)) + hpoll++; + else + hpoll = sys_poll; + if (peer->flags & FLAG_BURST) + peer->burst = NTP_BURST; } - if (peer->flags & FLAG_IBURST) - peer->burst = NTP_SHIFT; } else { /* - * Here the peer is reachable. If it has not - * been heard for three consecutive polls, stuff - * the clock filter. Next, determine the poll - * interval. If the peer is a synchronization - * candidate, use the system poll interval. If - * the peer is not sane, increase it by one. If - * the number of valid updates is not greater - * than half the register size, clamp it to the - * minimum. This is to quickly recover the time - * variables when a noisy peer shows life. + * Source rate control. If we are restrained, + * each burst consists of only one packet. */ - if (!(peer->reach & 0x07)) { - clock_filter(peer, 0., 0., MAXDISPERSE); - clock_select(); - } - if ((peer->stratum > 1 && peer->refid == - peer->dstadr->sin.sin_addr.s_addr) || - peer->stratum >= STRATUM_UNSPEC) - hpoll++; + if (memcmp((char *)&peer->refid, "RSTR", 4) == + 0) + peer->burst = 0; else - hpoll = sys_poll; - if (peer->flags & FLAG_BURST) - peer->burst = NTP_SHIFT; - } - } else { - peer->burst--; - if (peer->burst == 0) { - - /* - * 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->cast_flags & MDF_BCLNT) { - peer->hmode = MODE_BCLIENT; -#ifdef AUTOKEY - key_expire(peer); -#endif /* AUTOKEY */ - } - poll_update(peer, hpoll); - clock_select(); + peer->burst--; + if (peer->burst == 0) { + /* + * 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->cast_flags & MDF_BCLNT) { + peer->hmode = MODE_BCLIENT; +#ifdef OPENSSL + key_expire(peer); +#endif /* OPENSSL */ + } + poll_update(peer, hpoll); + clock_select(); - /* - * If ntpdate mode and the clock has not been - * set and all peers have completed the burst, - * we declare a successful failure. - */ - if (mode_ntpdate) { - peer_ntpdate--; - if (peer_ntpdate > 0) - return; - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "no reply; clock not set"); - printf( - "ntpd: no reply; clock not set\n"); - exit(0); + /* + * If ntpdate mode and the clock has not + * been set and all peers have completed + * the burst, we declare a successful + * failure. + */ + if (mode_ntpdate) { + peer_ntpdate--; + if (peer_ntpdate > 0) { + poll_update( + peer, hpoll); + return; + } + msyslog(LOG_NOTICE, + "no reply; clock not set"); + exit (0); + } + poll_update(peer, hpoll); + return; } - return; - } } peer->outdate = current_time; - poll_update(peer, hpoll); /* - * We need to be very careful about honking uncivilized time. - * Never transmit if in broadcast client mode or access denied. - * If in broadcast mode, transmit only if synchronized to a - * valid source. + * Do not transmit if in broadcast cclient mode or access has + * been denied. */ if (peer->hmode == MODE_BCLIENT || peer->flash & TEST4) { + poll_update(peer, hpoll); + return; + + /* + * Do not transmit in broadcast mode unless we are synchronized. + */ + } else if (peer->hmode == MODE_BROADCAST && sys_peer == NULL) { + poll_update(peer, hpoll); return; - } else if (peer->hmode == MODE_BROADCAST) { - if (sys_peer == NULL) - return; } peer_xmit(peer); + poll_update(peer, hpoll); } /* @@ -273,20 +304,24 @@ receive( struct recvbuf *rbufp ) { - register struct peer *peer; - register struct pkt *pkt; - int hismode; - int oflags; - int restrict_mask; - int has_mac; /* length of MAC field */ - int authlen; /* offset of MAC field */ - int is_authentic; /* cryptosum ok */ - keyid_t skeyid; /* cryptographic keys */ - struct sockaddr_in *dstadr_sin; /* active runway */ -#ifdef AUTOKEY - keyid_t pkeyid, tkeyid; /* cryptographic keys */ -#endif /* AUTOKEY */ - struct peer *peer2; + register struct peer *peer; /* peer structure pointer */ + register struct pkt *pkt; /* receive packet pointer */ + int hismode; /* packet mode */ + int restrict_mask; /* restrict bits */ + int has_mac; /* length of MAC field */ + int authlen; /* offset of MAC field */ + int is_authentic; /* cryptosum ok */ + keyid_t skeyid = 0; /* key ID */ + struct sockaddr_storage *dstadr_sin; /* active runway */ + struct peer *peer2; /* aux peer structure pointer */ + l_fp p_org; /* originate timestamp */ + l_fp p_xmt; /* transmit timestamp */ +#ifdef OPENSSL + keyid_t tkeyid = 0; /* temporary key ID */ + keyid_t pkeyid = 0; /* previous key ID */ + struct autokey *ap; /* autokey structure pointer */ + int rval; /* cookie snatcher */ +#endif /* OPENSSL */ int retcode = AM_NOMATCH; /* @@ -299,61 +334,103 @@ receive( * simply discarded without prejudice. Some restrictions have to * be handled later in order to generate a kiss-of-death packet. */ + /* + * Bogus port check is before anything, since it probably + * reveals a clogging attack. + */ + sys_received++; + if (SRCPORT(&rbufp->recv_srcadr) == 0) { + sys_badlength++; + return; /* bogus port */ + } ntp_monitor(rbufp); restrict_mask = restrictions(&rbufp->recv_srcadr); #ifdef DEBUG - if (debug > 2) - printf("receive: at %ld %s<-%s restrict %02x\n", - current_time, ntoa(&rbufp->dstadr->sin), - ntoa(&rbufp->recv_srcadr), restrict_mask); + if (debug > 1) + printf("receive: at %ld %s<-%s restrict %03x\n", + current_time, stoa(&rbufp->dstadr->sin), + stoa(&rbufp->recv_srcadr), restrict_mask); #endif - if (restrict_mask & RES_IGNORE) + if (restrict_mask & RES_IGNORE) { + sys_restricted++; return; /* no anything */ - - pkt = &rbufp->recv_pkt; - if (PKT_VERSION(pkt->li_vn_mode) == NTP_VERSION) { - sys_newversionpkt++; /* new version */ - } else if (!(restrict_mask & RES_VERSION) && - PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) { - sys_oldversionpkt++; /* old version */ - } else { - sys_unknownversion++; - return; /* invalid version */ } - if (PKT_MODE(pkt->li_vn_mode) == MODE_PRIVATE) { - if (restrict_mask & RES_NOQUERY) + pkt = &rbufp->recv_pkt; + hismode = (int)PKT_MODE(pkt->li_vn_mode); + if (hismode == MODE_PRIVATE) { + if (restrict_mask & RES_NOQUERY) { + sys_restricted++; return; /* no query private */ + } process_private(rbufp, ((restrict_mask & RES_NOMODIFY) == 0)); return; } - if (PKT_MODE(pkt->li_vn_mode) == MODE_CONTROL) { - if (restrict_mask & RES_NOQUERY) + if (hismode == MODE_CONTROL) { + if (restrict_mask & RES_NOQUERY) { + sys_restricted++; return; /* no query control */ + } process_control(rbufp, restrict_mask); return; } + if (restrict_mask & RES_DONTSERVE) { + sys_restricted++; + return; /* no time */ + } if (rbufp->recv_length < LEN_PKT_NOMAC) { sys_badlength++; return; /* runt packet */ } + + /* + * Version check must be after the query packets, since they + * intentionally use early version. + */ + if (PKT_VERSION(pkt->li_vn_mode) == NTP_VERSION) { + sys_newversionpkt++; /* new version */ + } else if (!(restrict_mask & RES_VERSION) && + PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) { + sys_oldversionpkt++; /* previous version */ + } else { + sys_unknownversion++; + return; /* old version */ + } /* - * Validate mode. Note that NTPv1 is no longer supported. + * Figure out his mode and validate the packet. This has some + * legacy raunch that probably should be removed. In very early + * NTP versions mode 0 was equivalent to what later versions + * would interpret as client mode. */ - hismode = (int)PKT_MODE(pkt->li_vn_mode); if (hismode == MODE_UNSPEC) { - sys_badlength++; - return; /* invalid mode */ + if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION) { + hismode = MODE_CLIENT; + } else { + sys_badlength++; + return; /* invalid mode */ + } } /* - * Discard broadcast packets received on the wildcard interface - * or if not enabled as broadcast client. + * Discard broadcast if not enabled as broadcast client. If + * Autokey, the wildcard interface cannot be used, so dump + * packets gettiing off the bus at that stop as well. This means + * that some systems with broken interface code, specifically + * Linux, will not work with Autokey. */ - if (PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST && - (rbufp->dstadr == any_interface || !sys_bclient)) - return; + if (hismode == MODE_BROADCAST) { + if (!sys_bclient || restrict_mask & RES_NOPEER) { + sys_restricted++; + return; /* no client */ + } +#ifdef OPENSSL + if (crypto_flags && rbufp->dstadr == any_interface) { + sys_restricted++; + return; /* no client */ + } +#endif /* OPENSSL */ + } /* * Parse the extension field if present. We figure out whether @@ -366,17 +443,14 @@ receive( * an extension field is present. If 2 or 4, the packet is a * runt and goes poof! with a brilliant flash. */ - skeyid = 0; -#ifdef AUTOKEY - pkeyid = tkeyid = 0; -#endif /* AUTOKEY */ authlen = LEN_PKT_NOMAC; - while ((has_mac = rbufp->recv_length - authlen) > 0) { + has_mac = rbufp->recv_length - authlen; + while (has_mac > 0) { int temp; if (has_mac % 4 != 0 || has_mac < 0) { sys_badlength++; - return; + return; /* bad MAC length */ } if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac == MAX_MAC_LEN) { @@ -386,23 +460,28 @@ receive( } else if (has_mac > MAX_MAC_LEN) { temp = ntohl(((u_int32 *)pkt)[authlen / 4]) & 0xffff; - if (temp < 4 || temp % 4 != 0) { + if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4 + != 0) { sys_badlength++; - return; + return; /* bad MAC length */ } authlen += temp; + has_mac -= temp; } else { sys_badlength++; - return; + return; /* bad MAC length */ } } +#ifdef OPENSSL + pkeyid = tkeyid = 0; +#endif /* OPENSSL */ /* * 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 or DES cycles, again to reduce exposure. There may be no + * MD5 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 @@ -424,11 +503,12 @@ receive( #ifdef DEBUG if (debug) printf("receive: at %ld %s<-%s mode %d code %d\n", - current_time, ntoa(&rbufp->dstadr->sin), - ntoa(&rbufp->recv_srcadr), hismode, retcode); + current_time, stoa(&rbufp->dstadr->sin), + stoa(&rbufp->recv_srcadr), hismode, + retcode); #endif } else { -#ifdef AUTOKEY +#ifdef OPENSSL /* * For autokey modes, generate the session key * and install in the key cache. Use the socket @@ -471,8 +551,7 @@ receive( * mobilized. */ pkeyid = 0; - if (rbufp->dstadr->bcast.sin_addr.s_addr - != 0) + if (!SOCKNUL(&rbufp->dstadr->bcast)) dstadr_sin = &rbufp->dstadr->bcast; } else if (peer == NULL) { @@ -480,7 +559,7 @@ receive( &rbufp->recv_srcadr, dstadr_sin, 0, sys_private, 0); } else { - pkeyid = peer->pcookie.key; + pkeyid = peer->pcookie; } /* @@ -503,29 +582,32 @@ receive( } } -#endif /* AUTOKEY */ +#endif /* OPENSSL */ /* * Compute the cryptosum. Note a clogging attack may * succeed in bloating the key cache. If an autokey, * purge it immediately, since we won't be needing it - * again. + * again. If the packet is authentic, it may mobilize an + * association. */ if (authdecrypt(skeyid, (u_int32 *)pkt, authlen, - has_mac)) + has_mac)) { is_authentic = 1; - else + restrict_mask &= ~RES_DONTTRUST; + } else { sys_badauth++; -#ifdef AUTOKEY + } +#ifdef OPENSSL if (skeyid > NTP_MAXKEY) authtrust(skeyid, 0); -#endif /* AUTOKEY */ +#endif /* OPENSSL */ #ifdef DEBUG if (debug) printf( "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n", - current_time, ntoa(dstadr_sin), - ntoa(&rbufp->recv_srcadr), hismode, retcode, + current_time, stoa(dstadr_sin), + stoa(&rbufp->recv_srcadr), hismode, retcode, skeyid, authlen, has_mac, is_authentic); #endif @@ -537,9 +619,10 @@ receive( * association is processed by that association. If not and * certain conditions prevail, then an ephemeral association is * mobilized: a broadcast packet mobilizes a broadcast client - * aassociation; a server packet mobilizes a client association; - * a symmetric active packet mobilizes a symmetric passive - * association. And, the adventure continues... + * aassociation; a manycast server packet mobilizes a manycast + * client association; a symmetric active packet mobilizes a + * symmetric passive association. And, the adventure + * continues... */ switch (retcode) { case AM_FXMIT: @@ -555,33 +638,29 @@ receive( INT_MULTICAST)) { /* - * We are picky about responding to a - * manycaster. There is no reason to respond to - * a request if our time is worse than the - * manycaster. We certainly don't reply if not - * synchronized to proventic time. + * There is no reason to respond to a request if + * our time is worse than the manycaster or it + * has already synchronized to us. */ - if (sys_peer == NULL) - return; - - /* - * We don't reply if the our stratum is greater - * than the manycaster. - */ - if (PKT_TO_STRATUM(pkt->stratum) < sys_stratum) - return; + if (sys_peer == NULL || + PKT_TO_STRATUM(pkt->stratum) < + sys_stratum || (sys_cohort && + PKT_TO_STRATUM(pkt->stratum) == + sys_stratum) || + rbufp->dstadr->addr_refid == pkt->refid) + return; /* manycast dropped */ } /* * Note that we don't require an authentication check * here, since we can't set the system clock; but, we do - * set the key ID to zero to tell the caller about this. + * send a crypto-NAK to tell the caller about this. */ - if (is_authentic) + if (has_mac && !is_authentic) + fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); + else fast_xmit(rbufp, MODE_SERVER, skeyid, restrict_mask); - else - fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); return; case AM_MANYCAST: @@ -594,100 +673,166 @@ receive( * there is no match, that's curious and could be an * intruder attempting to clog, so we just ignore it. * - * First, make sure the packet is authentic. If so and - * the manycast association is found, we mobilize a - * client mode association, copy pertinent variables - * from the manycast to the client mode association and - * wind up the spring. + * First, make sure the packet is authentic and not + * restricted. If so and the manycast association is + * found, we mobilize a client association and copy + * pertinent variables from the manycast association to + * the new client association. * * There is an implosion hazard at the manycast client, * since the manycast servers send the server packet - * immediately. + * immediately. If the guy is already here, don't fire + * up a duplicate. */ - if ((restrict_mask & (RES_DONTSERVE | RES_LIMITED | - RES_NOPEER)) || (sys_authenticate && - !is_authentic)) - return; + if (restrict_mask & RES_DONTTRUST) { + sys_restricted++; + return; /* no trust */ + } - peer2 = findmanycastpeer(rbufp); - if (peer2 == 0) - return; + if (sys_authenticate && !is_authentic) + return; /* bad auth */ + + if ((peer2 = findmanycastpeer(rbufp)) == NULL) + return; /* no assoc match */ - peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, + if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - sys_minpoll, NTP_MAXDPOLL, FLAG_IBURST | - (peer2->flags & (FLAG_AUTHENABLE | FLAG_SKEY)), - MDF_UCAST, 0, skeyid); - if (peer == NULL) - return; + NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_IBURST, MDF_UCAST | + MDF_ACLNT, 0, skeyid)) == NULL) + return; /* system error */ + + /* + * We don't need these, but it warms the billboards. + */ + peer->ttl = peer2->ttl; break; case AM_NEWPASS: /* * This is the first packet received from a symmetric - * active peer. First, make sure the packet is - * authentic. If so, mobilize a symmetric passive - * association. + * active peer. First, make sure it is authentic and not + * restricted. If so, mobilize a passive association. + * If authentication fails send a crypto-NAK; otherwise, + * kiss the frog. */ - if ((restrict_mask & (RES_DONTSERVE | RES_LIMITED | - RES_NOPEER)) || (sys_authenticate && - !is_authentic)) { + if (restrict_mask & RES_DONTTRUST) { + sys_restricted++; + return; /* no trust */ + } + if (sys_authenticate && !is_authentic) { fast_xmit(rbufp, MODE_PASSIVE, 0, restrict_mask); - return; + return; /* bad auth */ } - peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, + if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode), - sys_minpoll, NTP_MAXDPOLL, sys_authenticate ? - FLAG_AUTHENABLE : 0, MDF_UCAST, 0, skeyid); - if (peer == NULL) - return; + NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0, + skeyid)) == NULL) + return; /* system error */ + break; case AM_NEWBCL: /* * This is the first packet received from a broadcast - * server. First, make sure the packet is authentic, not - * restricted and that we are a broadcast or multicast - * client. If so, mobilize a broadcast client - * association. + * server. First, make sure it is authentic and not + * restricted and that we are a broadcast client. If so, + * mobilize a broadcast client association. We don't + * kiss any frogs here. */ - if ((restrict_mask & (RES_DONTSERVE | RES_LIMITED | - RES_NOPEER)) || (sys_authenticate && - !is_authentic) || !sys_bclient) - return; + if (restrict_mask & RES_DONTTRUST) { + sys_restricted++; + return; /* no trust */ + } + if (sys_authenticate && !is_authentic) + return; /* bad auth */ - peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, + if (!sys_bclient) + return; /* not a client */ + + if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - sys_minpoll, NTP_MAXDPOLL, FLAG_MCAST | - FLAG_IBURST | (sys_authenticate ? - FLAG_AUTHENABLE : 0), MDF_BCLNT, 0, skeyid); -#ifdef AUTOKEY -#ifdef PUBKEY - if (peer == NULL) - return; - if (peer->flags & FLAG_SKEY) - crypto_recv(peer, rbufp); -#endif /* PUBKEY */ -#endif /* AUTOKEY */ + NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST | + FLAG_IBURST, MDF_BCLNT, 0, skeyid)) == NULL) + return; /* system error */ +#ifdef OPENSSL + /* + * Danger looms. If this is autokey, go process the + * extension fields. If something goes wrong, abandon + * ship and don't trust subsequent packets. + */ + if (crypto_flags) { + if ((rval = crypto_recv(peer, rbufp)) != + XEVNT_OK) { + struct sockaddr_storage mskadr_sin; + + unpeer(peer); + sys_restricted++; + SET_HOSTMASK(&mskadr_sin, + rbufp->recv_srcadr.ss_family); + hack_restrict(RESTRICT_FLAGS, + &rbufp->recv_srcadr, &mskadr_sin, + 0, RES_DONTTRUST | RES_TIMEOUT); +#ifdef DEBUG + if (debug) + printf( + "packet: bad exten %x\n", + rval); +#endif + } + } +#endif /* OPENSSL */ return; case AM_POSSBCL: + + /* + * This is a broadcast packet received in client mode. + * It could happen if the initial client/server volley + * is not complete before the next broadcast packet is + * received. Be liberal in what we accept. + */ case AM_PROCPKT: /* - * Happiness and nothing broke. Earn some revenue. + * This is a symmetric mode packet received in symmetric + * mode, a server packet received in client mode or a + * broadcast packet received in broadcast client mode. + * If it is restricted, this is very strange because it + * is rude to send a packet to a restricted address. If + * anyway, flash a restrain kiss and skedaddle to + * Seattle. If not authentic, leave a light on and + * continue. */ + peer->flash = 0; + if (restrict_mask & RES_DONTTRUST) { + sys_restricted++; + if (peer->flags & FLAG_CONFIG) + peer_clear(peer, "RSTR"); + else + unpeer(peer); + return; /* no trust */ + } + if (has_mac && !is_authentic) + peer->flash |= TEST5; /* bad auth */ break; default: /* - * Invalid mode combination. Leave the island - * immediately. + * Invalid mode combination. This happens when a passive + * mode packet arrives and matches another passive + * association or no association at all, or when a + * server mode packet arrives and matches a broadcast + * client association. This is usually the result of + * reconfiguring a client on-fly. If authenticated + * passive mode packet, send a crypto-NAK; otherwise, + * ignore it. */ + if (has_mac && hismode == MODE_PASSIVE) + fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); #ifdef DEBUG if (debug) printf("receive: bad protocol %d\n", retcode); @@ -696,128 +841,242 @@ receive( } /* - * If the peer isn't configured, set his authenable and autokey - * status based on the packet. Once the status is set, it can't - * be unset. It seems like a silly idea to do this here, rather - * in the configuration routine, but in some goofy cases the - * first packet sent cannot be authenticated and we need a way - * for the dude to change his mind. + * We do a little homework. Note we can get here with an + * authentication error. We Need to do this in order to validate + * a crypto-NAK later. Note the order of processing; it is very + * important to avoid livelocks, deadlocks and lockpicks. */ - oflags = peer->flags; peer->timereceived = current_time; peer->received++; - if (!(peer->flags & FLAG_CONFIG) && has_mac) { - peer->flags |= FLAG_AUTHENABLE; -#ifdef AUTOKEY - if (skeyid > NTP_MAXKEY) - peer->flags |= FLAG_SKEY; -#endif /* AUTOKEY */ - } + if (peer->flash & TEST5) + peer->flags &= ~FLAG_AUTHENTIC; + else + peer->flags |= FLAG_AUTHENTIC; + NTOHL_FP(&pkt->org, &p_org); + NTOHL_FP(&pkt->xmt, &p_xmt); /* - * A valid packet must be from an authentic and allowed source. - * All packets must pass the authentication allowed tests. - * Autokey authenticated packets must pass additional tests and - * public-key authenticated packets must have the credentials - * verified. If all tests are passed, the packet is forwarded - * for processing. If not, the packet is discarded and the - * association demobilized if appropriate. + * If the packet is an old duplicate, we let it through so the + * extension fields will be processed. + */ + if (L_ISEQU(&peer->org, &p_xmt)) { /* test 1 */ + peer->flash |= TEST1; /* dupe */ + /* fall through */ + + /* + * For broadcast server mode, loopback checking is disabled. An + * authentication error probably means the server restarted or + * rolled a new private value. If so, dump the association + * and wait for the next message. + */ + } else if (hismode == MODE_BROADCAST) { + if (peer->flash & TEST5) { + unpeer(peer); + return; + } + /* fall through */ + + /* + * For server and symmetric modes, if the association transmit + * timestamp matches the packet originate timestamp, loopback is + * confirmed. Note in symmetric modes this also happens when the + * first packet from the active peer arrives at the newly + * mobilized passive peer. An authentication error probably + * means the server or peer restarted or rolled a new private + * value, but could be an intruder trying to stir up trouble. + * However, if this is a crypto-NAK, we know it is authentic, so + * dump the association and wait for the next message. + */ + } else if (L_ISEQU(&peer->xmt, &p_org)) { + if (peer->flash & TEST5) { + if (has_mac == 4 && pkt->exten[0] == 0) { + if (peer->flags & FLAG_CONFIG) + peer_clear(peer, "AUTH"); + else + unpeer(peer); + } + return; + } + /* fall through */ + + /* + * If the client or passive peer has never transmitted anything, + * this is either the first message from a symmetric peer or + * possibly a duplicate received before the transmit timeout. + * Pass it on. + */ + } else if (L_ISZERO(&peer->xmt)) { + /* fall through */ + + /* + * Now it gets interesting. We have transmitted at least one + * packet. If the packet originate timestamp is nonzero, it + * does not match the association transmit timestamp, which is a + * loopback error. This error might mean a manycast server has + * answered a manycast honk from us and we already have an + * association for him, in which case quietly drop the packet + * here. It might mean an old duplicate, dropped packet or + * intruder replay, in which case we drop it later after + * extension field processing, but never let it touch the time + * values. + */ + } else if (!L_ISZERO(&p_org)) { + if (peer->cast_flags & MDF_ACLNT) + return; /* not a client */ + + peer->flash |= TEST2; + /* fall through */ + + /* + * The packet originate timestamp is zero, meaning the other guy + * either didn't receive the first packet or died and restarted. + * If the association originate timestamp is zero, this is the + * first packet received, so we pass it on. + */ + } else if (L_ISZERO(&peer->org)) { + /* fall through */ + + /* + * The other guy has restarted and we are still on the wire. We + * should demobilize/clear and get out of Dodge. If this is + * symmetric mode, we should also send a crypto-NAK. */ - peer->flash = 0; - if (is_authentic) { - peer->flags |= FLAG_AUTHENTIC; } else { - peer->flags &= ~FLAG_AUTHENTIC; - } - if (peer->hmode == MODE_BROADCAST && - (restrict_mask & RES_DONTTRUST)) /* test 4 */ - peer->flash |= TEST4; /* access denied */ - if (peer->flags & FLAG_AUTHENABLE) { - if (!(peer->flags & FLAG_AUTHENTIC)) /* test 5 */ - peer->flash |= TEST5; /* auth failed */ - else if (!(oflags & FLAG_AUTHENABLE)) - report_event(EVNT_PEERAUTH, peer); - } - if (peer->flash) { -#ifdef DEBUG + if (hismode == MODE_ACTIVE) + fast_xmit(rbufp, MODE_PASSIVE, 0, + restrict_mask); + else if (hismode == MODE_PASSIVE) + fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); +#if DEBUG if (debug) - printf("receive: bad auth %03x\n", peer->flash); + printf("receive: dropped %03x\n", peer->flash); #endif + if (peer->flags & FLAG_CONFIG) + peer_clear(peer, "DROP"); + else + unpeer(peer); + return; + } + if (peer->flash & ~TEST2) { return; } -#ifdef AUTOKEY +#ifdef OPENSSL /* * More autokey dance. The rules of the cha-cha are as follows: * * 1. If there is no key or the key is not auto, do nothing. * - * 2. If an extension field contains a verified signature, it is + * 2. If this packet is in response to the one just previously + * sent or from a broadcast server, do the extension fields. + * Otherwise, assume bogosity and bail out. + * + * 3. If an extension field contains a verified signature, it is * self-authenticated and we sit the dance. * - * 3. If this is a server reply, check only to see that the + * 4. If this is a server reply, check only to see that the * transmitted key ID matches the received key ID. * - * 4. Check to see that one or more hashes of the current key ID + * 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. */ - if (peer->flags & FLAG_SKEY) { + if (crypto_flags && (peer->flags & FLAG_SKEY)) { peer->flash |= TEST10; - crypto_recv(peer, rbufp); - poll_update(peer, peer->hpoll); - if (hismode == MODE_SERVER) { + rval = crypto_recv(peer, rbufp); + if (rval != XEVNT_OK) { + /* fall through */ + + } else if (hismode == MODE_SERVER) { if (skeyid == peer->keyid) peer->flash &= ~TEST10; } else if (!peer->flash & TEST10) { peer->pkeyid = skeyid; - } else { + } else if ((ap = (struct autokey *)peer->recval.ptr) != + NULL) { int i; for (i = 0; ; i++) { if (tkeyid == peer->pkeyid || - tkeyid == peer->recauto.key) { + tkeyid == ap->key) { peer->flash &= ~TEST10; peer->pkeyid = skeyid; break; } - if (i > peer->recauto.seq) + if (i > ap->seq) break; tkeyid = session_key( &rbufp->recv_srcadr, dstadr_sin, tkeyid, pkeyid, 0); } } -#ifdef PUBKEY + if (!(peer->crypto & CRYPTO_FLAG_PROV)) /* test 11 */ + peer->flash |= TEST11; /* not proventic */ + + /* + * If the transmit queue is nonempty, clamp the host + * poll interval to the packet poll interval. + */ + if (peer->cmmd != 0) { + peer->ppoll = pkt->ppoll; + poll_update(peer, 0); + } /* - * This is delicious. Ordinarily, we kick out all errors - * at this point; however, in symmetric mode and just - * warming up, an unsynchronized peer must inject the - * timestamps, even if it fails further up the road. So, - * let the dude by here, but only if the jerk is not yet - * reachable. After that, he's on his own. + * If the return code from extension field processing is + * not okay, we scrub the association and start over. */ - if (!(peer->flags & FLAG_PROVEN)) - peer->flash |= TEST11; - if (peer->flash && peer->reach) { + if (rval != XEVNT_OK) { + + /* + * If the return code is bad, the crypto machine + * may be jammed or an intruder may lurk. First, + * we demobilize the association, then see if + * the error is recoverable. + */ + if (peer->flags & FLAG_CONFIG) + peer_clear(peer, "CRYP"); + else + unpeer(peer); #ifdef DEBUG if (debug) - printf("packet: bad autokey %03x\n", + printf("packet: bad exten %x\n", rval); +#endif + return; + } + + /* + * If TEST10 is lit, the autokey sequence has broken, + * which probably means the server has refreshed its + * private value. We reset the poll interval to the + & minimum and scrub the association clean. + */ + if (peer->flash & TEST10 && peer->crypto & + CRYPTO_FLAG_AUTO) { + poll_update(peer, peer->minpoll); +#ifdef DEBUG + if (debug) + printf( + "packet: bad auto %03x\n", peer->flash); #endif + if (peer->flags & FLAG_CONFIG) + peer_clear(peer, "AUTO"); + else + unpeer(peer); return; } -#endif /* PUBKEY */ } -#endif /* AUTOKEY */ +#endif /* OPENSSL */ /* * We have survived the gaunt. Forward to the packet routine. If * a symmetric passive association has been mobilized and the * association doesn't deserve to live, it will die in the - * transmit routine if not reachable after timeout. + * transmit routine if not reachable after timeout. However, if + * either symmetric mode and the crypto code has something + * urgent to say, we expedite the response. */ process_packet(peer, pkt, &rbufp->recv_time); } @@ -833,15 +1092,15 @@ void process_packet( register struct peer *peer, register struct pkt *pkt, - l_fp *recv_ts + l_fp *recv_ts ) { - l_fp t10, t23; - double p_offset, p_del, p_disp; - double dtemp; - l_fp p_rec, p_xmt, p_org, p_reftime; - l_fp ci; - int pmode, pleap, pstratum; + l_fp t34, t21; + double p_offset, p_del, p_disp; + double dtemp; + l_fp p_rec, p_xmt, p_org, p_reftime; + l_fp ci; + u_char pmode, pleap, pstratum; /* * Swap header fields and keep the books. The books amount to @@ -856,70 +1115,46 @@ process_packet( NTOHL_FP(&pkt->reftime, &p_reftime); NTOHL_FP(&pkt->rec, &p_rec); NTOHL_FP(&pkt->xmt, &p_xmt); - if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) + 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; + pstratum = PKT_TO_STRATUM(pkt->stratum); /* - * Test for old, duplicate or unsynch packets (tests 1-3). + * Test for unsynchronized server. */ - peer->rec = *recv_ts; - pmode = PKT_MODE(pkt->li_vn_mode); - pleap = PKT_LEAP(pkt->li_vn_mode); - pstratum = PKT_TO_STRATUM(pkt->stratum); if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */ peer->oldpkt++; - if (L_ISEQU(&peer->org, &p_xmt)) /* 1 */ - peer->flash |= TEST1; /* dupe */ - if (pmode != MODE_BROADCAST) { - if (!L_ISEQU(&peer->xmt, &p_org)) /* 2 */ - peer->flash |= TEST2; /* bogus */ - if (L_ISZERO(&p_rec) || L_ISZERO(&p_org)) /* test 3 */ - peer->flash |= TEST3; /* unsynch */ - } - if (L_ISZERO(&p_xmt)) /* 3 */ + if (pmode != MODE_BROADCAST && (L_ISZERO(&p_rec) || + L_ISZERO(&p_org))) /* test 3 */ + peer->flash |= TEST3; /* unsynch */ + if (L_ISZERO(&p_xmt)) /* test 3 */ peer->flash |= TEST3; /* unsynch */ - peer->org = p_xmt; /* - * If tests 1-3 fail, the packet is discarded leaving only the - * receive and origin timestamps and poll interval, which is - * enough to get the protocol started. + * If any tests fail, the packet is discarded leaving only the + * timestamps, which are enough to get the protocol started. The + * originate timestamp is copied from the packet transmit + * timestamp and the receive timestamp is copied from the + * packet receive timestamp. If okay so far, we save the leap, + * stratum and refid for billboards. */ + peer->org = p_xmt; + peer->rec = *recv_ts; if (peer->flash) { #ifdef DEBUG if (debug) - printf("packet: bad data %03x\n", - peer->flash); + printf("packet: bad data %03x from address: %s\n", + peer->flash, stoa(&peer->srcadr)); #endif return; } - - /* - * A kiss-of-death (kod) packet is returned by a server in case - * the client is denied access. It consists of the client - * request packet with the leap bits indicating never - * synchronized, stratum zero and reference ID field the ASCII - * string "DENY". If the packet originate timestamp matches the - * association transmit timestamp the kod is legitimate. If the - * peer leap bits indicate never synchronized, this must be - * access deny and the association is disabled; otherwise this - * must be a limit reject. In either case a naughty message is - * forced to the system log. - */ - if (pleap == LEAP_NOTINSYNC && pstratum >= STRATUM_UNSPEC && - memcmp(&pkt->refid, "DENY", 4) == 0) { - if (peer->leap == LEAP_NOTINSYNC) { - peer->stratum = STRATUM_UNSPEC; - peer->flash |= TEST4; - memcpy(&peer->refid, &pkt->refid, 4); - msyslog(LOG_INFO, "access denied"); - } else { - msyslog(LOG_INFO, "limit reject"); - } - return; - } + peer->leap = pleap; + peer->stratum = pstratum; + peer->refid = pkt->refid; /* * Test for valid peer data (tests 6-8) @@ -927,18 +1162,20 @@ process_packet( ci = p_xmt; L_SUB(&ci, &p_reftime); LFPTOD(&ci, dtemp); - if (pleap == LEAP_NOTINSYNC || /* 6 */ + if (pleap == LEAP_NOTINSYNC || /* test 6 */ pstratum >= STRATUM_UNSPEC || dtemp < 0) peer->flash |= TEST6; /* bad synch */ - if (!(peer->flags & FLAG_CONFIG) && sys_peer != NULL) { /* 7 */ - if (pstratum > sys_stratum && pmode != MODE_ACTIVE) { + if (!(peer->flags & FLAG_CONFIG) && sys_peer != NULL) { /* test 7 */ + if (pstratum > sys_stratum && pmode != MODE_ACTIVE) peer->flash |= TEST7; /* bad stratum */ - sys_badstratum++; - } } - if (p_del < 0 || p_disp < 0 || p_del / /* 8 */ + if (p_del < 0 || p_disp < 0 || p_del / /* test 8 */ 2 + p_disp >= MAXDISPERSE) - peer->flash |= TEST8; /* bad peer distance */ + peer->flash |= TEST8; /* bad peer values */ + + /* + * If any tests fail at this point, the packet is discarded. + */ if (peer->flash) { #ifdef DEBUG if (debug) @@ -954,14 +1191,11 @@ process_packet( */ record_raw_stats(&peer->srcadr, &peer->dstadr->sin, &p_org, &p_rec, &p_xmt, &peer->rec); - peer->leap = pleap; peer->pmode = pmode; - peer->stratum = pstratum; peer->ppoll = pkt->ppoll; peer->precision = pkt->precision; peer->rootdelay = p_del; peer->rootdispersion = p_disp; - peer->refid = pkt->refid; peer->reftime = p_reftime; if (!(peer->reach)) { report_event(EVNT_REACH, peer); @@ -969,7 +1203,7 @@ process_packet( } peer->reach |= 1; peer->unreach = 0; - poll_update(peer, peer->hpoll); + poll_update(peer, 0); /* * If running in a client/server association, calculate the @@ -980,16 +1214,16 @@ process_packet( * the system precision plus that due to the frequency error * since the originate time. * - * c = ((t2 - t3) + (t1 - t0)) / 2 - * d = (t2 - t3) - (t1 - t0) - * e = (org - rec) (seconds only) + * Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec: */ - t10 = p_xmt; /* compute t1 - t0 */ - L_SUB(&t10, &peer->rec); - t23 = p_rec; /* compute t2 - t3 */ - L_SUB(&t23, &p_org); - ci = t10; - p_disp = clock_phi * (peer->rec.l_ui - p_org.l_ui); + t34 = p_xmt; /* t3 - t4 */ + L_SUB(&t34, &peer->rec); + t21 = p_rec; /* t2 - t1 */ + L_SUB(&t21, &p_org); + ci = peer->rec; /* t4 - t1 */ + L_SUB(&ci, &p_org); + LFPTOD(&ci, p_disp); + p_disp = clock_phi * max(p_disp, LOGTOD(sys_precision)); /* * If running in a broadcast association, the clock offset is @@ -1000,6 +1234,7 @@ process_packet( * MODE_BCLIENT mode. The next broadcast message after that * computes the broadcast offset and clears FLAG_MCAST. */ + ci = t34; if (pmode == MODE_BROADCAST) { if (peer->flags & FLAG_MCAST) { LFPTOD(&ci, p_offset); @@ -1009,20 +1244,20 @@ process_packet( peer->flags &= ~FLAG_MCAST; } - DTOLFP(peer->estbdelay, &t10); - L_ADD(&ci, &t10); + DTOLFP(peer->estbdelay, &t34); + L_ADD(&ci, &t34); p_del = peer->delay; } else { - L_ADD(&ci, &t23); + L_ADD(&ci, &t21); /* (t2 - t1) + (t3 - t4) */ L_RSHIFT(&ci); - L_SUB(&t23, &t10); - LFPTOD(&t23, p_del); + L_SUB(&t21, &t34); /* (t2 - t1) - (t3 - t4) */ + LFPTOD(&t21, p_del); } p_del = max(p_del, LOGTOD(sys_precision)); LFPTOD(&ci, p_offset); if ((peer->rootdelay + p_del) / 2. + peer->rootdispersion + - p_disp >= MAXDISPERSE) /* 9 */ - peer->flash |= TEST9; /* bad peer distance */ + p_disp >= MAXDISPERSE) /* test 9 */ + peer->flash |= TEST9; /* bad root distance */ /* * If any flasher bits remain set at this point, abandon ship. @@ -1055,14 +1290,13 @@ clock_update(void) /* * Reset/adjust the system clock. Do this only if there is a - * system peer and we haven't seen that peer lately. Watch for - * timewarps here. + * system peer and the peer epoch is not older than the last + * update. */ if (sys_peer == NULL) return; - if (sys_peer->pollsw == FALSE || sys_peer->burst > 0) + if (sys_peer->epoch <= last_time) return; - sys_peer->pollsw = FALSE; #ifdef DEBUG if (debug) printf("clock_update: at %ld assoc %d \n", current_time, @@ -1076,8 +1310,8 @@ clock_update(void) * Clock is too screwed up. Just exit for now. */ case -1: - report_event(EVNT_SYSFAULT, (struct peer *)0); - exit(1); + report_event(EVNT_SYSFAULT, NULL); + exit (-1); /*NOTREACHED*/ /* @@ -1087,10 +1321,13 @@ clock_update(void) clear_all(); sys_peer = NULL; sys_stratum = STRATUM_UNSPEC; + memcpy(&sys_refid, "STEP", 4); sys_poll = NTP_MINPOLL; - NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, "synchronisation lost"); - report_event(EVNT_CLOCKRESET, (struct peer *)0); + report_event(EVNT_CLOCKRESET, NULL); +#ifdef OPENSSL + if (oleap != LEAP_NOTINSYNC) + expire_all(); +#endif /* OPENSSL */ break; /* @@ -1100,23 +1337,23 @@ clock_update(void) * changes, we gotta reroll the keys. */ default: - sys_stratum = sys_peer->stratum + 1; - if (sys_stratum == 1) + sys_stratum = (u_char) (sys_peer->stratum + 1); + if (sys_stratum == 1 || sys_stratum == STRATUM_UNSPEC) sys_refid = sys_peer->refid; else - sys_refid = sys_peer->srcadr.sin_addr.s_addr; + sys_refid = sys_peer_refid; sys_reftime = sys_peer->rec; sys_rootdelay = sys_peer->rootdelay + sys_peer->delay; sys_leap = leap_consensus; - } - if (oleap == LEAP_NOTINSYNC) { - report_event(EVNT_SYNCCHG, (struct peer *)0); -#ifdef AUTOKEY - expire_all(); -#endif /* AUTOKEY */ + if (oleap == LEAP_NOTINSYNC) { + report_event(EVNT_SYNCCHG, NULL); +#ifdef OPENSSL + expire_all(); +#endif /* OPENSSL */ + } } if (ostratum != sys_stratum) - report_event(EVNT_PEERSTCHG, (struct peer *)0); + report_event(EVNT_PEERSTCHG, NULL); } @@ -1126,12 +1363,12 @@ clock_update(void) void poll_update( struct peer *peer, - int hpoll + int hpoll ) { -#ifdef AUTOKEY - int oldpoll; -#endif /* AUTOKEY */ +#ifdef OPENSSL + int oldpoll; +#endif /* OPENSSL */ /* * A little foxtrot to determine what controls the poll @@ -1141,56 +1378,65 @@ poll_update( * association to ramp up the poll interval for useless sources * and to clamp it to the minimum when first starting up. */ -#ifdef AUTOKEY +#ifdef OPENSSL oldpoll = peer->kpoll; -#endif /* AUTOKEY */ - if (hpoll > peer->maxpoll) - peer->hpoll = peer->maxpoll; - else if (hpoll < peer->minpoll) - peer->hpoll = peer->minpoll; - else - peer->hpoll = hpoll; +#endif /* OPENSSL */ + if (hpoll > 0) { + if (hpoll > peer->maxpoll) + peer->hpoll = peer->maxpoll; + else if (hpoll < peer->minpoll) + peer->hpoll = peer->minpoll; + else + peer->hpoll = (u_char)hpoll; + } /* - * Bit of adventure here. If during a burst and not timeout, - * just slink away. If timeout, figure what the next timeout - * should be. If IBURST or a reference clock, use one second. If - * not and the dude was reachable during the previous poll - * interval, randomize over 1-4 seconds; otherwise, randomize - * over 15-18 seconds. This is to give time for a modem to - * complete the call, for example. If not during a burst, - * randomize over the poll interval -1 to +2 seconds. + * Bit of adventure here. If during a burst and not a poll, just + * slink away. If a poll, figure what the next poll should be. + * If a burst is pending and a reference clock or a pending + * crypto response, delay for one second. If the first sent in a + * burst, delay ten seconds for the modem to come up. For others + * in the burst, delay two seconds. * * In case of manycast server, make the poll interval, which is * axtually the manycast beacon interval, eight times the system * poll interval. Normally when the host poll interval settles - * up to 17.1 s, the beacon interval settles up to 2.3 hours. + * up to 1024 s, the beacon interval settles up to 2.3 hours. */ +#ifdef OPENSSL + if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC || + peer->crypto)) { + peer->nextdate = current_time + RESP_DELAY; + } else if (peer->burst > 0) { +#else /* OPENSSL */ if (peer->burst > 0) { - if (peer->nextdate != current_time) +#endif /* OPENSSL */ + if (hpoll == 0 && peer->nextdate != current_time) return; #ifdef REFCLOCK else if (peer->flags & FLAG_REFCLOCK) - peer->nextdate++; + peer->nextdate += RESP_DELAY; #endif - else if (peer->reach & 0x1) - peer->nextdate += RANDPOLL(BURST_INTERVAL2); + else if (peer->flags & (FLAG_IBURST | FLAG_BURST) && + peer->burst == NTP_BURST) + peer->nextdate += sys_calldelay; else - peer->nextdate += RANDPOLL(BURST_INTERVAL1); + peer->nextdate += BURST_DELAY; } else if (peer->cast_flags & MDF_ACAST) { - if (sys_survivors < NTP_MINCLOCK) - peer->kpoll = peer->hpoll; + if (sys_survivors >= sys_minclock || peer->ttl >= + sys_ttlmax) + peer->kpoll = (u_char) (peer->hpoll + 3); else - peer->kpoll = peer->hpoll + 3; + peer->kpoll = peer->hpoll; peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); } else { - peer->kpoll = max(min(peer->ppoll, peer->hpoll), - peer->minpoll); + peer->kpoll = (u_char) max(min(peer->ppoll, + peer->hpoll), peer->minpoll); peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); } if (peer->nextdate < current_time) peer->nextdate = current_time; -#ifdef AUTOKEY +#ifdef OPENSSL /* * Bit of crass arrogance at this point. If the poll interval * has changed and we have a keylist, the lifetimes in the @@ -1199,7 +1445,7 @@ poll_update( */ if (peer->kpoll != oldpoll) key_expire(peer); -#endif /* AUTOKEY */ +#endif /* OPENSSL */ #ifdef DEBUG if (debug > 1) printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n", @@ -1215,11 +1461,11 @@ poll_update( */ void peer_clear( - register struct peer *peer + struct peer *peer, /* peer structure */ + char *ident /* tally lights */ ) { - register int i; - u_long u_rand; + u_char oreach, i; /* * If cryptographic credentials have been acquired, toss them to @@ -1230,47 +1476,51 @@ peer_clear( * purged, too. This makes it much harder to sneak in some * unauthenticated data in the clock filter. */ -#ifdef DEBUG - if (debug) - printf("peer_clear: at %ld assoc ID %d\n", current_time, - peer->associd); -#endif -#ifdef AUTOKEY + oreach = peer->reach; +#ifdef OPENSSL key_expire(peer); -#ifdef PUBKEY - if (peer->keystr != NULL) - free(peer->keystr); - if (peer->pubkey.ptr != NULL) - free(peer->pubkey.ptr); - if (peer->certif.ptr != NULL) - free(peer->certif.ptr); -#endif /* PUBKEY */ -#endif /* AUTOKEY */ - memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); + if (peer->pkey != NULL) + EVP_PKEY_free(peer->pkey); + if (peer->ident_pkey != NULL) + EVP_PKEY_free(peer->ident_pkey); + if (peer->subject != NULL) + free(peer->subject); + if (peer->issuer != NULL) + free(peer->issuer); + if (peer->iffval != NULL) + BN_free(peer->iffval); + if (peer->grpkey != NULL) + BN_free(peer->grpkey); + if (peer->cmmd != NULL) + free(peer->cmmd); + value_free(&peer->cookval); + value_free(&peer->recval); + value_free(&peer->tai_leap); + value_free(&peer->encrypt); + value_free(&peer->sndval); +#endif /* OPENSSL */ /* - * If he dies as a broadcast client, he comes back to life as - * a broadcast client in client mode in order to recover the - * initial autokey values. Note that there is no need to call - * clock_select(), since the perp has already been voted off - * the island at this point. + * Wipe the association clean and initialize the nonzero values. */ - if (peer->cast_flags & MDF_BCLNT) { - peer->flags |= FLAG_MCAST; - peer->hmode = MODE_CLIENT; - } - peer->flags &= ~(FLAG_AUTOKEY | FLAG_ASSOC); + memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); + if (peer == sys_peer) + sys_peer = NULL; peer->estbdelay = sys_bdelay; peer->hpoll = peer->kpoll = peer->minpoll; peer->ppoll = peer->maxpoll; - peer->pollsw = FALSE; peer->jitter = MAXDISPERSE; peer->epoch = current_time; #ifdef REFCLOCK if (!(peer->flags & FLAG_REFCLOCK)) { peer->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM_UNSPEC; + memcpy(&peer->refid, ident, 4); } +#else + peer->leap = LEAP_NOTINSYNC; + peer->stratum = STRATUM_UNSPEC; + memcpy(&peer->refid, ident, 4); #endif for (i = 0; i < NTP_SHIFT; i++) { peer->filter_order[i] = i; @@ -1279,12 +1529,35 @@ peer_clear( } /* - * Randomize the first poll over 1-16s to avoid bunching. + * If he dies as a broadcast client, he comes back to life as + * a broadcast client in client mode in order to recover the + * initial autokey values. */ - peer->update = peer->outdate = current_time; - u_rand = RANDOM; - peer->nextdate = current_time + (u_rand & ((1 << - BURST_INTERVAL1) - 1)) + 1; + if (peer->cast_flags & MDF_BCLNT) { + peer->flags |= FLAG_MCAST; + peer->hmode = MODE_CLIENT; + } + + /* + * Randomize the first poll to avoid bunching, but only if the + * rascal has never been heard. During initialization use the + * association count to spread out the polls at one-second + * intervals. + */ + peer->nextdate = peer->update = peer->outdate = current_time; + peer->burst = 0; + if (oreach) + poll_update(peer, 0); + else if (initializing) + peer->nextdate = current_time + peer_associations; + else + peer->nextdate = current_time + (u_int)RANDOM % + peer_associations; +#ifdef DEBUG + if (debug) + printf("peer_clear: at %ld assoc ID %d refid %s\n", + current_time, peer->associd, ident); +#endif } @@ -1294,16 +1567,16 @@ peer_clear( */ void clock_filter( - register struct peer *peer, /* peer structure pointer */ - double sample_offset, /* clock offset */ - double sample_delay, /* roundtrip delay */ - double sample_disp /* dispersion */ + struct peer *peer, /* peer structure pointer */ + double sample_offset, /* clock offset */ + double sample_delay, /* roundtrip delay */ + double sample_disp /* dispersion */ ) { - double dst[NTP_SHIFT]; /* distance vector */ - int ord[NTP_SHIFT]; /* index vector */ - register int i, j, k, m; - double dsp, jit, dtemp, etemp; + double dst[NTP_SHIFT]; /* distance vector */ + int ord[NTP_SHIFT]; /* index vector */ + int i, j, k, m; + double dsp, jit, dtemp, etemp; /* * Shift the new sample into the register and discard the oldest @@ -1320,9 +1593,8 @@ clock_filter( peer->filter_offset[j] = sample_offset; peer->filter_delay[j] = max(0, sample_delay); peer->filter_disp[j] = dsp; - peer->filter_epoch[j] = current_time; - j++; j %=NTP_SHIFT; - peer->filter_nextpt = j; + j++; j %= NTP_SHIFT; + peer->filter_nextpt = (u_short) j; /* * Update dispersions since the last update and at the same @@ -1334,21 +1606,21 @@ clock_filter( dtemp = clock_phi * (current_time - peer->update); peer->update = current_time; for (i = NTP_SHIFT - 1; i >= 0; i--) { - if (i != 0) { + if (i != 0) peer->filter_disp[j] += dtemp; - if (peer->filter_disp[j] > MAXDISPERSE) - 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] = MAXDISTANCE + peer->filter_disp[j]; else - dst[i] = peer->filter_delay[j]; + dst[i] = peer->filter_delay[j]; ord[i] = j; j++; j %= NTP_SHIFT; } + peer->filter_epoch[j] = current_time; /* * Sort the samples in both lists by distance. @@ -1374,7 +1646,7 @@ clock_filter( */ m = 0; for (i = 0; i < NTP_SHIFT; i++) { - peer->filter_order[i] = ord[i]; + peer->filter_order[i] = (u_char) ord[i]; if (dst[i] >= MAXDISPERSE || (m >= 2 && dst[i] >= MAXDISTANCE)) continue; @@ -1387,8 +1659,7 @@ clock_filter( * normalized close to 1.0. The jitter is the mean of the square * differences relative to the lowest delay sample. If no * acceptable samples remain in the shift register, quietly - * tiptoe home leaving only the - * dispersion. + * tiptoe home leaving only the dispersion. */ jit = 0; peer->disp = 0; @@ -1411,7 +1682,8 @@ clock_filter( */ if (m == 0) return; - etemp = peer->offset; + etemp = fabs(peer->offset - peer->filter_offset[k]); + dtemp = sqrt(peer->jitter); peer->offset = peer->filter_offset[k]; peer->delay = peer->filter_delay[k]; if (m > 1) @@ -1420,9 +1692,10 @@ clock_filter( /* * A new sample is useful only if it is younger than the last - * one used. + * one used, but only if the sucker has been synchronized. */ - if (peer->filter_epoch[k] <= peer->epoch) { + if (peer->filter_epoch[k] <= peer->epoch && sys_leap != + LEAP_NOTINSYNC) { #ifdef DEBUG if (debug) printf("clock_filter: discard %lu\n", @@ -1433,27 +1706,26 @@ clock_filter( /* * If the difference between the last offset and the current one - * exceeds the jitter by CLOCK_SGATE (4) and the interval since - * the last update is less than twice the system poll interval, + * 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. */ - if (m > 1 && fabs(peer->offset - etemp) > SQRT(peer->jitter) * - CLOCK_SGATE && peer->filter_epoch[k] - peer->epoch < - (1 << (sys_poll + 1))) { + if (m > 1 && etemp > CLOCK_SGATE * dtemp && + (long)(peer->filter_epoch[k] - peer->epoch) < (1 << (sys_poll + + 1))) { #ifdef DEBUG if (debug) - printf("clock_filter: n %d popcorn spike %.6f jitter %.6f\n", - m, peer->offset, SQRT(peer->jitter)); + printf("clock_filter: popcorn %.6f %.6f\n", + etemp, dtemp); #endif return; } /* * The mitigated sample statistics are saved for later - * processing, but can be processed only once. + * processing. */ peer->epoch = peer->filter_epoch[k]; - peer->pollsw = TRUE; #ifdef DEBUG if (debug) printf( @@ -1466,17 +1738,23 @@ 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. */ void clock_select(void) { - register struct peer *peer; - int i, j, k, n; - int nreach, nlist, nl3; - double d, e, f; - int allow, found, sw; - double high, low; - double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; + struct peer *peer; + int i, j, k, n; + int nlist, nl3; + + double d, e, f; + int allow, sw, osurv; + double high, low; + double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; struct peer *osys_peer; struct peer *typeacts = NULL; struct peer *typelocal = NULL; @@ -1497,10 +1775,15 @@ clock_select(void) */ osys_peer = sys_peer; sys_peer = NULL; + osurv = sys_survivors; + sys_survivors = 0; sys_prefer = NULL; - nreach = nlist = 0; - low = 1e9; - high = -1e9; +#ifdef LOCKCLOCK + sys_leap = LEAP_NOTINSYNC; + sys_stratum = STRATUM_UNSPEC; + memcpy(&sys_refid, "DOWN", 4); +#endif /* LOCKCLOCK */ + nlist = 0; for (n = 0; n < HASH_SIZE; n++) nlist += peer_hash_count[n]; if (nlist > list_alloc) { @@ -1515,9 +1798,9 @@ clock_select(void) 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); + endpoint = emalloc(endpoint_size); + indx = emalloc(indx_size); + peer_list = emalloc(peer_list_size); } /* @@ -1527,8 +1810,8 @@ clock_select(void) * the falsetickers are culled and put to sea. The truechimers * remaining are subject to repeated rounds where the most * unpopular at each round is kicked off. When the population - * has dwindled to NTP_MINCLOCK (3), the survivors split a - * million bucks and collectively crank the chimes. + * 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 < HASH_SIZE; n++) { @@ -1538,18 +1821,10 @@ clock_select(void) peer->status = CTL_PST_SEL_REJECT; /* - * A peer leaves the island immediately if - * unreachable, synchronized to us or suffers - * excessive root distance. Careful with the - * root distance, since the poll interval can - * increase to a day and a half. - */ - if (!peer->reach || (peer->stratum > 1 && - peer->refid == - peer->dstadr->sin.sin_addr.s_addr) || - peer->stratum >= STRATUM_UNSPEC || - (root_distance(peer) >= MAXDISTANCE + 2 * - clock_phi * ULOGTOD(sys_poll))) + * Leave the island immediately if the peer is + * unfit to synchronize. + */ + if (peer_unfit(peer)) continue; /* @@ -1561,13 +1836,18 @@ clock_select(void) */ if (peer->refclktype == REFCLK_LOCALCLOCK #if defined(VMS) && defined(VMS_LOCALUNIT) - /* wjm: local unit VMS_LOCALUNIT taken seriously */ - && REFCLOCKUNIT(&peer->srcadr) != VMS_LOCALUNIT + /* wjm: VMS_LOCALUNIT taken seriously */ + && REFCLOCKUNIT(&peer->srcadr) != + VMS_LOCALUNIT #endif /* VMS && VMS_LOCALUNIT */ ) { typelocal = peer; if (!(peer->flags & FLAG_PREFER)) continue; /* no local clock */ +#ifdef LOCKCLOCK + else + sys_prefer = peer; +#endif /* LOCKCLOCK */ } if (peer->sstclktype == CTL_SST_TS_TELEPHONE) { typeacts = peer; @@ -1580,7 +1860,6 @@ clock_select(void) * island, but does not yet have the immunity * idol. */ - nreach++; peer->status = CTL_PST_SEL_SANE; peer_list[nlist++] = peer; @@ -1601,7 +1880,7 @@ clock_select(void) endpoint[nl3++].val = e; e = e - f; /* Center point */ - for ( ; i >= 0; i--) { + for (; i >= 0; i--) { if (e >= endpoint[indx[i]].val) break; indx[i + 2] = indx[i]; @@ -1611,7 +1890,7 @@ clock_select(void) endpoint[nl3++].val = e; e = e - f; /* Lower end */ - for ( ; i >= 0; i--) { + for (; i >= 0; i--) { if (e >= endpoint[indx[i]].val) break; indx[i + 1] = indx[i]; @@ -1628,39 +1907,81 @@ clock_select(void) endpoint[indx[i]].type, endpoint[indx[i]].val); #endif - i = 0; - j = nl3 - 1; - allow = nlist; /* falsetickers assumed */ - found = 0; - while (allow > 0) { - allow--; - for (n = 0; i <= j; i++) { - n += endpoint[indx[i]].type; - if (n < 0) + /* + * This is the actual algorithm that cleaves the truechimers + * from the falsetickers. The original algorithm was described + * in Keith Marzullo's dissertation, but has been modified for + * better accuracy. + * + * Briefly put, we first assume there are no falsetickers, then + * scan the candidate list first from the low end upwards and + * then from the high end downwards. The scans stop when the + * number of intersections equals the number of candidates less + * the number of falsetickers. If this doesn't happen for a + * given number of falsetickers, we bump the number of + * falsetickers and try again. If the number of falsetickers + * becomes equal to or greater than half the number of + * candidates, the Albanians have won the Byzantine wars and + * correct synchronization is not possible. + * + * Here, nlist is the number of candidates and allow is the + * number of falsetickers. + */ + 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. + */ + found = 0; + n = 0; + for (i = 0; i < nl3; i++) { + low = endpoint[indx[i]].val; + n -= endpoint[indx[i]].type; + if (n >= nlist - allow) break; if (endpoint[indx[i]].type == 0) found++; } - for (n = 0; i <= j; j--) { + n = 0; + for (j = nl3 - 1; j >= 0; j--) { + high = endpoint[indx[j]].val; n += endpoint[indx[j]].type; - if (n > 0) + 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. + */ + if (high > low) break; - low = endpoint[indx[i++]].val; - high = endpoint[indx[j--]].val; } /* * 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 declare - * us unsynchronized. + * of them as the only survivor. Otherwise, give up and leave + * the island to the rats. */ - if ((allow << 1) >= nlist) { + if (high <= low) { if (typeacts != 0) { typeacts->status = CTL_PST_SEL_SANE; peer_list[0] = typeacts; @@ -1674,42 +1995,58 @@ clock_select(void) sys_poll = NTP_MINPOLL; NLOG(NLOG_SYNCSTATUS) msyslog(LOG_INFO, - "synchronisation lost"); - report_event(EVNT_PEERSTCHG, - (struct peer *)0); + "no servers reachable"); + report_event(EVNT_PEERSTCHG, NULL); } - sys_survivors = 0; -#ifdef AUTOKEY - resetmanycast(); -#endif /* AUTOKEY */ + if (osurv > 0) + resetmanycast(); return; } } -#ifdef DEBUG - if (debug > 2) - printf("select: low %.6f high %.6f\n", low, high); -#endif + + /* + * 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 the value to 4 and use at least that + * number of synchronization sources. + */ + if (nlist < sys_minsane) + return; /* * Clustering algorithm. Construct candidate list in order first - * by stratum then by root distance. If we have more than - * MAXCLOCK peers, keep only the best MAXCLOCK of them. Scan the - * list to find falsetickers, who leave the island immediately. - * If a falseticker is not configured, his association raft is - * drowned as well. We must leave at least one peer to collect - * the million bucks. + * by stratum then by root distance, but keep only the best + * NTP_MAXCLOCK of them. Scan the list to find falsetickers, who + * leave the island immediately. If a falseticker is not + * configured, his association raft is drowned as well, but only + * if at at least eight poll intervals have gone. We must leave + * at least one peer to collect the million bucks. + * + * Note the hysteresis gimmick that increases the effective + * distance for those rascals that have not made the final cut. + * This is to discourage clockhopping. Note also the prejudice + * against lower stratum peers if the floor is elevated. */ j = 0; for (i = 0; i < nlist; i++) { peer = peer_list[i]; - if (nlist > 1 && (low >= peer->offset || peer->offset >= + if (nlist > 1 && (peer->offset <= low || peer->offset >= high)) { if (!(peer->flags & FLAG_CONFIG)) unpeer(peer); continue; } peer->status = CTL_PST_SEL_DISTSYSPEER; - d = root_distance(peer) + peer->stratum * MAXDISPERSE; + d = peer->stratum; + if (d < sys_floor) + d += sys_floor; + if (d > sys_ceiling) + d = STRATUM_UNSPEC; + d = root_distance(peer) + d * MAXDISTANCE; + d *= 1. - peer->hyst; if (j >= NTP_MAXCLOCK) { if (d >= synch[j - 1]) continue; @@ -1729,20 +2066,28 @@ clock_select(void) j++; } nlist = j; + if (nlist == 0) { +#ifdef DEBUG + if (debug) + printf("clock_select: empty intersection interval\n"); +#endif + return; + } for (i = 0; i < nlist; i++) { peer_list[i]->status = CTL_PST_SEL_SELCAND; #ifdef DEBUG if (debug > 2) - printf("select: %s distance %.6f\n", - ntoa(&peer_list[i]->srcadr), synch[i]); + printf("select: %s distance %.6f jitter %.6f\n", + ntoa(&peer_list[i]->srcadr), synch[i], + SQRT(error[i])); #endif } /* * Now, vote outlyers off the island by select jitter weighted * by root dispersion. Continue voting as long as there are more - * than NTP_MINCLOCK survivors and the minimum select jitter + * than sys_minclock survivors and the minimum select jitter * squared is greater than the maximum peer jitter squared. Stop * if we are about to discard a prefer peer, who of course has * the immunity idol. @@ -1752,7 +2097,6 @@ clock_select(void) e = -1e9; k = 0; for (i = 0; i < nlist; i++) { - if (error[i] < d) d = error[i]; f = 0; @@ -1762,24 +2106,25 @@ clock_select(void) peer_list[i]->offset); f /= nlist - 1; } - f = max(f, SQUARE(LOGTOD(sys_precision))); if (f * synch[i] > e) { sys_selerr = f; e = f * synch[i]; k = i; } } - + f = max(sys_selerr, SQUARE(LOGTOD(sys_precision))); + if (nlist <= sys_minclock || f <= d || + peer_list[k]->flags & FLAG_PREFER) + break; #ifdef DEBUG if (debug > 2) printf( - "select: survivors %d select %.6f peer %.6f\n", - k, SQRT(sys_selerr), SQRT(d)); + "select: drop %s select %.6f jitter %.6f\n", + ntoa(&peer_list[k]->srcadr), + SQRT(sys_selerr), SQRT(d)); #endif - if (nlist <= NTP_MINCLOCK || sys_selerr <= d || - peer_list[k]->flags & FLAG_PREFER) - break; - if (!(peer_list[k]->flags & FLAG_CONFIG)) + if (!(peer_list[k]->flags & FLAG_CONFIG) && + peer_list[k]->hmode == MODE_CLIENT) unpeer(peer_list[k]); for (j = k + 1; j < nlist; j++) { peer_list[j - 1] = peer_list[j]; @@ -1788,75 +2133,62 @@ clock_select(void) nlist--; } -#ifdef AUTOKEY - /* - * In manycast client mode we may have spooked a sizeable number - * of servers that we don't need. If there are at least - * NTP_MINCLOCK of them, the manycast message will be turned - * off. By the time we get here we nay be ready to prune some of - * them back, but we want to make sure all the candicates have - * had a chance. If they didn't pass the sanity and intersection - * tests, they have already been voted off the island. - */ - if (sys_survivors >= NTP_MINCLOCK && nlist < NTP_MINCLOCK) - resetmanycast(); -#endif /* AUTOKEY */ - sys_survivors = nlist; - -#ifdef DEBUG - if (debug > 2) { - for (i = 0; i < nlist; i++) - printf( - "select: %s offset %.6f, distance %.6f poll %d\n", - ntoa(&peer_list[i]->srcadr), - peer_list[i]->offset, synch[i], - peer_list[i]->pollsw); - } -#endif - /* - * What remains is a list of not greater than NTP_MINCLOCK + * 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. First record their order, diddle the - * flags and clamp the poll intervals. Then, consider the peers - * at the lowest stratum. Of these, OR the leap bits on the - * assumption that, if some of them honk nonzero bits, they must - * know what they are doing. Also, check for prefer and pps - * peers. If a prefer peer is found within clock_max, update the - * pps switch. Of the other peers not at the lowest stratum, - * check if the system peer is among them and, if found, zap - * him. We note that the head of the list is at the lowest + * flags and clamp the poll intervals. Then, 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. Check + * if the old system peer is among the peers at the lowest + * stratum. Note that the head of the list is at the lowest * stratum and that unsynchronized peers cannot survive this * far. * - * Note that we go no further, unless the number of survivors is - * a majority of the suckers that have been found reachable and - * no prior source is available. This avoids the transient when - * one of a flock of sources is out to lunch and just happens - * to be the first survivor. + * Fiddle for hysteresis. Pump it up for a peer only if the peer + * stratum is at least the floor and there are enough survivors. + * This minimizes the pain when tossing out rascals beneath the + * floorboard. Don't count peers with stratum above the ceiling. + * Manycast is sooo complicated. */ - if (osys_peer == NULL && 2 * nlist < min(nreach, NTP_MINCLOCK)) - return; leap_consensus = 0; for (i = nlist - 1; i >= 0; i--) { peer = peer_list[i]; + leap_consensus |= peer->leap; peer->status = CTL_PST_SEL_SYNCCAND; + peer->rank++; peer->flags |= FLAG_SYSPEER; - poll_update(peer, peer->hpoll); - if (peer->stratum == peer_list[0]->stratum) { - leap_consensus |= peer->leap; - if (peer->refclktype == REFCLK_ATOM_PPS && - peer->stratum < STRATUM_UNSPEC) - typepps = peer; - if (peer == osys_peer) - typesystem = peer; - if (peer->flags & FLAG_PREFER) - sys_prefer = peer; - } + if (peer->stratum >= sys_floor && osurv >= sys_minclock) + peer->hyst = HYST; + else + peer->hyst = 0; + if (peer->stratum <= sys_ceiling) + sys_survivors++; + if (peer->flags & FLAG_PREFER) + sys_prefer = peer; + if (peer->refclktype == REFCLK_ATOM_PPS && + peer->stratum < STRATUM_UNSPEC) + typepps = peer; + if (peer->stratum == peer_list[0]->stratum && peer == + osys_peer) + typesystem = peer; } /* + * In manycast client mode we may have spooked a sizeable number + * of peers that we don't need. If there are at least + * sys_minclock of them, the manycast message will be turned + * off. By the time we get here we nay be ready to prune some of + * them back, but we want to make sure all the candicates have + * had a chance. If they didn't pass the sanity and intersection + * tests, they have already been voted off the island. + */ + if (sys_survivors < sys_minclock && osurv >= sys_minclock) + resetmanycast(); + + /* * Mitigation rules of the game. There are several types of * peers that make a difference here: (1) prefer local peers * (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer modem @@ -1884,15 +2216,16 @@ clock_select(void) printf("select: prefer offset %.6f\n", sys_offset); #endif - } else if (typepps) { + } +#ifndef LOCKCLOCK + else if (typepps) { sys_peer = typepps; sys_peer->status = CTL_PST_SEL_PPS; sys_offset = sys_peer->offset; sys_syserr = sys_peer->jitter; if (!pps_control) NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, - "pps sync enabled"); + msyslog(LOG_INFO, "pps sync enabled"); pps_control = current_time; #ifdef DEBUG if (debug > 1) @@ -1905,6 +2238,7 @@ clock_select(void) else sys_peer = peer_list[0]; sys_peer->status = CTL_PST_SEL_SYSPEER; + sys_peer->rank++; sys_offset = clock_combine(peer_list, nlist); sys_syserr = sys_peer->jitter + sys_selerr; #ifdef DEBUG @@ -1913,8 +2247,26 @@ clock_select(void) sys_offset); #endif } - if (osys_peer != sys_peer) - report_event(EVNT_PEERSTCHG, (struct peer *)0); +#endif /* LOCKCLOCK */ + if (osys_peer != sys_peer) { + char *src; + + if (sys_peer == NULL) + sys_peer_refid = 0; + else + sys_peer_refid = addr2refid(&sys_peer->srcadr); + report_event(EVNT_PEERSTCHG, NULL); + +#ifdef REFCLOCK + if (ISREFCLOCKADR(&sys_peer->srcadr)) + src = refnumtoa(&sys_peer->srcadr); + else +#endif + src = ntoa(&sys_peer->srcadr); + NLOG(NLOG_SYNCSTATUS) + msyslog(LOG_INFO, "synchronized to %s, stratum=%d", src, + sys_peer->stratum); + } clock_update(); } @@ -1924,11 +2276,12 @@ clock_select(void) static double clock_combine( struct peer **peers, - int npeers + int npeers ) { - int i; - double x, y, z; + int i; + double x, y, z; + y = z = 0; for (i = 0; i < npeers; i++) { x = root_distance(peers[i]); @@ -1965,9 +2318,9 @@ peer_xmit( ) { struct pkt xpkt; /* transmit packet */ - int sendlen, authlen; - keyid_t xkeyid; /* transmit key ID */ - l_fp xmt_tx; + int sendlen, authlen; + keyid_t xkeyid = 0; /* transmit key ID */ + l_fp xmt_tx; /* * Initialize transmit packet header fields. @@ -1998,14 +2351,14 @@ peer_xmit( if (!(peer->flags & FLAG_AUTHENABLE)) { get_systime(&peer->xmt); HTONL_FP(&peer->xmt, &xpkt.xmt); - sendpkt(&peer->srcadr, peer->dstadr, peer->ttl, &xpkt, - sendlen); + sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], + &xpkt, sendlen); peer->sent++; #ifdef DEBUG if (debug) printf("transmit: at %ld %s->%s mode %d\n", - current_time, ntoa(&peer->dstadr->sin), - ntoa(&peer->srcadr), peer->hmode); + current_time, stoa(&peer->dstadr->sin), + stoa(&peer->srcadr), peer->hmode); #endif return; } @@ -2015,9 +2368,10 @@ peer_xmit( * must be authenticated. If autokey is enabled, fuss with the * various modes; otherwise, private key cryptography is used. */ -#ifdef AUTOKEY - if ((peer->flags & FLAG_SKEY)) { - u_int cmmd; +#ifdef OPENSSL + if (crypto_flags && (peer->flags & FLAG_SKEY)) { + struct exten *exten; /* extension field */ + u_int opcode; /* * The Public Key Dance (PKD): Cryptographic credentials @@ -2077,191 +2431,214 @@ peer_xmit( switch (peer->hmode) { /* - * In broadcast mode the autokey values are required. - * Send them when a new keylist is generated; otherwise, - * send the association ID 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) - cmmd = CRYPTO_AUTO | CRYPTO_RESP; + exten = crypto_args(peer, CRYPTO_AUTO | + CRYPTO_RESP, NULL); else - cmmd = CRYPTO_ASSOC | CRYPTO_RESP; - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, cmmd, 0, peer->associd); + exten = crypto_args(peer, CRYPTO_ASSOC | + CRYPTO_RESP, NULL); + sendlen += crypto_xmit(&xpkt, &peer->srcadr, + sendlen, exten, 0); + free(exten); break; /* - * In symmetric modes the public key, leapsecond table, - * agreement parameters and autokey values are required. - * - * 1. If a response is pending, always send it first. - * - * 2. Don't send anything except a public-key request - * until the public key has been stored. - * - * 3. Once the public key has been stored, don't send - * anything except an agreement parameter request - * until the agreement parameters have been stored. - * - * 4. Once the argeement parameters have been stored, - * don't send anything except a public value request - * until the agreed key has been stored. - * - * 5. When the agreed key has been stored and the key - * list is regenerated, send the autokey values - * gratis unless they have already been sent. + * 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. */ case MODE_ACTIVE: case MODE_PASSIVE: -#ifdef PUBKEY - if (peer->cmmd != 0) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, (peer->cmmd >> 16) | - CRYPTO_RESP, peer->hcookie, - peer->associd); + if (peer->cmmd != NULL) { + peer->cmmd->associd = + htonl(peer->associd); + sendlen += crypto_xmit(&xpkt, + &peer->srcadr, sendlen, peer->cmmd, + 0); + free(peer->cmmd); + peer->cmmd = NULL; + } + exten = NULL; if (!peer->crypto) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_ASSOC, - peer->hcookie, peer->assoc); - else if (!crypto_flags && - peer->pcookie.tstamp == 0 && sys_leap != - LEAP_NOTINSYNC) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_PRIV, peer->hcookie, - peer->assoc); - else if (crypto_flags && peer->pubkey.ptr == - NULL) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_NAME, peer->hcookie, - peer->assoc); - else if (peer->crypto & CRYPTO_FLAG_CERT) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_CERT, peer->hcookie, - peer->assoc); - else if (crypto_flags && peer->crypto & - CRYPTO_FLAG_DH && sys_leap != - LEAP_NOTINSYNC) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_DHPAR, - peer->hcookie, peer->assoc); - else if (crypto_flags && peer->pcookie.tstamp == - 0 && sys_leap != LEAP_NOTINSYNC) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_DH, peer->hcookie, - peer->assoc); -#else - if (peer->cmmd != 0) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, (peer->cmmd >> 16) | - CRYPTO_RESP, peer->hcookie, - peer->associd); - if (peer->pcookie.tstamp == 0 && sys_leap != - LEAP_NOTINSYNC) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_PRIV, peer->hcookie, - peer->assoc); -#endif /* PUBKEY */ - else if (!(peer->flags & FLAG_AUTOKEY)) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_AUTO, peer->hcookie, - peer->assoc); - else if ((peer->flags & FLAG_ASSOC) && - (peer->cmmd >> 16) != CRYPTO_AUTO) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_AUTO | CRYPTO_RESP, - peer->hcookie, peer->associd); -#ifdef PUBKEY - else if (peer->crypto & CRYPTO_FLAG_TAI) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_TAI, peer->hcookie, - peer->assoc); -#endif /* PUBKEY */ - peer->cmmd = 0; + exten = crypto_args(peer, CRYPTO_ASSOC, + sys_hostname); + else if (!(peer->crypto & CRYPTO_FLAG_VALID)) + 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. + */ + else if ((opcode = crypto_ident(peer)) != 0) + exten = crypto_args(peer, opcode, NULL); + else if (sys_leap != LEAP_NOTINSYNC && + !(peer->crypto & CRYPTO_FLAG_SIGN)) + exten = crypto_args(peer, CRYPTO_SIGN, + sys_hostname); + + /* + * 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. + */ + else if (sys_leap != LEAP_NOTINSYNC && + peer->leap != LEAP_NOTINSYNC && + !(peer->crypto & CRYPTO_FLAG_AGREE)) + exten = crypto_args(peer, CRYPTO_COOK, + NULL); + else if (peer->flags & FLAG_ASSOC) + exten = crypto_args(peer, CRYPTO_AUTO | + CRYPTO_RESP, NULL); + else if (!(peer->crypto & CRYPTO_FLAG_AUTO)) + exten = crypto_args(peer, CRYPTO_AUTO, + NULL); + + /* + * Postamble. We trade leapseconds only when the + * server and client are synchronized. + */ + 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); + if (exten != NULL) { + sendlen += crypto_xmit(&xpkt, + &peer->srcadr, sendlen, exten, 0); + free(exten); + } break; /* - * In client mode, the public key, host cookie and - * autokey values are required. In broadcast client - * mode, these values must be acquired during the + * 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. Note that we ask - * for the cookie at each key list regeneration anyway. + * 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. */ case MODE_CLIENT: - if (peer->cmmd != 0) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, (peer->cmmd >> 16) | - CRYPTO_RESP, peer->hcookie, - peer->associd); + if (peer->cmmd != NULL) { + peer->cmmd->associd = + htonl(peer->associd); + sendlen += crypto_xmit(&xpkt, + &peer->srcadr, sendlen, peer->cmmd, + 0); + free(peer->cmmd); + peer->cmmd = NULL; + } + exten = NULL; if (!peer->crypto) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_ASSOC, - peer->hcookie, peer->assoc); -#ifdef PUBKEY - else if (crypto_flags && peer->pubkey.ptr == - NULL) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_NAME, peer->hcookie, - peer->assoc); - else if (peer->crypto & CRYPTO_FLAG_CERT) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_CERT, peer->hcookie, - peer->assoc); -#endif /* PUBKEY */ - else if (peer->pcookie.tstamp == 0) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_PRIV, peer->hcookie, - peer->assoc); - else if (!(peer->flags & FLAG_AUTOKEY) && + exten = crypto_args(peer, CRYPTO_ASSOC, + sys_hostname); + else if (!(peer->crypto & CRYPTO_FLAG_VALID)) + exten = crypto_args(peer, CRYPTO_CERT, + peer->issuer); + + /* + * Identity. + */ + else if ((opcode = crypto_ident(peer)) != 0) + exten = crypto_args(peer, opcode, NULL); + + /* + * Autokey + */ + else if (!(peer->crypto & CRYPTO_FLAG_AGREE)) + exten = crypto_args(peer, CRYPTO_COOK, + NULL); + else if (!(peer->crypto & CRYPTO_FLAG_AUTO) && (peer->cast_flags & MDF_BCLNT)) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_AUTO, peer->hcookie, - peer->assoc); -#ifdef PUBKEY - else if (peer->crypto & CRYPTO_FLAG_TAI) - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, CRYPTO_TAI, peer->hcookie, - peer->assoc); -#endif /* PUBKEY */ - peer->cmmd = 0; + exten = crypto_args(peer, CRYPTO_AUTO, + NULL); + + /* + * Postamble. We can sign the certificate here, + * since there is no chance of deadlock. + */ + else if (sys_leap != LEAP_NOTINSYNC && + !(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); + if (exten != NULL) { + sendlen += crypto_xmit(&xpkt, + &peer->srcadr, sendlen, exten, 0); + free(exten); + } break; } /* * If extension fields are present, we must use a - * private value of zero and force min poll interval. + * private value of zero and force min poll interval. * Most intricate. */ if (sendlen > LEN_PKT_NOMAC) session_key(&peer->dstadr->sin, &peer->srcadr, xkeyid, 0, 2); } -#endif /* AUTOKEY */ +#endif /* OPENSSL */ 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_NOTICE, - "transmit: no encryption key found"); - peer->flash |= TEST4 | TEST5; + msyslog(LOG_INFO, + "transmit: encryption key %d not found", xkeyid); + if (peer->flags & FLAG_CONFIG) + peer_clear(peer, "NKEY"); + else + unpeer(peer); return; } sendlen += authlen; -#ifdef AUTOKEY +#ifdef OPENSSL if (xkeyid > NTP_MAXKEY) authtrust(xkeyid, 0); -#endif /* AUTOKEY */ +#endif /* OPENSSL */ get_systime(&xmt_tx); if (sendlen > sizeof(xpkt)) { msyslog(LOG_ERR, "buffer overflow %u", sendlen); - exit(-1); + exit (-1); } - sendpkt(&peer->srcadr, peer->dstadr, peer->ttl, &xpkt, sendlen); + sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt, + sendlen); /* * Calculate the encryption delay. Keep the minimum over @@ -2276,14 +2653,14 @@ peer_xmit( else sys_authdelay.l_uf = sys_authdly[1]; peer->sent++; -#ifdef AUTOKEY +#ifdef OPENSSL #ifdef DEBUG if (debug) printf( "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n", current_time, ntoa(&peer->dstadr->sin), - ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen, - authlen, peer->keynumber); + ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - + authlen, authlen, peer->keynumber); #endif #else #ifdef DEBUG @@ -2291,10 +2668,10 @@ peer_xmit( printf( "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n", current_time, ntoa(&peer->dstadr->sin), - ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen, - authlen); + ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - + authlen, authlen); #endif -#endif /* AUTOKEY */ +#endif /* OPENSSL */ } @@ -2305,16 +2682,19 @@ peer_xmit( static void fast_xmit( struct recvbuf *rbufp, /* receive packet pointer */ - int xmode, /* transmit mode */ - keyid_t xkeyid, /* transmit key ID */ - int mask /* restrict mask */ + int xmode, /* transmit mode */ + keyid_t xkeyid, /* transmit key ID */ + int mask /* restrict mask */ ) { - struct pkt xpkt; /* transmit packet structure */ - struct pkt *rpkt; /* receive packet structure */ - l_fp xmt_ts; /* transmit timestamp */ - l_fp xmt_tx; /* transmit timestamp after authent */ - int sendlen, authlen; + 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 + u_int32 temp32; +#endif /* * Initialize transmit packet header fields from the receive @@ -2327,19 +2707,35 @@ fast_xmit( rbufp->dstadr = findinterface(&rbufp->recv_srcadr); /* - * If the caller is restricted, return a kiss-of-death packet; - * otherwise, smooch politely. + * If the packet has picked up a restriction due to either + * access denied or rate exceeded, decide what to do with it. */ - if (mask & (RES_DONTSERVE | RES_LIMITED)) { - if (!(mask & RES_DEMOBILIZE)) { - return; - } else { - xpkt.li_vn_mode = - PKT_LI_VN_MODE(LEAP_NOTINSYNC, - PKT_VERSION(rpkt->li_vn_mode), xmode); - xpkt.stratum = STRATUM_UNSPEC; - memcpy(&xpkt.refid, "DENY", 4); + if (mask & (RES_DONTTRUST | RES_LIMITED)) { + char *code = "????"; + + if (mask & RES_LIMITED) { + sys_limitrejected++; + code = "RATE"; + } else if (mask & RES_DONTTRUST) { + sys_restricted++; + code = "DENY"; } + + /* + * Here we light up a kiss-of-death packet. 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 kod. + */ + if (sys_kod == 0 || !(mask & RES_DEMOBILIZE)) + return; + + sys_kod--; + memcpy(&xpkt.refid, code, 4); + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, + PKT_VERSION(rpkt->li_vn_mode), xmode); + xpkt.stratum = STRATUM_UNSPEC; } else { xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, PKT_VERSION(rpkt->li_vn_mode), xmode); @@ -2369,8 +2765,8 @@ fast_xmit( #ifdef DEBUG if (debug) printf("transmit: at %ld %s->%s mode %d\n", - current_time, ntoa(&rbufp->dstadr->sin), - ntoa(&rbufp->recv_srcadr), xmode); + current_time, stoa(&rbufp->dstadr->sin), + stoa(&rbufp->recv_srcadr), xmode); #endif return; } @@ -2383,10 +2779,9 @@ fast_xmit( * generate the cookie, which is unique for every source- * destination-key ID combination. */ -#ifdef AUTOKEY +#ifdef OPENSSL if (xkeyid > NTP_MAXKEY) { keyid_t cookie; - u_int code, associd; /* * The only way to get here is a reply to a legitimate @@ -2397,35 +2792,36 @@ fast_xmit( * jerk can decode it. If no extension field is present, * use the cookie to generate the session key. */ - code = (htonl(rpkt->exten[0]) >> 16) | CRYPTO_RESP; cookie = session_key(&rbufp->recv_srcadr, &rbufp->dstadr->sin, 0, sys_private, 0); - associd = htonl(rpkt->exten[1]); - if (rbufp->recv_length >= sendlen + MAX_MAC_LEN + 2 * - sizeof(u_int32)) { + if (rbufp->recv_length >= (int)(sendlen + MAX_MAC_LEN + 2 * + sizeof(u_int32))) { session_key(&rbufp->dstadr->sin, &rbufp->recv_srcadr, xkeyid, 0, 2); - sendlen += crypto_xmit((u_int32 *)&xpkt, - sendlen, code, cookie, associd); + temp32 = CRYPTO_RESP; + rpkt->exten[0] |= htonl(temp32); + sendlen += crypto_xmit(&xpkt, + &rbufp->recv_srcadr, sendlen, + (struct exten *)rpkt->exten, cookie); } else { session_key(&rbufp->dstadr->sin, &rbufp->recv_srcadr, xkeyid, cookie, 2); } } -#endif /* AUTOKEY */ +#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 AUTOKEY +#ifdef OPENSSL if (xkeyid > NTP_MAXKEY) authtrust(xkeyid, 0); -#endif /* AUTOKEY */ +#endif /* OPENSSL */ get_systime(&xmt_tx); if (sendlen > sizeof(xpkt)) { msyslog(LOG_ERR, "buffer overflow %u", sendlen); - exit(-1); + exit (-1); } sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen); @@ -2446,13 +2842,13 @@ fast_xmit( printf( "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n", current_time, ntoa(&rbufp->dstadr->sin), - ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen, - authlen); + ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen - + authlen, authlen); #endif } -#ifdef AUTOKEY +#ifdef OPENSSL /* * key_expire - purge the key list */ @@ -2463,131 +2859,128 @@ key_expire( { int i; - if (peer->keylist != NULL) { + if (peer->keylist != NULL) { for (i = 0; i <= peer->keynumber; i++) authtrust(peer->keylist[i], 0); free(peer->keylist); peer->keylist = NULL; } - peer->keynumber = peer->sndauto.seq = 0; + value_free(&peer->sndval); + peer->keynumber = 0; #ifdef DEBUG if (debug) printf("key_expire: at %lu\n", current_time); #endif } -#endif /* AUTOKEY */ +#endif /* OPENSSL */ + + +/* + * Determine if the peer is unfit for synchronization + * + * A peer is unfit for synchronization if + * > not reachable + * > a synchronization loop would form + * > never been synchronized + * > stratum undefined or too high + * > too long without synchronization + * > designated noselect + */ +static int /* 0 if no, 1 if yes */ +peer_unfit( + struct peer *peer /* peer structure pointer */ + ) +{ + return (!peer->reach || (peer->stratum > 1 && peer->refid == + peer->dstadr->addr_refid) || peer->leap == LEAP_NOTINSYNC || + peer->stratum >= STRATUM_UNSPEC || root_distance(peer) >= + MAXDISTANCE + 2. * clock_phi * ULOGTOD(sys_poll) || + peer->flags & FLAG_NOSELECT ); +} + /* * Find the precision of this particular machine */ -#define DUSECS 1000000 /* us in a s */ -#define HUSECS (1 << 20) /* approx DUSECS for shifting etc */ -#define MINSTEP 5 /* minimum clock increment (us) */ -#define MAXSTEP 20000 /* maximum clock increment (us) */ -#define MINLOOPS 5 /* minimum number of step samples */ +#define MINSTEP 100e-9 /* minimum clock increment (s) */ +#define MAXSTEP 20e-3 /* maximum clock increment (s) */ +#define MINLOOPS 5 /* minimum number of step samples */ /* - * This routine calculates the differences between successive calls to - * gettimeofday(). If a difference is less than zero, the us field - * has rolled over to the next second, so we add a second in us. If - * the difference is greater than zero and less than MINSTEP, the - * clock has been advanced by a small amount to avoid standing still. - * If the clock has advanced by a greater amount, then a timer interrupt - * has occurred and this amount represents the precision of the clock. - * In order to guard against spurious values, which could occur if we - * happen to hit a fat interrupt, we do this for MINLOOPS times and - * keep the minimum value obtained. + * This routine calculates the system precision, defined as the minimum + * of a sequency 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. + * + * 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. */ int default_get_precision(void) { - struct timeval tp; -#if !defined(SYS_WINNT) && !defined(VMS) && !defined(_SEQUENT_) && \ - !defined(MPE) - struct timezone tzp; -#elif defined(VMS) || defined(_SEQUENT_) - struct timezone { - int tz_minuteswest; - int tz_dsttime; - } tzp; -#endif /* defined(VMS) || defined(_SEQUENT_) */ - long last; - int i; - long diff; - long val; - long usec; -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - u_long freq; - size_t j; - - /* Try to see if we can find the frequency of of the counter - * which drives our timekeeping - */ - j = sizeof freq; - i = sysctlbyname("kern.timecounter.frequency", &freq, &j , 0, - 0); - if (i) - i = sysctlbyname("machdep.tsc_freq", &freq, &j , 0, 0); - if (i) - i = sysctlbyname("machdep.i586_freq", &freq, &j , 0, 0); - if (i) - i = sysctlbyname("machdep.i8254_freq", &freq, &j , 0, - 0); - if (!i) { - for (i = 1; freq ; i--) - freq >>= 1; - return (i); - } -#endif - usec = 0; - val = MAXSTEP; -#ifdef HAVE_GETCLOCK - (void) getclock(TIMEOFDAY, &ts); - tp.tv_sec = ts.tv_sec; - tp.tv_usec = ts.tv_nsec / 1000; -#else /* not HAVE_GETCLOCK */ - GETTIMEOFDAY(&tp, &tzp); -#endif /* not HAVE_GETCLOCK */ - last = tp.tv_usec; - for (i = 0; i < MINLOOPS && usec < HUSECS;) { -#ifdef HAVE_GETCLOCK - (void) getclock(TIMEOFDAY, &ts); - tp.tv_sec = ts.tv_sec; - tp.tv_usec = ts.tv_nsec / 1000; -#else /* not HAVE_GETCLOCK */ - GETTIMEOFDAY(&tp, &tzp); -#endif /* not HAVE_GETCLOCK */ - diff = tp.tv_usec - last; - last = tp.tv_usec; - if (diff < 0) - diff += DUSECS; - usec += diff; - if (diff > MINSTEP) { - i++; - if (diff < val) - val = diff; - } + l_fp val; /* current seconds fraction */ + l_fp last; /* last seconds fraction */ + l_fp diff; /* difference */ + double tick; /* computed tick value */ + double dtemp; /* scratch */ + 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;) { + get_systime(&val); + diff = val; + L_SUB(&diff, &last); + last = val; + LFPTOD(&diff, dtemp); + if (dtemp < MINSTEP) + continue; + i++; + if (dtemp < tick) + tick = dtemp; } - NLOG(NLOG_SYSINFO) - msyslog(LOG_INFO, "precision = %ld usec", val); - if (usec >= HUSECS) - val = MINSTEP; /* val <= MINSTEP; fast machine */ - diff = HUSECS; - for (i = 0; diff > val; i--) - diff >>= 1; - return (i); + + /* + * 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); } + +/* + * kod_proto - called once per second to limit kiss-of-death packets + */ +void +kod_proto(void) +{ + sys_kod = sys_kod_rate; +} + + /* * init_proto - initialize the protocol module's data */ void init_proto(void) { - l_fp dummy; + l_fp dummy; + int i; /* * Fill in the sys_* stuff. Default is don't listen to @@ -2595,32 +2988,31 @@ init_proto(void) */ 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_rootdelay = 0; sys_rootdispersion = 0; - sys_refid = 0; L_CLR(&sys_reftime); sys_peer = NULL; sys_survivors = 0; get_systime(&dummy); + sys_manycastserver = 0; sys_bclient = 0; sys_bdelay = DEFBROADDELAY; + sys_calldelay = BURST_DELAY; sys_authenticate = 1; L_CLR(&sys_authdelay); sys_authdly[0] = sys_authdly[1] = 0; sys_stattime = 0; - sys_badstratum = 0; - sys_oldversionpkt = 0; - sys_newversionpkt = 0; - sys_badlength = 0; - sys_unknownversion = 0; - sys_processed = 0; - sys_badauth = 0; - sys_manycastserver = 0; -#ifdef AUTOKEY + 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 /* AUTOKEY */ +#endif /* OPENSSL */ /* * Default these to enable @@ -2631,19 +3023,6 @@ init_proto(void) #endif pps_enable = 0; stats_control = 1; - - /* - * Some system clocks should only be adjusted in 10ms - * increments. - */ -#if defined RELIANTUNIX_CLOCK - systime_10ms_ticks = 1; /* Reliant UNIX */ -#elif defined SCO5_CLOCK - if (sys_precision >= (s_char)-10) /* pre-SCO OpenServer 5.0.6 */ - systime_10ms_ticks = 1; -#endif - if (systime_10ms_ticks) - msyslog(LOG_INFO, "using 10ms tick adjustments"); } @@ -2652,55 +3031,52 @@ init_proto(void) */ void proto_config( - int item, - u_long value, - double dvalue + int item, + u_long value, + double dvalue, + struct sockaddr_storage* svalue ) { /* * Figure out what he wants to change, then do it */ switch (item) { - case PROTO_KERNEL: - /* - * Turn on/off kernel discipline - */ + /* + * Turn on/off kernel discipline. + */ + case PROTO_KERNEL: kern_enable = (int)value; break; + /* + * Turn on/off clock discipline. + */ case PROTO_NTP: - - /* - * Turn on/off clock discipline - */ ntp_enable = (int)value; break; + /* + * Turn on/off monitoring. + */ case PROTO_MONITOR: - - /* - * Turn on/off monitoring - */ if (value) mon_start(MON_ON); else mon_stop(MON_ON); break; + /* + * Turn on/off statistics. + */ case PROTO_FILEGEN: - - /* - * Turn on/off statistics - */ stats_control = (int)value; break; + /* + * Turn on/off facility to listen to broadcasts. + */ case PROTO_BROADCLIENT: - - /* - * Turn on/off facility to listen to broadcasts - */ sys_bclient = (int)value; if (value) io_setbclient(); @@ -2708,65 +3084,107 @@ proto_config( io_unsetbclient(); break; + /* + * Add muliticast group address. + */ case PROTO_MULTICAST_ADD: - - /* - * Add muliticast group address - */ - io_multicast_add(value); + if (svalue) + io_multicast_add(*svalue); break; + /* + * Delete multicast group address. + */ case PROTO_MULTICAST_DEL: - - /* - * Delete multicast group address - */ - io_multicast_del(value); + if (svalue) + io_multicast_del(*svalue); break; + /* + * Set default broadcast delay. + */ case PROTO_BROADDELAY: - - /* - * Set default broadcast delay - */ sys_bdelay = dvalue; break; - case PROTO_AUTHENTICATE: + /* + * Set modem call delay. + */ + case PROTO_CALLDELAY: + sys_calldelay = (int)value; + break; - /* - * Specify the use of authenticated data - */ + /* + * Require authentication to mobilize ephemeral associations. + */ + case PROTO_AUTHENTICATE: sys_authenticate = (int)value; break; + /* + * Turn on/off PPS discipline. + */ case PROTO_PPS: - - /* - * Turn on/off PPS discipline - */ pps_enable = (int)value; break; + /* + * Set the minimum number of survivors. + */ + case PROTO_MINCLOCK: + sys_minclock = (int)dvalue; + break; + + /* + * Set the minimum number of candidates. + */ + case PROTO_MINSANE: + sys_minsane = (int)dvalue; + break; + + /* + * Set the stratum floor. + */ + case PROTO_FLOOR: + sys_floor = (int)dvalue; + break; + + /* + * Set the stratum ceiling. + */ + case PROTO_CEILING: + sys_ceiling = (int)dvalue; + break; + + /* + * Set the cohort switch. + */ + case PROTO_COHORT: + sys_cohort= (int)dvalue; + break; + /* + * Set the adjtime() resolution (s). + */ + case PROTO_ADJ: + sys_tick = dvalue; + break; + #ifdef REFCLOCK + /* + * Turn on/off refclock calibrate + */ case PROTO_CAL: - - /* - * Turn on/off refclock calibrate - */ cal_enable = (int)value; break; #endif - default: /* - * Log this error + * Log this error. */ - msyslog(LOG_ERR, - "proto_config: illegal item %d, value %ld", + msyslog(LOG_INFO, + "proto_config: illegal item %d, value %ld", item, value); - break; } } @@ -2777,13 +3195,14 @@ proto_config( void proto_clr_stats(void) { - sys_badstratum = 0; - sys_oldversionpkt = 0; + sys_stattime = current_time; + sys_received = 0; + sys_processed = 0; sys_newversionpkt = 0; + sys_oldversionpkt = 0; sys_unknownversion = 0; + sys_restricted = 0; sys_badlength = 0; - sys_processed = 0; sys_badauth = 0; - sys_stattime = current_time; sys_limitrejected = 0; } diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c index 2205b6c..172fbda 100644 --- a/contrib/ntp/ntpd/ntp_refclock.c +++ b/contrib/ntp/ntpd/ntp_refclock.c @@ -63,8 +63,9 @@ * 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, where t is the - * clock type and u the unit. Some legacy drivers derive the + * 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. @@ -107,7 +108,8 @@ refclock_report( { struct refclockproc *pp; - if (!(pp = peer->procptr)) + pp = peer->procptr; + if (pp == NULL) return; if (code == CEVNT_BADREPLY) pp->badformat++; @@ -116,25 +118,25 @@ refclock_report( if (code == CEVNT_TIMEOUT) pp->noreply++; if (pp->currentstatus != code) { - pp->currentstatus = code; - pp->lastevent = code; + pp->currentstatus = (u_char)code; + pp->lastevent = (u_char)code; if (code == CEVNT_FAULT) msyslog(LOG_ERR, "clock %s event '%s' (0x%02x)", - refnumtoa(peer->srcadr.sin_addr.s_addr), + refnumtoa(&peer->srcadr), ceventstr(code), code); else { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_INFO, "clock %s event '%s' (0x%02x)", - refnumtoa(peer->srcadr.sin_addr.s_addr), + refnumtoa(&peer->srcadr), ceventstr(code), code); } } #ifdef DEBUG if (debug) printf("clock %s event '%s' (0x%02x)\n", - refnumtoa(peer->srcadr.sin_addr.s_addr), + refnumtoa(&peer->srcadr), ceventstr(code), code); #endif } @@ -186,10 +188,16 @@ 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", - ntoa(&peer->srcadr)); + stoa(&peer->srcadr)); return (0); } clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); @@ -205,7 +213,8 @@ refclock_newpeer( /* * Allocate and initialize interface structure */ - if (!(pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)))) + pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)); + if (pp == NULL) return (0); memset((char *)pp, 0, sizeof(struct refclockproc)); typeunit[clktype][unit] = peer; @@ -215,12 +224,10 @@ refclock_newpeer( * Initialize structures */ peer->refclktype = clktype; - peer->refclkunit = unit; + peer->refclkunit = (u_char)unit; peer->flags |= FLAG_REFCLOCK; - peer->stratum = STRATUM_REFCLOCK; - peer->refid = peer->srcadr.sin_addr.s_addr; peer->maxpoll = peer->minpoll; - + peer->stratum = STRATUM_REFCLOCK; pp->type = clktype; pp->timestarted = current_time; @@ -228,12 +235,11 @@ refclock_newpeer( * Set peer.pmode based on the hmode. For appearances only. */ switch (peer->hmode) { - - case MODE_ACTIVE: + case MODE_ACTIVE: peer->pmode = MODE_PASSIVE; break; - default: + default: peer->pmode = MODE_SERVER; break; } @@ -248,10 +254,7 @@ refclock_newpeer( } peer->hpoll = peer->minpoll; peer->ppoll = peer->maxpoll; - if (peer->stratum <= 1) - peer->refid = pp->refid; - else - peer->refid = peer->srcadr.sin_addr.s_addr; + peer->refid = pp->refid; return (1); } @@ -297,7 +300,6 @@ refclock_transmit( { u_char clktype; int unit; - int hpoll; u_long next; clktype = peer->refclktype; @@ -309,14 +311,13 @@ refclock_transmit( * specialized for reference clocks. We do a little less * protocol here and call the driver-specific transmit routine. */ - hpoll = peer->hpoll; next = peer->outdate; if (peer->burst == 0) { u_char oreach; #ifdef DEBUG if (debug) printf("refclock_transmit: at %ld %s\n", - current_time, ntoa(&(peer->srcadr))); + current_time, stoa(&(peer->srcadr))); #endif /* @@ -329,17 +330,13 @@ refclock_transmit( if (oreach) { report_event(EVNT_UNREACH, peer); peer->timereachable = current_time; - peer_clear(peer); + peer_clear(peer, "NONE"); } } else { if (!(oreach & 0x03)) { clock_filter(peer, 0., 0., MAXDISPERSE); clock_select(); } - if (!(oreach & 0x0f)) { - hpoll--; - } else if ((oreach & 0x0f) == 0x0f) - hpoll++; if (peer->flags & FLAG_BURST) peer->burst = NSTAGE; } @@ -351,7 +348,7 @@ refclock_transmit( peer->outdate = next; if (peer->burst > 0) peer->burst--; - poll_update(peer, hpoll); + poll_update(peer, 0); } @@ -399,18 +396,19 @@ refclock_cmpl_fp( */ void refclock_process_offset( - struct refclockproc *pp, - l_fp offset, - l_fp lastrec, + struct refclockproc *pp, /* refclock structure pointer */ + l_fp lasttim, /* last timecode timestamp */ + l_fp lastrec, /* last receive timestamp */ double fudge ) { + l_fp lftemp; double doffset; - pp->lastref = offset; pp->lastrec = lastrec; - L_SUB(&offset, &lastrec); - LFPTOD(&offset, doffset); + lftemp = lasttim; + L_SUB(&lftemp, &lastrec); + LFPTOD(&lftemp, doffset); SAMPLE(doffset + fudge); } @@ -425,10 +423,10 @@ refclock_process_offset( */ int refclock_process( - struct refclockproc *pp + struct refclockproc *pp /* refclock structure pointer */ ) { - l_fp offset; + l_fp offset, ltemp; /* * Compute the timecode timestamp from the days, hours, minutes, @@ -441,11 +439,9 @@ refclock_process( if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) return (0); - if (pp->usec) { - TVUTOTSF(pp->usec, offset.l_uf); - } else { - MSUTOTSF(pp->msec, offset.l_uf); - } + offset.l_uf = 0; + DTOLFP(pp->nsec / 1e9, <emp); + L_ADD(&offset, <emp); refclock_process_offset(pp, offset, pp->lastrec, pp->fudgetime1); return (1); @@ -463,7 +459,7 @@ refclock_process( */ static int refclock_sample( - struct refclockproc *pp + struct refclockproc *pp /* refclock structure pointer */ ) { int i, j, k, m, n; @@ -474,11 +470,14 @@ refclock_sample( * Copy the raw offsets and sort into ascending order. Don't do * anything if the buffer is empty. */ - if (pp->codeproc == pp->coderecv) - return (0); n = 0; - while (pp->codeproc != pp->coderecv) - off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE]; + while (pp->codeproc != pp->coderecv) { + pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; + off[n] = pp->filter[pp->codeproc]; + n++; + } + if (n == 0) + return (0); if (n > 1) qsort((char *)off, (size_t)n, sizeof(double), refclock_cmpl_fp); @@ -536,7 +535,7 @@ refclock_receive( #ifdef DEBUG if (debug) printf("refclock_receive: at %lu %s\n", - current_time, ntoa(&peer->srcadr)); + current_time, stoa(&peer->srcadr)); #endif /* @@ -556,8 +555,9 @@ refclock_receive( if (!peer->reach) report_event(EVNT_REACH, peer); peer->reach |= 1; - peer->reftime = peer->org = pp->lastrec; - peer->rootdispersion = pp->disp + SQRT(pp->jitter); + peer->reftime = pp->lastref; + peer->org = pp->lastrec; + peer->rootdispersion = pp->disp; get_systime(&peer->rec); if (!refclock_sample(pp)) return; @@ -608,7 +608,7 @@ refclock_gtlin( * timestamp by noting its value is earlier than the buffer * timestamp, but not more than one second earlier. */ - dpt = (char *)&rbufp->recv_space; + dpt = (char *)rbufp->recv_buffer; dpend = dpt + rbufp->recv_length; trtmp = rbufp->recv_time; @@ -641,7 +641,7 @@ refclock_gtlin( if (dpend - dpt > bmax - 1) dpend = dpt + bmax - 1; for (dp = lineptr; dpt < dpend; dpt++) { - c = *dpt & 0x7f; + c = (char) (*dpt & 0x7f); if (c >= ' ') *dp++ = c; } @@ -649,9 +649,14 @@ refclock_gtlin( if (i > 0) *dp = '\0'; #ifdef DEBUG - if (debug > 1 && i > 0) - printf("refclock_gtlin: fd %d time %s timecode %d %s\n", - rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); + if (debug > 1) { + if (i > 0) + printf("refclock_gtlin: fd %d time %s timecode %d %s\n", + rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); + else + printf("refclock_gtlin: fd %d time %s\n", + rbufp->fd, ulfptoa(&trtmp, 6)); + } #endif *tsptr = trtmp; return (i); @@ -961,7 +966,7 @@ refclock_ioctl( */ void refclock_control( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct refclockstat *in, struct refclockstat *out ) @@ -974,13 +979,16 @@ 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; - if (!(peer = typeunit[clktype][unit])) + peer = typeunit[clktype][unit]; + if (peer == NULL) return; if (peer->procptr == NULL) return; @@ -995,13 +1003,16 @@ refclock_control( if (in->haveflags & CLK_HAVETIME2) pp->fudgetime2 = in->fudgetime2; if (in->haveflags & CLK_HAVEVAL1) - peer->stratum = (u_char) in->fudgeval1; + pp->stratum = (u_char) in->fudgeval1; if (in->haveflags & CLK_HAVEVAL2) pp->refid = in->fudgeval2; - if (peer->stratum <= 1) + peer->stratum = pp->stratum; + if (peer->stratum == STRATUM_REFCLOCK || peer->stratum == + STRATUM_UNSPEC) peer->refid = pp->refid; else - peer->refid = peer->srcadr.sin_addr.s_addr; + peer->refid = ((struct + sockaddr_in*)&peer->srcadr)->sin_addr.s_addr; if (in->haveflags & CLK_HAVEFLAG1) { pp->sloppyclockflag &= ~CLK_FLAG1; pp->sloppyclockflag |= in->flags & CLK_FLAG1; @@ -1028,7 +1039,7 @@ refclock_control( CLK_HAVEVAL2 | CLK_HAVEFLAG4; out->fudgetime1 = pp->fudgetime1; out->fudgetime2 = pp->fudgetime2; - out->fudgeval1 = peer->stratum; + out->fudgeval1 = pp->stratum; out->fudgeval2 = pp->refid; out->flags = (u_char) pp->sloppyclockflag; @@ -1063,7 +1074,7 @@ refclock_control( */ void refclock_buginfo( - struct sockaddr_in *srcadr, /* clock address */ + struct sockaddr_storage *srcadr, /* clock address */ struct refclockbug *bug /* output structure */ ) { @@ -1076,13 +1087,16 @@ refclock_buginfo( /* * 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; - if (!(peer = typeunit[clktype][unit])) + peer = typeunit[clktype][unit]; + if (peer == NULL) return; pp = peer->procptr; @@ -1096,7 +1110,7 @@ refclock_buginfo( bug->values[2] = pp->hour; bug->values[3] = pp->minute; bug->values[4] = pp->second; - bug->values[5] = pp->msec; + bug->values[5] = pp->nsec; bug->values[6] = pp->yearstart; bug->values[7] = pp->coderecv; bug->stimes = 0xfffffffc; diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c index 260b48b..eacba28 100644 --- a/contrib/ntp/ntpd/ntp_request.c +++ b/contrib/ntp/ntpd/ntp_request.c @@ -1,6 +1,7 @@ /* * ntp_request.c - respond to information requests */ + #ifdef HAVE_CONFIG_H # include #endif @@ -14,6 +15,7 @@ #include "ntp_stdlib.h" #include +#include #include #include #include @@ -31,12 +33,21 @@ #define AUTH 1 #define NO_REQUEST (-1) +/* + * Because we now have v6 addresses in the messages, we need to compensate + * for the larger size. Therefore, we introduce the alternate size to + * keep us friendly with older implementations. A little ugly. + */ +static int client_v6_capable = 0; /* the client can handle longer messages */ + +#define v6sizeof(type) (client_v6_capable ? sizeof(type) : v4sizeof(type)) struct req_proc { short request_code; /* defined request code */ short needs_auth; /* true when authentication needed */ - short sizeofitem; /* size of request data item */ - void (*handler) P((struct sockaddr_in *, struct interface *, + 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 */ }; @@ -47,105 +58,120 @@ static struct req_proc univ_codes[] = { { NO_REQUEST, NOAUTH, 0, 0 } }; -static void req_ack P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); -static char * prepare_pkt P((struct sockaddr_in *, struct interface *, struct req_pkt *, u_int)); +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_in *, struct interface *, struct req_pkt *)); -static void peer_list_sum P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void peer_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void peer_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void sys_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void sys_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void mem_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void io_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void timer_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void loop_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void dns_a P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_conf P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_unconf P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void set_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void clr_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, u_long)); -static void list_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_resaddflags P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_ressubflags P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_unrestrict P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); -static void mon_getlist_0 P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void mon_getlist_1 P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void reset_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void reset_peer P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_key_reread P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void trust_key P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void untrust_key P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_trustkey P((struct sockaddr_in *, struct interface *, struct req_pkt *, u_long)); -static void get_auth_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +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_in *, struct interface *, struct req_pkt *)); -static void req_set_trap P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void req_clr_trap P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void do_setclr_trap P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); -static void set_request_keyid P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void set_control_keyid P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void get_ctl_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +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 *)); #ifdef KERNEL_PLL -static void get_kernel_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void get_kernel_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); #endif /* KERNEL_PLL */ #ifdef REFCLOCK -static void get_clock_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); -static void set_clock_fudge P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +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 *)); #endif /* REFCLOCK */ #ifdef REFCLOCK -static void get_clkbug_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void get_clkbug_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); #endif /* REFCLOCK */ /* * ntpd request codes */ static struct req_proc ntp_codes[] = { - { REQ_PEER_LIST, NOAUTH, 0, peer_list }, - { REQ_PEER_LIST_SUM, NOAUTH, 0, peer_list_sum }, - { REQ_PEER_INFO, NOAUTH, sizeof(struct info_peer_list), peer_info }, - { REQ_PEER_STATS, NOAUTH, sizeof(struct info_peer_list), peer_stats }, - { REQ_SYS_INFO, NOAUTH, 0, sys_info }, - { REQ_SYS_STATS, NOAUTH, 0, sys_stats }, - { REQ_IO_STATS, NOAUTH, 0, io_stats }, - { REQ_MEM_STATS, NOAUTH, 0, mem_stats }, - { REQ_LOOP_INFO, NOAUTH, 0, loop_info }, - { REQ_TIMER_STATS, NOAUTH, 0, timer_stats }, - { REQ_HOSTNAME_ASSOCID, AUTH, sizeof(struct info_dns_assoc), dns_a }, - { REQ_CONFIG, AUTH, sizeof(struct conf_peer), do_conf }, - { REQ_UNCONFIG, AUTH, sizeof(struct conf_unpeer), do_unconf }, - { REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), set_sys_flag }, - { REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), clr_sys_flag }, - { REQ_GET_RESTRICT, NOAUTH, 0, list_restrict }, - { REQ_RESADDFLAGS, AUTH, sizeof(struct conf_restrict), do_resaddflags }, - { REQ_RESSUBFLAGS, AUTH, sizeof(struct conf_restrict), do_ressubflags }, - { REQ_UNRESTRICT, AUTH, sizeof(struct conf_restrict), do_unrestrict }, - { REQ_MON_GETLIST, NOAUTH, 0, mon_getlist_0 }, - { REQ_MON_GETLIST_1, NOAUTH, 0, mon_getlist_1 }, - { REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), reset_stats }, - { REQ_RESET_PEER, AUTH, sizeof(struct conf_unpeer), reset_peer }, - { REQ_REREAD_KEYS, AUTH, 0, do_key_reread }, - { REQ_TRUSTKEY, AUTH, sizeof(u_long), trust_key }, - { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), untrust_key }, - { REQ_AUTHINFO, NOAUTH, 0, get_auth_info }, - { REQ_TRAPS, NOAUTH, 0, req_get_traps }, - { REQ_ADD_TRAP, AUTH, sizeof(struct conf_trap), req_set_trap }, - { REQ_CLR_TRAP, AUTH, sizeof(struct conf_trap), req_clr_trap }, - { REQ_REQUEST_KEY, AUTH, sizeof(u_long), set_request_keyid }, - { REQ_CONTROL_KEY, AUTH, sizeof(u_long), set_control_keyid }, - { REQ_GET_CTLSTATS, NOAUTH, 0, get_ctl_stats }, + { REQ_PEER_LIST, NOAUTH, 0, 0, peer_list }, + { REQ_PEER_LIST_SUM, NOAUTH, 0, 0, peer_list_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), + sizeof(struct info_peer_list), peer_stats}, + { REQ_SYS_INFO, NOAUTH, 0, 0, sys_info }, + { REQ_SYS_STATS, NOAUTH, 0, 0, sys_stats }, + { REQ_IO_STATS, NOAUTH, 0, 0, io_stats }, + { REQ_MEM_STATS, NOAUTH, 0, 0, mem_stats }, + { REQ_LOOP_INFO, NOAUTH, 0, 0, loop_info }, + { REQ_TIMER_STATS, NOAUTH, 0, 0, timer_stats }, + { REQ_CONFIG, AUTH, v4sizeof(struct conf_peer), + sizeof(struct conf_peer), do_conf }, + { REQ_UNCONFIG, AUTH, v4sizeof(struct conf_unpeer), + sizeof(struct conf_unpeer), do_unconf }, + { REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), + sizeof(struct conf_sys_flags), set_sys_flag }, + { REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), + sizeof(struct conf_sys_flags), clr_sys_flag }, + { REQ_GET_RESTRICT, NOAUTH, 0, 0, list_restrict }, + { REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict), + sizeof(struct conf_restrict), do_resaddflags }, + { REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict), + 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_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats }, + { REQ_RESET_PEER, AUTH, v4sizeof(struct conf_unpeer), + sizeof(struct conf_unpeer), reset_peer }, + { REQ_REREAD_KEYS, AUTH, 0, 0, do_key_reread }, + { REQ_TRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), trust_key }, + { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key }, + { REQ_AUTHINFO, NOAUTH, 0, 0, get_auth_info }, + { REQ_TRAPS, NOAUTH, 0, 0, req_get_traps }, + { REQ_ADD_TRAP, AUTH, v4sizeof(struct conf_trap), + sizeof(struct conf_trap), req_set_trap }, + { REQ_CLR_TRAP, AUTH, v4sizeof(struct conf_trap), + sizeof(struct conf_trap), req_clr_trap }, + { REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long), + set_request_keyid }, + { REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long), + set_control_keyid }, + { REQ_GET_CTLSTATS, NOAUTH, 0, 0, get_ctl_stats }, #ifdef KERNEL_PLL - { REQ_GET_KERNEL, NOAUTH, 0, get_kernel_info }, + { REQ_GET_KERNEL, NOAUTH, 0, 0, get_kernel_info }, #endif #ifdef REFCLOCK - { REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), get_clock_info }, - { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), set_clock_fudge }, - { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), get_clkbug_info }, + { REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), + get_clock_info }, + { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), + sizeof(struct conf_fudge), set_clock_fudge }, + { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), + get_clkbug_info }, #endif - { NO_REQUEST, NOAUTH, 0, 0 } + { NO_REQUEST, NOAUTH, 0, 0, 0 } }; @@ -185,7 +211,7 @@ static int itemsize; static int databytes; static char exbuf[RESP_DATA_SIZE]; static int usingexbuf; -static struct sockaddr_in *toaddr; +static struct sockaddr_storage *toaddr; static struct interface *frominter; /* @@ -211,7 +237,7 @@ init_request (void) */ static void req_ack( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt, int errcode @@ -241,7 +267,7 @@ req_ack( */ static char * prepare_pkt( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *pkt, u_int structsize @@ -253,7 +279,7 @@ prepare_pkt( #endif /* - * Fill in the implementation, reqest and itemsize fields + * Fill in the implementation, request and itemsize fields * since these won't change. */ rpkt.implementation = pkt->implementation; @@ -380,10 +406,11 @@ process_private( { struct req_pkt *inpkt; struct req_pkt_tail *tailinpkt; - struct sockaddr_in *srcadr; + struct sockaddr_storage *srcadr; struct interface *inter; struct req_proc *proc; int ec; + short temp_size; /* * Initialize pointers, for convenience @@ -410,10 +437,9 @@ 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_MAC) || (++ec, rbufp->recv_length < REQ_LEN_HDR) ) { - msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test %d failed", ec); + msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test %d failed, pkt from %s", ec, stoa(srcadr)); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -425,7 +451,8 @@ process_private( */ if (inpkt->implementation == IMPL_UNIV) proc = univ_codes; - else if (inpkt->implementation == IMPL_XNTPD) + else if ((inpkt->implementation == IMPL_XNTPD) || + (inpkt->implementation == IMPL_XNTPD_OLD)) proc = ntp_codes; else { req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL); @@ -452,6 +479,50 @@ process_private( #endif /* + * If we need data, check to see if we have some. If we + * don't, check to see that there is none (picky, picky). + */ + + /* This part is a bit tricky, we want to be sure that the size + * returned is either the old or the new size. We also can find + * out if the client can accept both types of messages this way. + * + * Handle the exception of REQ_CONFIG. It can have two data sizes. + */ + temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize); + if ((temp_size != proc->sizeofitem && + temp_size != proc->v6_sizeofitem) && + !(inpkt->implementation == IMPL_XNTPD && + inpkt->request == REQ_CONFIG && + temp_size == sizeof(struct old_conf_peer))) { + if (debug > 2) + printf("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))) { + if (debug > 2) + printf("process_private: not enough data\n"); + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + switch (inpkt->implementation) { + case IMPL_XNTPD: + client_v6_capable = 1; + break; + case IMPL_XNTPD_OLD: + client_v6_capable = 0; + break; + default: + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + /* * If we need to authenticate, do so. Note that an * authenticatable packet must include a mac field, must * have used key info_auth_keyid and must have included @@ -463,10 +534,10 @@ process_private( l_fp ftmp; double dtemp; - if (rbufp->recv_length < (REQ_LEN_HDR + + if (rbufp->recv_length < (int)((REQ_LEN_HDR + (INFO_ITEMSIZE(inpkt->mbz_itemsize) * INFO_NITEMS(inpkt->err_nitems)) - + sizeof(struct req_pkt_tail))) { + + sizeof(struct req_pkt_tail)))) { req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); } tailinpkt = (struct req_pkt_tail *)((char *)&rbufp->recv_pkt + @@ -481,9 +552,14 @@ process_private( #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)); + 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", + INFO_IS_AUTH(inpkt->auth_seq), + (u_long)info_auth_keyid, + (u_long)ntohl(tailinpkt->keyid)); #endif req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); return; @@ -494,8 +570,8 @@ process_private( printf("bad pkt length %d\n", rbufp->recv_length); #endif - msyslog(LOG_ERR, "process_private: bad pkt length %d", - rbufp->recv_length); + msyslog(LOG_ERR, "process_private: bad pkt length %d", + rbufp->recv_length); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -503,6 +579,9 @@ process_private( #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 req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); return; @@ -519,6 +598,10 @@ process_private( /* * He's a loser. Tell him. */ +#ifdef DEBUG + if (debug > 4) + printf("xmit/rcv timestamp delta > INFO_TS_MAXSKEW\n"); +#endif req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); return; } @@ -529,36 +612,15 @@ process_private( 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 req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); return; } } - /* - * If we need data, check to see if we have some. If we - * don't, check to see that there is none (picky, picky). - * - * Handle the exception of REQ_CONFIG. It can have two data sizes. - */ - if (INFO_ITEMSIZE(inpkt->mbz_itemsize) != proc->sizeofitem && - !(inpkt->implementation == IMPL_XNTPD && - inpkt->request == REQ_CONFIG && - INFO_ITEMSIZE(inpkt->mbz_itemsize) == sizeof(struct old_conf_peer))) { - msyslog(LOG_ERR, "INFO_ITEMSIZE(inpkt->mbz_itemsize) != proc->sizeofitem: %d != %d", - INFO_ITEMSIZE(inpkt->mbz_itemsize), proc->sizeofitem); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - if (proc->sizeofitem != 0) - if (proc->sizeofitem*INFO_NITEMS(inpkt->err_nitems) - > sizeof(inpkt->data)) { - msyslog(LOG_ERR, "sizeofitem(%d)*NITEMS(%d) > data: %d > %ld", - proc->sizeofitem, INFO_NITEMS(inpkt->err_nitems), - proc->sizeofitem*INFO_NITEMS(inpkt->err_nitems), - (long)sizeof(inpkt->data)); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } #ifdef DEBUG if (debug > 3) printf("process_private: all okay, into handler\n"); @@ -576,7 +638,7 @@ process_private( */ static void peer_list( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -584,26 +646,44 @@ peer_list( register struct info_peer_list *ip; register struct peer *pp; register int i; + register int skip = 0; ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_peer_list)); + v6sizeof(struct info_peer_list)); for (i = 0; i < HASH_SIZE && ip != 0; i++) { pp = peer_hash[i]; while (pp != 0 && ip != 0) { - ip->address = pp->srcadr.sin_addr.s_addr; - ip->port = pp->srcadr.sin_port; - 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 (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; + 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; } } flush_pkt(); @@ -615,7 +695,7 @@ peer_list( */ static void peer_list_sum( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -624,14 +704,14 @@ peer_list_sum( 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 - ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_peer_summary)); + v6sizeof(struct info_peer_summary)); for (i = 0; i < HASH_SIZE && ips != 0; i++) { pp = peer_hash[i]; while (pp != 0 && ips != 0) { @@ -639,46 +719,66 @@ peer_list_sum( if (debug > 3) printf("sum: got one\n"); #endif - ips->dstadr = - (pp->processed) - ? pp->cast_flags == MDF_BCAST - ? pp->dstadr->bcast.sin_addr.s_addr - : pp->cast_flags - ? pp->dstadr->sin.sin_addr.s_addr - ? pp->dstadr->sin.sin_addr.s_addr - : pp->dstadr->bcast.sin_addr.s_addr - : 1 - : 5; - ips->srcadr = pp->srcadr.sin_addr.s_addr; - ips->srcport = pp->srcadr.sin_port; - 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, <mp); - HTONL_FP(<mp, &ips->offset); - ips->dispersion = HTONS_FP(DTOUFP(pp->disp)); - - pp = pp->next; + /* + * 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; + ips->dstadr6 = GET_INADDR6(pp->dstadr->sin); + 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 */ + 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); + + 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_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, <mp); + HTONL_FP(<mp, &ips->offset); + ips->dispersion = HTONS_FP(DTOUFP(pp->disp)); + } + pp = pp->next; ips = (struct info_peer_summary *)more_pkt(); } } @@ -691,7 +791,7 @@ peer_list_sum( */ static void peer_info ( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -701,33 +801,53 @@ peer_info ( register struct info_peer *ip; register int items; register int i, j; - struct sockaddr_in addr; + struct sockaddr_storage addr; extern struct peer *sys_peer; l_fp ltmp; memset((char *)&addr, 0, sizeof addr); - addr.sin_family = AF_INET; items = INFO_NITEMS(inpkt->err_nitems); ipl = (struct info_peer_list *) inpkt->data; + ip = (struct info_peer *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_peer)); + v6sizeof(struct info_peer)); while (items-- > 0 && ip != 0) { - addr.sin_port = ipl->port; - addr.sin_addr.s_addr = ipl->address; + 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; + } else { + addr.ss_family = AF_INET; + GET_INADDR(addr) = ipl->addr; + } +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + addr.ss_len = SOCKLEN(&addr); +#endif ipl++; if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0) continue; - ip->dstadr = - (pp->processed) - ? pp->cast_flags == MDF_BCAST - ? pp->dstadr->bcast.sin_addr.s_addr - : pp->cast_flags - ? pp->dstadr->sin.sin_addr.s_addr - ? pp->dstadr->sin.sin_addr.s_addr - : pp->dstadr->bcast.sin_addr.s_addr - : 2 - : 6; - ip->srcadr = NSRCADR(&pp->srcadr); + if (pp->srcadr.ss_family == AF_INET6) { + ip->dstadr6 = pp->cast_flags == MDF_BCAST ? + GET_INADDR6(pp->dstadr->bcast) : + GET_INADDR6(pp->dstadr->sin); + ip->srcadr6 = GET_INADDR6(pp->srcadr); + ip->v6_flag = 1; + } else { +/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */ + 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); + + ip->srcadr = GET_INADDR(pp->srcadr); + if (client_v6_capable) + ip->v6_flag = 0; + } ip->srcport = NSRCPORT(&pp->srcadr); ip->flags = 0; if (pp == sys_peer) @@ -755,9 +875,9 @@ peer_info ( ip->precision = pp->precision; ip->version = pp->version; ip->reach = pp->reach; - ip->unreach = pp->unreach; + ip->unreach = (u_char) pp->unreach; ip->flash = (u_char)pp->flash; - ip->flash2 = pp->flash; + ip->flash2 = (u_short) pp->flash; ip->estbdelay = HTONS_FP(DTOFP(pp->estbdelay)); ip->ttl = pp->ttl; ip->associd = htons(pp->associd); @@ -775,8 +895,8 @@ peer_info ( ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j])); DTOLFP(pp->filter_offset[j], <mp); HTONL_FP(<mp, &ip->filtoffset[i]); - ip->order[i] = (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; } @@ -796,7 +916,7 @@ peer_info ( */ static void peer_stats ( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -805,32 +925,54 @@ peer_stats ( register struct peer *pp; register struct info_peer_stats *ip; register int items; - struct sockaddr_in addr; + struct sockaddr_storage addr; extern struct peer *sys_peer; - memset((char *)&addr, 0, sizeof addr); - addr.sin_family = AF_INET; + printf("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, - sizeof(struct info_peer_stats)); + v6sizeof(struct info_peer_stats)); while (items-- > 0 && ip != 0) { - addr.sin_port = ipl->port; - addr.sin_addr.s_addr = ipl->address; - ipl++; + 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; + } else { + addr.ss_family = AF_INET; + GET_INADDR(addr) = ipl->addr; + } +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + addr.ss_len = SOCKLEN(&addr); +#endif + printf("peer_stats: looking for %s, %d, %d\n", stoa(&addr), + ipl->port, ((struct sockaddr_in6 *)&addr)->sin6_port); + ipl = (struct info_peer_list *)((char *)ipl + + INFO_ITEMSIZE(inpkt->mbz_itemsize)); + if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0) continue; - ip->dstadr = - (pp->processed) - ? pp->cast_flags == MDF_BCAST - ? pp->dstadr->bcast.sin_addr.s_addr - : pp->cast_flags - ? pp->dstadr->sin.sin_addr.s_addr - ? pp->dstadr->sin.sin_addr.s_addr - : pp->dstadr->bcast.sin_addr.s_addr - : 3 - : 7; - ip->srcadr = NSRCADR(&pp->srcadr); + printf("peer_stats: found %s\n", stoa(&addr)); + if (pp->srcadr.ss_family == AF_INET) { + 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; + ip->srcadr = GET_INADDR(pp->srcadr); + if (client_v6_capable) + ip->v6_flag = 0; + } else { + ip->dstadr6 = pp->cast_flags == MDF_BCAST ? + GET_INADDR6(pp->dstadr->bcast): + GET_INADDR6(pp->dstadr->sin); + ip->srcadr6 = GET_INADDR6(pp->srcadr); + ip->v6_flag = 1; + } ip->srcport = NSRCPORT(&pp->srcadr); ip->flags = 0; if (pp == sys_peer) @@ -871,7 +1013,7 @@ peer_stats ( */ static void sys_info( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -897,15 +1039,26 @@ sys_info( extern double sys_jitter; is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_sys)); + v6sizeof(struct info_sys)); if (sys_peer != 0) { - is->peer = NSRCADR(&sys_peer->srcadr); + if (sys_peer->srcadr.ss_family == AF_INET) { + is->peer = GET_INADDR(sys_peer->srcadr); + if (client_v6_capable) + is->v6_flag = 0; + } else if (client_v6_capable) { + is->peer6 = GET_INADDR6(sys_peer->srcadr); + is->v6_flag = 1; + } is->peer_mode = sys_peer->hmode; } else { is->peer = 0; + if (client_v6_capable) { + is->v6_flag = 0; + } is->peer_mode = 0; } + is->leap = sys_leap; is->stratum = sys_stratum; is->precision = sys_precision; @@ -950,7 +1103,7 @@ sys_info( */ static void sys_stats( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -960,22 +1113,11 @@ sys_stats( /* * Importations from the protocol module */ - extern u_long sys_stattime; - extern u_long sys_badstratum; - extern u_long sys_oldversionpkt; - extern u_long sys_newversionpkt; - extern u_long sys_unknownversion; - extern u_long sys_badlength; - extern u_long sys_processed; - extern u_long sys_badauth; - extern u_long sys_limitrejected; - ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_sys_stats)); - + sizeof(struct info_sys_stats)); ss->timeup = htonl((u_int32)current_time); ss->timereset = htonl((u_int32)(current_time - sys_stattime)); - ss->badstratum = htonl((u_int32)sys_badstratum); + 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); @@ -983,6 +1125,7 @@ sys_stats( ss->processed = htonl((u_int32)sys_processed); ss->badauth = htonl((u_int32)sys_badauth); ss->limitrejected = htonl((u_int32)sys_limitrejected); + ss->received = htonl((u_int32)sys_received); (void) more_pkt(); flush_pkt(); } @@ -993,7 +1136,7 @@ sys_stats( */ static void mem_stats( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1039,7 +1182,7 @@ mem_stats( */ static void io_stats( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1077,7 +1220,7 @@ io_stats( */ static void timer_stats( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1109,7 +1252,7 @@ timer_stats( */ static void loop_info( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1145,50 +1288,44 @@ loop_info( */ static void do_conf( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) { - u_int fl; - struct conf_peer *cp; - struct old_conf_peer *ocp; int items; - struct sockaddr_in peeraddr; + u_int fl; + struct conf_peer *cp; + struct conf_peer temp_cp; + struct sockaddr_storage peeraddr; + struct sockaddr_in tmp_clock; /* * Do a check of everything to see that it looks * okay. If not, complain about it. Note we are * very picky here. */ - ocp = NULL; - if (INFO_ITEMSIZE(inpkt->mbz_itemsize) == sizeof(struct old_conf_peer)) - ocp = (struct old_conf_peer *)inpkt->data; 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 (((cp->version) > NTP_VERSION) - || ((cp->version) < NTP_OLDVERSION)) + if (((temp_cp.version) > NTP_VERSION) + || ((temp_cp.version) < NTP_OLDVERSION)) fl = 1; - if (cp->hmode != MODE_ACTIVE - && cp->hmode != MODE_CLIENT - && cp->hmode != MODE_BROADCAST) + if (temp_cp.hmode != MODE_ACTIVE + && temp_cp.hmode != MODE_CLIENT + && temp_cp.hmode != MODE_BROADCAST) fl = 1; - if (cp->flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER | - CONF_FLAG_NOSELECT | CONF_FLAG_BURST | CONF_FLAG_IBURST | - CONF_FLAG_SKEY)) + if (temp_cp.flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER + | CONF_FLAG_BURST | CONF_FLAG_SKEY)) fl = 1; - if (ocp) { - ocp++; - cp = (struct conf_peer *)ocp; - } else - cp++; + cp = (struct conf_peer *) + ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } if (fl) { - msyslog(LOG_ERR, "do_conf: fl is nonzero!"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1197,69 +1334,70 @@ do_conf( * Looks okay, try it out */ items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_peer *)inpkt->data; - if (ocp) - ocp = (struct old_conf_peer *)inpkt->data; - memset((char *)&peeraddr, 0, sizeof(struct sockaddr_in)); - peeraddr.sin_family = AF_INET; - peeraddr.sin_port = htons(NTP_PORT); + cp = (struct conf_peer *)inpkt->data; - /* - * Make sure the address is valid - */ - if ( + 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)); + + 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; + 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; + } else { + peeraddr.ss_family = AF_INET; + GET_INADDR(peeraddr) = temp_cp.peeraddr; + /* + * Make sure the address is valid + */ + tmp_clock = *CAST_V4(peeraddr); + if ( #ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && + !ISREFCLOCKADR(&tmp_clock) && #endif - ISBADADR(&peeraddr)) { -#ifdef REFCLOCK - msyslog(LOG_ERR, "do_conf: !ISREFCLOCK && ISBADADR"); -#else - msyslog(LOG_ERR, "do_conf: ISBADADR"); + ISBADADR(&tmp_clock)) { + 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); #endif - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - while (items-- > 0) { - fl = 0; - if (cp->flags & CONF_FLAG_AUTHENABLE) - fl |= FLAG_AUTHENABLE; - if (cp->flags & CONF_FLAG_PREFER) - fl |= FLAG_PREFER; - if (cp->flags & CONF_FLAG_NOSELECT) - fl |= FLAG_NOSELECT; - if (cp->flags & CONF_FLAG_BURST) - fl |= FLAG_BURST; - if (cp->flags & CONF_FLAG_IBURST) - fl |= FLAG_IBURST; - if (cp->flags & CONF_FLAG_SKEY) - fl |= FLAG_SKEY; - peeraddr.sin_addr.s_addr = cp->peeraddr; /* XXX W2DO? minpoll/maxpoll arguments ??? */ - if (peer_config(&peeraddr, any_interface, cp->hmode, - cp->version, cp->minpoll, cp->maxpoll, fl, cp->ttl, - cp->keyid, NULL) == 0) { + if (peer_config(&peeraddr, (struct interface *)0, + temp_cp.hmode, temp_cp.version, temp_cp.minpoll, + temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid, + NULL) == 0) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; } - if (ocp) { - ocp++; - cp = (struct conf_peer *)ocp; - } else - cp++; + cp = (struct conf_peer *) + ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } 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_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1326,9 +1464,10 @@ dns_a( } msyslog(LOG_INFO, "dns_a: <%s> for %s, AssocID %d, bogon %d", - dp->hostname, inet_ntoa(peeraddr.sin_addr), associd, + dp->hostname, + stoa((struct sockaddr_storage *)&peeraddr), associd, bogon); - + if (bogon) { /* If it didn't work */ req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); @@ -1340,28 +1479,29 @@ dns_a( #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_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) { register struct conf_unpeer *cp; + struct conf_unpeer temp_cp; register int items; register struct peer *peer; - struct sockaddr_in peeraddr; + struct sockaddr_storage peeraddr; int bad, found; /* @@ -1370,17 +1510,28 @@ do_unconf( * configured. If so, we remove them. If not, we return * an error. */ - peeraddr.sin_family = AF_INET; - peeraddr.sin_port = htons(NTP_PORT); - items = INFO_NITEMS(inpkt->err_nitems); cp = (struct conf_unpeer *)inpkt->data; bad = 0; while (items-- > 0 && !bad) { - peeraddr.sin_addr.s_addr = cp->peeraddr; + 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; + } else { + peeraddr.ss_family = AF_INET; + GET_INADDR(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; + printf("searching for %s\n", stoa(&peeraddr)); while (!found) { peer = findexistingpeer(&peeraddr, peer, -1); if (peer == (struct peer *)0) @@ -1390,7 +1541,8 @@ do_unconf( } if (!found) bad = 1; - cp++; + cp = (struct conf_unpeer *) + ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } if (bad) { @@ -1405,9 +1557,23 @@ do_unconf( items = INFO_NITEMS(inpkt->err_nitems); cp = (struct conf_unpeer *)inpkt->data; while (items-- > 0) { - peeraddr.sin_addr.s_addr = cp->peeraddr; + 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; + } else { + peeraddr.ss_family = AF_INET; + GET_INADDR(peeraddr) = temp_cp.peeraddr; + } + NSRCPORT(&peeraddr) = htons(NTP_PORT); +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + peeraddr.ss_len = SOCKLEN(&peeraddr); +#endif peer_unconfig(&peeraddr, (struct interface *)0, -1); - cp++; + cp = (struct conf_unpeer *) + ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } req_ack(srcadr, inter, inpkt, INFO_OKAY); @@ -1419,7 +1585,7 @@ do_unconf( */ static void set_sys_flag( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1433,7 +1599,7 @@ set_sys_flag( */ static void clr_sys_flag( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1447,7 +1613,7 @@ clr_sys_flag( */ static void setclr_flags( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt, u_long set @@ -1467,7 +1633,7 @@ setclr_flags( SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) { msyslog(LOG_ERR, "setclr_flags: extra flags: %#x", - flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | + flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)); @@ -1476,21 +1642,21 @@ setclr_flags( } if (flags & SYS_FLAG_BCLIENT) - proto_config(PROTO_BROADCLIENT, set, 0.); + proto_config(PROTO_BROADCLIENT, set, 0., NULL); if (flags & SYS_FLAG_PPS) - proto_config(PROTO_PPS, set, 0.); + proto_config(PROTO_PPS, set, 0., NULL); if (flags & SYS_FLAG_NTP) - proto_config(PROTO_NTP, set, 0.); + proto_config(PROTO_NTP, set, 0., NULL); if (flags & SYS_FLAG_KERNEL) - proto_config(PROTO_KERNEL, set, 0.); + proto_config(PROTO_KERNEL, set, 0., NULL); if (flags & SYS_FLAG_MONITOR) - proto_config(PROTO_MONITOR, set, 0.); + proto_config(PROTO_MONITOR, set, 0., NULL); if (flags & SYS_FLAG_FILEGEN) - proto_config(PROTO_FILEGEN, set, 0.); + proto_config(PROTO_FILEGEN, set, 0., NULL); if (flags & SYS_FLAG_AUTH) - proto_config(PROTO_AUTHENTICATE, set, 0.); + proto_config(PROTO_AUTHENTICATE, set, 0., NULL); if (flags & SYS_FLAG_CAL) - proto_config(PROTO_CAL, set, 0.); + proto_config(PROTO_CAL, set, 0., NULL); req_ack(srcadr, inter, inpkt, INFO_OKAY); } @@ -1500,30 +1666,43 @@ setclr_flags( */ static void list_restrict( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) { register struct info_restrict *ir; register struct restrictlist *rl; - extern struct restrictlist *restrictlist; + register struct restrictlist6 *rl6; #ifdef DEBUG if (debug > 2) - printf("wants peer list summary\n"); + printf("wants restrict list summary\n"); #endif ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_restrict)); + 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(); } + 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(); + } flush_pkt(); } @@ -1534,7 +1713,7 @@ list_restrict( */ static void do_resaddflags( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1549,7 +1728,7 @@ do_resaddflags( */ static void do_ressubflags( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1563,7 +1742,7 @@ do_ressubflags( */ static void do_unrestrict( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1580,7 +1759,7 @@ do_unrestrict( */ static void do_restrict( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt, int op @@ -1588,8 +1767,8 @@ do_restrict( { register struct conf_restrict *cr; register int items; - struct sockaddr_in matchaddr; - struct sockaddr_in matchmask; + struct sockaddr_storage matchaddr; + struct sockaddr_storage matchmask; int bad; /* @@ -1606,9 +1785,16 @@ do_restrict( bad |= 1; if (cr->flags & ~(RES_ALLFLAGS)) bad |= 2; - if (cr->addr == htonl(INADDR_ANY) && cr->mask != htonl(INADDR_ANY)) - bad |= 4; - cr++; + if (cr->mask != htonl(INADDR_ANY)) { + if (client_v6_capable && cr->v6_flag != 0) { + if (IN6_IS_ADDR_UNSPECIFIED(&cr->addr6)) + bad |= 4; + } else + if (cr->addr == htonl(INADDR_ANY)) + bad |= 8; + } + cr = (struct conf_restrict *)((char *)cr + + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } if (bad) { @@ -1622,14 +1808,21 @@ do_restrict( */ items = INFO_NITEMS(inpkt->err_nitems); cr = (struct conf_restrict *)inpkt->data; - memset((char *)&matchaddr, 0, sizeof(struct sockaddr_in)); - memset((char *)&matchmask, 0, sizeof(struct sockaddr_in)); - matchaddr.sin_family = AF_INET; - matchmask.sin_family = AF_INET; + memset((char *)&matchaddr, 0, sizeof(struct sockaddr_storage)); + memset((char *)&matchmask, 0, sizeof(struct sockaddr_storage)); while (items-- > 0) { - matchaddr.sin_addr.s_addr = cr->addr; - matchmask.sin_addr.s_addr = cr->mask; + 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; + } else { + GET_INADDR(matchaddr) = cr->addr; + GET_INADDR(matchmask) = cr->mask; + matchaddr.ss_family = AF_INET; + matchmask.ss_family = AF_INET; + } hack_restrict(op, &matchaddr, &matchmask, cr->mflags, cr->flags); cr++; @@ -1644,7 +1837,7 @@ do_restrict( */ static void mon_getlist_0( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1662,19 +1855,24 @@ mon_getlist_0( req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; } - im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_monitor)); + 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)(current_time - md->lasttime)); - im->firsttime = htonl((u_int32)(current_time - md->firsttime)); - if (md->lastdrop) - im->lastdrop = htonl((u_int32)(current_time - md->lastdrop)); - else - im->lastdrop = 0; + 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)); - im->addr = md->rmtadr; + 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; @@ -1688,7 +1886,7 @@ mon_getlist_0( */ static void mon_getlist_1( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1698,36 +1896,36 @@ mon_getlist_1( extern struct mon_data mon_mru_list; extern int mon_enabled; -#ifdef DEBUG - if (debug > 2) - printf("wants monitor 1 list\n"); -#endif if (!mon_enabled) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; } - im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_monitor_1)); + 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)(current_time - md->lasttime)); - im->firsttime = htonl((u_int32)(current_time - md->firsttime)); - if (md->lastdrop) - im->lastdrop = htonl((u_int32)(current_time - md->lastdrop)); - else - im->lastdrop = 0; + 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); - im->addr = md->rmtadr; - im->daddr = - (md->cast_flags == MDF_BCAST) - ? md->interface->bcast.sin_addr.s_addr - : (md->cast_flags - ? (md->interface->sin.sin_addr.s_addr - ? md->interface->sin.sin_addr.s_addr - : md->interface->bcast.sin_addr.s_addr - ) - : 4); + 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 = md->cast_flags; im->port = md->rmtport; im->mode = md->mode; @@ -1761,7 +1959,7 @@ struct reset_entry reset_entries[] = { */ static void reset_stats( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1797,7 +1995,7 @@ reset_stats( */ static void reset_peer( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1805,26 +2003,36 @@ reset_peer( register struct conf_unpeer *cp; register int items; register struct peer *peer; - struct sockaddr_in peeraddr; + struct sockaddr_storage peeraddr; int bad; /* * We check first to see that every peer exists. If not, * we return an error. */ - peeraddr.sin_family = AF_INET; - peeraddr.sin_port = htons(NTP_PORT); items = INFO_NITEMS(inpkt->err_nitems); cp = (struct conf_unpeer *)inpkt->data; bad = 0; while (items-- > 0 && !bad) { - peeraddr.sin_addr.s_addr = cp->peeraddr; + memset((char *)&peeraddr, 0, sizeof(peeraddr)); + if (client_v6_capable && cp->v6_flag != 0) { + GET_INADDR6(peeraddr) = cp->peeraddr6; + peeraddr.ss_family = AF_INET6; + } else { + GET_INADDR(peeraddr) = cp->peeraddr; + peeraddr.ss_family = AF_INET; + } + NSRCPORT(&peeraddr) = htons(NTP_PORT); +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + peeraddr.ss_len = SOCKLEN(&peeraddr); +#endif peer = findexistingpeer(&peeraddr, (struct peer *)0, -1); if (peer == (struct peer *)0) bad++; - cp++; + cp = (struct conf_unpeer *)((char *)cp + + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } if (bad) { @@ -1839,13 +2047,24 @@ reset_peer( items = INFO_NITEMS(inpkt->err_nitems); cp = (struct conf_unpeer *)inpkt->data; while (items-- > 0) { - peeraddr.sin_addr.s_addr = cp->peeraddr; + memset((char *)&peeraddr, 0, sizeof(peeraddr)); + if (client_v6_capable && cp->v6_flag != 0) { + GET_INADDR6(peeraddr) = cp->peeraddr6; + peeraddr.ss_family = AF_INET6; + } else { + GET_INADDR(peeraddr) = cp->peeraddr; + peeraddr.ss_family = AF_INET; + } +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + peeraddr.ss_len = SOCKLEN(&peeraddr); +#endif peer = findexistingpeer(&peeraddr, (struct peer *)0, -1); while (peer != 0) { peer_reset(peer); peer = findexistingpeer(&peeraddr, (struct peer *)peer, -1); } - cp++; + cp = (struct conf_unpeer *)((char *)cp + + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } req_ack(srcadr, inter, inpkt, INFO_OKAY); @@ -1857,7 +2076,7 @@ reset_peer( */ static void do_key_reread( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1872,7 +2091,7 @@ do_key_reread( */ static void trust_key( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1886,7 +2105,7 @@ trust_key( */ static void untrust_key( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1900,7 +2119,7 @@ untrust_key( */ static void do_trustkey( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt, u_long trust @@ -1925,7 +2144,7 @@ do_trustkey( */ static void get_auth_info( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -1993,7 +2212,7 @@ reset_auth_stats(void) */ static void req_get_traps( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2014,16 +2233,27 @@ req_get_traps( } it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_trap)); + v6sizeof(struct info_trap)); for (i = 0, tr = ctl_trap; i < CTL_MAXTRAPS; i++, tr++) { if (tr->tr_flags & TRAP_INUSE) { - if (tr->tr_localaddr == any_interface) - it->local_address = 0; - else - it->local_address - = NSRCADR(&tr->tr_localaddr->sin); - it->trap_address = NSRCADR(&tr->tr_addr); + if (tr->tr_addr.ss_family == AF_INET) { + 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); + 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); + it->v6_flag = 1; + } it->trap_port = NSRCPORT(&tr->tr_addr); it->sequence = htons(tr->tr_sequence); it->settime = htonl((u_int32)(current_time - tr->tr_settime)); @@ -2042,7 +2272,7 @@ req_get_traps( */ static void req_set_trap( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2057,7 +2287,7 @@ req_set_trap( */ static void req_clr_trap( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2072,7 +2302,7 @@ req_clr_trap( */ static void do_setclr_trap( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt, int set @@ -2081,14 +2311,14 @@ do_setclr_trap( register struct conf_trap *ct; register struct interface *linter; int res; - struct sockaddr_in laddr; + struct sockaddr_storage laddr; /* - * Prepare sockaddr_in structure + * Prepare sockaddr_storage structure */ memset((char *)&laddr, 0, sizeof laddr); - laddr.sin_family = AF_INET; - laddr.sin_port = ntohs(NTP_PORT); + laddr.ss_family = srcadr->ss_family; + NSRCPORT(&laddr) = ntohs(NTP_PORT); /* * Restrict ourselves to one item only. This eliminates @@ -2107,7 +2337,10 @@ do_setclr_trap( if (ct->local_address == 0) { linter = any_interface; } else { - laddr.sin_addr.s_addr = ct->local_address; + if (laddr.ss_family == AF_INET) + GET_INADDR(laddr) = ct->local_address; + else + GET_INADDR6(laddr) = ct->local_address6; linter = findinterface(&laddr); if (linter == NULL) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); @@ -2115,11 +2348,14 @@ do_setclr_trap( } } - laddr.sin_addr.s_addr = ct->trap_address; + if (laddr.ss_family == AF_INET) + GET_INADDR(laddr) = ct->trap_address; + else + GET_INADDR6(laddr) = ct->trap_address6; if (ct->trap_port != 0) - laddr.sin_port = ct->trap_port; + NSRCPORT(&laddr) = ct->trap_port; else - laddr.sin_port = htons(TRAPPORT); + NSRCPORT(&laddr) = htons(TRAPPORT); if (set) { res = ctlsettrap(&laddr, linter, 0, @@ -2143,7 +2379,7 @@ do_setclr_trap( */ static void set_request_keyid( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2171,7 +2407,7 @@ set_request_keyid( */ static void set_control_keyid( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2200,7 +2436,7 @@ set_control_keyid( */ static void get_ctl_stats( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2256,7 +2492,7 @@ get_ctl_stats( */ static void get_kernel_info( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2311,7 +2547,7 @@ get_kernel_info( */ static void get_clock_info( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2320,12 +2556,16 @@ get_clock_info( register u_int32 *clkaddr; register int items; struct refclockstat clock_stat; - struct sockaddr_in addr; + struct sockaddr_storage addr; + struct sockaddr_in tmp_clock; l_fp ltmp; memset((char *)&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - addr.sin_port = htons(NTP_PORT); + addr.ss_family = AF_INET; +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + addr.ss_len = SOCKLEN(&addr); +#endif + NSRCPORT(&addr) = htons(NTP_PORT); items = INFO_NITEMS(inpkt->err_nitems); clkaddr = (u_int32 *) inpkt->data; @@ -2333,8 +2573,9 @@ get_clock_info( sizeof(struct info_clock)); while (items-- > 0) { - addr.sin_addr.s_addr = *clkaddr++; - if (!ISREFCLOCKADR(&addr) || + 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) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; @@ -2344,7 +2585,7 @@ get_clock_info( refclock_control(&addr, (struct refclockstat *)0, &clock_stat); - ic->clockadr = addr.sin_addr.s_addr; + ic->clockadr = tmp_clock.sin_addr.s_addr; ic->type = clock_stat.type; ic->flags = clock_stat.flags; ic->lastevent = clock_stat.lastevent; @@ -2356,7 +2597,7 @@ get_clock_info( ic->timestarted = htonl((u_int32)clock_stat.timereset); DTOLFP(clock_stat.fudgetime1, <mp); HTONL_FP(<mp, &ic->fudgetime1); - DTOLFP(clock_stat.fudgetime1, <mp); + DTOLFP(clock_stat.fudgetime2, <mp); HTONL_FP(<mp, &ic->fudgetime2); ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1); ic->fudgeval2 = htonl((u_int32)clock_stat.fudgeval2); @@ -2375,7 +2616,7 @@ get_clock_info( */ static void set_clock_fudge( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2383,19 +2624,24 @@ set_clock_fudge( register struct conf_fudge *cf; register int items; struct refclockstat clock_stat; - struct sockaddr_in addr; + struct sockaddr_storage addr; + struct sockaddr_in tmp_clock; l_fp ltmp; memset((char *)&addr, 0, sizeof addr); memset((char *)&clock_stat, 0, sizeof clock_stat); - addr.sin_family = AF_INET; - addr.sin_port = htons(NTP_PORT); items = INFO_NITEMS(inpkt->err_nitems); cf = (struct conf_fudge *) inpkt->data; while (items-- > 0) { - addr.sin_addr.s_addr = cf->clockadr; - if (!ISREFCLOCKADR(&addr) || + 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); +#endif + NSRCPORT(&addr) = htons(NTP_PORT); + if (!ISREFCLOCKADR(&tmp_clock) || findexistingpeer(&addr, (struct peer *)0, -1) == 0) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; @@ -2421,7 +2667,7 @@ set_clock_fudge( clock_stat.haveflags = CLK_HAVEVAL2; break; case FUDGE_FLAGS: - clock_stat.flags = (u_char) ntohl(cf->fudgeval_flags) & 0xf; + clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf); clock_stat.haveflags = (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4); break; @@ -2444,7 +2690,7 @@ set_clock_fudge( */ static void get_clkbug_info( - struct sockaddr_in *srcadr, + struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt ) @@ -2454,11 +2700,15 @@ get_clkbug_info( register u_int32 *clkaddr; register int items; struct refclockbug bug; - struct sockaddr_in addr; + struct sockaddr_storage addr; + struct sockaddr_in tmp_clock; memset((char *)&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - addr.sin_port = htons(NTP_PORT); + addr.ss_family = AF_INET; +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + addr.ss_len = SOCKLEN(&addr); +#endif + NSRCPORT(&addr) = htons(NTP_PORT); items = INFO_NITEMS(inpkt->err_nitems); clkaddr = (u_int32 *) inpkt->data; @@ -2466,8 +2716,9 @@ get_clkbug_info( sizeof(struct info_clkbug)); while (items-- > 0) { - addr.sin_addr.s_addr = *clkaddr++; - if (!ISREFCLOCKADR(&addr) || + 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) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; @@ -2480,7 +2731,7 @@ get_clkbug_info( return; } - ic->clockadr = addr.sin_addr.s_addr; + ic->clockadr = tmp_clock.sin_addr.s_addr; i = bug.nvalues; if (i > NUMCBUGVALUES) i = NUMCBUGVALUES; diff --git a/contrib/ntp/ntpd/ntp_restrict.c b/contrib/ntp/ntpd/ntp_restrict.c index 0e5b9dc..ede4225 100644 --- a/contrib/ntp/ntpd/ntp_restrict.c +++ b/contrib/ntp/ntpd/ntp_restrict.c @@ -1,5 +1,5 @@ /* - * ntp_restrict.c - find out what restrictions this host is running under + * ntp_restrict.c - determine host restrictions */ #ifdef HAVE_CONFIG_H #include @@ -14,28 +14,41 @@ /* * This code keeps a simple address-and-mask list of hosts we want - * to place restrictions on (or remove them from). The restrictions + * to place restrictions on (or remove them from). The restrictions * are implemented as a set of flags which tell you what the host - * can't do. There is a subroutine entry to return the flags. The + * can't do. There is a subroutine entry to return the flags. The * list is kept sorted to reduce the average number of comparisons * and make sure you get the set of restrictions most specific to * the address. * * The algorithm is that, when looking up a host, it is first assumed - * that the default set of restrictions will apply. It then searches - * down through the list. Whenever it finds a match it adopts the match's - * flags instead. When you hit the point where the sorted address is - * greater than the target, you return with the last set of flags you - * found. Because of the ordering of the list, the most specific match - * will provide the final set of flags. + * that the default set of restrictions will apply. It then searches + * down through the list. Whenever it finds a match it adopts the + * match's flags instead. When you hit the point where the sorted + * address is greater than the target, you return with the last set of + * flags you found. Because of the ordering of the list, the most + * specific match will provide the final set of flags. * * This was originally intended to restrict you from sync'ing to your - * own broadcasts when you are doing that, by restricting yourself - * from your own interfaces. It was also thought it would sometimes - * be useful to keep a misbehaving host or two from abusing your primary - * clock. It has been expanded, however, to suit the needs of those - * with more restrictive access policies. + * own broadcasts when you are doing that, by restricting yourself from + * your own interfaces. It was also thought it would sometimes be useful + * to keep a misbehaving host or two from abusing your primary clock. It + * has been expanded, however, to suit the needs of those with more + * restrictive access policies. */ +/* + * We will use two lists, one for IPv4 addresses and one for IPv6 + * 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]); \ + } \ + } while (0) /* * Memory allocation parameters. We allocate INITRESLIST entries @@ -45,43 +58,48 @@ #define INITRESLIST 10 #define INCRESLIST 5 +#define RES_AVG 8. /* interpacket averaging factor */ + /* * The restriction list */ struct restrictlist *restrictlist; -static int restrictcount; /* count of entries in the restriction list */ +struct restrictlist6 *restrictlist6; +static int restrictcount; /* count of entries in the res list */ +static int restrictcount6; /* count of entries in the res list 2*/ /* * 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 u_long res_calls; static u_long res_found; static u_long res_not_found; -/* static u_long res_timereset; */ /* * Parameters of the RES_LIMITED restriction option. - * client_limit is the number of hosts allowed per source net - * client_limit_period is the number of seconds after which an entry - * is no longer considered for client limit determination */ -u_long client_limit; -u_long client_limit_period; +u_long res_avg_interval = 5; /* min average interpacket interval */ +u_long res_min_interval = 1; /* min interpacket interval */ + /* - * count number of restriction entries referring to RES_LIMITED - * controls activation/deactivation of monitoring - * (with respect to RES_LIMITED control) + * Count number of restriction entries referring to RES_LIMITED controls + * activation/deactivation of monitoring (with respect to RES_LIMITED + * control) */ static u_long res_limited_refcnt; +static u_long res_limited_refcnt6; /* - * Our initial allocation of list entries. + * Our initial allocation of lists entries. */ static struct restrictlist resinit[INITRESLIST]; +static struct restrictlist6 resinit6[INITRESLIST]; /* * init_restrict - initialize the restriction data structures @@ -90,31 +108,35 @@ void init_restrict(void) { register int i; - char bp[80]; /* * Zero the list and put all but one on the free list */ resfree = 0; memset((char *)resinit, 0, sizeof resinit); - + resfree6 = 0; + 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]; } - numresfree = INITRESLIST-1; + numresfree6 = INITRESLIST-1; /* - * Put the remaining item at the head of the - * list as our default entry. Everything in here - * should be zero for now. + * 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 @@ -122,19 +144,12 @@ init_restrict(void) res_calls = 0; res_found = 0; res_not_found = 0; - /* res_timereset = 0; */ /* * set default values for RES_LIMIT functionality */ - client_limit = 3; - client_limit_period = 3600; res_limited_refcnt = 0; - - sprintf(bp, "client_limit=%ld", client_limit); - set_sys_var(bp, strlen(bp)+1, RO); - sprintf(bp, "client_limit_period=%ld", client_limit_period); - set_sys_var(bp, strlen(bp)+1, RO); + res_limited_refcnt6 = 0; } @@ -143,161 +158,131 @@ init_restrict(void) */ int restrictions( - struct sockaddr_in *srcadr + struct sockaddr_storage *srcadr ) { - register struct restrictlist *rl; - register struct restrictlist *match; - register u_int32 hostaddr; - register int isntpport; + 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; res_calls++; - /* - * 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); - - /* - * Ignore any packets with a multicast source address - * (this should be done early in the receive process, later!) - */ - if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) - return (int)RES_IGNORE; + 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); - /* - * Set match to first entry, which is default entry. Work our - * way down from there. - */ - match = restrictlist; - - for (rl = match->next; rl != 0 && 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) - res_not_found++; - else - res_found++; - - /* - * The following implements limiting the number of clients - * accepted from a given network. The notion of "same network" - * is determined by the mask and addr fields of the restrict - * list entry. The monitor mechanism has to be enabled for - * collecting info on current clients. - * - * The policy is as follows: - * - take the list of clients recorded - * from the given "network" seen within the last - * client_limit_period seconds - * - if there are at most client_limit entries: - * --> access allowed - * - otherwise sort by time first seen - * - current client among the first client_limit seen - * hosts? - * if yes: access allowed - * else: eccess denied - */ - if (match->flags & RES_LIMITED) { - int lcnt; - struct mon_data *md, *this_client; - -#ifdef DEBUG - if (debug > 2) - printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n", - client_limit, client_limit_period, - (u_long)netof(hostaddr)); -#endif /*DEBUG*/ - if (mon_enabled == MON_OFF) { -#ifdef DEBUG - if (debug > 4) - printf("no limit - monitoring is off\n"); -#endif - return (int)(match->flags & ~RES_LIMITED); - } + /* + * Ignore any packets with a multicast source address + * (this should be done early in the receive process, + * later!) + */ + if (IN_CLASSD(SRCADR(srcadr))) + return (int)RES_IGNORE; /* - * How nice, MRU list provides our current client as the - * first entry in the list. - * Monitoring was verified to be active above, thus we - * know an entry for our client must exist, or some - * brain dead set the memory limit for mon entries to ZERO!!! + * Set match to first entry, which is default entry. + * Work our way down from there. */ - this_client = mon_mru_list.mru_next; - - for (md = mon_fifo_list.fifo_next,lcnt = 0; - md != &mon_fifo_list; - md = md->fifo_next) { - if ((current_time - md->lasttime) - > client_limit_period) { -#ifdef DEBUG - if (debug > 5) - printf("checking: %s: ignore: too old: %ld\n", - numtoa(md->rmtadr), - current_time - md->lasttime); -#endif - continue; - } - if (md->mode == MODE_BROADCAST || - md->mode == MODE_CONTROL || - md->mode == MODE_PRIVATE) { -#ifdef DEBUG - if (debug > 5) - printf("checking: %s: ignore mode %d\n", - numtoa(md->rmtadr), - md->mode); -#endif - continue; + match = restrictlist; + for (rl = match->next; rl != 0 && rl->addr <= hostaddr; + rl = rl->next) + if ((hostaddr & rl->mask) == rl->addr) { + if ((rl->mflags & RESM_NTPONLY) && + !isntpport) + continue; + match = rl; } - if (netof(md->rmtadr) != - netof(hostaddr)) { -#ifdef DEBUG - if (debug > 5) - printf("checking: %s: different net 0x%lX\n", - numtoa(md->rmtadr), - (u_long)netof(md->rmtadr)); -#endif - continue; - } - lcnt++; - if (lcnt > (int) client_limit || - md->rmtadr == hostaddr) { -#ifdef DEBUG - if (debug > 5) - printf("considering %s: found host\n", - numtoa(md->rmtadr)); -#endif - break; - } -#ifdef DEBUG - else { - if (debug > 5) - printf("considering %s: same net\n", - numtoa(md->rmtadr)); - } -#endif + match->count++; + if (match == restrictlist) + res_not_found++; + else + res_found++; + flags = match->flags; + } + /* 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); + + /* + * Ignore any packets with a multicast source address + * (this should be done early in the receive process, + * later!) + */ + if (IN6_IS_ADDR_MULTICAST(&hostaddr6)) + 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 != 0 && + (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; + } } -#ifdef DEBUG - if (debug > 4) - printf("this one is rank %d in list, limit is %lu: %s\n", - lcnt, client_limit, - (lcnt <= (int) client_limit) ? "ALLOW" : "REJECT"); -#endif - if (lcnt <= (int) client_limit) { - this_client->lastdrop = 0; - return (int)(match->flags & ~RES_LIMITED); - } else { - this_client->lastdrop = current_time; - } + match6->count++; + if (match6 == restrictlist6) + 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 (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; } - return (int)match->flags; + return (flags); } @@ -307,61 +292,112 @@ restrictions( void hack_restrict( int op, - struct sockaddr_in *resaddr, - struct sockaddr_in *resmask, + struct sockaddr_storage *resaddr, + struct sockaddr_storage *resmask, int mflags, int flags ) { - register u_int32 addr; - register u_int32 mask; - register struct restrictlist *rl; - register struct restrictlist *rlprev; - int i; - - /* - * Get address and mask in host byte order - */ - addr = SRCADR(resaddr); - mask = SRCADR(resmask); - addr &= mask; /* make sure low bits are zero */ + 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) { + /* + * Get address and mask in host byte order + */ + addr = SRCADR(resaddr); + mask = SRCADR(resmask); + addr &= mask; /* make sure low bits zero */ - /* - * If this is the default address, point at first on list. Else - * go searching for it. - */ - if (addr == htonl(INADDR_ANY)) { - rlprev = 0; - rl = restrictlist; - } else { - rlprev = restrictlist; - rl = rlprev->next; - while (rl != 0) { - if (rl->addr > addr) { - rl = 0; - break; - } else if (rl->addr == addr) { - if (rl->mask == mask) { - if ((mflags & RESM_NTPONLY) - == (rl->mflags & RESM_NTPONLY)) - break; /* exact match */ - if (!(mflags & RESM_NTPONLY)) { - /* - * No flag fits before flag - */ + /* + * If this is the default address, point at first on + * list. Else go searching for it. + */ + if (addr == 0) { + rlprev = 0; + rl = restrictlist; + } else { + rlprev = restrictlist; + rl = rlprev->next; + while (rl != 0) { + if (rl->addr > addr) { + rl = 0; + break; + } else if (rl->addr == addr) { + if (rl->mask == mask) { + if ((mflags & + RESM_NTPONLY) == + (rl->mflags & + RESM_NTPONLY)) + break; + + if (!(mflags & + RESM_NTPONLY)) { + rl = 0; + break; + } + } else if (rl->mask > mask) { rl = 0; break; } - /* continue on */ - } else if (rl->mask > mask) { - rl = 0; + } + rlprev = rl; + rl = rl->next; + } + } + } + + 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 = 0; + rl6 = restrictlist6; + } else { + rlprev6 = restrictlist6; + rl6 = rlprev6->next; + while (rl6 != 0) { + addr_cmp = memcmp(&rl6->addr6, &addr6, + sizeof(addr6)); + if (addr_cmp > 0) { + rl6 = 0; 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 = 0; + break; + } + } else if (mask_cmp > 0) { + rl6 = 0; + break; + } } + rlprev6 = rl6; + rl6 = rl6->next; } - rlprev = rl; - rl = rl->next; } } + /* * In case the above wasn't clear :-), either rl now points * at the entry this call refers to, or rl is zero and rlprev @@ -372,89 +408,179 @@ hack_restrict( /* * Switch based on operation */ - switch (op) { - case RESTRICT_FLAGS: - /* - * Here we add bits to the flags. If this is a new - * restriction add it. - */ - if (rl == 0) { - if (numresfree == 0) { - 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++; + 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 == 0) { + if (numresfree == 0) { + 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; } - numresfree = INCRESLIST; - } - rl = resfree; - resfree = rl->next; - numresfree--; + rl = resfree; + resfree = rl->next; + numresfree--; - rl->addr = addr; - rl->mask = mask; - rl->mflags = (u_short)mflags; + rl->addr = addr; + rl->mask = mask; + rl->mflags = (u_short)mflags; - rl->next = rlprev->next; - rlprev->next = rl; - restrictcount++; - } - if ((rl->flags ^ (u_short)flags) & RES_LIMITED) { - res_limited_refcnt++; - mon_start(MON_RES); /* ensure data gets collected */ - } - rl->flags |= (u_short)flags; - break; - - case RESTRICT_UNFLAG: - /* - * Remove some bits from the flags. If we didn't - * find this one, just return. - */ - if (rl != 0) { - if ((rl->flags ^ (u_short)flags) & RES_LIMITED) { - res_limited_refcnt--; - if (res_limited_refcnt == 0) - mon_stop(MON_RES); + rl->next = rlprev->next; + rlprev->next = rl; + restrictcount++; } - rl->flags &= (u_short)~flags; - } - break; + if ((rl->flags ^ (u_short)flags) & + RES_LIMITED) { + res_limited_refcnt++; + mon_start(MON_RES); + } + rl->flags |= (u_short)flags; + break; + + case RESTRICT_UNFLAG: + /* + * Remove some bits from the flags. If we didn't + * find this one, just return. + */ + if (rl != 0) { + 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: - /* - * 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 != 0 - && rl->addr != htonl(INADDR_ANY) - && !(rl->mflags & RESM_INTERFACE)) { - rlprev->next = rl->next; - restrictcount--; - if (rl->flags & RES_LIMITED) { - res_limited_refcnt--; - if (res_limited_refcnt == 0) - mon_stop(MON_RES); + case RESTRICT_REMOVE: + /* + * 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 != 0 + && rl->addr != htonl(INADDR_ANY) + && !(rl->mflags & RESM_INTERFACE)) { + rlprev->next = 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++; } - memset((char *)rl, 0, sizeof(struct restrictlist)); + break; - rl->next = resfree; - resfree = rl; - numresfree++; + default: + break; } - break; + } 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 == 0) { + if (numresfree6 == 0) { + 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; + rl6->next = rlprev6->next; + rlprev6->next = rl6; + restrictcount6++; + } + if ((rl6->flags ^ (u_short)flags) & + RES_LIMITED) { + res_limited_refcnt6++; + mon_start(MON_RES); + } + rl6->flags |= (u_short)flags; + break; + + case RESTRICT_UNFLAG: + /* + * Remove some bits from the flags. If we didn't + * find this one, just return. + */ + if (rl6 != 0) { + 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: + /* + * 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 != 0 && + !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6) + && !(rl6->mflags & RESM_INTERFACE)) { + rlprev6->next = 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: - /* Oh, well */ - break; + default: + break; + } } - - /* done! */ } diff --git a/contrib/ntp/ntpd/ntp_timer.c b/contrib/ntp/ntpd/ntp_timer.c index c2b1d72..6f0f18b 100644 --- a/contrib/ntp/ntpd/ntp_timer.c +++ b/contrib/ntp/ntpd/ntp_timer.c @@ -23,10 +23,6 @@ # include "ntp_timer.h" #endif -#ifdef PUBKEY -#include "ntp_crypto.h" -#endif /* PUBKEY */ - /* * These routines provide support for the event timer. The timer is * implemented by an interrupt routine which sets a flag once every @@ -50,10 +46,10 @@ static u_long adjust_timer; /* second timer */ static u_long keys_timer; /* minute timer */ static u_long hourly_timer; /* hour timer */ static u_long huffpuff_timer; /* huff-n'-puff timer */ -#ifdef AUTOKEY +#ifdef OPENSSL static u_long revoke_timer; /* keys revoke timer */ -u_long sys_revoke = 1 << KEY_REVOKE; /* keys revoke timeout */ -#endif /* AUTOKEY */ +u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ +#endif /* OPENSSL */ /* * Statistics counter for the interested. @@ -83,6 +79,57 @@ static HANDLE WaitableTimerHandle = NULL; static RETSIGTYPE alarming P((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 */ + +/* + * reinit_timer - reinitialize interval timer. + */ +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< (1< (NTP_MAXFREQ * 1e6))) { - msyslog(LOG_ERR, "invalid frequency (%f) in %s", - old_drift, stats_drift_file); - old_drift = 0.0; - } - msyslog(LOG_INFO, "frequency initialized %.3f from %s", - old_drift, stats_drift_file); + fclose(fp); + msyslog(LOG_INFO, + "frequency initialized %.3f PPM from %s", + old_drift, stats_drift_file); loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); break; @@ -409,6 +432,20 @@ stats_config( 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 */ } break; @@ -442,38 +479,28 @@ stats_config( */ void record_peer_stats( - struct sockaddr_in *addr, - int status, - double offset, - double delay, - double dispersion, - double skew + struct sockaddr_storage *addr, + int status, + double offset, + double delay, + double dispersion, + double skew ) { - struct timeval tv; -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif - u_long day, sec, msec; + l_fp now; + u_long day; if (!stats_control) return; -#ifdef HAVE_GETCLOCK - (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 */ - day = tv.tv_sec / 86400 + MJD_1970; - sec = tv.tv_sec % 86400; - msec = tv.tv_usec / 1000; - filegen_setup(&peerstats, (u_long)(tv.tv_sec + JAN_1970)); + get_systime(&now); + filegen_setup(&peerstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; if (peerstats.fp != NULL) { fprintf(peerstats.fp, - "%lu %lu.%03lu %s %x %.9f %.9f %.9f %.9f\n", - day, sec, msec, ntoa(addr), status, offset, + "%lu %s %s %x %.9f %.9f %.9f %.9f\n", + day, ulfptoa(&now, 3), stoa(addr), status, offset, delay, dispersion, skew); fflush(peerstats.fp); } @@ -490,37 +517,27 @@ record_peer_stats( */ void record_loop_stats( - double offset, - double freq, - double jitter, - double stability, - int poll + double offset, + double freq, + double jitter, + double stability, + int spoll ) { - struct timeval tv; -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif - u_long day, sec, msec; + l_fp now; + u_long day; if (!stats_control) return; -#ifdef HAVE_GETCLOCK - (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 */ - day = tv.tv_sec / 86400 + MJD_1970; - sec = tv.tv_sec % 86400; - msec = tv.tv_usec / 1000; - filegen_setup(&loopstats, (u_long)(tv.tv_sec + JAN_1970)); + get_systime(&now); + filegen_setup(&loopstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; if (loopstats.fp != NULL) { - fprintf(loopstats.fp, "%lu %lu.%03lu %.9f %.6f %.9f %.6f %d\n", - day, sec, msec, offset, freq * 1e6, jitter, - stability * 1e6, poll); + fprintf(loopstats.fp, "%lu %s %.9f %.6f %.9f %.6f %d\n", + day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, + stability * 1e6, spoll); fflush(loopstats.fp); } } @@ -536,33 +553,23 @@ record_loop_stats( */ void record_clock_stats( - struct sockaddr_in *addr, + struct sockaddr_storage *addr, const char *text ) { - struct timeval tv; -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif - u_long day, sec, msec; + l_fp now; + u_long day; if (!stats_control) return; -#ifdef HAVE_GETCLOCK - (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 */ - day = tv.tv_sec / 86400 + MJD_1970; - sec = tv.tv_sec % 86400; - msec = tv.tv_usec / 1000; - filegen_setup(&clockstats, (u_long)(tv.tv_sec + JAN_1970)); + get_systime(&now); + filegen_setup(&clockstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; if (clockstats.fp != NULL) { - fprintf(clockstats.fp, "%lu %lu.%03lu %s %s\n", - day, sec, msec, ntoa(addr), text); + fprintf(clockstats.fp, "%lu %s %s %s\n", + day, ulfptoa(&now, 3), stoa(addr), text); fflush(clockstats.fp); } } @@ -579,43 +586,116 @@ record_clock_stats( */ void record_raw_stats( - struct sockaddr_in *srcadr, - struct sockaddr_in *dstadr, - l_fp *t1, - l_fp *t2, - l_fp *t3, - l_fp *t4 + struct sockaddr_storage *srcadr, + struct sockaddr_storage *dstadr, + l_fp *t1, + l_fp *t2, + l_fp *t3, + l_fp *t4 ) { - struct timeval tv; -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif - u_long day, sec, msec; + l_fp now; + u_long day; if (!stats_control) return; -#ifdef HAVE_GETCLOCK - (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 */ - day = tv.tv_sec / 86400 + MJD_1970; - sec = tv.tv_sec % 86400; - msec = tv.tv_usec / 1000; - filegen_setup(&rawstats, (u_long)(tv.tv_sec + JAN_1970)); + get_systime(&now); + filegen_setup(&rawstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; if (rawstats.fp != NULL) { - fprintf(rawstats.fp, "%lu %lu.%03lu %s %s %s %s %s %s\n", - day, sec, msec, ntoa(srcadr), ntoa(dstadr), + fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", + day, ulfptoa(&now, 3), stoa(srcadr), stoa(dstadr), ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9), ulfptoa(t4, 9)); fflush(rawstats.fp); } } + +/* + * record_sys_stats - write system statistics to file + * + * file format + * time (s past midnight) + * time since startup (hr) + * packets recieved + * packets processed + * current version + * previous version + * bad version + * access denied + * bad length or format + * bad authentication + * rate exceeded + */ +void +record_sys_stats(void) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&sysstats, now.l_ui); + 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); + fflush(sysstats.fp); + proto_clr_stats(); + } +} + + +#ifdef OPENSSL +/* + * record_crypto_stats - write crypto statistics to file + * + * file format: + * day (mjd) + * time (s past midnight) + * peer (ip address) + * text message + */ +void +record_crypto_stats( + struct sockaddr_storage *addr, + const char *text + ) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&cryptostats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (cryptostats.fp != NULL) { + if (addr == NULL) + fprintf(cryptostats.fp, "%lu %s %s\n", + day, ulfptoa(&now, 3), text); + else + fprintf(cryptostats.fp, "%lu %s %s %s\n", + day, ulfptoa(&now, 3), stoa(addr), text); + fflush(cryptostats.fp); + } +} +#endif /* OPENSSL */ + + /* * getauthkeys - read the authentication keys from the specified file */ @@ -667,3 +747,51 @@ rereadkeys(void) if (key_file_name != 0) authreadkeys(key_file_name); } + +/* + * sock_hash - hash an sockaddr_storage structure + */ +int +sock_hash( + struct sockaddr_storage *addr + ) +{ + 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; + + return hashVal; +} diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c index 1b80560..0b05253 100644 --- a/contrib/ntp/ntpd/ntpd.c +++ b/contrib/ntp/ntpd/ntpd.c @@ -11,6 +11,10 @@ #include "ntp_io.h" #include "ntp_stdlib.h" +#ifdef SIM +#include "ntpsim.h" +#endif + #ifdef HAVE_UNISTD_H # include #endif @@ -40,6 +44,7 @@ # include # include # include "../libntp/log.h" +# include # include #endif /* SYS_WINNT */ #if defined(HAVE_RTPRIO) @@ -99,9 +104,11 @@ # include #endif -#ifdef PUBKEY -#include "ntp_crypto.h" -#endif /* PUBKEY */ +#ifdef HAVE_CLOCKCTL +# include +# include +# include +#endif /* * Signals we catch for debugging. If not debugging we ignore them. @@ -123,11 +130,13 @@ /* handles for various threads, process, and objects */ HANDLE ResolverThreadHandle = NULL; /* variables used to inform the Service Control Manager of our current state */ +BOOL NoWinService = FALSE; SERVICE_STATUS ssStatus; SERVICE_STATUS_HANDLE sshStatusHandle; HANDLE WaitHandles[3] = { NULL, NULL, NULL }; char szMsgPath[255]; static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType); +BOOL init_randfile(); #endif /* SYS_WINNT */ /* @@ -146,10 +155,26 @@ int priority_done = 2; /* 0 - Set priority */ volatile int debug; /* + * Set the processing not to be in the forground + */ +int forground_process = FALSE; + +/* * No-fork flag. If set, we do not become a background daemon. */ int nofork; +#ifdef HAVE_CLOCKCTL +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; +struct group *gr; +struct passwd *pw; +#endif /* HAVE_CLOCKCTL */ + /* * Initializing flag. All async routines watch this and only do their * thing when it is clear. @@ -176,8 +201,10 @@ static RETSIGTYPE finish P((int)); #endif /* SIGDIE2 */ #ifdef DEBUG +#ifndef SYS_WINNT static RETSIGTYPE moredebug P((int)); static RETSIGTYPE lessdebug P((int)); +#endif #else /* not DEBUG */ static RETSIGTYPE no_debug P((int)); #endif /* not DEBUG */ @@ -185,7 +212,16 @@ static RETSIGTYPE no_debug P((int)); int ntpdmain P((int, char **)); static void set_process_priority P((void)); - +#ifdef SIM +int +main( + int argc, + char *argv[] + ) +{ + return ntpsim(argc, argv); +} +#else /* SIM */ #ifdef NO_MAIN_ALLOWED CALL(ntpd,"ntpd",ntpdmain); #else @@ -198,6 +234,7 @@ main( return ntpdmain(argc, argv); } #endif +#endif /* SIM */ #ifdef _AIX /* @@ -335,10 +372,6 @@ ntpdmain( { l_fp now; char *cp; -#ifdef AUTOKEY - u_int n; - char hostname[MAXFILENAME]; -#endif /* AUTOKEY */ struct recvbuf *rbuflist; struct recvbuf *rbuf; #ifdef _AIX /* HMS: ifdef SIGDANGER? */ @@ -384,9 +417,17 @@ ntpdmain( #endif getstartup(argc, argv); /* startup configuration, may set debug */ + if (debug) + printf("%s\n", Version); + /* * Initialize random generator and public key pair */ +#ifdef SYS_WINNT + /* Initialize random file before OpenSSL checks */ + if(!init_randfile()) + msyslog(LOG_ERR, "Unable to initialize .rnd file\n"); +#endif get_systime(&now); SRANDOM((int)(now.l_i * now.l_uf)); @@ -414,12 +455,12 @@ ntpdmain( int max_fd; #endif /* not F_CLOSEM */ +#if defined(F_CLOSEM) /* * From 'Writing Reliable AIX Daemons,' SG24-4946-00, * by Eric Agar (saves us from doing 32767 system * calls) */ -#if defined(F_CLOSEM) if (fcntl(0, F_CLOSEM, 0) == -1) msyslog(LOG_ERR, "ntpd: failed to close open files(): %m"); #else /* not F_CLOSEM */ @@ -484,16 +525,22 @@ ntpdmain( # else /* SYS_WINNT */ { - SERVICE_TABLE_ENTRY dispatchTable[] = { + if (NoWinService == FALSE) { + SERVICE_TABLE_ENTRY dispatchTable[] = { { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main }, { NULL, NULL } - }; + }; - /* daemonize */ - if (!StartServiceCtrlDispatcher(dispatchTable)) - { - msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m"); - ExitProcess(2); + /* daemonize */ + if (!StartServiceCtrlDispatcher(dispatchTable)) + { + msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m"); + ExitProcess(2); + } + } + else { + service_main(argc, argv); + return 0; } } # endif /* SYS_WINNT */ @@ -520,15 +567,13 @@ service_main( char *cp; struct recvbuf *rbuflist; struct recvbuf *rbuf; -#ifdef AUTOKEY - u_int n; - char hostname[MAXFILENAME]; -#endif /* AUTOKEY */ - if(!debug) + + if(!debug && NoWinService == FALSE) { /* register our service control handler */ - if (!(sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"), - (LPHANDLER_FUNCTION)service_ctrl))) + sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"), + (LPHANDLER_FUNCTION)service_ctrl); + if(sshStatusHandle == 0) { msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m"); return; @@ -567,7 +612,7 @@ service_main( debug = 0; /* will be immediately re-initialized 8-( */ getstartup(argc, argv); /* startup configuration, catch logfile this time */ -#if !defined(SYS_WINNT) && !defined(VMS) +#if !defined(VMS) # ifndef LOG_DAEMON openlog(cp, LOG_PID); @@ -624,6 +669,25 @@ service_main( #endif #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE) +# ifdef HAVE_SETRLIMIT + /* + * Set the stack limit to something smaller, so that we don't lock a lot + * of unused stack memory. + */ + { + struct rlimit rl; + + if (getrlimit(RLIMIT_STACK, &rl) != -1 + && (rl.rlim_cur = 20 * 4096) < rl.rlim_max) + { + if (setrlimit(RLIMIT_STACK, &rl) == -1) + { + msyslog(LOG_ERR, + "Cannot adjust stack limit for mlockall: %m"); + } + } + } +# endif /* HAVE_SETRLIMIT */ /* * lock the process into memory */ @@ -741,15 +805,9 @@ service_main( debug = 0; #endif getconfig(argc, argv); -#ifdef AUTOKEY - gethostname(hostname, MAXFILENAME); - n = strlen(hostname) + 1; - sys_hostname = emalloc(n); - memcpy(sys_hostname, hostname, n); -#ifdef PUBKEY +#ifdef OPENSSL crypto_setup(); -#endif /* PUBKEY */ -#endif /* AUTOKEY */ +#endif /* OPENSSL */ initializing = 0; #if defined(SYS_WINNT) && !defined(NODETACH) @@ -757,23 +815,83 @@ service_main( if(!debug) { # endif + if (NoWinService == FALSE) { /* report to the service control manager that the service is running */ - ssStatus.dwCurrentState = SERVICE_RUNNING; - ssStatus.dwWin32ExitCode = NO_ERROR; - if (!SetServiceStatus(sshStatusHandle, &ssStatus)) - { - msyslog(LOG_ERR, "SetServiceStatus: %m"); - if (ResolverThreadHandle != NULL) - CloseHandle(ResolverThreadHandle); - ssStatus.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(sshStatusHandle, &ssStatus); - return; + ssStatus.dwCurrentState = SERVICE_RUNNING; + ssStatus.dwWin32ExitCode = NO_ERROR; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + if (ResolverThreadHandle != NULL) + CloseHandle(ResolverThreadHandle); + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + return; + } } # if defined(DEBUG) } # endif #endif +#ifdef HAVE_CLOCKCTL + /* + * Drop super-user privileges and chroot now if the OS supports + * non root clock control (only NetBSD for now). + */ + if (user != NULL) { + if (isdigit((unsigned char)*user)) { + sw_uid = (uid_t)strtoul(user, &endp, 0); + if (*endp != '\0') + goto getuser; + } else { +getuser: + if ((pw = getpwnam(user)) != NULL) { + sw_uid = pw->pw_uid; + } else { + errno = 0; + msyslog(LOG_ERR, "Cannot find user `%s'", user); + exit (-1); + } + } + } + if (group != NULL) { + if (isdigit((unsigned char)*group)) { + sw_gid = (gid_t)strtoul(group, &endp, 0); + if (*endp != '\0') + goto getgroup; + } else { +getgroup: + if ((gr = getgrnam(group)) != NULL) { + sw_gid = pw->pw_gid; + } else { + errno = 0; + msyslog(LOG_ERR, "Cannot find group `%s'", group); + exit (-1); + } + } + } + if (chrootdir && chroot(chrootdir)) { + msyslog(LOG_ERR, "Cannot chroot to `%s': %m", chrootdir); + exit (-1); + } + if (group && setgid(sw_gid)) { + msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group); + exit (-1); + } + if (group && setegid(sw_gid)) { + msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group); + exit (-1); + } + if (user && setuid(sw_uid)) { + msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user); + exit (-1); + } + if (user && seteuid(sw_uid)) { + msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user); + exit (-1); + } +#endif /* * Report that we're up to any trappers */ @@ -797,10 +915,10 @@ service_main( #if defined(HAVE_IO_COMPLETION_PORT) WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */ WaitHandles[1] = get_timer_handle(); - WaitHandles[2] = get_io_event(); + WaitHandles[2] = get_io_event(); for (;;) { - DWORD Index = WaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, FALSE, 1000, MWMO_ALERTABLE); + DWORD Index = WaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, FALSE, 1000, TRUE); switch (Index) { case WAIT_OBJECT_0 + 0 : /* exit request */ exit(0); @@ -819,30 +937,16 @@ service_main( # endif break; -# if 1 - /* - * FIXME: According to the documentation for WaitForMultipleObjectsEx - * this is not possible. This may be a vestigial from when this was - * MsgWaitForMultipleObjects, maybe it should be removed? - */ - case WAIT_OBJECT_0 + 3 : /* windows message */ - { - MSG msg; - while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) - { - if ( msg.message == WM_QUIT ) - { - exit( 0 ); - } - DispatchMessage( &msg ); - } - } - break; -# endif - case WAIT_IO_COMPLETION : /* loop */ case WAIT_TIMEOUT : break; + case WAIT_FAILED: + msyslog(LOG_ERR, "ntpdc: WaitForMultipleObjectsEx Failed: Error: %m"); + break; + + /* For now do nothing if not expected */ + default: + break; } /* switch */ rbuflist = getrecvbufs(); /* get received buffers */ @@ -900,9 +1004,10 @@ service_main( } else if (nfound == -1 && errno != EINTR) msyslog(LOG_ERR, "select() error: %m"); - else if (debug > 2) { +# ifdef DEBUG + else if (debug > 2) msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); - } +# endif /* DEBUG */ # else /* HAVE_SIGNALED_IO */ wait_for_signal(); @@ -950,8 +1055,12 @@ service_main( * Go around again */ } +#ifndef SYS_WINNT exit(1); /* unreachable */ +#endif +#ifndef SYS_WINNT return 1; /* DEC OSF cc braindamage */ +#endif } @@ -984,6 +1093,7 @@ finish( #ifdef DEBUG +#ifndef SYS_WINNT /* * moredebug - increase debugging verbosity */ @@ -1019,8 +1129,9 @@ lessdebug( } errno = saved_errno; } +#endif #else /* not DEBUG */ -/* +#ifndef SYS_WINNT/* * no_debug - We don't do the debug here. */ static RETSIGTYPE @@ -1033,6 +1144,7 @@ no_debug( msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig); errno = saved_errno; } +#endif /* not SYS_WINNT */ #endif /* not DEBUG */ #ifdef SYS_WINNT diff --git a/contrib/ntp/ntpd/ntpsim.c b/contrib/ntp/ntpd/ntpsim.c new file mode 100644 index 0000000..3fbae17 --- /dev/null +++ b/contrib/ntp/ntpd/ntpsim.c @@ -0,0 +1,368 @@ +/* + * NTP simulator engine - Harish Nair + * University of Delaware, 2001 + */ +#include "ntpd.h" +#include "ntpsim.h" + +/* + * 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 + */ +void (*funcPtr[]) (Node *, Event) = { + &ndbeep, &ndeclk, &ntptmr, &netpkt +}; + + +/* + * ntpsim - initialize global variables and event queue and start + */ +int +ntpsim( + int argc, + char *argv[] + ) +{ + Event e; + double maxtime; + struct timeval seed; + + /* + * 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; + + /* + * Initialize ntp variables + */ + initializing = 1; + init_auth(); + init_util(); + init_restrict(); + init_mon(); + init_timer(); + init_lib(); + init_random(); + init_request(); + init_control(); + init_peer(); + init_proto(); + init_io(); + init_loopfilter(); + mon_start(MON_OFF); + getconfig(argc, argv); + initializing = 0; + + /* + * Watch out here, we want the real time, not the silly stuff. + */ + gettimeofday(&seed, NULL); + srand48(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); + + /* + * 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); + } + return (0); +} + + +/* + * Return an event + */ +Event +event( + double t, + funcTkn f + ) +{ + Event e; + + e.time = t; + e.function = f; + return (e); +} + +/* + * Create an event queue + */ +Queue +queue( + Event e, + Queue q + ) +{ + Queue ret; + + if ((ret = (Queue)malloc(sizeof(struct List))) == NULL) + abortsim("queue-malloc"); + ret->event = e; + ret->next = q; + return (ret); +} + + +/* + * Push an event into the event queue + */ +void push( + Event e, + Queue *qp + ) +{ + Queue *tmp = qp; + + while (*tmp != NULL && ((*tmp)->event.time < e.time)) + tmp = &((*tmp)->next); + *tmp = queue(e, (*tmp)); +} + + +/* + * Pop the first event from the event queue + */ +Event +pop( + Queue *qp + ) +{ + Event ret; + Queue tmp; + + tmp = *qp; + if (tmp == NULL) + abortsim("pop - empty queue"); + ret = tmp->event; + *qp = tmp->next; + free(tmp); + return (ret); +} + + +/* + * Update clocks + */ +void +ndeclk( + Node *n, + Event e + ) +{ + node_clock(n, e.time); +} + + +/* + * Timer interrupt. Eventually, this results in calling the + * srvr_rplyi() routine below. + */ +void +ntptmr( + Node *n, + Event e + ) +{ + struct recvbuf *rbuf; + + timer(); + + /* + * Process buffers received. They had better be in order by + * receive timestamp. + */ + while (n->rbuflist != NULL) { + rbuf = n->rbuflist; + n->rbuflist = rbuf->next; + (rbuf->receiver)(rbuf); + free(rbuf); + } + + /* + * Arm the next timer interrupt. + */ + push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events); +} + + +/* + * srvr_rply() - send packet + */ +int srvr_rply( + Node *n, + struct sockaddr_storage *dest, + struct interface *inter, struct pkt *rpkt + ) +{ + struct pkt xpkt; + struct recvbuf rbuf; + Event xvnt; + double dtemp, etemp; + + /* + * 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)); + rbuf.next = NULL; + + /* + * 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); +} + + +/* + * netpkt() - receive packet + */ +void +netpkt( + Node *n, + Event e + ) +{ + 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); + rbuf->next = NULL; + obuf = n->rbuflist; + + /* + * In the present incarnation, no more than one buffer can be on + * the queue; however, we sniff the queue anyway as a hint for + * further development. + */ + if (obuf == NULL) { + n->rbuflist = rbuf; + } else { + while (obuf->next != NULL) + obuf = obuf->next; + obuf->next = rbuf; + } +} + + +/* + * ndbeep() - progress indicator + */ +void +ndbeep( + Node *n, + Event e + ) +{ + 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); + } +} + + +/* + * Abort simulation + */ +void +abortsim( + char *errmsg + ) +{ + perror(errmsg); + exit(1); +} diff --git a/contrib/ntp/ntpd/refclock_acts.c b/contrib/ntp/ntpd/refclock_acts.c index efdf536..d26ceed 100644 --- a/contrib/ntp/ntpd/refclock_acts.c +++ b/contrib/ntp/ntpd/refclock_acts.c @@ -733,8 +733,9 @@ acts_receive ( * waiting for carrier loss or long-space disconnect, but we do * these clumsy things anyway. */ - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); + record_clock_stats(&peer->srcadr, pp->a_lastcode); pp->sloppyclockflag &= ~CLK_FLAG1; up->pollcnt = 0; (void)write(pp->io.fd, &hangup, 1); @@ -800,7 +801,7 @@ acts_timeout ( acts_disc(peer); return; } - switch (peer->ttlmax) { + switch (peer->ttl) { /* * In manual mode the ACTS calling program is activated diff --git a/contrib/ntp/ntpd/refclock_arbiter.c b/contrib/ntp/ntpd/refclock_arbiter.c index cdbe2ee..cf5f92f 100644 --- a/contrib/ntp/ntpd/refclock_arbiter.c +++ b/contrib/ntp/ntpd/refclock_arbiter.c @@ -419,8 +419,9 @@ arb_poll( refclock_report(peer, CEVNT_TIMEOUT); return; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); + record_clock_stats(&peer->srcadr, pp->a_lastcode); } #else diff --git a/contrib/ntp/ntpd/refclock_arc.c b/contrib/ntp/ntpd/refclock_arc.c index c771f47..f556da6 100644 --- a/contrib/ntp/ntpd/refclock_arc.c +++ b/contrib/ntp/ntpd/refclock_arc.c @@ -1,5 +1,5 @@ /* - * refclock_arc - clock driver for ARCRON MSF receivers + * refclock_arc - clock driver for ARCRON MSF/DCF/WWVB receivers */ #ifdef HAVE_CONFIG_H @@ -7,9 +7,11 @@ #endif #if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF) -static const char arc_version[] = { "V1.1 1997/06/23" }; +static const char arc_version[] = { "V1.3 2003/02/21" }; -#undef ARCRON_DEBUG /* Define only while in development... */ +/* define PRE_NTP420 for compatibility to previous versions of NTP (at least + to 4.1.0 */ +#undef PRE_NTP420 #ifndef ARCRON_NOT_KEEN #define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */ @@ -28,6 +30,9 @@ static const char arc_version[] = { "V1.1 1997/06/23" }; /* Code by Derek Mulcahy, , 1997. Modifications by Damon Hart-Davis, , 1997. +Modifications by Paul Alfille, , 2003. +Modifications by Christopher Price, , 2003. + THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND. USE AT YOUR OWN RISK. @@ -42,6 +47,33 @@ reproduced. ------------------------------------------------------------------------------- +Christopher's notes: + +MAJOR CHANGES SINCE V1.2 +======================== + 1) Applied patch by Andrey Bray + 2001-02-17 comp.protocols.time.ntp + + 2) Added WWVB support via clock mode command, localtime/UTC time configured + via flag1=(0=UTC, 1=localtime) + + 3) Added ignore resync request via flag2=(0=resync, 1=ignore resync) + + 4) Added simplified conversion from localtime to UTC with dst/bst translation + + 5) Added average signal quality poll + + 6) Fixed a badformat error when no code is available due to stripping + \n & \r's + + 7) Fixed a badformat error when clearing lencode & memset a_lastcode in poll + routine + + 8) Lots of code cleanup, including standardized DEBUG macros and removal + of unused code + +------------------------------------------------------------------------------- + Author's original note: I enclose my ntp driver for the Galleon Systems Arc MSF receiver. @@ -306,6 +338,7 @@ Also note h command which starts a resync to MSF signal. #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" +#include "ntp_calendar.h" #include "ntp_stdlib.h" #include @@ -324,7 +357,7 @@ Also note h command which starts a resync to MSF signal. #endif /* - * This driver supports the ARCRON MSF Radio Controlled Clock + * This driver supports the ARCRON MSF/DCF/WWVB Radio Controlled Clock */ /* @@ -335,9 +368,16 @@ Also note h command which starts a resync to MSF signal. #define PRECISION (-4) /* Precision (~63 ms). */ #define HIGHPRECISION (-5) /* If things are going well... */ #define REFID "MSFa" /* Reference ID. */ -#define DESCRIPTION "ARCRON MSF Receiver" +#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 NSAMPLESLONG 8 /* Stages of long filter. */ +#ifdef PRE_NTP420 +#define MODE ttlmax +#else +#define MODE ttl +#endif #define LENARC 16 /* Format `o' timecode length. */ @@ -405,22 +445,6 @@ Also note h command which starts a resync to MSF signal. #endif }; -/* Chose filter length dependent on fudge flag 4. */ -#define CHOSENSAMPLES(pp) \ -(((pp)->sloppyclockflag & CLK_FLAG4) ? NSAMPLESLONG : NSAMPLES) - /* -Chose how many filter samples to keep. Several factors are in play. - - 1) Discard at least one sample to allow a spike value to be - discarded. - - 2) Discard about 1-in-8 to 1-in-30 samples to handle spikes. - - 3) Keep an odd number of samples to avoid median value being biased - high or low. -*/ -#define NKEEP(pp) ((CHOSENSAMPLES(pp) - 1 - (CHOSENSAMPLES(pp)>>3)) | 1) - #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 @@ -454,6 +478,7 @@ struct arcunit { 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. */ @@ -463,6 +488,7 @@ struct arcunit { u_long saved_flags; /* Saved fudge flags. */ }; + #ifdef ARCRON_LEAPSECOND_KEEN /* The flag `possible_leap' is set non-zero when any MSF unit thinks a leap-second may have happened. @@ -522,18 +548,16 @@ struct refclock refclock_arc = { /* Queue us up for the next tick. */ #define ENQUEUE(up) \ do { \ - if((up)->ev.next != 0) { break; } /* WHOOPS! */ \ - peer->nextdate = current_time + QUEUETICK; \ + peer->nextaction = current_time + QUEUETICK; \ } while(0) -#if 0 -/* Placeholder event handler---does nothing safely---soaks up lose tick. */ +/* Placeholder event handler---does nothing safely---soaks up loose tick. */ static void dummy_event_handler( struct peer *peer ) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: dummy_event_handler() called.\n"); } #endif } @@ -558,7 +582,7 @@ arc_event_handler( register struct arcunit *up = (struct arcunit *)pp->unitptr; int i; char c; -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 2) { printf("arc: arc_event_handler() called.\n"); } #endif @@ -572,12 +596,13 @@ arc_event_handler( if(write(pp->io.fd, &c, 1) != 1) { msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd); } -#ifdef ARCRON_DEBUG +#ifdef DEBUG else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); } #endif } + + ENQUEUE(up); } -#endif /* 0 */ /* * arc_start - open the devices and initialize data for processing @@ -597,7 +622,7 @@ arc_start( #endif msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: %s: attempt to open unit %d.\n", arc_version, unit); } @@ -612,7 +637,7 @@ arc_start( (void)sprintf(device, DEVICE, unit); if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) return(0); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: unit %d using open().\n", unit); } #endif fd = open(device, OPEN_FLAGS); @@ -624,9 +649,9 @@ arc_start( } fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */ -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) - { printf("Opened RS232 port with file descriptor %d.\n", fd); } + { printf("arc: opened RS232 port with file descriptor %d.\n", fd); } #endif #ifdef HAVE_TERMIOS @@ -667,7 +692,27 @@ arc_start( peer->precision = PRECISION; peer->stratum = 2; /* Default to stratum 2 not 0. */ pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); + if (peer->MODE > 3) { + msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); + return 0; + } +#ifdef DEBUG + if(debug) { printf("arc: mode = %d.\n", peer->MODE); } +#endif + switch (peer->MODE) { + case 1: + memcpy((char *)&pp->refid, REFID_MSF, 4); + break; + case 2: + memcpy((char *)&pp->refid, REFID_DCF77, 4); + break; + case 3: + memcpy((char *)&pp->refid, REFID_WWVB, 4); + break; + default: + memcpy((char *)&pp->refid, REFID, 4); + break; + } /* Spread out resyncs so that they should remain separated. */ up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009; @@ -686,6 +731,11 @@ arc_start( #else up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */ #endif + + peer->action = arc_event_handler; + + ENQUEUE(up); + return(1); } @@ -702,6 +752,8 @@ arc_shutdown( register struct arcunit *up; struct refclockproc *pp; + peer->action = dummy_event_handler; + pp = peer->procptr; up = (struct arcunit *)pp->unitptr; io_closeclock(&pp->io); @@ -740,11 +792,11 @@ send_slow( int sl = strlen(s); int spaceleft = space_left(up); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); } #endif if(spaceleft < sl) { /* Should not normally happen... */ -#ifdef ARCRON_DEBUG +#ifdef DEBUG msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)", sl, spaceleft); #endif @@ -776,8 +828,11 @@ arc_receive( struct refclockproc *pp; struct peer *peer; char c; - int i, n, wday, month, bst, status; + int i, n, wday, month, flags, status; int arc_last_offset; + static int quality_average = 0; + static int quality_sum = 0; + static int quality_polls = 0; /* * Initialize pointers and read the timecode and timestamp @@ -857,7 +912,7 @@ arc_receive( handle for tty_clk or somesuch kernel timestamper. */ if(arc_last_offset > LENARC) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: input code too long (%d cf %d); rejected.\n", arc_last_offset, LENARC); @@ -869,7 +924,7 @@ arc_receive( } L_SUBUF(×tamp, charoffsets[arc_last_offset]); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf( "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", @@ -898,7 +953,7 @@ arc_receive( L_ISGEQ(&(up->lastrec), ×tamp)) #endif { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf("arc: system timestamp captured.\n"); #ifdef ARCRON_MULTIPLE_SAMPLES @@ -922,7 +977,7 @@ arc_receive( /* eg on receipt of the \r coming in on its own after the */ /* timecode. */ if(pp->lencode >= LENARC) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug && (rbufp->recv_buffer[0] != '\r')) { printf("arc: rubbish in pp->a_lastcode[].\n"); } #endif @@ -947,11 +1002,12 @@ arc_receive( */ if((c == 'o') && (pp->lencode == 1)) { L_CLR(&(up->lastrec)); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf("arc: clearing timestamp.\n"); } #endif } } + if (pp->lencode == 0) return; /* Handle a quality message. */ if(pp->a_lastcode[0] == 'g') { @@ -963,17 +1019,31 @@ arc_receive( if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || ((r & 0x70) != 0x30)) { /* Badly formatted response. */ -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); } #endif return; } if(r == '3') { /* Only use quality value whilst sync in progress. */ - up->quality = (q & 0xf); + if (up->quality_stamp < current_time) { + struct calendar cal; + l_fp new_stamp; + + get_systime (&new_stamp); + caljulian (new_stamp.l_ui, &cal); + up->quality_stamp = + current_time + 60 - cal.second + 5; + quality_sum = 0; + quality_polls = 0; + } + quality_sum += (q & 0xf); + quality_polls++; + quality_average = (quality_sum / quality_polls); #ifdef DEBUG - if(debug) { printf("arc: signal quality %d.\n", up->quality); } + if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); } #endif } else if( /* (r == '2') && */ up->resyncing) { + up->quality = quality_average; #ifdef DEBUG if(debug) { @@ -987,6 +1057,9 @@ arc_receive( up->quality, quality_action(up->quality)); up->resyncing = 0; /* Resync is over. */ + quality_average = 0; + quality_sum = 0; + quality_polls = 0; #ifdef ARCRON_KEEN /* Clock quality dubious; resync earlier than usual. */ @@ -1011,13 +1084,13 @@ arc_receive( /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */ -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); } #endif /* But check that we actually captured a system timestamp on it. */ if(L_ISZERO(&(up->lastrec))) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); } #endif pp->lencode = 0; @@ -1033,22 +1106,26 @@ arc_receive( pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ? '6' : ('0' + up->quality)); pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */ - record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef PRE_NTP420 /* We don't use the micro-/milli- second part... */ pp->usec = 0; pp->msec = 0; - +#else + /* We don't use the nano-second part... */ + pp->nsec = 0; +#endif n = sscanf(pp->a_lastcode, "o%2d%2d%2d%1d%2d%2d%2d%1d%1d", &pp->hour, &pp->minute, &pp->second, - &wday, &pp->day, &month, &pp->year, &bst, &status); + &wday, &pp->day, &month, &pp->year, &flags, &status); /* Validate format and numbers. */ if(n != 9) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG /* Would expect to have caught major problems already... */ if(debug) { printf("arc: badly formatted data.\n"); } #endif + pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } @@ -1064,15 +1141,21 @@ arc_receive( (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ + pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } - /* Check that BST/UTC bits are the complement of one another. */ - if(!(bst & 2) == !(bst & 4)) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } + + if(peer->MODE == 0) { /* compatiblity to original version */ + int bst = flags; + /* Check that BST/UTC bits are the complement of one another. */ + if(!(bst & 2) == !(bst & 4)) { + pp->lencode = 0; + refclock_report(peer, CEVNT_BADREPLY); + return; + } + } if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); } /* Year-2000 alert! */ @@ -1094,7 +1177,7 @@ arc_receive( printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n", n, pp->hour, pp->minute, pp->second, - pp->day, month, pp->year, bst, status); + pp->day, month, pp->year, flags, status); } #endif @@ -1114,41 +1197,159 @@ arc_receive( msyslog(LOG_NOTICE, "ARCRON: signal lost"); pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */ up->status = status; + pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } } up->status = status; - pp->day += moff[month - 1]; - - if(isleap_4(pp->year) && month > 2) { pp->day++; } /* Y2KFixes */ + if (peer->MODE == 0) { /* compatiblity to original version */ + int bst = flags; + + pp->day += moff[month - 1]; + + if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */ + + /* Convert to UTC if required */ + if(bst & 2) { + pp->hour--; + if (pp->hour < 0) { + pp->hour = 23; + pp->day--; + /* If we try to wrap round the year + * (BST on 1st Jan), reject.*/ + if(pp->day < 0) { + pp->lencode = 0; + refclock_report(peer, CEVNT_BADTIME); + return; + } + } + } + } - /* Convert to UTC if required */ - if(bst & 2) { - pp->hour--; - if (pp->hour < 0) { - pp->hour = 23; - pp->day--; - /* If we try to wrap round the year (BST on 1st Jan), reject.*/ - if(pp->day < 0) { - refclock_report(peer, CEVNT_BADTIME); + if(peer->MODE > 0) { + if(pp->sloppyclockflag & CLK_FLAG1) { + struct tm local; + struct tm *gmtp; + time_t unixtime; + + /* + * 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. + */ + + 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) { + case 1: + local.tm_isdst = (flags & 2); + break; + case 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 + ST->DST. Testing has shown this + to be irregular. For the time + being, let the OS decide. */ + 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; +#ifdef DEBUG + if (debug) + printf ("arc: DST = 01 (1)\n"); +#endif + break; + case 2: /* st->dst time */ + local.tm_isdst = -1; +#ifdef DEBUG + if (debug) + printf ("arc: DST = 10 (2)\n"); +#endif + break; + case 3: /* dst time */ + local.tm_isdst = 1; +#ifdef DEBUG + if (debug) + printf ("arc: DST = 11 (3)\n"); +#endif + break; + } + break; + default: + msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", + peer->MODE); return; + break; + } + unixtime = mktime (&local); + if ((gmtp = gmtime (&unixtime)) == NULL) + { + pp->lencode = 0; + 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; +#ifdef 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, + pp->second); } +#endif + } else + { + /* + * For more rational sites distributing UTC + */ + pp->day = ymd2yd(pp->year,month,pp->day); } } - /* If clock signal quality is unknown, revert to default PRECISION...*/ - if(up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } - /* ...else improve precision if flag3 is set... */ - else { - peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? - HIGHPRECISION : PRECISION); + if (peer->MODE == 0) { /* compatiblity to original version */ + /* If clock signal quality is + * unknown, revert to default PRECISION...*/ + if(up->quality == QUALITY_UNKNOWN) { + peer->precision = PRECISION; + } else { /* ...else improve precision if flag3 is set... */ + peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? + HIGHPRECISION : PRECISION); + } + } else { + if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) { + peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? + HIGHPRECISION : PRECISION); + } else if (up->quality == QUALITY_UNKNOWN) { + peer->precision = PRECISION; + } else { + peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? + HIGHPRECISION : PRECISION); + } } /* Notice and log any change (eg from initial defaults) for flags. */ if(up->saved_flags != pp->sloppyclockflag) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s", ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."), ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."), @@ -1156,8 +1357,6 @@ arc_receive( ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : ".")); /* Note effects of flags changing... */ if(debug) { - printf("arc: CHOSENSAMPLES(pp) = %d.\n", CHOSENSAMPLES(pp)); - printf("arc: NKEEP(pp) = %d.\n", NKEEP(pp)); printf("arc: PRECISION = %d.\n", peer->precision); } #endif @@ -1185,9 +1384,11 @@ arc_receive( #endif if (!refclock_process(pp)) { + pp->lencode = 0; refclock_report(peer, CEVNT_BADTIME); return; } + record_clock_stats(&peer->srcadr, pp->a_lastcode); refclock_receive(peer); } @@ -1208,9 +1409,12 @@ request_time( if(debug) { printf("arc: unit %d: requesting time.\n", unit); } #endif if (!send_slow(up, pp->io.fd, "o\r")) { -#ifdef ARCRON_DEBUG - msyslog(LOG_NOTICE, "ARCRON: unit %d: problem sending", unit); +#ifdef DEBUG + if (debug) { + printf("arc: unit %d: problem sending", unit); + } #endif + pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } @@ -1232,8 +1436,10 @@ arc_poll( pp = peer->procptr; up = (struct arcunit *)pp->unitptr; +#if 0 pp->lencode = 0; memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode)); +#endif #if 0 /* Flush input. */ @@ -1241,7 +1447,8 @@ arc_poll( #endif /* Resync if our next scheduled resync time is here or has passed. */ - resync_needed = (up->next_resync <= current_time); + resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) && + (up->next_resync <= current_time) ); #ifdef ARCRON_LEAPSECOND_KEEN /* @@ -1309,6 +1516,7 @@ arc_poll( printf("arc: clock quality %d too poor.\n", up->quality); } #endif + pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } diff --git a/contrib/ntp/ntpd/refclock_as2201.c b/contrib/ntp/ntpd/refclock_as2201.c index 516f7ad..f04d417b 100644 --- a/contrib/ntp/ntpd/refclock_as2201.c +++ b/contrib/ntp/ntpd/refclock_as2201.c @@ -299,12 +299,13 @@ as2201_receive( /* * Timecode format: "yy:ddd:hh:mm:ss.mmm" */ - if (sscanf(pp->a_lastcode, "%2d:%3d:%2d:%2d:%2d.%3d", &pp->year, - &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->msec) + if (sscanf(pp->a_lastcode, "%2d:%3d:%2d:%2d:%2d.%3ld", &pp->year, + &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec) != 6) { refclock_report(peer, CEVNT_BADREPLY); return; } + pp->nsec *= 1000000; /* * Test for synchronization (this is a temporary crock). diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c index 56f86b3..51153ae 100644 --- a/contrib/ntp/ntpd/refclock_atom.c +++ b/contrib/ntp/ntpd/refclock_atom.c @@ -1,3 +1,4 @@ + /* * refclock_atom - clock driver for 1-pps signals */ @@ -75,8 +76,6 @@ * Interface definitions */ #ifdef HAVE_PPSAPI -extern int pps_assert; /* selects rising or falling edge */ -extern int pps_hardpps; /* enables the kernel PPS interface */ #define DEVICE "/dev/pps%d" /* device name and unit */ #endif /* HAVE_PPSAPI */ @@ -159,9 +158,9 @@ atom_start( pp = peer->procptr; peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; + pp->stratum = STRATUM_UNSPEC; memcpy((char *)&pp->refid, REFID, 4); peer->burst = ASTAGE; - peer->stratum = STRATUM_UNSPEC; #ifdef HAVE_PPSAPI up = emalloc(sizeof(struct ppsunit)); memset(up, 0, sizeof(struct ppsunit)); @@ -194,7 +193,7 @@ atom_start( "refclock_atom: time_pps_create failed: %m"); return (0); } - return (atom_ppsapi(peer, pps_assert, pps_hardpps)); + return (atom_ppsapi(peer, 0, 0)); #else /* HAVE_PPSAPI */ return (1); #endif /* HAVE_PPSAPI */ @@ -250,7 +249,7 @@ atom_ppsapi( if (!up->pps_params.mode) { msyslog(LOG_ERR, "refclock_atom: invalid capture edge %d", - pps_assert); + enb_clear); return (0); } up->pps_params.mode |= PPS_TSFMT_TSPEC; @@ -459,17 +458,17 @@ atom_poll( * +-0.5 s of the local time and the seconds numbering is * unambiguous. Note that the leap bits are set no-warning on * the first valid update and the stratum is set at the prefer - * peer. + * peer, unless overriden by a fudge command. */ if (peer->burst > 0) return; - peer->stratum = STRATUM_UNSPEC; + peer->leap = LEAP_NOTINSYNC; if (pp->codeproc == pp->coderecv) { refclock_report(peer, CEVNT_TIMEOUT); peer->burst = ASTAGE; return; - } else if (!sys_prefer) { + } else if (sys_prefer == NULL) { pp->codeproc = pp->coderecv; peer->burst = ASTAGE; return; @@ -479,12 +478,17 @@ atom_poll( peer->burst = ASTAGE; return; } - peer->stratum = sys_prefer->stratum; - if (peer->stratum <= 1) + pp->leap = LEAP_NOWARNING; + if (pp->stratum >= STRATUM_UNSPEC) + peer->stratum = sys_prefer->stratum; + else + peer->stratum = pp->stratum; + if (peer->stratum == STRATUM_REFCLOCK || peer->stratum == + STRATUM_UNSPEC) peer->refid = pp->refid; else - peer->refid = peer->srcadr.sin_addr.s_addr; - pp->leap = LEAP_NOWARNING; + peer->refid = addr2refid(&sys_prefer->srcadr); + pp->lastref = pp->lastrec; refclock_receive(peer); peer->burst = ASTAGE; } diff --git a/contrib/ntp/ntpd/refclock_bancomm.c b/contrib/ntp/ntpd/refclock_bancomm.c index a3debcb..a63be44 100644 --- a/contrib/ntp/ntpd/refclock_bancomm.c +++ b/contrib/ntp/ntpd/refclock_bancomm.c @@ -317,8 +317,9 @@ vme_poll( refclock_report(peer, CEVNT_BADTIME); return; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); + record_clock_stats(&peer->srcadr, pp->a_lastcode); } struct vmedate * diff --git a/contrib/ntp/ntpd/refclock_chronolog.c b/contrib/ntp/ntpd/refclock_chronolog.c index 9273a84..a1d131e 100644 --- a/contrib/ntp/ntpd/refclock_chronolog.c +++ b/contrib/ntp/ntpd/refclock_chronolog.c @@ -215,7 +215,6 @@ chronolog_receive( * calls since it is transmitted a few seconds ahead of the * timestamp. */ - pp->msec = 0; got_good=0; if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day)) { @@ -293,8 +292,9 @@ chronolog_receive( refclock_report(peer, CEVNT_BADTIME); return; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); + record_clock_stats(&peer->srcadr, pp->a_lastcode); up->lasthour = pp->hour; } diff --git a/contrib/ntp/ntpd/refclock_chu.c b/contrib/ntp/ntpd/refclock_chu.c index b239ad6..e0c79e2 100644 --- a/contrib/ntp/ntpd/refclock_chu.c +++ b/contrib/ntp/ntpd/refclock_chu.c @@ -40,10 +40,10 @@ * change throughout the day and night. * * The driver receives, demodulates and decodes the radio signals when - * connected to the audio codec of a Sun workstation running SunOS or - * Solaris, 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. + * 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 can be compiled to use a Bell 103 compatible modem or * modem chip to receive the radio signal and demodulate the data. @@ -105,8 +105,8 @@ * * The timecode format used for debugging and data recording includes * data helpful in diagnosing problems with the radio signal and serial - * connections. With debugging enabled (-d -d -d on the ntpd command - * line), the driver produces one line for each burst in two formats + * 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: * * n b f s m code @@ -161,22 +161,22 @@ * * For accuracies better than the low millisceconds, fudge time1 can be * set to the radio propagation delay from CHU to the receiver. This can - * be done conviently using the minimuf program. When the modem driver - * is compiled, fudge flag3 enables the ppsclock line discipline. Fudge - * flag4 causes the dubugging output described above to be recorded in - * the clockstats file. + * be done conviently using the minimuf program. * - * When the audio driver is compiled, 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 speaker volume must be set before the driver is started. + * Fudge flag4 causes the dubugging output described above to be + * recorded in the clockstats file. When the audio driver is compiled, + * 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. * * The audio codec code is normally compiled in the driver if the - * architecture supports it (HAVE_AUDIO defined), but is used only if the - * link /dev/chu_audio is defined and valid. The serial port - * code is alwasy compiled in the driver, but is used only if the autdio - * codec is not available and the link /dev/chu%d is defined and valid. + * architecture supports it (HAVE_AUDIO defined), but is used only if + * the link /dev/chu_audio is defined and valid. The serial port code is + * always compiled in the driver, but is used only if the autdio codec + * is not available and the link /dev/chu%d is defined and valid. + * * The ICOM code is normally compiled in the driver if selected (ICOM * defined), but is used only if the link /dev/icom%d is defined and * valid and the mode keyword on the server configuration command @@ -194,11 +194,13 @@ #define DEVICE "/dev/chu%d" /* device name and unit */ #define SPEED232 B300 /* UART speed (300 baud) */ #ifdef ICOM -#define DWELL 5 /* minutes before qsy */ +#define TUNE .001 /* offset for narrow filter (kHz) */ +#define DWELL 5 /* minutes in a probe cycle */ #define NCHAN 3 /* number of channels */ +#define ISTAGE 3 /* number of integrator stages */ #endif /* ICOM */ -#ifdef HAVE_AUDIO +#ifdef HAVE_AUDIO /* * Audio demodulator definitions */ @@ -207,11 +209,13 @@ #define OFFSET 128 /* companded sample offset */ #define SIZE 256 /* decompanding table size */ #define MAXSIG 6000. /* maximum signal level */ +#define MAXCLP 100 /* max clips above reference per s */ #define LIMIT 1000. /* soft limiter threshold */ #define AGAIN 6. /* baseband gain */ #define LAG 10 /* discriminator lag */ #define DEVICE_AUDIO "/dev/chu_audio" /* device name */ #define DESCRIPTION "CHU Audio/Modem Receiver" /* WRU */ +#define AUDIO_BUFSIZ 240 /* audio buffer size (30 ms) */ #else #define DESCRIPTION "CHU Modem Receiver" /* WRU */ #endif /* HAVE_AUDIO */ @@ -224,16 +228,19 @@ #define BURST 11 /* max characters per burst */ #define MINCHAR 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 PANIC (4 * 1440) /* panic restart */ +#define METRIC 50. /* min channel metric */ +#define PANIC 1440 /* panic timeout (m) */ +#define HOLD 30 /* reach hold (m) */ /* * Hex extension codes (>= 16) */ -#define HEX_MISS 16 /* miss */ -#define HEX_SOFT 17 /* soft error */ -#define HEX_HARD 18 /* hard error */ +#define HEX_MISS 16 /* miss _ */ +#define HEX_SOFT 17 /* soft error * */ +#define HEX_HARD 18 /* hard error = */ /* * Status bits (status) @@ -246,8 +253,9 @@ #define AFORMAT 0x0020 /* invalid format A data */ #define DECODE 0x0040 /* invalid data decode */ #define STAMP 0x0080 /* too few timestamps */ -#define INYEAR 0x0100 /* valid B frame */ -#define INSYNC 0x0200 /* clock synchronized */ +#define AVALID 0x0100 /* valid A frame */ +#define BVALID 0x0200 /* valid B frame */ +#define INSYNC 0x0400 /* clock synchronized */ /* * Alarm status bits (alarm) @@ -264,6 +272,10 @@ #define TSPERR 0x08 /* insufficient data */ #ifdef HAVE_AUDIO +/* + * 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 */ @@ -272,6 +284,19 @@ struct surv { }; #endif /* HAVE_AUDIO */ +#ifdef ICOM +/* + * CHU station structure. There are three of these corresponding to the + * three frequencies. + */ +struct xmtr { + double integ[ISTAGE]; /* circular integrator */ + double metric; /* integrator sum */ + int iptr; /* integrator pointer */ + int probe; /* dwells since last probe */ +}; +#endif /* ICOM */ + /* * CHU unit control structure */ @@ -284,12 +309,13 @@ struct chuunit { l_fp charstamp; /* character time as a l_fp */ int errflg; /* error flags */ int status; /* status bits */ - int bufptr; /* buffer index pointer */ - char ident[10]; /* transmitter frequency */ + char ident[5]; /* station ID and channel */ #ifdef ICOM int fd_icom; /* ICOM file descriptor */ - int chan; /* frequency identifier */ - int dwell; /* dwell minutes at current frequency */ + int chan; /* data channel */ + int achan; /* active channel */ + int dwell; /* dwell cycle */ + struct xmtr xmtr[NCHAN]; /* station metric */ #endif /* ICOM */ /* @@ -300,7 +326,6 @@ struct chuunit { int ndx; /* buffer start index */ int prevsec; /* previous burst second */ int burdist; /* burst distance */ - int mindist; /* minimum distance */ int syndist; /* sync distance */ int burstcnt; /* format A bursts this minute */ @@ -320,7 +345,7 @@ struct chuunit { double comp[SIZE]; /* decompanding table */ int port; /* codec port */ int gain; /* codec gain */ - int bufcnt; /* samples in buffer */ + int mongain; /* codec monitor gain */ int clipcnt; /* sample clip count */ int seccnt; /* second interval counter */ @@ -362,21 +387,30 @@ 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 int chu_major P((struct peer *)); +static double chu_major P((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)); #endif /* HAVE_AUDIO */ +#ifdef ICOM +static int chu_newchan P((struct peer *, double)); +#endif /* ICOM */ static void chu_serial_receive P((struct recvbuf *rbufp)); /* * Global variables */ -static char hexchar[] = "0123456789abcdef_-="; +static char hexchar[] = "0123456789abcdef_*="; + #ifdef ICOM -static double qsy[NCHAN] = {3.33, 7.335, 14.67}; /* frequencies (MHz) */ +/* + * Note the tuned frequencies are 1 kHz higher than the carrier. CHU + * 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) */ #endif /* ICOM */ /* @@ -407,7 +441,6 @@ chu_start( char device[20]; /* device name */ int fd; /* file descriptor */ #ifdef ICOM - char tbuf[80]; /* trace buffer */ int temp; #endif /* ICOM */ #ifdef HAVE_AUDIO @@ -418,7 +451,7 @@ chu_start( /* * Open audio device. */ - fd_audio = audio_init(DEVICE_AUDIO); + fd_audio = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); #ifdef DEBUG if (fd_audio > 0 && debug) audio_show(); @@ -470,7 +503,8 @@ chu_start( */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); + strcpy(up->ident, "CHU"); + memcpy(&peer->refid, up->ident, 4); DTOLFP(CHAR, &up->charstamp); #ifdef HAVE_AUDIO @@ -493,15 +527,14 @@ chu_start( } DTOLFP(1. / SECOND, &up->tick); #endif /* HAVE_AUDIO */ - strcpy(up->ident, "X"); #ifdef ICOM temp = 0; #ifdef DEBUG if (debug > 1) temp = P_TRACE; #endif - if (peer->ttlmax > 0) { - if (peer->ttlmax & 0x80) + if (peer->ttl > 0) { + if (peer->ttl & 0x80) up->fd_icom = icom_init("/dev/icom", B1200, temp); else @@ -509,22 +542,17 @@ chu_start( temp); } if (up->fd_icom > 0) { - if (icom_freq(up->fd_icom, peer->ttlmax & 0x7f, - qsy[up->chan]) < 0) { + if (chu_newchan(peer, 0) != 0) { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_ERR, - "ICOM bus error; autotune disabled"); + msyslog(LOG_NOTICE, + "icom: radio not found"); up->errflg = CEVNT_FAULT; close(up->fd_icom); up->fd_icom = 0; } else { - sprintf(up->ident, "%.1f", qsy[up->chan]); - sprintf(tbuf, "chu: QSY to %s MHz", up->ident); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_NOTICE, + "icom: autotune enabled"); } } #endif /* ICOM */ @@ -548,12 +576,16 @@ chu_shutdown( up = (struct chuunit *)pp->unitptr; if (up == NULL) return; + io_closeclock(&pp->io); +#ifdef ICOM if (up->fd_icom > 0) close(up->fd_icom); +#endif /* ICOM */ free(up); } + /* * chu_receive - receive data from the audio or serial device */ @@ -588,8 +620,8 @@ chu_receive( #endif /* HAVE_AUDIO */ } -#ifdef HAVE_AUDIO +#ifdef HAVE_AUDIO /* * chu_audio_receive - receive data from the audio device */ @@ -604,10 +636,8 @@ chu_audio_receive( double sample; /* codec sample */ u_char *dpt; /* buffer pointer */ + int bufcnt; /* buffer counter */ l_fp ltemp; /* l_fp temp */ - int isneg; /* parity flag */ - double dtemp; - int i, j; peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; @@ -617,13 +647,12 @@ chu_audio_receive( * Main loop - read until there ain't no more. Note codec * samples are bit-inverted. */ + DTOLFP((double)rbufp->recv_length / SECOND, <emp); + L_SUB(&rbufp->recv_time, <emp); up->timestamp = rbufp->recv_time; - up->bufcnt = rbufp->recv_length; - DTOLFP(up->bufcnt * 1. / SECOND, <emp); - L_SUB(&up->timestamp, <emp); - dpt = (u_char *)&rbufp->recv_space; - for (up->bufptr = 0; up->bufptr < up->bufcnt; up->bufptr++) { - sample = up->comp[~*dpt & 0xff]; + dpt = rbufp->recv_buffer; + for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { + sample = up->comp[~*dpt++ & 0xff]; /* * Clip noise spikes greater than MAXSIG. If no clips, @@ -637,56 +666,30 @@ chu_audio_receive( sample = -MAXSIG; up->clipcnt++; } - up->seccnt = (up->seccnt + 1) % SECOND; - if (up->seccnt == 0) { - if (pp->sloppyclockflag & CLK_FLAG2) - up->port = 2; - else - up->port = 1; - chu_gain(peer); - } chu_rf(peer, sample); + L_ADD(&up->timestamp, &up->tick); /* - * During development, it is handy to have an audio - * monitor that can be switched to various signals. This - * code converts the linear signal left in up->monitor - * to codec format. If we can get the grass out of this - * thing and improve modem performance, this expensive - * code will be permanently nixed. + * Once each second ride gain. */ - isneg = 0; - dtemp = up->monitor; - if (sample < 0) { - isneg = 1; - dtemp-= dtemp; - } - i = 0; - j = OFFSET >> 1; - while (j != 0) { - if (dtemp > up->comp[i]) - i += j; - else if (dtemp < up->comp[i]) - i -= j; - else - break; - j >>= 1; + up->seccnt = (up->seccnt + 1) % SECOND; + if (up->seccnt == 0) { + pp->second = (pp->second + 1) % 60; + chu_gain(peer); } - if (isneg) - *dpt = ~(i + OFFSET); - else - *dpt = ~i; - dpt++; - L_ADD(&up->timestamp, &up->tick); } - + /* - * Squawk to the monitor speaker if enabled. + * Set the input port and monitor gain for the next buffer. */ + if (pp->sloppyclockflag & CLK_FLAG2) + up->port = 2; + else + up->port = 1; if (pp->sloppyclockflag & CLK_FLAG3) - if (write(pp->io.fd, (u_char *)&rbufp->recv_space, - (u_int)up->bufcnt) < 0) - perror("chu:"); + up->mongain = MONGAIN; + else + up->mongain = 0; } @@ -1068,13 +1071,13 @@ chu_b( * 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. + * 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]); + sprintf(&tbuf[strlen(tbuf)], "%02x", up->cbuf[i]); if (pp->sloppyclockflag & CLK_FLAG4) record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG @@ -1085,7 +1088,7 @@ chu_b( up->status |= BFRAME; return; } - up->status |= INYEAR; + up->status |= BVALID; /* * Convert the burst data to internal format. If this succeeds, @@ -1201,6 +1204,7 @@ chu_a( * the previous burst to the current one. */ if (temp != 0) { + pp->second = 30 + temp; offset.l_ui = 30 + temp; offset.l_f = 0; i = 0; @@ -1236,6 +1240,7 @@ chu_a( up->decode[i][(up->cbuf[j] >> 4) & 0xf]++; i++; } + up->status |= AVALID; up->burstcnt++; } @@ -1251,54 +1256,48 @@ chu_poll( { struct refclockproc *pp; struct chuunit *up; + l_fp offset; char synchar, qual, leapchar; - int minset; - int temp; -#ifdef ICOM - char tbuf[80]; /* trace buffer */ -#endif /* ICOM */ + int minset, i; + double dtemp; + pp = peer->procptr; up = (struct chuunit *)pp->unitptr; if (pp->coderecv == pp->codeproc) up->errflg = CEVNT_TIMEOUT; else pp->polls++; + + /* + * 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. + */ minset = ((current_time - peer->update) + 30) / 60; if (up->status & INSYNC) { if (minset > PANIC) up->status = 0; - else + else if (minset <= HOLD) peer->reach |= 1; } /* * Process the last burst, if still in the burst buffer. - * Don't mess with anything if nothing has been heard. + * 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. */ chu_burst(peer); + if (up->burstcnt == 0) { #ifdef ICOM - if (up->burstcnt > 2) { - up->dwell = 0; - } else if (up->dwell < DWELL) { - up->dwell++; - } else if (up->fd_icom > 0) { - up->dwell = 0; - up->chan = (up->chan + 1) % NCHAN; - icom_freq(up->fd_icom, peer->ttlmax & 0x7f, qsy[up->chan]); - sprintf(up->ident, "%.3f", qsy[up->chan]); - sprintf(tbuf, "chu: QSY to %s MHz", up->ident); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif - } + chu_newchan(peer, 0); #endif /* ICOM */ - if (up->burstcnt == 0) return; - temp = chu_major(peer); - if (up->status & INYEAR) - up->status |= INSYNC; + } + dtemp = chu_major(peer); qual = 0; if (up->status & (BFRAME | AFRAME)) qual |= SYNERR; @@ -1308,6 +1307,8 @@ chu_poll( qual |= DECERR; if (up->status & STAMP) qual |= TSPERR; + if (up->status & AVALID && up->status & BVALID) + up->status |= INSYNC; synchar = leapchar = ' '; if (!(up->status & INSYNC)) { pp->leap = LEAP_NOTINSYNC; @@ -1324,34 +1325,45 @@ chu_poll( #ifdef HAVE_AUDIO if (up->fd_audio) sprintf(pp->a_lastcode, - "%c%1X %4d %3d %02d:%02d:%02d.000 %c%x %+d %d %d %s %d %d %d %d", + "%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, up->tai, up->burstcnt, - up->mindist, up->ntstamp); + minset, up->gain, up->ident, dtemp, up->ntstamp); else sprintf(pp->a_lastcode, - "%c%1X %4d %3d %02d:%02d:%02d.000 %c%x %+d %d %s %d %d %d %d", + "%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, up->tai, up->burstcnt, - up->mindist, up->ntstamp); + minset, up->ident, dtemp, up->ntstamp); #else sprintf(pp->a_lastcode, - "%c%1X %4d %3d %02d:%02d:%02d.000 %c%x %+d %d %s %d %d %d %d", + "%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, up->tai, up->burstcnt, up->mindist, up->ntstamp); + pp->second, leapchar, up->dst, up->dut, minset, up->ident, + dtemp, up->ntstamp); #endif /* HAVE_AUDIO */ pp->lencode = strlen(pp->a_lastcode); /* - * If timestamps have been stuffed, the timecode is ipso fatso - * correct and can be selected to discipline the clock. + * 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. */ - if (temp > 0) { + if (up->status & INSYNC && dtemp > METRIC) { + if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT, + up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) { + up->errflg = CEVNT_BADTIME; + } else { + offset.l_uf = 0; + for (i = 0; i < up->ntstamp; i++) + refclock_process_offset(pp, offset, + up->tstamp[i], FUDGE + + pp->fudgetime1); + pp->lastref = up->timestamp; + refclock_receive(peer); + } record_clock_stats(&peer->srcadr, pp->a_lastcode); - refclock_receive(peer); } else if (pp->sloppyclockflag & CLK_FLAG4) { record_clock_stats(&peer->srcadr, pp->a_lastcode); } @@ -1360,6 +1372,9 @@ chu_poll( printf("chu: timecode %d %s\n", pp->lencode, pp->a_lastcode); #endif +#ifdef ICOM + chu_newchan(peer, dtemp); +#endif /* ICOM */ chu_clear(peer); if (up->errflg) refclock_report(peer, up->errflg); @@ -1370,7 +1385,7 @@ chu_poll( /* * chu_major - majority decoder */ -static int +static double chu_major( struct peer *peer /* peer structure pointer */ ) @@ -1379,10 +1394,9 @@ chu_major( struct chuunit *up; u_char code[11]; /* decoded timecode */ - l_fp toffset, offset; /* l_fp temps */ + int mindist; /* minimum distance */ int val1, val2; /* maximum distance */ int synchar; /* stray cat */ - double dtemp; int temp; int i, j, k; @@ -1392,20 +1406,20 @@ chu_major( /* * Majority decoder. Each burst encodes two replications at each * digit position in the timecode. Each row of the decoding - * matrix encodes the number of occurences of each digit found + * matrix encodes the number of occurrences of each digit found * at the corresponding position. The maximum over all - * occurences at each position is the distance for this position - * and the corresponding digit is the maximumn likelihood - * candidate. If the distance is zero, assume a miss '_'; if the - * distance is not more than half the total number of - * occurences, 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. + * 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. */ - up->mindist = 16; + mindist = 16; for (i = 0; i < 9; i++) { val1 = val2 = 0; k = 0; @@ -1425,19 +1439,18 @@ chu_major( code[i] = HEX_SOFT; else code[i] = k; - if (val1 < up->mindist) - up->mindist = val1; + if (val1 < mindist) + mindist = val1; code[i] = hexchar[code[i]]; } code[i] = 0; /* - * A valid timecode requires at least three bursts and a - * decoding distance greater than half the total number of - * occurences. A valid timecode also requires at least 20 valid - * timestamps. + * 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 < 3 || up->mindist <= up->burstcnt) + if (up->burstcnt < MINBURST || mindist < up->burstcnt) up->status |= DECODE; if (up->ntstamp < MINSTAMP) up->status |= STAMP; @@ -1458,20 +1471,7 @@ chu_major( up->errflg = CEVNT_BADREPLY; return (0); } - L_CLR(&offset); - if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT, - up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) { - up->errflg = CEVNT_BADTIME; - return (0); - } - pp->lastref = offset; - for (i = 0; i < up->ntstamp; i++) { - toffset = offset; - L_SUB(&toffset, &up->tstamp[i]); - LFPTOD(&toffset, dtemp); - SAMPLE(dtemp + FUDGE + pp->fudgetime1); - } - return (i); + return (mindist * 100. / (2. * up->burstcnt)); } @@ -1494,15 +1494,120 @@ chu_clear( * Clear stuff for the minute. */ up->ndx = up->prevsec = 0; - up->burstcnt = up->mindist = up->ntstamp = 0; - up->status &= INSYNC | INYEAR; - up->burstcnt = 0; + up->burstcnt = up->ntstamp = 0; + up->status &= INSYNC; for (i = 0; i < 20; i++) { for (j = 0; j < 16; j++) up->decode[i][j] = 0; } } +#ifdef ICOM +/* + * chu_newchan - called once per minute to find the best channel; + * returns zero on success, nonzero if ICOM error. + */ +static int +chu_newchan( + struct peer *peer, + double met + ) +{ + struct chuunit *up; + struct refclockproc *pp; + struct xmtr *sp; + char tbuf[80]; /* trace buffer */ + int rval; + double metric; + int i, j; + + pp = peer->procptr; + up = (struct chuunit *)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 + * 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. + */ + if (up->fd_icom <= 0) + return (0); + + sp = &up->xmtr[up->achan]; + sp->metric -= sp->integ[sp->iptr]; + sp->integ[sp->iptr] = met; + sp->metric += sp->integ[sp->iptr]; + 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 + } + + /* + * 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. + */ + 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) { + 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; + } + } + sprintf(up->ident, "CHU%d", up->achan); + memcpy(&peer->refid, up->ident, 4); + up->dwell = (up->dwell + 1) % DWELL; + return (rval); +} +#endif /* ICOM */ /* * chu_dist - determine the distance of two octet arguments @@ -1564,14 +1669,14 @@ chu_gain( */ if (up->clipcnt == 0) { up->gain += 4; - if (up->gain > 255) - up->gain = 255; - } else if (up->clipcnt > SECOND / 100) { + if (up->gain > MAXGAIN) + up->gain = MAXGAIN; + } else if (up->clipcnt > MAXCLP) { up->gain -= 4; if (up->gain < 0) up->gain = 0; } - audio_gain(up->gain, up->port); + audio_gain(up->gain, up->mongain, up->port); up->clipcnt = 0; } #endif /* HAVE_AUDIO */ diff --git a/contrib/ntp/ntpd/refclock_conf.c b/contrib/ntp/ntpd/refclock_conf.c index 04166d9..8a424f0 100644 --- a/contrib/ntp/ntpd/refclock_conf.c +++ b/contrib/ntp/ntpd/refclock_conf.c @@ -192,7 +192,7 @@ extern struct refclock refclock_oncore; #define refclock_oncore refclock_none #endif -#if defined(CLOCK_JUPITER) && defined(PPS) +#if defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) extern struct refclock refclock_jupiter; #else #define refclock_jupiter refclock_none diff --git a/contrib/ntp/ntpd/refclock_datum.c b/contrib/ntp/ntpd/refclock_datum.c index db03c95..82b7369 100644 --- a/contrib/ntp/ntpd/refclock_datum.c +++ b/contrib/ntp/ntpd/refclock_datum.c @@ -712,6 +712,7 @@ datum_pts_receive( &datum_pts->yearstart, &datum_pts->lastref.l_ui) ) { + datum_pts->lastref.l_uf = 0; error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui; #ifdef DEBUG_DATUM_PTC @@ -813,6 +814,7 @@ datum_pts_receive( ** necessary to use fudge factors in the ntp.conf file. Maybe later we will. */ /*LFPTOD(&tstmp, doffset);*/ + datum_pts->lastref = datum_pts->lastrec; refclock_receive(datum_pts->peer); /* diff --git a/contrib/ntp/ntpd/refclock_dumbclock.c b/contrib/ntp/ntpd/refclock_dumbclock.c index c439646..2788649 100644 --- a/contrib/ntp/ntpd/refclock_dumbclock.c +++ b/contrib/ntp/ntpd/refclock_dumbclock.c @@ -12,6 +12,11 @@ #include #endif +#if defined(SYS_WINNT) +#undef close +#define close closesocket +#endif + #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) #include "ntpd.h" @@ -114,14 +119,15 @@ dumbclock_start( if (debug) printf ("starting Dumbclock 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 dumbclock_unit *) - emalloc(sizeof(struct dumbclock_unit)))) { + up = (struct dumbclock_unit *)emalloc(sizeof(struct dumbclock_unit)); + if (up == NULL) { (void) close(fd); return (0); } @@ -218,7 +224,7 @@ dumbclock_receive( up->tcswitch = 0; return; } - pp->lencode = temp; + pp->lencode = (u_short)temp; pp->lastrec = up->laststamp; up->laststamp = trtmp; up->tcswitch = 1; @@ -232,7 +238,6 @@ dumbclock_receive( /* * We get down to business. Check the timecode format... */ - pp->msec = 0; got_good=0; if (sscanf(pp->a_lastcode,"%02d:%02d:%02d", &hours,&minutes,&seconds) == 3) @@ -330,9 +335,10 @@ dumbclock_receive( refclock_report(peer, CEVNT_BADTIME); return; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); - up->lasthour = pp->hour; + record_clock_stats(&peer->srcadr, pp->a_lastcode); + up->lasthour = (u_char)pp->hour; } #if 0 diff --git a/contrib/ntp/ntpd/refclock_fg.c b/contrib/ntp/ntpd/refclock_fg.c index 655b6bc..ebcf1b5 100644 --- a/contrib/ntp/ntpd/refclock_fg.c +++ b/contrib/ntp/ntpd/refclock_fg.c @@ -299,14 +299,14 @@ fg_receive( { pp->minute = BP1(7)*10 + BP2(7); pp->second = BP1(8)*10 + BP2(8); - pp->msec = BP1(9)*10 + BP2(9); - pp->usec = BP1(10); + 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->msec = BP1(8)*10 + BP2(8); - pp->usec = BP1(9); + pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000; + pp->nsec += BP1(9) * 1000; } if((pp->hour == 10) && (pp->minute == 10)) @@ -327,7 +327,7 @@ fg_receive( if (peer->stratum <= 1) peer->refid = pp->refid; pp->disp = (10e-6); - pp->lastrec = rbufp->recv_time; /* Is it better then get_systime()? */ + pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */ /* pp->leap = LEAP_NOWARNING; */ /* @@ -337,7 +337,7 @@ fg_receive( if (!refclock_process(pp)) refclock_report(peer, CEVNT_BADTIME); - + pp->lastref = pp->lastrec; refclock_receive(peer); return; } diff --git a/contrib/ntp/ntpd/refclock_gpsvme.c b/contrib/ntp/ntpd/refclock_gpsvme.c index 42eb2f9..a7fcf5f 100644 --- a/contrib/ntp/ntpd/refclock_gpsvme.c +++ b/contrib/ntp/ntpd/refclock_gpsvme.c @@ -349,6 +349,7 @@ vme_poll( l_fp tstmp; time_t tloc; struct tm *tadr; + long ltemp; @@ -395,13 +396,13 @@ vme_poll( vme->hour = tptr->hr; vme->minute = tptr->mn; vme->second = tptr->sec; - vme->usec = tptr->frac; + vme->nsec = tptr->frac * 1000; #ifdef DEBUG if (debug) printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n", vme->day, vme->hour, vme->minute, vme->second, - vme->usec, tptr->status); + vme->nsec, tptr->status); #endif if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ vme_report_event(vme, CEVNT_BADREPLY); @@ -424,14 +425,16 @@ vme_poll( msyslog(LOG_ERR, "refclock_gpsvme: bad data!!"); return; } - TVUTOTSF(vme->usec, vme->lastref.l_uf); + vme->lastref.l_uf = 0; + DTOLFP(vme->nsec / 1e9, <emp); + L_ADD(&vme->lastrec, <emp); tstmp = vme->lastref; L_SUB(&tstmp, &vme->lastrec); vme->coderecv++; L_ADD(&tstmp, &(fudgefactor[vme->unit])); - + vme->lastref = vme->lastrec; refclock_receive(vme->peer); } @@ -548,7 +551,7 @@ vme_buginfo( bug->values[4] = (u_long)vme->hour; bug->values[5] = (u_long)vme->minute; bug->values[6] = (u_long)vme->second; - bug->values[7] = (u_long)vme->usec; + bug->values[7] = (u_long)vme->nsec; bug->values[9] = vme->yearstart; bug->stimes = 0x1c; bug->times[0] = vme->lastref; diff --git a/contrib/ntp/ntpd/refclock_heath.c b/contrib/ntp/ntpd/refclock_heath.c index ef4db5a..c16cef3 100644 --- a/contrib/ntp/ntpd/refclock_heath.c +++ b/contrib/ntp/ntpd/refclock_heath.c @@ -177,14 +177,6 @@ static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static int speed[] = {B1200, B2400, B4800, B9600}; /* - * Unit control structure - */ -struct heathunit { - int pollcnt; /* poll message counter */ - l_fp tstamp; /* timestamp of last poll */ -}; - -/* * Function prototypes */ static int heath_start P((int, struct peer *)); @@ -215,7 +207,6 @@ heath_start( struct peer *peer ) { - register struct heathunit *up; struct refclockproc *pp; int fd; char device[20]; @@ -224,18 +215,8 @@ heath_start( * Open serial port */ (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, speed[peer->ttlmax & 0x3], 0))) + if (!(fd = refclock_open(device, speed[peer->ttl & 0x3], 0))) return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct heathunit *) - emalloc(sizeof(struct heathunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct heathunit)); pp = peer->procptr; pp->io.clock_recv = heath_receive; pp->io.srcclock = (caddr_t)peer; @@ -243,10 +224,8 @@ heath_start( pp->io.fd = fd; if (!io_addclock(&pp->io)) { (void) close(fd); - free(up); return (0); } - pp->unitptr = (caddr_t)up; /* * Initialize miscellaneous variables @@ -255,7 +234,6 @@ heath_start( peer->burst = NSTAGE; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); - up->pollcnt = 2; return (1); } @@ -269,13 +247,10 @@ heath_shutdown( struct peer *peer ) { - register struct heathunit *up; struct refclockproc *pp; pp = peer->procptr; - up = (struct heathunit *)pp->unitptr; io_closeclock(&pp->io); - free(up); } @@ -287,7 +262,6 @@ heath_receive( struct recvbuf *rbufp ) { - register struct heathunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; @@ -300,27 +274,10 @@ heath_receive( */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; - up = (struct heathunit *)pp->unitptr; pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); /* - * We get a buffer and timestamp for each ; however, we use - * the timestamp captured at the RTS modem control line toggle - * on the assumption that's what the radio bases the timecode - * on. Apparently, the radio takes about a second to make up its - * mind to send a timecode, so the receive timestamp is - * worthless. - */ - pp->lastrec = up->tstamp; - up->pollcnt = 2; -#ifdef DEBUG - if (debug) - printf("heath: 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. @@ -396,7 +353,7 @@ heath_receive( if (!isdigit((int)dsec)) pp->leap = LEAP_NOTINSYNC; else { - pp->msec = (dsec - '0') * 100; + pp->nsec = (dsec - '0') * 100000000; pp->leap = LEAP_NOWARNING; } if (!refclock_process(pp)) @@ -413,7 +370,6 @@ heath_poll( struct peer *peer ) { - register struct heathunit *up; struct refclockproc *pp; int bits = TIOCM_RTS; @@ -421,10 +377,11 @@ heath_poll( * At each poll we check for timeout and toggle the RTS modem * control line, then take a timestamp. Presumably, this is the * event the radio captures to generate the timecode. + * Apparently, the radio takes about a second to make up its + * mind to send a timecode, so the receive timestamp is + * worthless. */ pp = peer->procptr; - up = (struct heathunit *)pp->unitptr; - pp->polls++; /* * We toggle the RTS modem control lead (GC-1000) and sent a T @@ -437,19 +394,26 @@ heath_poll( */ if (ioctl(pp->io.fd, TIOCMBIC, (char *)&bits) < 0) refclock_report(peer, CEVNT_FAULT); - get_systime(&up->tstamp); - ioctl(pp->io.fd, TIOCMBIS, (char *)&bits); + get_systime(&pp->lastrec); 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; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); - peer->burst = NSTAGE; + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug) + printf("heath: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + peer->burst = MAXSTAGE; + pp->polls++; } #else diff --git a/contrib/ntp/ntpd/refclock_hopfpci.c b/contrib/ntp/ntpd/refclock_hopfpci.c index a9deb21..1b02319 100644 --- a/contrib/ntp/ntpd/refclock_hopfpci.c +++ b/contrib/ntp/ntpd/refclock_hopfpci.c @@ -48,6 +48,7 @@ #ifndef SYS_WINNT # include +# include # include # include # include @@ -149,7 +150,7 @@ hopfpci_start( pp->io.clock_recv = noentry; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; - pp->io.fd = -1; + pp->io.fd = INVALID_SOCKET; pp->unitptr = (caddr_t)up; get_systime(&pp->lastrec); @@ -190,7 +191,7 @@ hopfpci_shutdown( close(fd); #else CloseHopfDevice(); -// UnmapViewOfFile (up); +/* UnmapViewOfFile (up); */ #endif } @@ -212,7 +213,7 @@ hopfpci_poll( up = (struct hopfpciTime *)pp->unitptr; #ifndef SYS_WINNT - ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time); + ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time); #else GetHopfSystemTime(&m_time); #endif @@ -222,17 +223,16 @@ hopfpci_poll( pp->hour = m_time.wHour; pp->minute = m_time.wMinute; pp->second = m_time.wSecond; - pp->msec=m_time.wMilliseconds; - pp->usec=0; + pp->nsec = m_time.wMilliseconds * 1000000; if (m_time.wStatus & LEWAPWAR) pp->leap = LEAP_ADDSECOND; else pp->leap = LEAP_NOWARNING; - sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03d D: %02d.%02d.%04d", - m_time.wStatus, pp->hour, pp->minute, pp->second, pp->msec, - m_time.wDay, m_time.wMonth, m_time.wYear); - pp->lencode = strlen(pp->a_lastcode); + 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); + pp->lencode = (u_short)strlen(pp->a_lastcode); get_systime(&pp->lastrec); @@ -262,10 +262,9 @@ hopfpci_poll( refclock_report(peer, CEVNT_BADTIME); return; } + pp->lastref = pp->lastrec; refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); - return; } diff --git a/contrib/ntp/ntpd/refclock_hopfser.c b/contrib/ntp/ntpd/refclock_hopfser.c index a9d74dd..1d27333 100644 --- a/contrib/ntp/ntpd/refclock_hopfser.c +++ b/contrib/ntp/ntpd/refclock_hopfser.c @@ -14,6 +14,11 @@ # include "config.h" #endif +#if defined(SYS_WINNT) +#undef close +#define close closesocket +#endif + #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL)) #include "ntpd.h" @@ -216,7 +221,7 @@ hopfserial_receive ( struct refclockproc *pp; struct peer *peer; - int sync; /* synchronization indicator */ + int synch; /* synchhronization indicator */ int DoW; /* Dow */ int day, month; /* ddd conversion */ @@ -234,7 +239,7 @@ hopfserial_receive ( up->rpt_next = 0; /* wait until next poll interval occur */ - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); + pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); if (pp->lencode == 0) return; @@ -245,7 +250,7 @@ hopfserial_receive ( #else "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ #endif - &sync, + &synch, &DoW, &pp->hour, &pp->minute, @@ -286,7 +291,7 @@ hopfserial_receive ( #if 0 wsprintf(pp->a_lastcode, "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", - sync, + synch, DoW, day, month, @@ -296,7 +301,7 @@ hopfserial_receive ( pp->second); pp->lencode = strlen(pp->a_lastcode); - if ((sync && 0xc) == 0 ){ /* time ok? */ + if ((synch && 0xc) == 0 ){ /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; @@ -305,7 +310,7 @@ hopfserial_receive ( /* * If clock has no valid status then report error and exit */ - if ((sync & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ + if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; @@ -316,7 +321,7 @@ hopfserial_receive ( * if CLK_FLAG1 is set, sychronize even if no radio operation */ - if ((sync & HOPF_OPMODE) == HOPF_INTERNAL){ + if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){ if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; @@ -329,10 +334,11 @@ hopfserial_receive ( refclock_report(peer, CEVNT_BADTIME); return; } + pp->lastref = pp->lastrec; refclock_receive(peer); #if 0 - msyslog(LOG_ERR, " D:%x D:%d D:%d",sync,pp->minute,pp->second); + msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second); #endif record_clock_stats(&peer->srcadr, pp->a_lastcode); diff --git a/contrib/ntp/ntpd/refclock_hpgps.c b/contrib/ntp/ntpd/refclock_hpgps.c index 7a506cf..7c801bb 100644 --- a/contrib/ntp/ntpd/refclock_hpgps.c +++ b/contrib/ntp/ntpd/refclock_hpgps.c @@ -554,6 +554,7 @@ hpgps_receive( refclock_report(peer, CEVNT_BADTIME); return; } + pp->lastref = pp->lastrec; refclock_receive(peer); /* diff --git a/contrib/ntp/ntpd/refclock_irig.c b/contrib/ntp/ntpd/refclock_irig.c index 7efd57e..0b35368 100644 --- a/contrib/ntp/ntpd/refclock_irig.c +++ b/contrib/ntp/ntpd/refclock_irig.c @@ -75,8 +75,8 @@ * 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 + * 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 @@ -97,11 +97,11 @@ * * 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 -d -d on the ntpd command - * line), the driver produces one line for each timecode in the - * following format: + * connections. With debugging enabled (-d on the ntpd command line), + * the driver produces one line for each timecode in the following + * format: * - * 00 1 98 23 19:26:52 721 143 0.694 47 20 0.083 66.5 3094572411.00027 + * 00 1 98 23 19:26:52 721 143 0.694 20 0.1 66.5 3094572411.00027 * * The most recent line is also written to the clockstats file at 64-s * intervals. @@ -111,14 +111,18 @@ * 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), - * field phase (0-79), time constant (2-20), modulation index (0-1), - * carrier phase error (0+-0.5) and carrier frequency error (PPM). The - * last field is the on-time timestamp in NTP format. + * 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. With an UltrSPARC 30, this thing can keep - * the clock within a few tens of microseconds relative to the IRIG-B - * signal. Accuracy with IRIG-E is about ten times worse. + * well the driver is doing. With an UltrSPARC 30 and Solaris 2.7, this + * thing can keep the clock within a few tens of microseconds relative + * to the IRIG-B signal. Accuracy with IRIG-E is 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. + * Your experience may vary. * * Unlike other drivers, which can have multiple instantiations, this * one supports only one. It does not seem likely that more than one @@ -127,16 +131,15 @@ * * Fudge factors * - * Fudge flag2 selects the audio input port, where 0 is the mike port + * Fudge flag4 causes the dubugging output described above to be + * recorded in the clockstats file. When the audio driver is compiled, + * 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 speaker volume - * must be set before the driver is started. Fudge flag4 causes the - * debugging output described above to be recorded in the clockstats - * file. Any of these flags can be changed during operation with the - * ntpdc program. + * monitoring of the input signal. For this purpose, the monitor gain is + * set to a default value. Fudgetime2 is used as a frequency vernier for + * broken codec sample frequency. */ - /* * Interface definitions */ @@ -144,7 +147,7 @@ #define PRECISION (-17) /* precision assumed (about 10 us) */ #define REFID "IRIG" /* reference ID */ #define DESCRIPTION "Generic IRIG Audio Driver" /* WRU */ - +#define AUDIO_BUFSIZ 320 /* audio buffer size (40 ms) */ #define SECOND 8000 /* nominal sample rate (Hz) */ #define BAUD 80 /* samples per baud interval */ #define OFFSET 128 /* companded sample offset */ @@ -155,16 +158,20 @@ #define MINTC 2 /* min PLL time constant */ #define MAXTC 20 /* max PLL time constant max */ #define MAXSIG 6000. /* maximum signal level */ +#define MAXCLP 100 /* max clips above reference per s */ #define DRPOUT 100. /* dropout signal level */ #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 fudge factors + * Experimentally determined filter delays */ -#define IRIG_B .0019 /* IRIG-B phase delay */ -#define IRIG_E .0019 /* IRIG-E phase delay */ +#define IRIG_B .0019 /* IRIG-B filter delay */ +#define IRIG_E .0019 /* IRIG-E filter delay */ /* * Data bit definitions @@ -183,6 +190,7 @@ #define IRIG_ERR_DECODE 0x10 /* frame decoding error */ #define IRIG_ERR_CHECK 0x20 /* second numbering discrepancy */ #define IRIG_ERR_ERROR 0x40 /* codec error (overrun) */ +#define IRIG_ERR_SIGERR 0x80 /* IRIG status error (Spectracom) */ /* * IRIG unit control structure @@ -191,23 +199,24 @@ struct irigunit { u_char timecode[21]; /* timecode string */ l_fp timestamp; /* audio sample timestamp */ l_fp tick; /* audio sample increment */ - double comp[SIZE]; /* decompanding table */ double integ[BAUD]; /* baud integrator */ double phase, freq; /* logical clock phase and frequency */ double zxing; /* phase detector integrator */ - double yxing; /* phase detector display */ + double yxing; /* cycle phase */ + double exing; /* envelope phase */ double modndx; /* modulation index */ double irig_b; /* IRIG-B signal amplitude */ double irig_e; /* IRIG-E signal amplitude */ int errflg; /* error flags */ - int bufcnt; /* samples in buffer */ - int bufptr; /* buffer index pointer */ - int pollcnt; /* poll counter */ + /* + * Audio codec variables + */ + double comp[SIZE]; /* decompanding table */ int port; /* codec port */ int gain; /* codec gain */ + int mongain; /* codec monitor gain */ int clipcnt; /* sample clipped count */ int seccnt; /* second interval counter */ - int decim; /* sample decimation factor */ /* * RF variables @@ -222,8 +231,8 @@ struct irigunit { double lastenv[CYCLE]; /* last cycle amplitudes */ double lastint[CYCLE]; /* last integrated cycle amplitudes */ double lastsig; /* last carrier sample */ - double xxing; /* phase detector interpolated output */ double fdelay; /* filter delay */ + int decim; /* sample decimation factor */ int envphase; /* envelope phase */ int envptr; /* envelope phase pointer */ int carphase; /* carrier phase */ @@ -236,8 +245,6 @@ struct irigunit { /* * Decoder variables */ - l_fp montime; /* reference timestamp for eyeball */ - int timecnt; /* timecode counter */ int pulse; /* cycle counter */ int cycles; /* carrier cycles */ int dcycles; /* data cycles */ @@ -247,6 +254,13 @@ struct irigunit { int fieldcnt; /* subfield count in field */ 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; }; /* @@ -282,10 +296,10 @@ struct refclock refclock_irig = { * 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 */ + '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 */ }; @@ -294,7 +308,7 @@ static char hexchar[] = { /* really quick decoding table */ */ static int irig_start( - int unit, /* instance number (not used) */ + int unit, /* instance number (used for PCM) */ struct peer *peer /* peer structure pointer */ ) { @@ -311,7 +325,7 @@ irig_start( /* * Open audio device */ - fd = audio_init(DEVICE_AUDIO); + fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); if (fd < 0) return (0); #ifdef DEBUG @@ -350,7 +364,6 @@ irig_start( up->decim = 1; up->fdelay = IRIG_B; up->gain = 127; - up->pollcnt = 2; /* * The companded samples are encoded sign-magnitude. The table @@ -364,7 +377,7 @@ irig_start( up->comp[i] = up->comp[i - 1] + step; up->comp[OFFSET + i] = -up->comp[i]; if (i % 16 == 0) - step *= 2.; + step *= 2.; } DTOLFP(1. / SECOND, &up->tick); return (1); @@ -410,6 +423,7 @@ irig_receive( */ double sample; /* codec sample */ u_char *dpt; /* buffer pointer */ + int bufcnt; /* buffer counter */ l_fp ltemp; /* l_fp temp */ peer = (struct peer *)rbufp->recv_srcclock; @@ -420,20 +434,17 @@ irig_receive( * Main loop - read until there ain't no more. Note codec * samples are bit-inverted. */ + DTOLFP((double)rbufp->recv_length / SECOND, <emp); + L_SUB(&rbufp->recv_time, <emp); up->timestamp = rbufp->recv_time; - up->bufcnt = rbufp->recv_length; - DTOLFP((double)up->bufcnt / SECOND, <emp); - L_SUB(&up->timestamp, <emp); dpt = rbufp->recv_buffer; - for (up->bufptr = 0; up->bufptr < up->bufcnt; up->bufptr++) { + for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { sample = up->comp[~*dpt++ & 0xff]; /* * Clip noise spikes greater than MAXSIG. If no clips, * increase the gain a tad; if the clips are too high, - * decrease a tad. Choose either IRIG-B or IRIG-E - * according to the energy at the respective filter - * output. + * decrease a tad. */ if (sample > MAXSIG) { sample = MAXSIG; @@ -444,11 +455,15 @@ irig_receive( } /* - * Variable frequency oscillator. A phase change of one - * unit produces a change of 360 degrees; a frequency - * change of one unit produces a change of 1 Hz. + * 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 + * results in either duplicating or deleting one sample + * per second, which results in a frequency change of + * 125 PPM. */ up->phase += up->freq / SECOND; + up->phase += pp->fudgetime2 / 1e6; if (up->phase >= .5) { up->phase -= 1.; } else if (up->phase < -.5) { @@ -461,8 +476,7 @@ irig_receive( L_ADD(&up->timestamp, &up->tick); /* - * Once each second, determine the IRIG format, codec - * port and gain. + * Once each second, determine the IRIG format and gain. */ up->seccnt = (up->seccnt + 1) % SECOND; if (up->seccnt == 0) { @@ -473,22 +487,22 @@ irig_receive( up->decim = 10; up->fdelay = IRIG_E; } - if (pp->sloppyclockflag & CLK_FLAG2) - up->port = 2; - else - up->port = 1; irig_gain(peer); up->irig_b = up->irig_e = 0; } } /* - * Squawk to the monitor speaker if enabled. + * Set the input port and monitor gain for the next buffer. */ + if (pp->sloppyclockflag & CLK_FLAG2) + up->port = 2; + else + up->port = 1; if (pp->sloppyclockflag & CLK_FLAG3) - if (write(pp->io.fd, (u_char *)&rbufp->recv_space, - (u_int)up->bufcnt) < 0) - perror("irig:"); + up->mongain = MONGAIN; + else + up->mongain = 0; } /* @@ -521,7 +535,7 @@ irig_rf( /* * IRIG-B filter. 4th-order elliptic, 800-Hz highpass, 0.3 dB - * passband ripple, -50 dB stopband ripple, phase delay -.0022 + * passband ripple, -50 dB stopband ripple, phase delay .0022 * s) */ irig_b = (up->hpf[4] = up->hpf[3]) * 2.322484e-01; @@ -558,9 +572,9 @@ irig_rf( up->badcnt = (up->badcnt + 1) % up->decim; if (up->badcnt == 0) { if (up->decim == 1) - irig_base(peer, irig_b); + irig_base(peer, irig_b); else - irig_base(peer, irig_e); + irig_base(peer, irig_e); } } @@ -583,10 +597,10 @@ irig_base( /* * Local variables */ + double xxing; /* phase detector interpolated output */ double lope; /* integrator output */ double env; /* envelope detector output */ double dtemp; /* double temp */ - int i; /* index temp */ pp = peer->procptr; up = (struct irigunit *)pp->unitptr; @@ -612,8 +626,8 @@ irig_base( * change of 360 degrees produces an output change of one unit. */ if (up->lastsig > 0 && lope <= 0) { - up->xxing = lope / (up->lastsig - lope); - up->zxing += (up->carphase - 4 + up->xxing) / 8.; + xxing = lope / (up->lastsig - lope); + up->zxing += (up->carphase - 4 + xxing) / CYCLE; } up->lastsig = lope; @@ -629,16 +643,17 @@ irig_base( up->maxsignal = up->intmax; up->noise = up->intmin; if (up->maxsignal < DRPOUT) - up->errflg |= IRIG_ERR_AMP; - if (up->intmax > 0) - up->modndx = (up->intmax - up->intmin) / up->intmax; + up->errflg |= IRIG_ERR_AMP; + if (up->maxsignal > 0) + up->modndx = (up->intmax - up->intmin) / + up->intmax; else - up->modndx = 0; + up->modndx = 0; if (up->modndx < MODMIN) - up->errflg |= IRIG_ERR_MOD; + 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)) { + IRIG_ERR_MOD | IRIG_ERR_SYNCH)) { up->tc = MINTC; up->tcount = 0; } @@ -674,13 +689,13 @@ irig_base( * the slice level and left-shifted in the decoding register. */ if (up->carphase != 7) - return; + return; env = (up->lastenv[2] - up->lastenv[6]) / 2.; lope = (up->lastint[2] - up->lastint[6]) / 2.; if (lope > up->intmax) - up->intmax = lope; + up->intmax = lope; if (lope < up->intmin) - up->intmin = lope; + up->intmin = lope; /* * Pulse code demodulator and reference timestamp. The decoder @@ -690,15 +705,15 @@ irig_base( */ up->pulse = (up->pulse + 1) % 10; if (up->pulse == 1) - up->envmax = env; + up->envmax = env; else if (up->pulse == 9) - up->envmin = env; + up->envmin = env; up->dcycles <<= 1; if (env >= (up->envmax + up->envmin) / 2.) - up->dcycles |= 1; + up->dcycles |= 1; up->cycles <<= 1; if (lope >= (up->maxsignal + up->noise) / 2.) - up->cycles |= 1; + up->cycles |= 1; if ((up->cycles & 0x303c0f03) == 0x300c0300) { l_fp ltemp; int bitz; @@ -711,22 +726,19 @@ irig_base( * persist for lots of samples. */ if (up->pulse != 9) - up->errflg |= IRIG_ERR_SYNCH; + up->errflg |= IRIG_ERR_SYNCH; up->pulse = 9; - dtemp = BAUD - up->zxing; - i = up->envxing - up->envphase; - if (i < 0) - i -= i; - if (i <= 1) { + 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->tc = MAXTC; up->tcount = 0; up->envxing = up->envphase; } else { - dtemp -= up->envxing - up->envphase; + up->exing -= up->envxing - up->envphase; } } else { up->tcount = 0; @@ -740,8 +752,9 @@ irig_base( * this plus the delay since the last carrier positive * zero crossing. */ - DTOLFP(up->decim * (dtemp / SECOND + 1.) + up->fdelay, - <emp); + dtemp = up->decim * ((up->exing + BAUD) / SECOND + 1.) + + up->fdelay; + DTOLFP(dtemp, <emp); pp->lastrec = up->timestamp; L_SUB(&pp->lastrec, <emp); @@ -756,23 +769,23 @@ irig_base( bitz = up->dcycles & 0xfc; switch(bitz) { - case 0x00: - case 0x80: + case 0x00: + case 0x80: irig_decode(peer, BIT0); break; - case 0xc0: - case 0xe0: - case 0xf0: + case 0xc0: + case 0xe0: + case 0xf0: irig_decode(peer, BIT1); break; - case 0xf8: - case 0xfc: + case 0xf8: + case 0xfc: irig_decode(peer, BITP); break; - default: + default: irig_decode(peer, 0); up->errflg |= IRIG_ERR_DECODE; } @@ -797,11 +810,14 @@ irig_decode( { struct refclockproc *pp; struct irigunit *up; +#ifdef IRIG_SUCKS + int i; +#endif /* IRIG_SUCKS */ /* * Local variables */ - char syncchar; /* sync character (Spectracom only) */ + char syncchar; /* sync character (Spectracom) */ char sbs[6]; /* binary seconds since 0h */ char spare[2]; /* mulligan digits */ @@ -824,15 +840,63 @@ irig_decode( up->bitcnt = 1; up->fieldcnt = 0; up->lastbit = 0; - up->montime = pp->lastrec; if (up->errflg == 0) { - up->timecnt++; +#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(<emp, &pp->lastref); + if (ltemp.l_f < 0) + ltemp.l_i = -1; + else + ltemp.l_i = 0; + pp->lastref = pp->lastrec; + if (!L_ISNEG(<emp)) + L_CLR(&up->wigwag); + else + L_ADD(&up->wigwag, <emp); + 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); - } - if (up->timecnt >= MAXSTAGE) { - refclock_receive(peer); - up->timecnt = 0; - up->pollcnt = 2; +#else /* IRIG_SUCKS */ + pp->lastref = pp->lastrec; + up->wuggle = pp->lastrec; + refclock_process(pp); +#endif /* IRIG_SUCKS */ } up->errflg = 0; } @@ -848,45 +912,58 @@ irig_decode( if (up->xptr < 2) up->xptr = 2 * FIELD; up->timecode[--up->xptr] = hexchar[(up->bits >> 5) & - 0xf]; + 0xf]; up->timecode[--up->xptr] = hexchar[up->bits & 0xf]; up->fieldcnt = (up->fieldcnt + 1) % FIELD; if (up->fieldcnt == 0) { /* - * End of field. Decode the timecode, adjust the - * gain and set the input port. Set the port - * here on the assumption somebody might even - * change it on-wing. + * End of field. 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, + * it is lit when the source is okay and dim + * when bad. We watch this only if the year is + * nonzero. Not all are configured for signature + * control. If so, all BCD digits are set to + * zero if the source is bad. In this case the + * refclock_process() will reject the timecode + * as invalid. */ up->xptr = 2 * FIELD; if (sscanf((char *)up->timecode, - "%6s%2d%c%2s%3d%2d%2d%2d", - sbs, &pp->year, &syncchar, spare, &pp->day, - &pp->hour, &pp->minute, &pp->second) != 8) - pp->leap = LEAP_NOTINSYNC; + "%6s%2d%c%2s%3d%2d%2d%2d", sbs, &pp->year, + &syncchar, spare, &pp->day, &pp->hour, + &pp->minute, &pp->second) != 8) + pp->leap = LEAP_NOTINSYNC; else - pp->leap = LEAP_NOWARNING; + pp->leap = LEAP_NOWARNING; up->second = (up->second + up->decim) % 60; + if (pp->year > 0) { + pp->year += 2000; + if (syncchar == '0') + up->errflg |= IRIG_ERR_CHECK; + } if (pp->second != up->second) - up->errflg |= IRIG_ERR_CHECK; + 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 %2d %6.3f %6.1f %s", - up->errflg, syncchar, pp->year, pp->day, - pp->hour, pp->minute, pp->second, - up->maxsignal, up->gain, up->modndx, - up->envxing, up->tc, up->yxing, up->freq * - 1e6 / SECOND, ulfptoa(&up->montime, 6)); + "%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, + 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)); pp->lencode = strlen(pp->a_lastcode); - if (up->timecnt == 0 || pp->sloppyclockflag & - CLK_FLAG4) - record_clock_stats(&peer->srcadr, - pp->a_lastcode); + if (pp->sloppyclockflag & CLK_FLAG4) { + record_clock_stats(&peer->srcadr, + pp->a_lastcode); #ifdef DEBUG - if (debug > 2) - printf("irig: %s\n", pp->a_lastcode); + if (debug) + printf("irig: %s\n", + pp->a_lastcode); #endif /* DEBUG */ + } } } up->lastbit = bit; @@ -896,9 +973,10 @@ irig_decode( /* * irig_poll - called by the transmit procedure * - * This routine keeps track of status. If nothing is heard for two - * successive poll intervals, a timeout event is declared and any - * orphaned timecode updates are sent to foster care. + * 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. */ static void irig_poll( @@ -912,15 +990,17 @@ irig_poll( pp = peer->procptr; up = (struct irigunit *)pp->unitptr; - /* - * Keep book for tattletales - */ - if (up->pollcnt == 0) { + if (pp->coderecv == pp->codeproc) { refclock_report(peer, CEVNT_TIMEOUT); - up->timecnt = 0; return; + } else { + refclock_receive(peer); + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug) + printf("irig: %s\n", pp->a_lastcode); +#endif /* DEBUG */ } - up->pollcnt--; pp->polls++; } @@ -953,18 +1033,17 @@ irig_gain( */ if (up->clipcnt == 0) { up->gain += 4; - if (up->gain > 255) - up->gain = 255; - } else if (up->clipcnt > SECOND / 100) { + if (up->gain > MAXGAIN) + up->gain = MAXGAIN; + } else if (up->clipcnt > MAXCLP) { up->gain -= 4; if (up->gain < 0) up->gain = 0; } - audio_gain(up->gain, up->port); + 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 dba6070..2aa9d6a 100644 --- a/contrib/ntp/ntpd/refclock_jjy.c +++ b/contrib/ntp/ntpd/refclock_jjy.c @@ -188,7 +188,7 @@ jjy_start ( int unit, struct peer *peer ) #ifdef DEBUG if ( debug ) { - printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttlmax ) ; + printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ; printf ( DEVICE, unit ) ; printf ( "\n" ) ; } @@ -202,15 +202,15 @@ jjy_start ( int unit, struct peer *peer ) sprintf ( pDeviceName, DEVICE, unit ) ; /* - * peer->ttlmax is a mode number specified by "127.127.40.X mode N" in the ntp.conf + * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf */ - switch ( peer->ttlmax ) { + switch ( peer->ttl ) { case 0 : case 1 : iDiscipline = LDISC_CLK ; break ; case 2 : iDiscipline = LDISC_RAW ; break ; default : msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", - ntoa(&peer->srcadr), peer->ttlmax ) ; + ntoa(&peer->srcadr), peer->ttl ) ; free ( (void*) pDeviceName ) ; return RC_START_ERROR ; } @@ -233,9 +233,9 @@ jjy_start ( int unit, struct peer *peer ) up->linediscipline = iDiscipline ; /* - * peer->ttlmax is a mode number specified by "127.127.40.X mode N" in the ntp.conf + * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf */ - switch ( peer->ttlmax ) { + switch ( peer->ttl ) { case 0 : /* * The mode 0 is a default clock type at this time. @@ -255,7 +255,7 @@ jjy_start ( int unit, struct peer *peer ) break ; default : msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", - ntoa(&peer->srcadr), peer->ttlmax ) ; + ntoa(&peer->srcadr), peer->ttl ) ; close ( fd ) ; free ( (void*) up ) ; return RC_START_ERROR ; @@ -422,8 +422,7 @@ jjy_receive ( struct recvbuf *rbufp ) pp->hour = up->hour ; pp->minute = up->minute ; pp->second = up->second ; - pp->msec = up->msecond ; - pp->usec = 0; + pp->nsec = up->msecond * 1000000; /* * JST to UTC @@ -460,10 +459,9 @@ jjy_receive ( struct recvbuf *rbufp ) sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d JST", up->year, up->month, up->day, up->hour, up->minute, up->second ) ; - record_clock_stats ( &peer->srcadr, sLogText ) ; - + pp->lastref = pp->lastrec; refclock_receive(peer); - + record_clock_stats ( &peer->srcadr, sLogText ) ; } /**************************************************************************************************/ diff --git a/contrib/ntp/ntpd/refclock_jupiter.c b/contrib/ntp/ntpd/refclock_jupiter.c index 4d1d4c2..eff088b 100644 --- a/contrib/ntp/ntpd/refclock_jupiter.c +++ b/contrib/ntp/ntpd/refclock_jupiter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998 + * Copyright (c) 1997, 1998, 2003 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,21 +35,28 @@ # include #endif -#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(PPS) +#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" -#include "ntp_calendar.h" #include #include #include "jupiter.h" -#include +#ifdef HAVE_PPSAPI +# ifdef HAVE_TIMEPPS_H +# include +# else +# ifdef HAVE_SYS_TIMEPPS_H +# include +# endif +# endif +#endif #ifdef XNTP_BIG_ENDIAN #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) @@ -83,15 +90,6 @@ char *strerror(int); #define SPEED232 B9600 /* baud */ /* - * The number of raw samples which we acquire to derive a single estimate. - * NSAMPLES ideally should not exceed the default poll interval 64. - * NKEEP must be a power of 2 to simplify the averaging process. - */ -#define NSAMPLES 64 -#define NKEEP 8 -#define REFCLOCKMAXDISPERSE .25 /* max sample dispersion */ - -/* * Radio interface parameters */ #define PRECISION (-18) /* precision assumed (about 4 us) */ @@ -114,24 +112,27 @@ char *strerror(int); /* * Jupiter unit control structure. */ -struct jupiterunit { +struct instance { + struct peer *peer; /* peer */ u_int pollcnt; /* poll message counter */ u_int polled; /* Hand in a time sample? */ - u_int lastserial; /* last pps serial number */ - struct ppsclockev ppsev; /* PPS control structure */ +#ifdef HAVE_PPSAPI + pps_params_t pps_params; /* pps parameters */ + pps_info_t pps_info; /* last pps data */ + pps_handle_t pps_handle; /* pps handle */ + u_int assert; /* pps edge to use */ + struct timespec ts; /* last timestamp */ +#endif + l_fp limit; + u_int gpos_gweek; /* Current GPOS GPS week number */ + u_int gpos_sweek; /* Current GPOS GPS seconds into week */ u_int gweek; /* current GPS week number */ u_int32 lastsweek; /* last seconds into GPS week */ - u_int32 timecode; /* current ntp timecode */ + time_t timecode; /* current ntp timecode */ u_int32 stime; /* used to detect firmware bug */ int wantid; /* don't reconfig on channel id msg */ u_int moving; /* mobile platform? */ - u_long sloppyclockflag; /* fudge flags */ - u_int known; /* position known yet? */ - int coderecv; /* total received samples */ - int nkeep; /* number of samples to preserve */ - int rshift; /* number of rshifts for division */ - l_fp filter[NSAMPLES]; /* offset filter */ - l_fp lastref; /* last reference timestamp */ + u_char sloppyclockflag; /* fudge flags */ u_short sbuf[512]; /* local input buffer */ int ssize; /* space used in sbuf */ }; @@ -139,30 +140,28 @@ struct jupiterunit { /* * Function prototypes */ -static void jupiter_canmsg P((struct peer *, u_int)); +static void jupiter_canmsg P((struct instance *, u_int)); static u_short jupiter_cksum P((u_short *, u_int)); -#ifdef QSORT_USES_VOID_P - int jupiter_cmpl_fp P((const void *, const void *)); -#else - int jupiter_cmpl_fp P((const l_fp *, const l_fp *)); -#endif /* not QSORT_USES_VOID_P */ -static void jupiter_config P((struct peer *)); -static void jupiter_debug P((struct peer *, char *, ...)) - __attribute__ ((format (printf, 2, 3))); -static char * jupiter_offset P((struct peer *)); -static char * jupiter_parse_t P((struct peer *, u_short *)); -static void jupiter_platform P((struct peer *, 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 int jupiter_pps P((struct peer *)); -static char * jupiter_process P((struct peer *)); -static int jupiter_recv P((struct peer *)); -static void jupiter_receive P((register struct recvbuf *rbufp)); -static void jupiter_reqmsg P((struct peer *, u_int, u_int)); -static void jupiter_reqonemsg P((struct peer *, u_int)); -static char * jupiter_send P((struct peer *, struct jheader *)); +static void jupiter_control P((int, struct refclockstat *, struct + refclockstat *, struct peer *)); +#ifdef HAVE_PPSAPI +static int jupiter_ppsapi P((struct instance *, int, int)); +static int jupiter_pps P((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_ttyinit P((struct peer *, int)); /* * Transfer vector @@ -171,7 +170,7 @@ struct refclock refclock_jupiter = { jupiter_start, /* start up driver */ jupiter_shutdown, /* shut down driver */ jupiter_poll, /* transmit poll message */ - noentry, /* (clock control) */ + jupiter_control, /* (clock control) */ noentry, /* (clock init) */ noentry, /* (clock buginfo) */ NOFLAGS /* not used */ @@ -182,39 +181,34 @@ struct refclock refclock_jupiter = { */ static int jupiter_start( - register int unit, - register struct peer *peer + int unit, + struct peer *peer ) { struct refclockproc *pp; - register struct jupiterunit *up; - register int fd; + struct instance *instance; + int fd = -1; char gpsdev[20]; /* * Open serial port */ (void)sprintf(gpsdev, DEVICE, unit); - fd = open(gpsdev, O_RDWR -#ifdef O_NONBLOCK - | O_NONBLOCK -#endif - , 0); - if (fd < 0) { - jupiter_debug(peer, "jupiter_start: open %s: %s\n", + fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); + if (fd == 0) { + jupiter_debug(peer, "jupiter_start", "open %s: %s", gpsdev, strerror(errno)); return (0); } - if (!jupiter_ttyinit(peer, fd)) - return (0); /* Allocate unit structure */ - if ((up = (struct jupiterunit *) - emalloc(sizeof(struct jupiterunit))) == NULL) { + if ((instance = (struct instance *) + emalloc(sizeof(struct instance))) == NULL) { (void) close(fd); return (0); } - memset((char *)up, 0, sizeof(struct jupiterunit)); + memset((char *)instance, 0, sizeof(struct instance)); + instance->peer = peer; pp = peer->procptr; pp->io.clock_recv = jupiter_receive; pp->io.srcclock = (caddr_t)peer; @@ -222,10 +216,10 @@ jupiter_start( pp->io.fd = fd; if (!io_addclock(&pp->io)) { (void) close(fd); - free(up); + free(instance); return (0); } - pp->unitptr = (caddr_t)up; + pp->unitptr = (caddr_t)instance; /* * Initialize miscellaneous variables @@ -234,145 +228,228 @@ jupiter_start( pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); +#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, &instance->pps_handle) < 0) { + instance->pps_handle = 0; + msyslog(LOG_ERR, + "refclock_jupiter: time_pps_create failed: %m"); + } + else if (!jupiter_ppsapi(instance, 0, 0)) + goto clean_up; +#endif /* HAVE_PPSAPI */ /* Ensure the receiver is properly configured */ - jupiter_config(peer); + if (!jupiter_config(instance)) + goto clean_up; - /* Turn on pulse gathering by requesting the first sample */ - if (ioctl(fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { - jupiter_debug(peer, "jupiter_ttyinit: CIOGETEV: %s\n", - strerror(errno)); - (void) close(fd); - free(up); - return (0); - } - up->lastserial = up->ppsev.serial; - memset(&up->ppsev, 0, sizeof(up->ppsev)); return (1); + +clean_up: + jupiter_shutdown(unit, peer); + pp->unitptr = 0; + return (0); } /* * jupiter_shutdown - shut down the clock */ static void -jupiter_shutdown(register int unit, register struct peer *peer) +jupiter_shutdown(int unit, struct peer *peer) { - register struct jupiterunit *up; + struct instance *instance; struct refclockproc *pp; pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + instance = (struct instance *)pp->unitptr; + if(!instance) + return; + +#ifdef HAVE_PPSAPI + if (instance->pps_handle) { + time_pps_destroy(instance->pps_handle); + instance->pps_handle = 0; + } +#endif /* HAVE_PPSAPI */ + io_closeclock(&pp->io); - free(up); + free(instance); } /* * jupiter_config - Configure the receiver */ -static void -jupiter_config(register struct peer *peer) +static int +jupiter_config(struct instance *instance) { - register int i; - register struct jupiterunit *up; - register struct refclockproc *pp; - - pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + jupiter_debug(instance->peer, "jupiter_config", "init receiver"); /* * Initialize the unit variables - * - * STRANGE BEHAVIOUR WARNING: The fudge flags are not available - * at the time jupiter_start is called. These are set later, - * and so the code must be prepared to handle changing flags. */ - up->sloppyclockflag = pp->sloppyclockflag; - if (pp->sloppyclockflag & CLK_FLAG2) { - up->moving = 1; /* Receiver on mobile platform */ - msyslog(LOG_DEBUG, "jupiter_config: mobile platform"); - } else { - up->moving = 0; /* Static Installation */ - } - - /* XXX fludge flags don't make the trip from the config to here... */ -#ifdef notdef - /* Configure for trailing edge triggers */ -#ifdef CIOSETTET - i = ((pp->sloppyclockflag & CLK_FLAG3) != 0); - jupiter_debug(peer, "jupiter_configure: (sloppyclockflag 0x%lx)\n", - pp->sloppyclockflag); - if (ioctl(pp->io.fd, CIOSETTET, (char *)&i) < 0) - msyslog(LOG_DEBUG, "jupiter_configure: CIOSETTET %d: %m", i); -#else - if (pp->sloppyclockflag & CLK_FLAG3) - msyslog(LOG_DEBUG, "jupiter_configure: \ -No kernel support for trailing edge trigger"); -#endif -#endif - - up->pollcnt = 2; - up->polled = 0; - up->known = 0; - up->gweek = 0; - up->lastsweek = 2 * WEEKSECS; - up->timecode = 0; - up->stime = 0; - up->ssize = 0; - up->coderecv = 0; - up->nkeep = NKEEP; - if (up->nkeep > NSAMPLES) - up->nkeep = NSAMPLES; - if (up->nkeep >= 1) - up->rshift = 0; - if (up->nkeep >= 2) - up->rshift = 1; - if (up->nkeep >= 4) - up->rshift = 2; - if (up->nkeep >= 8) - up->rshift = 3; - if (up->nkeep >= 16) - up->rshift = 4; - if (up->nkeep >= 32) - up->rshift = 5; - if (up->nkeep >= 64) - up->rshift = 6; - up->nkeep = 1; - i = up->rshift; - while (i > 0) { - up->nkeep *= 2; - i--; - } + instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; + instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); + if (instance->moving) + jupiter_debug(instance->peer, "jupiter_config", + "mobile platform"); + + instance->pollcnt = 2; + instance->polled = 0; + instance->gpos_gweek = 0; + instance->gpos_sweek = 0; + instance->gweek = 0; + instance->lastsweek = 2 * WEEKSECS; + instance->timecode = 0; + instance->stime = 0; + instance->ssize = 0; /* Stop outputting all messages */ - jupiter_canmsg(peer, JUPITER_ALL); + jupiter_canmsg(instance, JUPITER_ALL); /* Request the receiver id so we can syslog the firmware version */ - jupiter_reqonemsg(peer, JUPITER_O_ID); + jupiter_reqonemsg(instance, JUPITER_O_ID); /* Flag that this the id was requested (so we don't get called again) */ - up->wantid = 1; + instance->wantid = 1; /* Request perodic time mark pulse messages */ - jupiter_reqmsg(peer, JUPITER_O_PULSE, 1); + jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); + + /* Request perodic geodetic position status */ + jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); /* Set application platform type */ - if (up->moving) - jupiter_platform(peer, JUPITER_I_PLAT_MED); + if (instance->moving) + jupiter_platform(instance, JUPITER_I_PLAT_MED); + else + jupiter_platform(instance, JUPITER_I_PLAT_LOW); + + return (1); +} + +#ifdef HAVE_PPSAPI +/* + * Initialize PPSAPI + */ +int +jupiter_ppsapi( + struct instance *instance, /* unit structure pointer */ + int enb_clear, /* clear enable */ + int enb_hardpps /* hardpps enable */ + ) +{ + int capability; + + if (time_pps_getcap(instance->pps_handle, &capability) < 0) { + msyslog(LOG_ERR, + "refclock_jupiter: time_pps_getcap failed: %m"); + return (0); + } + memset(&instance->pps_params, 0, sizeof(pps_params_t)); + if (enb_clear) + instance->pps_params.mode = capability & PPS_CAPTURECLEAR; else - jupiter_platform(peer, JUPITER_I_PLAT_LOW); + instance->pps_params.mode = capability & PPS_CAPTUREASSERT; + if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { + msyslog(LOG_ERR, + "refclock_jupiter: invalid capture edge %d", + !enb_clear); + return (0); + } + instance->pps_params.mode |= PPS_TSFMT_TSPEC; + if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { + msyslog(LOG_ERR, + "refclock_jupiter: time_pps_setparams failed: %m"); + return (0); + } + if (enb_hardpps) { + if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, + instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR), + PPS_TSFMT_TSPEC) < 0) { + msyslog(LOG_ERR, + "refclock_jupiter: time_pps_kcbind failed: %m"); + return (0); + } + pps_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", + "pps capability 0x%x version %d mode 0x%x kern %d", + capability, instance->pps_params.api_version, + instance->pps_params.mode, enb_hardpps); + } +#endif + + return (1); +} + +/* + * Get PPSAPI timestamps. + * + * Return 0 on failure and 1 on success. + */ +static int +jupiter_pps(struct instance *instance) +{ + 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 (instance->pps_handle == 0) + return 1; + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); + if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, + &timeout) < 0) + return 1; + if (instance->pps_params.mode & PPS_CAPTUREASSERT) { + if (pps_info.assert_sequence == + instance->pps_info.assert_sequence) + return 1; + ts = instance->pps_info.assert_timestamp; + } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { + if (pps_info.clear_sequence == + instance->pps_info.clear_sequence) + return 1; + ts = instance->pps_info.clear_timestamp; + } else { + return 1; + } + if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) + return 1; + instance->ts = ts; + + tstmp.l_ui = ts.tv_sec + JAN_1970; + dtemp = ts.tv_nsec * FRAC / 1e9; + tstmp.l_uf = (u_int32)dtemp; + instance->peer->procptr->lastrec = tstmp; + return 0; } +#endif /* HAVE_PPSAPI */ /* * jupiter_poll - jupiter watchdog routine */ static void -jupiter_poll(register int unit, register struct peer *peer) +jupiter_poll(int unit, struct peer *peer) { - register struct jupiterunit *up; - register struct refclockproc *pp; + struct instance *instance; + struct refclockproc *pp; pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + instance = (struct instance *)pp->unitptr; /* * You don't need to poll this clock. It puts out timecodes @@ -383,79 +460,106 @@ jupiter_poll(register int unit, register struct peer *peer) /* * If we haven't had a response in a while, reset the receiver. */ - if (up->pollcnt > 0) { - up->pollcnt--; + if (instance->pollcnt > 0) { + instance->pollcnt--; } else { refclock_report(peer, CEVNT_TIMEOUT); /* Request the receiver id to trigger a reconfig */ - jupiter_reqonemsg(peer, JUPITER_O_ID); - up->wantid = 0; + jupiter_reqonemsg(instance, JUPITER_O_ID); + instance->wantid = 0; } /* * polled every 64 seconds. Ask jupiter_receive to hand in * a timestamp. */ - up->polled = 1; + instance->polled = 1; pp->polls++; } /* - * jupiter_receive - receive gps data - * Gag me! + * jupiter_control - fudge control */ static void -jupiter_receive(register struct recvbuf *rbufp) +jupiter_control( + int unit, /* unit (not used) */ + struct refclockstat *in, /* input parameters (not used) */ + struct refclockstat *out, /* output parameters (not used) */ + struct peer *peer /* peer structure pointer */ + ) { - register int bpcnt, cc, size, ppsret; - register u_int32 last_timecode, laststime; - register char *cp; - register u_char *bp; - register u_short *sp; - register u_long sloppyclockflag; - register struct jupiterunit *up; - register struct jid *ip; - register struct jheader *hp; - register struct refclockproc *pp; - register struct peer *peer; + struct refclockproc *pp; + struct instance *instance; + u_char sloppyclockflag; - /* Initialize pointers and read the timecode and timestamp */ - peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + instance = (struct instance *)pp->unitptr; - /* - * If operating mode has been changed, then reinitialize the receiver - * before doing anything else. - */ -/* XXX Sloppy clock flags are broken!! */ - sloppyclockflag = up->sloppyclockflag; - up->sloppyclockflag = pp->sloppyclockflag; - if ((pp->sloppyclockflag & CLK_FLAG2) != + DTOLFP(pp->fudgetime2, &instance->limit); + /* Force positive value. */ + if (L_ISNEG(&instance->limit)) + L_NEG(&instance->limit); + +#ifdef HAVE_PPSAPI + instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); + jupiter_ppsapi(instance, !instance->assert, 0); +#endif /* HAVE_PPSAPI */ + + sloppyclockflag = instance->sloppyclockflag; + instance->sloppyclockflag = pp->sloppyclockflag; + if ((instance->sloppyclockflag & CLK_FLAG2) != (sloppyclockflag & CLK_FLAG2)) { jupiter_debug(peer, - "jupiter_receive: mode switch: reset receiver\n"); - jupiter_config(peer); + "jupiter_control", + "mode switch: reset receiver"); + jupiter_config(instance); return; } +} + +/* + * jupiter_receive - receive gps data + * Gag me! + */ +static void +jupiter_receive(struct recvbuf *rbufp) +{ + int bpcnt, cc, size, ppsret; + time_t last_timecode; + u_int32 laststime; + char *cp; + u_char *bp; + u_short *sp; + struct jid *ip; + struct jheader *hp; + struct peer *peer; + struct refclockproc *pp; + struct instance *instance; + l_fp tstamp; - up->pollcnt = 2; + /* Initialize pointers and read the timecode and timestamp */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + instance = (struct instance *)pp->unitptr; bp = (u_char *)rbufp->recv_buffer; bpcnt = rbufp->recv_length; /* This shouldn't happen */ - if (bpcnt > sizeof(up->sbuf) - up->ssize) - bpcnt = sizeof(up->sbuf) - up->ssize; + if (bpcnt > sizeof(instance->sbuf) - instance->ssize) + bpcnt = sizeof(instance->sbuf) - instance->ssize; /* Append to input buffer */ - memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt); - up->ssize += bpcnt; + memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); + 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) { + instance->pollcnt = 2; - /* While there's at least a header and we parse a intact message */ - while (up->ssize > sizeof(*hp) && (cc = jupiter_recv(peer)) > 0) { - hp = (struct jheader *)up->sbuf; + tstamp = rbufp->recv_time; + hp = (struct jheader *)instance->sbuf; sp = (u_short *)(hp + 1); size = cc - sizeof(*hp); switch (getshort(hp->id)) { @@ -463,7 +567,7 @@ jupiter_receive(register struct recvbuf *rbufp) case JUPITER_O_PULSE: if (size != sizeof(struct jpulse)) { jupiter_debug(peer, - "jupiter_receive: pulse: len %d != %u\n", + "jupiter_receive", "pulse: len %d != %u", size, (int)sizeof(struct jpulse)); refclock_report(peer, CEVNT_BADREPLY); break; @@ -479,23 +583,32 @@ jupiter_receive(register struct recvbuf *rbufp) * pulse message in the last 210 ms, we skip * this one. */ - laststime = up->stime; - up->stime = DS2UI(((struct jpulse *)sp)->stime); - if (laststime != 0 && up->stime - laststime <= 21) { - jupiter_debug(peer, "jupiter_receive: \ -avoided firmware bug (stime %.2f, laststime %.2f)\n", - (double)up->stime * 0.01, (double)laststime * 0.01); + laststime = instance->stime; + instance->stime = DS2UI(((struct jpulse *)sp)->stime); + if (laststime != 0 && instance->stime - laststime <= 21) { + jupiter_debug(peer, "jupiter_receive", + "avoided firmware bug (stime %.2f, laststime %.2f)", + (double)instance->stime * 0.01, (double)laststime * 0.01); break; } /* Retrieve pps timestamp */ - ppsret = jupiter_pps(peer); + ppsret = jupiter_pps(instance); + + /* + * Add one second if msg received early + * (i.e. before limit, a.k.a. fudgetime2) in + * the second. + */ + L_SUB(&tstamp, &pp->lastrec); + if (!L_ISGEQ(&tstamp, &instance->limit)) + ++pp->lastrec.l_ui; /* Parse timecode (even when there's no pps) */ - last_timecode = up->timecode; - if ((cp = jupiter_parse_t(peer, sp)) != NULL) { + last_timecode = instance->timecode; + if ((cp = jupiter_parse_t(instance, sp)) != NULL) { jupiter_debug(peer, - "jupiter_receive: pulse: %s\n", cp); + "jupiter_receive", "pulse: %s", cp); break; } @@ -508,300 +621,118 @@ avoided firmware bug (stime %.2f, laststime %.2f)\n", break; /* Add the new sample to a median filter */ - if ((cp = jupiter_offset(peer)) != NULL) { - jupiter_debug(peer, - "jupiter_receive: offset: %s\n", cp); - refclock_report(peer, CEVNT_BADTIME); - break; - } + tstamp.l_ui = JAN_1970 + last_timecode; + tstamp.l_uf = 0; + + refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1); /* * The clock will blurt a timecode every second * but we only want one when polled. If we * havn't been polled, bail out. */ - if (!up->polled) + if (!instance->polled) break; + instance->polled = 0; /* * It's a live one! Remember this time. */ - pp->lasttime = current_time; + + pp->lastref = pp->lastrec; + refclock_receive(peer); /* - * Determine the reference clock offset and - * dispersion. NKEEP of NSAMPLE offsets are - * passed through a median filter. - * Save the (filtered) offset and dispersion in - * pp->offset and pp->disp. - */ - if ((cp = jupiter_process(peer)) != NULL) { - jupiter_debug(peer, - "jupiter_receive: process: %s\n", cp); - refclock_report(peer, CEVNT_BADTIME); - break; - } - /* - * Return offset and dispersion to control - * module. 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 we get here - what we got from the clock is + * OK, so say so */ - jupiter_debug(peer, - "jupiter_receive: process time: \ -%4d-%03d %02d:%02d:%02d at %s, %s\n", - pp->year, pp->day, - pp->hour, pp->minute, pp->second, - prettydate(&pp->lastrec), lfptoa(&pp->offset, 6)); - - refclock_receive(peer); + refclock_report(peer, CEVNT_NOMINAL); /* * We have succeeded in answering the poll. * Turn off the flag and return */ - up->polled = 0; + instance->polled = 0; + break; + + case JUPITER_O_GPOS: + if (size != sizeof(struct jgpos)) { + jupiter_debug(peer, + "jupiter_receive", "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); + break; + } break; case JUPITER_O_ID: if (size != sizeof(struct jid)) { jupiter_debug(peer, - "jupiter_receive: id: len %d != %u\n", + "jupiter_receive", "id: len %d != %u", size, (int)sizeof(struct jid)); refclock_report(peer, CEVNT_BADREPLY); break; } /* * If we got this message because the Jupiter - * just powered up, it needs to be reconfigured. + * just powered instance, it needs to be reconfigured. */ ip = (struct jid *)sp; jupiter_debug(peer, - "jupiter_receive: >> %s chan ver %s, %s (%s)\n", + "jupiter_receive", "%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)\n", ip->chans, ip->vers, ip->date, ip->opts); - if (up->wantid) - up->wantid = 0; + if (instance->wantid) + instance->wantid = 0; else { jupiter_debug(peer, - "jupiter_receive: reset receiver\n"); - jupiter_config(peer); - /* Rese since jupiter_config() just zeroed it */ - up->ssize = cc; + "jupiter_receive", "reset receiver"); + jupiter_config(instance); + /* + * Restore since jupiter_config() just + * zeroed it + */ + instance->ssize = cc; } break; default: jupiter_debug(peer, - "jupiter_receive: >> unknown message id %d\n", + "jupiter_receive", "unknown message id %d", getshort(hp->id)); break; } - up->ssize -= cc; - if (up->ssize < 0) { + instance->ssize -= cc; + if (instance->ssize < 0) { fprintf(stderr, "jupiter_recv: negative ssize!\n"); abort(); - } else if (up->ssize > 0) - memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize); + } else if (instance->ssize > 0) + memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize); } - record_clock_stats(&peer->srcadr, ""); } -/* - * jupiter_offset - Calculate the offset, and add to the rolling filter. - */ static char * -jupiter_offset(register struct peer *peer) +jupiter_parse_t(struct instance *instance, u_short *sp) { - register struct jupiterunit *up; - register struct refclockproc *pp; - register int i; - l_fp offset; - - pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + struct tm *tm; + char *cp; + struct jpulse *jp; + u_int32 sweek; + time_t last_timecode; + u_short flags; - /* - * Calculate the offset - */ - if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, - pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) { - return ("jupiter_process: clocktime failed"); - } - if (pp->usec) { - TVUTOTSF(pp->usec, offset.l_uf); - } else { - MSUTOTSF(pp->msec, offset.l_uf); - } - L_ADD(&offset, &pp->fudgetime1); - up->lastref = offset; /* save last reference time */ - L_SUB(&offset, &pp->lastrec); /* form true offset */ - - /* - * A rolling filter. Initialize first time around. - */ - i = ((up->coderecv)) % NSAMPLES; - - up->filter[i] = offset; - if (up->coderecv == 0) - for (i = 1; (u_int) i < NSAMPLES; i++) - up->filter[i] = up->filter[0]; - up->coderecv++; - - return (NULL); -} - -/* - * jupiter_process - process the sample from the clock, - * passing it through a median filter and optionally averaging - * the samples. Returns offset and dispersion in "up" structure. - */ -static char * -jupiter_process(register struct peer *peer) -{ - register struct jupiterunit *up; - register struct refclockproc *pp; - register int i, n; - register int j, k; - l_fp offset, median, lftmp; - u_fp disp; - l_fp off[NSAMPLES]; - - pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; - - /* - * Copy the raw offsets and sort into ascending order - */ - for (i = 0; i < NSAMPLES; i++) - off[i] = up->filter[i]; - qsort((char *)off, (size_t)NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp); - - /* - * Reject the furthest from the median of NSAMPLES samples until - * NKEEP samples remain. - */ - i = 0; - n = NSAMPLES; - while ((n - i) > up->nkeep) { - lftmp = off[n - 1]; - median = off[(n + i) / 2]; - L_SUB(&lftmp, &median); - L_SUB(&median, &off[i]); - if (L_ISHIS(&median, &lftmp)) { - /* reject low end */ - i++; - } else { - /* reject high end */ - n--; - } - } - - /* - * Copy key values to the billboard to measure performance. - */ - pp->lastref = up->lastref; - pp->coderecv = up->coderecv; - pp->filter[0] = off[0]; /* smallest offset */ - pp->filter[1] = off[NSAMPLES-1]; /* largest offset */ - for (j = 2, k = i; k < n; j++, k++) - pp->filter[j] = off[k]; /* offsets actually examined */ - - /* - * Compute the dispersion based on the difference between the - * extremes of the remaining offsets. Add to this the time since - * the last clock update, which represents the dispersion - * increase with time. We know that NTP_MAXSKEW is 16. If the - * sum is greater than the allowed sample dispersion, bail out. - * If the loop is unlocked, return the most recent offset; - * otherwise, return the median offset. - */ - lftmp = off[n - 1]; - L_SUB(&lftmp, &off[i]); - disp = LFPTOFP(&lftmp); - if (disp > REFCLOCKMAXDISPERSE) - return ("Maximum dispersion exceeded"); - - /* - * Now compute the offset estimate. If fudge flag 1 - * is set, average the remainder, otherwise pick the - * median. - */ - if (pp->sloppyclockflag & CLK_FLAG1) { - L_CLR(&lftmp); - while (i < n) { - L_ADD(&lftmp, &off[i]); - i++; - } - i = up->rshift; - while (i > 0) { - L_RSHIFT(&lftmp); - i--; - } - offset = lftmp; - } else { - i = (n + i) / 2; - offset = off[i]; - } - - /* - * The payload: filtered offset and dispersion. - */ - - pp->offset = offset; - pp->disp = disp; - - return (NULL); - -} - -/* Compare two l_fp's, used with qsort() */ -#ifdef QSORT_USES_VOID_P -int -jupiter_cmpl_fp(register const void *p1, register const void *p2) -#else -int -jupiter_cmpl_fp(register const l_fp *fp1, register const l_fp *fp2) -#endif -{ -#ifdef QSORT_USES_VOID_P - register const l_fp *fp1 = (const l_fp *)p1; - register const l_fp *fp2 = (const l_fp *)p2; -#endif - - if (!L_ISGEQ(fp1, fp2)) - return (-1); - if (L_ISEQU(fp1, fp2)) - return (0); - return (1); -} - -static char * -jupiter_parse_t(register struct peer *peer, register u_short *sp) -{ - register struct refclockproc *pp; - register struct jupiterunit *up; - register struct tm *tm; - register char *cp; - register struct jpulse *jp; - register struct calendar *jt; - register u_int32 sweek; - register u_int32 last_timecode; - register u_short flags; - time_t t; - struct calendar cal; - - pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; jp = (struct jpulse *)sp; /* The timecode is presented as seconds into the current GPS week */ - sweek = DS2UI(jp->sweek); + sweek = DS2UI(jp->sweek) % WEEKSECS; /* * If we don't know the current GPS week, calculate it from the @@ -815,12 +746,31 @@ jupiter_parse_t(register struct peer *peer, register u_short *sp) * If we already know the current GPS week, increment it when * we wrap into a new week. */ - if (up->gweek == 0) - up->gweek = (time(NULL) - GPS_EPOCH) / WEEKSECS; - else if (sweek == 0 && up->lastsweek == WEEKSECS - 1) { - ++up->gweek; - jupiter_debug(peer, - "jupiter_parse_t: NEW gps week %u\n", up->gweek); + if (instance->gweek == 0) { + if (!instance->gpos_gweek) { + return ("jupiter_parse_t: Unknown gweek"); + } + + instance->gweek = instance->gpos_gweek; + + /* + * Fix warps. GPOS has GPS time and PULSE has UTC. + * Plus, GPOS need not be completely in synch with + * the PPS signal. + */ + if (instance->gpos_sweek >= sweek) { + if ((instance->gpos_sweek - sweek) > WEEKSECS / 2) + ++instance->gweek; + } + else { + if ((sweek - instance->gpos_sweek) > WEEKSECS / 2) + --instance->gweek; + } + } + else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) { + ++instance->gweek; + jupiter_debug(instance->peer, + "jupiter_parse_t", "NEW gps week %u", instance->gweek); } /* @@ -835,167 +785,145 @@ jupiter_parse_t(register struct peer *peer, register u_short *sp) * * Then we warped. */ - if (up->lastsweek == sweek) - jupiter_debug(peer, - "jupiter_parse_t: gps sweek not incrementing (%d)\n", + if (instance->lastsweek == sweek) + jupiter_debug(instance->peer, + "jupiter_parse_t", "gps sweek not incrementing (%d)", sweek); - else if (up->lastsweek != 2 * WEEKSECS && - up->lastsweek + 1 != sweek && - !(sweek == 0 && up->lastsweek == WEEKSECS - 1)) - jupiter_debug(peer, - "jupiter_parse_t: gps sweek jumped (was %d, now %d)\n", - up->lastsweek, sweek); - up->lastsweek = 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)", + instance->lastsweek, sweek); + instance->lastsweek = sweek; /* This timecode describes next pulse */ - last_timecode = up->timecode; - up->timecode = (u_int32)JAN_1970 + - GPS_EPOCH + (up->gweek * WEEKSECS) + sweek; + last_timecode = instance->timecode; + instance->timecode = + GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek; if (last_timecode == 0) /* XXX debugging */ - jupiter_debug(peer, - "jupiter_parse_t: UTC (gweek/sweek %u/%u)\n", - up->gweek, sweek); + jupiter_debug(instance->peer, + "jupiter_parse_t", "UTC (gweek/sweek %u/%u)", + instance->gweek, sweek); else { /* XXX debugging */ - t = last_timecode - (u_int32)JAN_1970; - tm = gmtime(&t); + tm = gmtime(&last_timecode); cp = asctime(tm); - jupiter_debug(peer, - "jupiter_parse_t: UTC %.24s (gweek/sweek %u/%u)\n", - cp, up->gweek, sweek); + jupiter_debug(instance->peer, + "jupiter_parse_t", "UTC %.24s (gweek/sweek %u/%u)", + cp, instance->gweek, sweek); /* Billboard last_timecode (which is now the current time) */ - jt = &cal; - caljulian(last_timecode, jt); - pp = peer->procptr; - pp->year = jt->year; - pp->day = jt->yearday; - pp->hour = jt->hour; - pp->minute = jt->minute; - pp->second = jt->second; - pp->msec = 0; - pp->usec = 0; + instance->peer->procptr->year = tm->tm_year + 1900; + instance->peer->procptr->day = tm->tm_yday + 1; + instance->peer->procptr->hour = tm->tm_hour; + instance->peer->procptr->minute = tm->tm_min; + instance->peer->procptr->second = tm->tm_sec; } - /* XXX debugging */ - tm = gmtime(&up->ppsev.tv.tv_sec); - cp = asctime(tm); flags = getshort(jp->flags); - jupiter_debug(peer, - "jupiter_parse_t: PPS %.19s.%06lu %.4s (serial %u)%s\n", - cp, up->ppsev.tv.tv_usec, cp + 20, up->ppsev.serial, - (flags & JUPITER_O_PULSE_VALID) == 0 ? - " NOT VALID" : ""); /* Toss if not designated "valid" by the gps */ if ((flags & JUPITER_O_PULSE_VALID) == 0) { - refclock_report(peer, CEVNT_BADTIME); + refclock_report(instance->peer, CEVNT_BADTIME); return ("time mark not valid"); } /* We better be sync'ed to UTC... */ if ((flags & JUPITER_O_PULSE_UTC) == 0) { - refclock_report(peer, CEVNT_BADTIME); + refclock_report(instance->peer, CEVNT_BADTIME); return ("time mark not sync'ed to UTC"); } return (NULL); } -/* - * Process a PPS signal, returning a timestamp. - */ -static int -jupiter_pps(register struct peer *peer) +static char * +jupiter_parse_gpos(struct instance *instance, u_short *sp) { - register struct refclockproc *pp; - register struct jupiterunit *up; - register int firsttime; - struct timeval ntp_tv; + struct jgpos *jg; + time_t t; + struct tm *tm; + char *cp; - pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + jg = (struct jgpos *)sp; - /* - * Grab the timestamp of the PPS signal. - */ - firsttime = (up->ppsev.tv.tv_sec == 0); - if (ioctl(pp->io.fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { - /* XXX Actually, if this fails, we're pretty much screwed */ - jupiter_debug(peer, "jupiter_pps: CIOGETEV: %s\n", - strerror(errno)); - refclock_report(peer, CEVNT_FAULT); - return (1); + if (jg->navval != 0) { + /* + * Solution not valid. Use caution and refuse + * to determine GPS week from this message. + */ + instance->gpos_gweek = 0; + instance->gpos_sweek = 0; + return ("Navigation solution not valid"); } - /* - * Check pps serial number against last one - */ - if (!firsttime && up->lastserial + 1 != up->ppsev.serial) { - if (up->ppsev.serial == up->lastserial) - jupiter_debug(peer, "jupiter_pps: no new pps event\n"); - else - jupiter_debug(peer, - "jupiter_pps: missed %d pps events\n", - up->ppsev.serial - up->lastserial - 1); - up->lastserial = up->ppsev.serial; - refclock_report(peer, CEVNT_FAULT); - return (1); + instance->gpos_gweek = jg->gweek; + instance->gpos_sweek = DS2UI(jg->sweek); + while(instance->gpos_sweek >= WEEKSECS) { + instance->gpos_sweek -= WEEKSECS; + ++instance->gpos_gweek; } - up->lastserial = up->ppsev.serial; + instance->gweek = 0; - /* - * Return the timestamp in pp->lastrec - */ - ntp_tv = up->ppsev.tv; - ntp_tv.tv_sec += (u_int32)JAN_1970; - TVTOTS(&ntp_tv, &pp->lastrec); + t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek; + tm = gmtime(&t); + cp = asctime(tm); - return (0); + jupiter_debug(instance->peer, + "jupiter_parse_g", "GPS %.24s (gweek/sweek %u/%u)", + cp, instance->gpos_gweek, instance->gpos_sweek); + return (NULL); } /* * jupiter_debug - print debug messages */ -#if defined(__STDC__) +#if defined(__STDC__) || defined(SYS_WINNT) static void -jupiter_debug(struct peer *peer, char *fmt, ...) +jupiter_debug(struct peer *peer, char *function, char *fmt, ...) #else static void -jupiter_debug(peer, fmt, va_alist) +jupiter_debug(peer, function, fmt, va_alist) struct peer *peer; + char *function; char *fmt; #endif /* __STDC__ */ { + char buffer[200]; va_list ap; - if (debug) { - -#if defined(__STDC__) - va_start(ap, fmt); +#if defined(__STDC__) || defined(SYS_WINNT) + va_start(ap, fmt); #else - va_start(ap); + va_start(ap); #endif /* __STDC__ */ - /* - * Print debug message to stdout - * In the future, we may want to get get more creative... - */ - vfprintf(stderr, fmt, ap); - - va_end(ap); + /* + * 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); + if (debug) { + fprintf(stdout, "%s: ", function); + fprintf(stdout, buffer); + fprintf(stdout, "\n"); + fflush(stdout); } + + va_end(ap); } /* Checksum and transmit a message to the Jupiter */ static char * -jupiter_send(register struct peer *peer, register struct jheader *hp) +jupiter_send(struct instance *instance, struct jheader *hp) { - register u_int len, size; - register int cc; - register u_short *sp; + u_int len, size; + int cc; + u_short *sp; static char errstr[132]; size = sizeof(*hp); @@ -1008,7 +936,7 @@ jupiter_send(register struct peer *peer, register struct jheader *hp) size += (len + 1) * sizeof(u_short); } - if ((cc = write(peer->procptr->io.fd, (char *)hp, size)) < 0) { + if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { (void)sprintf(errstr, "write: %s", strerror(errno)); return (errstr); } else if (cc != size) { @@ -1025,65 +953,65 @@ static struct { } reqmsg = { { putshort(JUPITER_SYNC), 0, putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), - 0, putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | + 0, (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_CONN | JUPITER_FLAG_LOG), 0 }, { 0, 0, 0, 0 } }; /* An interval of zero means to output on trigger */ static void -jupiter_reqmsg(register struct peer *peer, register u_int id, - register u_int interval) +jupiter_reqmsg(struct instance *instance, u_int id, + u_int interval) { - register struct jheader *hp; - register struct jrequest *rp; - register char *cp; + struct jheader *hp; + struct jrequest *rp; + char *cp; hp = &reqmsg.jheader; hp->id = putshort(id); rp = &reqmsg.jrequest; rp->trigger = putshort(interval == 0); rp->interval = putshort(interval); - if ((cp = jupiter_send(peer, hp)) != NULL) - jupiter_debug(peer, "jupiter_reqmsg: %u: %s\n", id, cp); + if ((cp = jupiter_send(instance, hp)) != NULL) + jupiter_debug(instance->peer, "jupiter_reqmsg", "%u: %s", id, cp); } /* Cancel periodic message output */ static struct jheader canmsg = { putshort(JUPITER_SYNC), 0, 0, 0, - putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC), + (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC), 0 }; static void -jupiter_canmsg(register struct peer *peer, register u_int id) +jupiter_canmsg(struct instance *instance, u_int id) { - register struct jheader *hp; - register char *cp; + struct jheader *hp; + char *cp; hp = &canmsg; hp->id = putshort(id); - if ((cp = jupiter_send(peer, hp)) != NULL) - jupiter_debug(peer, "jupiter_canmsg: %u: %s\n", id, cp); + if ((cp = jupiter_send(instance, hp)) != NULL) + jupiter_debug(instance->peer, "jupiter_canmsg", "%u: %s", id, cp); } /* Request a single message output */ static struct jheader reqonemsg = { putshort(JUPITER_SYNC), 0, 0, 0, - putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY), + (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY), 0 }; static void -jupiter_reqonemsg(register struct peer *peer, register u_int id) +jupiter_reqonemsg(struct instance *instance, u_int id) { - register struct jheader *hp; - register char *cp; + struct jheader *hp; + char *cp; hp = &reqonemsg; hp->id = putshort(id); - if ((cp = jupiter_send(peer, hp)) != NULL) - jupiter_debug(peer, "jupiter_reqonemsg: %u: %s\n", id, cp); + if ((cp = jupiter_send(instance, hp)) != NULL) + jupiter_debug(instance->peer, "jupiter_reqonemsg", "%u: %s", id, cp); } /* Set the platform dynamics */ @@ -1093,29 +1021,29 @@ static struct { } platmsg = { { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, - putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 }, + (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 }, { 0, 0, 0 } }; static void -jupiter_platform(register struct peer *peer, register u_int platform) +jupiter_platform(struct instance *instance, u_int platform) { - register struct jheader *hp; - register struct jplat *pp; - register char *cp; + struct jheader *hp; + struct jplat *pp; + char *cp; hp = &platmsg.jheader; pp = &platmsg.jplat; pp->platform = putshort(platform); - if ((cp = jupiter_send(peer, hp)) != NULL) - jupiter_debug(peer, "jupiter_platform: %u: %s\n", platform, cp); + if ((cp = jupiter_send(instance, hp)) != NULL) + jupiter_debug(instance->peer, "jupiter_platform", "%u: %s", platform, cp); } /* Checksum "len" shorts */ static u_short -jupiter_cksum(register u_short *sp, register u_int len) +jupiter_cksum(u_short *sp, u_int len) { - register u_short sum, x; + u_short sum, x; sum = 0; while (len-- > 0) { @@ -1127,60 +1055,61 @@ jupiter_cksum(register u_short *sp, register u_int len) /* Return the size of the next message (or zero if we don't have it all yet) */ static int -jupiter_recv(register struct peer *peer) +jupiter_recv(struct instance *instance) { - register int n, len, size, cc; - register struct refclockproc *pp; - register struct jupiterunit *up; - register struct jheader *hp; - register u_char *bp; - register u_short *sp; - - pp = peer->procptr; - up = (struct jupiterunit *)pp->unitptr; + int n, len, size, cc; + struct jheader *hp; + u_char *bp; + u_short *sp; /* Must have at least a header's worth */ cc = sizeof(*hp); - size = up->ssize; + size = instance->ssize; if (size < cc) return (0); /* Search for the sync short if missing */ - sp = up->sbuf; + sp = instance->sbuf; hp = (struct jheader *)sp; if (getshort(hp->sync) != JUPITER_SYNC) { /* Wasn't at the front, sync up */ - jupiter_debug(peer, "syncing"); + jupiter_debug(instance->peer, "jupiter_recv", "syncing"); bp = (u_char *)sp; n = size; while (n >= 2) { if (bp[0] != (JUPITER_SYNC & 0xff)) { - jupiter_debug(peer, "{0x%x}", bp[0]); + /* + jupiter_debug(instance->peer, "{0x%x}", bp[0]); + */ ++bp; --n; continue; } if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) break; - jupiter_debug(peer, "{0x%x 0x%x}", bp[0], bp[1]); + /* + jupiter_debug(instance->peer, "{0x%x 0x%x}", bp[0], bp[1]); + */ bp += 2; n -= 2; } - jupiter_debug(peer, "\n"); + /* + jupiter_debug(instance->peer, "\n"); + */ /* Shuffle data to front of input buffer */ if (n > 0) memcpy(sp, bp, n); size = n; - up->ssize = size; + instance->ssize = size; if (size < cc || hp->sync != JUPITER_SYNC) return (0); } if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != getshort(hp->hsum)) { - jupiter_debug(peer, "jupiter_recv: bad header checksum!\n"); + jupiter_debug(instance->peer, "jupiter_recv", "bad header checksum!"); /* This is drastic but checksum errors should be rare */ - up->ssize = 0; + instance->ssize = 0; return (0); } @@ -1195,10 +1124,10 @@ jupiter_recv(register struct peer *peer) /* Check payload checksum */ sp = (u_short *)(hp + 1); if (jupiter_cksum(sp, len) != getshort(sp[len])) { - jupiter_debug(peer, - "jupiter_recv: bad payload checksum!\n"); + jupiter_debug(instance->peer, + "jupiter_recv", "bad payload checksum!"); /* This is drastic but checksum errors should be rare */ - up->ssize = 0; + instance->ssize = 0; return (0); } cc += n; @@ -1206,57 +1135,6 @@ jupiter_recv(register struct peer *peer) return (cc); } -static int -jupiter_ttyinit(register struct peer *peer, register int fd) -{ - struct termios termios; - - memset((char *)&termios, 0, sizeof(termios)); - if (cfsetispeed(&termios, B9600) < 0 || - cfsetospeed(&termios, B9600) < 0) { - jupiter_debug(peer, - "jupiter_ttyinit: cfsetispeed/cfgetospeed: %s\n", - strerror(errno)); - return (0); - } -#ifdef HAVE_CFMAKERAW - cfmakeraw(&termios); -#else - termios.c_iflag &= ~(IMAXBEL | IXOFF | INPCK | BRKINT | PARMRK | - ISTRIP | INLCR | IGNCR | ICRNL | IXON | IGNPAR); - termios.c_iflag |= IGNBRK; - termios.c_oflag &= ~OPOST; - termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG | - IEXTEN | NOFLSH | TOSTOP | PENDIN); - termios.c_cflag &= ~(CSIZE | PARENB); - termios.c_cflag |= CS8 | CREAD; - termios.c_cc[VMIN] = 1; -#endif - termios.c_cflag |= CLOCAL; - if (tcsetattr(fd, TCSANOW, &termios) < 0) { - jupiter_debug(peer, "jupiter_ttyinit: tcsetattr: %s\n", - strerror(errno)); - return (0); - } - -#ifdef TIOCSPPS - if (ioctl(fd, TIOCSPPS, (char *)&fdpps) < 0) { - jupiter_debug(peer, "jupiter_ttyinit: TIOCSPPS: %s\n", - strerror(errno)); - return (0); - } -#endif -#ifdef I_PUSH - if (ioctl(fd, I_PUSH, "ppsclock") < 0) { - jupiter_debug(peer, "jupiter_ttyinit: push ppsclock: %s\n", - strerror(errno)); - return (0); - } -#endif - - return (1); -} - -#else /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ +#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ int refclock_jupiter_bs; -#endif /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ +#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ diff --git a/contrib/ntp/ntpd/refclock_leitch.c b/contrib/ntp/ntpd/refclock_leitch.c index 42b02fc..d7cd9bb 100644 --- a/contrib/ntp/ntpd/refclock_leitch.c +++ b/contrib/ntp/ntpd/refclock_leitch.c @@ -446,6 +446,7 @@ leitch_receive( leitch->state = STATE_IDLE; break; } + leitch->reftime1.l_uf = 0; #ifdef DEBUG if (debug) fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui); diff --git a/contrib/ntp/ntpd/refclock_local.c b/contrib/ntp/ntpd/refclock_local.c index 0a0ecc0..3478f43 100644 --- a/contrib/ntp/ntpd/refclock_local.c +++ b/contrib/ntp/ntpd/refclock_local.c @@ -1,7 +1,8 @@ -/* wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT */ /* * refclock_local - local pseudo-clock driver + * + * wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT */ #ifdef HAVE_CONFIG_H #include @@ -69,31 +70,34 @@ * * 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 - * "LCL" 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. + * 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 "LCL" 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. * * 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. + * 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. */ - /* * Local interface definitions */ #define PRECISION (-7) /* about 10 ms precision */ -#define REFID "LCL\0" /* reference ID */ +#if defined(VMS) && defined(VMS_LOCALUNIT) +#define REFID "LCLv" /* reference ID */ +#else /* VMS VMS_LOCALUNIT */ +#define REFID "LCL\0" /* reference ID */ +#endif /* VMS VMS_LOCALUNIT */ #define DESCRIPTION "Undisciplined local clock" /* WRU */ #define STRATUM 5 /* default stratum */ @@ -160,14 +164,11 @@ local_start( * Initialize miscellaneous variables */ peer->precision = sys_precision; + pp->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM; + pp->stratum = STRATUM; pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); -#if defined(VMS) && defined(VMS_LOCALUNIT) - /* provide a non-standard REFID */ - if(unit == VMS_LOCALUNIT) - memcpy((char *)&pp->refid,"LCLv",4); -#endif /* VMS && VMS_LOCALUNIT */ + memcpy(&pp->refid, "INIT", 4); poll_time = current_time; return (1); } @@ -175,6 +176,15 @@ local_start( /* * local_poll - called by the transmit procedure + * + * LOCKCLOCK: If the kernel supports the nanokernel or microkernel + * system calls, the leap bits are extracted from the kernel. If there + * is a kernel error or the kernel leap bits are set to 11, the NTP leap + * bits are set to 11 and the stratum is set to infinity. Otherwise, the + * NTP leap bits are set to the kernel leap bits and the stratum is set + * as fudged. This behavior does not faithfully follow the + * specification, but is probably more appropriate in a multiple-server + * national laboratory network. */ static void local_poll( @@ -182,20 +192,19 @@ local_poll( struct peer *peer ) { - struct refclockproc *pp; -#if defined(KERNEL_PLL) && defined(STA_CLK) +#if defined(KERNEL_PLL) && defined(LOCKCLOCK) struct timex ntv; - int retval; -#endif /* KERNEL_PLL STA_CLK */ +#endif /* KERNEL_PLL LOCKCLOCK */ + struct refclockproc *pp; #if defined(VMS) && defined(VMS_LOCALUNIT) - if(unit == VMS_LOCALUNIT) { + if (unit == VMS_LOCALUNIT) { extern void vms_local_poll(struct peer *); vms_local_poll(peer); return; } -#endif /* VMS && VMS_LOCALUNIT */ +#endif /* VMS && VMS_LOCALUNIT */ pp = peer->procptr; pp->polls++; @@ -210,48 +219,42 @@ local_poll( pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time - poll_time); poll_time = current_time; - refclock_process_offset(pp, pp->lastrec, pp->lastrec, pp->fudgetime1); - pp->leap = LEAP_NOWARNING; - pp->disp = DISPERSION; - pp->jitter = 0; -#if defined(KERNEL_PLL) && defined(STA_CLK) + refclock_process_offset(pp, pp->lastrec, pp->lastrec, + pp->fudgetime1); /* - * If the kernel pll code is up and running, somebody else - * may come diddle the clock. If so, they better use ntp_adjtime(), - * and set the STA_CLK bit in the status word. In this case, the - * performance information is read from the kernel and becomes the - * variables presented to the clock mitigation process. + * If another process is disciplining the system clock, we set + * the leap bits and quality indicators from the kernel. */ - if (pll_control && kern_enable && (peer->flags & FLAG_PREFER)) { - memset((char *)&ntv, 0, sizeof ntv); - retval = ntp_adjtime(&ntv); - if (ntv.status & STA_CLK) { - ext_enable = 1; - switch(retval) { +#if defined(KERNEL_PLL) && defined(LOCKCLOCK) + memset(&ntv, 0, sizeof ntv); + switch (ntp_adjtime(&ntv)) { + case TIME_OK: + pp->leap = LEAP_NOWARNING; + peer->stratum = pp->stratum; + break; - case TIME_OK: - pp->leap = LEAP_NOWARNING; - break; + case TIME_INS: + pp->leap = LEAP_ADDSECOND; + peer->stratum = pp->stratum; + break; - case TIME_INS: - pp->leap = LEAP_ADDSECOND; - break; + case TIME_DEL: + pp->leap = LEAP_DELSECOND; + peer->stratum = pp->stratum; + break; - case TIME_DEL: - pp->leap = LEAP_DELSECOND; - break; - - case TIME_ERROR: - pp->leap = LEAP_NOTINSYNC; - } - pp->disp = ntv.maxerror / 1e6; - pp->jitter = SQUARE(ntv.esterror / 1e6); - } - } else { - ext_enable = 0; + default: + pp->leap = LEAP_NOTINSYNC; + peer->stratum = STRATUM_UNSPEC; } -#endif /* KERNEL_PLL STA_CLK */ + pp->disp = 0; + pp->jitter = 0; +#else /* KERNEL_PLL LOCKCLOCK */ + pp->leap = LEAP_NOWARNING; + pp->disp = DISPERSION; + pp->jitter = 0; +#endif /* KERNEL_PLL LOCKCLOCK */ pp->lastref = pp->lastrec; refclock_receive(peer); pp->fudgetime1 = 0; diff --git a/contrib/ntp/ntpd/refclock_msfees.c b/contrib/ntp/ntpd/refclock_msfees.c index b1aaa56..ebfb983 100644 --- a/contrib/ntp/ntpd/refclock_msfees.c +++ b/contrib/ntp/ntpd/refclock_msfees.c @@ -99,7 +99,7 @@ * On the next minute it steps forward again :-( * This is typically 16.5uS/S then 3975uS at the 4min re-sync, * or 9.5uS/S then 3990.5uS at a 7min re-sync, - * at which point it may loose the "00" second time stamp. + * at which point it may lose the "00" second time stamp. * I assume that the most accurate time is just AFTER the re-sync. * Hence remember the last cycle interval, * @@ -720,7 +720,7 @@ ees_receive( /* Incomplete. Wait for more. */ if (debug & DB_LOG_AWAITMORE) msyslog(LOG_INFO, - "I: ees clock %d: %x == %x: await more", + "I: ees clock %d: %p == %p: await more", ees->unit, dpt, dpend); return; } diff --git a/contrib/ntp/ntpd/refclock_mx4200.c b/contrib/ntp/ntpd/refclock_mx4200.c index 3c520b0..bc694ad 100644 --- a/contrib/ntp/ntpd/refclock_mx4200.c +++ b/contrib/ntp/ntpd/refclock_mx4200.c @@ -67,6 +67,8 @@ # include #endif +#include "ntp_sprintf.h" + #ifndef HAVE_STRUCT_PPSCLOCKEV struct ppsclockev { # ifdef HAVE_STRUCT_TIMESPEC @@ -892,7 +894,7 @@ mx4200_receive( mx4200_debug(peer, "%4d-%03d %02d:%02d:%02d at %s, %.6f\n", pp->year, pp->day, pp->hour, pp->minute, pp->second, prettydate(&pp->lastrec), pp->offset); - + pp->lastref = pp->lastrec; refclock_receive(peer); /* @@ -947,7 +949,7 @@ mx4200_receive( * 10 int User Time Bias: Operator specified bias, in nanoseconds * 11 int Leap Second Flag: Indicates that a leap second will * occur. This value is usually zero, except during - * the week prior to the leap second occurence, when + * the week prior to the leap second occurrence, when * this value will be set to +1 or -1. A value of * +1 indicates that GPS time will be 1 second * further ahead of UTC time. @@ -1103,8 +1105,6 @@ mx4200_parse_t( pp->hour = hour; pp->minute = minute; pp->second = second; - pp->msec = 0; - pp->usec = 0; /* * Toss if sentence is marked invalid @@ -1636,25 +1636,11 @@ mx4200_send(peer, fmt, va_alist) cp = buf; *cp++ = '$'; -#ifdef notdef - /* BSD is rational */ - n = vsnprintf(cp, sizeof(buf) - 1, fmt, ap); -#else - /* SunOS sucks */ - (void)vsprintf(cp, fmt, ap); - n = strlen(cp); -#endif /* notdef */ + n = VSNPRINTF((cp, sizeof(buf) - 1, fmt, ap)); ck = mx4200_cksum(cp, n); cp += n; ++n; -#ifdef notdef - /* BSD is rational */ - n += snprintf(cp, sizeof(buf) - n - 5, "*%02X\r\n", ck); -#else - /* SunOS sucks */ - sprintf(cp, "*%02X\r\n", ck); - n += strlen(cp); -#endif /* notdef */ + n += SNPRINTF((cp, sizeof(buf) - n - 5, "*%02X\r\n", ck)); m = write(pp->io.fd, buf, (unsigned)n); if (m < 0) diff --git a/contrib/ntp/ntpd/refclock_neoclock4x.c b/contrib/ntp/ntpd/refclock_neoclock4x.c index 3b64017..082b1cf 100644 --- a/contrib/ntp/ntpd/refclock_neoclock4x.c +++ b/contrib/ntp/ntpd/refclock_neoclock4x.c @@ -1,15 +1,15 @@ /* * - * refclock_neoclock4x.c + * Refclock_neoclock4x.c * - NeoClock4X driver for DCF77 or FIA Timecode * - * Date: 2002-04-27 1.0 + * Date: 2003-07-07 v1.13 * * see http://www.linum.com/redir/jump/id=neoclock4x&action=redir * for details about the NeoClock4X device * - * Copyright (C) 2002 by Linum Software GmbH - * + * Copyright (C) 2002-2003 by Linum Software GmbH + * * 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. @@ -58,6 +58,24 @@ # include #endif +/* + * If you want the driver for whatever reason to not use + * the TX line to send anything to your NeoClock4X + * device you must tell the NTP refclock driver which + * firmware you NeoClock4X device uses. + * + * If you want to enable this feature change the "#if 0" + * line to "#if 1" and make sure that the defined firmware + * matches the firmware off your NeoClock4X receiver! + * + */ + +#if 0 +#define NEOCLOCK4X_FIRMWARE NEOCLOCK4X_FIRMWARE_VERSION_A +#endif + +#define NEOCLOCK4X_FIRMWARE_VERSION_A 'A' + #define NEOCLOCK4X_TIMECODELEN 37 #define NEOCLOCK4X_OFFSET_SERIAL 3 @@ -77,14 +95,17 @@ #define NEOCLOCK4X_OFFSET_ANTENNA2 33 #define NEOCLOCK4X_OFFSET_CRC 35 +#define NEOCLOCK4X_DRIVER_VERSION "1.12 (2003-01-10)" + struct neoclock4x_unit { l_fp laststamp; /* last receive timestamp */ short unit; /* NTP refclock unit number */ - u_long polled; /* flag to detect noreplies */ + u_long polled; /* flag to detect noreplies */ char leap_status; /* leap second flag */ int recvnow; - + char firmware[80]; + char firmwaretag; char serial[7]; char radiosignal[4]; char timesource; @@ -112,8 +133,13 @@ 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)); +#if 0 static void neol_mdelay P((int)); +#endif +#if !defined(NEOCLOCK4X_FIRMWARE) static int neol_query_firmware P((int, int, char *, int)); +static int neol_check_firmware P((int, const char*, char *)); +#endif struct refclock refclock_neoclock4x = { neoclock4x_start, /* start up driver */ @@ -134,11 +160,15 @@ neoclock4x_start(int unit, int fd; char dev[20]; int sl232; +#if defined(HAVE_TERMIOS) struct termios termsettings; +#endif +#if !defined(NEOCLOCK4X_FIRMWARE) int tries; +#endif + + (void) snprintf(dev, sizeof(dev)-1, "/dev/neoclock4x-%d", unit); - (void) sprintf(dev, "/dev/neoclock4x-%d", unit); - /* LDISC_STD, LDISC_RAW * Open serial port. Use CLK line discipline, if available. */ @@ -147,13 +177,61 @@ neoclock4x_start(int unit, { return (0); } - + +#if defined(HAVE_TERMIOS) + if(tcgetattr(fd, &termsettings) < 0) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit); + (void) close(fd); + return (0); + } + + /* 2400 Baud 8N2 */ + termsettings.c_cflag &= ~PARENB; + termsettings.c_cflag |= CSTOPB; + termsettings.c_cflag &= ~CSIZE; + termsettings.c_cflag |= CS8; + + if(tcsetattr(fd, TCSANOW, &termsettings) < 0) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit); + (void) close(fd); + return (0); + } +#elif defined(HAVE_SYSV_TTYS) + if(ioctl(fd, TCGETA, &termsettings) < 0) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): (TCGETA) can't query serial port settings: %m", unit); + (void) close(fd); + return (0); + } + + /* 2400 Baud 8N2 */ + termsettings.c_cflag &= ~PARENB; + termsettings.c_cflag |= CSTOPB; + termsettings.c_cflag &= ~CSIZE; + termsettings.c_cflag |= CS8; + + if(ioctl(fd, TCSETA, &termsettings) < 0) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): (TSGETA) can't set serial port 2400 8N2: %m", unit); + (void) close(fd); + return (0); + } +#else + msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set port to 2400 8N2 with this OS!", unit); + (void) close(fd); + return (0); +#endif + #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) /* turn on RTS, and DTR for power supply */ /* NeoClock4x is powered from serial line */ if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1) { msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit); + (void) close(fd); + return (0); } #ifdef TIOCM_RTS sl232 = sl232 | TIOCM_DTR | TIOCM_RTS; /* turn on RTS, and DTR for power supply */ @@ -163,28 +241,16 @@ neoclock4x_start(int unit, if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) { msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit); - } - - if(ioctl(fd, TCGETS, (caddr_t)&termsettings) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't query serial port settings: %m", unit); - } - - /* 2400 Baud mit 8N2 */ - termsettings.c_cflag &= ~PARENB; - termsettings.c_cflag |= CSTOPB; - termsettings.c_cflag &= ~CSIZE; - termsettings.c_cflag |= CS8; - - if(ioctl(fd, TCSETS, &termsettings) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't set serial port to 2400 8N2: %m", unit); + (void) close(fd); + return (0); } #else - msyslog(LOG_EMERG, "NeoClock4X(%d): OS interface is incapable of setting DTR/RTS to power NeoClock4X", + msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set DTR/RTS to power NeoClock4X with this OS!", unit); + (void) close(fd); + return (0); #endif - + up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit)); if(!(up)) { @@ -201,31 +267,26 @@ neoclock4x_start(int unit, pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; - /* no time is given by user! use 169.583333 ms to compensate the serial line delay + /* + * no fudge time is given by user! + * use 169.583333 ms to compensate the serial line delay * formula is: * 2400 Baud / 11 bit = 218.18 charaters per second * (NeoClock4X timecode len) */ pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0; - if (!io_addclock(&pp->io)) - { - msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m",unit); - (void) close(fd); - free(up); - return (0); - } - /* * 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, "?"); + up->firmwaretag = '?'; strcpy(up->serial, "?"); strcpy(up->radiosignal, "?"); up->timesource = '?'; @@ -241,13 +302,25 @@ neoclock4x_start(int unit, up->utc_second = 0; up->utc_msec = 0; +#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)"); + up->firmwaretag = 'A'; +#else + msyslog(LOG_EMERG, "NeoClock4X(%d): Unkown firmware defined at compile time for NeoClock4X", + unit); + (void) close(fd); + pp->io.fd = -1; + free(pp->unitptr); + pp->unitptr = NULL; + return (0); +#endif +#else for(tries=0; tries < 5; tries++) { - /* - * Wait 3 second for receiver to power up - */ NLOG(NLOG_CLOCKINFO) - msyslog(LOG_INFO, "NeoClock4X(%d): try query NeoClock4X firmware version (%d/5)", unit, tries); + msyslog(LOG_INFO, "NeoClock4X(%d): checking NeoClock4X firmware version (%d/5)", unit, tries); + /* wait 3 seconds for receiver to power up */ sleep(3); if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware))) { @@ -255,9 +328,30 @@ neoclock4x_start(int unit, } } + /* can I handle this firmware version? */ + if(!neol_check_firmware(up->unit, up->firmware, &up->firmwaretag)) + { + (void) close(fd); + pp->io.fd = -1; + free(pp->unitptr); + pp->unitptr = NULL; + return (0); + } +#endif + + if(!io_addclock(&pp->io)) + { + msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m", unit); + (void) close(fd); + pp->io.fd = -1; + free(pp->unitptr); + pp->unitptr = NULL; + return (0); + } + NLOG(NLOG_CLOCKINFO) msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit); - + return (1); } @@ -269,30 +363,47 @@ neoclock4x_shutdown(int unit, struct refclockproc *pp; int sl232; - pp = peer->procptr; - up = (struct neoclock4x_unit *)pp->unitptr; - -#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) - /* turn on RTS, and DTR for power supply */ - /* NeoClock4x is powered from serial line */ - if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) + if(NULL != peer) { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit); - } + pp = peer->procptr; + if(pp != NULL) + { + up = (struct neoclock4x_unit *)pp->unitptr; + if(up != NULL) + { + if(-1 != pp->io.fd) + { +#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) + /* turn on RTS, and DTR for power supply */ + /* NeoClock4x is powered from serial line */ + if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", + unit); + } #ifdef TIOCM_RTS - sl232 &= ~(TIOCM_DTR | TIOCM_RTS); /* turn on RTS, and DTR for power supply */ + /* turn on RTS, and DTR for power supply */ + sl232 &= ~(TIOCM_DTR | TIOCM_RTS); #else - sl232 &= ~(CIOCM_DTR | CIOCM_RTS); /* turn on RTS, and DTR for power supply */ + /* turn on RTS, and DTR for power supply */ + sl232 &= ~(CIOCM_DTR | CIOCM_RTS); #endif - if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit); - } + if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", + unit); + } #endif + io_closeclock(&pp->io); + } + free(up); + pp->unitptr = NULL; + } + } + } + msyslog(LOG_ERR, "NeoClock4X(%d): shutdown", unit); - io_closeclock(&pp->io); - free(up); NLOG(NLOG_CLOCKINFO) msyslog(LOG_INFO, "NeoClock4X(%d): receiver shutdown done", unit); } @@ -307,23 +418,25 @@ neoclock4x_receive(struct recvbuf *rbufp) int day; int month; /* ddd conversion */ int c; + int dsec; unsigned char calc_chksum; int recv_chksum; - + peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct neoclock4x_unit *)pp->unitptr; - + /* wait till poll interval is reached */ if(0 == up->recvnow) return; - + /* reset poll interval flag */ up->recvnow = 0; /* read last received timecode */ pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); - + pp->leap = LEAP_NOWARNING; + if(NEOCLOCK4X_TIMECODELEN != pp->lencode) { NLOG(NLOG_CLOCKEVENT) @@ -353,7 +466,7 @@ neoclock4x_receive(struct recvbuf *rbufp) /* Allow synchronization even is quartz clock is * never initialized. * WARNING: This is dangerous! - */ + */ up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS]; if(0==(pp->sloppyclockflag & CLK_FLAG2)) { @@ -373,9 +486,9 @@ neoclock4x_receive(struct recvbuf *rbufp) msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s", up->unit, pp->a_lastcode); } - + /* - * If NeoClock4X is not synchronized to a radio clock + * If NeoClock4X is not synchronized to a radio clock * check if we're allowed to synchronize with the quartz * clock. */ @@ -410,9 +523,9 @@ neoclock4x_receive(struct recvbuf *rbufp) neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &pp->msec, 2); - pp->msec *= 10; /* convert 1/100s from neoclock to real miliseconds */ - + neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2); + pp->nsec = dsec * 10000; /* convert 1/100s from neoclock to nanoseconds */ + memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3); up->radiosignal[3] = 0; memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6); @@ -438,18 +551,23 @@ neoclock4x_receive(struct recvbuf *rbufp) refclock_report(peer, CEVNT_BADDATE); return; } - - /* Year-2000 check! */ - /* wrap 2-digit date into 4-digit */ - - if(pp->year < YEAR_PIVOT) /* < 98 */ - { - pp->year += 100; - } - pp->year += 1900; - + + /* Year-2000 check not needed anymore. Same problem + * will arise at 2099 but what should we do...? + * + * wrap 2-digit date into 4-digit + * + * if(pp->year < YEAR_PIVOT) + * { + * pp->year += 100; + * } + */ + pp->year += 2000; + + /* adjust NeoClock4X local time to UTC */ calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second); calc_utc -= 3600; + /* adjust NeoClock4X daylight saving time if needed */ if('S' == up->dststatus) calc_utc -= 3600; neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second); @@ -457,16 +575,15 @@ neoclock4x_receive(struct recvbuf *rbufp) /* some preparations */ - pp->day = ymd2yd(pp->year,month,day); + pp->day = ymd2yd(pp->year, month, day); pp->leap = 0; - if(pp->sloppyclockflag & CLK_FLAG4) { - msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03d", + msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld", up->unit, pp->year, month, day, - pp->hour, pp->minute, pp->second, pp->msec); + pp->hour, pp->minute, pp->second, pp->nsec/1000); } up->utc_year = pp->year; @@ -475,8 +592,8 @@ neoclock4x_receive(struct recvbuf *rbufp) up->utc_hour = pp->hour; up->utc_minute = pp->minute; up->utc_second = pp->second; - up->utc_msec = pp->msec; - + up->utc_msec = pp->nsec/1000; + if(!refclock_process(pp)) { NLOG(NLOG_CLOCKEVENT) @@ -485,7 +602,10 @@ neoclock4x_receive(struct recvbuf *rbufp) return; } refclock_receive(peer); - + + /* report good status */ + refclock_report(peer, CEVNT_NOMINAL); + record_clock_stats(&peer->srcadr, pp->a_lastcode); } @@ -511,7 +631,7 @@ neoclock4x_control(int unit, { struct neoclock4x_unit *up; struct refclockproc *pp; - + if(NULL == peer) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); @@ -542,7 +662,7 @@ neoclock4x_control(int unit, msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.", unit, pp->fudgetime1); } - + /* notify */ if(pp->sloppyclockflag & CLK_FLAG1) { @@ -561,61 +681,66 @@ neoclock4x_control(int unit, static char outstatus[800]; /* status output buffer */ char *tt; char tmpbuf[80]; - + outstatus[0] = '\0'; out->kv_list = (struct ctl_var *)0; out->type = REFCLK_NEOCLOCK4X; - - sprintf(tmpbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d", - up->utc_year, up->utc_month, up->utc_day, - up->utc_hour, up->utc_minute, up->utc_second, - up->utc_msec); - - tt = add_var(&out->kv_list, 512, RO|DEF); - tt += sprintf(tt, "calc_utc=\"%s\"", tmpbuf); - tt = add_var(&out->kv_list, 512, RO|DEF); - tt += sprintf(tt, "radiosignal=\"%s\"", up->radiosignal); - tt = add_var(&out->kv_list, 512, RO|DEF); - tt += sprintf(tt, "antenna1=\"%d\"", up->antenna1); - tt = add_var(&out->kv_list, 512, RO|DEF); - tt += sprintf(tt, "antenna2=\"%d\"", up->antenna2); - tt = add_var(&out->kv_list, 512, RO|DEF); + + snprintf(tmpbuf, sizeof(tmpbuf)-1, + "%04d-%02d-%02d %02d:%02d:%02d.%03d", + up->utc_year, up->utc_month, up->utc_day, + up->utc_hour, up->utc_minute, up->utc_second, + up->utc_msec); + tt = add_var(&out->kv_list, sizeof(tmpbuf)-1, RO|DEF); + snprintf(tt, sizeof(tmpbuf)-1, "calc_utc=\"%s\"", tmpbuf); + + tt = add_var(&out->kv_list, 40, RO|DEF); + snprintf(tt, 39, "radiosignal=\"%s\"", up->radiosignal); + tt = add_var(&out->kv_list, 40, RO|DEF); + snprintf(tt, 39, "antenna1=\"%d\"", up->antenna1); + tt = add_var(&out->kv_list, 40, RO|DEF); + snprintf(tt, 39, "antenna2=\"%d\"", up->antenna2); + tt = add_var(&out->kv_list, 40, RO|DEF); if('A' == up->timesource) - tt += sprintf(tt, "timesource=\"radio\""); + snprintf(tt, 39, "timesource=\"radio\""); else if('C' == up->timesource) - tt += sprintf(tt, "timesource=\"quartz\""); + snprintf(tt, 39, "timesource=\"quartz\""); else - tt += sprintf(tt, "timesource=\"unknown\""); - tt = add_var(&out->kv_list, 512, RO|DEF); + snprintf(tt, 39, "timesource=\"unknown\""); + tt = add_var(&out->kv_list, 40, RO|DEF); if('I' == up->quarzstatus) - tt += sprintf(tt, "quartzstatus=\"synchronized\""); + snprintf(tt, 39, "quartzstatus=\"synchronized\""); else if('X' == up->quarzstatus) - tt += sprintf(tt, "quartzstatus=\"not synchronized\""); + snprintf(tt, 39, "quartzstatus=\"not synchronized\""); else - tt += sprintf(tt, "quartzstatus=\"unknown\""); - tt = add_var(&out->kv_list, 512, RO|DEF); + snprintf(tt, 39, "quartzstatus=\"unknown\""); + tt = add_var(&out->kv_list, 40, RO|DEF); if('S' == up->dststatus) - tt += sprintf(tt, "dststatus=\"summer\""); + snprintf(tt, 39, "dststatus=\"summer\""); else if('W' == up->dststatus) - tt += sprintf(tt, "dststatus=\"winter\""); + snprintf(tt, 39, "dststatus=\"winter\""); else - tt += sprintf(tt, "dststatus=\"unknown\""); - tt = add_var(&out->kv_list, 512, RO|DEF); - tt += sprintf(tt, "firmware=\"%s\"", up->firmware); - tt = add_var(&out->kv_list, 512, RO|DEF); - tt += sprintf(tt, "serialnumber=\"%s\"", up->serial); - tt = add_var(&out->kv_list, 512, RO|DEF); + snprintf(tt, 39, "dststatus=\"unknown\""); + tt = add_var(&out->kv_list, 80, RO|DEF); + snprintf(tt, 79, "firmware=\"%s\"", up->firmware); + tt = add_var(&out->kv_list, 40, RO|DEF); + snprintf(tt, 39, "firmwaretag=\"%c\"", up->firmwaretag); + tt = add_var(&out->kv_list, 80, RO|DEF); + snprintf(tt, 79, "driver version=\"%s\"", NEOCLOCK4X_DRIVER_VERSION); + tt = add_var(&out->kv_list, 80, RO|DEF); + snprintf(tt, 79, "serialnumber=\"%s\"", up->serial); } } -static int neol_hexatoi_len(const char str[], - int *result, - int maxlen) +static int +neol_hexatoi_len(const char str[], + int *result, + int maxlen) { int hexdigit; int i; int n = 0; - + for(i=0; isxdigit(str[i]) && i < maxlen; i++) { hexdigit = isdigit(str[i]) ? toupper(str[i]) - '0' : toupper(str[i]) - 'A' + 10; @@ -625,14 +750,15 @@ static int neol_hexatoi_len(const char str[], return (n); } -int neol_atoi_len(const char str[], +static int +neol_atoi_len(const char str[], int *result, int maxlen) { int digit; int i; int n = 0; - + for(i=0; isdigit(str[i]) && i < maxlen; i++) { digit = str[i] - '0'; @@ -657,12 +783,13 @@ int neol_atoi_len(const char str[], * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ -static unsigned long neol_mktime(int year, - int mon, - int day, - int hour, - int min, - int sec) +static unsigned long +neol_mktime(int year, + int mon, + int day, + int hour, + int min, + int sec) { if (0 >= (int) (mon -= 2)) { /* 1..12 . 11,12,1..10 */ mon += 12; /* Puts Feb last since it has leap day */ @@ -676,41 +803,36 @@ static unsigned long neol_mktime(int year, )*60 + sec; /* finally seconds */ } -static void neol_localtime(unsigned long utc, - int* year, - int* month, - int* day, - int* hour, - int* minute, - int* second) +static void +neol_localtime(unsigned long utc, + int* year, + int* month, + int* day, + int* hour, + int* min, + int* sec) { - ldiv_t d; - - /* Sekunden */ - d = ldiv(utc, 60); - *second = d.rem; - - /* Minute */ - d = ldiv(d.quot, 60); - *minute = d.rem; - - /* Stunden */ - d = ldiv(d.quot, 24); - *hour = d.rem; - + *sec = utc % 60; + utc /= 60; + *min = utc % 60; + utc /= 60; + *hour = utc % 24; + utc /= 24; + /* JDN Date 1/1/1970 */ - neol_jdn_to_ymd(d.quot + 2440588L, year, month, day); + neol_jdn_to_ymd(utc + 2440588L, year, month, day); } -static void neol_jdn_to_ymd(unsigned long jdn, - int *yy, - int *mm, - int *dd) +static void +neol_jdn_to_ymd(unsigned long jdn, + int *yy, + int *mm, + int *dd) { unsigned long x, z, m, d, y; unsigned long daysPer400Years = 146097UL; unsigned long fudgedDaysPer4000Years = 1460970UL + 31UL; - + x = jdn + 68569UL; z = 4UL * x / daysPer400Years; x = x - (daysPer400Years * z + 3UL) / 4UL; @@ -721,83 +843,110 @@ static void neol_jdn_to_ymd(unsigned long jdn, x = m / 11UL; m = m + 2UL - 12UL * x; y = 100UL * (z - 49UL) + y + x; - + *yy = (int)y; *mm = (int)m; *dd = (int)d; } -/* - * delay in milliseconds - */ -static void -neol_mdelay(int milliseconds) -{ - struct timeval tv; - - if (milliseconds) - { - tv.tv_sec = 0; - tv.tv_usec = milliseconds * 1000; - select(1, NULL, NULL, NULL, &tv); - } +#if 0 +/* + * delay in milliseconds + */ +static void +neol_mdelay(int milliseconds) +{ + struct timeval tv; + + if(milliseconds) + { + tv.tv_sec = 0; + tv.tv_usec = milliseconds * 1000; + select(1, NULL, NULL, NULL, &tv); + } } +#endif +#if !defined(NEOCLOCK4X_FIRMWARE) static int neol_query_firmware(int fd, int unit, char *firmware, int maxlen) { - unsigned char tmpbuf[256]; + char tmpbuf[256]; int len; int lastsearch; unsigned char c; int last_c_was_crlf; int last_crlf_conv_len; int init; - int read_tries; + int read_errors; int flag = 0; + int chars_read; /* wait a little bit */ - neol_mdelay(250); + sleep(1); if(-1 != write(fd, "V", 1)) { /* wait a little bit */ - neol_mdelay(250); + sleep(1); memset(tmpbuf, 0x00, sizeof(tmpbuf)); - + len = 0; lastsearch = 0; last_c_was_crlf = 0; last_crlf_conv_len = 0; init = 1; - read_tries = 0; + read_errors = 0; + chars_read = 0; for(;;) { - if(read_tries++ > 500) + if(read_errors > 5) { msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit); strcpy(tmpbuf, "unknown due to timeout"); break; } + if(chars_read > 500) + { + msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit); + strcpy(tmpbuf, "unknown due to garbage input"); + break; + } if(-1 == read(fd, &c, 1)) { - neol_mdelay(25); + if(EAGAIN != errno) + { + msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %s", unit ,strerror(errno)); + read_errors++; + } + else + { + sleep(1); + } continue; } + else + { + chars_read++; + } + if(init) { if(0xA9 != c) /* wait for (c) char in input stream */ continue; - + strcpy(tmpbuf, "(c)"); len = 3; init = 0; continue; } - - //msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c); + +#if 0 + msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c); +#endif + if(0x0A == c || 0x0D == c) { if(last_c_was_crlf) @@ -823,7 +972,7 @@ neol_query_firmware(int fd, { last_c_was_crlf = 0; if(0x00 != c) - tmpbuf[len++] = c; + tmpbuf[len++] = (char) c; } tmpbuf[len] = '\0'; if(len > sizeof(tmpbuf)-5) @@ -846,7 +995,35 @@ neol_query_firmware(int fd, return (flag); } - + +static int +neol_check_firmware(int unit, + const char *firmware, + char *firmwaretag) +{ + char *ptr; + + *firmwaretag = '?'; + ptr = strstr(firmware, "NDF:"); + if(NULL != ptr) + { + if((strlen(firmware) - strlen(ptr)) >= 7) + { + if(':' == *(ptr+5) && '*' == *(ptr+6)) + *firmwaretag = *(ptr+4); + } + } + + if('A' != *firmwaretag) + { + msyslog(LOG_CRIT, "NeoClock4X(%d): firmware version \"%c\" not supported with this driver version!", unit, *firmwaretag); + return (0); + } + + return (1); +} +#endif + #else int refclock_neoclock4x_bs; #endif /* REFCLOCK */ @@ -858,7 +1035,34 @@ int refclock_neoclock4x_bs; * 2002/04/27 cjh * Revision 1.0 first release * - * 2002/0715 cjh + * 2002/07/15 cjh * preparing for bitkeeper reposity * + * 2002/09/09 cjh + * Revision 1.1 + * - don't assume sprintf returns an int anymore + * - change the way the firmware version is read + * - some customers would like to put a device called + * data diode to the NeoClock4X device to disable + * the write line. We need to now the firmware + * version even in this case. We made a compile time + * definition in this case. The code was previously + * only available on request. + * + * 2003/01/08 cjh + * Revision 1.11 + * - changing xprinf to xnprinf to avoid buffer overflows + * - change some logic + * - fixed memory leaks if drivers can't initialize + * + * 2003/01/10 cjh + * Revision 1.12 + * - replaced ldiv + * - add code to support FreeBSD + * + * 2003/07/07 cjh + * Revision 1.13 + * - fix reporting of clock status + * changes. previously a bad clock + * status was never reset. */ diff --git a/contrib/ntp/ntpd/refclock_nmea.c b/contrib/ntp/ntpd/refclock_nmea.c index e9304ee..28d6263 100644 --- a/contrib/ntp/ntpd/refclock_nmea.c +++ b/contrib/ntp/ntpd/refclock_nmea.c @@ -7,6 +7,11 @@ #include #endif +#if defined(SYS_WINNT) +#undef close +#define close closesocket +#endif + #if defined(REFCLOCK) && defined(CLOCK_NMEA) #include "ntpd.h" @@ -147,14 +152,15 @@ nmea_start( */ (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + fd = refclock_open(device, SPEED232, LDISC_CLK); + if (fd < 0) return (0); /* * Allocate and initialize unit structure */ - if (!(up = (struct nmeaunit *) - emalloc(sizeof(struct nmeaunit)))) { + up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit)); + if (up == NULL) { (void) close(fd); return (0); } @@ -380,7 +386,7 @@ nmea_receive( peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct nmeaunit *)pp->unitptr; - rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); + rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); /* * There is a case that a gives back a "blank" line @@ -433,8 +439,8 @@ nmea_receive( /* See if I want to process this message type */ - if ( ((peer->ttlmax == 0) && (cmdtype != GPRMC)) - || ((peer->ttlmax != 0) && !(cmdtype & peer->ttlmax)) ) + if ( ((peer->ttl == 0) && (cmdtype != GPRMC)) + || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) ) return; pp->lencode = rd_lencode; @@ -530,21 +536,21 @@ nmea_receive( /* Default to 0 milliseconds, if decimal convert milliseconds in one, two or three digits */ - pp->msec = 0; + pp->nsec = 0; if (dp[6] == '.') { if (isdigit((int)dp[7])) { - pp->msec = (dp[7] - '0') * 100; + pp->nsec = (dp[7] - '0') * 100000000; if (isdigit((int)dp[8])) { - pp->msec += (dp[8] - '0') * 10; + pp->nsec += (dp[8] - '0') * 10000000; if (isdigit((int)dp[9])) { - pp->msec += (dp[9] - '0'); + pp->nsec += (dp[9] - '0') * 1000000; } } } } if (pp->hour > 23 || pp->minute > 59 || pp->second > 59 - || pp->msec > 1000) { + || pp->nsec > 1000000000) { refclock_report(peer, CEVNT_BADTIME); return; } @@ -604,7 +610,7 @@ nmea_receive( */ if (nmea_pps(up, &rd_tmp) == 1) { pp->lastrec = up->tstamp = rd_tmp; - pp->msec = 0; + pp->nsec = 0; } #endif /* HAVE_PPSAPI */ @@ -630,7 +636,7 @@ nmea_receive( 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 */ diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c index 43a38fb..14db92f 100644 --- a/contrib/ntp/ntpd/refclock_oncore.c +++ b/contrib/ntp/ntpd/refclock_oncore.c @@ -9,8 +9,9 @@ * refclock_oncore.c * * Driver for some of the various the Motorola Oncore GPS receivers. - * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12. - * The receivers with TRAIM (VP, UT, UT+), will be more accurate than the others. + * 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. * The receivers without position hold (GT, GT+) will be less accurate. * * Tested with: @@ -28,16 +29,16 @@ * OPTIONS LIST IB * * (Basic) (M12) - * COPYRIGHT 1991-1996 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. - * SFTW P/N # 98-P36830P SFTW P/N # 61-G10002A - * SOFTWARE VER # 8 SOFTWARE VER # 1 - * SOFTWARE REV # 8 SOFTWARE REV # 3 - * SOFTWARE DATE 06 Aug 1996 SOFTWARE DATE Mar 13 2000 - * MODEL # B4121P1155 MODEL # P143T12NR1 + * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. + * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A + * SOFTWARE VER # 5 SOFTWARE VER # 1 + * SOFTWARE REV # 0 SOFTWARE REV # 3 + * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000 + * MODEL # A11121P116 MODEL # P143T12NR1 * HDWR P/N # _ HWDR P/N # 1 - * SERIAL # SSG0226478 SERIAL # P003UD - * MANUFACTUR DATE 7E02 MANUFACTUR DATE 0C27 - * OPTIONS LIST IB + * SERIAL # SSG0049809 SERIAL # P003UD + * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27 + * OPTIONS LIST AB * * -------------------------------------------------------------------------- * This code uses the two devices @@ -138,7 +139,9 @@ struct ppsclockev { enum receive_state { ONCORE_NO_IDEA, - ONCORE_ID_SENT, + ONCORE_CHECK_ID, + ONCORE_CHECK_CHAN, + ONCORE_HAVE_CHAN, ONCORE_RESET_SENT, ONCORE_TEST_SENT, ONCORE_INIT, @@ -154,6 +157,14 @@ enum site_survey_state { ONCORE_SS_DONE }; +enum antenna_state { + ONCORE_ANTENNA_UNKNOWN = -1, + ONCORE_ANTENNA_OK = 0, + ONCORE_ANTENNA_OC = 1, + ONCORE_ANTENNA_UC = 2, + ONCORE_ANTENNA_NV = 3 +}; + /* Model Name, derived from the @@Cj message. * Used to initialize some variables. */ @@ -204,7 +215,7 @@ struct instance { int ttyfd; /* TTY file descriptor */ int ppsfd; /* PPS file descriptor */ - int statusfd; /* Status shm descriptor */ + int shmemfd; /* Status shm descriptor */ #ifdef HAVE_PPSAPI pps_handle_t pps_h; pps_params_t pps_p; @@ -212,6 +223,7 @@ struct instance { enum receive_state o_state; /* Receive state */ enum posn_mode mode; /* 0D, 2D, 3D */ enum site_survey_state site_survey; /* Site Survey state */ + enum antenna_state ant_state; /* antenna state */ int Bj_day; @@ -224,9 +236,10 @@ struct instance { u_int shmem_Ba; u_int shmem_Ea; u_int shmem_Ha; - u_char shmem_first; u_char shmem_reset; u_char shmem_Posn; + u_char shmem_bad_Ea; + u_char almanac_from_shmem; double ss_lat; double ss_long; @@ -240,59 +253,98 @@ struct instance { u_int revision; u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ - s_char traim; /* do we have traim? yes UT/VP, no BASIC, GT, -1 unknown, 0 no, +1 yes */ + s_char traim; /* do we have traim? yes UT/VP, no BASIC, GT, M12+T, -1 unknown, 0 no, +1 yes */ + + /* the following 7 are all timing counters */ u_char traim_delay; /* seconds counter, waiting for reply */ + u_char count; /* cycles thru Ea before starting */ + u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ + u_char count2; /* cycles thru Ea after count, to check for @@Ea */ + u_char count3; /* cycles thru Ea checking for # channels */ + u_char count4; /* cycles thru leap after Gj to issue Bj */ + u_char pollcnt; + u_char timeout; /* count to retry Cj after Fa self-test */ struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ u_char printed; u_char polled; - int pollcnt; - u_int ev_serial; + u_long ev_serial; int Rcvptr; u_char Rcvbuf[500]; - u_char Ea[160]; /* Ba, Ea or Ha */ - u_char En[70]; /* Bn or En */ + u_char BEHa[160]; /* Ba, Ea or Ha */ + u_char BEHn[80]; /* Bn , En , or Hn */ u_char Cj[300]; - u_char As; - u_char Ay; - u_char Az; + u_char Ag; /* Satellite mask angle */ + u_char saw_At; + u_char saw_Ay; + u_char saw_Az; + s_char saw_Gj; u_char have_dH; u_char init_type; s_char saw_tooth; - u_int timeout; /* count to retry Cj after Fa self-test */ - u_char count; /* cycles thru Ea before starting */ + s_char chan_in; /* chan number from INPUT, will always use it */ + u_char chan_id; /* chan number determined from part number */ + u_char chan_ck; /* chan number determined by sending commands to hardware */ + s_char traim_in; /* TRAIM from INPUT, will always use it */ + s_char traim_id; /* TRAIM determined from part number */ + u_char traim_ck; /* TRAIM determined by sending commands to hardware */ + u_char once; /* one pass code at top of BaEaHa */ s_char assert; - u_int saw_At; + u_char hardpps; }; #define rcvbuf instance->Rcvbuf #define rcvptr instance->Rcvptr -static void oncore_consume P((struct instance *)); -static void oncore_poll P((int, struct peer *)); -static void oncore_read_config P((struct instance *)); -static void oncore_receive P((struct recvbuf *)); -static void oncore_sendmsg P((int fd, u_char *, size_t)); -static void oncore_shutdown P((int, struct peer *)); -static int oncore_start P((int, struct peer *)); -static void oncore_get_timestamp P((struct instance *, long, long)); -static void oncore_init_shmem P((struct instance *)); -static void oncore_print_As P((struct instance *)); +static int oncore_start P((int, struct peer *)); +static void oncore_control P((int, struct refclockstat *, struct refclockstat *, 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_BnEn 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_Gd 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)); @@ -300,7 +352,7 @@ struct refclock refclock_oncore = { oncore_start, /* start up driver */ oncore_shutdown, /* shut down driver */ oncore_poll, /* transmit poll message */ - noentry, /* not used */ + oncore_control, /* fudge (flag) control messages */ noentry, /* not used */ noentry, /* not used */ NOFLAGS /* not used */ @@ -322,13 +374,15 @@ static struct msg_desc { { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, - { "En", 69, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, - { "Bn", 59, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, + { "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, 0, "" }, - { "Ae", 11, 0, "" }, - { "Af", 15, 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, "" }, @@ -338,6 +392,7 @@ static struct msg_desc { { "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, "" }, @@ -347,132 +402,92 @@ static struct msg_desc { { "Cj", 294, oncore_msg_Cj, "" }, { "Ek", 71, 0, "" }, { "Fa", 9, oncore_msg_CaFaIa, "" }, - { "Gd", 8, 0, "" }, + { "Ga", 20, oncore_msg_Ga, "" }, + { "Gb", 17, oncore_msg_Gb, "" }, + { "Gc", 8, 0, "" }, + { "Gd", 8, oncore_msg_Gd, "" }, + { "Ge", 8, 0, "" }, { "Gj", 21, oncore_msg_Gj, "" }, { "Ia", 10, oncore_msg_CaFaIa, "" }, { "Sz", 8, oncore_msg_Sz, "" }, { {0}, 7, 0, "" } }; -/* - * Position Set. - */ -u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; -u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; -u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; -u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; - -/* - * Position-Hold Mode - * Start automatic site survey - */ -static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* Posn Hold off */ -static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* Posn Hold on */ -static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* Start Site Survey */ - -/* - * 0D/2D Position and Set. - */ -u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; -u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xff }; -u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0,0 }; - -u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; -u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; - -u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 3D */ -u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 0D */ -u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 2D */ - -/* - * Set to UTC time (not GPS). - */ -u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; - -/* - * Output Almanac when it changes - */ -u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; - -/* - * Read back PPS Offset for Output - */ -u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; -u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; - -/* - * Read back Cable Delay for Output - */ -u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; -u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; - -/* - * Application type = static. - */ -u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; - -/* - * Visible Satellite Status Msg. - */ -u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; - -/* - * Leap Second Pending Message - * Request message once - */ -u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; -u_char oncore_cmd_Gj[] = { 'G', 'j' }; - -/* - * Set to Defaults - */ -static u_char oncore_cmd_Cf[] = { 'C', 'f' }; - -/* - * Set to Position Fix mode (only needed on VP). - */ -u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; - -/* - * Receiver Id - */ -static u_char oncore_cmd_Cj[] = { 'C', 'j' }; - -/* - * Position/Status/Data message - * Send once per second - */ -static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; -static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; -static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; -static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; -static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; - -/* - * Position/Status Extension Msg - */ -u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ -/* - * Time Raim Setup & Status Message - * Send once per second - * Time-RAIM on - * Alarm limit 1us - * PPS on when we have the first sat +static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */ +static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */ +static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */ +static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */ +static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */ +static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */ +static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */ +static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */ +static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */ +static u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 6/8/12 Posn Hold Parameters */ +static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ + 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ + 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */ +static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */ +static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */ +static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */ +static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */ +static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */ +static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */ +static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */ +static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */ +static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */ +static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */ +static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */ +static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */ +static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */ +static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */ +static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */ +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_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', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on traim off */ +static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */ +static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */ +static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */ +static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */ +static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */ +static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */ +static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */ +static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim on */ +static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim on */ +static u_char oncore_cmd_Enx[] = { 'E', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim off */ +static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */ +static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */ +static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */ + 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_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) */ +static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */ +static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */ +static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */ +static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */ +static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */ +static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */ +static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */ +static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */ +static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */ + +/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av + * the GT had Au,Av, but not As,At + * This was as of v2.0 of both firmware sets. possibly 1.3 for UT. + * Bj in UT at v1.3 + * dont see Bd in UT/GT thru 1999 + * Gj in UT as of 3.0, 1999 , Bj as of 1.3 */ -static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* - * Self-test - */ -static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Chan */ -static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Chan */ -static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Chan */ +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 */ @@ -502,10 +517,6 @@ static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Chan */ /* from buffer, char *buf, result to an int */ #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) -extern int pps_assert; -extern int pps_hardpps; - - /* * oncore_start - initialize data for processing @@ -519,7 +530,7 @@ oncore_start( { register struct instance *instance; struct refclockproc *pp; - int fd1, fd2, mode; + int fd1, fd2; char device1[30], device2[30]; const char *cp; struct stat stat1, stat2; @@ -548,6 +559,14 @@ oncore_start( exit(1); } + /* create instance structure for this unit */ + + if (!(instance = (struct instance *) malloc(sizeof *instance))) { + perror("malloc"); + return (0); + } + memset((char *) instance, 0, sizeof *instance); + if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) { /* same device here */ if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW @@ -559,7 +578,7 @@ oncore_start( exit(1); } fd2 = fd1; - } else { /* different devices here */ + } else { /* different devices here */ if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) { perror("ONCORE: fd1"); exit(1); @@ -570,24 +589,18 @@ oncore_start( } } - /* Devices now open, create instance structure for this unit */ - - if (!(instance = (struct instance *) malloc(sizeof *instance))) { - perror("malloc"); - close(fd1); - return (0); - } - memset((char *) instance, 0, sizeof *instance); - - /* link instance up and down */ + /* initialize miscellaneous variables */ pp = peer->procptr; pp->unitptr = (caddr_t) instance; instance->pp = pp; instance->unit = unit; instance->peer = peer; + instance->assert = 1; + instance->once = 1; - /* initialize miscellaneous variables */ + cp = "ONCORE DRIVER -- CONFIGURING"; + record_clock_stats(&(instance->peer->srcadr), cp); instance->o_state = ONCORE_NO_IDEA; cp = "state = ONCORE_NO_IDEA"; @@ -597,11 +610,14 @@ oncore_start( instance->ppsfd = fd2; instance->Bj_day = -1; - instance->assert = pps_assert; instance->traim = -1; + instance->traim_in = -1; + instance->chan_in = -1; 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->precision = -26; peer->minpoll = 4; @@ -609,7 +625,7 @@ oncore_start( pp->clockdesc = "Motorola Oncore GPS Receiver"; memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); - /* go read any input data in /etc/ntp.oncoreX */ + /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */ oncore_read_config(instance); @@ -619,15 +635,183 @@ oncore_start( return(0); } + if (instance->assert) + cp = "Initializing timing to Assert."; + else + cp = "Initializing timing to Clear."; + record_clock_stats(&(instance->peer->srcadr), cp); + + if (instance->hardpps) { + cp = "HARDPPS Set."; + record_clock_stats(&(instance->peer->srcadr), cp); + } + + if (!oncore_ppsapi(instance)) + return(0); +#endif + + pp->io.clock_recv = oncore_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd1; + if (!io_addclock(&pp->io)) { + perror("io_addclock"); + (void) close(fd1); + free(instance); + return (0); + } + +#ifdef ONCORE_SHMEM_STATUS + /* + * Before starting ONCORE, lets setup SHMEM + * This will include merging an old SHMEM into the new one if + * an old one is found. + */ + + oncore_init_shmem(instance); +#endif + + /* + * This will return the Model of the Oncore receiver. + * and start the Initialization loop in oncore_msg_Cj. + */ + + instance->o_state = ONCORE_CHECK_ID; + cp = "state = ONCORE_CHECK_ID"; + record_clock_stats(&(instance->peer->srcadr), cp); + + 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)); + + instance->pollcnt = 2; + return (1); +} + + +/* + * Fudge control (get Flag2 and Flag3, not available at oncore_start time. + */ + +static void +oncore_control( + int unit, /* unit (not used) */ + struct refclockstat *in, /* input parameters (not used) */ + struct refclockstat *out, /* output parameters (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + char *cp; + struct refclockproc *pp; + struct instance *instance; + + pp = peer->procptr; + instance = (struct instance *) pp->unitptr; + + instance->assert = !(pp->sloppyclockflag & CLK_FLAG2); + instance->hardpps = pp->sloppyclockflag & CLK_FLAG3; + + if (instance->assert) + cp = "Resetting timing to Assert."; + else + cp = "Resetting timing to Clear."; + record_clock_stats(&(instance->peer->srcadr), cp); + + if (instance->hardpps) { + cp = "HARDPPS Set."; + record_clock_stats(&(instance->peer->srcadr), cp); + } + + (void) oncore_ppsapi(instance); +} + + + +/* + * oncore_shutdown - shut down the clock + */ + +static void +oncore_shutdown( + int unit, + struct peer *peer + ) +{ + register struct instance *instance; + struct refclockproc *pp; + + pp = peer->procptr; + instance = (struct instance *) pp->unitptr; + + io_closeclock(&pp->io); + + close(instance->ttyfd); + close(instance->ppsfd); + if (instance->shmemfd) + close(instance->shmemfd); + free(instance); +} + + + +/* + * oncore_poll - called by the transmit procedure + */ + +static void +oncore_poll( + int unit, + struct peer *peer + ) +{ + struct instance *instance; + + instance = (struct 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_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); + } + return; + } + + if (!instance->pollcnt) + refclock_report(peer, CEVNT_TIMEOUT); + else + instance->pollcnt--; + peer->procptr->polls++; + instance->polled = 1; +} + + + +/* + * Initialize PPSAPI + */ + +#ifdef HAVE_PPSAPI +static int +oncore_ppsapi( + struct instance *instance + ) +{ + int mode; + if (time_pps_getcap(instance->pps_h, &mode) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_getcap failed: %m"); + msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m"); return (0); } if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_getparams failed: %m"); + msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m"); return (0); } @@ -652,72 +836,196 @@ oncore_start( exit(1); } - if (pps_device && pps_device[0]) { - if (stat(pps_device, &stat1)) { - perror("ONCORE: stat pps_device"); - return(0); - } + /* If HARDPPS is on, we tell kernel */ - /* must have hardpps ON, and fd2 must be the same device as on the pps line */ + if (instance->hardpps) { + int i; - if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) { - int i; + if (instance->assert) + i = PPS_CAPTUREASSERT; + else + i = PPS_CAPTURECLEAR; - if (instance->assert) - i = PPS_CAPTUREASSERT; - else - i = PPS_CAPTURECLEAR; - - if (i&mode) { - if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, - PPS_TSFMT_TSPEC) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_kcbind failed: %m"); - return (0); - } - pps_enable = 1; + if (i&mode) { + if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, + PPS_TSFMT_TSPEC) < 0) { + msyslog(LOG_ERR, "refclock_ioctl: time_pps_kcbind failed: %m"); + return (0); } + pps_enable = 1; } } + return(1); +} #endif - pp->io.clock_recv = oncore_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd1; - if (!io_addclock(&pp->io)) { - perror("io_addclock"); - (void) close(fd1); - free(instance); - return (0); - } - /* - * This will return the Model Number of the Oncore receiver. - */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); - instance->o_state = ONCORE_ID_SENT; - cp = "state = ONCORE_ID SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->timeout = 4; +#ifdef ONCORE_SHMEM_STATUS +static void +oncore_init_shmem( + struct instance *instance + ) +{ + int i, l, n, fd, shmem_old_size, n1; + char *buf, Msg[160]; + u_char *cp, *cp1, *shmem_old; + struct msg_desc *mp; + struct stat sbuf; + size_t shmem_length; - instance->pollcnt = 2; - return (1); -} + /* + * 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). + */ + shmem_old = 0; + if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0) + perror("LOAD:SHMEM"); + else { + fstat(fd, &sbuf); + shmem_old_size = sbuf.st_size; + shmem_old = (u_char *) malloc((unsigned) sbuf.st_size); + if (shmem_old == NULL) { + perror("malloc"); + close(fd); + return; + } + read(fd, shmem_old, shmem_old_size); + close(fd); + } -/* - * Read Input file if it exists. - */ + /* OK, we now create the NEW SHMEM. */ -static void -oncore_read_config( - struct instance *instance - ) -{ -/* + if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { + perror(instance->shmem_fname); + return; + } + + /* see how big it needs to be */ + + n = 1; + for (mp=oncore_messages; mp->flag[0]; mp++) { + mp->shmem = n; + /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ + if (!strcmp(mp->flag, "Cb")) { + instance->shmem_Cb = n; + n += (mp->len + 3) * 34; + } + if (!strcmp(mp->flag, "Ba")) { + instance->shmem_Ba = n; + n += (mp->len + 3) * 3; + } + if (!strcmp(mp->flag, "Ea")) { + instance->shmem_Ea = n; + n += (mp->len + 3) * 3; + } + if (!strcmp(mp->flag, "Ha")) { + instance->shmem_Ha = n; + n += (mp->len + 3) * 3; + } + n += (mp->len + 3); + } + shmem_length = n + 2; + fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) shmem_length); + + buf = malloc(shmem_length); + if (buf == NULL) { + perror("malloc"); + close(instance->shmemfd); + return; + } + + memset(buf, 0, shmem_length); + + /* next build the new SHMEM buffer in memory */ + + for (mp=oncore_messages; mp->flag[0]; mp++) { + l = mp->shmem; + buf[l + 0] = mp->len >> 8; + buf[l + 1] = mp->len & 0xff; + buf[l + 2] = 0; + buf[l + 3] = '@'; + buf[l + 4] = '@'; + buf[l + 5] = mp->flag[0]; + buf[l + 6] = mp->flag[1]; + if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { + if (!strcmp(mp->flag, "Cb")) + n = 35; + else + n = 4; + for (i=1; ilen+3) + 0] = mp->len >> 8; + buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; + buf[l + i * (mp->len+3) + 2] = 0; + buf[l + i * (mp->len+3) + 3] = '@'; + buf[l + i * (mp->len+3) + 4] = '@'; + buf[l + i * (mp->len+3) + 5] = mp->flag[0]; + buf[l + i * (mp->len+3) + 6] = mp->flag[1]; + } + } + } + + /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) + * copying the data in shmem_old to buf. When we are done we write it out + * and free both buffers. + * If the structures change (an addition or deletion) I will stop copying. + * The two will be the same unless we add/subtract from the oncore_messages list + * so this should work most of the time, and takes a lot less code than doing it right. + */ + + if (shmem_old) { + for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { + n1 = 256*(*(cp1-3)) + *(cp1-2); + if (n1 != n || strncmp(cp, cp1, 4)) + break; + + memcpy(cp, cp1, (size_t) n); + } + free(shmem_old); + } + + i = write(instance->shmemfd, buf, shmem_length); + free(buf); + + if (i != shmem_length) { + perror(instance->shmem_fname); + close(instance->shmemfd); + return; + } + + instance->shmem = (u_char *) mmap(0, shmem_length, + PROT_READ | PROT_WRITE, +#ifdef MAP_HASSEMAPHORE + MAP_HASSEMAPHORE | +#endif + MAP_SHARED, instance->shmemfd, (off_t)0); + + if (instance->shmem == (u_char *)MAP_FAILED) { + instance->shmem = 0; + close(instance->shmemfd); + return; + } + + sprintf(Msg, "SHMEM (size = %d) is CONFIGURED and available as %s", shmem_length, instance->shmem_fname); + record_clock_stats(&(instance->peer->srcadr), Msg); +} +#endif /* ONCORE_SHMEM_STATUS */ + + + +/* + * Read Input file if it exists. + */ + +static void +oncore_read_config( + struct instance *instance + ) +{ +/* * First we try to open the configuration file * /etc/oncoreN * where N is the unit number viz 127.127.30.N. @@ -751,8 +1059,8 @@ oncore_read_config( * ------------------------------------------------------------------------------- * * If we open one or the other of the files, we read it looking for - * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, STATUS, - * POSN3D, POSN2D, CHAN, TRAIM + * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, + * STATUS, POSN3D, POSN2D, CHAN, TRAIM * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must * be present or mode reverts to (2,4). * @@ -773,7 +1081,7 @@ oncore_read_config( * Expect to see one line with 'HT' as first field, * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' * for feet or meters. HT is the height above the GPS ellipsoid. - * If the reciever reports height in both GPS and MSL, then we will report + * If the receiver reports height in both GPS and MSL, then we will report * the difference GPS-MSL on the clockstats file. * * There is an optional line, starting with DELAY, followed @@ -793,24 +1101,36 @@ oncore_read_config( * There is an optional line, with either ASSERT or CLEAR on it, which * determine which transition of the PPS signal is used for timing by the * PPSAPI. If neither is present, then ASSERT is assumed. + * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. + * 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. + * HARDPPS can also be set with FLAG3 of the ntp.conf input. + * For Flag3, 0 is disabled, and the default. * - * There are three options that have to do with using the shared memory opition. - * First, to enable the option there must be an ASSERT line with a file name. + * There are three options that have to do with using the shared memory option. + * First, to enable the option there must be a SHMEM line with a file name. * The file name is the file associated with the shared memory. * - * In the shared memory there are three 'records' containing the @@Ea (or equivalent) - * data, and this contains the position data. There will always be data in the - * record cooresponding to the '0D' @@Ea record, and the user has a choice of - * filling the '3D' @@Ea record by specifying POSN3D, or the '2D' record by - * specifying POSN2D. In either case the '2D' or '3D' record is filled once - * every 15s. + * In shared memory, there is one 'record' for each returned variable. + * For the @@Ea data there are three 'records' containing position data. + * There will always be data in the record corresponding to the '0D' @@Ea record, + * and the user has a choice of filling the '3D' record by specifying POSN3D, + * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' + * record is filled once every 15s. * * Two additional variables that can be set are CHAN and TRAIM. These should be * set correctly by the code examining the @@Cj record, but we bring them out here - * to allow the user to override either the # of channels, or the existance of TRAIM. + * to allow the user to override either the # of channels, or the existence of TRAIM. * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be * followed by YES or NO. * + * There is an optional line with MASK on it followed by one integer field in the + * range 0 to 89. This sets the satellite mask angle and will determine the minimum + * 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. + * * So acceptable input would be * # these are my coordinates (RWC) * LON -106 34.610 @@ -821,7 +1141,7 @@ oncore_read_config( FILE *fd; char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160]; - int i, sign, lat_flg, long_flg, ht_flg, mode; + int i, sign, lat_flg, long_flg, ht_flg, mode, mask; double f1, f2, f3; sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */ @@ -835,7 +1155,7 @@ oncore_read_config( } } - mode = 0; + mode = mask = 0; lat_flg = long_flg = ht_flg = 0; while (fgets(line, 100, fd)) { @@ -871,12 +1191,6 @@ oncore_read_config( for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++) continue; - /* - * move call to oncore_shmem_init() from here to after - * we have determined Oncore Model, so we can ignore - * request if model doesnt 'support' it - */ - if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { i = strlen(ca); instance->shmem_fname = (char *) malloc((unsigned) (i+1)); @@ -963,6 +1277,8 @@ oncore_read_config( instance->assert = 1; } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { instance->assert = 0; + } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) { + instance->hardpps = 1; } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { instance->shmem_Posn = 2; } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { @@ -970,11 +1286,15 @@ oncore_read_config( } else if (!strncmp(cc, "CHAN", (size_t) 4)) { sscanf(ca, "%d", &i); if ((i == 6) || (i == 8) || (i == 12)) - instance->chan = i; + instance->chan_in = i; } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { - instance->traim = 1; /* so TRAIM alone is YES */ + instance->traim_in = 1; /* so TRAIM alone is YES */ if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ - instance->traim = 0; + instance->traim_in = 0; + } else if (!strncmp(cc, "MASK", (size_t) 4)) { + sscanf(ca, "%d", &mask); + if (mask > -1 && mask < 90) + instance->Ag = mask; /* Satellite mask angle */ } } fclose(fd); @@ -985,7 +1305,7 @@ oncore_read_config( */ instance->posn_set = 1; - if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) { + if (!( lat_flg && long_flg && ht_flg )) { printf("ONCORE: incomplete data on %s\n", INIT_FILE); instance->posn_set = 0; if (mode == 1 || mode == 3) { @@ -1002,170 +1322,8 @@ oncore_read_config( -static void -oncore_init_shmem( - struct instance *instance - ) -{ -#ifdef ONCORE_SHMEM_STATUS - int i, l, n; - char *buf; - struct msg_desc *mp; - size_t oncore_shmem_length; - - if (instance->shmem_first) - return; - - instance->shmem_first++; - - if ((instance->statusfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { - perror(instance->shmem_fname); - return; - } - - n = 1; - for (mp = oncore_messages; mp->flag[0]; mp++) { - mp->shmem = n; - /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ - if (!strcmp(mp->flag, "Cb")) { - instance->shmem_Cb = n; - n += (mp->len + 3) * 34; - } - if (!strcmp(mp->flag, "Ba")) { - instance->shmem_Ba = n; - n += (mp->len + 3) * 3; - } - if (!strcmp(mp->flag, "Ea")) { - instance->shmem_Ea = n; - n += (mp->len + 3) * 3; - } - if (!strcmp(mp->flag, "Ha")) { - instance->shmem_Ha = n; - n += (mp->len + 3) * 3; - } - n += (mp->len + 3); - } - oncore_shmem_length = n + 2; - fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) oncore_shmem_length); - - buf = malloc(oncore_shmem_length); - if (buf == NULL) { - perror("malloc"); - return; - } - memset(buf, 0, sizeof(buf)); - i = write(instance->statusfd, buf, oncore_shmem_length); - if (i != oncore_shmem_length) { - perror(instance->shmem_fname); - return; - } - free(buf); - instance->shmem = (u_char *) mmap(0, oncore_shmem_length, - PROT_READ | PROT_WRITE, -#ifdef MAP_HASSEMAPHORE - MAP_HASSEMAPHORE | -#endif - MAP_SHARED, - instance->statusfd, (off_t)0); - if (instance->shmem == (u_char *)MAP_FAILED) { - instance->shmem = 0; - close (instance->statusfd); - return; - } - for (mp = oncore_messages; mp->flag[0]; mp++) { - l = mp->shmem; - instance->shmem[l + 0] = mp->len >> 8; - instance->shmem[l + 1] = mp->len & 0xff; - instance->shmem[l + 2] = 0; - instance->shmem[l + 3] = '@'; - instance->shmem[l + 4] = '@'; - instance->shmem[l + 5] = mp->flag[0]; - instance->shmem[l + 6] = mp->flag[1]; - if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { - if (!strcmp(mp->flag, "Cb")) - n = 35; - else - n = 4; - for (i = 1; i < n; i++) { - instance->shmem[l + i * (mp->len+3) + 0] = mp->len >> 8; - instance->shmem[l + i * (mp->len+3) + 1] = mp->len & 0xff; - instance->shmem[l + i * (mp->len+3) + 2] = 0; - instance->shmem[l + i * (mp->len+3) + 3] = '@'; - instance->shmem[l + i * (mp->len+3) + 4] = '@'; - instance->shmem[l + i * (mp->len+3) + 5] = mp->flag[0]; - instance->shmem[l + i * (mp->len+3) + 6] = mp->flag[1]; - } - } - } -#endif /* ONCORE_SHMEM_STATUS */ -} - - - -/* - * oncore_shutdown - shut down the clock - */ - -static void -oncore_shutdown( - int unit, - struct peer *peer - ) -{ - register struct instance *instance; - struct refclockproc *pp; - - pp = peer->procptr; - instance = (struct instance *) pp->unitptr; - - io_closeclock(&pp->io); - - free(instance); -} - - - -/* - * oncore_poll - called by the transmit procedure - */ - -static void -oncore_poll( - int unit, - struct peer *peer - ) -{ - struct instance *instance; - - instance = (struct 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_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); - } - return; - } - - if (!instance->pollcnt) - refclock_report(peer, CEVNT_TIMEOUT); - else - instance->pollcnt--; - peer->procptr->polls++; - instance->polled = 1; -} - - - /* - * move data from NTP to buffer (toss in unlikely case it wont fit) + * move data from NTP to buffer (toss the extra in the unlikely case it won't fit) */ static void @@ -1215,7 +1373,7 @@ oncore_consume( struct instance *instance ) { - int i, j, m; + int i, m; unsigned l; while (rcvptr >= 7) { @@ -1261,10 +1419,7 @@ oncore_consume( if (debug) printf("ONCORE[%d]: NO at end of message\n", instance->unit); } else { /* check the CheckSum */ - j = 0; - for (i = 2; i < l-3; i++) - j ^= rcvbuf[i]; - if (j == rcvbuf[l-3]) { + if (oncore_checksum_ok(rcvbuf, l)) { if (instance->shmem != NULL) { instance->shmem[oncore_messages[m].shmem + 2]++; memcpy(instance->shmem + oncore_messages[m].shmem + 3, @@ -1274,7 +1429,7 @@ oncore_consume( if (oncore_messages[m].handler) oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); } else if (debug) { - printf("ONCORE[%d]: Checksum mismatch! calc %o is %o\n", instance->unit, j, rcvbuf[l-3]); + printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit); printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]); for (i=4; i 3) { + int Rsm; + u_long i, j; + l_fp ts, ts_tmp; + double dmy; +#ifdef HAVE_STRUCT_TIMESPEC + struct timespec *tsp = 0; +#else + struct timeval *tsp = 0; +#endif +#ifdef HAVE_PPSAPI + int current_mode; + pps_params_t current_params; + struct timespec timeout; + pps_info_t pps_i; +#else /* ! HAVE_PPSAPI */ +#ifdef HAVE_CIOGETEV + struct ppsclockev ev; + int r = CIOGETEV; +#endif +#ifdef HAVE_TIOCGPPSEV + struct ppsclockev ev; + int r = TIOCGPPSEV; +#endif +#if TIOCDCDTIMESTAMP + struct timeval tv; +#endif +#endif /* ! HAVE_PPS_API */ + +#if 1 + /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru. + * If we have Finished the SiteSurvey, then we fall thru for the 14/15 + * times we get here in 0D mode (the 1/15 is in 3D for SHMEM). + * This gives good time, which gets better when the SS is done. + */ + + 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)) +#endif + return; + + /* Don't do anything without an almanac to define the GPS->UTC delta */ + + if (instance->rsm.bad_almanac) + return; + +#ifdef HAVE_PPSAPI + j = instance->ev_serial; + timeout.tv_sec = 0; + 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"); + return; + } + + if (instance->assert) { + tsp = &pps_i.assert_timestamp; + + if (debug > 2) { + 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); +#else + printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", + instance->unit, i, j, + (long)tsp->tv_sec, (long)tsp->tv_usec); +#endif + } + + if (pps_i.assert_sequence == j) { + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); + return; + } + instance->ev_serial = pps_i.assert_sequence; + } else { + tsp = &pps_i.clear_timestamp; + + if (debug > 2) { + 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); +#else + printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", + instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec); +#endif + } + + if (pps_i.clear_sequence == j) { + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); + return; + } + instance->ev_serial = pps_i.clear_sequence; + } + + /* convert timespec -> ntp l_fp */ + + dmy = tsp->tv_nsec; + dmy /= 1e9; + ts.l_uf = dmy * 4294967296.0; + ts.l_ui = tsp->tv_sec; +#if 0 + alternate code for previous 4 lines is + dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ + DTOLFP(dmy, &ts); + dmy = tsp->tv_sec; /* integer part */ + DTOLFP(dmy, &ts_tmp); + L_ADD(&ts, &ts_tmp); + or more simply + dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ + DTOLFP(dmy, &ts); + ts.l_ui = tsp->tv_sec; +#endif /* 0 */ +#else +# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV) + j = instance->ev_serial; + if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) { + perror("ONCORE: IOCTL:"); + return; + } + + tsp = &ev.tv; + + if (debug > 2) +#ifdef HAVE_STRUCT_TIMESPEC + printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", + ev.serial, j, tsp->tv_sec, tsp->tv_nsec); +#else + printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", + ev.serial, j, tsp->tv_sec, tsp->tv_usec); +#endif + + if (ev.serial == j) { + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); + return; + } + instance->ev_serial = ev.serial; + + /* convert timeval -> ntp l_fp */ + + TVTOTS(tsp, &ts); +# else +# if defined(TIOCDCDTIMESTAMP) + if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) { + perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)"); + return; + } + tsp = &tv; + TVTOTS(tsp, &ts); +# else +#error "Cannot compile -- no PPS mechanism configured!" +# endif +# endif +#endif + /* now have timestamp in ts */ + /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ + + /* saw_tooth not really necessary if using TIMEVAL */ + /* since its only precise to us, but do it anyway. */ + + /* offset in ns, and is positive (late), we subtract */ + /* to put the PPS time transition back where it belongs */ + +#ifdef HAVE_PPSAPI + /* must hand the offset for the NEXT sec off to the Kernel to do */ + /* the addition, so that the Kernel PLL sees the offset too */ + + if (instance->assert) + instance->pps_p.assert_offset.tv_nsec = -dt2; + else + instance->pps_p.clear_offset.tv_nsec = -dt2; + + /* The following code is necessary, and not just a time_pps_setparams, + * using the saved instance->pps_p, since some other process on the + * machine may have diddled with the mode bits (say adding something + * that it needs). We take what is there and ADD what we need. + * [[ The results from the time_pps_getcap is unlikely to change so + * we could probably just save it, but I choose to do the call ]] + * Unfortunately, there is only ONE set of mode bits in the kernel per + * interface, and not one set for each open handle. + * + * There is still a race condition here where we might mess up someone + * elses mode, but if he is being careful too, he should survive. + */ + + if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { + msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m"); + return; + } + + if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { + msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m"); + return; + } + + /* or current and mine */ + current_params.mode |= instance->pps_p.mode; + /* but only set whats legal */ + current_params.mode &= current_mode; + + current_params.assert_offset.tv_sec = 0; + current_params.assert_offset.tv_nsec = -dt2; + current_params.clear_offset.tv_sec = 0; + current_params.clear_offset.tv_nsec = -dt2; + + if (time_pps_setparams(instance->pps_h, ¤t_params)) + perror("time_pps_setparams"); +#else + /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */ + /* offset for THIS second */ + + dmy = -1.0e-9*dt1; + DTOLFP(dmy, &ts_tmp); + L_ADD(&ts, &ts_tmp); +#endif + /* have time from UNIX origin, convert to NTP origin. */ + + ts.l_ui += JAN_1970; + instance->pp->lastrec = ts; + + /* print out information about this timestamp (long line) */ + + ts_tmp = ts; + ts_tmp.l_ui = 0; /* zero integer part */ + LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ + j = 1.0e9*dmy; /* then to integer ns */ + + Rsm = 0; + if (instance->chan == 6) + Rsm = instance->BEHa[64]; + else if (instance->chan == 8) + Rsm = instance->BEHa[72]; + else if (instance->chan == 12) + Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]); + + if (instance->chan == 6 || instance->chan == 8) { + sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 117 */ + "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %2d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", + ts.l_ui, j, + instance->pp->year, instance->pp->day, + instance->pp->hour, instance->pp->minute, instance->pp->second, + (long) tsp->tv_sec % 60, + Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]), + /*rsat dop */ + instance->BEHa[38], instance->BEHa[39], instance->BEHn[21], + /* nsat visible, nsat tracked, traim */ + instance->BEHn[23]*256+instance->BEHn[24], (s_char) instance->BEHn[25], + /* sigma neg-sawtooth */ + /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53], + instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69] + ); /* will be 0 for 6 chan */ + } else if (instance->chan == 12) { + sprintf(instance->pp->a_lastcode, + "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d%d%d%d%d", + ts.l_ui, j, + instance->pp->year, instance->pp->day, + instance->pp->hour, instance->pp->minute, instance->pp->second, + (long) tsp->tv_sec % 60, + Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]), + /*rsat dop */ + instance->BEHa[55], instance->BEHa[56], instance->BEHn[6], + /* nsat visible, nsat tracked traim */ + instance->BEHn[12]*256+instance->BEHn[13], (s_char) instance->BEHn[14], + /* sigma neg-sawtooth */ + /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76], + instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100], + instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124] + ); + } + + 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); + } + + /* and some things I dont understnd (magic ntp things) */ + + if (!refclock_process(instance->pp)) { + refclock_report(instance->peer, CEVNT_BADTIME); + return; + } + + record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); + instance->pollcnt = 2; + + if (instance->polled) { + instance->polled = 0; +/* + instance->pp->dispersion = instance->pp->skew = 0; +*/ + instance->pp->lastref = instance->pp->lastrec; + refclock_receive(instance->peer); + } +} + + +/*************** oncore_msg_XX routines start here *******************/ + + +/* + * print Oncore response message. + */ + +static void +oncore_msg_any( + struct instance *instance, + u_char *buf, + size_t len, + int idx + ) +{ + int i; + const char *fmt = oncore_messages[idx].fmt; + const char *p; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + struct timeval tv; + + if (debug > 3) { #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 GETTIMEOFDAY(&tv, 0); #endif @@ -1368,433 +1811,570 @@ oncore_msg_any( +/* Latitude, Longitude, Height */ + +static void +oncore_msg_Adef( + struct instance *instance, + u_char *buf, + size_t len + ) +{ +} + + + +/* Mask Angle */ + +static void +oncore_msg_Ag( + struct instance *instance, + u_char *buf, + size_t len + ) +{ char Msg[160], *cp; + + 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); +} + + + /* - * Demultiplex the almanac into shmem + * get Position hold position */ static void -oncore_msg_Cb( +oncore_msg_As( struct instance *instance, u_char *buf, size_t len ) { - int i; + instance->ss_lat = buf_w32(&buf[4]); + instance->ss_long = buf_w32(&buf[8]); + instance->ss_ht = buf_w32(&buf[12]); - if (instance->shmem == NULL) + /* Print out Position */ + oncore_print_posn(instance); +} + + + +/* + * Try to use Oncore UT+ Auto Survey Feature + * If its not there (VP), set flag to do it ourselves. + */ + +static void +oncore_msg_At( + struct instance *instance, + u_char *buf, + 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), + "Initiating hardware 3D site survey"); + + cp = "SSstate = ONCORE_SS_HW"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->site_survey = ONCORE_SS_HW; + } + } +} + + + +/* + * get PPS Offset + * Nb. @@Ay is not supported for early UT (no plus) model + */ + +static void +oncore_msg_Ay( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char Msg[120]; + + if (instance->saw_Ay) return; - if (buf[4] == 5) - i = buf[5]; - else if (buf[4] == 4 && buf[5] <= 5) - i = buf[5] + 24; - else if (buf[4] == 4 && buf[5] <= 10) - i = buf[5] + 23; - else - i = 34; - i *= 36; - instance->shmem[instance->shmem_Cb + i + 2]++; - memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); + instance->saw_Ay = 1; + + instance->offset = buf_w32(&buf[4]); + + sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); + record_clock_stats(&(instance->peer->srcadr), Msg); } /* - * We do an @@Cj twice in the initialization sequence. - * o Once at the very beginning to get the Model number so we know what commands - * we can issue, - * o And once later after we have done a reset and test, (which may hang), - * as we are about to initialize the Oncore and start it running. - * o We have one routine below for each case. + * get Cable Delay */ +static void +oncore_msg_Az( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char Msg[120]; + + if (instance->saw_Az) + return; + + instance->saw_Az = 1; + + instance->delay = buf_w32(&buf[4]); + + sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); + record_clock_stats(&(instance->peer->srcadr), Msg); +} + + + +/* Ba, Ea and Ha come here, these contain Position */ + +static void +oncore_msg_BaEaHa( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + const char *cp; + char Msg[160]; + int mode; + + /* OK, we are close to the RUN state now. + * But we have a few more items to initialize first. + * + * At the beginning of this routine there are several 'timers'. + * We enter this routine 1/sec, and since the upper levels of NTP have usurped + * the use of timers, we use the 1/sec entry to do things that + * we would normally do with timers... + */ + + if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */ + if (buf[2] == 'B') { /* 6chan */ + if (instance->chan_ck < 6) instance->chan_ck = 6; + } else if (buf[2] == 'E') { /* 8chan */ + if (instance->chan_ck < 8) instance->chan_ck = 8; + } else if (buf[2] == 'H') { /* 12chan */ + if (instance->chan_ck < 12) instance->chan_ck = 12; + } + + if (instance->count3++ < 5) + return; + + instance->count3 = 0; + + if (instance->chan_in != -1) /* set in Input */ + instance->chan = instance->chan_in; + 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); + + instance->o_state = ONCORE_HAVE_CHAN; + cp = "state = ONCORE_HAVE_CHAN"; + record_clock_stats(&(instance->peer->srcadr), cp); + + instance->timeout = 4; + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); + return; + } + + if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) + return; + + /* PAUSE 5sec */ + + if (instance->count) { + if (instance->count++ < 5) /* make sure results are stable, using position */ + return; + instance->count = 0; + } + + memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */ + + /* check the antenna and almanac for changes (did it get unplugged, is it ready?) */ + + oncore_check_almanac(instance); + oncore_check_antenna(instance); + + /* Almanac mode, waiting for Almanac, we can't do anything till we have it */ + /* When we have an almanac, we will start the Bn/En/@@Hn messages */ + + if (instance->o_state == ONCORE_ALMANAC) + if (oncore_wait_almanac(instance)) + return; + + /* do some things once when we get this far in BaEaHa */ + + if (instance->once) { + instance->once = 0; + instance->count2 = 1; + + /* Have we seen an @@At (position hold) command response */ + /* 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)); + } + + /* have an Almanac, can start the SiteSurvey + * (actually only need to get past the almanac_load where we diddle with At + * command,- we can't change it after we start the HW_SS below + */ + + mode = instance->init_type; + switch (mode) { + case 0: /* NO initialization, don't change anything */ + 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); + break; + + case 2: + case 4: /* Site Survey */ + cp = "SSstate = ONCORE_SS_TESTING"; + record_clock_stats(&(instance->peer->srcadr), cp); + 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 */ + else + oncore_sendmsg(instance->ttyfd, 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 */ -/* - * Determine the Type from the Model #, this determines #chan and if TRAIM is - * available. We use ONLY the #chans, and determint TRAIM by trying it. - */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); -static void -oncore_msg_Cj( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - memcpy(instance->Cj, buf, len); + /* Read back Cable Delay for Output */ - instance->timeout = 0; - if (instance->o_state == ONCORE_ID_SENT) - oncore_msg_Cj_id(instance, buf, len); - else if (instance->o_state == ONCORE_INIT) - oncore_msg_Cj_init(instance, buf, len); -} + oncore_sendmsg(instance->ttyfd, 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)); + } + + if (instance->count1) { + if (instance->count1++ > 5 || instance->site_survey == ONCORE_SS_HW) { + instance->count1 = 0; + if (instance->site_survey == ONCORE_SS_TESTING) { + /* + * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec + * wait after the @@At2/@@Gd3 command we have not changed the state to + * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then + * the variable would have been changed by now. + * There are three possibilities: + * 6/8chan + * (a) We did not get a response to the @@At0 or @@At2 commands, + * and it must be a GT/GT+/SL with no position hold mode. + * We will have to do it ourselves. + * (b) We saw the @@At0, @@At2 commands, but @@At2 failed, + * must be a VP or older UT which doesn't have Site Survey mode. + * We will have to do it ourselves. + * 12chan + * (c) We saw the @@Gd command, but @@Gd3 failed, + * We will have to do it ourselves. + */ + + sprintf(Msg, "Initiating software 3D site survey (%d samples)", + POS_HOLD_AVERAGE); + record_clock_stats(&(instance->peer->srcadr), Msg); + record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW"); + instance->site_survey = ONCORE_SS_SW; -/* The information on determing a Oncore 'Model', viz VP, UT, etc, from - * the Model Number comes from "Richard M. Hambly" - * and from Motorola. Until recently Rick was the only source of - * this information as Motorola didnt give the information out. - */ + 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 */ + 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 */ + } + } + } + } -static void -oncore_msg_Cj_id( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char *cp, *cp1, *cp2, Model[21], Msg[160]; - int mode; + /* check the mode we are in 0/2/3D */ - /* Write Receiver ID message to clockstats file */ + if (instance->chan == 6) { + if (instance->BEHa[64]&0x8) + instance->mode = MODE_0D; + else if (instance->BEHa[64]&0x10) + instance->mode = MODE_2D; + else if (instance->BEHa[64]&0x20) + instance->mode = MODE_3D; + } else if (instance->chan == 8) { + if (instance->BEHa[72]&0x8) + instance->mode = MODE_0D; + else if (instance->BEHa[72]&0x10) + instance->mode = MODE_2D; + else if (instance->BEHa[72]&0x20) + instance->mode = MODE_3D; + } else if (instance->chan == 12) { + int bits; - 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; + bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ + if (bits == 0x4) + instance->mode = MODE_0D; + else if (bits == 0x6) + instance->mode = MODE_2D; + else if (bits == 0x7) + instance->mode = MODE_3D; } - /* next, the Firmware Version and Revision numbers */ + /* copy the record to the (extra) location in SHMEM */ - instance->version = atoi(&instance->Cj[83]); - instance->revision = atoi(&instance->Cj[111]); + if (instance->shmem) { + int i; + u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */ - /* from model number decide which Oncore this is, - and then the number of channels */ + switch(instance->chan) { + case 6: smp = &instance->shmem[instance->shmem_Ba]; break; + case 8: smp = &instance->shmem[instance->shmem_Ea]; break; + case 12: smp = &instance->shmem[instance->shmem_Ha]; break; + default: smp = (u_char) 0; break; + } - for (cp=&instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ - ; - cp1 = cp; - cp2 = Model; - for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++) - *cp2 = *cp; - *cp2 = '\0'; + switch (instance->mode) { + case MODE_0D: i = 1; break; /* 0D, Position Hold */ + case MODE_2D: i = 2; break; /* 2D, Altitude Hold */ + case MODE_3D: i = 3; break; /* 3D fix */ + default: i = 0; break; + } - cp = 0; - if (!strncmp(Model, "PVT6", (size_t) 4)) { - cp = "PVT6"; - instance->model = ONCORE_PVT6; - } else if (Model[0] == 'A') { - cp = "Basic"; - instance->model = ONCORE_BASIC; - } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { - cp = "VP"; - instance->model = ONCORE_VP; - } else if (!strncmp(Model, "P1", (size_t) 2)) { - cp = "M12"; - instance->model = ONCORE_M12; - } else if (Model[0] == 'R') { - if (Model[5] == 'N') { - cp = "GT"; - instance->model = ONCORE_GT; - } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { - cp = "GT+"; - instance->model = ONCORE_GTPLUS; - } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { - cp = "UT"; - instance->model = ONCORE_UT; - } else if (Model[1] == '5' && Model[5] == 'G') { - cp = "UT+"; - instance->model = ONCORE_UTPLUS; - } else if (Model[1] == '6' && Model[5] == 'G') { - cp = "SL"; - instance->model = ONCORE_SL; - } else { - cp = "Unknown"; - instance->model = ONCORE_UNKNOWN; + if (i) { + i *= (len+6); + smp[i + 2]++; + memcpy(&smp[i+3], buf, (size_t) (len+3)); } - } else { - cp = "Unknown"; - instance->model = ONCORE_UNKNOWN; } - 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); - - if (instance->chan == 0) { /* dont reset if set in input data */ - instance->chan = 8; /* default */ - if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) - instance->chan = 6; - else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) - instance->chan = 8; - else if (instance->model == ONCORE_M12) - instance->chan = 12; - } + /* + * check if timer active + * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond + */ - if (instance->traim == -1) { /* dont reset if set in input data */ - instance->traim = 0; /* default */ - if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) - instance->traim = 0; - else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) - instance->traim = 1; - else if (instance->model == ONCORE_M12) + if (instance->traim_delay) { + if (instance->traim_delay++ > 5) { instance->traim = 0; + instance->traim_delay = 0; + cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; + record_clock_stats(&(instance->peer->srcadr), cp); + + oncore_set_traim(instance); + } else + return; + } - sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan, - ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF"))); - record_clock_stats(&(instance->peer->srcadr), Msg); + /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */ - /* The M12 with 1.3 Firmware, looses track of all Satellites and has to - * start again if we go from 0D -> 3D, then looses them again when we - * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. - * For NOW we have SHMEM turned off for the M12, v1.3 + if (!instance->have_dH && !instance->traim_delay) + oncore_compute_dH(instance); + + /* + * must be ONCORE_RUN if we are here. + * Have # chan and TRAIM by now. */ -/*BAD M12*/ if (instance->model == ONCORE_M12 && instance->version == 1 && instance->revision <= 3) { - instance->shmem_fname = 0; - cp = "*** SHMEM turned off for ONCORE M12 ***"; - record_clock_stats(&(instance->peer->srcadr), cp); - } + instance->pp->year = buf[6]*256+buf[7]; + instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); + instance->pp->hour = buf[8]; + instance->pp->minute = buf[9]; + instance->pp->second = buf[10]; /* - * we now know model number and have zeroed - * instance->shmem_fname if SHMEM is not supported + * Are we doing a Hardware or Software Site Survey? */ - if (instance->shmem_fname); - oncore_init_shmem(instance); + if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW) + oncore_ss(instance); - if (instance->shmem) - cp = "SHMEM is available"; - else - cp = "SHMEM is NOT available"; - record_clock_stats(&(instance->peer->srcadr), cp); + /* see if we ever saw a response from the @@Ayx above */ -#ifdef HAVE_PPSAPI - if (instance->assert) - cp = "Timing on Assert."; - else - cp = "Timing on Clear."; - record_clock_stats(&(instance->peer->srcadr), cp); -#endif + if (instance->count2) { + if (instance->count2++ > 5) { /* this delay to check on @@Ay command */ + instance->count2 = 0; - mode = instance->init_type; - if (mode == 3 || mode == 4) { /* Cf will call Fa */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); - instance->o_state = ONCORE_RESET_SENT; - cp = "state = ONCORE_RESET_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } else { - if (instance->chan == 6) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); - else if (instance->chan == 8) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); - else if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); + /* Have we seen an Ay (1PPS time offset) command response */ + /* if not, and non-zero offset, zero the offset, and send message */ - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->timeout = 4; + if (!instance->saw_Ay && instance->offset) { + cp = "No @@Ay command, PPS OFFSET ignored"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->offset = 0; + } + } } + + /* + * Check the leap second status once per day. + */ + + oncore_check_leap_sec(instance); + + /* + * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. + */ + + if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) + oncore_shmem_get_3D(instance); + + if (!instance->traim) /* NO traim, no BnEnHn, go get tick */ + oncore_get_timestamp(instance, instance->offset, instance->offset); } +/* Almanac Status */ + static void -oncore_msg_Cj_init( +oncore_msg_Bd( struct instance *instance, u_char *buf, size_t len ) { - char *cp, Cmd[20], Msg[160]; - int mode; + char Msg[160]; - /* OK, know type of Oncore, have possibly reset, and have tested. - * If we have or don't have TRAIM and position hold may still be unknown. - * Now initialize. - */ - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem */ - - /* Turn OFF position hold, it needs to be off to set position (for some units), - will get set ON in @@Ea later */ - - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); - else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); - } - - mode = instance->init_type; - if (debug) { - printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode); - printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan); - } + 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); +} - /* If there is Position input in the Config file - * and mode = (1,3) set it as posn hold posn, goto 0D mode. - * or mode = (2,4) set it as INITIAL position, and do Site Survey. - */ - if (instance->posn_set) { - switch (mode) { /* if we have a position, put it in as posn and posn-hold posn */ - case 0: - break; - case 1: - case 2: - case 3: - case 4: - memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As)); /* dont modify static variables */ - w32_buf(&Cmd[2], (int) instance->ss_lat); - w32_buf(&Cmd[6], (int) instance->ss_long); - w32_buf(&Cmd[10], (int) instance->ss_ht); - Cmd[14] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); - - memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au)); - w32_buf(&Cmd[2], (int) instance->ss_ht); - Cmd[6] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); - - if (instance->chan == 12) { - memcpy(Cmd, oncore_cmd_Ga, sizeof(oncore_cmd_Ga)); - w32_buf(&Cmd[2], (int) instance->ss_lat); - w32_buf(&Cmd[6], (int) instance->ss_long); - w32_buf(&Cmd[10], (int) instance->ss_ht); - Cmd[14] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); - } else { - memcpy(Cmd, oncore_cmd_Ad, sizeof(oncore_cmd_Ad)); - w32_buf(&Cmd[2], (int) instance->ss_lat); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); - - memcpy(Cmd, oncore_cmd_Ae, sizeof(oncore_cmd_Ae)); - w32_buf(&Cmd[2], (int) instance->ss_long); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); - - memcpy(Cmd, oncore_cmd_Af, sizeof(oncore_cmd_Af)); - w32_buf(&Cmd[2], (int) instance->ss_ht); - Cmd[6] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); - } - break; - } - } +/* get leap-second warning message */ +/* + * @@Bj does NOT behave as documented in current Oncore firmware. + * It turns on the LEAP indicator when the data is set, and does not, + * as documented, wait until the beginning of the month when the + * leap second will occur. + * Since this firmware bug will never be fixed in all the outstanding Oncore receivers + * @@Bj is only called in June/December. + */ - switch (mode) { - case 0: /* NO initialization, don't change anything */ - instance->site_survey = ONCORE_SS_DONE; - break; +static void +oncore_msg_Bj( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + const char *cp; + switch(buf[4]) { case 1: - case 3: /* Use given Position */ - instance->site_survey = ONCORE_SS_DONE; + instance->peer->leap = LEAP_ADDSECOND; + cp = "Set peer.leap to LEAP_ADDSECOND"; break; - case 2: - case 4: /* Site Survey */ - if (instance->chan == 12) { /* no 12chan site survey command */ - instance->site_survey = ONCORE_SS_SW; - sprintf(Msg, "Initiating software 3D site survey (%d samples)", POS_HOLD_AVERAGE); - record_clock_stats(&(instance->peer->srcadr), Msg); - } else { - instance->site_survey = ONCORE_SS_TESTING; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); - } - break; - } - - if (mode != 0) { - /* cable delay in ns */ - memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az)); - w32_buf(&Cmd[2], instance->delay); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); - - /* PPS offset in ns */ - if (instance->offset) { - if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || - instance->model == ONCORE_UTPLUS) { - memcpy(Cmd, oncore_cmd_Ay, sizeof(oncore_cmd_Ay)); - w32_buf(&Cmd[2], instance->offset); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay)); - } else { - cp = "Can only set PPS OFFSET for VP/UT/UT+, offset ignored"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->offset = 0; - } - } - } - - /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s */ - /* now we're really running */ - - if (instance->chan == 6) { /* kill 8 chan commands, possibly testing VP in 6chan mode */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); - } else if (instance->chan == 8) { /* kill 6chan commands */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); - } else if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); - - instance->count = 1; - instance->o_state = ONCORE_ALMANAC; - cp = "state = ONCORE_ALMANAC"; + instance->peer->leap = LEAP_DELSECOND; + cp = "Set peer.leap to LEAP_DELSECOND"; + break; + case 0: + default: + instance->peer->leap = LEAP_NOWARNING; + cp = "Set peer.leap to LEAP_NOWARNING"; + break; + } record_clock_stats(&(instance->peer->srcadr), cp); } -/* - * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup - * not so for VP (eeprom) or any unit with a battery - */ - static void -oncore_msg_Cf( +oncore_msg_BnEnHn( struct instance *instance, u_char *buf, - size_t len + size_t len ) { - const char *cp; + long dt1, dt2; + char *cp; - if (instance->o_state == ONCORE_RESET_SENT) { - if (instance->chan == 6) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); - else if (instance->chan == 8) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); - else if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); + if (instance->o_state != ONCORE_RUN) + return; - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); + 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_set_traim(instance); + } + + memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ + + /* If Time RAIM doesn't like it, don't trust it */ + + if (buf[2] == 'H') { + if (instance->BEHn[6]) /* bad TRAIM */ + return; + + dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ + instance->saw_tooth = (s_char) instance->BEHn[10]; /* update for next time Hn[10] */ + dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ + } else { + if (instance->BEHn[21]) /* bad TRAIM */ + return; + + dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ + instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time */ + dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ } + + oncore_get_timestamp(instance, dt1, dt2); } /* Here for @@Ca, @@Fa and @@Ia messages */ -/* There are good reasons NOT to do a @@Ca or @@Fa command with the ONCORE. - * Doing it, it was found that under some circumstances the following +/* These are Self test Commands for 6, 8, and 12 chan receivers. + * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. + * It was found that under some circumstances the following * command would fail if issued immediately after the return from the * @@Fa, but a 2sec delay seemed to fix things. Since simply calling - * sleep(2) is wastefull, and may cause trouble for some OS's, repeating - * itimer, we set a flag, and test it at the next POLL. If it hasnt + * sleep(2) is wasteful, and may cause trouble for some OS's, repeating + * itimer, we set a flag, and test it at the next POLL. If it hasn't * been cleared, we reissue the @@Cj that is issued below. * Note that we do a @@Cj at the beginning, and again here. * The first is to get the info, the 2nd is just used as a safe command @@ -1810,9 +2390,10 @@ oncore_msg_CaFaIa( ) { char *cp; + int i; if (instance->o_state == ONCORE_TEST_SENT) { - int antenna; + enum antenna_state antenna; instance->timeout = 0; @@ -1823,867 +2404,973 @@ oncore_msg_CaFaIa( printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]); } - antenna = buf[4] & 0xc0; - antenna >>= 6; + antenna = (buf[4] & 0xc0) >> 6; buf[4] &= ~0xc0; - if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) { - cp = "ONCORE: Self Test Failed, shutting down driver"; - record_clock_stats(&(instance->peer->srcadr), cp); + 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); + + refclock_report(instance->peer, CEVNT_FAULT); oncore_shutdown(instance->unit, instance->peer); return; } - if (antenna) { - char *cp1, Msg[160]; - cp1 = (antenna == 0x1) ? "(Over Current)" : - ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)"); + /* report the current antenna state */ - cp = "ONCORE: Self Test, NonFatal Antenna Problems "; - strcpy(Msg, cp); - strcat(Msg, cp1); - record_clock_stats(&(instance->peer->srcadr), Msg); - } + oncore_antenna_report(instance, antenna); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); instance->o_state = ONCORE_INIT; cp = "state = ONCORE_INIT"; record_clock_stats(&(instance->peer->srcadr), cp); + + instance->timeout = 4; + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); } } -/* Ba, Ea and Ha come here */ +/* + * Demultiplex the almanac into shmem + */ static void -oncore_msg_BaEaHa( +oncore_msg_Cb( struct instance *instance, u_char *buf, size_t len ) { - const char *cp; - char Msg[160], Cmd[20]; - u_char *vp; /* pointer to start of shared mem for Ba/Ea/Ha */ - size_t Len; + int i; - /* At the beginning of Ea here there are various 'timers'. - * We enter Ea 1/sec, and since the upper levels of NTP have usurped - * the use of timers, we use the 1/sec entry to Ea to do things that - * we would normally do with timers... - */ + if (instance->shmem == NULL) + return; - if (instance->count) { - if (instance->count++ < 5) /* make sure results are stable, using position */ - return; - instance->count = 0; - } + if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) + i = buf[5]; + else if (buf[4] == 4 && buf[5] <= 5) + i = buf[5] + 24; + else if (buf[4] == 4 && buf[5] <= 10) + i = buf[5] + 23; + else if (buf[4] == 4 && buf[5] == 25) + i = 34; + else { + char *cp; - if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) + cp = "Cb: Response is NO ALMANAC"; + record_clock_stats(&(instance->peer->srcadr), cp); return; + } - Len = len+3; /* message length @@ -> CR,LF */ - memcpy(instance->Ea, buf, Len); /* Ba, Ea or Ha */ - - if (buf[2] == 'B') { /* 6chan */ - if (instance->Ea[64]&0x8) - instance->mode = MODE_0D; - else if (instance->Ea[64]&0x10) - instance->mode = MODE_2D; - else if (instance->Ea[64]&0x20) - instance->mode = MODE_3D; - } else if (buf[2] == 'E') { /* 8chan */ - if (instance->Ea[72]&0x8) - instance->mode = MODE_0D; - else if (instance->Ea[72]&0x10) - instance->mode = MODE_2D; - else if (instance->Ea[72]&0x20) - instance->mode = MODE_3D; - } else if (buf[2] == 'H') { /* 12chan */ - int bits; + i *= 36; + instance->shmem[instance->shmem_Cb + i + 2]++; + memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); - bits = (instance->Ea[129]>>5) & 0x7; /* actually Ha */ - if (bits == 0x4) - instance->mode = MODE_0D; - else if (bits == 0x6) - instance->mode = MODE_2D; - else if (bits == 0x7) - instance->mode = MODE_3D; +#if 1 + { + char Msg[160]; + sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]); + record_clock_stats(&(instance->peer->srcadr), Msg); } +#endif +} - vp = (u_char) 0; /* just to keep compiler happy */ - if (instance->chan == 6) { - instance->rsm.bad_almanac = instance->Ea[64]&0x1; - instance->rsm.bad_fix = instance->Ea[64]&0x52; - vp = &instance->shmem[instance->shmem_Ba]; - } else if (instance->chan == 8) { - instance->rsm.bad_almanac = instance->Ea[72]&0x1; - instance->rsm.bad_fix = instance->Ea[72]&0x52; - vp = &instance->shmem[instance->shmem_Ea]; - } else if (instance->chan == 12) { - int bits1, bits2; - bits1 = (instance->Ea[129]>>5) & 0x7; /* actually Ha */ - bits2 = instance->Ea[130]; - instance->rsm.bad_almanac = (bits2 & 0x80); - instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); - /* too few sat Bad Geom */ - vp = &instance->shmem[instance->shmem_Ha]; -#if 0 -fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n", - instance->Ea[129], instance->Ea[130], bits1, bits2, instance->mode == MODE_0D, instance->mode == MODE_2D, - instance->mode == MODE_3D, instance->rsm.bad_almanac, instance->rsm.bad_fix); -#endif + +/* + * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup + * not so for VP (eeprom) or any unit with a battery + */ + +static void +oncore_msg_Cf( + struct instance *instance, + u_char *buf, + 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 */ + /* Reset set VP to IDLE */ + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); } +} - /* Here calculate dH = GPS - MSL for output message */ - /* also set Altitude Hold mode if GT */ - if (!instance->have_dH) { - int GPS, MSL; - instance->have_dH++; - if (instance->chan == 12) { - GPS = buf_w32(&instance->Ea[39]); - MSL = buf_w32(&instance->Ea[43]); - } else { - GPS = buf_w32(&instance->Ea[23]); - MSL = buf_w32(&instance->Ea[27]); - } - instance->dH = GPS - MSL; - instance->dH /= 100.; +/* + * This is the Grand Central Station for the Preliminary Initialization. + * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. + * + * We do an @@Cj whenever we need a safe command for all Oncores. + * The @@Cj gets us back here where we can switch to the next phase of setup. + * + * o Once at the very beginning (in start) to get the Model number. + * This info is printed, but no longer used. + * o Again after we have determined the number of Channels in the receiver. + * o And once later after we have done a reset and test, (which may hang), + * as we are about to initialize the Oncore and start it running. + * o We have one routine below for each case. + */ - if (MSL) { /* not set ! */ - sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH); - record_clock_stats(&(instance->peer->srcadr), Msg); - } +static void +oncore_msg_Cj( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + int mode; + char *cp; - /* stuck in here as it only gets done once */ + memcpy(instance->Cj, buf, len); - if (instance->chan != 12 && !instance->saw_At) { - cp = "Not Good, no @@At command, must be a GT/GT+"; + instance->timeout = 0; + if (instance->o_state == ONCORE_CHECK_ID) { + oncore_msg_Cj_id(instance, buf, len); + oncore_chan_test(instance); + } else if (instance->o_state == ONCORE_HAVE_CHAN) { + 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)); + } else { + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; record_clock_stats(&(instance->peer->srcadr), cp); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); } } - /* - * For instance->site_survey to be ONCORE_SS_TESTING, this must be the first - * time thru @@Ea. There are two choices - * (a) We did not get a response to the @@At0 or @@At2 commands, - * must be a GT/GT+/SL with no position hold mode. - * (b) Saw the @@At0, @@At2 commands, but @@At2 failed, - * must be a VP or older UT which doesnt have Site Survey mode. - * We will have to do it ourselves. - */ + if (instance->o_state == ONCORE_TEST_SENT) { + if (instance->chan == 6) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); + else if (instance->chan == 8) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); + else if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); + } else if (instance->o_state == ONCORE_INIT) + oncore_msg_Cj_init(instance, buf, len); +} - if (instance->site_survey == ONCORE_SS_TESTING) { /* first time thru Ea */ - sprintf(Msg, "Initiating software 3D site survey (%d samples)", - POS_HOLD_AVERAGE); - record_clock_stats(&(instance->peer->srcadr), Msg); - instance->site_survey = ONCORE_SS_SW; - instance->ss_lat = instance->ss_long = instance->ss_ht = 0; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ + +/* The information on determining a Oncore 'Model', viz VP, UT, etc, from + * the Model Number comes from "Richard M. Hambly" + * and from Motorola. Until recently Rick was the only source of + * this information as Motorola didn't give the information out. + * + * Determine the Type from the Model #, this determines #chan and if TRAIM is + * available. + * + * The Information from this routine is NO LONGER USED. + * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED + */ + +static void +oncore_msg_Cj_id( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char *cp, *cp1, *cp2, Model[21], Msg[160]; + + /* 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; + } + + /* next, the Firmware Version and Revision numbers */ + + instance->version = atoi(&instance->Cj[83]); + instance->revision = atoi(&instance->Cj[111]); + + /* from model number decide which Oncore this is, + and then the number of channels */ + + for (cp=&instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ + ; + cp1 = cp; + cp2 = Model; + for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++) + *cp2 = *cp; + *cp2 = '\0'; + + cp = 0; + if (!strncmp(Model, "PVT6", (size_t) 4)) { + cp = "PVT6"; + instance->model = ONCORE_PVT6; + } else if (Model[0] == 'A') { + cp = "Basic"; + instance->model = ONCORE_BASIC; + } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { + cp = "VP"; + instance->model = ONCORE_VP; + } else if (Model[0] == 'P') { + cp = "M12"; + instance->model = ONCORE_M12; + } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { + if (Model[5] == 'N') { + cp = "GT"; + instance->model = ONCORE_GT; + } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { + cp = "GT+"; + instance->model = ONCORE_GTPLUS; + } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { + cp = "UT"; + instance->model = ONCORE_UT; + } else if (Model[1] == '5' && Model[5] == 'G') { + cp = "UT+"; + instance->model = ONCORE_UTPLUS; + } else if (Model[1] == '6' && Model[5] == 'G') { + cp = "SL"; + instance->model = ONCORE_SL; + } else { + cp = "Unknown"; + instance->model = ONCORE_UNKNOWN; + } + } else { + cp = "Unknown"; + instance->model = ONCORE_UNKNOWN; } - if (instance->shmem) { - int i; + /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ - i = 0; - if (instance->mode == MODE_0D) /* 0D, Position Hold */ - i = 1; - else if (instance->mode == MODE_2D) /* 2D, Altitude Hold */ - i = 2; - else if (instance->mode == MODE_3D) /* 3D fix */ - i = 3; - if (i) { - i *= (Len+3); - vp[i + 2]++; - memcpy(&vp[i+3], buf, Len); - } - } + 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); - /* Almanac mode, waiting for Almanac, cant do anything till we have it */ - /* When we have an almanac, start the En/Bn messages */ + instance->chan_id = 8; /* default */ + if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) + instance->chan_id = 6; + else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) + instance->chan_id = 8; + else if (instance->model == ONCORE_M12) + instance->chan_id = 12; + + instance->traim_id = 0; /* default */ + if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) + instance->traim_id = 0; + else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) + instance->traim_id = 1; + 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); +} - if (instance->o_state == ONCORE_ALMANAC) { - if (instance->rsm.bad_almanac) { - if (debug) - printf("ONCORE: waiting for almanac\n"); - return; - } else { /* Here we have almanac. - Start TRAIM (@@En/@@Bn) dependant on TRAIM flag. - If flag == -1, then we dont know if this unit supports - traim, and we issue the command and then wait up to - 5sec to see if we get a reply */ - - if (instance->traim != 0) { /* either yes or unknown */ - if (instance->chan == 6) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); - else if (instance->chan == 8) - oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En)); - - if (instance->traim == -1) - instance->traim_delay = 1; - } - instance->o_state = ONCORE_RUN; - cp = "state = ONCORE_RUN"; - record_clock_stats(&(instance->peer->srcadr), cp); - } - } - /* - * check if timer active - * if it hasnt been cleared, then @@En/@@Bn did not respond - */ - if (instance->traim_delay) { - if (instance->traim_delay++ > 5) { - instance->traim = 0; - instance->traim_delay = 0; - cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; - record_clock_stats(&(instance->peer->srcadr), cp); - } - } +/* OK, know type of Oncore, have possibly reset it, and have tested it. + * We know the number of channels. + * We will determine whether we have TRAIM before we actually start. + * Now initialize. + */ - /* - * must be ONCORE_RUN if we are here. - */ +static void +oncore_msg_Cj_init( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char *cp, Cmd[20], Msg[160]; + int mode; - instance->pp->year = buf[6]*256+buf[7]; - instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); - instance->pp->hour = buf[8]; - instance->pp->minute = buf[9]; - instance->pp->second = buf[10]; - /* - * Check to see if Hardware SiteSurvey has Finished. + /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to + * start again if we go from 0D -> 3D, then loses them again when we + * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. + * For NOW we will turn this aspect of filling SHMEM off for the M12 */ - if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) { - record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); - instance->site_survey = ONCORE_SS_DONE; + 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); } - if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { - instance->printed = 1; - /* Read back Position Hold Params (cant for GT) */ - if (instance->saw_At) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); - else - oncore_print_As(instance); - - /* 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->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 */ - /* Read back Cable Delay for Output */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); - } + mode = instance->init_type; - /* - * Check the leap second status once per day. + /* If there is Position input in the Config file + * and mode = (1,3) set it as posn hold posn, goto 0D mode. + * or mode = (2,4) set it as INITIAL position, and do Site Survey. */ - if (instance->Bj_day != buf[5]) { /* do this 1/day */ - instance->Bj_day = buf[5]; + if (instance->posn_set) { + record_clock_stats(&(instance->peer->srcadr), "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)); - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); - else { - /* - * The following additional check, checking for June/December, is a - * workaround for incorrect ONCORE firmware. The oncore starts - * reporting the leap second when the GPS satellite data message - * (page 18, subframe 4) is updated to a date in the future, which - * can be several months before the leap second. WWV and other - * services seem to wait until the month of the event to turn - * on their indicators (which is usually a single bit). - */ - - if ((buf[4] == 6) || (buf[4] == 12)) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); + 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 */ + + /* 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)); + } + + /* 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)); } } - /* - * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. + /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s + * now we're really running + * these were ALL started in the chan test, + * However, if we had mode=3,4 then commands got turned off, so we turn + * them on again here just in case */ - if (instance->shmem && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) { /* dont screw up the SS by changing mode */ - if (instance->pp->second%15 == 3) { /* start the sequence */ - 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 */ - else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ - } else { - if (instance->saw_At) { - oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* out of 0D to 3D mode */ - if (instance->shmem_Posn == 2) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); /* 3D to 2D mode */ - } else - oncore_sendmsg(instance->ttyfd, 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 */ - else { - if (instance->saw_At) { - if (instance->mode == MODE_2D) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* 2D -> 3D or 0D */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ - } else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); - } - } + 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 )); + } 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 )); + } 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 )); } - if (instance->traim == 0) /* NO traim, go get tick */ - oncore_get_timestamp(instance, instance->offset, instance->offset); + instance->count = 1; + instance->o_state = ONCORE_ALMANAC; + cp = "state = ONCORE_ALMANAC"; + record_clock_stats(&(instance->peer->srcadr), cp); +} - if (instance->site_survey != ONCORE_SS_SW) - return; - /* - * We have to average our own position for the Position Hold Mode - * We use Heights from the GPS ellipsoid. - */ - if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ - return; +/* 12chan position */ - if (instance->mode != MODE_3D) /* Only 3D Fix */ - return; +static void +oncore_msg_Ga( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char Msg[160]; + long lat, lon, ht; + double Lat, Lon, Ht; - instance->ss_lat += buf_w32(&instance->Ea[15]); - instance->ss_long += buf_w32(&instance->Ea[19]); - instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipsoid */ - instance->ss_count++; - if (instance->ss_count != POS_HOLD_AVERAGE) - return; + lat = buf_w32(&buf[4]); + lon = buf_w32(&buf[8]); + ht = buf_w32(&buf[12]); /* GPS ellipsoid */ - instance->ss_lat /= POS_HOLD_AVERAGE; - instance->ss_long /= POS_HOLD_AVERAGE; - instance->ss_ht /= POS_HOLD_AVERAGE; + Lat = lat; + Lon = lon; + Ht = ht; - sprintf(Msg, "Surveyed posn: lat %.3f long %.3f ht %.3f", - instance->ss_lat, instance->ss_long, instance->ss_ht); + Lat /= 3600000; + Lon /= 3600000; + Ht /= 100; + + + sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht); record_clock_stats(&(instance->peer->srcadr), Msg); - /* set newly determined position as 3D Position hold position */ + instance->ss_lat = lat; + instance->ss_long = lon; + instance->ss_ht = ht; - memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As)); - w32_buf(&Cmd[2], (int) instance->ss_lat); - w32_buf(&Cmd[6], (int) instance->ss_long); - w32_buf(&Cmd[10], (int) instance->ss_ht); - Cmd[14] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); + oncore_print_posn(instance); +} - /* set height seperately for 2D */ - memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au)); - w32_buf(&Cmd[2], (int) instance->ss_ht); - Cmd[6] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); - /* and set Position Hold */ +/* 12 chan time/date */ - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); - else { - if (instance->saw_At) - oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); - else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); - } +static void +oncore_msg_Gb( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char Msg[160], *gmts; + int mo, d, y, h, m, s, gmth, gmtm; - record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); - instance->site_survey = ONCORE_SS_DONE; + mo = buf[4]; + d = buf[5]; + y = 256*buf[6]+buf[7]; + + h = buf[8]; + m = buf[9]; + s = buf[10]; + + gmts = ((buf[11] == 0) ? "+" : "-"); + 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); } +/* + * Try to use Oncore M12+Timing Auto Survey Feature + * If its not there (M12), set flag to do it ourselves. + */ + static void -oncore_msg_BnEn( +oncore_msg_Gd( struct instance *instance, u_char *buf, size_t len ) { - long dt1, dt2; char *cp; - if (instance->o_state != ONCORE_RUN) - return; + if (instance->site_survey == ONCORE_SS_TESTING) { + if (buf[4] == 3) { + record_clock_stats(&(instance->peer->srcadr), + "Initiating hardware 3D site survey"); - if (instance->traim_delay) { /* flag that @@En/@@Bn returned */ - instance->traim = 1; - instance->traim_delay = 0; - cp = "ONCORE: Detected TRAIM, TRAIM = ON"; + cp = "SSstate = ONCORE_SS_HW"; record_clock_stats(&(instance->peer->srcadr), cp); + instance->site_survey = ONCORE_SS_HW; + } } - - memcpy(instance->En, buf, len); /* En or Bn */ - - /* If Time RAIM doesn't like it, don't trust it */ - - if (instance->En[21]) - return; - - dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ - instance->saw_tooth = (s_char) instance->En[25]; /* update for next time */ - dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ - - oncore_get_timestamp(instance, dt1, dt2); } +/* Leap Second for M12, gives all info from satellite message */ +/* also in UT v3.0 */ + static void -oncore_get_timestamp( +oncore_msg_Gj( struct instance *instance, - long dt1, /* tick offset THIS time step */ - long dt2 /* tick offset NEXT time step */ + u_char *buf, + size_t len ) { - int Rsm; - u_long i, j; - l_fp ts, ts_tmp; - double dmy; -#ifdef HAVE_STRUCT_TIMESPEC - struct timespec *tsp = 0; -#else - struct timeval *tsp = 0; -#endif -#ifdef HAVE_PPSAPI - int current_mode; - pps_params_t current_params; - struct timespec timeout; - pps_info_t pps_i; -#else /* ! HAVE_PPSAPI */ -#ifdef HAVE_CIOGETEV - struct ppsclockev ev; - int r = CIOGETEV; -#endif -#ifdef HAVE_TIOCGPPSEV - struct ppsclockev ev; - int r = TIOCGPPSEV; -#endif -#if TIOCDCDTIMESTAMP - struct timeval tv; -#endif -#endif /* ! HAVE_PPS_API */ - - if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) - return; - - /* Don't do anything without an almanac to define the GPS->UTC delta */ + int dt; + char Msg[160], *cp; - if (instance->rsm.bad_almanac) - return; + instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ -#ifdef HAVE_PPSAPI - j = instance->ev_serial; - timeout.tv_sec = 0; - 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"); - return; - } + /* print the message to verify whats there */ - if (instance->assert) { - tsp = &pps_i.assert_timestamp; + dt = buf[5] - buf[4]; - if (debug > 2) { - 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); -#else - printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", - instance->unit, i, j, - (long)tsp->tv_sec, (long)tsp->tv_usec); +#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]], 256*buf[6]+buf[7], + buf[15], buf[16], buf[17]); + record_clock_stats(&(instance->peer->srcadr), Msg); + } - if (pps_i.assert_sequence == j) { - printf("ONCORE: oncore_get_timestamp, error serial pps\n"); - return; - } - instance->ev_serial = pps_i.assert_sequence; - } else { - tsp = &pps_i.clear_timestamp; + /* Only raise warning within a month of the leap second */ - if (debug > 2) { - 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); -#else - printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", - instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec); -#endif - } + instance->peer->leap = LEAP_NOWARNING; + cp = "Set peer.leap to LEAP_NOWARNING"; - if (pps_i.clear_sequence == j) { - printf("ONCORE: oncore_get_timestamp, error serial pps\n"); - return; + if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ + buf[8] == instance->BEHa[4]) { /* month */ + if (dt) { + if (dt < 0) { + instance->peer->leap = LEAP_DELSECOND; + cp = "Set peer.leap to LEAP_DELSECOND"; + } else { + instance->peer->leap = LEAP_ADDSECOND; + cp = "Set peer.leap to LEAP_ADDSECOND"; + } } - instance->ev_serial = pps_i.clear_sequence; } + record_clock_stats(&(instance->peer->srcadr), cp); +} - /* convert timespec -> ntp l_fp */ - dmy = tsp->tv_nsec; - dmy /= 1e9; - ts.l_uf = dmy * 4294967296.0; - ts.l_ui = tsp->tv_sec; -#if 0 - alternate code for previous 4 lines is - dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ - DTOLFP(dmy, &ts); - dmy = tsp->tv_sec; /* integer part */ - DTOLFP(dmy, &ts_tmp); - L_ADD(&ts, &ts_tmp); - or more simply - dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ - DTOLFP(dmy, &ts); - ts.l_ui = tsp->tv_sec; -#endif /* 0 */ -#else -# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV) - j = instance->ev_serial; - if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) { - perror("ONCORE: IOCTL:"); - return; - } - tsp = &ev.tv; +/* Power on failure */ - if (debug > 2) -#ifdef HAVE_STRUCT_TIMESPEC - printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", - ev.serial, j, tsp->tv_sec, tsp->tv_nsec); -#else - printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", - ev.serial, j, tsp->tv_sec, tsp->tv_usec); -#endif +static void +oncore_msg_Sz( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + const char *cp; - if (ev.serial == j) { - printf("ONCORE: oncore_get_timestamp, error serial pps\n"); - return; + cp = "Oncore: System Failure at Power On"; + if (instance && instance->peer) { + record_clock_stats(&(instance->peer->srcadr), cp); + oncore_shutdown(instance->unit, instance->peer); } - instance->ev_serial = ev.serial; +} - /* convert timeval -> ntp l_fp */ +/************** Small Subroutines ***************/ - TVTOTS(tsp, &ts); -# else -# if defined(TIOCDCDTIMESTAMP) - if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) { - perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)"); + +static void +oncore_antenna_report( + struct instance *instance, + enum antenna_state new_state) +{ + char *cp; + + if (instance->ant_state == new_state) return; + + switch (new_state) { + case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; + case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; + case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; + case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; + default: cp = "GPS antenna: ?"; break; } - tsp = &tv; - TVTOTS(tsp, &ts); -# else -#error "Cannot compile -- no PPS mechanism configured!" -# endif -# endif -#endif - /* now have timestamp in ts */ - /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ - /* saw_tooth not really necessary if using TIMEVAL */ - /* since its only precise to us, but do it anyway. */ + instance->ant_state = new_state; + record_clock_stats(&instance->peer->srcadr, cp); +} - /* offset in ns, and is positive (late), we subtract */ - /* to put the PPS time transition back where it belongs */ -#ifdef HAVE_PPSAPI - /* must hand the offset for the NEXT sec off to the Kernel to do */ - /* the addition, so that the Kernel PLL sees the offset too */ - if (instance->assert) - instance->pps_p.assert_offset.tv_nsec = -dt2; - else - instance->pps_p.clear_offset.tv_nsec = -dt2; +static void +oncore_chan_test( + struct instance *instance + ) +{ + char *cp; - /* The following code is necessary, and not just a time_pps_setparams, - * using the saved instance->pps_p, since some other process on the - * machine may have diddled with the mode bits (say adding something - * that it needs). We take what is there and ADD what we need. - * [[ The results from the time_pps_getcap is unlikely to change so - * we could probably just save it, but I choose to do the call ]] - * Unfortunately, there is only ONE set of mode bits in the kernel per - * interface, and not one set for each open handle. + /* 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 + * trying a 6, 8, and 12 chan command, and see which responds. + * Caution: more than one CAN respond. * - * There is still a race condition here where we might mess up someone - * elses mode, but if he is being careful too, he should survive. + * This #chan is used by the code rather than that calculated from the model number. */ - if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_getcap failed: %m"); - return; - } - - if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_getparams failed: %m"); - return; - } + instance->o_state = ONCORE_CHECK_CHAN; + cp = "state = ONCORE_CHECK_CHAN"; + record_clock_stats(&(instance->peer->srcadr), cp); - /* or current and mine */ - current_params.mode |= instance->pps_p.mode; - /* but only set whats legal */ - current_params.mode &= current_mode; + 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)); +} - current_params.assert_offset.tv_sec = 0; - current_params.assert_offset.tv_nsec = -dt2; - current_params.clear_offset.tv_sec = 0; - current_params.clear_offset.tv_nsec = -dt2; - if (time_pps_setparams(instance->pps_h, ¤t_params)) - perror("time_pps_setparams"); -#else - /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */ - /* offset for THIS second */ - dmy = -1.0e-9*dt1; - DTOLFP(dmy, &ts_tmp); - L_ADD(&ts, &ts_tmp); -#endif - /* have time from UNIX origin, convert to NTP origin. */ +/* check for a GOOD Almanac, have we got one yet? */ - ts.l_ui += JAN_1970; - instance->pp->lastrec = ts; - instance->pp->msec = 0; +static void +oncore_check_almanac( + struct instance *instance + ) +{ + if (instance->chan == 6) { + instance->rsm.bad_almanac = instance->BEHa[64]&0x1; + instance->rsm.bad_fix = instance->BEHa[64]&0x52; + } else if (instance->chan == 8) { + instance->rsm.bad_almanac = instance->BEHa[72]&0x1; + instance->rsm.bad_fix = instance->BEHa[72]&0x52; + } else if (instance->chan == 12) { + int bits1, bits2; - ts_tmp = ts; - ts_tmp.l_ui = 0; /* zero integer part */ - LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ - j = 1.0e9*dmy; /* then to integer ns */ + bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ + bits2 = instance->BEHa[130]; + instance->rsm.bad_almanac = (bits2 & 0x80); + instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); + /* too few sat Bad Geom */ +#if 0 + fprintf(stderr, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n", + instance->unit, + instance->BEHa[129], instance->BEHa[130], bits1, bits2, instance->mode == MODE_0D, + instance->mode == MODE_2D, instance->mode == MODE_3D, + instance->rsm.bad_almanac, instance->rsm.bad_fix); +#endif + } +} - Rsm = 0; - if (instance->chan == 6) - Rsm = instance->Ea[64]; - else if (instance->chan == 8) - Rsm = instance->Ea[72]; - else if (instance->chan == 12) - Rsm = ((instance->Ea[129]<<8) | instance->Ea[130]); - if (instance->chan == 6 || instance->chan == 8) { - sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 117 */ - "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", - ts.l_ui, j, - instance->pp->year, instance->pp->day, - instance->pp->hour, instance->pp->minute, instance->pp->second, - (long) tsp->tv_sec % 60, - Rsm, 0.1*(256*instance->Ea[35]+instance->Ea[36]), - /*rsat dop */ - instance->Ea[38], instance->Ea[39], instance->En[21], - /* nsat visible, nsat tracked, traim */ - instance->En[23]*256+instance->En[24], (s_char) instance->En[25], - /* sigma neg-sawtooth */ - /*sat*/ instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53], - instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69] - ); /* will be 0 for 6 chan */ - } else if (instance->chan == 12) { - sprintf(instance->pp->a_lastcode, - "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d sat %d%d%d%d%d%d%d%d%d%d%d%d", - ts.l_ui, j, - instance->pp->year, instance->pp->day, - instance->pp->hour, instance->pp->minute, instance->pp->second, - (long) tsp->tv_sec % 60, - Rsm, 0.1*(256*instance->Ea[53]+instance->Ea[54]), - /*rsat dop */ - instance->Ea[55], instance->Ea[56], - /* nsat visible, nsat tracked */ - /*sat*/ instance->Ea[58], instance->Ea[64], instance->Ea[70], instance->Ea[76], - instance->Ea[82], instance->Ea[88], instance->Ea[94], instance->Ea[100], - instance->Ea[106], instance->Ea[112], instance->Ea[118], instance->Ea[124] - ); - } - 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); - } +/* check the antenna for changes (did it get unplugged?) */ - if (!refclock_process(instance->pp)) { - refclock_report(instance->peer, CEVNT_BADTIME); - return; - } +static void +oncore_check_antenna( + struct instance *instance + ) +{ + enum antenna_state antenna; /* antenna state */ - record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); - instance->pollcnt = 2; + antenna = instance->ant_state; + if (instance->chan == 12) + antenna = (instance->BEHa[130] & 0x6 ) >> 1; + else + antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */ - if (instance->polled) { - instance->polled = 0; -/* - instance->pp->dispersion = instance->pp->skew = 0; -*/ - refclock_receive(instance->peer); - } + oncore_antenna_report (instance, antenna); } /* - * Try to use Oncore UT+ Auto Survey Feature - * If its not there (VP), set flag to do it ourselves. + * Check the leap second status once per day. + * + * Note that the ONCORE firmware for the Bj command is wrong at + * least in the VP. + * It starts advertising a LEAP SECOND as soon as the GPS satellite + * data message (page 18, subframe 4) is updated to a date in the + * future, and does not wait for the month that it will occur. + * The event will usually be advertised several months in advance. + * Since there is a one bit flag, there is no way to tell if it is + * this month, or when... + * + * As such, we have the workaround below, of only checking for leap + * seconds with the Bj command in June/December. + * + * The Gj command gives more information, and we can tell in which + * month to apply the correction. + * + * Note that with the VP we COULD read the raw data message, and + * interpret it ourselves, but since this is specific to this receiver + * only, and the above workaround is adequate, we don't bother. */ static void -oncore_msg_At( - struct instance *instance, - u_char *buf, - size_t len +oncore_check_leap_sec( + struct instance *instance ) { - instance->saw_At = 1; - if (instance->site_survey == ONCORE_SS_TESTING) { - if (buf[4] == 2) { - record_clock_stats(&(instance->peer->srcadr), - "Initiating hardware 3D site survey"); - instance->site_survey = ONCORE_SS_HW; + 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)); + 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)); + return; } -} + /* Gj works for some 6/8 chan UT and the M12 */ + /* if no response from Gj in 5 sec, we try Bj */ + /* which isnt implemented in all the GT/UT either */ + + if (instance->count4) { /* delay, waiting for Gj response */ + if (instance->saw_Gj == 1) + instance->count4 = 0; + 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)); + } + } +} -/* get leap-second warning message */ -/* - * @@Bj does NOT behave as documented in current Oncore firmware. - * It turns on the LEAP indicator when the data is set, and does not, - * as documented, wait until the beginning of the month when the - * leap second will occur. - * Until this firmware bug is fixed, @@Bj is only called in June/December. +/* check the message checksum, + * buf points to START of message ( @@ ) + * len is length WITH CR/LF. */ -static void -oncore_msg_Bj( - struct instance *instance, +static int +oncore_checksum_ok( u_char *buf, - size_t len + int len ) { - const char *cp; + int i, j; - switch(buf[4]) { - case 1: - instance->peer->leap = LEAP_ADDSECOND; - cp = "Set peer.leap to LEAP_ADDSECOND"; - break; - case 2: - instance->peer->leap = LEAP_DELSECOND; - cp = "Set peer.leap to LEAP_DELSECOND"; - break; - case 0: - default: - instance->peer->leap = LEAP_NOWARNING; - cp = "Set peer.leap to LEAP_NOWARNING"; - break; + j = 0; + for (i = 2; i < len-3; i++) + j ^= buf[i]; + + return(j == buf[len-3]); +} + + + +static void +oncore_compute_dH( + struct instance *instance + ) +{ + int GPS, MSL; + char Msg[160]; + + /* Here calculate dH = GPS - MSL for output message */ + /* also set Altitude Hold mode if GT */ + + instance->have_dH = 1; + if (instance->chan == 12) { + GPS = buf_w32(&instance->BEHa[39]); + MSL = buf_w32(&instance->BEHa[43]); + } else { + GPS = buf_w32(&instance->BEHa[23]); + MSL = buf_w32(&instance->BEHa[27]); + } + instance->dH = GPS - MSL; + instance->dH /= 100.; + + /* 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); } - record_clock_stats(&(instance->peer->srcadr), cp); } -/* Leap Second for M12, gives all info from satellite message */ + + +/* + * try loading Almanac from shmem (where it was copied from shmem_old + */ static void -oncore_msg_Gj( - struct instance *instance, - u_char *buf, - size_t len +oncore_load_almanac( + struct instance *instance ) { - int dt; - char Msg[160], *cp; - static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", - "Aug", "Sep", "Oct", "Nov", "Dec" }; - - /* print the message to verify whats there */ + u_char *cp, Cmd[20]; + int n; + struct timeval tv; + struct tm *tm; - dt = buf[5] - buf[4]; + if (!instance->shmem) + return; #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); + for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { + if (!strncmp(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 - 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]], 256*buf[6]+buf[7], - buf[15], buf[16], buf[17]); + } + } +#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); + + 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"); + write(instance->ttyfd, cp, n); + } else + record_clock_stats(&(instance->peer->srcadr), "BAD SF"); + } else + record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM"); + } } +/************DEBUG************/ +#endif - /* Only raise warning within a month of the leap second */ + /* Must load position and time or the Almanac doesn't do us any good */ - instance->peer->leap = LEAP_NOWARNING; - cp = "Set peer.leap to LEAP_NOWARNING"; + if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */ + record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM"); + for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { + if ((instance->chan == 6 && (!strncmp(cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) || + (instance->chan == 8 && (!strncmp(cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) || + (instance->chan == 12 && (!strncmp(cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) { + int ii, jj, kk; - if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] && /* year */ - buf[8] == instance->Ea[4]) { /* month */ - if (dt) { - if (dt < 0) { - instance->peer->leap = LEAP_DELSECOND; - cp = "Set peer.leap to LEAP_DELSECOND"; - } else { - instance->peer->leap = LEAP_ADDSECOND; - cp = "Set peer.leap to LEAP_ADDSECOND"; + instance->posn_set = 1; + ii = buf_w32(cp + 15); + jj = buf_w32(cp + 19); + kk = buf_w32(cp + 23); +{ +char Msg[160]; +sprintf(Msg, "SHMEM posn = %d (%d, %d, %d)", cp-instance->shmem, ii, jj, kk); +record_clock_stats(&(instance->peer->srcadr), Msg); +} + if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */ + instance->ss_lat = ii; + instance->ss_long = jj; + instance->ss_ht = kk; + } } } } - record_clock_stats(&(instance->peer->srcadr), cp); + oncore_set_posn(instance); + + /* and set time to time from Computer clock */ + + 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); + } +#endif + if (instance->chan == 12) { + memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb)); + Cmd[-2+4] = tm->tm_mon; + Cmd[-2+5] = tm->tm_mday; + Cmd[-2+6] = (1900+tm->tm_year)/256; + Cmd[-2+7] = (1900+tm->tm_year)%256; + Cmd[-2+8] = tm->tm_hour; + Cmd[-2+9] = tm->tm_min; + Cmd[-2+10] = tm->tm_sec; + Cmd[-2+11] = 0; + Cmd[-2+12] = 0; + Cmd[-2+13] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb)); + } else { + /* First set GMT offset to zero */ + + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab)); + + memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac)); + Cmd[-2+4] = tm->tm_mon; + 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)); + + 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)); + } + + record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac"); } -/* - * get Position hold position - */ +/* Almanac data input */ static void -oncore_msg_As( +oncore_print_Cb( struct instance *instance, - u_char *buf, - size_t len + u_char *cp ) { - if (!instance->printed || instance->As) - return; - - instance->As = 1; +#if 0 + int ii; + char Msg[160]; - instance->ss_lat = buf_w32(&buf[4]); - instance->ss_long = buf_w32(&buf[8]); - instance->ss_ht = buf_w32(&buf[12]); + 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"); - /* Print out Position */ - oncore_print_As(instance); + sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5)); + record_clock_stats(&(instance->peer->srcadr), Msg); +#endif } +#if 0 +static void +oncore_print_array( + u_char *cp, + int n + ) +{ + int jj, i, j, nn; + + nn = 0; + printf("\nTOP\n"); + jj = n/16; + for (j=0; jpeer->srcadr), Msg); imx = xm; @@ -2730,79 +3418,306 @@ oncore_print_As( 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); + 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); } /* - * get PPS Offset - * Nb. @@Ay is not supported for early UT (no plus) model + * write message to Oncore. */ static void -oncore_msg_Ay( - struct instance *instance, - u_char *buf, +oncore_sendmsg( + int fd, + u_char *ptr, size_t len ) { - char Msg[120]; + u_char cs = 0; - if (!instance->printed || instance->Ay) - return; + if (debug > 4) + printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len); + write(fd, "@@", (size_t) 2); + write(fd, ptr, len); + while (len--) + cs ^= *ptr++; + write(fd, &cs, (size_t) 1); + write(fd, "\r\n", (size_t) 2); +} - instance->Ay = 1; - instance->offset = buf_w32(&buf[4]); - sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); +static void +oncore_set_posn( + struct instance *instance + ) +{ + int mode; + char Cmd[20]; + + /* Turn OFF position hold, it needs to be off to set position (for some units), + will get set ON in @@Ea later */ + + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, 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) */ + } + + mode = instance->init_type; + + if (mode != 0) { /* first set posn hold position */ + memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */ + w32_buf(&Cmd[-2+4], (int) instance->ss_lat); + 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) */ + + 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) */ + + /* next set current position */ + + if (instance->chan == 12) { + memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga)); + w32_buf(&Cmd[-2+4], (int) instance->ss_lat); + 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) */ + } 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) */ + + 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) */ + + 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) */ + } + + /* Finally, turn on position hold */ + + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); + else + oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); + } +} + + + +static void +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); + + 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)); + else if (instance->chan == 8) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); + else /* chan == 12 */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); + } } /* - * get Cable Delay + * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. */ static void -oncore_msg_Az( - struct instance *instance, - u_char *buf, - size_t len +oncore_shmem_get_3D( + struct instance *instance ) { - char Msg[120]; - - if (!instance->printed || instance->Az) - return; + if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */ + 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 */ + else + oncore_sendmsg(instance->ttyfd, 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)); + if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); + } else + oncore_sendmsg(instance->ttyfd, 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 */ + 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 */ + } else + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); + } + } +} - instance->Az = 1; - instance->delay = buf_w32(&buf[4]); - sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); - record_clock_stats(&(instance->peer->srcadr), Msg); -} +/* + * Here we do the Software SiteSurvey. + * We have to average our own position for the Position Hold Mode + * We use Heights from the GPS ellipsoid. + * We check for the END of either HW or SW SiteSurvey. + */ static void -oncore_msg_Sz( - struct instance *instance, - u_char *buf, - size_t len +oncore_ss( + struct instance *instance ) { - const char *cp; + char *cp, Msg[160]; + double lat, lon, ht; - cp = "Oncore: System Failure at Power On"; - if (instance && instance->peer) { + + if (instance->site_survey == ONCORE_SS_HW) { + + /* + * Check to see if Hardware SiteSurvey has Finished. + */ + + 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"); + + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); + else + oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); + + cp = "SSstate = ONCORE_SS_DONE"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->site_survey = ONCORE_SS_DONE; + } + } else { + /* + * Must be a Software Site Survey. + */ + + if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ + return; + + if (instance->mode != MODE_3D) /* Use only 3D Fixes */ + return; + + instance->ss_lat += buf_w32(&instance->BEHa[15]); + instance->ss_long += buf_w32(&instance->BEHa[19]); + instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */ + instance->ss_count++; + + if (instance->ss_count != POS_HOLD_AVERAGE) + return; + + instance->ss_lat /= POS_HOLD_AVERAGE; + 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); + 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_set_posn(instance); + + record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); + + cp = "SSstate = ONCORE_SS_DONE"; record_clock_stats(&(instance->peer->srcadr), cp); - oncore_shutdown(instance->unit, instance->peer); + instance->site_survey = ONCORE_SS_DONE; + } +} + + + +static int +oncore_wait_almanac( + struct instance *instance + ) +{ + if (instance->rsm.bad_almanac) { + if (debug) + printf("ONCORE[%d]: waiting for almanac\n", instance->unit); + + /* + * If we get here (first time) then we don't have an almanac in memory. + * Check if we have a SHMEM, and if so try to load whatever is there. + */ + + if (!instance->almanac_from_shmem) { + instance->almanac_from_shmem = 1; + oncore_load_almanac(instance); + } + return(1); + } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn + commands, and can finally check for TRAIM. Again, we set a delay + (5sec) and wait for things to settle down */ + + if (instance->chan == 6) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); + else if (instance->chan == 8) + oncore_sendmsg(instance->ttyfd, 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 */ + } + instance->traim_delay = 1; + + record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC"); + + instance->o_state = ONCORE_RUN; + record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN"); } + return(0); } + + #else int refclock_oncore_bs; #endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_palisade.c b/contrib/ntp/ntpd/refclock_palisade.c index 4b36b78..897221b 100644 --- a/contrib/ntp/ntpd/refclock_palisade.c +++ b/contrib/ntp/ntpd/refclock_palisade.c @@ -56,6 +56,11 @@ #include "config.h" #endif +#if defined(SYS_WINNT) +#undef close +#define close closesocket +#endif + #if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE)) #include "refclock_palisade.h" @@ -88,6 +93,16 @@ struct refclock refclock_palisade = { int day_of_year P((char *dt)); +/* Extract the clock type from the mode setting */ +#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F)) + +/* Supported clock types */ +#define CLK_TRIMBLE 0 /* Trimble Palisade */ +#define CLK_PRAECIS 1 /* Endrun Technologies Praecis */ + +int praecis_msg; +static void praecis_parse(struct recvbuf *rbufp, struct peer *peer); + /* * palisade_start - open the devices and initialize data for processing */ @@ -195,6 +210,19 @@ palisade_start ( memset((char *)up, 0, sizeof(struct palisade_unit)); + 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; + } + pp = peer->procptr; pp->io.clock_recv = palisade_io; pp->io.srcclock = (caddr_t)peer; @@ -335,7 +363,10 @@ TSIP_decode ( return 0; } - if (up->rpt_buf[0] == (char) 0x8f) { + /* + * 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 */ @@ -385,7 +416,7 @@ if (debug > 1) { secint = (long) secs; secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ - pp->usec = (long) (secfrac * 1000000); + pp->nsec = (long) (secfrac * 1000000000); secint %= 86400; /* Only care about today */ pp->hour = secint / 3600; @@ -402,7 +433,7 @@ if (debug > 1) { 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->usec, mb(12), mb(11), pp->year, GPS_UTC_Offset); + 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 @@ -463,7 +494,7 @@ if (debug > 1) { return 0; } - pp->usec = (long) (getdbl((u_char *) &mb(3)) * 1000000); + pp->nsec = (long) (getdbl((u_char *) &mb(3)) * 1000000); if ((pp->day = day_of_year(&mb(14))) < 0) break; @@ -476,7 +507,7 @@ if (debug > 1) { 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->usec, mb(15), mb(14), pp->year, + pp->second, pp->nsec, mb(15), mb(14), pp->year, mb(19), *Tracking_Status[st]); #endif return 1; @@ -534,7 +565,7 @@ palisade_receive ( printf( "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n", up->unit, pp->year, pp->day, pp->hour, pp->minute, - pp->second, pp->usec); + pp->second, pp->nsec); #endif /* @@ -544,7 +575,7 @@ palisade_receive ( */ (void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld", - pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->usec); + pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->nsec); pp->lencode = 24; #ifdef PALISADE @@ -571,7 +602,7 @@ palisade_receive ( 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, @@ -620,10 +651,43 @@ palisade_poll ( if (pp->sloppyclockflag & CLK_FLAG2) return; /* using synchronous packet input */ + if(up->type == CLK_PRAECIS) { + if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) + msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); + else { + praecis_msg = 1; + return; + } + } + if (HW_poll(pp) < 0) refclock_report(peer, CEVNT_FAULT); } +static void +praecis_parse(struct recvbuf *rbufp, struct peer *peer) +{ + static char buf[100]; + static int p = 0; + struct refclockproc *pp; + + pp = peer->procptr; + + memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); + p += rbufp->recv_length; + + if(buf[p-2] == '\r' && buf[p-1] == '\n') { + buf[p-2] = '\0'; + record_clock_stats(&peer->srcadr, buf); + + p = 0; + praecis_msg = 0; + + if (HW_poll(pp) < 0) + refclock_report(peer, CEVNT_FAULT); + + } +} static void palisade_io ( @@ -649,6 +713,13 @@ palisade_io ( pp = peer->procptr; up = (struct palisade_unit *)pp->unitptr; + if(up->type == CLK_PRAECIS) { + if(praecis_msg) { + praecis_parse(rbufp,peer); + return; + } + } + c = (char *) &rbufp->recv_space; d = c + rbufp->recv_length; diff --git a/contrib/ntp/ntpd/refclock_palisade.h b/contrib/ntp/ntpd/refclock_palisade.h index cc37716..7e1ed49 100644 --- a/contrib/ntp/ntpd/refclock_palisade.h +++ b/contrib/ntp/ntpd/refclock_palisade.h @@ -146,6 +146,7 @@ struct palisade_unit { char rpt_status; /* TSIP Parser State */ short rpt_cnt; /* TSIP packet length so far */ char rpt_buf[BMAX]; /* packet assembly buffer */ + int type; /* Clock mode type */ }; /* diff --git a/contrib/ntp/ntpd/refclock_parse.c b/contrib/ntp/ntpd/refclock_parse.c index cfb9904..52fadaa 100644 --- a/contrib/ntp/ntpd/refclock_parse.c +++ b/contrib/ntp/ntpd/refclock_parse.c @@ -802,7 +802,7 @@ static struct parse_clockinfo const char *cl_description; /* device name */ const char *cl_format; /* fixed format */ u_char cl_type; /* clock type (ntp control) */ - u_long cl_maxunsync; /* time to trust oscillator after loosing synch */ + u_long cl_maxunsync; /* time to trust oscillator after losing synch */ u_long cl_speed; /* terminal input & output baudrate */ u_long cl_cflag; /* terminal control flags */ u_long cl_iflag; /* terminal input flags */ @@ -1181,7 +1181,7 @@ static struct parse_clockinfo "WHARTON 400A Series clock Output Format 1", /* fixed format */ /* Must match a format-name in a libparse/clk_xxx.c file */ DCF_TYPE, /* clock type (ntp control) */ - (1*60*60), /* time to trust oscillator after loosing synch */ + (1*60*60), /* time to trust oscillator after losing synch */ B9600, /* terminal input & output baudrate */ (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 0, /* terminal input flags */ @@ -1240,10 +1240,10 @@ static struct parse_clockinfo static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); -#define CLK_REALTYPE(x) ((int)(((x)->ttlmax) & 0x7F)) +#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) -#define CLK_PPS(x) (((x)->ttlmax) & 0x80) +#define CLK_PPS(x) (((x)->ttl) & 0x80) /* * Other constant stuff @@ -3095,7 +3095,7 @@ parse_event( NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ ERR(ERR_BADEVENT) msyslog(LOG_ERR, - "clock %s fault '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), + "clock %s fault '%s' (0x%02x)", refnumtoa(&parse->peer->srcadr), ceventstr(event), (u_int)event); } else @@ -3103,7 +3103,7 @@ parse_event( NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT)) msyslog(LOG_INFO, - "clock %s event '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), + "clock %s event '%s' (0x%02x)", refnumtoa(&parse->peer->srcadr), ceventstr(event), (u_int)event); } @@ -3728,11 +3728,11 @@ gps16x_message( case GPS_ANT_INFO: { ANT_INFO antinfo; - char buffer[512]; - char *p; + u_char buffer[512]; + u_char *p; get_mbg_antinfo(&bufp, &antinfo); - sprintf((char *)buffer, "meinberg_antenna_status=\""); + sprintf(buffer, "meinberg_antenna_status=\""); p = buffer + strlen(buffer); switch (antinfo.status) @@ -3750,20 +3750,20 @@ gps16x_message( CLK_UNIT(parse->peer), p); p += strlen(p); - mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); + mbg_tm_str(&p, &antinfo.tm_disconn); *p = '\0'; break; case ANT_RECONN: strcat(p, "RECONNECTED on "); p += strlen(p); - mbg_tm_str((unsigned char **)&p, &antinfo.tm_reconn); + mbg_tm_str(&p, &antinfo.tm_reconn); sprintf(p, ", reconnect clockoffset %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((unsigned char **)&p, &antinfo.tm_disconn); + mbg_tm_str(&p, &antinfo.tm_disconn); *p = '\0'; break; @@ -3786,8 +3786,8 @@ gps16x_message( case GPS_CFGH: { CFGH cfgh; - char buffer[512]; - char *p; + u_char buffer[512]; + u_char *p; get_mbg_cfgh(&bufp, &cfgh); if (cfgh.valid) @@ -3797,7 +3797,7 @@ gps16x_message( p = buffer; strcpy(buffer, "gps_tot_51=\""); p += strlen(p); - mbg_tgps_str((unsigned char **)&p, &cfgh.tot_51); + mbg_tgps_str(&p, &cfgh.tot_51); *p++ = '"'; *p = '\0'; set_var(&parse->kv, buffer, sizeof(buffer), RO); @@ -3805,7 +3805,7 @@ gps16x_message( p = buffer; strcpy(buffer, "gps_tot_63=\""); p += strlen(p); - mbg_tgps_str((unsigned char **)&p, &cfgh.tot_63); + mbg_tgps_str(&p, &cfgh.tot_63); *p++ = '"'; *p = '\0'; set_var(&parse->kv, buffer, sizeof(buffer), RO); @@ -3813,7 +3813,7 @@ gps16x_message( p = buffer; strcpy(buffer, "gps_t0a=\""); p += strlen(p); - mbg_tgps_str((unsigned char **)&p, &cfgh.t0a); + mbg_tgps_str(&p, &cfgh.t0a); *p++ = '"'; *p = '\0'; set_var(&parse->kv, buffer, sizeof(buffer), RO); @@ -5176,7 +5176,7 @@ rawdcf_init_1( } #else static int -rawdcfdtr_init( +rawdcfdtr_init_1( struct parseunit *parse ) { diff --git a/contrib/ntp/ntpd/refclock_pcf.c b/contrib/ntp/ntpd/refclock_pcf.c index ff2b28e..d4e9fd1 100644 --- a/contrib/ntp/ntpd/refclock_pcf.c +++ b/contrib/ntp/ntpd/refclock_pcf.c @@ -196,9 +196,9 @@ pcf_poll( pp->hour = tp->tm_hour; pp->minute = tp->tm_min; pp->second = tp->tm_sec; - pp->usec = buf[16] * 31250; + pp->nsec = buf[16] * 31250000; if (buf[17] & 1) - pp->usec += 500000; + pp->nsec += 500000000; #ifdef DEBUG if (debug) @@ -216,6 +216,7 @@ pcf_poll( pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; + pp->lastref = pp->lastrec; refclock_receive(peer); } #else diff --git a/contrib/ntp/ntpd/refclock_pst.c b/contrib/ntp/ntpd/refclock_pst.c index b92a2e0..2443b2c 100644 --- a/contrib/ntp/ntpd/refclock_pst.c +++ b/contrib/ntp/ntpd/refclock_pst.c @@ -71,7 +71,7 @@ /* * Interface definitions */ -#define DEVICE "/dev/pst%d" /* device name and unit */ +#define DEVICE "/dev/wwv%d" /* device name and unit */ #define SPEED232 B9600 /* uart speed (9600 baud) */ #define PRECISION (-10) /* precision assumed (about 1 ms) */ #define WWVREFID "WWV\0" /* WWV reference ID */ @@ -84,7 +84,7 @@ * Unit control structure */ struct pstunit { - u_char tcswitch; /* timecode switch */ + int tcswitch; /* timecode switch */ char *lastptr; /* pointer to timecode data */ }; @@ -155,9 +155,9 @@ pst_start( * Initialize miscellaneous variables */ peer->precision = PRECISION; - peer->burst = NSTAGE; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, WWVREFID, 4); + peer->burst = MAXSTAGE; return (1); } @@ -214,17 +214,12 @@ pst_receive( * Note we get a buffer and timestamp for each , but only * the first timestamp is retained. */ - if (!up->tcswitch) + if (up->tcswitch == 0) pp->lastrec = trtmp; up->tcswitch++; pp->lencode = up->lastptr - pp->a_lastcode; if (up->tcswitch < 3) return; -#ifdef DEBUG - if (debug) - printf("pst: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif /* * We get down to business, check the timecode format and decode @@ -240,13 +235,14 @@ pst_receive( * Timecode format: * "ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx" */ - if (sscanf(pp->a_lastcode, "%c%2d:%2d:%2d.%3d%c %9s%3d%13s%4ld", - &mchar, &pp->hour, &pp->minute, &pp->second, - &pp->msec, &daychar, junque, &pp->day, - info, <emp) != 10) { + if (sscanf(pp->a_lastcode, + "%c%2d:%2d:%2d.%3ld%c %9s%3d%13s%4ld", + &mchar, &pp->hour, &pp->minute, &pp->second, &pp->nsec, + &daychar, junque, &pp->day, info, <emp) != 10) { refclock_report(peer, CEVNT_BADREPLY); return; } + pp->nsec *= 1000000; /* * Decode synchronization, quality and last update. If @@ -263,7 +259,9 @@ pst_receive( memcpy((char *)&pp->refid, WWVREFID, 4); if (peer->stratum <= 1) peer->refid = pp->refid; - pp->disp = PST_PHI * ltemp; + if (ltemp == 0) + pp->lastref = pp->lastrec; + pp->disp = PST_PHI * ltemp * 60; /* * Process the new sample in the median filter and determine the @@ -290,8 +288,10 @@ pst_poll( /* * Time to poll the clock. The PSTI/Traconex clock responds to a * "QTQDQMT" 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. + * above. Note there is no checking on state, since this may not + * be the only customer reading the clock. Only one customer + * need poll the clock; all others just listen in. If the clock + * becomes unreachable, declare a timeout and keep going. */ pp = peer->procptr; up = (struct pstunit *)pp->unitptr; @@ -299,17 +299,21 @@ pst_poll( up->lastptr = pp->a_lastcode; if (write(pp->io.fd, "QTQDQMT", 6) != 6) refclock_report(peer, CEVNT_FAULT); - else - pp->polls++; 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; + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug) + printf("pst: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + peer->burst = MAXSTAGE; + pp->polls++; } #else diff --git a/contrib/ntp/ntpd/refclock_ripencc.c b/contrib/ntp/ntpd/refclock_ripencc.c index f18270e..6337f63 100644 --- a/contrib/ntp/ntpd/refclock_ripencc.c +++ b/contrib/ntp/ntpd/refclock_ripencc.c @@ -461,8 +461,6 @@ struct refclock refclock_ripencc = { 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}; -extern int pps_hardpps; -extern int pps_assert; /* * ripencc_start - open the GPS devices and initialize data for processing @@ -612,7 +610,7 @@ ripencc_start(int unit, struct peer *peer) return (1); } - return(ripencc_ppsapi(peer, pps_assert, pps_hardpps)); + return(ripencc_ppsapi(peer, 0, 0)); } /* @@ -988,7 +986,7 @@ ripencc_receive(struct recvbuf *rbufp) */ if (ripencc_get_pps_ts(up, &rd_tmp) == 1) { pp->lastrec = up->tstamp = rd_tmp; - pp->msec = 0; + pp->nsec = 0; } else msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__); @@ -1479,7 +1477,7 @@ parse0x8FAD(rpt, peer) pp->hour = hour; pp->minute = minute; pp-> second = second; - pp->msec = 0; + pp->nsec = 0; if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0) pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND); @@ -4706,7 +4704,7 @@ 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 occurence of a series of reports */ + /* for the first occurrence of a series of reports */ static int last_rptcode = 0; int diff --git a/contrib/ntp/ntpd/refclock_shm.c b/contrib/ntp/ntpd/refclock_shm.c index 3747ce0..4ab0ede 100644 --- a/contrib/ntp/ntpd/refclock_shm.c +++ b/contrib/ntp/ntpd/refclock_shm.c @@ -87,6 +87,9 @@ struct shmTime { int valid; int dummy[10]; }; + +struct shmTime *getShmTime(int); + struct shmTime *getShmTime (int unit) { #ifndef SYS_WINNT int shmid=0; @@ -149,7 +152,6 @@ struct shmTime *getShmTime (int unit) { return p; } #endif - return 0; } /* * shm_start - attach to shared memory @@ -201,7 +203,8 @@ shm_shutdown( pp = peer->procptr; up = (struct shmTime *)pp->unitptr; #ifndef SYS_WINNT - shmdt (up); + /* HMS: shmdt()wants char* or const void * */ + (void) shmdt (up); #else UnmapViewOfFile (up); #endif @@ -272,8 +275,7 @@ shm_poll( pp->hour=t->tm_hour; pp->minute=t->tm_min; pp->second=t->tm_sec; - pp->msec=0; - pp->usec=tvt.tv_usec; + pp->nsec=tvt.tv_usec * 1000; peer->precision=up->precision; pp->leap=up->leap; } @@ -285,13 +287,16 @@ shm_poll( } else { refclock_report(peer, CEVNT_TIMEOUT); + /* msyslog (LOG_NOTICE, "SHM: no new value found in shared memory"); + */ return; } if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } + pp->lastref = pp->lastrec; refclock_receive(peer); } diff --git a/contrib/ntp/ntpd/refclock_tpro.c b/contrib/ntp/ntpd/refclock_tpro.c index 159f817..3c42568 100644 --- a/contrib/ntp/ntpd/refclock_tpro.c +++ b/contrib/ntp/ntpd/refclock_tpro.c @@ -164,6 +164,11 @@ tpro_poll( * 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. + * + * 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", @@ -179,11 +184,12 @@ tpro_poll( pp->a_lastcode); #endif if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day, - &pp->hour, &pp->minute, &pp->second, &pp->usec) + &pp->hour, &pp->minute, &pp->second, &pp->nsec) != 5) { refclock_report(peer, CEVNT_BADTIME); return; } + pp->nsec *= 1000; /* Convert usec to nsec */ if (!tp->status & 0x3) pp->leap = LEAP_NOTINSYNC; else @@ -198,6 +204,8 @@ tpro_poll( 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; diff --git a/contrib/ntp/ntpd/refclock_trak.c b/contrib/ntp/ntpd/refclock_trak.c index 326a8e9..3a4a54e 100644 --- a/contrib/ntp/ntpd/refclock_trak.c +++ b/contrib/ntp/ntpd/refclock_trak.c @@ -325,6 +325,7 @@ trak_receive( refclock_report(peer, CEVNT_BADTIME); return; } + pp->lastref = pp->lastrec; refclock_receive(peer); } diff --git a/contrib/ntp/ntpd/refclock_true.c b/contrib/ntp/ntpd/refclock_true.c index 986031d..dd355d9 100644 --- a/contrib/ntp/ntpd/refclock_true.c +++ b/contrib/ntp/ntpd/refclock_true.c @@ -503,6 +503,7 @@ true_receive( refclock_report(peer, CEVNT_BADTIME); return; } + off.l_uf = 0; #endif pp->usec = true_sample720(); @@ -545,8 +546,9 @@ true_receive( * If clock is good we send a NOMINAL message so that * any previous BAD messages are nullified */ - refclock_report(peer, CEVNT_NOMINAL); + pp->lastref = pp->lastrec; refclock_receive(peer); + refclock_report(peer, CEVNT_NOMINAL); /* * We have succedded in answering the poll. diff --git a/contrib/ntp/ntpd/refclock_ulink.c b/contrib/ntp/ntpd/refclock_ulink.c index 5bf569a..1f5e78a 100644 --- a/contrib/ntp/ntpd/refclock_ulink.c +++ b/contrib/ntp/ntpd/refclock_ulink.c @@ -248,8 +248,6 @@ ulink_receive( * proper format, we declare bad format and exit. */ syncchar = leapchar = modechar = ' '; - pp->msec = 0; - switch (pp->lencode ) { case LEN33X: /* @@ -347,11 +345,11 @@ ulink_receive( * T = DST <-> STD transition indicators * */ - if (sscanf(pp->a_lastcode, "%c%1d%c%4d%3d%*c%2d:%2d:%2d.%2d%c", + if (sscanf(pp->a_lastcode, "%c%1d%c%4d%3d%*c%2d:%2d:%2d.%2ld%c", &syncchar, &quality, &modechar, &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, - &pp->msec,&leapchar) == 10) { - pp->msec *= 10; /* M320 returns 10's of msecs */ + &pp->nsec, &leapchar) == 10) { + pp->nsec *= 10000000; /* M320 returns 10's of msecs */ if (leapchar == 'I' ) leapchar = '+'; if (leapchar == 'D' ) leapchar = '-'; if (syncchar != '?' ) syncchar = ':'; @@ -487,8 +485,9 @@ ulink_poll( refclock_report(peer, CEVNT_TIMEOUT); return; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); - refclock_receive(peer); + 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_usno.c b/contrib/ntp/ntpd/refclock_usno.c index 30a1330..057eef9 100644 --- a/contrib/ntp/ntpd/refclock_usno.c +++ b/contrib/ntp/ntpd/refclock_usno.c @@ -344,8 +344,9 @@ usno_receive( * protocol module to chuck out the data. Finaly, we unhook the * timeout, arm for the next call, fold the tent and go home. */ - record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastref = pp->lastrec; refclock_receive(peer); + record_clock_stats(&peer->srcadr, pp->a_lastcode); pp->sloppyclockflag &= ~CLK_FLAG1; up->pollcnt = 0; up->state = 0; @@ -437,7 +438,7 @@ usno_timeout( peer->nextdate = current_time + ANSWER; return; } - switch (peer->ttlmax) { + switch (peer->ttl) { /* * In manual mode the calling program is activated diff --git a/contrib/ntp/ntpd/refclock_wwv.c b/contrib/ntp/ntpd/refclock_wwv.c index b1d05c7..11aae7f 100644 --- a/contrib/ntp/ntpd/refclock_wwv.c +++ b/contrib/ntp/ntpd/refclock_wwv.c @@ -21,7 +21,7 @@ # include #endif /* HAVE_SYS_IOCTL_H */ -#define ICOM 1 /* undefine to suppress ICOM code */ +#define ICOM 1 #ifdef ICOM #include "icom.h" @@ -32,7 +32,7 @@ * * This driver synchronizes the computer time using data encoded in * radio transmissions from NIST time/frequency stations WWV in Boulder, - * CO, and WWVH in Kauai, HI. Transmikssions are made continuously on + * CO, and WWVH in Kauai, HI. Transmissions are made continuously on * 2.5, 5, 10, 15 and 20 MHz in 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 @@ -40,16 +40,16 @@ * night. * * The driver receives, demodulates and decodes the radio signals when - * connected to the audio codec of a Sun workstation running SunOS or - * Solaris, 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. + * 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 demodulation and decoding algorithms used in this driver are * based on those developed for the TAPR DSP93 development board and the * TI 320C25 digital signal processor described in: Mills, D.L. A * precision radio clock for WWV transmissions. Electrical Engineering - * Report 97-8-1, University of Delaware, August 1997, 25 pp. Available + * Report 97-8-1, University of Delaware, August 1997, 25 pp., available * from www.eecis.udel.edu/~mills/reports.htm. The algorithms described * in this report have been modified somewhat to improve performance * under weak signal conditions and to provide an automatic station @@ -64,66 +64,69 @@ * Interface definitions */ #define DEVICE_AUDIO "/dev/audio" /* audio device name */ +#define AUDIO_BUFSIZ 320 /* audio buffer size (50 ms) */ #define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define REFID "NONE" /* reference ID */ #define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */ #define SECOND 8000 /* second epoch (sample rate) (Hz) */ #define MINUTE (SECOND * 60) /* minute epoch */ #define OFFSET 128 /* companded sample offset */ #define SIZE 256 /* decompanding table size */ -#define MAXSIG 6000. /* maximum signal level reference */ +#define MAXSIG 6000. /* max signal level reference */ +#define MAXCLP 100 /* max clips above reference per s */ #define MAXSNR 30. /* max SNR reference */ #define DGAIN 20. /* data channel gain reference */ #define SGAIN 10. /* sync channel gain reference */ -#define MAXFREQ (125e-6 * SECOND) /* freq tolerance (.0125%) */ +#define MAXFREQ 1. /* max frequency tolerance (125 PPM) */ #define PI 3.1415926535 /* the real thing */ #define DATSIZ (170 * MS) /* data matched filter size */ #define SYNSIZ (800 * MS) /* minute sync matched filter size */ -#define UTCYEAR 72 /* the first UTC year */ #define MAXERR 30 /* max data bit errors in minute */ -#define NCHAN 5 /* number of channels */ - -/* - * Macroni - */ -#define MOD(x, y) ((x) < 0 ? -(-(x) % (y)) : (x) % (y)) +#define NCHAN 5 /* number of radio channels */ +#define AUDIO_PHI 5e-6 /* dispersion growth factor */ +#ifdef IRIG_SUCKS +#define WIGGLE 11 /* wiggle filter length */ +#endif /* IRIG_SUCKS */ /* * General purpose status bits (status) * - * Notes: SELV and/or SELH are set when the minute sync pulse from - * either or both WWV and/or WWVH stations has been heard. MSYNC is set - * when the minute sync pulse has been acquired and never reset. SSYNC - * is set when the second sync pulse has been acquired and cleared by - * watchdog or signal loss. DSYNC is set when the minutes unit digit has - * reached the threshold and INSYNC is set when if all nine digits have - * reached the threshold and never cleared. + * SELV and/or SELH are set when WWV or WWVH has been heard and cleared + * on signal loss. SSYNC is set when the second sync pulse has been + * acquired and cleared by signal loss. MSYNC is set when the minute + * sync pulse has been acquired. DSYNC is set when a digit reaches the + * threshold and INSYNC is set when all nine digits have reached the + * threshold. The MSYNC, DSYNC and INSYNC bits are cleared only by + * timeout, upon which the driver starts over from scratch. * - * DGATE is set if a data bit is invalid, BGATE is set if a BCD digit + * DGATE is set if a data bit is invalid and BGATE is set if a BCD digit * bit is invalid. SFLAG is set when during seconds 59, 0 and 1 while - * probing for alternate frequencies. LEPSEC is set when the SECWAR of - * the timecode is set on the last second of 30 June or 31 December. At - * the end of this minute both the receiver and transmitter insert - * second 60 in the minute and the minute sync slips a second. + * probing alternate frequencies. LEPDAY is set when SECWAR of the + * timecode is set on 30 June or 31 December. LEPSEC is set during the + * last minute of the day when LEPDAY is set. At the end of this minute + * the driver inserts second 60 in the seconds state machine and the + * minute sync slips a second. The SLOSS and SJITR bits are for monitor + * only. */ #define MSYNC 0x0001 /* minute epoch sync */ #define SSYNC 0x0002 /* second epoch sync */ #define DSYNC 0x0004 /* minute units sync */ #define INSYNC 0x0008 /* clock synchronized */ -#define DGATE 0x0010 /* data bit error */ -#define BGATE 0x0020 /* BCD digit bit error */ +#define FGATE 0x0010 /* frequency gate */ +#define DGATE 0x0020 /* data bit error */ +#define BGATE 0x0040 /* BCD digit bit error */ #define SFLAG 0x1000 /* probe flag */ -#define LEPSEC 0x2000 /* leap second in progress */ +#define LEPDAY 0x2000 /* leap second day */ +#define LEPSEC 0x4000 /* leap second minute */ /* - * Station scoreboard bits (select) + * Station scoreboard bits * * These are used to establish the signal quality for each of the five * frequencies and two stations. */ -#define JITRNG 0x0001 /* jitter above threshold */ -#define SYNCNG 0x0002 /* sync below threshold or SNR */ -#define DATANG 0x0004 /* data below threshold or SNR */ +#define SYNCNG 0x0001 /* sync or SNR below threshold */ +#define DATANG 0x0002 /* data or SNR below threshold */ +#define ERRRNG 0x0004 /* data error */ #define SELV 0x0100 /* WWV station select */ #define SELH 0x0200 /* WWVH station select */ @@ -131,75 +134,72 @@ * Alarm status bits (alarm) * * These bits indicate various alarm conditions, which are decoded to - * form the quality character included in the timecode. There are four - * four-bit nibble fields in the word, each corresponding to a specific - * alarm condition. At the end of each second, the word is shifted left - * one position and the least significant bit of each nibble cleared. - * This bit can be set during the next minute if the associated alarm - * condition is raised. This provides a way to remember alarm conditions - * up to four minutes. - * - * If not tracking both minute sync and second sync, the SYNERR alarm is - * raised. The data error counter is incremented for each invalid data - * bit. If too many data bit errors are encountered in one minute, the - * MODERR alarm is raised. The DECERR alarm is raised if a maximum - * likelihood digit fails to compare with the current clock digit. If - * the probability of any miscellaneous bit or any digit falls below the - * threshold, the SYMERR alarm is raised. + * form the quality character included in the timecode. If not tracking + * second sync, the SYNERR alarm is raised. The data error counter is + * incremented for each invalid data bit. If too many data bit errors + * are encountered in one minute, the MODERR alarm is raised. The DECERR + * alarm is raised if a maximum likelihood digit fails to compare with + * the current clock digit. If the probability of any miscellaneous bit + * or any digit falls below the threshold, the SYMERR alarm is raised. */ -#define DECERR 0 /* BCD digit compare error */ -#define SYMERR 4 /* low bit or digit probability */ -#define MODERR 8 /* too many data bit errors */ -#define SYNERR 12 /* not synchronized to station */ +#define DECERR 1 /* BCD digit compare error */ +#define SYMERR 2 /* low bit or digit probability */ +#define MODERR 4 /* too many data bit errors */ +#define SYNERR 8 /* not synchronized to station */ /* - * Watchdog timeouts (watch) + * Watchcat timeouts (watch) * * If these timeouts expire, the status bits are mashed to zero and the * driver starts from scratch. Suitably more refined procedures may be * developed in future. All these are in minutes. */ -#define ACQSN 5 /* acquisition timeout */ -#define HSPEC 15 /* second sync timeout */ +#define ACQSN 5 /* station acquisition timeout */ #define DIGIT 30 /* minute unit digit timeout */ -#define PANIC (4 * 1440) /* panic timeout */ +#define HOLD 30 /* reachable timeout */ +#define PANIC (2 * 1440) /* panic timeout */ /* * Thresholds. These establish the minimum signal level, minimum SNR and * maximum jitter thresholds which establish the error and false alarm - * rates of the receiver. The values defined here may be on the + * rates of the driver. The values defined here may be on the * adventurous side in the interest of the highest sensitivity. */ -#define ATHR 2000 /* acquisition amplitude threshold */ -#define ASNR 6.0 /* acquisition SNR threshold (dB) */ -#define AWND 50 /* acquisition window threshold (ms) */ -#define AMIN 3 /* acquisition min compare count */ -#define AMAX 6 /* max compare count */ -#define QTHR 2000 /* QSY amplitude threshold */ -#define QSNR 20.0 /* QSY SNR threshold (dB) */ +#define MTHR 13. /* acquisition signal gate (percent) */ +#define TTHR 50. /* tracking signal gate (percent) */ +#define ATHR 2000. /* acquisition amplitude threshold */ +#define ASNR 6. /* acquisition SNR threshold (dB) */ +#define AWND 20. /* acquisition jitter threshold (ms) */ +#define AMIN 3 /* min bit count */ +#define AMAX 6 /* max bit count */ +#define QTHR 2000 /* QSY sync threshold */ +#define QSNR 20. /* QSY sync SNR threshold (dB) */ +#define XTHR 1000. /* QSY data threshold */ +#define XSNR 10. /* QSY data SNR threshold (dB) */ #define STHR 500 /* second sync amplitude threshold */ +#define SSNR 10. /* second sync SNR threshold */ #define SCMP 10 /* second sync compare threshold */ #define DTHR 1000 /* bit amplitude threshold */ -#define DSNR 10.0 /* bit SNR threshold (dB) */ -#define BTHR 1000 /* digit probability threshold */ -#define BSNR 3.0 /* digit likelihood threshold (dB) */ -#define BCMP 5 /* digit compare threshold (dB) */ +#define DSNR 10. /* bit SNR threshold (dB) */ +#define BTHR 1000 /* digit amplitude threshold */ +#define BSNR 3. /* digit likelihood threshold (dB) */ +#define BCMP 5 /* digit compare threshold */ /* - * Tone frequency definitions. + * Tone frequency definitions. The increments are for 4.5-deg sine + * table. */ -#define MS 8 /* samples per millisecond */ -#define IN100 1 /* 100 Hz 4.5-deg sin table */ -#define IN1000 10 /* 1000 Hz 4.5-deg sin table */ -#define IN1200 12 /* 1200 Hz 4.5-deg sin 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 */ /* * Acquisition and tracking time constants. Usually powers of 2. */ -#define MINAVG 8 /* min time constant (s) */ -#define MAXAVG 7 /* max time constant (log2 s) */ -#define TCONST 16 /* minute time constant (s) */ -#define SYNCTC (1024 / (1 << MAXAVG)) /* FLL constant (s) */ +#define MINAVG 8 /* min time constant */ +#define MAXAVG 1024 /* max time constant */ +#define TCONST 16 /* data bit/digit time constant */ /* * Miscellaneous status bits (misc) @@ -212,30 +212,20 @@ #define DUT2 0x02 /* 57 DUT .2 */ #define DUT4 0x04 /* 58 DUT .4 */ #define DUTS 0x08 /* 50 DUT sign */ -#define DST1 0x10 /* 55 DST1 DST in progress */ -#define DST2 0x20 /* 2 DST2 DST change warning */ +#define DST1 0x10 /* 55 DST1 leap warning */ +#define DST2 0x20 /* 2 DST2 DST1 delayed one day */ #define SECWAR 0x40 /* 3 leap second warning */ /* - * The total system delay with the DSP93 program is at 22.5 ms, - * including the propagation delay from Ft. Collins, CO, to Newark, DE - * (8.9 ms), the communications receiver delay and the delay of the - * DSP93 program itself. The DSP93 program delay is due mainly to the - * 400-Hz FIR bandpass filter (5 ms) and second sync matched filter (5 - * ms), leaving about 3.6 ms for the receiver delay and strays. - * - * The total system delay with this program is estimated at 27.1 ms by - * comparison with another PPS-synchronized NTP server over a 10-Mb/s - * Ethernet. The propagation and receiver delays are the same as with - * the DSP93 program. The program delay is due only to the 600-Hz - * IIR bandpass filter (1.1 ms), since other delays have been removed. - * Assuming 4.7 ms for the receiver, program and strays, this leaves - * 13.5 ms for the audio codec and operating system latencies for a - * total of 18.2 ms. as the systematic delay. 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 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. */ -#define PDELAY (.0036 + .0011 + .0135) /* net system delay (s) */ +#define PDELAY (.0011 + .0047 + .0002) /* net system delay (s) */ /* * Table of sine values at 4.5-degree increments. This is used by the @@ -280,20 +270,19 @@ struct progx { * Case switch numbers */ #define IDLE 0 /* no operation */ -#define COEF 1 /* BCD bit conditioned on DSYNC */ -#define COEF1 2 /* BCD bit */ -#define COEF2 3 /* BCD bit ignored */ -#define DECIM9 4 /* BCD digit 0-9 */ -#define DECIM6 5 /* BCD digit 0-6 */ -#define DECIM3 6 /* BCD digit 0-3 */ -#define DECIM2 7 /* BCD digit 0-2 */ -#define MSCBIT 8 /* miscellaneous bit */ -#define MSC20 9 /* miscellaneous bit */ -#define MSC21 10 /* QSY probe channel */ -#define MIN1 11 /* minute */ -#define MIN2 12 /* leap second */ -#define SYNC2 13 /* QSY data channel */ -#define SYNC3 14 /* QSY data channel */ +#define COEF 1 /* BCD bit */ +#define COEF2 2 /* BCD bit ignored */ +#define DECIM9 3 /* BCD digit 0-9 */ +#define DECIM6 4 /* BCD digit 0-6 */ +#define DECIM3 5 /* BCD digit 0-3 */ +#define DECIM2 6 /* BCD digit 0-2 */ +#define MSCBIT 7 /* miscellaneous bit */ +#define MSC20 8 /* miscellaneous bit */ +#define MSC21 9 /* QSY probe channel */ +#define MIN1 10 /* minute */ +#define MIN2 11 /* leap second */ +#define SYNC2 12 /* QSY data channel */ +#define SYNC3 13 /* QSY data channel */ /* * Offsets in decoding matrix @@ -314,10 +303,10 @@ struct progx progx[] = { {COEF, 3}, /* 7 8 */ {DECIM9, YR}, /* 8 */ {IDLE, 0}, /* 9 p1 */ - {COEF1, 0}, /* 10 1 minute units */ - {COEF1, 1}, /* 11 2 */ - {COEF1, 2}, /* 12 4 */ - {COEF1, 3}, /* 13 8 */ + {COEF, 0}, /* 10 1 minute units */ + {COEF, 1}, /* 11 2 */ + {COEF, 2}, /* 12 4 */ + {COEF, 3}, /* 13 8 */ {DECIM9, MN}, /* 14 */ {COEF, 0}, /* 15 10 minute tens */ {COEF, 1}, /* 16 20 */ @@ -442,8 +431,8 @@ double bcd2[][4] = { */ char dstcod[] = { 'S', /* 00 standard time */ - 'I', /* 01 daylight warning */ - 'O', /* 10 standard warning */ + 'I', /* 01 set clock ahead at 0200 local */ + 'O', /* 10 set clock back at 0200 local */ 'D' /* 11 daylight time */ }; @@ -472,32 +461,32 @@ struct decvec { * for WWVH. Other than frequency, the format is the same. */ struct sync { - double amp; /* sync amplitude (I, Q square) */ - double synamp; /* sync envelope at 800 ms */ + double epoch; /* accumulated epoch differences */ + double maxamp; /* sync max envelope (square) */ + double noiamp; /* sync noise envelope (square) */ + long pos; /* max amplitude position */ + long lastpos; /* last max position */ + long mepoch; /* minute synch epoch */ + + double amp; /* sync amplitude (I, Q squares) */ + double synamp; /* sync max envelope at 800 ms */ double synmax; /* sync envelope at 0 s */ - double synmin; /* avg sync envelope at 59 s, 1 s */ + double synmin; /* sync envelope at 59, 1 s */ double synsnr; /* sync signal SNR */ - double noise; /* max amplitude off pulse */ - double sigmax; /* max amplitude on pulse */ - double lastmax; /* last max amplitude on pulse */ - long pos; /* position at maximum amplitude */ - long lastpos; /* last position at maximum amplitude */ - long jitter; /* shake, wiggle and waggle */ - long mepoch; /* minute synch epoch */ - int count; /* compare counter */ + int count; /* bit counter */ char refid[5]; /* reference identifier */ - char ident[4]; /* station identifier */ int select; /* select bits */ + int reach; /* reachability register */ }; /* - * The channel structure is used to mitigate between channels. At this - * point we have already decided which station to use. + * The channel structure is used to mitigate between channels. */ struct chan { int gain; /* audio gain */ - int errcnt; /* data bit error counter */ - double noiamp; /* I-channel average noise amplitude */ + double sigamp; /* data max envelope (square) */ + double noiamp; /* data noise envelope (square) */ + double datsnr; /* data signal SNR */ struct sync wwv; /* wwv station */ struct sync wwvh; /* wwvh station */ }; @@ -508,37 +497,42 @@ struct chan { struct wwvunit { l_fp timestamp; /* audio sample timestamp */ l_fp tick; /* audio sample increment */ - double comp[SIZE]; /* decompanding table */ double phase, freq; /* logical clock phase and frequency */ double monitor; /* audio monitor point */ int fd_icom; /* ICOM file descriptor */ int errflg; /* error flags */ - int bufcnt; /* samples in buffer */ - int bufptr; /* buffer index pointer */ + int watch; /* watchcat */ + + /* + * Audio codec variables + */ + double comp[SIZE]; /* decompanding table */ int port; /* codec port */ int gain; /* codec gain */ + int mongain; /* codec monitor gain */ int clipcnt; /* sample clipped count */ - int seccnt; /* second countdown */ - int minset; /* minutes since last clock set */ - int watch; /* watchcat */ - int swatch; /* second sync watchcat */ +#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 */ /* * Variables used to establish basic system timing */ - int avgint; /* log2 master time constant (s) */ - int epoch; /* second epoch ramp */ - int repoch; /* receiver sync epoch */ - int yepoch; /* transmitter sync epoch */ + int avgint; /* master time constant */ + int tepoch; /* sync epoch median */ + int yepoch; /* sync epoch */ + int repoch; /* buffered sync epoch */ double epomax; /* second sync amplitude */ + double eposnr; /* second sync SNR */ double irig; /* data I channel amplitude */ double qrig; /* data Q channel amplitude */ int datapt; /* 100 Hz ramp */ double datpha; /* 100 Hz VFO control */ - int rphase; /* receiver sample counter */ - int rsec; /* receiver seconds counter */ + int rphase; /* second sample counter */ long mphase; /* minute sample counter */ - long nepoch; /* minute epoch index */ /* * Variables used to mitigate which channel to use @@ -553,19 +547,16 @@ struct wwvunit { * Variables used by the clock state machine */ struct decvec decvec[9]; /* decoding matrix */ - int cdelay; /* WWV propagation delay (samples) */ - int hdelay; /* WVVH propagation delay (samples) */ - int pdelay; /* propagation delay (samples) */ - int tphase; /* transmitter sample counter */ - int tsec; /* transmitter seconds counter */ + int rsec; /* seconds counter */ int digcnt; /* count of digits synchronized */ /* * Variables used to estimate signal levels and bit/digit * probabilities */ - double sigamp; /* I-channel peak signal amplitude */ - double noiamp; /* I-channel average noise amplitude */ + double sigsig; /* data max signal */ + double sigamp; /* data max envelope (square) */ + double noiamp; /* data noise envelope (square) */ double datsnr; /* data SNR (dB) */ /* @@ -575,6 +566,7 @@ struct wwvunit { int alarm; /* alarm flashers */ int misc; /* miscellaneous timecode bits */ int errcnt; /* data bit error counter */ + int errbit; /* data bit errors in minute */ }; /* @@ -590,10 +582,10 @@ static void wwv_poll P((int, struct peer *)); */ static void wwv_epoch P((struct peer *)); static void wwv_rf P((struct peer *, double)); -static void wwv_endpoc P((struct peer *, double, int)); +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 *, - double)); + double, int)); static void wwv_corr4 P((struct peer *, struct decvec *, double [], double [][4])); static void wwv_gain P((struct peer *)); @@ -603,7 +595,12 @@ static int timecode P((struct wwvunit *, char *)); static double wwv_snr P((double, double)); static int carry P((struct decvec *)); static void wwv_newchan P((struct peer *)); +static void wwv_newgame P((struct peer *)); +static double wwv_metric P((struct sync *)); +#ifdef ICOM static int wwv_qsy P((struct peer *, int)); +#endif /* ICOM */ + static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */ /* @@ -625,13 +622,12 @@ struct refclock refclock_wwv = { */ static int wwv_start( - int unit, /* instance number (not used) */ + int unit, /* instance number (used by PCM) */ struct peer *peer /* peer structure pointer */ ) { struct refclockproc *pp; struct wwvunit *up; - struct chan *cp; #ifdef ICOM int temp; #endif /* ICOM */ @@ -646,7 +642,7 @@ wwv_start( /* * Open audio device */ - fd = audio_init(DEVICE_AUDIO); + fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); if (fd < 0) return (0); #ifdef DEBUG @@ -657,12 +653,11 @@ wwv_start( /* * Allocate and initialize unit structure */ - if (!(up = (struct wwvunit *) - emalloc(sizeof(struct wwvunit)))) { - (void) close(fd); + if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) { + close(fd); return (0); } - memset((char *)up, 0, sizeof(struct wwvunit)); + memset(up, 0, sizeof(struct wwvunit)); pp = peer->procptr; pp->unitptr = (caddr_t)up; pp->io.clock_recv = wwv_receive; @@ -670,7 +665,7 @@ wwv_start( pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { - (void)close(fd); + close(fd); free(up); return (0); } @@ -680,8 +675,6 @@ wwv_start( */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - DTOLFP(1. / SECOND, &up->tick); /* * The companded samples are encoded sign-magnitude. The table @@ -697,6 +690,7 @@ wwv_start( if (i % 16 == 0) step *= 2.; } + DTOLFP(1. / SECOND, &up->tick); /* * Initialize the decoding matrix with the radix for each digit @@ -711,22 +705,8 @@ wwv_start( up->decvec[DA + 2].radix = 4; up->decvec[YR].radix = 10; /* years */ up->decvec[YR + 1].radix = 10; - - /* - * Initialize the station processes for audio gain, select bit, - * station/frequency identifier and reference identifier. - */ - up->gain = 127; - for (i = 0; i < NCHAN; i++) { - cp = &up->mitig[i]; - cp->gain = up->gain; - cp->wwv.select = SELV; - strcpy(cp->wwv.refid, "WWV "); - sprintf(cp->wwv.ident,"C%.0f", floor(qsy[i])); - cp->wwvh.select = SELH; - strcpy(cp->wwvh.refid, "WWVH"); - sprintf(cp->wwvh.ident, "H%.0f", floor(qsy[i])); - } + wwv_newgame(peer); + up->schan = up->achan = 3; /* * Initialize autotune if available. Start out at 15 MHz. Note @@ -739,8 +719,8 @@ wwv_start( if (debug > 1) temp = P_TRACE; #endif - if (peer->ttlmax != 0) { - if (peer->ttlmax & 0x80) + if (peer->ttl != 0) { + if (peer->ttl & 0x80) up->fd_icom = icom_init("/dev/icom", B1200, temp); else @@ -748,14 +728,17 @@ wwv_start( temp); } if (up->fd_icom > 0) { - up->schan = 3; - if ((temp = wwv_qsy(peer, up->schan)) < 0) { + if ((temp = wwv_qsy(peer, up->schan)) != 0) { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_ERR, - "ICOM bus error; autotune disabled"); + msyslog(LOG_NOTICE, + "icom: radio not found"); up->errflg = CEVNT_FAULT; close(up->fd_icom); up->fd_icom = 0; + } else { + NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) + msyslog(LOG_NOTICE, + "icom: autotune enabled"); } } #endif /* ICOM */ @@ -806,10 +789,8 @@ wwv_receive( */ double sample; /* codec sample */ u_char *dpt; /* buffer pointer */ + int bufcnt; /* buffer counter */ l_fp ltemp; - int isneg; - double dtemp; - int i, j; peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; @@ -819,13 +800,12 @@ wwv_receive( * Main loop - read until there ain't no more. Note codec * samples are bit-inverted. */ + DTOLFP((double)rbufp->recv_length / SECOND, <emp); + L_SUB(&rbufp->recv_time, <emp); up->timestamp = rbufp->recv_time; - up->bufcnt = rbufp->recv_length; - DTOLFP((double)up->bufcnt / SECOND, <emp); - L_SUB(&up->timestamp, <emp); dpt = rbufp->recv_buffer; - for (up->bufptr = 0; up->bufptr < up->bufcnt; up->bufptr++) { - sample = up->comp[~*dpt & 0xff]; + for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { + sample = up->comp[~*dpt++ & 0xff]; /* * Clip noise spikes greater than MAXSIG. If no clips, @@ -841,14 +821,17 @@ wwv_receive( } /* - * Variable frequency oscillator. A phase change of one - * unit produces a change of 360 degrees; a frequency - * change of one unit produces a change of 1 Hz. + * 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 + * results in either duplicating or deleting one sample + * per second, which results in a frequency change of + * 125 PPM. */ up->phase += up->freq / SECOND; if (up->phase >= .5) { up->phase -= 1.; - } else if (up->phase < - .5) { + } else if (up->phase < -.5) { up->phase += 1.; wwv_rf(peer, sample); wwv_rf(peer, sample); @@ -856,71 +839,30 @@ wwv_receive( wwv_rf(peer, sample); } L_ADD(&up->timestamp, &up->tick); - - /* - * Once each second adjust the codec port and gain. - * While at it, initialize the propagation delay for - * both WWV and WWVH. Don't forget to correct for the - * receiver phase delay, mostly due to the 600-Hz - * IIR bandpass filter used for the sync signals. - */ - up->cdelay = (int)(SECOND * (pp->fudgetime1 + PDELAY)); - up->hdelay = (int)(SECOND * (pp->fudgetime2 + PDELAY)); - up->seccnt = (up->seccnt + 1) % SECOND; - if (up->seccnt == 0) { - if (pp->sloppyclockflag & CLK_FLAG2) - up->port = 2; - else - up->port = 1; - } - - /* - * During development, it is handy to have an audio - * monitor that can be switched to various signals. This - * code converts the linear signal left in up->monitor - * to codec format. - */ - isneg = 0; - dtemp = up->monitor; - if (sample < 0) { - isneg = 1; - dtemp -= dtemp; - } - i = 0; - j = OFFSET >> 1; - while (j != 0) { - if (dtemp > up->comp[i]) - i += j; - else if (dtemp < up->comp[i]) - i -= j; - else - break; - j >>= 1; - } - if (isneg) - *dpt = ~(i + OFFSET); - else - *dpt = ~i; - dpt++; } /* - * Squawk to the monitor speaker if enabled. + * Set the input port and monitor gain for the next buffer. */ + if (pp->sloppyclockflag & CLK_FLAG2) + up->port = 2; + else + up->port = 1; if (pp->sloppyclockflag & CLK_FLAG3) - if (write(pp->io.fd, (u_char *)&rbufp->recv_space, - (u_int)up->bufcnt) < 0) - perror("wwv:"); + up->mongain = MONGAIN; + else + up->mongain = 0; } /* * wwv_poll - called by the transmit procedure * - * This routine keeps track of status. If nothing is heard for two - * successive poll intervals, a timeout event is declared and any - * orphaned timecode updates are sent to foster care. Once the clock is - * set, it always appears reachable, unless reset by watchdog timeout. + * This routine keeps track of status. If no offset samples have been + * processed during a poll interval, a timeout event is declared. If + * errors have have occurred during the interval, they are reported as + * well. Once the clock is set, it always appears reachable, unless + * reset by watchdog timeout. */ static void wwv_poll( @@ -935,13 +877,10 @@ wwv_poll( up = (struct wwvunit *)pp->unitptr; if (pp->coderecv == pp->codeproc) up->errflg = CEVNT_TIMEOUT; - else - pp->polls++; - if (up->status & INSYNC) - peer->reach |= 1; if (up->errflg) refclock_report(peer, up->errflg); up->errflg = 0; + pp->polls++; } @@ -953,36 +892,27 @@ wwv_poll( * form, plus the epoch index of the second sync signal and the second * index of the minute sync signal. * - * There are three 1-s ramps used by this program, all spanning the - * range 0-7999 logical samples for exactly one second, as determined by - * the logical clock. The first drives the second epoch and runs - * continuously. The second determines the receiver phase and the third - * the transmitter phase within the second. The receiver second begins - * upon arrival of the 5-ms second sync pulse which begins the second; - * while the transmitter second begins before it by the specified - * propagation delay. - * - * There are three 1-m ramps spanning the range 0-59 seconds. The first - * drives the minute epoch in samples and runs continuously. The second - * determines the receiver second and the third the transmitter second. - * The receiver second begins upon arrival of the 800-ms sync pulse sent - * during the first second of the minute; while the transmitter second - * begins before it by the specified propagation delay. + * There are two 1-s ramps used by this program. Both count the 8000 + * logical clock samples spanning exactly one second. The epoch ramp + * counts the samples starting at an arbitrary time. The rphase ramp + * counts the samples starting at the 5-ms second sync pulse found + * during the epoch ramp. * - * The output signals include the epoch maximum and phase and second - * maximum and index. The epoch phase provides the master reference for - * all signal and timing functions, while the second index identifies - * the first second of the minute. The epoch and second maxima are used - * to calculate SNR for gating functions. + * There are two 1-m ramps used by this program. The mphase ramp counts + * the 480,000 logical clock samples spanning exactly one minute and + * starting at an arbitrary time. The rsec ramp counts the 60 seconds of + * the minute starting at the 800-ms minute sync pulse found during the + * mphase ramp. The rsec ramp drives the seconds state machine to + * determine the bits and digits of the timecode. * * Demodulation operations are based on three synthesized quadrature - * sinusoids: 100 Hz for the data subcarrier, 1000 Hz for the WWV sync - * signals and 1200 Hz for the WWVH sync signal. These drive synchronous - * matched filters for the data subcarrier (170 ms at 100 Hz), WWV - * minute sync signal (800 ms at 1000 Hz) and WWVH minute sync signal - * (800 ms at 1200 Hz). Two additional matched filters are switched in - * as required for the WWV seconds sync signal (5 ms at 1000 Hz) and - * WWVH seconds sync signal (5 ms at 1200 Hz). + * sinusoids: 100 Hz for the data signal, 1000 Hz for the WWV sync + * signal and 1200 Hz for the WWVH sync signal. These drive synchronous + * matched filters for the data signal (170 ms at 100 Hz), WWV minute + * sync signal (800 ms at 1000 Hz) and WWVH minute sync signal (800 ms + * at 1200 Hz). Two additional matched filters are switched in + * as required for the WWV second sync signal (5 ms at 1000 Hz) and + * WWVH second sync signal (5 ms at 1200 Hz). */ static void wwv_rf( @@ -992,6 +922,7 @@ wwv_rf( { struct refclockproc *pp; struct wwvunit *up; + struct sync *sp; static double lpf[5]; /* 150-Hz lpf delay line */ double data; /* lpf output */ @@ -1021,13 +952,14 @@ wwv_rf( static int epopos; /* epoch sync position buffer */ static int iniflg; /* initialization flag */ - struct sync *sp; - double dtemp; - long ltemp; - int i; + int epoch; /* comb filter index */ + int pdelay; /* propagation delay (samples) */ + double dtemp; + int i; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; + if (!iniflg) { iniflg = 1; memset((char *)lpf, 0, sizeof(lpf)); @@ -1041,7 +973,6 @@ wwv_rf( memset((char *)hqbuf, 0, sizeof(hqbuf)); memset((char *)epobuf, 0, sizeof(epobuf)); } - up->monitor = isig; /* change for debug */ /* * Baseband data demodulation. The 100-Hz subcarrier is @@ -1069,13 +1000,9 @@ wwv_rf( * multiplying the filtered signal by 100-Hz sine and cosine * signals, respectively. The data signals are demodulated by * 170-ms synchronous matched filters to produce the amplitude - * and phase signals used by the decoder. Note the correction - * due to the propagation delay is necessary for seamless - * handover between WWV and WWVH. + * and phase signals used by the decoder. */ - i = up->datapt - up->pdelay % 80; - if (i < 0) - i += 80; + i = up->datapt; up->datapt = (up->datapt + IN100) % 80; dtemp = sintab[i] * data / DATSIZ * DGAIN; up->irig -= ibuf[iptr]; @@ -1123,9 +1050,14 @@ wwv_rf( * signals are demodulated by 800-ms synchronous matched filters * to synchronize the second and minute and to detect which one * (or both) the WWV or WWVH signal is present. + * + * Note the master timing ramps, which run continuously. The + * minute counter (mphase) counts the samples in the minute, + * while the second counter (epoch) counts the samples in the + * second. */ up->mphase = (up->mphase + 1) % MINUTE; - + epoch = up->mphase % SECOND; i = csinptr; csinptr = (csinptr + IN1000) % 80; dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; @@ -1135,9 +1067,12 @@ wwv_rf( dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; cqamp = cqamp - cqbuf[jptr] + dtemp; cqbuf[jptr] = dtemp; + sp = &up->mitig[up->schan].wwv; dtemp = ciamp * ciamp + cqamp * cqamp; - wwv_qrz(peer, &up->mitig[up->schan].wwv, dtemp); - + sp->amp = dtemp; + if (!(up->status & MSYNC)) + wwv_qrz(peer, sp, dtemp, (int)(pp->fudgetime1 * + SECOND)); i = hsinptr; hsinptr = (hsinptr + IN1200) % 80; dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; @@ -1147,98 +1082,95 @@ wwv_rf( dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; hqamp = hqamp - hqbuf[jptr] + dtemp; hqbuf[jptr] = dtemp; + sp = &up->mitig[up->schan].wwvh; dtemp = hiamp * hiamp + hqamp * hqamp; - wwv_qrz(peer, &up->mitig[up->schan].wwvh, dtemp); - + sp->amp = dtemp; + if (!(up->status & MSYNC)) + wwv_qrz(peer, sp, dtemp, (int)(pp->fudgetime2 * + SECOND)); jptr = (jptr + 1) % SYNSIZ; + /* + * The following section is called once per minute. It does + * housekeeping and timeout functions and empties the dustbins. + */ if (up->mphase == 0) { - - /* - * This section is called once per minute at the minute - * epoch independently of the transmitter or receiver - * minute. If the leap bit is set, set the minute epoch - * back one second so the station processes don't miss a - * beat. Then, increment the watchdog counter and test - * for two sets of conditions depending on whether - * minute sync has been acquired or not. - */ up->watch++; - if (up->rsec == 60) { - up->mphase -= SECOND; - if (up->mphase < 0) - up->mphase += MINUTE; - } else if (!(up->status & MSYNC)) { - - /* - * If minute sync has not been acquired, the - * program listens for minute sync pulses from - * both WWV and WWVH. The station with the - * greater compare count is selected, with ties - * broken by WWV, but only if the count is at - * least three. Once a station has been - * acquired, it is initialized and begins - * tracking the signal. + if (!(up->status & MSYNC)) { + + /* + * If minute sync has not been acquired before + * timeout, or if no signal is heard, the + * program cycles to the next frequency and + * tries again. */ - if (up->mitig[up->achan].wwv.count >= - up->mitig[up->achan].wwvh.count) - sp = &up->mitig[up->achan].wwv; - else - sp = &up->mitig[up->achan].wwvh; - if (sp->count >= AMIN) { - up->watch = up->swatch = 0; - up->status |= MSYNC; - ltemp = sp->mepoch - SYNSIZ; - if (ltemp < 0) - ltemp += MINUTE; - up->rsec = (MINUTE - ltemp) / SECOND; - if (!(up->status & SSYNC)) { - up->repoch = ltemp % SECOND; - up->yepoch = up->repoch - - up->pdelay; - if (up->yepoch < 0) - up->yepoch += SECOND; + wwv_newchan(peer); + if (!(up->status & (SELV | SELH)) || up->watch > + ACQSN) { + wwv_newgame(peer); +#ifdef ICOM + if (up->fd_icom > 0) { + up->schan = (up->schan + 1) % + NCHAN; + wwv_qsy(peer, up->schan); } - wwv_newchan(peer); - } else if (sp->count == 0 || up->watch >= ACQSN) - { - up->watch = sp->count = 0; - up->schan = (up->schan + 1) % NCHAN; - wwv_qsy(peer, up->schan); +#endif /* ICOM */ } } else { /* - * If minute sync has been acquired, the program - * watches for timeout. The timeout is reset - * when the clock is set or verified. If a - * timeout occurs and the minute units digit has - * not synchronized, reset the program and start - * over. + * If the leap bit is set, set the minute epoch + * back one second so the station processes + * don't miss a beat. */ - if (up->watch > DIGIT && !(up->status & DSYNC)) - up->watch = up->status = 0; + if (up->status & LEPSEC) { + up->mphase -= SECOND; + if (up->mphase < 0) + up->mphase += MINUTE; + } + } + } - /* - * If the second sync times out, dim the sync - * lamp and raise an alarm. - */ - up->swatch++; - if (up->swatch > HSPEC) - up->status &= ~SSYNC; + /* + * When the channel metric reaches threshold and the second + * counter matches the minute epoch within the second, the + * driver has synchronized to the station. The second number is + * the remaining seconds until the next minute epoch, while the + * sync epoch is zero. Watch out for the first second; if + * already synchronized to the second, the buffered sync epoch + * must be set. + */ + if (up->status & MSYNC) { + wwv_epoch(peer); + } else if ((sp = up->sptr) != NULL) { + struct chan *cp; + + if (sp->count >= AMIN && epoch == sp->mepoch % SECOND) { + up->rsec = 60 - sp->mepoch / SECOND; + up->rphase = 0; + up->status |= MSYNC; + up->watch = 0; if (!(up->status & SSYNC)) - up->alarm |= 1 << SYNERR; + up->repoch = up->yepoch = epoch; + else + up->repoch = up->yepoch; + for (i = 0; i < NCHAN; i++) { + cp = &up->mitig[i]; + cp->wwv.count = cp->wwv.reach = 0; + cp->wwvh.count = cp->wwvh.reach = 0; + } } } /* - * The second sync pulse is extracted using 5-ms FIR matched - * filters at 1000 Hz for WWV or 1200 Hz for WWVH. This pulse is - * used for the most precise synchronization, since if provides - * a resolution of one sample (125 us). + * The second sync pulse is extracted using 5-ms (40 sample) FIR + * matched filters at 1000 Hz for WWV or 1200 Hz for WWVH. This + * pulse is used for the most precise synchronization, since if + * provides a resolution of one sample (125 us). The filters run + * only if the station has been reliably determined. */ if (up->status & SELV) { - up->pdelay = up->cdelay; + pdelay = (int)(pp->fudgetime1 * SECOND); /* * WWV FIR matched filter, five cycles of 1000-Hz @@ -1286,7 +1218,7 @@ wwv_rf( mfsync += (mf[1] = mf[0]) * -4.224514e-02; mf[0] = syncx; } else if (up->status & SELH) { - up->pdelay = up->hdelay; + pdelay = (int)(pp->fudgetime2 * SECOND); /* * WWVH FIR matched filter, six cycles of 1200-Hz @@ -1335,32 +1267,47 @@ wwv_rf( mf[0] = syncx; } else { mfsync = 0; + pdelay = 0; } /* - * Extract the seconds sync pulse using a 1-s comb filter at - * baseband. Correct for the FIR matched filter delay, which is - * 5 ms for both the WWV and WWVH filters. Blank the signal when - * probing. + * Enhance the seconds sync pulse using a 1-s (8000-sample) comb + * filter. Correct for the FIR matched filter delay, which is 5 + * ms for both the WWV and WWVH filters, and also for the + * propagation delay. Once each second look for second sync. If + * not in minute sync, fiddle the codec gain. Note the SNR is + * computed from the maximum sample and the two samples 6 ms + * before and 6 ms after it, so if we slip more than a cycle the + * SNR should plummet. */ - up->epoch = (up->epoch + 1) % SECOND; - if (up->epoch == 0) { - wwv_endpoc(peer, epomax, epopos); - up->epomax = epomax; - epomax = 0; - if (!(up->status & MSYNC)) - wwv_gain(peer); - } - dtemp = (epobuf[up->epoch] += (mfsync - epobuf[up->epoch]) / - (MINAVG << up->avgint)); + dtemp = (epobuf[epoch] += (mfsync - epobuf[epoch]) / + up->avgint); if (dtemp > epomax) { epomax = dtemp; - epopos = up->epoch - up->pdelay - 5 * MS; + epopos = epoch; + } + if (epoch == 0) { + int k, j; + + up->epomax = epomax; + k = epopos - 6 * MS; + if (k < 0) + k += SECOND; + j = epopos + 6 * MS; + if (j >= SECOND) + i -= SECOND; + up->eposnr = wwv_snr(epomax, max(abs(epobuf[k]), + abs(epobuf[j]))); + epopos -= pdelay + 5 * MS; if (epopos < 0) epopos += SECOND; + wwv_endpoc(peer, epopos); + if (!(up->status & SSYNC)) + up->alarm |= SYNERR; + epomax = 0; + if (!(up->status & MSYNC)) + wwv_gain(peer); } - if (up->status & MSYNC) - wwv_epoch(peer); } @@ -1369,39 +1316,41 @@ wwv_rf( * * This routine implements a virtual station process used to acquire * minute sync and to mitigate among the ten frequency and station - * combinations. During minute sync acquisition, the process probes each + * combinations. During minute sync acquisition the process probes each * frequency in turn for the minute pulse from either station, which - * involves searching through the entire epoch minute of samples. After - * minute sync acquisition, the process searches only during the probe - * window, which occupies seconds 59, 0 and 1, to construct a metric - * used to determine which frequency and station provides the best - * signal. - * - * The pulse discriminator requires that (a) the peak on-pulse sample - * amplitude must be above 2000, (b) the SNR relative to the peak - * off-pulse sample amplitude must be reduced 6 dB or more below the - * peak and (c) the maximum difference between the current and previous - * epoch indices must be less than 50 ms. A compare counter keeps track - * of the number of successive intervals which satisfy these criteria. + * involves searching through the entire minute of samples. After + * finding a candidate, the process searches only the seconds before and + * after the candidate for the signal and all other seconds for the + * noise. * * Students of radar receiver technology will discover this algorithm - * amounts to a range gate discriminator. In practice, the performance - * of this gadget is amazing. Once setting teeth in a station, it hangs - * on until the minute beep can barely be heard and long after the - * second tick and comb filter have given up. + * amounts to a range gate discriminator. The discriminator requires + * that the peak minute pulse amplitude be at least 2000 and the SNR be + * at least 6 dB. In addition after finding a candidate, The peak second + * pulse amplitude must be at least 2000, the SNR at least 6 dB and the + * difference between the current and previous epoch must be less than + * 7.5 ms, which corresponds to a frequency error of 125 PPM.. A compare + * counter keeps track of the number of successive intervals which + * satisfy these criteria. + * + * Note that, while the minute pulse is found by by the discriminator, + * the actual value is determined from the second epoch. The assumption + * is that the discriminator peak occurs about 800 ms into the second, + * so the timing is retarted to the previous second epoch. */ static void wwv_qrz( - struct peer *peer, /* peerstructure pointer */ + struct peer *peer, /* peer structure pointer */ struct sync *sp, /* sync channel structure */ - double syncx /* bandpass filtered sync signal */ + double syncx, /* bandpass filtered sync signal */ + int pdelay /* propagation delay (samples) */ ) { struct refclockproc *pp; struct wwvunit *up; char tbuf[80]; /* monitor buffer */ double snr; /* on-pulse/off-pulse ratio (dB) */ - long epoch; + long epoch, fpoch; int isgood; pp = peer->procptr; @@ -1409,171 +1358,147 @@ wwv_qrz( /* * Find the sample with peak energy, which defines the minute - * epoch. If minute sync has been acquired, search only the - * probe window; otherwise, search the entire minute. If a - * maximum has been found with good amplitude, search only the - * second before and after that position for the next maximum - * and the rest of the window for the noise. - */ - if (!(up->status & MSYNC) || up->status & SFLAG) { - sp->amp = syncx; - if (up->status & MSYNC) - epoch = up->nepoch; - else if (sp->count > 1) - epoch = sp->mepoch; - else - epoch = sp->lastpos; - if (syncx > sp->sigmax) { - sp->sigmax = syncx; - sp->pos = up->mphase; - } - if (abs(MOD(up->mphase - epoch, MINUTE)) > SYNSIZ && - syncx > sp->noise) { - sp->noise = syncx; - } + * epoch. If a sample has been found with good amplitude, + * accumulate the noise squares for all except the second before + * and after that position. + */ + isgood = up->epomax > STHR && up->eposnr > SSNR; + if (isgood) { + fpoch = up->mphase % SECOND - up->tepoch; + if (fpoch < 0) + fpoch += SECOND; + } else { + fpoch = pdelay + SYNSIZ; + } + epoch = up->mphase - fpoch; + if (epoch < 0) + epoch += MINUTE; + if (syncx > sp->maxamp) { + sp->maxamp = syncx; + sp->pos = epoch; } + if (abs((epoch - sp->lastpos) % MINUTE) > SECOND) + sp->noiamp += syncx; + + /* + * At the end of the minute, determine the epoch of the + * sync pulse, as well as the SNR and difference between + * the current and previous epoch, which represents the + * intrinsic frequency error plus jitter. + */ if (up->mphase == 0) { + sp->synmax = sqrt(sp->maxamp); + sp->synmin = sqrt(sp->noiamp / (MINUTE - 2 * SECOND)); + epoch = (sp->pos - sp->lastpos) % MINUTE; /* - * At the end of the minute, determine the epoch of the - * sync pulse, as well as the SNR and difference between - * the current and previous epoch (jitter). + * If not yet in minute sync, we have to do a little + * dance to find a valid minute sync pulse, emphasis + * valid. */ - sp->jitter = MOD(sp->pos - sp->lastpos, MINUTE); - sp->select &= ~JITRNG; - if (abs(sp->jitter) > AWND * MS) - sp->select |= JITRNG; - sp->sigmax = SQRT(sp->sigmax); - sp->noise = SQRT(sp->noise); - if (up->status & MSYNC) { - - /* - * If in minute sync, just count the runs up and - * down. - */ - if (sp->select & (DATANG | SYNCNG | JITRNG)) { - if (sp->count > 0) - sp->count--; - } else { - if (sp->count < AMAX) - sp->count++; - } - } else { + snr = wwv_snr(sp->synmax, sp->synmin); + isgood = isgood && sp->synmax > ATHR && snr > ASNR; + switch (sp->count) { - /* - * If not yet in minute sync, we have to do a - * little dance to find a valid minute sync - * pulse, emphasis valid. - */ - snr = wwv_snr(sp->sigmax, sp->noise); - isgood = sp->sigmax > ATHR && snr > ASNR && - !(sp->select & JITRNG); - switch (sp->count) { + /* + * In state 0 the station was not heard during the + * previous probe. Look for the biggest blip greater + * than the amplitude threshold in the minute and assume + * that the minute sync pulse. We're fishing here, since + * the range gate has not yet been determined. If found, + * bump to state 1. + */ + case 0: + if (sp->synmax >= ATHR) + sp->count++; + break; - /* - * In state 0 the station was not heard during - * the previous probe. Look for the biggest blip - * greater than the amplitude threshold in the - * minute and assume that the minute sync pulse. - * If found, bump to state 1. - */ - case 0: - if (sp->sigmax >= ATHR) - sp->count++; + /* + * In state 1 a candidate blip has been found and the + * next minute has been searched for another blip. If + * none are found acceptable, drop back to state 0 and + * hunt some more. Otherwise, a legitimate minute pulse + * may have been found, so bump to state 2. + */ + case 1: + if (!isgood) { + sp->count = 0; break; + } + sp->count++; + break; - /* - * In state 1 a candidate blip has been found - * and the next minute has been searched for - * another blip. If none are found greater than - * the threshold, or if the biggest blip outside - * the candidate pulse is less than 6 dB below - * the biggest blip, drop back to state 0 and - * hunt some more. Otherwise, a legitimate - * minute pulse may have been found, so bump to - * state 2. - */ - case 1: - if (sp->sigmax < ATHR) { - sp->count--; - break; - } else if (!isgood) { - break; - } - /* fall through */ - - /* - * In states 2 and above, continue to groom - * samples as before and drop back to the - * previous state if the groom fails. If it - * succeeds, bump to the next state until - * reaching the clamp, if ever. - */ - default: - if (!isgood) { - sp->count--; - break; - } - sp->mepoch = sp->pos; - if (sp->count < AMAX) - sp->count++; - break; + /* + * In states 2 and above, continue to groom samples as + * before and drop back to state 0 if the groom fails. + * If it succeeds, set the epoch and bump to the next + * state until reaching the threshold, if ever. + */ + default: + if (!isgood || abs(epoch) > AWND * MS) { + sp->count = 0; + break; } + sp->mepoch = sp->pos; + sp->count++; + break; + } + if (pp->sloppyclockflag & CLK_FLAG4) { sprintf(tbuf, - "wwv8 %d %3d %-3s %d %5.0f %5.1f %7ld %7ld %7ld", - up->port, up->gain, sp->ident, sp->count, - sp->sigmax, snr, sp->pos, sp->jitter, - MOD(sp->pos - up->nepoch - SYNSIZ, MINUTE)); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); + "wwv8 %d %3d %s %d %5.0f %5.1f %5ld %5d %ld", + up->port, up->gain, sp->refid, sp->count, + sp->synmax, snr, sp->pos, up->tepoch, + epoch); + record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG if (debug) printf("%s\n", tbuf); #endif } - sp->lastmax = sp->sigmax; sp->lastpos = sp->pos; - sp->sigmax = sp->noise = 0; + sp->maxamp = sp->noiamp = 0; } } /* - * wwv_endpoc - process receiver epoch + * wwv_endpoc - identify and acquire second sync pulse * - * This routine is called at the end of the receiver epoch. It - * determines the epoch position within the second and disciplines the - * sample clock using a frequency-lock loop (FLL). + * This routine is called at the end of the second sync interval. It + * determines the second sync epoch position within the interval and + * disciplines the sample clock using a frequency-lock loop (FLL). * - * Seconds sync is determined in the RF input routine as the maximum + * Second sync is determined in the RF input routine as the maximum * over all 8000 samples in the second comb filter. To assure accurate * and reliable time and frequency discipline, this routine performs a - * great deal of heavy-handed data filtering and grooming. + * great deal of heavy-handed heuristic data filtering and grooming. + * + * Note that, since the minute sync pulse is very wide (800 ms), precise + * minute sync epoch acquisition requires at least a rough estimate of + * the second sync pulse (5 ms). This becomes more important in choppy + * conditions at the lower frequencies at night, since sferics and + * cochannel crude can badly distort the minute pulse. */ static void wwv_endpoc( struct peer *peer, /* peer structure pointer */ - double epomax, /* epoch max */ int epopos /* epoch max position */ ) { struct refclockproc *pp; struct wwvunit *up; - static int epoch_mf[3]; /* epoch median filter */ - static int tepoch; /* median filter epoch */ - static int tspan; /* median filter span */ static int xepoch; /* last second epoch */ static int zepoch; /* last averaging interval epoch */ - static int syncnt; /* second epoch run length counter */ - static int jitcnt; /* jitter holdoff counter */ + static int syncnt; /* run length counter */ + static int maxrun; /* longest run length */ + static int mepoch; /* longest run epoch */ static int avgcnt; /* averaging interval counter */ static int avginc; /* averaging ratchet */ - static int iniflg; /* initialization flag */ char tbuf[80]; /* monitor buffer */ double dtemp; - int tmp2, tmp3; + int tmp2; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; @@ -1584,86 +1509,64 @@ wwv_endpoc( /* * A three-stage median filter is used to help denoise the - * seconds sync pulse. The median sample becomes the candidate - * epoch; the difference between the other two samples becomes - * the span, which is used currently only for debugging. + * second sync pulse. The median sample becomes the candidate + * epoch. */ epoch_mf[2] = epoch_mf[1]; epoch_mf[1] = epoch_mf[0]; epoch_mf[0] = epopos; if (epoch_mf[0] > epoch_mf[1]) { - if (epoch_mf[1] > epoch_mf[2]) { - tepoch = epoch_mf[1]; /* 0 1 2 */ - tspan = epoch_mf[0] - epoch_mf[2]; - } else if (epoch_mf[2] > epoch_mf[0]) { - tepoch = epoch_mf[0]; /* 2 0 1 */ - tspan = epoch_mf[2] - epoch_mf[1]; - } else { - tepoch = epoch_mf[2]; /* 0 2 1 */ - tspan = epoch_mf[0] - epoch_mf[1]; - } + if (epoch_mf[1] > epoch_mf[2]) + up->tepoch = epoch_mf[1]; /* 0 1 2 */ + else if (epoch_mf[2] > epoch_mf[0]) + up->tepoch = epoch_mf[0]; /* 2 0 1 */ + else + up->tepoch = epoch_mf[2]; /* 0 2 1 */ } else { - if (epoch_mf[1] < epoch_mf[2]) { - tepoch = epoch_mf[1]; /* 2 1 0 */ - tspan = epoch_mf[2] - epoch_mf[0]; - } else if (epoch_mf[2] < epoch_mf[0]) { - tepoch = epoch_mf[0]; /* 1 0 2 */ - tspan = epoch_mf[1] - epoch_mf[2]; - } else { - tepoch = epoch_mf[2]; /* 1 2 0 */ - tspan = epoch_mf[1] - epoch_mf[0]; - } + if (epoch_mf[1] < epoch_mf[2]) + up->tepoch = epoch_mf[1]; /* 2 1 0 */ + else if (epoch_mf[2] < epoch_mf[0]) + up->tepoch = epoch_mf[0]; /* 1 0 2 */ + else + up->tepoch = epoch_mf[2]; /* 1 2 0 */ } /* - * If the epoch candidate is within 1 ms of the last one, the - * new candidate replaces the last one and the jitter counter is - * reset; otherwise, the candidate is ignored and the jitter - * counter is incremented. If the jitter counter exceeds the - * frequency averaging interval, the new candidate replaces the - * old one anyway. The compare counter is incremented if the new - * candidate is identical to the last one; otherwise, it is - * forced to zero. If the compare counter increments to 10, the - * epoch is reset and the receiver second epoch is set. - * - * Careful attention to detail here. If the signal amplitude - * falls below the threshold or if no stations are heard, we - * certainly cannot be in sync. + * If the signal amplitude or SNR fall below thresholds or if no + * stations are heard, dim the second sync lamp and start over. */ - tmp2 = MOD(tepoch - xepoch, SECOND); - if (up->epomax < STHR || !(up->status & (SELV | SELH))) { - up->status &= ~SSYNC; - jitcnt = syncnt = avgcnt = 0; - } else if (abs(tmp2) <= MS || jitcnt >= (MINAVG << up->avgint)) - { - jitcnt = 0; - if (tmp2 != 0) { - xepoch = tepoch; - syncnt = 0; - } else { - if (syncnt < SCMP) { - syncnt++; - } else { - up->status |= SSYNC; - up->swatch = 0; - up->repoch = tepoch; - up->yepoch = up->repoch; - if (up->yepoch < 0) - up->yepoch += SECOND; - } - } - avgcnt++; + if (!(up->status & (SELV | SELH)) || up->epomax < STHR || + up->eposnr < SSNR) { + up->status &= ~(SSYNC | FGATE); + avgcnt = syncnt = maxrun = 0; + return; + } + avgcnt++; + + /* + * If the epoch candidate is the same as the last one, increment + * the compare counter. If not, save the length and epoch of the + * current run for use later and reset the counter. + */ + tmp2 = (up->tepoch - xepoch) % SECOND; + if (tmp2 == 0) { + syncnt++; } else { - jitcnt++; - syncnt = avgcnt = 0; + if (maxrun > 0 && mepoch == xepoch) { + maxrun += syncnt; + } else if (syncnt > maxrun) { + maxrun = syncnt; + mepoch = xepoch; + } + syncnt = 0; } - if (!(up->status & SSYNC) && 0) { + if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & (SSYNC | + MSYNC))) { sprintf(tbuf, - "wwv1 %2d %04x %5.0f %2d %5.0f %5d %5d %5d %2d %4d", - up->rsec, up->status, up->epomax, avgcnt, epomax, - tepoch, tspan, tmp2, syncnt, jitcnt); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); + "wwv1 %04x %5.0f %5.1f %5d %5d %4d %4d", + up->status, up->epomax, up->eposnr, up->tepoch, + tmp2, avgcnt, syncnt); + record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG if (debug) printf("%s\n", tbuf); @@ -1671,72 +1574,122 @@ wwv_endpoc( } /* - * The sample clock frequency is disciplined using a first-order + * The sample clock frequency is disciplined using a first order * feedback loop with time constant consistent with the Allan - * intercept of typical computer clocks. The loop update is - * calculated each averaging interval from the epoch change in - * 125-us units and interval length in seconds. The interval is - * doubled after four intervals where epoch change is not more - * than one sample. + * intercept of typical computer clocks. * + * The frequency update is calculated from the epoch change in + * 125-us units divided by the averaging interval in seconds. * The averaging interval affects other receiver functions, - * including the the 1000/1200-Hz comb filter and sample clock + * including the the 1000/1200-Hz comb filter and codec clock * loop. It also affects the 100-Hz subcarrier loop and the bit * and digit comparison counter thresholds. */ - tmp3 = MOD(tepoch - zepoch, SECOND); - if (avgcnt >= (MINAVG << up->avgint)) { - if (abs(tmp3) < MS) { - dtemp = (double)tmp3 / avgcnt; - up->freq += dtemp / SYNCTC; - if (up->freq > MAXFREQ) - up->freq = MAXFREQ; - else if (up->freq < -MAXFREQ) - up->freq = -MAXFREQ; - if (abs(tmp3) <= 1 && up->avgint < MAXAVG) { - if (avginc < 4) { + if (avgcnt < up->avgint) { + xepoch = up->tepoch; + return; + } + + /* + * During the averaging interval the longest run of identical + * epoches is determined. If the longest run is at least 10 + * seconds, the SSYNC bit is lit and the value becomes the + * reference epoch for the next interval. If not, the second + * synd lamp is dark and flashers set. + */ + if (maxrun > 0 && mepoch == xepoch) { + maxrun += syncnt; + } else if (syncnt > maxrun) { + maxrun = syncnt; + mepoch = xepoch; + } + xepoch = up->tepoch; + if (maxrun > SCMP) { + up->status |= SSYNC; + up->yepoch = mepoch; + } else { + up->status &= ~SSYNC; + } + + /* + * If the epoch change over the averaging interval is less than + * 1 ms, the frequency is adjusted, but clamped at +-125 PPM. If + * greater than 1 ms, the counter is decremented. If the epoch + * change is less than 0.5 ms, the counter is incremented. If + * the counter increments to +3, the averaging interval is + * doubled and the counter set to zero; if it increments to -3, + * the interval is halved and the counter set to zero. + * + * Here be spooks. From careful observations, the epoch + * sometimes makes a long run of identical samples, then takes a + * lurch due apparently to lost interrupts or spooks. If this + * happens, the epoch change times the maximum run length will + * be greater than the averaging interval, so the lurch should + * be believed but the frequency left alone. Really intricate + * here. + */ + if (maxrun == 0) + mepoch = up->tepoch; + dtemp = (mepoch - zepoch) % SECOND; + if (up->status & FGATE) { + if (abs(dtemp) < MAXFREQ * MINAVG) { + if (maxrun * abs(mepoch - zepoch) < + avgcnt) { + up->freq += dtemp / avgcnt; + if (up->freq > MAXFREQ) + up->freq = MAXFREQ; + else if (up->freq < -MAXFREQ) + up->freq = -MAXFREQ; + } + if (abs(dtemp) < MAXFREQ * MINAVG / 2) { + if (avginc < 3) { avginc++; } else { + if (up->avgint < MAXAVG) { + up->avgint <<= 1; + avginc = 0; + } + } + } + } else { + if (avginc > -3) { + avginc--; + } else { + if (up->avgint > MINAVG) { + up->avgint >>= 1; avginc = 0; - up->avgint++; } } - if (up->avgint < MAXAVG) { - sprintf(tbuf, - "wwv2 %2d %04x %5.0f %5d %5d %2d %2d %6.1f %6.1f", - up->rsec, up->status, up->epomax, - MINAVG << up->avgint, avgcnt, - avginc, tmp3, dtemp / SECOND * 1e6, - up->freq / SECOND * 1e6); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats( - &peer->srcadr, tbuf); + } + } + if (pp->sloppyclockflag & CLK_FLAG4) { + sprintf(tbuf, + "wwv2 %04x %4.0f %4d %4d %2d %4d %4.0f %6.1f", + up->status, up->epomax, mepoch, maxrun, avginc, + avgcnt, dtemp, up->freq * 1e6 / SECOND); + record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG - if (debug) - printf("%s\n", tbuf); + if (debug) + printf("%s\n", tbuf); #endif /* DEBUG */ - } - } - zepoch = tepoch; - avgcnt = 0; } + up->status |= FGATE; + zepoch = mepoch; + avgcnt = syncnt = maxrun = 0; } /* - * wwv_epoch - main loop + * wwv_epoch - epoch scanner * - * This routine establishes receiver and transmitter epoch - * synchronization and determines the data subcarrier pulse length. - * Receiver synchronization is determined by the minute sync pulse - * detected in the wwv_rf() routine and the second sync pulse detected - * in the wwv_epoch() routine. This establishes when to sample the data - * subcarrier in-phase signal for the maximum level and noise level and - * when to determine the pulse length. The transmitter second leads the - * receiver second by the propagation delay, receiver delay and filter - * delay of this program. It establishes the clock time and implements - * the sometimes idiosyncratic conventional clock time and civil - * calendar. + * This routine scans the receiver second epoch to determine the signal + * amplitudes and pulse timings. Receiver synchronization is determined + * by the minute sync pulse detected in the wwv_rf() routine and the + * second sync pulse detected in the wwv_epoch() routine. A pulse width + * discriminator extracts data signals from the 100-Hz subcarrier. The + * transmitted signals are delayed by the propagation delay, receiver + * delay and filter delay of this program. Delay corrections are + * introduced separately for WWV and WWVH. * * Most communications radios use a highpass filter in the audio stages, * which can do nasty things to the subcarrier phase relative to the @@ -1750,152 +1703,96 @@ wwv_epoch( struct peer *peer /* peer structure pointer */ ) { - static double dpulse; /* data pulse length */ struct refclockproc *pp; struct wwvunit *up; struct chan *cp; - struct sync *sp; - l_fp offset; /* NTP format offset */ + static double dpulse; /* data pulse length */ double dtemp; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; /* - * Sample the minute sync pulse amplitude at epoch 800 for both + * Sample the minute sync pulse envelopes at epoch 800 for both * the WWV and WWVH stations. This will be used later for - * channel mitigation. + * channel and station mitigation. Note that the seconds epoch + * is set here well before the end of the second to make sure we + * never seet the epoch backwards. */ - cp = &up->mitig[up->achan]; if (up->rphase == 800 * MS) { - sp = &cp->wwv; - sp->synamp = SQRT(sp->amp); - sp = &cp->wwvh; - sp->synamp = SQRT(sp->amp); + up->repoch = up->yepoch; + cp = &up->mitig[up->achan]; + cp->wwv.synamp = cp->wwv.amp; + cp->wwvh.synamp = cp->wwvh.amp; } - if (up->rsec == 0) { - up->sigamp = up->datsnr = 0; - } else { - - /* - * Estimate the noise level by integrating the I-channel - * energy at epoch 30 ms. - */ - if (up->rphase == 30 * MS) { - if (!(up->status & SFLAG)) - up->noiamp += (up->irig - up->noiamp) / - (MINAVG << up->avgint); - else - cp->noiamp += (SQRT(up->irig * - up->irig + up->qrig * up->qrig) - - cp->noiamp) / 8; - - /* - * Strobe the peak I-channel data signal at epoch 200 - * ms. Compute the SNR and adjust the 100-Hz reference - * oscillator phase using the Q-channel data signal at - * that epoch. Save the envelope amplitude for the probe - * channel. - */ - } else if (up->rphase == 200 * MS) { - if (!(up->status & SFLAG)) { - up->sigamp = up->irig; - if (up->sigamp < 0) - up->sigamp = 0; - up->datsnr = wwv_snr(up->sigamp, - up->noiamp); - up->datpha = up->qrig / (MINAVG << - up->avgint); - if (up->datpha >= 0) { - up->datapt++; - if (up->datapt >= 80) - up->datapt -= 80; - } else { - up->datapt--; - if (up->datapt < 0) - up->datapt += 80; - } - } else { - up->sigamp = SQRT(up->irig * up->irig + - up->qrig * up->qrig); - up->datsnr = wwv_snr(up->sigamp, - cp->noiamp); - } + /* + * Sample the data subcarrier at epoch 15 ms, giving a guard + * time of +-15 ms from the beginning of the second until the + * pulse rises at 30 ms. The I-channel amplitude is used to + * calculate the slice level. The envelope amplitude is used + * during the probe seconds to determine the SNR. There is a + * compromise here; we want to delay the sample as long as + * possible to give the radio time to change frequency and the + * AGC to stabilize, but as early as possible if the second + * epoch is not exact. + */ + if (up->rphase == 15 * MS) { + up->noiamp = up->irig * up->irig + up->qrig * up->qrig; - /* - * The slice level is set half way between the peak - * signal and noise levels. Strobe the negative zero - * crossing after epoch 200 ms and record the epoch at - * that time. This defines the length of the data pulse, - * which will later be converted into scaled bit - * probabilities. - */ - } else if (up->rphase > 200 * MS) { - dtemp = (up->sigamp + up->noiamp) / 2; - if (up->irig < dtemp && dpulse == 0) - dpulse = up->rphase; + /* + * Sample the data subcarrier at epoch 215 ms, giving a guard + * time of +-15 ms from the earliest the pulse peak can be + * reached to the earliest it can begin to fall. For the data + * channel latch the I-channel amplitude for all except the + * probe seconds and adjust the 100-Hz reference oscillator + * phase using the Q-channel amplitude at this epoch. For the + * probe channel latch the envelope amplitude. + */ + } else if (up->rphase == 215 * MS) { + up->sigsig = up->irig; + if (up->sigsig < 0) + up->sigsig = 0; + up->datpha = up->qrig / up->avgint; + if (up->datpha >= 0) { + up->datapt++; + if (up->datapt >= 80) + up->datapt -= 80; + } else { + up->datapt--; + if (up->datapt < 0) + up->datapt += 80; } - } + up->sigamp = up->irig * up->irig + up->qrig * up->qrig; /* - * At the end of the transmitter second, crank the clock state - * machine. Note we have to be careful to set the transmitter - * epoch at the same time as the receiver epoch to be sure the - * right propagation delay is used. We don't bother the heavy - * machinery unless the clock is set. + * The slice level is set half way between the peak signal and + * noise levels. Sample the negative zero crossing after epoch + * 200 ms and record the epoch at that time. This defines the + * length of the data pulse, which will later be converted into + * scaled bit probabilities. */ - up->tphase++; - if (up->epoch == up->yepoch) { - wwv_tsec(up); - up->tphase = 0; - - /* - * Determine the current offset from the time of century - * and the sample timestamp, but only if the SYNERR - * alarm has not been raised in the present or previous - * minute. - */ - if (!(up->status & SFLAG) && up->status & INSYNC && - (up->alarm & (3 << SYNERR)) == 0) { - pp->second = up->tsec; - pp->minute = up->decvec[MN].digit + - up->decvec[MN + 1].digit * 10; - pp->hour = up->decvec[HR].digit + - up->decvec[HR + 1].digit * 10; - pp->day = up->decvec[DA].digit + up->decvec[DA + - 1].digit * 10 + up->decvec[DA + 2].digit * - 100; - pp->year = up->decvec[YR].digit + - up->decvec[YR + 1].digit * 10; - if (pp->year < UTCYEAR) - pp->year += 2000; - else - pp->year += 1900; - - /* - * We have to simulate refclock_process() here, - * since the fudgetime gets added much earlier - * than this. - */ - pp->lastrec = up->timestamp; - L_CLR(&offset); - if (!clocktime(pp->day, pp->hour, pp->minute, - pp->second, GMT, pp->lastrec.l_ui, - &pp->yearstart, &offset.l_ui)) - up->errflg = CEVNT_BADTIME; - else - refclock_process_offset(pp, offset, - pp->lastrec, 0.); - } + } else if (up->rphase > 200 * MS) { + dtemp = (up->sigsig + sqrt(up->noiamp)) / 2; + if (up->irig < dtemp && dpulse == 0) + dpulse = up->rphase; } /* - * At the end of the receiver second, process the data bit and - * update the decoding matrix probabilities. + * At the end of the second crank the clock state machine and + * adjust the codec gain. Note the epoch is buffered from the + * center of the second in order to avoid jitter while the + * seconds synch is diddling the epoch. Then, determine the true + * offset and update the median filter in the driver interface. + * + * Sample the data subcarrier envelope at the end of the second + * to determine the SNR for the pulse. This gives a guard time + * of +-30 ms from the decay of the longest pulse to the rise of + * the next pulse. */ up->rphase++; - if (up->epoch == up->repoch) { + if (up->mphase % SECOND == up->repoch) { + up->datsnr = wwv_snr(up->sigsig, sqrt(up->noiamp)); wwv_rsec(peer, dpulse); wwv_gain(peer); up->rphase = dpulse = 0; @@ -1915,9 +1812,7 @@ wwv_epoch( * for leap years) or 31 December (day 365 or 366 for leap years) is * augmented by one second numbered 60. This is accomplished by * extending the minute interval by one second and teaching the state - * machine to ignore it. BTW, stations WWV/WWVH cowardly kill the - * transmitter carrier for a few seconds around the leap to avoid icky - * details of transmission format during the leap. + * machine to ignore it. */ static void wwv_rsec( @@ -1932,9 +1827,14 @@ wwv_rsec( struct wwvunit *up; struct chan *cp; struct sync *sp, *rp; + l_fp offset; /* offset in NTP seconds */ double bit; /* bit likelihood */ char tbuf[80]; /* monitor buffer */ int sw, arg, nsec; +#ifdef IRIG_SUCKS + int i; + l_fp ltemp; +#endif /* IRIG_SUCKS */ pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; @@ -1969,65 +1869,105 @@ wwv_rsec( * Probe channel stuff * * The WWV/H format contains data pulses in second 59 (position - * identifier) and second 1 (not used), and the minute sync - * pulse in second 0. At the end of second 58, we QSYed to the - * probe channel, which rotates over all WWV/H frequencies. At - * the end of second 59, we latched the sync noise and tested - * for data bit error. At the end of second 0, we now latch the - * sync peak. + * identifier), second 1 (not used) and the minute sync pulse in + * second 0. At the end of second 58, QSY to the probe channel, + * which rotates over all WWV/H frequencies. At the end of + * second 1 QSY back to the data channel. + * + * At the end of second 0 save the minute sync pulse peak value + * previously latched at 800 ms. */ case SYNC2: /* 0 */ cp = &up->mitig[up->achan]; - sp = &cp->wwv; - sp->synmax = sp->synamp; - sp = &cp->wwvh; - sp->synmax = sp->synamp; + cp->wwv.synmax = sqrt(cp->wwv.synamp); + cp->wwvh.synmax = sqrt(cp->wwvh.synamp); break; /* - * At the end of second 1, latch and average the sync noise and - * test for data bit error. Set SYNCNG if the sync pulse - * amplitude and SNR are not above thresholds. Set DATANG if - * data error occured on both second 59 and second 1. Finally, - * QSY back to the data channel. + * At the end of second 1 determine the minute sync pulse + * amplitude and SNR and set SYNCNG if these values are below + * thresholds. Determine the data pulse amplitude and SNR and + * set DATANG if these values are below thresholds. Set ERRRNG + * if data pulses in second 59 and second 1 are decoded in + * error. Shift a 1 into the reachability register if SYNCNG and + * DATANG are both lit; otherwise shift a 0. Ignore ERRRNG for + * the present. The number of 1 bits in the last six intervals + * represents the channel metric used by the mitigation routine. + * Finally, QSY back to the data channel. */ case SYNC3: /* 1 */ cp = &up->mitig[up->achan]; - if (up->sigamp < DTHR || up->datsnr < DSNR) - cp->errcnt++; + cp->sigamp = sqrt(up->sigamp); + cp->noiamp = sqrt(up->noiamp); + cp->datsnr = wwv_snr(cp->sigamp, cp->noiamp); + /* + * WWV station + */ sp = &cp->wwv; - sp->synmin = (sp->synmin + sp->synamp) / 2; + sp->synmin = sqrt((sp->synmin + sp->synamp) / 2.); sp->synsnr = wwv_snr(sp->synmax, sp->synmin); - sp->select &= ~(DATANG | SYNCNG); + sp->select &= ~(SYNCNG | DATANG | ERRRNG); if (sp->synmax < QTHR || sp->synsnr < QSNR) sp->select |= SYNCNG; - if (cp->errcnt > 1) + if (cp->sigamp < XTHR || cp->datsnr < XSNR) sp->select |= DATANG; + if (up->errcnt > 2) + sp->select |= ERRRNG; + sp->reach <<= 1; + if (sp->reach & (1 << AMAX)) + sp->count--; + if (!(sp->select & (SYNCNG | DATANG))) { + sp->reach |= 1; + sp->count++; + } + /* + * WWVH station + */ rp = &cp->wwvh; - rp->synmin = (rp->synmin + rp->synamp) / 2; + rp->synmin = sqrt((rp->synmin + rp->synamp) / 2.); rp->synsnr = wwv_snr(rp->synmax, rp->synmin); - rp->select &= ~(DATANG | SYNCNG); + rp->select &= ~(SYNCNG | DATANG | ERRRNG); if (rp->synmax < QTHR || rp->synsnr < QSNR) rp->select |= SYNCNG; - if (cp->errcnt > 1) + if (cp->sigamp < XTHR || cp->datsnr < XSNR) rp->select |= DATANG; + if (up->errcnt > 2) + rp->select |= ERRRNG; + rp->reach <<= 1; + if (rp->reach & (1 << AMAX)) + rp->count--; + if (!(rp->select & (SYNCNG | DATANG | ERRRNG))) { + rp->reach |= 1; + rp->count++; + } - cp->errcnt = 0; - sprintf(tbuf, - "wwv5 %d %3d %-3s %04x %d %.0f/%.1f/%ld %s %04x %d %.0f/%.1f/%ld", - up->port, up->gain, sp->ident, sp->select, - sp->count, sp->synmax, sp->synsnr, sp->jitter, - rp->ident, rp->select, rp->count, rp->synmax, - rp->synsnr, rp->jitter); - if (pp->sloppyclockflag & CLK_FLAG4) + /* + * Set up for next minute. + */ + if (pp->sloppyclockflag & CLK_FLAG4) { + sprintf(tbuf, + "wwv5 %2d %04x %3d %4d %d %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f", + up->port, up->status, up->gain, up->yepoch, + up->errcnt, cp->sigamp, cp->datsnr, + sp->refid, sp->reach & 0xffff, + wwv_metric(sp), sp->synmax, sp->synsnr, + rp->refid, rp->reach & 0xffff, + wwv_metric(rp), rp->synmax, rp->synsnr); record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG - if (debug) - printf("%s\n", tbuf); + if (debug) + printf("%s\n", tbuf); #endif /* DEBUG */ + } +#ifdef ICOM + if (up->fd_icom > 0) + wwv_qsy(peer, up->dchan); +#endif /* ICOM */ up->status &= ~SFLAG; + up->errcnt = 0; + up->alarm = 0; wwv_newchan(peer); break; @@ -2038,7 +1978,9 @@ wwv_rsec( * considered valid. Bits not used in the digit are forced to * zero and not checked for errors. */ - case COEF1: /* 10-13 */ + case COEF: /* 4-7, 10-13, 15-17, 20-23, + 25-26, 30-33, 35-38, 40-41, + 51-54 */ if (up->status & DGATE) up->status |= BGATE; bcddld[arg] = bit; @@ -2048,13 +1990,6 @@ wwv_rsec( bcddld[arg] = 0; break; - case COEF: /* 4-7, 15-17, 20-23, 25-26, - 30-33, 35-38, 40-41, 51-54 */ - if (up->status & DGATE || !(up->status & DSYNC)) - up->status |= BGATE; - bcddld[arg] = bit; - break; - /* * Correlate coefficient vector with each valid digit vector and * save in decoding matrix. We step through the decoding matrix @@ -2081,122 +2016,207 @@ wwv_rsec( * Miscellaneous bits. If above the positive threshold, declare * 1; if below the negative threshold, declare 0; otherwise * raise the SYMERR alarm. At the end of second 58, QSY to the - * probe channel. + * probe channel. The design is intended to preserve the bits + * over periods of signal loss. */ case MSC20: /* 55 */ wwv_corr4(peer, &up->decvec[YR + 1], bcddld, bcd9); /* fall through */ - case MSCBIT: /* 2, 3, 50, 56-57 */ + case MSCBIT: /* 2-3, 50, 56-57 */ if (bitvec[up->rsec] > BTHR) up->misc |= arg; else if (bitvec[up->rsec] < -BTHR) up->misc &= ~arg; else - up->alarm |= 1 << SYMERR; + up->alarm |= SYMERR; break; + /* + * Save the data channel gain, then QSY to the probe channel. + */ case MSC21: /* 58 */ if (bitvec[up->rsec] > BTHR) up->misc |= arg; else if (bitvec[up->rsec] < -BTHR) up->misc &= ~arg; else - up->alarm |= 1 << SYMERR; - up->schan = (up->schan + 1) % NCHAN; - wwv_qsy(peer, up->schan); - up->status |= SFLAG; + up->alarm |= SYMERR; + up->mitig[up->dchan].gain = up->gain; +#ifdef ICOM + if (up->fd_icom > 0) { + up->schan = (up->schan + 1) % NCHAN; + wwv_qsy(peer, up->schan); + } +#endif /* ICOM */ + up->status |= SFLAG | SELV | SELH; + up->errbit = up->errcnt; + up->errcnt = 0; break; /* * The endgames * - * Second 59 contains the first data pulse of the probe - * sequence. Check it for validity and establish the noise floor - * for the minute sync SNR. + * During second 59 the receiver and codec AGC are settling + * down, so the data pulse is unusable. At the end of this + * second, latch the minute sync pulse noise floor. Then do the + * minute processing and update the system clock. If a leap + * second sail on to the next second (60); otherwise, set up for + * the next minute. */ case MIN1: /* 59 */ cp = &up->mitig[up->achan]; - if (up->sigamp < DTHR || up->datsnr < DSNR) - cp->errcnt++; - sp = &cp->wwv; - sp->synmin = sp->synamp; - sp = &cp->wwvh; - sp->synmin = sp->synamp; + cp->wwv.synmin = cp->wwv.synamp; + cp->wwvh.synmin = cp->wwvh.synamp; /* - * If SECWARN is set on the last minute of 30 June or 31 - * December, LEPSEC bit is set. At the end of the minute - * in which LEPSEC is set the transmitter and receiver - * insert an extra second (60) in the timescale and the - * minute sync skips a second. We only get to test this - * wrinkle at intervals of about 18 months, the actual - * mileage may vary. + * Dance the leap if necessary and the kernel has the + * right stuff. Then, wind up the clock and initialize + * for the following minute. If the leap dance, note the + * kernel is armed one second before the actual leap is + * scheduled. */ - if (up->tsec == 60) { - up->status &= ~LEPSEC; - break; - } - /* fall through */ - - /* - * If all nine clock digits are valid and the SYNERR alarm is - * not raised in the current or previous second, the clock is - * set or validated. If at least one digit is set, which by - * design must be the minute units digit, the clock state - * machine begins to count the minutes. - */ - case MIN2: /* 59/60 */ - up->minset = ((current_time - peer->update) + 30) / 60; - if (up->digcnt > 0) - up->status |= DSYNC; - if (up->digcnt >= 9 && (up->alarm & (3 << SYNERR)) == 0) - { + if (up->status & SSYNC && up->digcnt >= 9) up->status |= INSYNC; - up->watch = 0; - } - pp->lencode = timecode(up, pp->a_lastcode); - if (up->misc & SECWAR) + if (up->status & LEPDAY) { pp->leap = LEAP_ADDSECOND; - else + } else { pp->leap = LEAP_NOWARNING; - refclock_receive(peer); + wwv_tsec(up); + nsec = up->digcnt = 0; + } + pp->lencode = timecode(up, pp->a_lastcode); record_clock_stats(&peer->srcadr, pp->a_lastcode); #ifdef DEBUG if (debug) printf("wwv: timecode %d %s\n", pp->lencode, pp->a_lastcode); #endif /* DEBUG */ + if (up->status & INSYNC && up->watch < HOLD) + refclock_receive(peer); + break; - /* - * The ultimate watchdog is the interval since the - * reference clock interface code last received an - * update from this driver. If the interval is greater - * than a couple of days, manual intervention is - * probably required, so the program resets and tries to - * resynchronized from scratch. - */ - if (up->minset > PANIC) - up->status = 0; - up->alarm = (up->alarm & ~0x8888) << 1; - up->nepoch = (up->mphase + SYNSIZ) % MINUTE; - up->errcnt = up->digcnt = nsec = 0; + /* + * If LEPDAY is set on the last minute of 30 June or 31 + * December, the LEPSEC bit is set. At the end of the minute in + * which LEPSEC is set the transmitter and receiver insert an + * extra second (60) in the timescale and the minute sync skips + * a second. We only get to test this wrinkle at intervals of + * about 18 months; the actual mileage may vary. + */ + case MIN2: /* 60 */ + wwv_tsec(up); + nsec = up->digcnt = 0; break; } - if (!(up->status & DSYNC)) { + + /* + * If digit sync has not been acquired before timeout or if no + * station has been heard, game over and restart from scratch. + */ + if (!(up->status & DSYNC) && (!(up->status & (SELV | SELH)) || + up->watch > DIGIT)) { + wwv_newgame(peer); + return; + } + + /* + * If no timestamps have been struck before timeout, game over + * and restart from scratch. + */ + if (up->watch > PANIC) { + wwv_newgame(peer); + return; + } + pp->disp += AUDIO_PHI; + up->rsec = nsec; + +#ifdef IRIG_SUCKS + /* + * 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(<emp, &pp->lastref); + if (ltemp.l_f < 0) + ltemp.l_i = -1; + else + ltemp.l_i = 0; + pp->lastref = pp->lastrec; + if (!L_ISNEG(<emp)) + L_CLR(&up->wigwag); + else + L_ADD(&up->wigwag, <emp); + 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; +#endif /* IRIG_SUCKS */ + + /* + * If victory has been declared and seconds sync is lit, strike + * a timestamp. It should not be a surprise, especially if the + * radio is not tunable, that sometimes no stations are above + * the noise and the reference ID set to NONE. + */ + if (up->status & INSYNC && up->status & SSYNC) { + pp->second = up->rsec; + pp->minute = up->decvec[MN].digit + up->decvec[MN + + 1].digit * 10; + pp->hour = up->decvec[HR].digit + up->decvec[HR + + 1].digit * 10; + pp->day = up->decvec[DA].digit + up->decvec[DA + + 1].digit * 10 + up->decvec[DA + 2].digit * 100; + pp->year = up->decvec[YR].digit + up->decvec[YR + + 1].digit * 10; + pp->year += 2000; + L_CLR(&offset); + if (!clocktime(pp->day, pp->hour, pp->minute, + pp->second, GMT, up->timestamp.l_ui, + &pp->yearstart, &offset.l_ui)) { + up->errflg = CEVNT_BADTIME; + } else { + up->watch = 0; + pp->disp = 0; + refclock_process_offset(pp, offset, + up->timestamp, PDELAY); + } + } + if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & + DSYNC)) { sprintf(tbuf, - "wwv3 %2d %04x %5.0f %5.0f %5.0f %5.1f %5.0f %5.0f", - up->rsec, up->status, up->epomax, up->sigamp, - up->datpha, up->datsnr, bit, bitvec[up->rsec]); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); + "wwv3 %2d %04x %5.0f %5.1f %5.0f %5.1f %5.0f", + up->rsec, up->status, up->epomax, up->eposnr, + up->sigsig, up->datsnr, bit); + record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG if (debug) printf("%s\n", tbuf); #endif /* DEBUG */ - } - up->rsec = up->tsec = nsec; - return; + } } @@ -2209,7 +2229,12 @@ wwv_rsec( * bit is bad, a bit error is declared and the probabilities are forced * to zero. Otherwise, the data gate is enabled and the probabilities * are calculated. Note that the data matched filter contributes half - * the pulse width, or 85 ms.. + * the pulse width, or 85 ms. + * + * It's important to observe that there are three conditions to + * determine: average to +1 (hit), average to -1 (miss) or average to + * zero (erasure). The erasure condition results from insufficient + * signal (noise) and has no bias toward either a hit or miss. */ static double wwv_data( @@ -2224,14 +2249,16 @@ wwv_data( dpulse = pulse - DATSIZ / 2; /* - * If the data amplitude or SNR are below threshold or if the - * pulse length is less than 170 ms, declare an erasure. + * If no station is being tracked, if either the data amplitude + * or SNR are below threshold or if the pulse length is less + * than 170 ms, declare an erasure. */ - if (up->sigamp < DTHR || up->datsnr < DSNR || dpulse < DATSIZ) { + if (!(up->status & (SELV | SELH)) || up->sigsig < DTHR || + up->datsnr < DSNR || dpulse < DATSIZ) { up->status |= DGATE; up->errcnt++; if (up->errcnt > MAXERR) - up->alarm |= 1 << MODERR; + up->alarm |= MODERR; return (0); } @@ -2325,44 +2352,59 @@ wwv_corr4( /* * The maximum likelihood digit is compared with the current * clock digit. The difference represents the decoding phase - * error. If the digit probability and likelihood are good and - * the difference stays the same for a number of comparisons, - * the clock digit is reset to the maximum likelihood digit. + * error. If the clock is not yet synchronized, the phase error + * is corrected even of the digit probability and likelihood are + * below thresholds. This avoids lengthy averaging times should + * a carry mistake occur. However, the digit is not declared + * synchronized until these values are above thresholds and the + * last five decoded values are identical. If the clock is + * synchronized, the phase error is not corrected unless the + * last five digits are all above thresholds and identical. This + * avoids mistakes when the signal is coming out of the noise + * and the SNR is very marginal. */ diff = mldigit - vp->digit; if (diff < 0) diff += vp->radix; if (diff != vp->phase) { - vp->phase = diff; vp->count = 0; + vp->phase = diff; } - if (vp->digprb < BTHR || vp->digsnr < BSNR) { + if (vp->digsnr < BSNR) { vp->count = 0; - up->alarm |= 1 << SYMERR; - } else if (vp->count < BCMP) { + up->alarm |= SYMERR; + } else if (vp->digprb < BTHR) { + vp->count = 0; + up->alarm |= SYMERR; if (!(up->status & INSYNC)) { vp->phase = 0; vp->digit = mldigit; } + } else if (vp->count < BCMP) { vp->count++; + up->status |= DSYNC; + if (!(up->status & INSYNC)) { + vp->phase = 0; + vp->digit = mldigit; + } } else { vp->phase = 0; vp->digit = mldigit; up->digcnt++; } if (vp->digit != mldigit) - up->alarm |= 1 << DECERR; - if (!(up->status & INSYNC)) { + up->alarm |= DECERR; + if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & + INSYNC)) { sprintf(tbuf, "wwv4 %2d %04x %5.0f %2d %d %d %d %d %5.0f %5.1f", - up->rsec, up->status, up->epomax, vp->radix, + up->rsec, up->status, up->epomax, vp->radix, vp->digit, vp->mldigit, vp->phase, vp->count, vp->digprb, vp->digsnr); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); + record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG - if (debug) - printf("%s\n", tbuf); + if (debug) + printf("%s\n", tbuf); #endif /* DEBUG */ } up->status &= ~BGATE; @@ -2370,13 +2412,11 @@ wwv_corr4( /* - * wwv_tsec - transmitter second processing + * wwv_tsec - transmitter minute processing * - * This routine is called at the end of the transmitter second. It + * This routine is called at the end of the transmitter minute. It * implements a state machine that advances the logical clock subject to - * the funny rules that govern the conventional clock and calendar. Note - * that carries from the least significant (minutes) digit are inhibited - * until that digit is synchronized. + * the funny rules that govern the conventional clock and calendar. */ static void wwv_tsec( @@ -2386,18 +2426,10 @@ wwv_tsec( int minute, day, isleap; int temp; - up->tsec++; - if (up->tsec < 60 || up->status & LEPSEC) - return; - up->tsec = 0; - /* - * Advance minute unit of the day. If the minute unit is not - * synchronized, go no further. + * Advance minute unit of the day. */ temp = carry(&up->decvec[MN]); /* minute units */ - if (!(up->status & DSYNC)) - return; /* * Propagate carries through the day. @@ -2410,8 +2442,10 @@ wwv_tsec( temp = carry(&up->decvec[HR + 1]); /* - * Decode the current minute and day. Set the leap second enable - * bit on the last minute of 30 June and 31 December. + * Decode the current minute and day. Set leap day if the + * timecode leap bit is set on 30 June or 31 December. Set leap + * minute if the last minute on leap day. This code fails in + * 2400 AD. */ minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10 + up->decvec[HR].digit * 60 + up->decvec[HR + @@ -2419,9 +2453,16 @@ wwv_tsec( day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 + up->decvec[DA + 2].digit * 100; isleap = (up->decvec[YR].digit & 0x3) == 0; - if (minute == 1439 && (day == (isleap ? 182 : 183) || day == - (isleap ? 365 : 366)) && up->misc & SECWAR) + if (up->misc & SECWAR && (day == (isleap ? 182 : 183) || day == + (isleap ? 365 : 366)) && up->status & INSYNC && up->status & + SSYNC) + up->status |= LEPDAY; + else + up->status &= ~LEPDAY; + if (up->status & LEPDAY && minute == 1439) up->status |= LEPSEC; + else + up->status &= ~LEPSEC; /* * Roll the day if this the first minute and propagate carries @@ -2459,8 +2500,8 @@ wwv_tsec( * carry - process digit * * This routine rotates a likelihood vector one position and increments - * the clock digit modulo the radix. It returns the new clock digit - - * zero if a carry occured. Once synchronized, the clock digit will + * 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. */ static int @@ -2517,19 +2558,36 @@ wwv_snr( return (rval); } + /* * wwv_newchan - change to new data channel * - * Assuming the radio can be tuned by this program, it actually appears - * as a 10-channel receiver, one channel for each of WWV and WWVH on - * each of five frequencies. While the radio is tuned to the working - * data channel (frequency and station) for most of the minute, during - * seconds 59, 0 and 1 the radio is tuned to a probe channel, in order - * to pick up minute sync and data pulses. The search for WWV and WWVH - * stations operates simultaneously, with WWV on 1000 Hz and WWVH on - * 1200 Hz. The probe channel rotates for each minute over the five - * frequencies. At the end of each rotation, this routine mitigates over - * all channels and chooses the best frequency and station. + * The radio actually appears to have ten channels, one channel for each + * of five frequencies and each of two stations (WWV and WWVH), although + * if not tunable only the 15 MHz channels appear live. While the radio + * is tuned to the working data channel frequency and station for most + * of the minute, during seconds 59, 0 and 1 the radio is tuned to a + * probe frequency in order to search for minute sync pulse and data + * subcarrier from other transmitters. + * + * The search for WWV and WWVH operates simultaneously, with WWV minute + * sync pulse at 1000 Hz and WWVH at 1200 Hz. The probe frequency + * rotates each minute over 2.5, 5, 10, 15 and 20 MHz in order and yes, + * we all know WWVH is dark on 20 MHz, but few remember when WWV was lit + * on 25 MHz. + * + * This routine selects the best channel using a metric computed from + * the reachability register and minute pulse amplitude. Normally, the + * award goes to the the channel with the highest metric; but, in case + * of ties, the award goes to the channel with the highest minute sync + * pulse amplitude and then to the highest frequency. + * + * The routine performs an important squelch function to keep dirty data + * from polluting the integrators. During acquisition and until the + * clock is synchronized, the signal metric must be at least MTR (13); + * after that the metrict must be at least TTHR (50). If either of these + * is not true, the station select bits are cleared so the second sync + * is disabled and the data bit integrators averaged to a miss. */ static void wwv_newchan( @@ -2538,61 +2596,119 @@ wwv_newchan( { struct refclockproc *pp; struct wwvunit *up; - struct chan *cp; struct sync *sp, *rp; - int rank; + double rank, dtemp; int i, j; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; /* - * Reset the matched filter selector and station pointer to - * avoid fooling around should we lose this game. - */ - up->sptr = 0; - up->status &= ~(SELV | SELH); - - /* - * Search all five station pairs looking for the station with - * the maximum compare counter. Ties go to the highest frequency - * and then to WWV. + * Search all five station pairs looking for the channel with + * maximum metric. If no station is found above thresholds, the + * reference ID is set to NONE and we wait for hotter ions. */ j = 0; - sp = (struct sync *)0; + sp = NULL; rank = 0; for (i = 0; i < NCHAN; i++) { - cp = &up->mitig[i]; - rp = &cp->wwvh; - if (rp->count >= rank) { + rp = &up->mitig[i].wwvh; + dtemp = wwv_metric(rp); + if (dtemp >= rank) { + rank = dtemp; sp = rp; - rank = rp->count; j = i; } - rp = &cp->wwv; - if (rp->count >= rank) { + rp = &up->mitig[i].wwv; + dtemp = wwv_metric(rp); + if (dtemp >= rank) { + rank = dtemp; sp = rp; - rank = rp->count; j = i; } } + up->dchan = j; + up->sptr = sp; + up->status &= ~(SELV | SELH); + memcpy(&pp->refid, "NONE", 4); + if ((!(up->status & INSYNC) && rank >= MTHR) || ((up->status & + INSYNC) && rank >= TTHR)) { + up->status |= sp->select & (SELV | SELH); + memcpy(&pp->refid, sp->refid, 4); + } + if (peer->stratum <= 1) + memcpy(&peer->refid, &pp->refid, 4); +} + + +/* + * www_newgame - reset and start over + */ +static void +wwv_newgame( + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct wwvunit *up; + struct chan *cp; + int i; + + pp = peer->procptr; + up = (struct wwvunit *)pp->unitptr; /* - * If we find a station, continue to track it. If not, X marks - * the spot and we wait for better ions. + * Initialize strategic values. Note we set the leap bits + * NOTINSYNC and the refid "NONE". */ - if (rank > 0) { - up->dchan = j; - up->sptr = sp; - up->status |= sp->select & (SELV | SELH); - memcpy((char *)&pp->refid, sp->refid, 4); - if (peer->stratum <= 1) - memcpy((char *)&peer->refid, sp->refid, 4); - wwv_qsy(peer, up->dchan); + peer->leap = LEAP_NOTINSYNC; + up->watch = up->status = up->alarm = 0; + up->avgint = MINAVG; + up->freq = 0; + up->sptr = NULL; + up->gain = MAXGAIN / 2; + + /* + * Initialize the station processes for audio gain, select bit, + * station/frequency identifier and reference identifier. + */ + 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])); + cp->wwvh.select = SELH; + sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i])); } + wwv_newchan(peer); +} + +/* + * wwv_metric - compute station metric + * + * The most significant bits represent the number of ones in the + * reachability register. The least significant bits represent the + * minute sync pulse amplitude. The combined value is scaled 0-100. + */ +double +wwv_metric( + struct sync *sp /* station pointer */ + ) +{ + double dtemp; + + dtemp = sp->count * MAXSIG; + if (sp->synmax < MAXSIG) + dtemp += sp->synmax; + else + dtemp += MAXSIG - 1; + dtemp /= (AMAX + 1) * MAXSIG; + return (dtemp * 100.); } +#ifdef ICOM /* * wwv_qsy - Tune ICOM receiver * @@ -2606,22 +2722,22 @@ wwv_qsy( int chan /* channel */ ) { + int rval = 0; struct refclockproc *pp; struct wwvunit *up; - int rval = 0; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; - up->mitig[up->achan].gain = up->gain; -#ifdef ICOM - if (up->fd_icom > 0) - rval = icom_freq(up->fd_icom, peer->ttlmax & 0x7f, + if (up->fd_icom > 0) { + up->mitig[up->achan].gain = up->gain; + rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, qsy[chan]); -#endif /* ICOM */ - up->achan = chan; - up->gain = up->mitig[up->achan].gain; + up->achan = chan; + up->gain = up->mitig[up->achan].gain; + } return (rval); } +#endif /* ICOM */ /* @@ -2629,23 +2745,22 @@ wwv_qsy( * * Prettytime format - similar to Spectracom * - * sq yy ddd hh:mm:ss.fff ld dut lset agc stn comp errs freq avgt + * sq yy ddd hh:mm:ss ld dut lset agc iden sig errs freq avgt * * s sync indicator ('?' or ' ') - * q quality character (hex 0-F) + * q error bits (hex 0-F) * yyyy year of century * ddd day of year * hh hour of day * mm minute of hour - * ss minute of hour - * fff millisecond of second - * l leap second warning ' ' or 'L' - * d DST state 'S', 'D', 'I', or 'O' - * dut DUT sign and magnitude in deciseconds + * ss second of minute) + * l leap second warning (' ' or 'L') + * d DST state ('S', 'D', 'I', or 'O') + * dut DUT sign and magnitude (0.1 s) * lset minutes since last clock update * agc audio gain (0-255) - * iden station identifier (station and frequency) - * comp minute sync compare counter + * iden reference identifier (station and frequency) + * sig signal quality (0-100) * errs bit errors in last minute * freq frequency offset (PPM) * avgt averaging time (s) @@ -2657,8 +2772,8 @@ timecode( ) { struct sync *sp; - int year, day, hour, minute, second, frac, dut; - char synchar, qual, leapchar, dst; + int year, day, hour, minute, second, dut; + char synchar, leapchar, dst; char cptr[50]; @@ -2666,49 +2781,30 @@ timecode( * Common fixed-format fields */ synchar = (up->status & INSYNC) ? ' ' : '?'; - qual = 0; - if (up->alarm & (3 << DECERR)) - qual |= 0x1; - if (up->alarm & (3 << SYMERR)) - qual |= 0x2; - if (up->alarm & (3 << MODERR)) - qual |= 0x4; - if (up->alarm & (3 << SYNERR)) - qual |= 0x8; - year = up->decvec[7].digit + up->decvec[7].digit * 10; - if (year < UTCYEAR) - year += 2000; - else - year += 1900; - day = up->decvec[4].digit + up->decvec[5].digit * 10 + - up->decvec[6].digit * 100; - hour = up->decvec[2].digit + up->decvec[3].digit * 10; - minute = up->decvec[0].digit + up->decvec[1].digit * 10; - second = up->tsec; - frac = (up->tphase * 1000) / SECOND; + year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 + + 2000; + day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 + + up->decvec[DA + 2].digit * 100; + hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10; + minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10; + second = 0; leapchar = (up->misc & SECWAR) ? 'L' : ' '; dst = dstcod[(up->misc >> 4) & 0x3]; dut = up->misc & 0x7; if (!(up->misc & DUTS)) dut = -dut; - sprintf(ptr, "%c%1X", synchar, qual); - sprintf(cptr, " %4d %03d %02d:%02d:%02d.%.03d %c%c %+d", - year, day, hour, minute, second, frac, leapchar, dst, 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); /* * Specific variable-format fields */ sp = up->sptr; - if (sp != 0) - sprintf(cptr, " %d %d %s %d %d %.1f %d", up->minset, - up->mitig[up->dchan].gain, sp->ident, sp->count, - up->errcnt, up->freq / SECOND * 1e6, MINAVG << - up->avgint); - else - sprintf(cptr, " %d %d X 0 %d %.1f %d", up->minset, - up->mitig[up->dchan].gain, up->errcnt, up->freq / - SECOND * 1e6, MINAVG << up->avgint); + sprintf(cptr, " %d %d %s %.0f %d %.1f %d", up->watch, + up->mitig[up->dchan].gain, sp->refid, wwv_metric(sp), + up->errbit, up->freq / SECOND * 1e6, up->avgint); strcat(ptr, cptr); return (strlen(ptr)); } @@ -2717,9 +2813,10 @@ timecode( /* * wwv_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 + * This routine is called at the end of each second. It counts the + * number of signal clips above the MAXSIG threshold during the previous + * second. If there are no clips, the gain is bumped up; if too many + * clips, 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. */ @@ -2741,15 +2838,19 @@ wwv_gain( */ if (up->clipcnt == 0) { up->gain += 4; - if (up->gain > 255) - up->gain = 255; - } else if (up->clipcnt > SECOND / 100) { + if (up->gain > MAXGAIN) + up->gain = MAXGAIN; + } else if (up->clipcnt > MAXCLP) { up->gain -= 4; if (up->gain < 0) up->gain = 0; } - audio_gain(up->gain, up->port); + audio_gain(up->gain, up->mongain, up->port); up->clipcnt = 0; +#if DEBUG + if (debug > 1) + audio_show(); +#endif } diff --git a/contrib/ntp/ntpd/refclock_wwvb.c b/contrib/ntp/ntpd/refclock_wwvb.c index 0ca9f75..c5ef9f9 100644 --- a/contrib/ntp/ntpd/refclock_wwvb.c +++ b/contrib/ntp/ntpd/refclock_wwvb.c @@ -103,6 +103,7 @@ #define DESCRIPTION "Spectracom WWVB/GPS Receivers" /* 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 MONLIN 15 /* number of monitoring lines */ @@ -187,7 +188,7 @@ wwvb_start( peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); - peer->burst = NSTAGE; + peer->burst = MAXSTAGE; return (1); } @@ -263,11 +264,6 @@ wwvb_receive( pp->lastrec = up->laststamp; up->laststamp = trtmp; up->tcswitch = 1; -#ifdef DEBUG - if (debug) - printf("wwvb: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif /* * We get down to business, check the timecode format and decode @@ -277,10 +273,9 @@ wwvb_receive( */ syncchar = qualchar = leapchar = dstchar = ' '; tz = 0; - pp->msec = 0; switch (pp->lencode) { - case LENWWVB0: + case LENWWVB0: /* * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" @@ -289,20 +284,22 @@ wwvb_receive( "%c %3d %2d:%2d:%2d%c%cTZ=%2d", &syncchar, &pp->day, &pp->hour, &pp->minute, &pp->second, &tmpchar, &dstchar, &tz) == 8) + pp->nsec = 0; break; - case LENWWVB2: + case LENWWVB2: /* * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */ if (sscanf(pp->a_lastcode, - "%c%c %2d %3d %2d:%2d:%2d.%3d %c", + "%c%c %2d %3d %2d:%2d:%2d.%3ld %c", &syncchar, &qualchar, &pp->year, &pp->day, - &pp->hour, &pp->minute, &pp->second, &pp->msec, + &pp->hour, &pp->minute, &pp->second, &pp->nsec, &leapchar) == 9) + pp->nsec *= 1000000; break; - case LENWWVB3: + case LENWWVB3: /* * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#" @@ -313,10 +310,11 @@ wwvb_receive( &pp->minute, &pp->second, &dstchar, &leapchar) == 8) { pp->day = ymd2yd(pp->year, month, day); + pp->nsec = 0; break; } - default: + default: /* * Unknown format: If dumping internal table, record @@ -343,6 +341,7 @@ wwvb_receive( case ' ': pp->disp = .001; + pp->lastref = pp->lastrec; break; case 'A': @@ -411,17 +410,21 @@ wwvb_poll( pollchar = 'T'; if (write(pp->io.fd, &pollchar, 1) != 1) refclock_report(peer, CEVNT_FAULT); - else - pp->polls++; 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; + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug) + printf("wwvb: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + peer->burst = MAXSTAGE; + pp->polls++; /* * If the monitor flag is set (flag4), we dump the internal -- cgit v1.1