diff options
author | roberto <roberto@FreeBSD.org> | 2001-08-29 14:35:15 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 2001-08-29 14:35:15 +0000 |
commit | 40b8e415eb0f835a9dd7a473ddf134ec67877fd7 (patch) | |
tree | 3cfb63f1a112ee17469b17fc1593a88d004ddda6 /contrib/ntp/ntpd | |
parent | a5a8dc6136fcee95f261a31609a25669038c3861 (diff) | |
download | FreeBSD-src-40b8e415eb0f835a9dd7a473ddf134ec67877fd7.zip FreeBSD-src-40b8e415eb0f835a9dd7a473ddf134ec67877fd7.tar.gz |
Virgin import of ntpd 4.1.0
Diffstat (limited to 'contrib/ntp/ntpd')
57 files changed, 11811 insertions, 5477 deletions
diff --git a/contrib/ntp/ntpd/Makefile.am b/contrib/ntp/ntpd/Makefile.am index 2fd16c4..718d996 100644 --- a/contrib/ntp/ntpd/Makefile.am +++ b/contrib/ntp/ntpd/Makefile.am @@ -1,9 +1,14 @@ #AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies AUTOMAKE_OPTIONS = ../util/ansi2knr bin_PROGRAMS = ntpd -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/librsaref # LDADD might need RESLIB and ADJLIB LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@ +# 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 DISTCLEANFILES = .version version.c #EXTRA_DIST = ntpd.mak @@ -13,15 +18,18 @@ check_PROGRAMS = @MAKE_CHECK_Y2K@ EXTRA_PROGRAMS = check_y2k check-local: @MAKE_CHECK_Y2K@ - [ -z "@MAKE_CHECK_Y2K@" ] || ./@MAKE_CHECK_Y2K@ + test -z "@MAKE_CHECK_Y2K@" || ./@MAKE_CHECK_Y2K@ -ntpd_SOURCES = jupiter.h map_vme.c ntp_config.c ntp_control.c ntp_filegen.c \ +ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.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_proto.c ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \ + ntp_proto.c ntp_refclock.c ntp_request.c ntp_resolver.c \ + ntp_restrict.c ntp_timer.c \ ntp_util.c ntpd.c refclock_acts.c refclock_arbiter.c refclock_arc.c \ refclock_as2201.c refclock_atom.c refclock_bancomm.c \ refclock_chronolog.c refclock_chu.c refclock_conf.c refclock_datum.c \ refclock_dumbclock.c refclock_fg.c refclock_gpsvme.c refclock_heath.c \ + refclock_hopfser.c refclock_hopfpci.c \ refclock_hpgps.c refclock_irig.c refclock_jupiter.c refclock_leitch.c \ refclock_local.c refclock_msfees.c refclock_mx4200.c refclock_nmea.c \ refclock_oncore.c refclock_palisade.c refclock_palisade.h \ diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in index d12a343..0e3ad1c 100644 --- a/contrib/ntp/ntpd/Makefile.in +++ b/contrib/ntp/ntpd/Makefile.in @@ -1,6 +1,7 @@ -# Makefile.in generated automatically by automake 1.4a from Makefile.am +# Makefile.in generated automatically by automake 1.4e from Makefile.am. -# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -31,8 +32,6 @@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include -DESTDIR = - pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ @@ -48,7 +47,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_FLAG = +INSTALL_HEADER = $(INSTALL_DATA) transform = @program_transform_name@ NORMAL_INSTALL = : @@ -57,24 +56,30 @@ 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@ + +@SET_MAKE@ AMDEP = @AMDEP@ AMTAR = @AMTAR@ +AUTOKEY = @AUTOKEY@ AWK = @AWK@ CC = @CC@ CFLAGS = @CFLAGS@ CHUTEST = @CHUTEST@ CLKTEST = @CLKTEST@ CPP = @CPP@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ DCFD = @DCFD@ DEPDIR = @DEPDIR@ +EF_LIBS = @EF_LIBS@ +EF_PROGS = @EF_PROGS@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTALL_STRIP_PROGRAM_ENV = @INSTALL_STRIP_PROGRAM_ENV@ LDFLAGS = @LDFLAGS@ LIBPARSE = @LIBPARSE@ LIBRSAREF = @LIBRSAREF@ @@ -86,16 +91,27 @@ MAKE_LIBPARSE = @MAKE_LIBPARSE@ MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_NTP_GENKEYS = @MAKE_NTP_GENKEYS@ MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ MAKE_TICKADJ = @MAKE_TICKADJ@ +MAKE_TIMETRIM = @MAKE_TIMETRIM@ +OPENSSL = @OPENSSL@ +OPENSSL_INC = @OPENSSL_INC@ +OPENSSL_LIB = @OPENSSL_LIB@ PACKAGE = @PACKAGE@ +PATH_PERL = @PATH_PERL@ PATH_SH = @PATH_SH@ PROPDELAY = @PROPDELAY@ RANLIB = @RANLIB@ +RSADIR = @RSADIR@ +RSAOBJS = @RSAOBJS@ RSAREF = @RSAREF@ +RSASRCS = @RSASRCS@ +STRIP = @STRIP@ TESTDCF = @TESTDCF@ U = @U@ VERSION = @VERSION@ +_am_include = @_am_include@ install_sh = @install_sh@ #AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies @@ -103,9 +119,14 @@ install_sh = @install_sh@ AUTOMAKE_OPTIONS = ../util/ansi2knr bin_PROGRAMS = ntpd -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/librsaref # LDADD might need RESLIB and ADJLIB LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@ +# 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 DISTCLEANFILES = .version version.c #EXTRA_DIST = ntpd.mak @@ -114,13 +135,16 @@ ETAGS_ARGS = Makefile.am check_PROGRAMS = @MAKE_CHECK_Y2K@ EXTRA_PROGRAMS = check_y2k -ntpd_SOURCES = jupiter.h map_vme.c ntp_config.c ntp_control.c ntp_filegen.c \ +ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.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_proto.c ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \ + ntp_proto.c ntp_refclock.c ntp_request.c ntp_resolver.c \ + ntp_restrict.c ntp_timer.c \ ntp_util.c ntpd.c refclock_acts.c refclock_arbiter.c refclock_arc.c \ refclock_as2201.c refclock_atom.c refclock_bancomm.c \ refclock_chronolog.c refclock_chu.c refclock_conf.c refclock_datum.c \ refclock_dumbclock.c refclock_fg.c refclock_gpsvme.c refclock_heath.c \ + refclock_hopfser.c refclock_hopfpci.c \ refclock_hpgps.c refclock_irig.c refclock_jupiter.c refclock_leitch.c \ refclock_local.c refclock_msfees.c refclock_mx4200.c refclock_nmea.c \ refclock_oncore.c refclock_palisade.c refclock_palisade.h \ @@ -128,154 +152,148 @@ ntpd_SOURCES = jupiter.h map_vme.c ntp_config.c ntp_control.c ntp_filegen.c \ refclock_shm.c refclock_tpro.c refclock_trak.c refclock_true.c \ refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c +EXEEXT = +OBJEXT = o subdir = ntpd mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = ../config.h -CONFIG_CLEAN_FILES = -PROGRAMS = $(bin_PROGRAMS) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +EXTRA_PROGRAMS = check_y2k$(EXEEXT) +bin_PROGRAMS = ntpd$(EXEEXT) +check_PROGRAMS = @MAKE_CHECK_Y2K@ +PROGRAMS = $(bin_PROGRAMS) -DEFS = @DEFS@ -I. -I$(srcdir) -I.. +DEFS = @DEFS@ -I. -I$(srcdir) -I$(top_builddir) CPPFLAGS = @CPPFLAGS@ LIBS = @LIBS@ ANSI2KNR = ../util/ansi2knr check_y2k_SOURCES = check_y2k.c -check_y2k_OBJECTS = check_y2k$U.o +check_y2k_OBJECTS = check_y2k$U.$(OBJEXT) check_y2k_LDADD = $(LDADD) -check_y2k_DEPENDENCIES = version.o ../libntp/libntp.a +check_y2k_DEPENDENCIES = version.o ../libntp/libntp.a check_y2k_LDFLAGS = -am_ntpd_OBJECTS = map_vme$U.o ntp_config$U.o ntp_control$U.o \ -ntp_filegen$U.o ntp_intres$U.o ntp_io$U.o ntp_loopfilter$U.o \ -ntp_monitor$U.o ntp_peer$U.o ntp_proto$U.o ntp_refclock$U.o \ -ntp_request$U.o ntp_restrict$U.o ntp_timer$U.o ntp_util$U.o ntpd$U.o \ -refclock_acts$U.o refclock_arbiter$U.o refclock_arc$U.o \ -refclock_as2201$U.o refclock_atom$U.o refclock_bancomm$U.o \ -refclock_chronolog$U.o refclock_chu$U.o refclock_conf$U.o \ -refclock_datum$U.o refclock_dumbclock$U.o refclock_fg$U.o \ -refclock_gpsvme$U.o refclock_heath$U.o refclock_hpgps$U.o \ -refclock_irig$U.o refclock_jupiter$U.o refclock_leitch$U.o \ -refclock_local$U.o refclock_msfees$U.o refclock_mx4200$U.o \ -refclock_nmea$U.o refclock_oncore$U.o refclock_palisade$U.o \ -refclock_parse$U.o refclock_pcf$U.o refclock_pst$U.o \ -refclock_ptbacts$U.o refclock_shm$U.o refclock_tpro$U.o \ -refclock_trak$U.o refclock_true$U.o refclock_ulink$U.o \ -refclock_usno$U.o refclock_wwv$U.o refclock_wwvb$U.o -ntpd_OBJECTS = $(am_ntpd_OBJECTS) -ntpd_DEPENDENCIES = version.o ../libntp/libntp.a +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_resolver$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_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_ulink$U.$(OBJEXT) \ +refclock_usno$U.$(OBJEXT) refclock_wwv$U.$(OBJEXT) \ +refclock_wwvb$U.$(OBJEXT) +ntpd_OBJECTS = $(am_ntpd_OBJECTS) +ntpd_DEPENDENCIES = version.o ../libntp/libntp.a ntpd_LDFLAGS = COMPILE = $(CC) $(DEFS) $(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 - - -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) - -GZIP_ENV = --best +DIST_SOURCES = check_y2k.c $(ntpd_SOURCES) depcomp = $(SHELL) $(top_srcdir)/depcomp -DEP_FILES = @AMDEP@ $(DEPDIR)/check_y2k$U.Po $(DEPDIR)/map_vme$U.Po \ -$(DEPDIR)/ntp_config$U.Po $(DEPDIR)/ntp_control$U.Po \ -$(DEPDIR)/ntp_filegen$U.Po $(DEPDIR)/ntp_intres$U.Po \ -$(DEPDIR)/ntp_io$U.Po $(DEPDIR)/ntp_loopfilter$U.Po \ -$(DEPDIR)/ntp_monitor$U.Po $(DEPDIR)/ntp_peer$U.Po \ -$(DEPDIR)/ntp_proto$U.Po $(DEPDIR)/ntp_refclock$U.Po \ -$(DEPDIR)/ntp_request$U.Po $(DEPDIR)/ntp_restrict$U.Po \ -$(DEPDIR)/ntp_timer$U.Po $(DEPDIR)/ntp_util$U.Po $(DEPDIR)/ntpd$U.Po \ -$(DEPDIR)/refclock_acts$U.Po $(DEPDIR)/refclock_arbiter$U.Po \ -$(DEPDIR)/refclock_arc$U.Po $(DEPDIR)/refclock_as2201$U.Po \ -$(DEPDIR)/refclock_atom$U.Po $(DEPDIR)/refclock_bancomm$U.Po \ -$(DEPDIR)/refclock_chronolog$U.Po $(DEPDIR)/refclock_chu$U.Po \ -$(DEPDIR)/refclock_conf$U.Po $(DEPDIR)/refclock_datum$U.Po \ -$(DEPDIR)/refclock_dumbclock$U.Po $(DEPDIR)/refclock_fg$U.Po \ -$(DEPDIR)/refclock_gpsvme$U.Po $(DEPDIR)/refclock_heath$U.Po \ -$(DEPDIR)/refclock_hpgps$U.Po $(DEPDIR)/refclock_irig$U.Po \ -$(DEPDIR)/refclock_jupiter$U.Po $(DEPDIR)/refclock_leitch$U.Po \ -$(DEPDIR)/refclock_local$U.Po $(DEPDIR)/refclock_msfees$U.Po \ -$(DEPDIR)/refclock_mx4200$U.Po $(DEPDIR)/refclock_nmea$U.Po \ -$(DEPDIR)/refclock_oncore$U.Po $(DEPDIR)/refclock_palisade$U.Po \ -$(DEPDIR)/refclock_parse$U.Po $(DEPDIR)/refclock_pcf$U.Po \ -$(DEPDIR)/refclock_pst$U.Po $(DEPDIR)/refclock_ptbacts$U.Po \ -$(DEPDIR)/refclock_shm$U.Po $(DEPDIR)/refclock_tpro$U.Po \ -$(DEPDIR)/refclock_trak$U.Po $(DEPDIR)/refclock_true$U.Po \ -$(DEPDIR)/refclock_ulink$U.Po $(DEPDIR)/refclock_usno$U.Po \ -$(DEPDIR)/refclock_wwv$U.Po $(DEPDIR)/refclock_wwvb$U.Po -SOURCES = check_y2k.c $(ntpd_SOURCES) -OBJECTS = check_y2k$U.o $(am_ntpd_OBJECTS) - -all: all-redirect -.SUFFIXES: -.SUFFIXES: .c .h .o -$(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 $(BUILT_SOURCES) - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - +@AMDEP@DEP_FILES = $(DEPDIR)/check_y2k$U.Po $(DEPDIR)/cmd_args$U.Po \ +@AMDEP@ $(DEPDIR)/map_vme$U.Po $(DEPDIR)/ntp_config$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_control$U.Po $(DEPDIR)/ntp_crypto$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_filegen$U.Po $(DEPDIR)/ntp_intres$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_io$U.Po $(DEPDIR)/ntp_loopfilter$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_monitor$U.Po $(DEPDIR)/ntp_peer$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_proto$U.Po $(DEPDIR)/ntp_refclock$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_request$U.Po $(DEPDIR)/ntp_resolver$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_restrict$U.Po $(DEPDIR)/ntp_timer$U.Po \ +@AMDEP@ $(DEPDIR)/ntp_util$U.Po $(DEPDIR)/ntpd$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_acts$U.Po $(DEPDIR)/refclock_arbiter$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_arc$U.Po $(DEPDIR)/refclock_as2201$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_atom$U.Po $(DEPDIR)/refclock_bancomm$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_chronolog$U.Po $(DEPDIR)/refclock_chu$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_conf$U.Po $(DEPDIR)/refclock_datum$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_dumbclock$U.Po $(DEPDIR)/refclock_fg$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_gpsvme$U.Po $(DEPDIR)/refclock_heath$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_hopfpci$U.Po $(DEPDIR)/refclock_hopfser$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_hpgps$U.Po $(DEPDIR)/refclock_irig$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_jupiter$U.Po $(DEPDIR)/refclock_leitch$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_local$U.Po $(DEPDIR)/refclock_msfees$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_mx4200$U.Po $(DEPDIR)/refclock_nmea$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_oncore$U.Po $(DEPDIR)/refclock_palisade$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_parse$U.Po $(DEPDIR)/refclock_pcf$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_pst$U.Po $(DEPDIR)/refclock_ptbacts$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_shm$U.Po $(DEPDIR)/refclock_tpro$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_trak$U.Po $(DEPDIR)/refclock_true$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_ulink$U.Po $(DEPDIR)/refclock_usno$U.Po \ +@AMDEP@ $(DEPDIR)/refclock_wwv$U.Po $(DEPDIR)/refclock_wwvb$U.Po +DIST_COMMON = Makefile.am Makefile.in -mostlyclean-binPROGRAMS: +SOURCES = check_y2k.c $(ntpd_SOURCES) +OBJECTS = check_y2k$U.$(OBJEXT) $(am_ntpd_OBJECTS) -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +all: all-am -distclean-binPROGRAMS: +.SUFFIXES: +.SUFFIXES: .c .h .o .obj -maintainer-clean-binPROGRAMS: +$(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 install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(bindir) @list='$(bin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ - f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ - echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ - $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f; \ else :; fi; \ done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ rm -f $(DESTDIR)$(bindir)/$$f; \ done -mostlyclean-checkPROGRAMS: +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) clean-checkPROGRAMS: -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) -distclean-checkPROGRAMS: - -maintainer-clean-checkPROGRAMS: - mostlyclean-compile: - -rm -f *.o core *.core - -clean-compile: + -rm -f *.$(OBJEXT) core *.core distclean-compile: -rm -f *.tab.c - -maintainer-clean-compile: -../util/ansi2knr: ../util/ansi2knr.o +../util/ansi2knr: ../util/ansi2knr.$(OBJEXT) cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr -../util/ansi2knr.o: - cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o +../util/ansi2knr.$(OBJEXT): + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.$(OBJEXT) mostlyclean-kr: -rm -f *_.c -clean-kr: - -distclean-kr: - -maintainer-clean-kr: - check_y2k: $(check_y2k_OBJECTS) $(check_y2k_DEPENDENCIES) @rm -f check_y2k $(LINK) $(check_y2k_LDFLAGS) $(check_y2k_OBJECTS) $(check_y2k_LDADD) $(LIBS) @@ -285,12 +303,16 @@ ntpd: $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES) $(LINK) $(ntpd_LDFLAGS) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS) check_y2k_.c: check_y2k.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 +cmd_args_.c: cmd_args.c $(ANSI2KNR) + $(CPP) $(DEFS) $(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 map_vme_.c: map_vme.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 ntp_config_.c: ntp_config.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 ntp_control_.c: ntp_control.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 +ntp_crypto_.c: ntp_crypto.c $(ANSI2KNR) + $(CPP) $(DEFS) $(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 ntp_filegen_.c: ntp_filegen.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 ntp_intres_.c: ntp_intres.c $(ANSI2KNR) @@ -309,6 +331,8 @@ ntp_refclock_.c: ntp_refclock.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 ntp_request_.c: ntp_request.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 +ntp_resolver_.c: ntp_resolver.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_resolver.c; then echo $(srcdir)/ntp_resolver.c; else echo ntp_resolver.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_resolver_.c ntp_restrict_.c: ntp_restrict.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 ntp_timer_.c: ntp_timer.c $(ANSI2KNR) @@ -345,6 +369,10 @@ refclock_gpsvme_.c: refclock_gpsvme.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 refclock_heath_.c: refclock_heath.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 +refclock_hopfpci_.c: refclock_hopfpci.c $(ANSI2KNR) + $(CPP) $(DEFS) $(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 +refclock_hopfser_.c: refclock_hopfser.c $(ANSI2KNR) + $(CPP) $(DEFS) $(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 refclock_hpgps_.c: refclock_hpgps.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 refclock_irig_.c: refclock_irig.c $(ANSI2KNR) @@ -389,20 +417,32 @@ refclock_wwv_.c: refclock_wwv.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 refclock_wwvb_.c: refclock_wwvb.c $(ANSI2KNR) $(CPP) $(DEFS) $(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 -check_y2k_.o map_vme_.o ntp_config_.o ntp_control_.o ntp_filegen_.o \ -ntp_intres_.o ntp_io_.o ntp_loopfilter_.o ntp_monitor_.o ntp_peer_.o \ -ntp_proto_.o ntp_refclock_.o ntp_request_.o ntp_restrict_.o \ -ntp_timer_.o ntp_util_.o ntpd_.o refclock_acts_.o refclock_arbiter_.o \ -refclock_arc_.o refclock_as2201_.o refclock_atom_.o refclock_bancomm_.o \ -refclock_chronolog_.o refclock_chu_.o refclock_conf_.o \ -refclock_datum_.o refclock_dumbclock_.o refclock_fg_.o \ -refclock_gpsvme_.o refclock_heath_.o refclock_hpgps_.o refclock_irig_.o \ -refclock_jupiter_.o refclock_leitch_.o refclock_local_.o \ -refclock_msfees_.o refclock_mx4200_.o refclock_nmea_.o \ -refclock_oncore_.o refclock_palisade_.o refclock_parse_.o \ -refclock_pcf_.o refclock_pst_.o refclock_ptbacts_.o refclock_shm_.o \ -refclock_tpro_.o refclock_trak_.o refclock_true_.o refclock_ulink_.o \ -refclock_usno_.o refclock_wwv_.o refclock_wwvb_.o : $(ANSI2KNR) +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_resolver_.$(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_jupiter_.$(OBJEXT) \ +refclock_leitch_.$(OBJEXT) refclock_local_.$(OBJEXT) \ +refclock_msfees_.$(OBJEXT) refclock_mx4200_.$(OBJEXT) \ +refclock_nmea_.$(OBJEXT) refclock_oncore_.$(OBJEXT) \ +refclock_palisade_.$(OBJEXT) refclock_parse_.$(OBJEXT) \ +refclock_pcf_.$(OBJEXT) refclock_pst_.$(OBJEXT) \ +refclock_ptbacts_.$(OBJEXT) refclock_shm_.$(OBJEXT) \ +refclock_tpro_.$(OBJEXT) refclock_trak_.$(OBJEXT) \ +refclock_true_.$(OBJEXT) refclock_ulink_.$(OBJEXT) \ +refclock_usno_.$(OBJEXT) refclock_wwv_.$(OBJEXT) \ +refclock_wwvb_.$(OBJEXT) : $(ANSI2KNR) tags: TAGS @@ -413,9 +453,9 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - mkid -f$$here/ID $$unique $(LISP) + mkid -fID $$unique $(LISP) -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ @@ -428,128 +468,130 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -mostlyclean-tags: - -clean-tags: +GTAGS: + here=`CDPATH=: && cd $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $$here distclean-tags: -rm -f TAGS ID -maintainer-clean-tags: - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) - -distdir: $(DISTFILES) - @for file in $(DISTFILES); do \ - d=$(srcdir); \ - if test -d $$d/$$file; then \ - cp -pR $$d/$$file $(distdir); \ - else \ - test -f $(distdir)/$$file \ - || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ - || cp -p $$d/$$file $(distdir)/$$file || :; \ - fi; \ - done - -@AMDEP@include $(DEPDIR)/check_y2k$U.Po -@AMDEP@include $(DEPDIR)/map_vme$U.Po -@AMDEP@include $(DEPDIR)/ntp_config$U.Po -@AMDEP@include $(DEPDIR)/ntp_control$U.Po -@AMDEP@include $(DEPDIR)/ntp_filegen$U.Po -@AMDEP@include $(DEPDIR)/ntp_intres$U.Po -@AMDEP@include $(DEPDIR)/ntp_io$U.Po -@AMDEP@include $(DEPDIR)/ntp_loopfilter$U.Po -@AMDEP@include $(DEPDIR)/ntp_monitor$U.Po -@AMDEP@include $(DEPDIR)/ntp_peer$U.Po -@AMDEP@include $(DEPDIR)/ntp_proto$U.Po -@AMDEP@include $(DEPDIR)/ntp_refclock$U.Po -@AMDEP@include $(DEPDIR)/ntp_request$U.Po -@AMDEP@include $(DEPDIR)/ntp_restrict$U.Po -@AMDEP@include $(DEPDIR)/ntp_timer$U.Po -@AMDEP@include $(DEPDIR)/ntp_util$U.Po -@AMDEP@include $(DEPDIR)/ntpd$U.Po -@AMDEP@include $(DEPDIR)/refclock_acts$U.Po -@AMDEP@include $(DEPDIR)/refclock_arbiter$U.Po -@AMDEP@include $(DEPDIR)/refclock_arc$U.Po -@AMDEP@include $(DEPDIR)/refclock_as2201$U.Po -@AMDEP@include $(DEPDIR)/refclock_atom$U.Po -@AMDEP@include $(DEPDIR)/refclock_bancomm$U.Po -@AMDEP@include $(DEPDIR)/refclock_chronolog$U.Po -@AMDEP@include $(DEPDIR)/refclock_chu$U.Po -@AMDEP@include $(DEPDIR)/refclock_conf$U.Po -@AMDEP@include $(DEPDIR)/refclock_datum$U.Po -@AMDEP@include $(DEPDIR)/refclock_dumbclock$U.Po -@AMDEP@include $(DEPDIR)/refclock_fg$U.Po -@AMDEP@include $(DEPDIR)/refclock_gpsvme$U.Po -@AMDEP@include $(DEPDIR)/refclock_heath$U.Po -@AMDEP@include $(DEPDIR)/refclock_hpgps$U.Po -@AMDEP@include $(DEPDIR)/refclock_irig$U.Po -@AMDEP@include $(DEPDIR)/refclock_jupiter$U.Po -@AMDEP@include $(DEPDIR)/refclock_leitch$U.Po -@AMDEP@include $(DEPDIR)/refclock_local$U.Po -@AMDEP@include $(DEPDIR)/refclock_msfees$U.Po -@AMDEP@include $(DEPDIR)/refclock_mx4200$U.Po -@AMDEP@include $(DEPDIR)/refclock_nmea$U.Po -@AMDEP@include $(DEPDIR)/refclock_oncore$U.Po -@AMDEP@include $(DEPDIR)/refclock_palisade$U.Po -@AMDEP@include $(DEPDIR)/refclock_parse$U.Po -@AMDEP@include $(DEPDIR)/refclock_pcf$U.Po -@AMDEP@include $(DEPDIR)/refclock_pst$U.Po -@AMDEP@include $(DEPDIR)/refclock_ptbacts$U.Po -@AMDEP@include $(DEPDIR)/refclock_shm$U.Po -@AMDEP@include $(DEPDIR)/refclock_tpro$U.Po -@AMDEP@include $(DEPDIR)/refclock_trak$U.Po -@AMDEP@include $(DEPDIR)/refclock_true$U.Po -@AMDEP@include $(DEPDIR)/refclock_ulink$U.Po -@AMDEP@include $(DEPDIR)/refclock_usno$U.Po -@AMDEP@include $(DEPDIR)/refclock_wwv$U.Po -@AMDEP@include $(DEPDIR)/refclock_wwvb$U.Po - -mostlyclean-depend: - -clean-depend: +@AMDEP@@_am_include@ $(DEPDIR)/check_y2k$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/cmd_args$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/map_vme$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_config$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_control$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_crypto$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_filegen$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_intres$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_io$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_loopfilter$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_monitor$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_peer$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_proto$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_refclock$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_request$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_resolver$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_restrict$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_timer$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntp_util$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/ntpd$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_acts$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_arbiter$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_arc$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_as2201$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_atom$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_bancomm$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_chronolog$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_chu$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_conf$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_datum$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_dumbclock$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_fg$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_gpsvme$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_heath$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_hopfpci$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_hopfser$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_hpgps$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_irig$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_jupiter$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_leitch$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_local$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_msfees$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_mx4200$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_nmea$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_oncore$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_palisade$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_parse$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_pcf$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_pst$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_ptbacts$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_shm$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_tpro$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_trak$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_true$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_ulink$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_usno$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_wwv$U.Po +@AMDEP@@_am_include@ $(DEPDIR)/refclock_wwvb$U.Po distclean-depend: -rm -rf $(DEPDIR) -maintainer-clean-depend: - @AMDEP@CCDEPMODE = @CCDEPMODE@ .c.o: @AMDEP@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ @AMDEP@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ - $(COMPILE) -c -o $@ $< + $(COMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$< -info-am: -info: info-am -dvi-am: -dvi: dvi-am +.c.obj: +@AMDEP@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c -o $@ `cygpath -w $<` + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir) \ + || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am -installcheck-am: -installcheck: installcheck-am -install-exec-am: install-binPROGRAMS -install-exec: install-exec-am +all-am: Makefile $(PROGRAMS) -install-data-am: +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + +install: install-am +install-exec: install-exec-am install-data: install-data-am +uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -install: install-am -uninstall-am: uninstall-binPROGRAMS -uninstall: uninstall-am -all-am: Makefile $(PROGRAMS) -all-redirect: all-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install -installdirs: - $(mkinstalldirs) $(DESTDIR)$(bindir) +installcheck: installcheck-am + +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_PROGRAM_ENV='$(INSTALL_STRIP_PROGRAM_ENV)' install mostlyclean-generic: @@ -561,51 +603,61 @@ distclean-generic: -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." -rm -f Makefile.in -mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-checkPROGRAMS \ - mostlyclean-compile mostlyclean-kr mostlyclean-tags \ - mostlyclean-depend mostlyclean-generic +clean: clean-am -mostlyclean: mostlyclean-am +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + mostlyclean-am -clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-compile clean-kr \ - clean-tags clean-depend clean-generic mostlyclean-am +distclean: distclean-am -clean: clean-am +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags -distclean-am: distclean-binPROGRAMS distclean-checkPROGRAMS \ - distclean-compile distclean-kr distclean-tags \ - distclean-depend distclean-generic clean-am +dvi: -distclean: distclean-am +dvi-am: -maintainer-clean-am: maintainer-clean-binPROGRAMS \ - maintainer-clean-checkPROGRAMS maintainer-clean-compile \ - maintainer-clean-kr maintainer-clean-tags \ - maintainer-clean-depend maintainer-clean-generic \ - distclean-am - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." +info: + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: + +install-man: + +installcheck-am: maintainer-clean: maintainer-clean-am -.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ -maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ -mostlyclean-checkPROGRAMS distclean-checkPROGRAMS clean-checkPROGRAMS \ -maintainer-clean-checkPROGRAMS mostlyclean-compile distclean-compile \ -clean-compile maintainer-clean-compile mostlyclean-kr distclean-kr \ -clean-kr maintainer-clean-kr tags mostlyclean-tags distclean-tags \ -clean-tags maintainer-clean-tags distdir mostlyclean-depend \ -distclean-depend clean-depend maintainer-clean-depend info-am info \ -dvi-am dvi check-local check check-am installcheck-am installcheck \ -install-exec-am install-exec install-data-am install-data install-am \ -install uninstall-am uninstall all-redirect all-am all install-strip \ -installdirs mostlyclean-generic distclean-generic clean-generic \ -maintainer-clean-generic clean mostlyclean distclean maintainer-clean +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr + +uninstall-am: uninstall-binPROGRAMS + +.PHONY: 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-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 check-local: @MAKE_CHECK_Y2K@ - [ -z "@MAKE_CHECK_Y2K@" ] || ./@MAKE_CHECK_Y2K@ + test -z "@MAKE_CHECK_Y2K@" || ./@MAKE_CHECK_Y2K@ $(PROGRAMS): $(LDADD) diff --git a/contrib/ntp/ntpd/check_y2k.c b/contrib/ntp/ntpd/check_y2k.c index 3cc05fc..f0f4480 100644 --- a/contrib/ntp/ntpd/check_y2k.c +++ b/contrib/ntp/ntpd/check_y2k.c @@ -31,7 +31,8 @@ # include <config.h> #endif -#include <sys/types.h> +#include "ntpd.h" + #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -48,7 +49,6 @@ # ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> # endif /* HAVE_SYS_IOCTL_H */ -# include <sys/time.h> # if !defined(VMS) /*wjm*/ # include <sys/resource.h> # endif /* VMS */ @@ -94,8 +94,6 @@ # include <apollo/base.h> #endif /* SYS_DOMAINOS */ -#include "ntpd.h" - /* } end definitions lifted from ntpd.c */ #include "ntp_calendar.h" @@ -103,10 +101,11 @@ #define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 ) -int debug = 0; /* debugging requests for parse stuff */ +volatile int debug = 0; /* debugging requests for parse stuff */ char const *progname = "check_y2k"; -long Days ( int Year ) /* return number of days since year "0" */ +long +Days ( int Year ) /* return number of days since year "0" */ { long Return; /* this is a known to be good algorithm */ @@ -137,7 +136,8 @@ static struct tm LocalTime; #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \ Warnings++; else Fatals++ -int main( void ) +int +main( void ) { int Fatals; int Warnings; diff --git a/contrib/ntp/ntpd/cmd_args.c b/contrib/ntp/ntpd/cmd_args.c new file mode 100644 index 0000000..9f61b4a --- /dev/null +++ b/contrib/ntp/ntpd/cmd_args.c @@ -0,0 +1,313 @@ +/* + * cmd_args.c = command-line argument processing + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntpd.h" +#include "ntp_stdlib.h" +#include "ntp_cmdargs.h" + +/* + * Definitions of things either imported from or exported to outside + */ +extern char const *progname; +int listen_to_virtual_ips = 0; + +static const char *ntp_options = "aAbc:dD:f:gk:l:LmnN:p:P:qr:s:t:v:V:x"; + +#ifdef HAVE_NETINFO +extern int check_netinfo; +#endif + + +/* + * getstartup - search through the options looking for a debugging flag + */ +void +getstartup( + int argc, + char *argv[] + ) +{ + int errflg; + extern int priority_done; + int c; + +#ifdef DEBUG + debug = 0; /* no debugging by default */ +#endif + + /* + * This is a big hack. We don't really want to read command line + * configuration until everything else is initialized, since + * the ability to configure the system may depend on storage + * and the like having been initialized. Except that we also + * don't want to initialize anything until after detaching from + * the terminal, but we won't know to do that until we've + * parsed the command line. Do that now, crudely, and do it + * again later. Our ntp_getopt() is explicitly reusable, by the + * way. Your own mileage may vary. + * + * This hack is even called twice (to allow complete logging to file) + */ + errflg = 0; + progname = argv[0]; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) + switch (c) { +#ifdef DEBUG + case 'd': + ++debug; + break; + case 'D': + debug = (int)atol(ntp_optarg); + printf("Debug1: %s -> %x = %d\n", ntp_optarg, debug, debug); + break; +#else + 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"); + ++errflg; + break; +#endif + case 'L': + listen_to_virtual_ips = 1; + break; + case 'l': + { + FILE *new_file; + + new_file = fopen(ntp_optarg, "a"); + if (new_file != NULL) { + NLOG(NLOG_SYSINFO) + msyslog(LOG_NOTICE, "logging to file %s", ntp_optarg); + if (syslog_file != NULL && + fileno(syslog_file) != fileno(new_file)) + (void)fclose(syslog_file); + + syslog_file = new_file; + syslogit = 0; + } + else + msyslog(LOG_ERR, + "Cannot open log file %s", + ntp_optarg); + } + break; + + case 'n': + case 'q': + ++nofork; + break; + + case 'N': + priority_done = strcmp(ntp_optarg, "high"); + break; + + case '?': + ++errflg; + break; + + default: + break; + } + + if (errflg || ntp_optind != argc) { + (void) fprintf(stderr, "usage: %s [ -abdgmnqx ] [ -c config_file ] [ -e e_delay ]\n", progname); + (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); + (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); + (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); +#if defined(HAVE_SCHED_SETSCHEDULER) + (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); +#endif + exit(2); + } + ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */ + +#ifdef DEBUG + if (debug) { +#ifdef HAVE_SETVBUF + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } +#endif +} + +/* + * getCmdOpts - get command line options + */ +void +getCmdOpts( + int argc, + char *argv[] + ) +{ + extern char *config_file; + int errflg; + int c; + + /* + * Initialize, initialize + */ + errflg = 0; +#ifdef DEBUG + debug = 0; +#endif /* DEBUG */ + + progname = argv[0]; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) { + switch (c) { + case 'a': + proto_config(PROTO_AUTHENTICATE, 1, 0.); + break; + + case 'A': + proto_config(PROTO_AUTHENTICATE, 0, 0.); + break; + + case 'b': + proto_config(PROTO_BROADCLIENT, 1, 0.); + break; + + case 'c': + config_file = ntp_optarg; +#ifdef HAVE_NETINFO + check_netinfo = 0; +#endif + break; + + case 'd': +#ifdef DEBUG + debug++; +#else + errflg++; +#endif /* DEBUG */ + break; + + case 'D': +#ifdef DEBUG + debug = (int)atol(ntp_optarg); + printf("Debug2: %s -> %x = %d\n", ntp_optarg, debug, debug); +#else + errflg++; +#endif /* DEBUG */ + break; + + case 'f': + stats_config(STATS_FREQ_FILE, ntp_optarg); + break; + + case 'g': + allow_panic = TRUE; + break; + + case 'k': + getauthkeys(ntp_optarg); + break; + + case 'L': /* already done at pre-scan */ + case 'l': /* already done at pre-scan */ + break; + + case 'm': + proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP), 0.); + sys_bclient = 1; + break; + + case 'n': /* already done at pre-scan */ + break; + + case 'N': /* already done at pre-scan */ + break; + + case 'p': + stats_config(STATS_PID_FILE, ntp_optarg); + break; + + case 'P': +#if defined(HAVE_SCHED_SETSCHEDULER) + config_priority = (int)atol(ntp_optarg); + config_priority_override = 1; +#else + errflg++; +#endif + break; + + case 'q': + mode_ntpdate = TRUE; + break; + + case 'r': + do { + double tmp; + + if (sscanf(ntp_optarg, "%lf", &tmp) != 1) { + msyslog(LOG_ERR, + "command line broadcast delay value %s undecodable", + ntp_optarg); + } else { + proto_config(PROTO_BROADDELAY, 0, tmp); + } + } while (0); + break; + + case 's': + stats_config(STATS_STATSDIR, ntp_optarg); + break; + + case 't': + do { + u_long tkey; + + tkey = (int)atol(ntp_optarg); + if (tkey <= 0 || tkey > NTP_MAXKEY) { + msyslog(LOG_ERR, + "command line trusted key %s is invalid", + ntp_optarg); + } else { + authtrust(tkey, 1); + } + } while (0); + break; + + case 'v': + case 'V': + set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, + RW | ((c == 'V') ? DEF : 0)); + break; + + case 'x': + allow_step = FALSE; + break; + + default: + errflg++; + break; + } + } + + if (errflg || ntp_optind != argc) { + (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); + (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); + (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); + (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); +#if defined(HAVE_SCHED_SETSCHEDULER) + (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); +#endif + exit(2); + } + return; +} diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c index e21f5b0..208b257 100644 --- a/contrib/ntp/ntpd/ntp_config.c +++ b/contrib/ntp/ntpd/ntp_config.c @@ -1,28 +1,12 @@ /* * ntp_config.c - read and apply configuration information */ - #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include <stdio.h> -#include <ctype.h> -#include <sys/param.h> -#include <sys/types.h> -#include <signal.h> -#ifndef SIGCHLD -#define SIGCHLD SIGCLD -#endif -#if !defined(VMS) -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#endif /* VMS */ -#include <sys/time.h> - #ifdef HAVE_NETINFO -#include <netinfo/ni.h> +# include <netinfo/ni.h> #endif #include "ntpd.h" @@ -31,12 +15,33 @@ #include "ntp_refclock.h" #include "ntp_filegen.h" #include "ntp_stdlib.h" +#include "ntp_config.h" +#include "ntp_cmdargs.h" + +#ifdef PUBKEY +# include "ntp_crypto.h" +#endif /* PUBKEY */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/param.h> +#include <signal.h> +#ifndef SIGCHLD +# define SIGCHLD SIGCLD +#endif +#if !defined(VMS) +# ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +# endif +#endif /* VMS */ #ifdef SYS_WINNT -#include <io.h> +# include <io.h> extern HANDLE ResolverThreadHandle; #endif /* SYS_WINNT */ +extern int priority_done; + /* * These routines are used to read the configuration file at * startup time. An entry in the file must fit on a single line. @@ -46,18 +51,6 @@ extern HANDLE ResolverThreadHandle; */ /* - * Configuration file name - */ -#ifndef CONFIG_FILE -# ifndef SYS_WINNT -# define CONFIG_FILE "/etc/ntp.conf" -# else /* SYS_WINNT */ -# define CONFIG_FILE "%windir%\\system32\\drivers\\etc\\ntp.conf" -# define ALT_CONFIG_FILE "%windir%\\ntp.conf" -# endif /* SYS_WINNT */ -#endif /* not CONFIG_FILE */ - -/* * We understand the following configuration entries and defaults. * * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] @@ -71,6 +64,8 @@ extern HANDLE ResolverThreadHandle; * 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 ] @@ -88,94 +83,10 @@ extern HANDLE ResolverThreadHandle; * disable auth|bclient|pll|kernel|monitor|stats * phone ... * pps device [assert|clear] [hardpps] + * priority high|normal */ /* - * Types of entries we understand. - */ -#define CONFIG_UNKNOWN 0 - -#define CONFIG_PEER 1 -#define CONFIG_SERVER 2 -#define CONFIG_AUTOMAX 3 -#define CONFIG_DRIFTFILE 4 -#define CONFIG_BROADCAST 5 -#define CONFIG_BROADCASTCLIENT 6 -#define CONFIG_AUTHENTICATE 7 -#define CONFIG_KEYS 8 -#define CONFIG_REVOKE 9 -#define CONFIG_PPS 10 -#define CONFIG_RESTRICT 11 -#define CONFIG_BDELAY 12 -#define CONFIG_TRUSTEDKEY 13 -#define CONFIG_REQUESTKEY 14 -#define CONFIG_CONTROLKEY 15 -#define CONFIG_TRAP 16 -#define CONFIG_FUDGE 17 -#define CONFIG_18 18 /* unused */ -#define CONFIG_STATSDIR 19 -#define CONFIG_FILEGEN 20 -#define CONFIG_STATISTICS 21 -#define CONFIG_PIDFILE 22 -#define CONFIG_SETVAR 23 -#define CONFIG_CLIENTLIMIT 24 -#define CONFIG_CLIENTPERIOD 25 -#define CONFIG_MULTICASTCLIENT 26 -#define CONFIG_ENABLE 27 -#define CONFIG_DISABLE 28 -#define CONFIG_PHONE 29 -#define CONFIG_LOGFILE 30 -#define CONFIG_LOGCONFIG 31 -#define CONFIG_MANYCASTCLIENT 32 -#define CONFIG_MANYCASTSERVER 33 - -#define CONF_MOD_VERSION 1 -#define CONF_MOD_KEY 2 -#define CONF_MOD_MINPOLL 3 -#define CONF_MOD_MAXPOLL 4 -#define CONF_MOD_PREFER 5 -#define CONF_MOD_BURST 6 -#define CONF_MOD_SKEY 7 -#define CONF_MOD_TTL 8 -#define CONF_MOD_MODE 9 -#define CONF_MOD_NOSELECT 10 - -#define CONF_RES_MASK 1 -#define CONF_RES_IGNORE 2 -#define CONF_RES_NOSERVE 3 -#define CONF_RES_NOTRUST 4 -#define CONF_RES_NOQUERY 5 -#define CONF_RES_NOMODIFY 6 -#define CONF_RES_NOPEER 7 -#define CONF_RES_NOTRAP 8 -#define CONF_RES_LPTRAP 9 -#define CONF_RES_NTPPORT 10 -#define CONF_RES_LIMITED 11 - -#define CONF_TRAP_PORT 1 -#define CONF_TRAP_INTERFACE 2 - -#define CONF_FDG_TIME1 1 -#define CONF_FDG_TIME2 2 -#define CONF_FDG_STRATUM 3 -#define CONF_FDG_REFID 4 -#define CONF_FDG_FLAG1 5 -#define CONF_FDG_FLAG2 6 -#define CONF_FDG_FLAG3 7 -#define CONF_FDG_FLAG4 8 - -#define CONF_FGEN_FILE 1 -#define CONF_FGEN_TYPE 2 -#define CONF_FGEN_FLAG_LINK 3 -#define CONF_FGEN_FLAG_NOLINK 4 -#define CONF_FGEN_FLAG_ENABLE 5 -#define CONF_FGEN_FLAG_DISABLE 6 - -#define CONF_PPS_ASSERT 1 -#define CONF_PPS_CLEAR 2 -#define CONF_PPS_HARDPPS 3 - -/* * Translation table - keywords to function index */ struct keyword { @@ -187,38 +98,46 @@ struct keyword { * Command keywords */ static struct keyword keywords[] = { - { "peer", CONFIG_PEER }, - { "server", CONFIG_SERVER }, - { "driftfile", CONFIG_DRIFTFILE }, - { "broadcast", CONFIG_BROADCAST }, - { "broadcastclient", CONFIG_BROADCASTCLIENT }, - { "multicastclient", CONFIG_MULTICASTCLIENT }, - { "manycastclient", CONFIG_MANYCASTCLIENT }, - { "manycastserver", CONFIG_MANYCASTSERVER }, { "authenticate", CONFIG_AUTHENTICATE }, - { "keys", CONFIG_KEYS }, - { "revoke", CONFIG_REVOKE }, - { "pps", CONFIG_PPS }, { "automax", CONFIG_AUTOMAX }, - { "restrict", CONFIG_RESTRICT }, + { "broadcast", CONFIG_BROADCAST }, + { "broadcastclient", CONFIG_BROADCASTCLIENT }, { "broadcastdelay", CONFIG_BDELAY }, - { "trustedkey", CONFIG_TRUSTEDKEY }, - { "requestkey", CONFIG_REQUESTKEY }, - { "controlkey", CONFIG_CONTROLKEY }, - { "trap", CONFIG_TRAP }, - { "fudge", CONFIG_FUDGE }, - { "statsdir", CONFIG_STATSDIR }, - { "filegen", CONFIG_FILEGEN }, - { "statistics", CONFIG_STATISTICS }, - { "pidfile", CONFIG_PIDFILE }, - { "setvar", CONFIG_SETVAR }, { "clientlimit", CONFIG_CLIENTLIMIT }, { "clientperiod", CONFIG_CLIENTPERIOD }, - { "enable", CONFIG_ENABLE }, +#ifdef PUBKEY + { "crypto", CONFIG_CRYPTO }, +#endif /* PUBKEY */ + { "controlkey", CONFIG_CONTROLKEY }, { "disable", CONFIG_DISABLE }, - { "phone", CONFIG_PHONE }, - { "logfile", CONFIG_LOGFILE }, + { "driftfile", CONFIG_DRIFTFILE }, + { "enable", CONFIG_ENABLE }, + { "filegen", CONFIG_FILEGEN }, + { "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 }, + { "manycastserver", CONFIG_MANYCASTSERVER }, + { "multicastclient", CONFIG_MULTICASTCLIENT }, + { "peer", CONFIG_PEER }, + { "phone", CONFIG_PHONE }, + { "pidfile", CONFIG_PIDFILE }, + { "pps", CONFIG_PPS }, + { "requestkey", CONFIG_REQUESTKEY }, + { "restrict", CONFIG_RESTRICT }, + { "revoke", CONFIG_REVOKE }, + { "server", CONFIG_SERVER }, + { "setvar", CONFIG_SETVAR }, + { "statistics", CONFIG_STATISTICS }, + { "statsdir", CONFIG_STATSDIR }, + { "tinker", CONFIG_TINKER }, + { "trap", CONFIG_TRAP }, + { "trustedkey", CONFIG_TRUSTEDKEY }, { "", CONFIG_UNKNOWN } }; @@ -226,16 +145,20 @@ static struct keyword keywords[] = { * "peer", "server", "broadcast" modifier keywords */ static struct keyword mod_keywords[] = { - { "version", CONF_MOD_VERSION }, + { "autokey", CONF_MOD_SKEY }, + { "burst", CONF_MOD_BURST }, + { "iburst", CONF_MOD_IBURST }, { "key", CONF_MOD_KEY }, - { "minpoll", CONF_MOD_MINPOLL }, { "maxpoll", CONF_MOD_MAXPOLL }, - { "prefer", CONF_MOD_PREFER }, + { "minpoll", CONF_MOD_MINPOLL }, + { "mode", CONF_MOD_MODE }, /* refclocks */ { "noselect", CONF_MOD_NOSELECT }, - { "burst", CONF_MOD_BURST }, - { "autokey", CONF_MOD_SKEY }, - { "mode", CONF_MOD_MODE }, /* reference clocks */ + { "prefer", CONF_MOD_PREFER }, +#ifdef PUBKEY + { "publickey", CONF_MOD_PUBLICKEY }, +#endif /* PUBKEY */ { "ttl", CONF_MOD_TTL }, /* NTP peers */ + { "version", CONF_MOD_VERSION }, { "", CONFIG_UNKNOWN } }; @@ -243,17 +166,19 @@ static struct keyword mod_keywords[] = { * "restrict" modifier keywords */ static struct keyword res_keywords[] = { - { "mask", CONF_RES_MASK }, { "ignore", CONF_RES_IGNORE }, - { "noserve", CONF_RES_NOSERVE }, - { "notrust", CONF_RES_NOTRUST }, - { "noquery", CONF_RES_NOQUERY }, + { "limited", CONF_RES_LIMITED }, + { "kod", CONF_RES_DEMOBILIZE }, + { "lowpriotrap", CONF_RES_LPTRAP }, + { "mask", CONF_RES_MASK }, { "nomodify", CONF_RES_NOMODIFY }, { "nopeer", CONF_RES_NOPEER }, + { "noquery", CONF_RES_NOQUERY }, + { "noserve", CONF_RES_NOSERVE }, { "notrap", CONF_RES_NOTRAP }, - { "lowpriotrap", CONF_RES_LPTRAP }, + { "notrust", CONF_RES_NOTRUST }, { "ntpport", CONF_RES_NTPPORT }, - { "limited", CONF_RES_LIMITED }, + { "version", CONF_RES_VERSION }, { "", CONFIG_UNKNOWN } }; @@ -266,19 +191,18 @@ static struct keyword trap_keywords[] = { { "", CONFIG_UNKNOWN } }; - /* * "fudge" modifier keywords */ static struct keyword fudge_keywords[] = { - { "time1", CONF_FDG_TIME1 }, - { "time2", CONF_FDG_TIME2 }, - { "stratum", CONF_FDG_STRATUM }, - { "refid", CONF_FDG_REFID }, { "flag1", CONF_FDG_FLAG1 }, { "flag2", CONF_FDG_FLAG2 }, { "flag3", CONF_FDG_FLAG3 }, { "flag4", CONF_FDG_FLAG4 }, + { "refid", CONF_FDG_REFID }, + { "stratum", CONF_FDG_STRATUM }, + { "time1", CONF_FDG_TIME1 }, + { "time2", CONF_FDG_TIME2 }, { "", CONFIG_UNKNOWN } }; @@ -287,12 +211,12 @@ static struct keyword fudge_keywords[] = { * "filegen" modifier keywords */ static struct keyword filegen_keywords[] = { + { "disable", CONF_FGEN_FLAG_DISABLE }, + { "enable", CONF_FGEN_FLAG_ENABLE }, { "file", CONF_FGEN_FILE }, - { "type", CONF_FGEN_TYPE }, { "link", CONF_FGEN_FLAG_LINK }, { "nolink", CONF_FGEN_FLAG_NOLINK }, - { "enable", CONF_FGEN_FLAG_ENABLE }, - { "disable", CONF_FGEN_FLAG_DISABLE }, + { "type", CONF_FGEN_TYPE }, { "", CONFIG_UNKNOWN } }; @@ -300,13 +224,13 @@ static struct keyword filegen_keywords[] = { * "type" modifier keywords */ static struct keyword fgen_types[] = { + { "age", FILEGEN_AGE }, + { "day", FILEGEN_DAY }, + { "month", FILEGEN_MONTH }, { "none", FILEGEN_NONE }, { "pid", FILEGEN_PID }, - { "day", FILEGEN_DAY }, { "week", FILEGEN_WEEK }, - { "month", FILEGEN_MONTH }, { "year", FILEGEN_YEAR }, - { "age", FILEGEN_AGE }, { "", CONFIG_UNKNOWN} }; @@ -316,15 +240,17 @@ static struct keyword fgen_types[] = { static struct keyword flags_keywords[] = { { "auth", PROTO_AUTHENTICATE }, { "bclient", PROTO_BROADCLIENT }, - { "ntp", PROTO_NTP }, { "kernel", PROTO_KERNEL }, { "monitor", PROTO_MONITOR }, + { "ntp", PROTO_NTP }, { "stats", PROTO_FILEGEN }, + { "pps", PROTO_PPS }, + { "calibrate", PROTO_CAL }, { "", CONFIG_UNKNOWN } }; /* - * pps modifier keywords + * "pps" modifier keywords */ static struct keyword pps_keywords[] = { { "assert", CONF_PPS_ASSERT }, @@ -334,6 +260,34 @@ static struct keyword pps_keywords[] = { }; /* + * "tinker" modifier keywords + */ +static struct keyword tinker_keywords[] = { + { "step", CONF_CLOCK_MAX }, + { "panic", CONF_CLOCK_PANIC }, + { "dispersion", CONF_CLOCK_PHI }, + { "stepout", CONF_CLOCK_MINSTEP }, + { "minpoll", CONF_CLOCK_MINPOLL }, + { "allan", CONF_CLOCK_ALLAN }, + { "huffpuff", CONF_CLOCK_HUFFPUFF }, + { "", CONFIG_UNKNOWN } +}; + +#ifdef PUBKEY +/* + * "crypto" modifier keywords + */ +static struct keyword crypto_keywords[] = { + { "dh", CONF_CRYPTO_DH }, + { "flags", CONF_CRYPTO_FLAGS }, + { "leap", CONF_CRYPTO_LEAP }, + { "privatekey", CONF_CRYPTO_PRIVATEKEY }, + { "publickey", CONF_CRYPTO_PUBLICKEY }, + { "", CONFIG_UNKNOWN } +}; +#endif /* PUBKEY */ + +/* * "logconfig" building blocks */ struct masks { @@ -342,10 +296,10 @@ struct masks { }; static struct masks logcfg_class[] = { - { "sys", NLOG_OSYS }, - { "peer", NLOG_OPEER }, { "clock", NLOG_OCLOCK }, + { "peer", NLOG_OPEER }, { "sync", NLOG_OSYNC }, + { "sys", NLOG_OSYS }, { (char *)0, 0 } }; @@ -373,8 +327,7 @@ static struct masks logcfg_item[] = { #define MAXLINE 1024 /* maximum length of line */ #define MAXPHONE 5 /* maximum number of phone strings */ #define MAXPPS 20 /* maximum length of PPS device string */ -#define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */ - +#define MAXINCLUDELEVEL 5 /* maximum include file levels */ /* * Miscellaneous macros @@ -384,6 +337,8 @@ static struct masks logcfg_item[] = { #define ISSPACE(c) ((c) == ' ' || (c) == '\t') #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) +#define KEY_TYPE_MD5 4 + /* * File descriptor used by the resolver save routines, and temporary file * name. @@ -402,15 +357,24 @@ static char res_file[MAX_PATH]; char const *progname; char sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */ char pps_device[MAXPPS + 1]; /* PPS device name */ -int pps_assert = 1; +int pps_assert; int pps_hardpps; -int listen_to_virtual_ips = 0; #if defined(HAVE_SCHED_SETSCHEDULER) int config_priority_override = 0; int config_priority; #endif -static const char *ntp_options = "aAbc:dD:f:gk:l:Lmnp:P:r:s:t:v:V:x"; +const char *config_file; +#ifdef HAVE_NETINFO + struct netinfo_config_state *config_netinfo = NULL; + int check_netinfo = 1; +#endif /* HAVE_NETINFO */ +#ifdef SYS_WINNT + char *alt_config_file; + LPTSTR temp; + char config_file_storage[MAX_PATH]; + char alt_config_file_storage[MAX_PATH]; +#endif /* SYS_WINNT */ #ifdef HAVE_NETINFO /* @@ -439,7 +403,8 @@ static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *)); 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 void save_resolve P((char *, int, int, int, int, int, int, u_long)); +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) @@ -510,119 +475,6 @@ get_logmask( return 0; } -/* - * getstartup - search through the options looking for a debugging flag - */ -void -getstartup( - int argc, - char *argv[] - ) -{ - int errflg; - int c; - -#ifdef DEBUG - debug = 0; /* no debugging by default */ -#endif - - /* - * This is a big hack. We don't really want to read command line - * configuration until everything else is initialized, since - * the ability to configure the system may depend on storage - * and the like having been initialized. Except that we also - * don't want to initialize anything until after detaching from - * the terminal, but we won't know to do that until we've - * parsed the command line. Do that now, crudely, and do it - * again later. Our ntp_getopt() is explicitly reusable, by the - * way. Your own mileage may vary. - * - * This hack is even called twice (to allow complete logging to file) - */ - errflg = 0; - progname = argv[0]; - - /* - * Decode argument list - */ - while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) - switch (c) { -#ifdef DEBUG - case 'd': - ++debug; - break; - case 'D': - debug = (int)atol(ntp_optarg); - printf("Debug1: %s -> %x = %d\n", ntp_optarg, debug, debug); - break; -#else - 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"); - ++errflg; - break; -#endif - case 'L': - listen_to_virtual_ips = 1; - break; - case 'l': - { - FILE *new_file; - - new_file = fopen(ntp_optarg, "a"); - if (new_file != NULL) { - NLOG(NLOG_SYSINFO) - msyslog(LOG_NOTICE, "logging to file %s", ntp_optarg); - if (syslog_file != NULL && - fileno(syslog_file) != fileno(new_file)) - (void)fclose(syslog_file); - - syslog_file = new_file; - syslogit = 0; - } - else - msyslog(LOG_ERR, - "Cannot open log file %s", - ntp_optarg); - } - break; - - case 'n': - ++nofork; - break; - - case '?': - ++errflg; - break; - - default: - break; - } - - if (errflg || ntp_optind != argc) { - (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); - (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); - (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); - (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); -#if defined(HAVE_SCHED_SETSCHEDULER) - (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); -#endif - exit(2); - } - ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */ - -#ifdef DEBUG - if (debug) { -#ifdef HAVE_SETVBUF - static char buf[BUFSIZ]; - setvbuf(stdout, buf, _IOLBF, BUFSIZ); -#else - setlinebuf(stdout); -#endif - } -#endif -} /* * getconfig - get command line options and read the configuration file @@ -640,29 +492,23 @@ getconfig( int minpoll; int maxpoll; int ttl; - u_long peerkey; - u_long lpeerkey; - int peerflags; + long stratum; + unsigned long ul; + keyid_t peerkey; + u_char *peerkeystr; + u_long fudgeflag; + u_int peerflags; int hmode; struct sockaddr_in peeraddr; struct sockaddr_in maskaddr; - FILE *fp; + FILE *fp[MAXINCLUDELEVEL+1]; + FILE *includefile; + int includelevel = 0; char line[MAXLINE]; char *(tokens[MAXTOKENS]); int ntokens; int tok = CONFIG_UNKNOWN; struct interface *localaddr; - const char *config_file; -#ifdef HAVE_NETINFO - struct netinfo_config_state *config_netinfo = NULL; - int check_netinfo = 1; -#endif /* HAVE_NETINFO */ -#ifdef SYS_WINNT - char *alt_config_file; - LPTSTR temp; - char config_file_storage[MAX_PATH]; - char alt_config_file_storage[MAX_PATH]; -#endif /* SYS_WINNT */ struct refclockstat clock_stat; FILEGEN *filegen; @@ -670,9 +516,7 @@ getconfig( * Initialize, initialize */ errflg = 0; -#ifdef DEBUG - debug = 0; -#endif /* DEBUG */ + /* HMS: don't initialize debug to 0 here! */ #ifndef SYS_WINNT config_file = CONFIG_FILE; #else @@ -713,146 +557,10 @@ getconfig( */ loop_config(LOOP_DRIFTINIT, 0.); - /* - * Decode argument list - */ - while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) { - switch (c) { - case 'a': - proto_config(PROTO_AUTHENTICATE, 1, 0.); - break; - - case 'A': - proto_config(PROTO_AUTHENTICATE, 0, 0.); - break; - - case 'b': - proto_config(PROTO_BROADCLIENT, 1, 0.); - break; - - case 'c': - config_file = ntp_optarg; -#ifdef HAVE_NETINFO - check_netinfo = 0; -#endif - break; - - case 'd': -#ifdef DEBUG - debug++; -#else - errflg++; -#endif /* DEBUG */ - break; - - case 'D': -#ifdef DEBUG - debug = (int)atol(ntp_optarg); - printf("Debug2: %s -> %x = %d\n", ntp_optarg, debug, debug); -#else - errflg++; -#endif /* DEBUG */ - break; - - case 'f': - stats_config(STATS_FREQ_FILE, ntp_optarg); - break; - - case 'g': - correct_any = TRUE; - break; - - case 'k': - getauthkeys(ntp_optarg); - break; - - case 'L': /* already done at pre-scan */ - case 'l': /* already done at pre-scan */ - break; - - case 'm': - proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP), 0.); - sys_bclient = 1; - break; - - case 'n': /* already done at pre-scan */ - break; - - case 'p': - stats_config(STATS_PID_FILE, ntp_optarg); - break; - - case 'P': -#if defined(HAVE_SCHED_SETSCHEDULER) - config_priority = (int)atol(ntp_optarg); - config_priority_override = 1; -#else - errflg++; -#endif - break; - - case 'r': - do { - double tmp; - - if (sscanf(ntp_optarg, "%lf", &tmp) != 1) { - msyslog(LOG_ERR, - "command line broadcast delay value %s undecodable", - ntp_optarg); - } else { - proto_config(PROTO_BROADDELAY, 0, tmp); - } - } while (0); - break; - - case 's': - stats_config(STATS_STATSDIR, ntp_optarg); - break; - - case 't': - do { - u_long tkey; - - tkey = (int)atol(ntp_optarg); - if (tkey <= 0 || tkey > NTP_MAXKEY) { - msyslog(LOG_ERR, - "command line trusted key %s is invalid", - ntp_optarg); - } else { - authtrust(tkey, 1); - } - } while (0); - break; - - case 'v': - case 'V': - set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, - RW | ((c == 'V') ? DEF : 0)); - break; - - case 'x': - allow_set_backward = FALSE; - break; - - default: - errflg++; - break; - } - } - - if (errflg || ntp_optind != argc) { - (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); - (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); - (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); - (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); -#if defined(HAVE_SCHED_SETSCHEDULER) - (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); -#endif - exit(2); - } + getCmdOpts(argc, argv); if ( - (fp = fopen(FindConfig(config_file), "r")) == NULL + (fp[0] = fopen(FindConfig(config_file), "r")) == NULL #ifdef HAVE_NETINFO /* If there is no config_file, try NetInfo. */ && check_netinfo && !(config_netinfo = get_netinfo_config()) @@ -863,7 +571,7 @@ getconfig( #ifdef SYS_WINNT /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ - if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) { + if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) { /* * Broadcast clients can sometimes run without @@ -880,14 +588,21 @@ getconfig( } for (;;) { - if (fp) - tok = gettokens(fp, line, tokens, &ntokens); + if (fp[includelevel]) + tok = gettokens(fp[includelevel], line, tokens, &ntokens); #ifdef HAVE_NETINFO else tok = gettokens_netinfo(config_netinfo, tokens, &ntokens); #endif /* HAVE_NETINFO */ - if (tok == CONFIG_UNKNOWN) break; + if (tok == CONFIG_UNKNOWN) { + if (includelevel > 0) { + fclose(fp[includelevel--]); + continue; + } else { + break; + } + } switch(tok) { case CONFIG_PEER: @@ -954,6 +669,7 @@ getconfig( minpoll = NTP_MINDPOLL; maxpoll = NTP_MAXDPOLL; peerkey = 0; + peerkeystr = "*"; peerflags = 0; ttl = 0; for (i = 2; i < ntokens; i++) @@ -994,8 +710,12 @@ getconfig( break; } minpoll = atoi(tokens[++i]); - if (minpoll < NTP_MINPOLL) + if (minpoll < NTP_MINPOLL) { + msyslog(LOG_INFO, + "minpoll: provided value (%d) is below minimum (%d)", + minpoll, NTP_MINPOLL); minpoll = NTP_MINPOLL; + } break; case CONF_MOD_MAXPOLL: @@ -1007,8 +727,12 @@ getconfig( break; } maxpoll = atoi(tokens[++i]); - if (maxpoll > NTP_MAXPOLL) + if (maxpoll > NTP_MAXPOLL) { + msyslog(LOG_INFO, + "maxpoll: provided value (%d) is above maximum (%d)", + maxpoll, NTP_MAXPOLL); maxpoll = NTP_MAXPOLL; + } break; case CONF_MOD_PREFER: @@ -1023,10 +747,30 @@ getconfig( peerflags |= FLAG_BURST; break; + case CONF_MOD_IBURST: + peerflags |= FLAG_IBURST; + break; +#ifdef AUTOKEY case CONF_MOD_SKEY: - peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; + 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 */ + case CONF_MOD_TTL: if (i >= ntokens-1) { msyslog(LOG_ERR, @@ -1056,19 +800,18 @@ getconfig( errflg = 1; } if (errflg == 0) { - if (peer_config(&peeraddr, - (struct interface *)0, hmode, - peerversion, minpoll, maxpoll, - peerflags, ttl, peerkey) - == 0) { + if (peer_config(&peeraddr, any_interface, hmode, + peerversion, minpoll, maxpoll, peerflags, + ttl, peerkey, peerkeystr) == 0) { msyslog(LOG_ERR, "configuration of %s failed", ntoa(&peeraddr)); - } + } + } else if (errflg == -1) { save_resolve(tokens[1], hmode, peerversion, - minpoll, maxpoll, peerflags, ttl, - peerkey); + minpoll, maxpoll, peerflags, ttl, + peerkey, peerkeystr); } break; @@ -1086,9 +829,29 @@ getconfig( stats_config(STATS_PID_FILE, (char *)0); break; + case CONFIG_INCLUDEFILE: + if (ntokens < 2) { + msyslog(LOG_ERR, "includefile needs one argument"); + break; + } + if (includelevel >= MAXINCLUDELEVEL) { + fprintf(stderr, "getconfig: Maximum include file level exceeded.\n"); + msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded."); + break; + } + includefile = fopen(FindConfig(tokens[1]), "r"); + if (includefile == NULL) { + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1])); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1])); + break; + } + fp[++includelevel] = includefile; + break; + case CONFIG_LOGFILE: if (ntokens >= 2) { FILE *new_file; + new_file = fopen(tokens[1], "a"); if (new_file != NULL) { NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ @@ -1159,20 +922,10 @@ getconfig( } else proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP), 0.); - if (tok == CONFIG_MULTICASTCLIENT) { + if (tok == CONFIG_MULTICASTCLIENT) sys_bclient = 1; -#ifdef DEBUG - if (debug) - printf("sys_bclient\n"); -#endif /* DEBUG */ - } - else if (tok == CONFIG_MANYCASTSERVER) { + else if (tok == CONFIG_MANYCASTSERVER) sys_manycastserver = 1; -#ifdef DEBUG - if (debug) - printf("sys_manycastserver\n"); -#endif /* DEBUG */ - } break; case CONFIG_AUTHENTICATE: @@ -1199,17 +952,121 @@ getconfig( } break; - case CONFIG_REVOKE: - if (ntokens >= 2) { - sys_revoke = 1 << max(atoi(tokens[1]), 10); + case CONFIG_TINKER: + for (i = 1; i < ntokens; i++) { + int temp; + double ftemp; + + temp = matchkey(tokens[i++], + tinker_keywords); + if (i > ntokens - 1) { + msyslog(LOG_ERR, + "tinker: missing argument"); + errflg++; + break; + } + sscanf(tokens[i], "%lf", &ftemp); + switch(temp) { + case CONF_CLOCK_MAX: + loop_config(LOOP_MAX, ftemp); + break; + + case CONF_CLOCK_PANIC: + loop_config(LOOP_PANIC, ftemp); + break; + + case CONF_CLOCK_PHI: + loop_config(LOOP_PHI, ftemp); + break; + + case CONF_CLOCK_MINSTEP: + 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; + + case CONF_CLOCK_HUFFPUFF: + loop_config(LOOP_HUFFPUFF, ftemp); + break; + } } break; +#ifdef AUTOKEY + case CONFIG_REVOKE: + if (ntokens >= 2) + sys_revoke = 1 << max(atoi(tokens[1]), 10); + break; + case CONFIG_AUTOMAX: - if (ntokens >= 2) { - sys_automax = 1 << max(atoi(tokens[1]), 10); + if (ntokens >= 2) + 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"); + break; + } + for (i = 1; i < ntokens; i++) { + int temp; + + temp = matchkey(tokens[i++], crypto_keywords); + if (i > ntokens - 1) { + msyslog(LOG_ERR, + "crypto: missing argument"); + errflg++; + break; + } + switch(temp) { + case CONF_CRYPTO_FLAGS: + crypto_config(CRYPTO_CONF_FLAGS, tokens[i]); + break; + + case CONF_CRYPTO_LEAP: + crypto_config(CRYPTO_CONF_LEAP, tokens[i]); + break; + + case CONF_CRYPTO_DH: + crypto_config(CRYPTO_CONF_DH, tokens[i]); + break; + + case CONF_CRYPTO_PRIVATEKEY: + crypto_config(CRYPTO_CONF_PRIV, tokens[i]); + break; + + case CONF_CRYPTO_PUBLICKEY: + crypto_config(CRYPTO_CONF_PUBL, tokens[i]); + break; + + case CONF_CRYPTO_CERT: + crypto_config(CRYPTO_CONF_CERT, tokens[i]); + break; + + default: + msyslog(LOG_ERR, "crypto: unknown keyword"); + break; + } } break; +#endif /* PUBKEY */ +#endif /* AUTOKEY */ case CONFIG_RESTRICT: if (ntokens < 2) { @@ -1278,6 +1135,14 @@ getconfig( peerkey |= RESM_NTPONLY; break; + case CONF_RES_VERSION: + peerversion |= RES_VERSION; + break; + + case CONF_RES_DEMOBILIZE: + peerversion |= RES_DEMOBILIZE; + break; + case CONF_RES_LIMITED: peerversion |= RES_LIMITED; break; @@ -1310,7 +1175,7 @@ getconfig( case CONFIG_TRUSTEDKEY: for (i = 1; i < ntokens; i++) { - u_long tkey; + keyid_t tkey; tkey = atol(tokens[i]); if (tkey == 0) { @@ -1325,13 +1190,11 @@ getconfig( case CONFIG_REQUESTKEY: if (ntokens >= 2) { - u_long rkey; - - if (!atouint(tokens[1], &rkey)) { + if (!atouint(tokens[1], &ul)) { msyslog(LOG_ERR, "%s is undecodable as request key", tokens[1]); - } else if (rkey == 0) { + } else if (ul == 0) { msyslog(LOG_ERR, "%s makes a poor request keyid", tokens[1]); @@ -1339,16 +1202,16 @@ getconfig( #ifdef DEBUG if (debug > 3) printf( - "set info_auth_key to %lu\n", rkey); + "set info_auth_key to %08lx\n", ul); #endif - info_auth_keyid = rkey; + info_auth_keyid = (keyid_t)ul; } } break; case CONFIG_CONTROLKEY: if (ntokens >= 2) { - u_long ckey; + keyid_t ckey; ckey = atol(tokens[1]); if (ckey == 0) { @@ -1455,6 +1318,7 @@ getconfig( } memset((void *)&clock_stat, 0, sizeof clock_stat); + fudgeflag = 0; errflg = 0; for (i = 2; i < ntokens-1; i++) { switch (c = matchkey(tokens[i], @@ -1485,9 +1349,7 @@ getconfig( case CONF_FDG_STRATUM: - /* HMS: the (long *)_ may be trouble */ - if (!atoint(tokens[++i], - (long *)&clock_stat.fudgeval1)) + if (!atoint(tokens[++i], &stratum)) { msyslog(LOG_ERR, "fudge %s stratum value in error", @@ -1495,6 +1357,7 @@ getconfig( errflg = i; break; } + clock_stat.fudgeval1 = stratum; clock_stat.haveflags |= CLK_HAVEVAL1; break; @@ -1510,16 +1373,14 @@ getconfig( case CONF_FDG_FLAG2: case CONF_FDG_FLAG3: case CONF_FDG_FLAG4: - if (!atouint(tokens[++i], &lpeerkey) - || lpeerkey > 1) { + if (!atouint(tokens[++i], &fudgeflag) + || fudgeflag > 1) { msyslog(LOG_ERR, "fudge %s flag value in error", ntoa(&peeraddr)); - peerkey = lpeerkey; errflg = i; break; } - peerkey = lpeerkey; switch(c) { case CONF_FDG_FLAG1: c = CLK_FLAG1; @@ -1538,7 +1399,7 @@ getconfig( clock_stat.haveflags|=CLK_HAVEFLAG4; break; } - if (peerkey == 0) + if (fudgeflag == 0) clock_stat.flags &= ~c; else clock_stat.flags |= c; @@ -1558,15 +1419,14 @@ getconfig( */ if (!errflg) { refclock_control(&peeraddr, &clock_stat, - (struct refclockstat *)0); + (struct refclockstat *)0); } #endif break; case CONFIG_STATSDIR: - if (ntokens >= 2) { + if (ntokens >= 2) stats_config(STATS_STATSDIR,tokens[1]); - } break; case CONFIG_STATISTICS: @@ -1659,10 +1519,9 @@ getconfig( break; } } - if (!errflg) { + if (!errflg) filegen_config(filegen, tokens[peerversion], - (u_char)peerkey, (u_char)peerflags); - } + (u_char)peerkey, (u_char)peerflags); break; case CONFIG_SETVAR: @@ -1776,10 +1635,10 @@ getconfig( flag = matchkey(tokens[i], pps_keywords); switch(flag) { case CONF_PPS_ASSERT: - pps_assert = 1; + pps_assert = 0; break; case CONF_PPS_CLEAR: - pps_assert = 0; + pps_assert = 1; break; case CONF_PPS_HARDPPS: pps_hardpps = 1; @@ -1797,11 +1656,44 @@ getconfig( break; } } - if (fp) (void)fclose(fp); + if (fp[0]) + (void)fclose(fp[0]); + #ifdef HAVE_NETINFO - if (config_netinfo) free_netinfo_config(config_netinfo); + if (config_netinfo) + free_netinfo_config(config_netinfo); #endif /* HAVE_NETINFO */ +#if !defined(VMS) && !defined(SYS_VXWORKS) + /* find a keyid */ + if (info_auth_keyid == 0) + req_keyid = 65535; + else + req_keyid = info_auth_keyid; + + /* if doesn't exist, make up one at random */ + if (!authhavekey(req_keyid)) { + char rankey[9]; + int j; + + for (i = 0; i < 8; i++) + for (j = 1; j < 100; ++j) { + rankey[i] = RANDOM & 0xff; + if (rankey[i] != 0) break; + } + rankey[8] = 0; + authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey); + authtrust(req_keyid, 1); + if (!authhavekey(req_keyid)) { + msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!"); + /* HMS: Should this be fatal? */ + } + } + + /* save keyid so we will accept config requests with it */ + info_auth_keyid = req_keyid; +#endif /* !defined(VMS) && !defined(SYS_VXWORKS) */ + if (res_fp != NULL) { /* * Need name resolution @@ -2165,9 +2057,10 @@ save_resolve( int version, int minpoll, int maxpoll, - int flags, + u_int flags, int ttl, - u_long keyid + keyid_t keyid, + u_char *keystr ) { #ifndef SYS_VXWORKS @@ -2191,7 +2084,7 @@ save_resolve( res_fp = NULL; if ((fd = mkstemp(res_file)) != -1) - res_fp = fdopen(fd, "w"); + res_fp = fdopen(fd, "r+"); } #else (void) mktemp(res_file); @@ -2208,8 +2101,14 @@ save_resolve( } #endif - (void) fprintf(res_fp, "%s %d %d %d %d %d %d %lu\n", name, mode, - version, minpoll, maxpoll, flags, ttl, keyid); + (void)fprintf(res_fp, "%s %d %d %d %d %d %d %d %s\n", name, + mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr); +#ifdef DEBUG + if (debug > 1) + printf("config: %s %d %d %d %d %x %d %08x %s\n", name, mode, + version, minpoll, maxpoll, flags, ttl, keyid, keystr); +#endif + #else /* SYS_VXWORKS */ /* save resolve info to a struct */ #endif /* SYS_VXWORKS */ @@ -2242,8 +2141,6 @@ abort_resolve(void) } -#define KEY_TYPE_MD5 4 - /* * do_resolve_internal - start up the resolver function (not program) */ @@ -2262,7 +2159,7 @@ do_resolve_internal(void) if (res_fp == NULL) { /* belch */ msyslog(LOG_ERR, - "internal error in do_resolve_internal: res_fp == NULL"); + "do_resolve_internal: Fatal: res_fp == NULL"); exit(1); } @@ -2271,24 +2168,6 @@ do_resolve_internal(void) res_fp = NULL; #if !defined(VMS) && !defined (SYS_VXWORKS) - /* find a keyid */ - if (info_auth_keyid == 0) - req_keyid = 65535; - else - req_keyid = info_auth_keyid; - - /* if doesn't exist, make up one at random */ - if (!authhavekey(req_keyid)) { - char rankey[8]; - - for (i = 0; i < 8; i++) - rankey[i] = RANDOM & 0xff; - authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey); - authtrust(req_keyid, 1); - } - - /* save keyid so we will accept config requests with it */ - info_auth_keyid = req_keyid; req_file = res_file; /* set up pointer to res file */ #ifndef SYS_WINNT (void) signal_no_reset(SIGCHLD, catchchild); @@ -2317,10 +2196,10 @@ do_resolve_internal(void) * async io information causes it to process requests from * all file decriptor causing a race between the NTP daemon * and the resolver. which then eats data when it wins 8-(. - * It is absolutly necessary to kill ane io associations - * shared with the NTP daemon. I currently don't want + * It is absolutly necessary to kill any IO associations + * shared with the NTP daemon. * - * we also block SIGIO (currently no portes means to + * We also block SIGIO (currently no ports means to * disable the signal handle for IO). * * Thanks to wgstuken@informatik.uni-erlangen.de to notice diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c index e2fb039..570e2f9 100644 --- a/contrib/ntp/ntpd/ntp_control.c +++ b/contrib/ntp/ntpd/ntp_control.c @@ -5,18 +5,23 @@ #include <config.h> #endif -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <signal.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_control.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> +#include <signal.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifdef PUBKEY +#include "ntp_crypto.h" +#endif /* PUBKEY */ + /* * Structure to hold request procedure information */ @@ -26,9 +31,9 @@ #define NO_REQUEST (-1) struct ctl_proc { - short control_code; /* defined request code */ - u_short flags; /* flags word */ - void (*handler) P((struct recvbuf *, int)); /* routine to handle request */ + short control_code; /* defined request code */ + u_short flags; /* flags word */ + void (*handler) P((struct recvbuf *, int)); /* handle request */ }; /* @@ -44,9 +49,10 @@ static void ctl_error P((int)); static u_short ctlclkstatus P((struct refclockstat *)); static void ctl_flushpkt P((int)); static void ctl_putdata P((const char *, unsigned int, int)); -static void ctl_putstr P((const char *, const char *, unsigned int)); +static void ctl_putstr P((const char *, const char *, + unsigned int)); static void ctl_putdbl P((const char *, double)); -static void ctl_putuint P((const char *, u_long)); +static void ctl_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 *)); @@ -54,21 +60,22 @@ static void ctl_putadr P((const char *, u_int32)); static void ctl_putid P((const char *, char *)); static void ctl_putarray P((const char *, double *, int)); static void ctl_putsys P((int)); -static void ctl_putpeer P((int, struct peer *)); +static void ctl_putpeer P((int, struct peer *)); #ifdef REFCLOCK static void ctl_putclock P((int, struct refclockstat *, int)); #endif /* REFCLOCK */ static struct ctl_var *ctl_getitem P((struct ctl_var *, char **)); -static u_long count_var P((struct ctl_var *)); +static u_long count_var P((struct ctl_var *)); static void control_unspec P((struct recvbuf *, int)); -static void read_status P((struct recvbuf *, int)); +static void read_status P((struct recvbuf *, int)); static void read_variables P((struct recvbuf *, int)); static void write_variables P((struct recvbuf *, int)); -static void read_clock_status P((struct recvbuf *, int)); -static void write_clock_status P((struct recvbuf *, int)); +static void 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 *, struct interface *)); +static struct ctl_trap *ctlfindtrap P((struct sockaddr_in *, + struct interface *)); static struct ctl_proc control_codes[] = { { CTL_OP_UNSPEC, NOAUTH, control_unspec }, @@ -83,10 +90,10 @@ static struct ctl_proc control_codes[] = { }; /* - * System variable values. The array can be indexed by - * the variable index to find the textual name. + * System variable values. The array can be indexed by the variable + * index to find the textual name. */ -static struct ctl_var sys_var[] = { +static struct ctl_var sys_var[] = { { 0, PADDING, "" }, /* 0 */ { CS_LEAP, RW, "leap" }, /* 1 */ { CS_STRATUM, RO, "stratum" }, /* 2 */ @@ -98,23 +105,36 @@ static struct ctl_var sys_var[] = { { CS_POLL, RO, "poll" }, /* 8 */ { CS_PEERID, RO, "peer" }, /* 9 */ { CS_STATE, RO, "state" }, /* 10 */ - { CS_OFFSET, RO, "phase" }, /* 11 */ + { CS_OFFSET, RO, "offset" }, /* 11 */ { CS_DRIFT, RO, "frequency" }, /* 12 */ - { CS_COMPLIANCE, RO, "jitter" }, /* 13 */ + { CS_JITTER, RO, "jitter" }, /* 13 */ { CS_CLOCK, RO, "clock" }, /* 14 */ { CS_PROCESSOR, RO, "processor" }, /* 15 */ { CS_SYSTEM, RO, "system" }, /* 16 */ - { CS_STABIL, RO, "stability" }, /* 17 */ - { CS_VARLIST, RO, "sys_var_list" }, /* 18 */ - { 0, EOV, "" } + { CS_VERSION, RO, "version" }, /* 17 */ + { CS_STABIL, RO, "stability" }, /* 18 */ + { CS_VARLIST, RO, "sys_var_list" }, /* 19 */ +#ifdef PUBKEY + { 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 */ + { 0, EOV, "" } /* 28 */ }; -static struct ctl_var *ext_sys_var = (struct ctl_var *)0; +static struct ctl_var *ext_sys_var = (struct ctl_var *)0; /* - * System variables we print by default (in fuzzball order, more-or-less) + * System variables we print by default (in fuzzball order, + * more-or-less) */ static u_char def_sys_var[] = { + CS_VERSION, CS_PROCESSOR, CS_SYSTEM, CS_LEAP, @@ -130,8 +150,16 @@ static u_char def_sys_var[] = { CS_STATE, CS_OFFSET, CS_DRIFT, - CS_COMPLIANCE, + CS_JITTER, CS_STABIL, +#ifdef PUBKEY + CS_FLAGS, + CS_HOST, + CS_CERTIF, + CS_DHPARAMS, + CS_REVTIME, + CS_LEAPTAB, +#endif /* PUBKEY */ 0 }; @@ -139,82 +167,103 @@ static u_char def_sys_var[] = { /* * Peer variable list */ -static struct ctl_var peer_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CP_CONFIG, RO, "config" }, /* 1 */ - { CP_AUTHENABLE, RO, "authenable" }, /* 2 */ - { CP_AUTHENTIC, RO, "authentic" }, /* 3 */ - { CP_SRCADR, RO, "srcadr" }, /* 4 */ - { CP_SRCPORT, RO, "srcport" }, /* 5 */ - { CP_DSTADR, RO, "dstadr" }, /* 6 */ - { CP_DSTPORT, RO, "dstport" }, /* 7 */ - { CP_LEAP, RO, "leap" }, /* 8 */ - { CP_HMODE, RO, "hmode" }, /* 9 */ - { CP_STRATUM, RO, "stratum" }, /* 10 */ - { CP_PPOLL, RO, "ppoll" }, /* 11 */ - { CP_HPOLL, RO, "hpoll" }, /* 12 */ - { CP_PRECISION, RO, "precision" }, /* 13 */ - { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */ +static struct ctl_var peer_var[] = { + { 0, PADDING, "" }, /* 0 */ + { CP_CONFIG, RO, "config" }, /* 1 */ + { CP_AUTHENABLE, RO, "authenable" }, /* 2 */ + { CP_AUTHENTIC, RO, "authentic" }, /* 3 */ + { CP_SRCADR, RO, "srcadr" }, /* 4 */ + { CP_SRCPORT, RO, "srcport" }, /* 5 */ + { CP_DSTADR, RO, "dstadr" }, /* 6 */ + { CP_DSTPORT, RO, "dstport" }, /* 7 */ + { CP_LEAP, RO, "leap" }, /* 8 */ + { CP_HMODE, RO, "hmode" }, /* 9 */ + { CP_STRATUM, RO, "stratum" }, /* 10 */ + { CP_PPOLL, RO, "ppoll" }, /* 11 */ + { CP_HPOLL, RO, "hpoll" }, /* 12 */ + { CP_PRECISION, RO, "precision" }, /* 13 */ + { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */ { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */ - { CP_REFID, RO, "refid" }, /* 16 */ - { CP_REFTIME, RO, "reftime" }, /* 17 */ - { CP_ORG, RO, "org" }, /* 18 */ - { CP_REC, RO, "rec" }, /* 19 */ - { CP_XMT, RO, "xmt" }, /* 20 */ - { CP_REACH, RO, "reach" }, /* 21 */ - { CP_VALID, RO, "valid" }, /* 22 */ - { CP_TIMER, RO, "timer" }, /* 23 */ - { CP_DELAY, RO, "delay" }, /* 24 */ - { CP_OFFSET, RO, "offset" }, /* 25 */ - { CP_JITTER, RO, "jitter" }, /* 26 */ - { CP_DISPERSION,RO, "dispersion" }, /* 27 */ - { CP_KEYID, RO, "keyid" }, /* 28 */ - { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */ - { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */ - { CP_PMODE, RO, "pmode" }, /* 31 */ - { CP_RECEIVED, RO, "received"}, /* 32 */ - { CP_SENT, RO, "sent" }, /* 33 */ - { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ - { CP_FLASH, RO, "flash" }, /* 35 */ - { CP_DISP, PADDING,"" }, /* 36 */ - { CP_VARLIST, RO, "peer_var_list" }, /* 37 */ - { 0, EOV, "" } + { CP_REFID, RO, "refid" }, /* 16 */ + { CP_REFTIME, RO, "reftime" }, /* 17 */ + { CP_ORG, RO, "org" }, /* 18 */ + { CP_REC, RO, "rec" }, /* 19 */ + { CP_XMT, RO, "xmt" }, /* 20 */ + { CP_REACH, RO, "reach" }, /* 21 */ + { CP_VALID, RO, "unreach" }, /* 22 */ + { CP_TIMER, RO, "timer" }, /* 23 */ + { CP_DELAY, RO, "delay" }, /* 24 */ + { CP_OFFSET, RO, "offset" }, /* 25 */ + { CP_JITTER, RO, "jitter" }, /* 26 */ + { CP_DISPERSION, RO, "dispersion" }, /* 27 */ + { CP_KEYID, RO, "keyid" }, /* 28 */ + { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */ + { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */ + { CP_PMODE, RO, "pmode" }, /* 31 */ + { CP_RECEIVED, RO, "received"}, /* 32 */ + { CP_SENT, RO, "sent" }, /* 33 */ + { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ + { CP_FLASH, RO, "flash" }, /* 35 */ + { CP_TTL, RO, "ttl" }, /* 36 */ + { CP_TTLMAX, RO, "ttlmax" }, /* 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 */ }; /* * Peer variables we print by default */ -static u_char def_peer_var[] = { +static u_char def_peer_var[] = { CP_SRCADR, CP_SRCPORT, CP_DSTADR, CP_DSTPORT, - CP_KEYID, + CP_LEAP, CP_STRATUM, CP_PRECISION, CP_ROOTDELAY, CP_ROOTDISPERSION, CP_REFID, - CP_REFTIME, - CP_DELAY, - CP_OFFSET, - CP_JITTER, - CP_DISPERSION, CP_REACH, CP_VALID, CP_HMODE, CP_PMODE, CP_HPOLL, CP_PPOLL, - CP_LEAP, CP_FLASH, + CP_KEYID, + CP_TTL, + CP_TTLMAX, + CP_OFFSET, + CP_DELAY, + CP_DISPERSION, + CP_JITTER, + CP_REFTIME, CP_ORG, CP_REC, CP_XMT, CP_FILTDELAY, CP_FILTOFFSET, CP_FILTERROR, +#ifdef PUBKEY + CP_FLAGS, + CP_HOST, + CP_CERTIF, + CP_SESKEY, + CP_INITSEQ, +#endif /* PUBKEY */ 0 }; @@ -223,31 +272,31 @@ static u_char def_peer_var[] = { /* * Clock variable list */ -static struct ctl_var clock_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CC_TYPE, RO, "type" }, /* 1 */ - { CC_TIMECODE, RO, "timecode" }, /* 2 */ - { CC_POLL, RO, "poll" }, /* 3 */ - { CC_NOREPLY, RO, "noreply" }, /* 4 */ - { CC_BADFORMAT, RO, "badformat" }, /* 5 */ - { CC_BADDATA, RO, "baddata" }, /* 6 */ - { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */ - { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */ - { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */ - { CC_FUDGEVAL2, RO, "refid" }, /* 10 */ - { CC_FLAGS, RO, "flags" }, /* 11 */ - { CC_DEVICE, RO, "device" }, /* 12 */ - { CC_VARLIST, RO, "clock_var_list" },/* 13 */ - { 0, EOV, "" } +static struct ctl_var clock_var[] = { + { 0, PADDING, "" }, /* 0 */ + { CC_TYPE, RO, "type" }, /* 1 */ + { CC_TIMECODE, RO, "timecode" }, /* 2 */ + { CC_POLL, RO, "poll" }, /* 3 */ + { CC_NOREPLY, RO, "noreply" }, /* 4 */ + { CC_BADFORMAT, RO, "badformat" }, /* 5 */ + { CC_BADDATA, RO, "baddata" }, /* 6 */ + { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */ + { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */ + { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */ + { CC_FUDGEVAL2, RO, "refid" }, /* 10 */ + { CC_FLAGS, RO, "flags" }, /* 11 */ + { CC_DEVICE, RO, "device" }, /* 12 */ + { CC_VARLIST, RO, "clock_var_list" }, /* 13 */ + { 0, EOV, "" } /* 14 */ }; /* * Clock variables printed by default */ -static u_char def_clock_var[] = { +static u_char def_clock_var[] = { CC_DEVICE, - CC_TYPE, /* won't be output if device= known */ + CC_TYPE, /* won't be output if device = known */ CC_TIMECODE, CC_POLL, CC_NOREPLY, @@ -264,14 +313,14 @@ static u_char def_clock_var[] = { /* - * System and processor definitions. These will change for the gizmo board. + * System and processor definitions. */ #ifndef HAVE_UNAME # ifndef STR_SYSTEM -# define STR_SYSTEM "UNIX" +# define STR_SYSTEM "UNIX" # endif # ifndef STR_PROCESSOR -# define STR_PROCESSOR "unknown" +# define STR_PROCESSOR "unknown" # endif static char str_system[] = STR_SYSTEM; @@ -282,10 +331,10 @@ static struct utsname utsnamebuf; #endif /* HAVE_UNAME */ /* - * Trap structures. We only allow a few of these, and send - * a copy of each async message to each live one. Traps time - * out after an hour, it is up to the trap receipient to - * keep resetting it to avoid being timed out. + * Trap structures. We only allow a few of these, and send a copy of + * each async message to each live one. Traps time out after an hour, it + * is up to the trap receipient to keep resetting it to avoid being + * timed out. */ /* ntp_request.c */ struct ctl_trap ctl_trap[CTL_MAXTRAPS]; @@ -301,9 +350,9 @@ int num_ctl_traps; /* * List relating reference clock types to control message time sources. - * Index by the reference clock type. - * This list will only be used iff the reference clock driver doesn't - * set peer->sstclktype to something different than CTL_SST_TS_UNSPEC. + * Index by the reference clock type. This list will only be used iff + * the reference clock driver doesn't set peer->sstclktype to something + * different than CTL_SST_TS_UNSPEC. */ static u_char clocktypes[] = { CTL_SST_TS_NTP, /* REFCLK_NONE (0) */ @@ -342,15 +391,17 @@ static u_char clocktypes[] = { CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (32) */ CTL_SST_TS_LF, /* REFCLK_ULINK (33) */ CTL_SST_TS_LF, /* REFCLK_PCF (35) */ - CTL_SST_TS_LF, /* REFCLK_WWW (36) */ + CTL_SST_TS_LF, /* REFCLK_WWV (36) */ CTL_SST_TS_LF, /* REFCLK_FG (37) */ + CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */ + CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */ }; /* * Keyid used for authenticating write requests. */ -u_long ctl_auth_keyid; +keyid_t ctl_auth_keyid; /* * We keep track of the last error reported by the system internally @@ -366,7 +417,7 @@ u_long ctltimereset; /* time stats reset */ u_long numctlreq; /* number of requests we've received */ u_long numctlbadpkts; /* number of bad control packets */ u_long numctlresponses; /* number of resp packets sent with data */ -u_long numctlfrags; /* number of fragments sent */ +u_long numctlfrags; /* number of fragments sent */ u_long numctlerrors; /* number of error responses sent */ u_long numctltooshort; /* number of too short input packets */ u_long numctlinputresp; /* number of responses on input */ @@ -375,11 +426,11 @@ u_long numctlinputerr; /* number of input pkts with err bit set */ u_long numctlbadoffset; /* number of input pkts with nonzero offset */ u_long numctlbadversion; /* number of input pkts with unknown version */ u_long numctldatatooshort; /* data too short for count */ -u_long numctlbadop; /* bad op code found in packet */ +u_long numctlbadop; /* bad op code found in packet */ u_long numasyncmsgs; /* number of async messages we've sent */ /* - * Response packet used by these routines. Also some state information + * Response packet used by these routines. Also some state information * so that we can handle packet formatting within a common set of * subroutines. Note we try to enter data in place whenever possible, * but the need to set the more bit correctly means we occasionally @@ -388,7 +439,7 @@ u_long numasyncmsgs; /* number of async messages we've sent */ static struct ntp_control rpkt; static u_char res_version; static u_char res_opcode; -static u_short res_associd; +static associd_t res_associd; static int res_offset; static u_char * datapt; static u_char * dataend; @@ -399,7 +450,7 @@ static struct interface *lcl_inter; static u_char res_authenticate; static u_char res_authokay; -static u_long res_keyid; +static keyid_t res_keyid; #define MAXDATALINELEN (72) @@ -448,10 +499,11 @@ ctl_error( printf("sending control error %d\n", errcode); #endif /* - * fill in the fields. We assume rpkt.sequence and rpkt.associd + * Fill in the fields. We assume rpkt.sequence and rpkt.associd * have already been filled in. */ - rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & CTL_OP_MASK)); + rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & + CTL_OP_MASK)); rpkt.status = htons((u_short) ((errcode<<8) & 0xff00)); rpkt.count = 0; @@ -461,15 +513,15 @@ ctl_error( if (res_authenticate && sys_authenticate) { int maclen; - *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) - = htonl(res_keyid); + *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) = + htonl(res_keyid); maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, - CTL_HEADER_LEN); + CTL_HEADER_LEN); sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt, - CTL_HEADER_LEN + maclen); + CTL_HEADER_LEN + maclen); } else { sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt, - CTL_HEADER_LEN); + CTL_HEADER_LEN); } numctlerrors++; } @@ -492,7 +544,7 @@ process_control( int maclen; #ifdef DEBUG - if (debug > 1) + if (debug > 2) printf("in process_control()\n"); #endif @@ -509,8 +561,8 @@ process_control( * it is a response or a fragment, ignore this. */ if (rbufp->recv_length < CTL_HEADER_LEN - || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) - || pkt->offset != 0) { + || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) + || pkt->offset != 0) { #ifdef DEBUG if (debug) printf("invalid format in control packet\n"); @@ -539,9 +591,11 @@ process_control( } /* - * Pull enough data from the packet to make intelligent responses + * Pull enough data from the packet to make intelligent + * responses */ - rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version, MODE_CONTROL); + rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version, + MODE_CONTROL); res_opcode = pkt->r_m_e_op; rpkt.sequence = pkt->sequence; rpkt.associd = pkt->associd; @@ -559,8 +613,8 @@ process_control( dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); /* - * We're set up now. Make sure we've got at least - * enough incoming data space to match the count. + * We're set up now. Make sure we've got at least enough + * incoming data space to match the count. */ req_data = rbufp->recv_length - CTL_HEADER_LEN; if (req_data < req_count || rbufp->recv_length & 0x3) { @@ -571,40 +625,43 @@ process_control( properlen = req_count + CTL_HEADER_LEN; #ifdef DEBUG - if (debug >= 2 && (rbufp->recv_length & 0x3) != 0) - printf("Packet length %d unrounded\n", rbufp->recv_length); + if (debug > 2 && (rbufp->recv_length & 0x3) != 0) + printf("Packet length %d unrounded\n", + rbufp->recv_length); #endif /* round up proper len to a 8 octet boundary */ properlen = (properlen + 7) & ~7; maclen = rbufp->recv_length - properlen; if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 && - maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN && - sys_authenticate) { + maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN && + sys_authenticate) { res_authenticate = 1; - res_keyid = ntohl(*(u_int32 *)((u_char *)pkt + properlen)); + res_keyid = ntohl(*(u_int32 *)((u_char *)pkt + + properlen)); #ifdef DEBUG - if (debug >= 3) + if (debug > 2) printf( - "recv_len %d, properlen %d, wants auth with keyid %ld, MAC length=%d\n", - rbufp->recv_length, properlen, res_keyid, maclen); + "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n", + rbufp->recv_length, properlen, res_keyid, maclen); #endif if (!authistrusted(res_keyid)) { #ifdef DEBUG - if (debug >= 2) - printf("invalid keyid %lu\n", res_keyid); + if (debug > 2) + printf("invalid keyid %08x\n", + res_keyid); #endif } else if (authdecrypt(res_keyid, (u_int32 *)pkt, - rbufp->recv_length - maclen, maclen)) { + rbufp->recv_length - maclen, maclen)) { #ifdef DEBUG - if (debug >= 3) + if (debug > 2) printf("authenticated okay\n"); #endif res_authokay = 1; } else { #ifdef DEBUG - if (debug >= 3) + if (debug > 2) printf("authentication failed\n"); #endif res_keyid = 0; @@ -623,12 +680,12 @@ process_control( for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) { if (cc->control_code == res_opcode) { #ifdef DEBUG - if (debug >= 2) + if (debug > 2) printf("opcode %d, found command handler\n", - res_opcode); + res_opcode); #endif - if (cc->flags == AUTH && (!res_authokay - || res_keyid != ctl_auth_keyid)) { + if (cc->flags == AUTH && (!res_authokay || + res_keyid != ctl_auth_keyid)) { ctl_error(CERR_PERMISSION); return; } @@ -666,7 +723,7 @@ ctlpeerstatus( if (peer->reach != 0) status |= CTL_PST_REACH; return (u_short)CTL_PEER_STATUS(status, peer->num_events, - peer->last_event); + peer->last_event); } @@ -678,12 +735,11 @@ ctlclkstatus( struct refclockstat *this_clock ) { - return ((u_short)(this_clock->currentstatus) << 8) - | (u_short)(this_clock->lastevent); + return ((u_short)(this_clock->currentstatus) << 8) | + (u_short)(this_clock->lastevent); } - /* * ctlsysstatus - return the system status word */ @@ -700,17 +756,17 @@ ctlsysstatus(void) this_clock |= CTL_SST_TS_PPS; } else { if (sys_peer->refclktype < sizeof(clocktypes)) - this_clock = clocktypes[sys_peer->refclktype]; + this_clock = + clocktypes[sys_peer->refclktype]; if (pps_control) this_clock |= CTL_SST_TS_PPS; } } return (u_short)CTL_SYS_STATUS(sys_leap, this_clock, - ctl_sys_num_events, ctl_sys_last_event); + ctl_sys_num_events, ctl_sys_last_event); } - /* * ctl_flushpkt - write out the current packet and prepare * another if necessary. @@ -744,7 +800,8 @@ ctl_flushpkt( /* * Fill in the packet with the current info */ - rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode & CTL_OP_MASK)); + rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode & + CTL_OP_MASK)); rpkt.count = htons((u_short) dlen); rpkt.offset = htons( (u_short) res_offset); if (res_async) { @@ -752,12 +809,14 @@ ctl_flushpkt( for (i = 0; i < CTL_MAXTRAPS; i++) { if (ctl_trap[i].tr_flags & TRAP_INUSE) { - rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, - ctl_trap[i].tr_version, MODE_CONTROL); - rpkt.sequence = htons(ctl_trap[i].tr_sequence); + rpkt.li_vn_mode = + PKT_LI_VN_MODE(sys_leap, + ctl_trap[i].tr_version, + MODE_CONTROL); + rpkt.sequence = + htons(ctl_trap[i].tr_sequence); sendpkt(&ctl_trap[i].tr_addr, - ctl_trap[i].tr_localaddr, - -4, + ctl_trap[i].tr_localaddr, -4, (struct pkt *)&rpkt, sendlen); if (!more) ctl_trap[i].tr_sequence++; @@ -768,25 +827,25 @@ ctl_flushpkt( if (res_authenticate && sys_authenticate) { int maclen; int totlen = sendlen; - u_long keyid = htonl(res_keyid); + keyid_t keyid = htonl(res_keyid); /* - * If we are going to authenticate, then there is - * an additional requirement that the MAC begin on - * a 64 bit boundary. + * If we are going to authenticate, then there + * is an additional requirement that the MAC + * begin on a 64 bit boundary. */ while (totlen & 7) { *datapt++ = '\0'; totlen++; } memcpy(datapt, &keyid, sizeof keyid); - maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, - totlen); - sendpkt(rmt_addr, lcl_inter, -5, (struct pkt *)&rpkt, - totlen + maclen); + maclen = authencrypt(res_keyid, + (u_int32 *)&rpkt, totlen); + sendpkt(rmt_addr, lcl_inter, -5, + (struct pkt *)&rpkt, totlen + maclen); } else { - sendpkt(rmt_addr, lcl_inter, -6, (struct pkt *)&rpkt, - sendlen); + sendpkt(rmt_addr, lcl_inter, -6, + (struct pkt *)&rpkt, sendlen); } if (more) numctlfrags++; @@ -803,8 +862,8 @@ ctl_flushpkt( /* - * ctl_putdata - write data into the packet, fragmenting and - * starting another if this one is full. + * ctl_putdata - write data into the packet, fragmenting and starting + * another if this one is full. */ static void ctl_putdata( @@ -822,7 +881,8 @@ ctl_putdata( if (datapt != rpkt.data) { *datapt++ = ','; datalinelen++; - if ((dlen + datalinelen + 1) >= MAXDATALINELEN) { + if ((dlen + datalinelen + 1) >= MAXDATALINELEN) + { *datapt++ = '\r'; *datapt++ = '\n'; datalinelen = 0; @@ -842,7 +902,6 @@ ctl_putdata( */ ctl_flushpkt(CTL_MORE); } - memmove((char *)datapt, dp, (unsigned)dlen); datapt += dlen; datalinelen += dlen; @@ -867,7 +926,6 @@ ctl_putstr( cq = tag; while (*cq != '\0') *cp++ = *cq++; - if (len > 0) { *cp++ = '='; *cp++ = '"'; @@ -877,7 +935,6 @@ ctl_putstr( cp += len; *cp++ = '"'; } - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); } @@ -928,7 +985,6 @@ ctl_putuint( (void) sprintf(cp, "%lu", uval); while (*cp != '\0') cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); } @@ -955,7 +1011,6 @@ ctl_puthex( (void) sprintf(cp, "0x%lx", uval); while (*cp != '\0') cp++; - ctl_putdata(buffer,(unsigned)( cp - buffer ), 0); } @@ -982,7 +1037,6 @@ ctl_putint( (void) sprintf(cp, "%ld", ival); while (*cp != '\0') cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); } @@ -1010,7 +1064,6 @@ ctl_putts( ts->l_uf & 0xffffffffL); while (*cp != '\0') cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); } @@ -1037,7 +1090,6 @@ ctl_putadr( cq = numtoa(addr); while (*cq != '\0') *cp++ = *cq++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); } @@ -1064,7 +1116,6 @@ ctl_putid( cq = id; while (*cq != '\0' && (cq - id) < 4) *cp++ = *cq++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); } @@ -1111,145 +1162,213 @@ ctl_putsys( { l_fp tmp; #ifdef HAVE_UNAME - char str[50]; + char str[256]; #endif switch (varid) { - case CS_LEAP: + + case CS_LEAP: ctl_putuint(sys_var[CS_LEAP].text, sys_leap); break; - case CS_STRATUM: + + case CS_STRATUM: ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum); break; - case CS_PRECISION: + + case CS_PRECISION: ctl_putint(sys_var[CS_PRECISION].text, sys_precision); break; - case CS_ROOTDELAY: - ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay * 1e3); + + case CS_ROOTDELAY: + ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay * + 1e3); break; - case CS_ROOTDISPERSION: + + case CS_ROOTDISPERSION: ctl_putdbl(sys_var[CS_ROOTDISPERSION].text, sys_rootdispersion * 1e3); break; - case CS_REFID: + + case CS_REFID: if (sys_stratum > 1) ctl_putadr(sys_var[CS_REFID].text, sys_refid); else - ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid); + ctl_putid(sys_var[CS_REFID].text, + (char *)&sys_refid); break; - case CS_REFTIME: + + case CS_REFTIME: ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime); break; - case CS_POLL: + + case CS_POLL: ctl_putuint(sys_var[CS_POLL].text, sys_poll); break; - case CS_PEERID: + + case CS_PEERID: if (sys_peer == NULL) ctl_putuint(sys_var[CS_PEERID].text, 0); else ctl_putuint(sys_var[CS_PEERID].text, sys_peer->associd); break; - case CS_STATE: + + case CS_STATE: ctl_putuint(sys_var[CS_STATE].text, (unsigned)state); break; - case CS_OFFSET: + + case CS_OFFSET: ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3); break; - case CS_DRIFT: + + case CS_DRIFT: ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6); break; - case CS_COMPLIANCE: - ctl_putdbl(sys_var[CS_COMPLIANCE].text, sys_error * 1e3); + + case CS_JITTER: + ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3); break; - case CS_CLOCK: + + case CS_CLOCK: get_systime(&tmp); ctl_putts(sys_var[CS_CLOCK].text, &tmp); break; - case CS_PROCESSOR: + + case CS_PROCESSOR: #ifndef HAVE_UNAME ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor, - sizeof(str_processor) - 1); + sizeof(str_processor) - 1); #else - ctl_putstr(sys_var[CS_PROCESSOR].text, utsnamebuf.machine, - strlen(utsnamebuf.machine)); + ctl_putstr(sys_var[CS_PROCESSOR].text, + utsnamebuf.machine, strlen(utsnamebuf.machine)); #endif /* HAVE_UNAME */ break; - case CS_SYSTEM: + + case CS_SYSTEM: #ifndef HAVE_UNAME ctl_putstr(sys_var[CS_SYSTEM].text, str_system, - sizeof(str_system) - 1); + sizeof(str_system) - 1); #else (void)strcpy(str, utsnamebuf.sysname); (void)strcat(str, utsnamebuf.release); ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str)); #endif /* HAVE_UNAME */ break; - case CS_STABIL: - ctl_putdbl(sys_var[CS_STABIL].text, clock_stability * 1e6); - break; - case CS_VARLIST: - { - char buf[CTL_MAX_DATA_LEN]; - register char *s, *t, *be; - register const char *ss; - register int i; - register struct ctl_var *k; - - s = buf; - be = buf + sizeof(buf) - strlen(sys_var[CS_VARLIST].text) - 4; - if (s > be) - break; /* really long var name 8-( - Killer */ - - strcpy(s, sys_var[CS_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - - for (k = sys_var; !(k->flags &EOV); k++) - { - if (k->flags & PADDING) + + case CS_VERSION: + ctl_putstr(sys_var[CS_VERSION].text, Version, + strlen(Version)); + break; + + case CS_STABIL: + ctl_putdbl(sys_var[CS_STABIL].text, clock_stability * + 1e6); + break; + + case CS_VARLIST: + { + char buf[CTL_MAX_DATA_LEN]; + register char *s, *t, *be; + register const char *ss; + register int i; + register struct ctl_var *k; + + s = buf; + be = buf + sizeof(buf) - + strlen(sys_var[CS_VARLIST].text) - 4; + if (s > be) + break; /* really long var name */ + + strcpy(s, sys_var[CS_VARLIST].text); + strcat(s, "=\""); + s += strlen(s); + t = s; + for (k = sys_var; !(k->flags &EOV); k++) { + if (k->flags & PADDING) continue; + i = strlen(k->text); + if (s+i+1 >= be) + break; - i = strlen(k->text); - if (s+i+1 >= be) - break; - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } + if (s != t) + *s++ = ','; + strcpy(s, k->text); + s += i; + } - for (k = ext_sys_var; k && !(k->flags &EOV); k++) - { - if (k->flags & PADDING) + for (k = ext_sys_var; k && !(k->flags &EOV); + k++) { + if (k->flags & PADDING) continue; - ss = k->text; - if (!ss) + ss = k->text; + if (!ss) continue; - while (*ss && *ss != '=') + while (*ss && *ss != '=') ss++; - - i = ss - k->text; - if (s+i+1 >= be) + i = ss - k->text; + if (s + i + 1 >= be) break; - if (s != t) - *s++ = ','; - strncpy(s, k->text, (unsigned)i); - s += i; - } - if (s+2 >= be) + if (s != t) + *s++ = ','; + strncpy(s, k->text, + (unsigned)i); + s += i; + } + if (s+2 >= be) break; - *s++ = '"'; - *s = '\0'; + *s++ = '"'; + *s = '\0'; - ctl_putdata(buf, (unsigned)( s - buf ), 0); - } - break; + ctl_putdata(buf, (unsigned)( s - buf ), + 0); + } + break; + +#ifdef PUBKEY + case CS_FLAGS: + if (crypto_flags) + ctl_puthex(sys_var[CS_FLAGS].text, + crypto_flags); + 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)); + break; + + case CS_CERTIF: + if (certif.fstamp != 0) + ctl_putuint(sys_var[CS_CERTIF].text, + ntohl(certif.fstamp)); + break; + + case CS_DHPARAMS: + if (dhparam.fstamp != 0) + ctl_putuint(sys_var[CS_DHPARAMS].text, + ntohl(dhparam.fstamp)); + break; + + case CS_REVTIME: + if (host.tstamp != 0) + ctl_putuint(sys_var[CS_REVTIME].text, + ntohl(host.tstamp)); + break; + + case CS_LEAPTAB: + if (tai_leap.fstamp != 0) + ctl_putuint(sys_var[CS_LEAPTAB].text, + ntohl(tai_leap.fstamp)); + if (sys_tai != 0) + ctl_putuint(sys_var[CS_TAI].text, sys_tai); + break; +#endif /* PUBKEY */ } } @@ -1264,186 +1383,266 @@ ctl_putpeer( ) { switch (varid) { - case CP_CONFIG: + + case CP_CONFIG: ctl_putuint(peer_var[CP_CONFIG].text, - (unsigned)((peer->flags & FLAG_CONFIG) != 0)); + (unsigned)((peer->flags & FLAG_CONFIG) != 0)); break; - case CP_AUTHENABLE: + + case CP_AUTHENABLE: ctl_putuint(peer_var[CP_AUTHENABLE].text, - (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0)); + (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0)); break; - case CP_AUTHENTIC: + + case CP_AUTHENTIC: ctl_putuint(peer_var[CP_AUTHENTIC].text, - (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0)); + (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0)); break; - case CP_SRCADR: + + case CP_SRCADR: ctl_putadr(peer_var[CP_SRCADR].text, - peer->srcadr.sin_addr.s_addr); + peer->srcadr.sin_addr.s_addr); break; - case CP_SRCPORT: + + case CP_SRCPORT: ctl_putuint(peer_var[CP_SRCPORT].text, - ntohs(peer->srcadr.sin_port)); + ntohs(peer->srcadr.sin_port)); break; - case CP_DSTADR: + + case CP_DSTADR: ctl_putadr(peer_var[CP_DSTADR].text, - peer->processed ? - peer->cast_flags & MDF_BCAST ? - peer->dstadr->bcast.sin_addr.s_addr: - peer->cast_flags ? - peer->dstadr->sin.sin_addr.s_addr ? - peer->dstadr->sin.sin_addr.s_addr: - peer->dstadr->bcast.sin_addr.s_addr: - 8 : 12); - break; - case CP_DSTPORT: + peer->dstadr->sin.sin_addr.s_addr); + break; + + case CP_DSTPORT: ctl_putuint(peer_var[CP_DSTPORT].text, - (u_long)(peer->dstadr - ? ntohs(peer->dstadr->sin.sin_port) - : 0 - ) - ); + (u_long)(peer->dstadr ? + ntohs(peer->dstadr->sin.sin_port) : 0)); break; - case CP_LEAP: + + case CP_LEAP: ctl_putuint(peer_var[CP_LEAP].text, peer->leap); break; - case CP_HMODE: + + case CP_HMODE: ctl_putuint(peer_var[CP_HMODE].text, peer->hmode); break; - case CP_STRATUM: + + case CP_STRATUM: ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum); break; - case CP_PPOLL: + + case CP_PPOLL: ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll); break; - case CP_HPOLL: + + case CP_HPOLL: ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll); break; - case CP_PRECISION: - ctl_putint(peer_var[CP_PRECISION].text, peer->precision); + + case CP_PRECISION: + ctl_putint(peer_var[CP_PRECISION].text, + peer->precision); break; - case CP_ROOTDELAY: - ctl_putdbl(peer_var[CP_ROOTDELAY].text, peer->rootdelay * 1e3); + + case CP_ROOTDELAY: + ctl_putdbl(peer_var[CP_ROOTDELAY].text, + peer->rootdelay * 1e3); break; - case CP_ROOTDISPERSION: + + case CP_ROOTDISPERSION: ctl_putdbl(peer_var[CP_ROOTDISPERSION].text, - peer->rootdispersion * 1e3); + peer->rootdispersion * 1e3); break; - case CP_REFID: - if (peer->stratum > 1) - { + + 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); + peer->srcadr.sin_addr.s_addr); else ctl_putadr(peer_var[CP_REFID].text, - peer->refid); - } - else + peer->refid); + } else { ctl_putid(peer_var[CP_REFID].text, - (char *)&peer->refid); + (char *)&peer->refid); + } break; - case CP_REFTIME: + + case CP_REFTIME: ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime); break; - case CP_ORG: + + case CP_ORG: ctl_putts(peer_var[CP_ORG].text, &peer->org); break; - case CP_REC: + + case CP_REC: ctl_putts(peer_var[CP_REC].text, &peer->rec); break; - case CP_XMT: + + case CP_XMT: ctl_putts(peer_var[CP_XMT].text, &peer->xmt); break; - case CP_REACH: + + case CP_REACH: ctl_puthex(peer_var[CP_REACH].text, peer->reach); break; - case CP_FLASH: + + case CP_FLASH: ctl_puthex(peer_var[CP_FLASH].text, peer->flash); break; - case CP_VALID: - ctl_putuint(peer_var[CP_VALID].text, peer->valid); + + case CP_TTL: + if (!(peer->cast_flags & MDF_ACAST)) + break; + ctl_putint(peer_var[CP_TTL].text, peer->ttl); break; - case CP_TIMER: + + case CP_TTLMAX: + if (!(peer->cast_flags & (MDF_MCAST | MDF_ACAST))) + break; + ctl_putint(peer_var[CP_TTLMAX].text, peer->ttlmax); + break; + + case CP_VALID: + ctl_putuint(peer_var[CP_VALID].text, peer->unreach); + break; + + case CP_TIMER: ctl_putuint(peer_var[CP_TIMER].text, peer->nextdate - current_time); break; - case CP_DELAY: + + case CP_DELAY: ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3); break; - case CP_OFFSET: - ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset * 1e3); + + case CP_OFFSET: + ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset * + 1e3); break; - case CP_JITTER: + + case CP_JITTER: ctl_putdbl(peer_var[CP_JITTER].text, - SQRT(peer->variance) * 1e3); + SQRT(peer->jitter) * 1e3); break; - case CP_DISPERSION: - ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp * 1e3); + + case CP_DISPERSION: + ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp * + 1e3); break; - case CP_KEYID: + + case CP_KEYID: ctl_putuint(peer_var[CP_KEYID].text, peer->keyid); break; - case CP_FILTDELAY: + + case CP_FILTDELAY: ctl_putarray(peer_var[CP_FILTDELAY].text, peer->filter_delay, (int)peer->filter_nextpt); break; - case CP_FILTOFFSET: + + case CP_FILTOFFSET: ctl_putarray(peer_var[CP_FILTOFFSET].text, peer->filter_offset, (int)peer->filter_nextpt); break; - case CP_FILTERROR: + + case CP_FILTERROR: ctl_putarray(peer_var[CP_FILTERROR].text, peer->filter_disp, (int)peer->filter_nextpt); break; - case CP_PMODE: + + case CP_PMODE: ctl_putuint(peer_var[CP_PMODE].text, peer->pmode); break; - case CP_RECEIVED: + + case CP_RECEIVED: ctl_putuint(peer_var[CP_RECEIVED].text, peer->received); break; - case CP_SENT: + + case CP_SENT: ctl_putuint(peer_var[CP_SENT].text, peer->sent); break; - case CP_VARLIST: - { - char buf[CTL_MAX_DATA_LEN]; - register char *s, *t, *be; - register int i; - register struct ctl_var *k; - - s = buf; - be = buf + sizeof(buf) - strlen(peer_var[CP_VARLIST].text) - 4; - if (s > be) - break; /* really long var name 8-( - Killer */ - - strcpy(s, peer_var[CP_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - - for (k = peer_var; !(k->flags &EOV); k++) - { - if (k->flags & PADDING) + + case CP_VARLIST: + { + char buf[CTL_MAX_DATA_LEN]; + register char *s, *t, *be; + register int i; + register struct ctl_var *k; + + s = buf; + be = buf + sizeof(buf) - + strlen(peer_var[CP_VARLIST].text) - 4; + if (s > be) + break; /* really long var name */ + + strcpy(s, peer_var[CP_VARLIST].text); + strcat(s, "=\""); + s += strlen(s); + t = s; + for (k = peer_var; !(k->flags &EOV); k++) { + if (k->flags & PADDING) continue; - i = strlen(k->text); - if (s+i+1 >= be) - break; - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } + i = strlen(k->text); + if (s + i + 1 >= be) + break; - if (s+2 >= be) + if (s != t) + *s++ = ','; + strcpy(s, k->text); + s += i; + } + if (s+2 >= be) break; - *s++ = '"'; - *s = '\0'; + *s++ = '"'; + *s = '\0'; + ctl_putdata(buf, (unsigned)(s - buf), 0); + } + break; +#ifdef PUBKEY + case CP_FLAGS: + if (peer->crypto) + ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto); + break; - ctl_putdata(buf, (unsigned)(s - buf), 0); - } + 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); + break; + + case CP_CERTIF: + if (peer->certif.fstamp != 0) + ctl_putuint(peer_var[CP_CERTIF].text, + peer->certif.fstamp); + 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); + break; + + case CP_INITSEQ: + if (peer->recauto.key == 0) break; + ctl_putint(peer_var[CP_INITSEQ].text, + peer->recauto.seq); + ctl_puthex(peer_var[CP_INITKEY].text, + peer->recauto.key); + ctl_putuint(peer_var[CP_INITTSP].text, + peer->recauto.tstamp); + break; +#endif /* PUBKEY */ } } @@ -1460,132 +1659,148 @@ ctl_putclock( ) { switch(varid) { - case CC_TYPE: + + case CC_TYPE: if (mustput || clock_stat->clockdesc == NULL || *(clock_stat->clockdesc) == '\0') { ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type); } break; - case CC_TIMECODE: - ctl_putstr(clock_var[CC_TIMECODE].text, clock_stat->p_lastcode, - (unsigned)clock_stat->lencode); + case CC_TIMECODE: + ctl_putstr(clock_var[CC_TIMECODE].text, + clock_stat->p_lastcode, + (unsigned)clock_stat->lencode); break; - case CC_POLL: + + case CC_POLL: ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls); break; - case CC_NOREPLY: - ctl_putuint(clock_var[CC_NOREPLY].text, clock_stat->noresponse); + + case CC_NOREPLY: + ctl_putuint(clock_var[CC_NOREPLY].text, + clock_stat->noresponse); break; - case CC_BADFORMAT: - ctl_putuint(clock_var[CC_BADFORMAT].text, clock_stat->badformat); + + case CC_BADFORMAT: + ctl_putuint(clock_var[CC_BADFORMAT].text, + clock_stat->badformat); break; - case CC_BADDATA: - ctl_putuint(clock_var[CC_BADDATA].text, clock_stat->baddata); + + case CC_BADDATA: + ctl_putuint(clock_var[CC_BADDATA].text, + clock_stat->baddata); break; - case CC_FUDGETIME1: - if (mustput || (clock_stat->haveflags & CLK_HAVETIME1)) { + + case CC_FUDGETIME1: + if (mustput || (clock_stat->haveflags & CLK_HAVETIME1)) ctl_putdbl(clock_var[CC_FUDGETIME1].text, - clock_stat->fudgetime1 * 1e3); - } + clock_stat->fudgetime1 * 1e3); break; - case CC_FUDGETIME2: - if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) { - ctl_putdbl(clock_var[CC_FUDGETIME2].text, - clock_stat->fudgetime2 * 1e3); - } + + case CC_FUDGETIME2: + if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) ctl_putdbl(clock_var[CC_FUDGETIME2].text, + clock_stat->fudgetime2 * 1e3); break; - case CC_FUDGEVAL1: + + case CC_FUDGEVAL1: if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1)) ctl_putint(clock_var[CC_FUDGEVAL1].text, - clock_stat->fudgeval1); + clock_stat->fudgeval1); break; - case CC_FUDGEVAL2: + + case CC_FUDGEVAL2: if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) { if (clock_stat->fudgeval1 > 1) - ctl_putadr(clock_var[CC_FUDGEVAL2].text, - (u_int32)clock_stat->fudgeval2); + ctl_putadr(clock_var[CC_FUDGEVAL2].text, + (u_int32)clock_stat->fudgeval2); else - ctl_putid(clock_var[CC_FUDGEVAL2].text, - (char *)&clock_stat->fudgeval2); + ctl_putid(clock_var[CC_FUDGEVAL2].text, + (char *)&clock_stat->fudgeval2); } break; - case CC_FLAGS: - if (mustput || (clock_stat->haveflags & - (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))) - ctl_putuint(clock_var[CC_FLAGS].text, clock_stat->flags); + + case CC_FLAGS: + if (mustput || (clock_stat->haveflags & (CLK_HAVEFLAG1 | + CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4))) + ctl_putuint(clock_var[CC_FLAGS].text, + clock_stat->flags); break; - case CC_DEVICE: - if (clock_stat->clockdesc == NULL || *(clock_stat->clockdesc) == '\0') { + + case CC_DEVICE: + if (clock_stat->clockdesc == NULL || + *(clock_stat->clockdesc) == '\0') { if (mustput) - ctl_putstr(clock_var[CC_DEVICE].text, "", 0); + ctl_putstr(clock_var[CC_DEVICE].text, + "", 0); } else { - ctl_putstr(clock_var[CC_DEVICE].text, clock_stat->clockdesc, - strlen(clock_stat->clockdesc)); + ctl_putstr(clock_var[CC_DEVICE].text, + clock_stat->clockdesc, + strlen(clock_stat->clockdesc)); } break; - case CC_VARLIST: - { - char buf[CTL_MAX_DATA_LEN]; - register char *s, *t, *be; - register const char *ss; - register int i; - register struct ctl_var *k; - - s = buf; - be = buf + sizeof(buf); - if (s + strlen(clock_var[CC_VARLIST].text) + 4 > be) - break; /* really long var name 8-( - Killer */ - - strcpy(s, clock_var[CC_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - - for (k = clock_var; !(k->flags &EOV); k++) - { - if (k->flags & PADDING) + + case CC_VARLIST: + { + char buf[CTL_MAX_DATA_LEN]; + register char *s, *t, *be; + register const char *ss; + register int i; + register struct ctl_var *k; + + s = buf; + be = buf + sizeof(buf); + if (s + strlen(clock_var[CC_VARLIST].text) + 4 > + be) + break; /* really long var name */ + + strcpy(s, clock_var[CC_VARLIST].text); + strcat(s, "=\""); + s += strlen(s); + t = s; + + for (k = clock_var; !(k->flags &EOV); k++) { + if (k->flags & PADDING) continue; - i = strlen(k->text); - if (s+i+1 >= be) + i = strlen(k->text); + if (s + i + 1 >= be) break; - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } - for (k = clock_stat->kv_list; k && !(k->flags &EOV); k++) - { - if (k->flags & PADDING) + if (s != t) + *s++ = ','; + strcpy(s, k->text); + s += i; + } + + for (k = clock_stat->kv_list; k && !(k->flags & + EOV); k++) { + if (k->flags & PADDING) continue; - ss = k->text; - if (!ss) + ss = k->text; + if (!ss) continue; - while (*ss && *ss != '=') + while (*ss && *ss != '=') ss++; - - i = ss - k->text; - if (s+i+1 >= be) + i = ss - k->text; + if (s+i+1 >= be) break; - if (s != t) - *s++ = ','; - strncpy(s, k->text, (unsigned)i); - s += i; - *s = '\0'; - } - - if (s+2 >= be) - break; - *s++ = '"'; + if (s != t) + *s++ = ','; + strncpy(s, k->text, (unsigned)i); + s += i; *s = '\0'; - - ctl_putdata(buf, (unsigned)( s - buf ), 0); } - break; + if (s+2 >= be) + break; + + *s++ = '"'; + *s = '\0'; + ctl_putdata(buf, (unsigned)( s - buf ), 0); + } + break; } } #endif @@ -1610,15 +1825,14 @@ ctl_getitem( /* * Delete leading commas and white space */ - while (reqpt < reqend && (*reqpt == ',' || isspace((int)*reqpt))) { + while (reqpt < reqend && (*reqpt == ',' || + isspace((int)*reqpt))) reqpt++; - } - if (reqpt >= reqend) - return 0; + return (0); if (var_list == (struct ctl_var *)0) - return &eol; + return (&eol); /* * Look for a first character match on the tag. If we find @@ -1629,7 +1843,8 @@ ctl_getitem( while (!(v->flags & EOV)) { if (!(v->flags & PADDING) && *cp == *(v->text)) { tp = v->text; - while (*tp != '\0' && *tp != '=' && cp < reqend && *cp == *tp) { + while (*tp != '\0' && *tp != '=' && cp < + reqend && *cp == *tp) { cp++; tp++; } @@ -1649,16 +1864,29 @@ ctl_getitem( tp = buf; while (cp < reqend && isspace((int)*cp)) cp++; - while (cp < reqend && *cp != ',') + while (cp < reqend && *cp != ',') { *tp++ = *cp++; + if (tp >= buf + sizeof(buf)) { + ctl_error(CERR_BADFMT); + numctlbadpkts++; + msyslog(LOG_WARNING, + "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n", + inet_ntoa(rmt_addr->sin_addr), ntohs(rmt_addr->sin_port) + ); + return (0); + } + } if (cp < reqend) cp++; - *tp = '\0'; - while (isspace((int)(*(tp-1)))) - *(--tp) = '\0'; + *tp-- = '\0'; + while (tp > buf) { + *tp-- = '\0'; + if (!isspace((int)(*tp))) + break; + } reqpt = cp; *data = buf; - return v; + return (v); } } cp = reqpt; @@ -1687,7 +1915,7 @@ control_unspec( * doesn't exist. */ if (res_associd != 0) { - if ((peer = findpeerbyassoc((int)res_associd)) == 0) { + if ((peer = findpeerbyassoc(res_associd)) == 0) { ctl_error(CERR_BADASSOC); return; } @@ -1701,7 +1929,7 @@ control_unspec( /* * read_status - return either a list of associd's, or a particular - * peer's status. + * peer's status. */ /*ARGSUSED*/ static void @@ -1712,14 +1940,14 @@ read_status( { register int i; register struct peer *peer; - u_short ass_stat[CTL_MAX_DATA_LEN/sizeof(u_short)]; + u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)]; #ifdef DEBUG - if (debug >= 2) + if (debug > 2) printf("read_status: ID %d\n", res_associd); #endif /* - * Two choices here. If the specified association ID is + * Two choices here. If the specified association ID is * zero we return all known assocation ID's. Otherwise * we return a bunch of stuff about the particular peer. */ @@ -1730,22 +1958,25 @@ read_status( rpkt.status = htons(ctlsysstatus()); for (i = 0; i < HASH_SIZE; i++) { for (peer = assoc_hash[i]; peer != 0; - peer = peer->ass_next) { + peer = peer->ass_next) { ass_stat[n++] = htons(peer->associd); - ass_stat[n++] = htons(ctlpeerstatus(peer)); - if (n == CTL_MAX_DATA_LEN/sizeof(u_short)) { + ass_stat[n++] = + htons(ctlpeerstatus(peer)); + if (n == + CTL_MAX_DATA_LEN/sizeof(u_short)) { ctl_putdata((char *)ass_stat, - n * sizeof(u_short), 1); + n * sizeof(u_short), 1); n = 0; } } } if (n != 0) - ctl_putdata((char *)ass_stat, n * sizeof(u_short), 1); + ctl_putdata((char *)ass_stat, n * + sizeof(u_short), 1); ctl_flushpkt(0); } else { - peer = findpeerbyassoc((int)res_associd); + peer = findpeerbyassoc(res_associd); if (peer == 0) { ctl_error(CERR_BADASSOC); } else { @@ -1755,8 +1986,8 @@ read_status( if (res_authokay) peer->num_events = 0; /* - * For now, output everything we know about the peer. - * May be more selective later. + * For now, output everything we know about the + * peer. May be more selective later. */ for (cp = def_peer_var; *cp != 0; cp++) ctl_putpeer((int)*cp, peer); @@ -1780,11 +2011,11 @@ read_variables( register int i; char *valuep; u_char *wants; - unsigned int gotvar = (CS_MAXCODE>CP_MAXCODE) ? (CS_MAXCODE+1) : (CP_MAXCODE+1); - + unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE + + 1) : (CP_MAXCODE + 1); if (res_associd == 0) { /* - * Wants system variables. Figure out which he wants + * Wants system variables. Figure out which he wants * and give them to him. */ rpkt.status = htons(ctlsysstatus()); @@ -1796,13 +2027,15 @@ read_variables( gotvar = 0; while ((v = ctl_getitem(sys_var, &valuep)) != 0) { if (v->flags & EOV) { - if ((v = ctl_getitem(ext_sys_var, &valuep)) != 0) { + if ((v = ctl_getitem(ext_sys_var, + &valuep)) != 0) { if (v->flags & EOV) { ctl_error(CERR_UNKNOWNVAR); free((char *)wants); return; } - wants[CS_MAXCODE+1+v->code] = 1; + wants[CS_MAXCODE + 1 + + v->code] = 1; gotvar = 1; continue; } else { @@ -1815,35 +2048,38 @@ read_variables( if (gotvar) { for (i = 1; i <= CS_MAXCODE; i++) if (wants[i]) - ctl_putsys(i); - for (i = 0; ext_sys_var && !(ext_sys_var[i].flags & EOV); i++) - if (wants[i+CS_MAXCODE+1]) - ctl_putdata(ext_sys_var[i].text, - strlen(ext_sys_var[i].text), 0); + ctl_putsys(i); + for (i = 0; ext_sys_var && + !(ext_sys_var[i].flags & EOV); i++) + if (wants[i + CS_MAXCODE + 1]) + ctl_putdata(ext_sys_var[i].text, + strlen(ext_sys_var[i].text), + 0); } else { register u_char *cs; register struct ctl_var *kv; for (cs = def_sys_var; *cs != 0; cs++) ctl_putsys((int)*cs); - for (kv = ext_sys_var; kv && !(kv->flags & EOV); kv++) + for (kv = ext_sys_var; kv && !(kv->flags & EOV); + kv++) if (kv->flags & DEF) - ctl_putdata(kv->text, strlen(kv->text), 0); + ctl_putdata(kv->text, + strlen(kv->text), 0); } free((char *)wants); } else { register struct peer *peer; /* - * Wants info for a particular peer. See if we know + * Wants info for a particular peer. See if we know * the guy. */ - peer = findpeerbyassoc((int)res_associd); + peer = findpeerbyassoc(res_associd); if (peer == 0) { ctl_error(CERR_BADASSOC); return; } - rpkt.status = htons(ctlpeerstatus(peer)); if (res_authokay) peer->num_events = 0; @@ -1862,7 +2098,7 @@ read_variables( if (gotvar) { for (i = 1; i <= CP_MAXCODE; i++) if (wants[i]) - ctl_putpeer(i, peer); + ctl_putpeer(i, peer); } else { register u_char *cp; @@ -1876,8 +2112,8 @@ read_variables( /* - * write_variables - write into variables. We only allow leap bit writing - * this way. + * write_variables - write into variables. We only allow leap bit + * writing this way. */ /*ARGSUSED*/ static void @@ -1890,7 +2126,6 @@ write_variables( register int ext_var; char *valuep; long val; - /*int leapind, leapwarn;*/ /* * If he's trying to write into a peer tell him no way @@ -1906,20 +2141,14 @@ write_variables( rpkt.status = htons(ctlsysstatus()); /* - * Set flags to not-in-sync so we can tell when we get something. - */ - /* - leapind = ~0; - leapwarn = ~0; - */ - - /* - * Look through the variables. Dump out at the first sign of trouble. + * Look through the variables. Dump out at the first sign of + * trouble. */ while ((v = ctl_getitem(sys_var, &valuep)) != 0) { ext_var = 0; if (v->flags & EOV) { - if ((v = ctl_getitem(ext_sys_var, &valuep)) != 0) { + if ((v = ctl_getitem(ext_sys_var, &valuep)) != + 0) { if (v->flags & EOV) { ctl_error(CERR_UNKNOWNVAR); return; @@ -1933,7 +2162,8 @@ write_variables( ctl_error(CERR_PERMISSION); return; } - if (!ext_var && (*valuep == '\0' || !atoint(valuep, &val))) { + if (!ext_var && (*valuep == '\0' || !atoint(valuep, + &val))) { ctl_error(CERR_BADFMT); return; } @@ -1943,7 +2173,8 @@ write_variables( } if (ext_var) { - char *s = (char *)emalloc(strlen(v->text)+strlen(valuep)+2); + char *s = (char *)emalloc(strlen(v->text) + + strlen(valuep) + 2); const char *t; char *tt = s; @@ -1953,24 +2184,24 @@ write_variables( *tt++ = '='; strcat(tt, valuep); - set_sys_var(s, strlen(s)+1, v->flags); free(s); } else { /* - * This one seems sane. Save it. + * This one seems sane. Save it. */ switch(v->code) { - case CS_LEAP: - default: - ctl_error(CERR_UNSPEC); /* our fault, really */ + + case CS_LEAP: + default: + ctl_error(CERR_UNSPEC); /* really */ return; } } } /* - * If we got anything, do it. + * If we got anything, do it. xxx nothing to do *** */ /* if (leapind != ~0 || leapwarn != ~0) { @@ -2009,18 +2240,20 @@ read_clock_status( struct refclockstat clock_stat; if (res_associd == 0) { + /* * Find a clock for this jerk. If the system peer * is a clock use it, else search the hash tables * for one. */ - if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK)) { + if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK)) + { peer = sys_peer; } else { peer = 0; for (i = 0; peer == 0 && i < HASH_SIZE; i++) { for (peer = assoc_hash[i]; peer != 0; - peer = peer->ass_next) { + peer = peer->ass_next) { if (peer->flags & FLAG_REFCLOCK) break; } @@ -2031,7 +2264,7 @@ read_clock_status( } } } else { - peer = findpeerbyassoc((int)res_associd); + peer = findpeerbyassoc(res_associd); if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) { ctl_error(CERR_BADASSOC); return; @@ -2039,30 +2272,32 @@ read_clock_status( } /* - * If we got here we have a peer which is a clock. Get his status. + * If we got here we have a peer which is a clock. Get his + * status. */ clock_stat.kv_list = (struct ctl_var *)0; - - refclock_control(&peer->srcadr, (struct refclockstat *)0, &clock_stat); + refclock_control(&peer->srcadr, (struct refclockstat *)0, + &clock_stat); /* * Look for variables in the packet. */ rpkt.status = htons(ctlclkstatus(&clock_stat)); - gotvar = CC_MAXCODE+1+count_var(clock_stat.kv_list); + gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list); wants = (u_char *)emalloc(gotvar); memset((char*)wants, 0, gotvar); gotvar = 0; while ((v = ctl_getitem(clock_var, &valuep)) != 0) { if (v->flags & EOV) { - if ((v = ctl_getitem(clock_stat.kv_list, &valuep)) != 0) { + if ((v = ctl_getitem(clock_stat.kv_list, + &valuep)) != 0) { if (v->flags & EOV) { ctl_error(CERR_UNKNOWNVAR); free((char*)wants); free_varlist(clock_stat.kv_list); return; } - wants[CC_MAXCODE+1+v->code] = 1; + wants[CC_MAXCODE + 1 + v->code] = 1; gotvar = 1; continue; } else { @@ -2077,19 +2312,23 @@ read_clock_status( for (i = 1; i <= CC_MAXCODE; i++) if (wants[i]) ctl_putclock(i, &clock_stat, 1); - for (i = 0; clock_stat.kv_list && !(clock_stat.kv_list[i].flags & EOV); i++) - if (wants[i+CC_MAXCODE+1]) - ctl_putdata(clock_stat.kv_list[i].text, - strlen(clock_stat.kv_list[i].text), 0); + for (i = 0; clock_stat.kv_list && + !(clock_stat.kv_list[i].flags & EOV); i++) + if (wants[i + CC_MAXCODE + 1]) + ctl_putdata(clock_stat.kv_list[i].text, + strlen(clock_stat.kv_list[i].text), + 0); } else { register u_char *cc; register struct ctl_var *kv; for (cc = def_clock_var; *cc != 0; cc++) ctl_putclock((int)*cc, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); kv++) + for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); + kv++) if (kv->flags & DEF) - ctl_putdata(kv->text, strlen(kv->text), 0); + ctl_putdata(kv->text, strlen(kv->text), + 0); } free((char*)wants); @@ -2114,11 +2353,10 @@ write_clock_status( } /* - * Trap support from here on down. We send async trap messages when the - * upper levels report trouble. Traps can by set either by control + * Trap support from here on down. We send async trap messages when the + * upper levels report trouble. Traps can by set either by control * messages or by configuration. */ - /* * set_trap - set a trap in response to a control message */ @@ -2150,7 +2388,7 @@ set_trap( * an error if it can't assign the trap. */ if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype, - (int)res_version)) + (int)res_version)) ctl_error(CERR_NORESOURCE); ctl_flushpkt(0); } @@ -2168,11 +2406,10 @@ unset_trap( int traptype; /* - * We don't prevent anyone from removing his own - * trap unless the trap is configured. Note we also - * must be aware of the possibility that restriction - * flags were changed since this guy last set his trap. - * Set the trap type based on this. + * We don't prevent anyone from removing his own trap unless the + * trap is configured. Note we also must be aware of the + * possibility that restriction flags were changed since this + * guy last set his trap. Set the trap type based on this. */ traptype = TRAP_TYPE_PRIO; if (restrict_mask & RES_LPTRAP) @@ -2207,69 +2444,77 @@ ctlsettrap( */ if ((tp = ctlfindtrap(raddr, linter)) != NULL) { switch (traptype) { - case TRAP_TYPE_CONFIG: + + case TRAP_TYPE_CONFIG: tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED; break; - case TRAP_TYPE_PRIO: + + case TRAP_TYPE_PRIO: if (tp->tr_flags & TRAP_CONFIGURED) - return 1; /* don't change anything */ + return (1); /* don't change anything */ tp->tr_flags = TRAP_INUSE; break; - case TRAP_TYPE_NONPRIO: + + case TRAP_TYPE_NONPRIO: if (tp->tr_flags & TRAP_CONFIGURED) - return 1; /* don't change anything */ + return (1); /* don't change anything */ tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO; break; } tp->tr_settime = current_time; tp->tr_resets++; - return 1; + return (1); } /* * First we heard of this guy. Try to find a trap structure * for him to use, clearing out lesser priority guys if we - * have to. Clear out anyone who's expired while we're at it. + * have to. Clear out anyone who's expired while we're at it. */ tptouse = NULL; for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { if ((tp->tr_flags & TRAP_INUSE) && - !(tp->tr_flags & TRAP_CONFIGURED) && - ((tp->tr_settime + CTL_TRAPTIME) > current_time)) { + !(tp->tr_flags & TRAP_CONFIGURED) && + ((tp->tr_settime + CTL_TRAPTIME) > current_time)) { tp->tr_flags = 0; num_ctl_traps--; } - if (!(tp->tr_flags & TRAP_INUSE)) { tptouse = tp; } else if (!(tp->tr_flags & TRAP_CONFIGURED)) { switch (traptype) { - case TRAP_TYPE_CONFIG: + + case TRAP_TYPE_CONFIG: if (tptouse == NULL) { tptouse = tp; break; } - if (tptouse->tr_flags & TRAP_NONPRIO - && !(tp->tr_flags & TRAP_NONPRIO)) + if (tptouse->tr_flags & TRAP_NONPRIO && + !(tp->tr_flags & TRAP_NONPRIO)) break; + if (!(tptouse->tr_flags & TRAP_NONPRIO) - && tp->tr_flags & TRAP_NONPRIO) { + && tp->tr_flags & TRAP_NONPRIO) { tptouse = tp; break; } - if (tptouse->tr_origtime < tp->tr_origtime) + if (tptouse->tr_origtime < + tp->tr_origtime) tptouse = tp; break; - case TRAP_TYPE_PRIO: + + case TRAP_TYPE_PRIO: if (tp->tr_flags & TRAP_NONPRIO) { if (tptouse == NULL || - (tptouse->tr_flags & TRAP_INUSE - && tptouse->tr_origtime - < tp->tr_origtime)) + (tptouse->tr_flags & + TRAP_INUSE && + tptouse->tr_origtime < + tp->tr_origtime)) tptouse = tp; } break; - case TRAP_TYPE_NONPRIO: + + case TRAP_TYPE_NONPRIO: break; } } @@ -2279,7 +2524,7 @@ ctlsettrap( * If we don't have room for him return an error. */ if (tptouse == NULL) - return 0; + return (0); /* * Set up this structure for him. @@ -2290,19 +2535,18 @@ ctlsettrap( tptouse->tr_addr = *raddr; tptouse->tr_localaddr = linter; tptouse->tr_version = version; - tptouse->tr_flags = TRAP_INUSE; if (traptype == TRAP_TYPE_CONFIG) tptouse->tr_flags |= TRAP_CONFIGURED; else if (traptype == TRAP_TYPE_NONPRIO) tptouse->tr_flags |= TRAP_NONPRIO; num_ctl_traps++; - return 1; + return (1); } /* - * ctlclrtrap - called to clr a trap + * ctlclrtrap - called to clear a trap */ int ctlclrtrap( @@ -2314,15 +2558,15 @@ ctlclrtrap( register struct ctl_trap *tp; if ((tp = ctlfindtrap(raddr, linter)) == NULL) - return 0; + return (0); if (tp->tr_flags & TRAP_CONFIGURED && traptype != TRAP_TYPE_CONFIG) - return 0; + return (0); tp->tr_flags = 0; num_ctl_traps--; - return 1; + return (1); } @@ -2338,11 +2582,11 @@ ctlfindtrap( 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 && NSRCADR(raddr) == + NSRCADR(&tp->tr_addr) && NSRCPORT(raddr) == + NSRCPORT(&tp->tr_addr) && linter == + tp->tr_localaddr) + return (tp); } return (struct ctl_trap *)NULL; } @@ -2368,14 +2612,15 @@ report_event( ctl_sys_num_events++; if (ctl_sys_last_event != (u_char)err) { NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)", - eventstr(err), err, - sysstatstr(ctlsysstatus()), ctlsysstatus()); + msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)", + eventstr(err), err, + sysstatstr(ctlsysstatus()), ctlsysstatus()); #ifdef DEBUG if (debug) printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n", - eventstr(err), err, - sysstatstr(ctlsysstatus()), ctlsysstatus()); + eventstr(err), err, + sysstatstr(ctlsysstatus()), + ctlsysstatus()); #endif ctl_sys_last_event = (u_char)err; } @@ -2393,19 +2638,25 @@ report_event( if (peer->num_events < CTL_PEER_MAXEVENTS) peer->num_events++; NLOG(NLOG_PEEREVENT) - msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)", - src, eventstr(err), err, - peerstatstr(ctlpeerstatus(peer)), ctlpeerstatus(peer)); + msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)", + src, eventstr(err), err, + peerstatstr(ctlpeerstatus(peer)), + ctlpeerstatus(peer)); #ifdef DEBUG if (debug) printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n", - src, eventstr(err), err, - peerstatstr(ctlpeerstatus(peer)), ctlpeerstatus(peer)); + src, eventstr(err), err, + peerstatstr(ctlpeerstatus(peer)), + ctlpeerstatus(peer)); #endif } else { - msyslog(LOG_ERR, "report_event: err '%s' (0x%02x), no peer", eventstr(err), err); + msyslog(LOG_ERR, + "report_event: err '%s' (0x%02x), no peer", + eventstr(err), err); #ifdef DEBUG - printf("report_event: peer event '%s' (0x%02x), no peer\n", eventstr(err), err); + printf( + "report_event: peer event '%s' (0x%02x), no peer\n", + eventstr(err), err); #endif return; } @@ -2425,38 +2676,42 @@ report_event( res_authenticate = 0; datapt = rpkt.data; dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); - if (!(err & PEER_EVENT)) { rpkt.associd = 0; rpkt.status = htons(ctlsysstatus()); /* * For now, put everything we know about system - * variables. Maybe more selective later + * variables. Don't send crypto strings. */ - for (i = 1; i <= CS_MAXCODE; i++) + for (i = 1; i <= CS_MAXCODE; i++) { +#ifdef PUBKEY + if (i > CS_VARLIST) + continue; +#endif /* PUBKEY */ ctl_putsys(i); + } #ifdef REFCLOCK /* - * for clock exception events: - * add clock variables to reflect info on exception + * for clock exception events: add clock variables to + * reflect info on exception */ if (err == EVNT_CLOCKEXCPT) { struct refclockstat clock_stat; struct ctl_var *kv; clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, - (struct refclockstat *)0, &clock_stat); - ctl_puthex("refclockstatus", ctlclkstatus(&clock_stat)); - + (struct refclockstat *)0, &clock_stat); + ctl_puthex("refclockstatus", + ctlclkstatus(&clock_stat)); for (i = 1; i <= CC_MAXCODE; i++) ctl_putclock(i, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); kv++) + for (kv = clock_stat.kv_list; kv && + !(kv->flags & EOV); kv++) if (kv->flags & DEF) - ctl_putdata(kv->text, strlen(kv->text), 0); - + ctl_putdata(kv->text, + strlen(kv->text), 0); free_varlist(clock_stat.kv_list); } #endif /*REFCLOCK*/ @@ -2465,34 +2720,37 @@ report_event( rpkt.status = htons(ctlpeerstatus(peer)); /* - * Dump it all. Later, maybe less. + * Dump it all. Later, maybe less. */ for (i = 1; i <= CP_MAXCODE; i++) +#ifdef PUBKEY + if (i > CP_VARLIST) + continue; +#endif /* PUBKEY */ ctl_putpeer(i, peer); #ifdef REFCLOCK /* - * for clock exception events: - * add clock variables to reflect info on exception + * for clock exception events: add clock variables to + * reflect info on exception */ if (err == EVNT_PEERCLOCK) { struct refclockstat clock_stat; struct ctl_var *kv; clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, - (struct refclockstat *)0, - &clock_stat); + (struct refclockstat *)0, &clock_stat); ctl_puthex("refclockstatus", - ctlclkstatus(&clock_stat)); + ctlclkstatus(&clock_stat)); for (i = 1; i <= CC_MAXCODE; i++) ctl_putclock(i, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); kv++) + for (kv = clock_stat.kv_list; kv && + !(kv->flags & EOV); kv++) if (kv->flags & DEF) - ctl_putdata(kv->text, strlen(kv->text), 0); - + ctl_putdata(kv->text, + strlen(kv->text), 0); free_varlist(clock_stat.kv_list); } #endif /*REFCLOCK*/ @@ -2537,14 +2795,12 @@ count_var( register u_long c; if (!k) - return 0; + return (0); c = 0; - while (!(k++->flags & EOV)) - c++; - - return c; + c++; + return (c); } char * @@ -2561,12 +2817,11 @@ add_var( k = *kv; *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var)); - if (k) - { - memmove((char *)*kv, (char *)k, sizeof(struct ctl_var)*c); + if (k) { + memmove((char *)*kv, (char *)k, + sizeof(struct ctl_var)*c); free((char *)k); } - (*kv)[c].code = (u_short) c; (*kv)[c].text = (char *)emalloc(size); (*kv)[c].flags = def; @@ -2592,21 +2847,16 @@ set_var( if (!data || !size) return; - if ((k = *kv)) - { - while (!(k->flags & EOV)) - { + if ((k = *kv)) { + while (!(k->flags & EOV)) { s = data; t = k->text; - if (t) - { - while (*t != '=' && *s - *t == 0) - { + if (t) { + while (*t != '=' && *s - *t == 0) { s++; t++; } - if (*s == *t && ((*t == '=') || !*t)) - { + if (*s == *t && ((*t == '=') || !*t)) { free((void *)k->text); td = (char *)emalloc(size); memmove(td, data, size); @@ -2614,9 +2864,7 @@ set_var( k->flags = def; return; } - } - else - { + } else { td = (char *)emalloc(size); memmove(td, data, size); k->text = td; @@ -2646,10 +2894,9 @@ free_varlist( ) { struct ctl_var *k; - if (kv) - { + if (kv) { for (k = kv; !(k->flags & EOV); k++) - free((void *)k->text); + free((void *)k->text); free((void *)kv); } } diff --git a/contrib/ntp/ntpd/ntp_crypto.c b/contrib/ntp/ntpd/ntp_crypto.c new file mode 100644 index 0000000..d8516b5 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_crypto.c @@ -0,0 +1,2060 @@ +/* + * ntp_crypto.c - NTP version 4 public key routines + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef AUTOKEY +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include "ntpd.h" +#include "ntp_stdlib.h" +#include "ntp_string.h" +#include "ntp_crypto.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. + */ +/* + * Minimum sizes of fields + */ +#define COOKIE_LEN (5 * 4) +#define AUTOKEY_LEN (6 * 4) +#define VALUE_LEN (6 * 4) + +/* + * Global cryptodata in host byte order. + */ +u_int crypto_flags; /* 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. + */ +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 */ + +/* + * Global cryptodata in network 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 */ + +/* + * 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 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 */ + +/* + * session_key - generate session key + * + * This routine generates a session key from the source address, + * 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. + */ +keyid_t /* returns next key ID */ +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 */ + ) +{ + 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 */ + + /* + * 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); + keyid = ntohl(keyid); + if (lifetime != 0) { + MD5auth_setkey(keyno, digest, 16); + 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, + private, keyid, lifetime); +#endif + return (keyid); +} + + +/* + * make_keylist - generate key list + * + * This routine constructs a pseudo-random sequence by repeatedly + * hashing the session key starting from a given source address, + * destination address, private value and the next key ID of the + * preceeding session key. The last entry on the list is saved along + * with its sequence number and public signature. + */ +void +make_keylist( + struct peer *peer, /* peer structure pointer */ + struct interface *dstadr /* interface */ + ) +{ + 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 */ + + /* + * Allocate the key list if necessary. + */ + L_CLR(&tstamp); + if (sys_leap != LEAP_NOTINSYNC) + get_systime(&tstamp); + if (peer->keylist == NULL) + peer->keylist = (keyid_t *)emalloc(sizeof(keyid_t) * + NTP_MAXSESSION); + + /* + * Generate an initial key ID which is unique and greater than + * NTP_MAXKEY. + */ + while (1) { + keyid = (u_long)RANDOM & 0xffffffff; + if (keyid <= NTP_MAXKEY) + continue; + if (authhavekey(keyid)) + continue; + break; + } + + /* + * Generate up to NTP_MAXSESSION session keys. Stop if the + * next one would not be unique or not a session key ID or if + * it would expire before the next poll. The private value + * 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); + if (peer->hmode == MODE_BROADCAST) + cookie = 0; + else + cookie = peer->pcookie.key; + 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; + if (auth_havekey(keyid) || keyid <= NTP_MAXKEY || + ltemp <= (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. + */ + ap = &peer->sndauto; + ap->tstamp = htonl(tstamp.l_ui); + ap->seq = htonl(peer->keynumber); + ap->key = htonl(keyid); + ap->siglen = 0; +#if DEBUG + if (debug) + printf("make_keys: %d %08x %08x ts %u poll %d\n", + ntohl(ap->seq), ntohl(ap->key), cookie, + ntohl(ap->tstamp), 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 */ +} + + +/* + * crypto_recv - parse extension fields + * + * This routine is called when the packet has been matched to an + * association and passed sanity, format and MAC checks. We believe the + * 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 + * bit is not set. + */ +void +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; +#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. + */ + 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]); +#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])); +#endif + switch (code) { + + /* + * Install association ID and status word. + */ + 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; + } +#ifdef DEBUG + if (debug) + printf( + "crypto_recv: verify %d flags 0x%x ts %u\n", + rval, temp, tstamp); +#endif + break; + + /* + * Install autokey values in broadcast client and + * symmetric modes. + */ + 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); + } +#else /* PUBKEY */ + if (tstamp < peer->recauto.tstamp || (tstamp == + peer->recauto.tstamp && (peer->flags & + FLAG_AUTOKEY))) + rval = RV_TSP; + else + rval = RV_OK; +#endif /* PUBKEY */ +#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); +#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. + */ + case CRYPTO_PRIV: + peer->cmmd = ntohl(pkt[i]); + /* fall through */ + + 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 */ + + /* + * Tricky here. If in client mode, use the + * server cookie; otherwise, use EXOR of both + * peer cookies. We call this Daffy-Hooligan + * agreement. + */ + if (peer->hmode == MODE_CLIENT) + temp = ntohl(cp->key); + else + temp = ntohl(cp->key) ^ peer->hcookie; +#ifdef DEBUG + if (debug) + printf( + "crypto_recv: verify %x cookie %08x ts %u (%u)\n", + rval, temp, tstamp, + peer->pcookie.tstamp); +#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. + */ + case CRYPTO_NAME | CRYPTO_RESP: + if (!crypto_flags) + 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; + } + } +#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); +#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. + */ + case CRYPTO_CERT | CRYPTO_RESP: + if (!crypto_flags) + 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); + } +#ifdef DEBUG + if (debug) + printf( + "crypto_recv: verify %x certificate %u ts %u fs %u\n", + rval, temp, tstamp, fstamp); +#endif + + /* + * If the peer data are newer than the host + * data, replace the host data. Otherwise, + * wait for the peer to fetch the host data. + */ + 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); + 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. + */ + 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(); + break; + + /* + * Install agreement parameters in symmetric modes. + */ + case CRYPTO_DHPAR | CRYPTO_RESP: + if (!crypto_flags) + 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); + } +#ifdef DEBUG + if (debug) + printf( + "crypto_recv: verify %x parameters %u ts %u fs %u\n", + rval, temp, tstamp, fstamp); +#endif + + /* + * If the peer data are newer than the host + * data, replace the host data. Otherwise, + * wait for the peer to fetch the host data. + */ + 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); + 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. + */ + 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); + + /* + * Initialize public value extension field. + */ + 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(); + break; + + /* + * Verify public value and compute agreed key in + * symmetric modes. + */ + case CRYPTO_DH: + peer->cmmd = ntohl(pkt[i]); + if (!crypto_flags) + peer->cmmd |= CRYPTO_ERROR; + /* fall through */ + + case CRYPTO_DH | CRYPTO_RESP: + if (!crypto_flags) + 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. + */ + 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); + } +#ifdef DEBUG + if (debug) + printf( + "crypto_recv: verify %x agreement %08x ts %u (%u) fs %u\n", + rval, temp, tstamp, + peer->pcookie.tstamp, fstamp); +#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. + */ + case CRYPTO_TAI | CRYPTO_RESP: + if (!crypto_flags) + 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 + + /* + * If the peer data are newer than the host + * data, replace the host data. Otherwise, + * wait for the peer to fetch the host data. + */ + 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); + break; + } + peer->flash &= ~TEST10; + crypto_flags |= CRYPTO_FLAG_TAI; + peer->crypto &= ~CRYPTO_FLAG_TAI; + sys_tai = temp / 4 + TAI_1972 - 1; +#ifdef KERNEL_PLL +#if NTP_API > 3 + ntv.modes = MOD_TAI; + ntv.constant = sys_tai; + if (ntp_adjtime(&ntv) == TIME_ERROR) + msyslog(LOG_ERR, + "kernel TAI update failed"); +#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(); + break; +#endif /* PUBKEY */ + + /* + * For other requests, save the request code for later; + * for unknown responses or errors, just ignore for now. + */ + default: + if (code & (CRYPTO_RESP | CRYPTO_ERROR)) + break; + peer->cmmd = ntohl(pkt[i]); + break; + + } + authlen += len; + } +} + + +/* + * 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 + * association ID to match the association. + */ +int /* return length of extension field */ +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 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 */ + + /* + * 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); + len = 8; + switch (opcode) { + + /* + * Send association ID, timestamp and status word. + */ + 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; + 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. + */ + case CRYPTO_AUTO | CRYPTO_RESP: + peer = findpeerbyassoc(associd); + if (peer == NULL) { + opcode |= CRYPTO_ERROR; + break; + } + 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 */ + break; + + /* + * Send peer cookie and signature in server mode. + */ + 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); + break; + } + cp->siglen = htonl(temp); + len += temp; +#endif /* PUBKEY */ + 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 certificate, timestamp and signature. + */ + case CRYPTO_CERT | CRYPTO_RESP: + if (!crypto_flags) { + 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; + break; + + /* + * Send agreement parameters, timestamp and signature. + */ + case CRYPTO_DHPAR | CRYPTO_RESP: + if (!crypto_flags) { + 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; + break; + + /* + * Send public value, timestamp and signature. + */ + case CRYPTO_DH: + case CRYPTO_DH | CRYPTO_RESP: + if (!crypto_flags) { + 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; + break; + + /* + * Send public key, host name, timestamp and signature. + */ + case CRYPTO_NAME | CRYPTO_RESP: + if (!crypto_flags) { + 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; + break; + + /* + * Send leapseconds table, timestamp and signature. + */ + 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; + break; +#endif /* PUBKEY */ + + /* + * Default - Fall through for requests; for unknown responses, + * flag as error. + */ + 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. + */ + len = ((len + 7) / 8) * 8; + if (len >= 4) { + xpkt[i] = htonl((u_int32)((opcode << 16) | len)); +#ifdef DEBUG + if (debug) + printf( + "crypto_xmit: ext offset %d len %d code %x assocID %d\n", + start, len, code, 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. + */ +void +crypto_setup(void) +{ + char filename[MAXFILENAME]; + u_int fstamp; /* filestamp */ + u_int len, temp; + u_int32 *pp; + + /* + * Initialize structures. + */ + 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; + + /* + * Load required private key from file, default "ntpkey". + */ + 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))); + + /* + * Load required public key from file, default + * "ntpkey_host", where "host" is the canonical name of this + * machine. + */ + if (public_key_file == NULL) { + snprintf(filename, MAXFILENAME, "ntpkey_%s", + sys_hostname); + public_key_file = emalloc(strlen(filename) + 1); + strcpy(public_key_file, filename); + } + 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); + } + 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. + */ + 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); + + /* + * 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 (certif_file == NULL) + snprintf(filename, MAXFILENAME, "ntpkey_certif_%s", + sys_hostname); + certif_file = emalloc(strlen(filename) + 1); + strcpy(certif_file, filename); + crypto_cert(certif_file); + + /* + * 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. + */ + if (dh_params_file == NULL) + dh_params_file = "ntpkey_dh"; + crypto_dh(dh_params_file); + + /* + * 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 (tai_leap_file == NULL) + tai_leap_file = "ntpkey_leap"; + crypto_tai(tai_leap_file); +} + + +/* + * crypto_agree - compute new public value and sign extension fields. + */ +void +crypto_agree(void) +{ + 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; + + /* + * Sign host name and timestamps, but only if the clock is + * synchronized. + */ + if (sys_leap == LEAP_NOTINSYNC) + return; + get_systime(&lstamp); + tstamp = lstamp.l_ui; + host.tstamp = htonl(tstamp); + if (!crypto_flags) + 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); + + /* + * Sign certificate and timestamps. + */ + 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); + } + + /* + * Sign agreement parameters and timestamps. + */ + 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); + } + dhpub.siglen = ntohl(len); + } + + /* + * Sign leapseconds table and timestamps. + */ + if (tai_leap.vallen != 0) { + tai_leap.tstamp = htonl(tstamp); + EVP_SignInit(&ctx, DA_MD5); + 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); + } +#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)); +#endif +} + + +/* + * crypto_rsa - read RSA key, decode and check for errors. + */ +static u_int +crypto_rsa( + char *cp, /* file name */ + u_char *key, /* key pointer */ + u_int keylen /* key length */ + ) +{ + 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; + + /* + * Open the file and discard comment lines. If the first + * character of the file name is not '/', prepend the keys + * directory string. + */ + 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); + } + + /* + * Ignore initial comments and empty lines. + */ + while ((rptr = fgets(buf, MAX_LINLEN - 1, str)) != NULL) { + len = strlen(buf); + if (len < 1) + continue; + if (*buf == '#' || *buf == '\r' || *buf == '\0') + continue; + break; + } + + /* + * 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); + } + fclose(str); + *(u_int *)buf = bits; + memcpy(key, buf, keylen); + + /* + * Extract filestamp if present. + */ + 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_cert - read certificate + */ +static void +crypto_cert( + char *cp /* file name */ + ) +{ + 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; + + /* + * Open the file and discard comment lines. If the first + * character of the file name is not '/', prepend the keys + * directory string. If the file is not found, not to worry; it + * can be retrieved over the net. But, if it is found with + * errors, we crash and burn. + */ + if (*cp == '/') + strcpy(filename, cp); + else + snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); + fd = open(filename, O_RDONLY, 0777); + if (fd <= 0) { + msyslog(LOG_INFO, + "crypto: certificate file %s not found", + filename); + return; + } + + /* + * We are rather paranoid here, since an intruder might cause a + * coredump by infiltrating naughty values. + */ + 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); + } + + /* + * The extension field entry consists of the raw certificate. + */ + 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; + + /* + * Extract filestamp if present. + */ + 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); +#ifdef DEBUG + if (debug) + printf( + "crypto_cert: certif file %s link %d fs %u len %d\n", + cp, rval, fstamp, len); +#endif +} + + +/* + * crypto_dh - read agreement parameters, decode and check for errors. + */ +static void +crypto_dh( + 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; + + /* + * Open the file and discard comment lines. If the first + * character of the file name is not '/', prepend the keys + * directory string. If the file is not found, not to worry; it + * can be retrieved over the net. But, if it is found with + * errors, we crash and burn. + */ + if (*cp == '/') + strcpy(filename, cp); + else + snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); + str = fopen(filename, "r"); + if (str == NULL) { + msyslog(LOG_INFO, + "crypto: parameters file %s not found", filename); + return; + } + + /* + * Ignore initial comments and empty lines. + */ + while ((rptr = fgets(buf, MAX_LINLEN - 1, str)) != NULL) { + if (strlen(buf) < 1) + continue; + if (*buf == '#' || *buf == '\r' || *buf == '\0') + continue; + break; + } + + /* + * 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); + } + 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. + */ + dhpub.vallen = htonl(dh_params.primeLen); + dhpub.ptr = emalloc(dh_params.primeLen); + dhpub.sig = emalloc(private_key.bits / 8); + + /* + * Extract filestamp if present. + */ + 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); +#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); +#endif +} + + +/* + * crypto_tai - read leapseconds table and check for errors. + */ +static void +crypto_tai( + 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; +#ifdef KERNEL_PLL +#if NTP_API > 3 + struct timex ntv; /* kernel interface structure */ +#endif /* NTP_API */ +#endif /* KERNEL_PLL */ + + /* + * Open the file and discard comment lines. If the first + * character of the file name is not '/', prepend the keys + * directory string. If the file is not found, not to worry; it + * can be retrieved over the net. But, if it is found with + * errors, we crash and burn. + */ + if (*cp == '/') + strcpy(filename, cp); + else + snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); + str = fopen(filename, "r"); + if (str == NULL) { + msyslog(LOG_INFO, + "crypto: leapseconds file %s not found", + filename); + return; + } + + /* + * We are rather paranoid here, since an intruder might cause a + * coredump by infiltrating naughty values. Empty lines and + * comments are ignored. Other lines must begin with two + * integers followed by junk or comments. The first integer is + * the NTP seconds of leap insertion, the second is the offset + * of TAI relative to UTC after that insertion. The second word + * must equal the initial insertion of ten seconds on 1 January + * 1972 plus one second for each succeeding insertion. + */ + i = 0; + rval = RV_OK; + while (i < MAX_LEAP) { + rptr = fgets(buf, MAX_LINLEN - 1, str); + if (rptr == NULL) + break; + if (strlen(buf) < 1) + continue; + if (*buf == '#') + continue; + if (sscanf(buf, "%u %u", &leapsec[i], &offset) != 2) + continue; + if (i != offset - TAI_1972) { + rval = RV_DAT; + break; + } + i++; + } + fclose(str); + if (rval != RV_OK || i == 0) { + msyslog(LOG_ERR, + "crypto: leapseconds file %s error %d", cp, + rval); + exit (-1); + } + + /* + * The extension field table entries consists of the NTP seconds + * of leap insertion in reverse order, so that the most recent + * insertion is the first entry in the table. + */ + len = i * 4; + tai_leap.vallen = htonl(len); + pp = emalloc(len); + tai_leap.ptr = (u_char *)pp; + for (; i >= 0; i--) { + *pp++ = 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 +#if NTP_API > 3 + ntv.modes = MOD_TAI; + ntv.constant = sys_tai; + if (ntp_adjtime(&ntv) == TIME_ERROR) + msyslog(LOG_ERR, + "crypto: kernel TAI update failed"); +#endif /* NTP_API */ +#endif /* KERNEL_PLL */ + + + /* + * Extract filestamp if present. + */ + 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; + tai_leap.fstamp = htonl(fstamp); +#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); +#endif +} + + +/* + * crypto_config - configure crypto data from crypto configuration + * command. + */ +void +crypto_config( + int item, /* configuration item */ + char *cp /* file name */ + ) +{ + switch (item) { + + /* + * Initialize flags + */ + case CRYPTO_CONF_FLAGS: + sscanf(cp, "%x", &crypto_flags); + break; + + /* + * Set private key file name. + */ + case CRYPTO_CONF_PRIV: + private_key_file = emalloc(strlen(cp) + 1); + strcpy(private_key_file, cp); + break; + + /* + * Set public key file name. + */ + case CRYPTO_CONF_PUBL: + public_key_file = emalloc(strlen(cp) + 1); + strcpy(public_key_file, cp); + break; + + /* + * Set certificate file name. + */ + case CRYPTO_CONF_CERT: + certif_file = emalloc(strlen(cp) + 1); + strcpy(certif_file, cp); + break; + + /* + * Set agreement parameter file name. + */ + case CRYPTO_CONF_DH: + dh_params_file = emalloc(strlen(cp) + 1); + strcpy(dh_params_file, cp); + break; + + /* + * Set leapseconds table file name. + */ + case CRYPTO_CONF_LEAP: + tai_leap_file = emalloc(strlen(cp) + 1); + strcpy(tai_leap_file, cp); + break; + + /* + * Set crypto keys directory. + */ + case CRYPTO_CONF_KEYS: + keysdir = emalloc(strlen(cp) + 1); + strcpy(keysdir, cp); + break; + } + crypto_flags |= CRYPTO_FLAG_ENAB; +} +# else +int ntp_crypto_bs_pubkey; +# endif /* PUBKEY */ +#else +int ntp_crypto_bs_autokey; +#endif /* AUTOKEY */ diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c index e9a387e..9653fdd 100644 --- a/contrib/ntp/ntpd/ntp_intres.c +++ b/contrib/ntp/ntpd/ntp_intres.c @@ -20,19 +20,25 @@ # include <config.h> #endif -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/time.h> -#include <netdb.h> -#include <signal.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_request.h" #include "ntp_stdlib.h" #include "ntp_syslog.h" +#include <stdio.h> +#include <ctype.h> +#include <netdb.h> +#include <signal.h> + +/**/ +#include <netinet/in.h> +#include <arpa/inet.h> +/**/ +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> /* MAXHOSTNAMELEN (often) */ +#endif + #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) /* @@ -52,6 +58,7 @@ struct conf_entry { #define ce_flags ce_config.flags #define ce_ttl ce_config.ttl #define ce_keyid ce_config.keyid +#define ce_keystr ce_config.keystr /* * confentries is a pointer to the list of configuration entries @@ -73,7 +80,6 @@ static struct conf_entry *confentries = NULL; #define MAXRESOLVE 32 #define CONFIG_TIME 2 #define ALARM_TIME 30 - #define SLEEPTIME 2 static volatile int config_timer = 0; @@ -107,7 +113,8 @@ static int resolve_value; /* next value of resolve timer */ #define TOK_FLAGS 5 #define TOK_TTL 6 #define TOK_KEYID 7 -#define NUMTOK 8 +#define TOK_KEYSTR 8 +#define NUMTOK 9 #define MAXLINESIZE 512 @@ -120,7 +127,7 @@ static int sockfd = -1; /* stuff to be filled in by caller */ -u_long req_keyid; /* request keyid */ +keyid_t req_keyid; /* request keyid */ char *req_file; /* name of the file with configuration info */ /* end stuff to be filled in */ @@ -129,7 +136,8 @@ char *req_file; /* name of the file with configuration info */ static RETSIGTYPE bong P((int)); static void checkparent P((void)); static void removeentry P((struct conf_entry *)); -static void addentry P((char *, int, int, int, int, int, int, u_long)); +static void addentry P((char *, int, int, int, int, u_int, + int, keyid_t, char *)); static int findhostaddr P((struct conf_entry *)); static void openntp P((void)); static int request P((struct conf_peer *)); @@ -137,10 +145,48 @@ static char * nexttoken P((char **)); static void readconf P((FILE *, char *)); static void doconfigure P((int)); +struct ntp_res_t_pkt { /* Tagged packet: */ + void *tag; /* For the caller */ + u_int32 paddr; /* IP to look up, or 0 */ + char name[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */ +}; + +struct ntp_res_c_pkt { /* Control packet: */ + char name[MAXHOSTNAMELEN]; + u_int32 paddr; + int mode; + int version; + int minpoll; + int maxpoll; + u_int flags; + int ttl; + keyid_t keyid; + u_char keystr[MAXFILENAME]; +}; + + /* - * assumes: req_key, req_keyid, conffile valid - * syslog still open + * ntp_res_recv: Process an answer from the resolver */ + +void +ntp_res_recv(void) +{ + /* + We have data ready on our descriptor. + It may be an EOF, meaning the resolver process went away. + Otherwise, it will be an "answer". + */ +} + + +/* + * ntp_intres needs; + * + * req_key(???), req_keyid, req_file valid + * syslog still open + */ + void ntp_intres(void) { @@ -149,7 +195,7 @@ ntp_intres(void) sigset_t set; sigemptyset(&set); -#endif /* NTP_POSIX_SOURCE */ +#endif /* HAVE_SIGSUSPEND */ #ifdef DEBUG if (debug > 1) { @@ -160,7 +206,7 @@ ntp_intres(void) /* check out auth stuff */ if (sys_authenticate) { if (!authistrusted(req_keyid)) { - msyslog(LOG_ERR, "invalid request keyid %lu", + msyslog(LOG_ERR, "invalid request keyid %08x", req_keyid ); exit(1); } @@ -180,7 +226,7 @@ ntp_intres(void) (void) fclose(in); if (!debug ) - (void) unlink(req_file); + (void) unlink(req_file); /* * Sleep a little to make sure the server is completely up @@ -192,12 +238,13 @@ ntp_intres(void) * Make a first cut at resolving the bunch */ doconfigure(1); - if (confentries == NULL) + if (confentries == NULL) { #if defined SYS_WINNT - ExitThread(0); /* Don't want to kill whole NT process */ + ExitThread(0); /* Don't want to kill whole NT process */ #else - exit(0); /* done that quick */ + exit(0); /* done that quick */ #endif + } /* * Here we've got some problem children. Set up the timer @@ -221,7 +268,8 @@ ntp_intres(void) resolve_value <<= 1; resolve_timer = resolve_value; #ifdef DEBUG - msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer); + if (debug > 2) + msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer); #endif config_timer = CONFIG_TIME; doconfigure(1); @@ -229,7 +277,8 @@ ntp_intres(void) } else if (config_timer == 0) { config_timer = CONFIG_TIME; #ifdef DEBUG - msyslog(LOG_INFO, "config_timer: 0->%d", config_timer); + if (debug > 2) + msyslog(LOG_INFO, "config_timer: 0->%d", config_timer); #endif doconfigure(0); continue; @@ -239,11 +288,11 @@ ntp_intres(void) * There is a race in here. Is okay, though, since * all it does is delay things by 30 seconds. */ -#ifdef HAVE_SIGSUSPEND +# ifdef HAVE_SIGSUSPEND sigsuspend(&set); -#else +# else sigpause(0); -#endif /* HAVE_SIGSUSPEND */ +# endif /* HAVE_SIGSUSPEND */ #else if (config_timer > 0) config_timer--; @@ -336,17 +385,25 @@ addentry( int version, int minpoll, int maxpoll, - int flags, + u_int flags, int ttl, - u_long keyid + keyid_t keyid, + char *keystr ) { register char *cp; register struct conf_entry *ce; unsigned int len; +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "intres: <%s> %d %d %d %d %x %d %x %s\n", name, + mode, version, minpoll, maxpoll, flags, ttl, keyid, + keystr); +#endif len = strlen(name) + 1; - cp = (char*)emalloc(len); + cp = (char *)emalloc(len); memmove(cp, name, len); ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); @@ -359,6 +416,7 @@ addentry( ce->ce_flags = (u_char)flags; ce->ce_ttl = (u_char)ttl; ce->ce_keyid = keyid; + strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME); ce->ce_next = NULL; if (confentries == NULL) { @@ -375,12 +433,12 @@ addentry( /* - * findhostaddr - resolve a host name into an address + * findhostaddr - resolve a host name into an address (Or vice-versa) * - * The routine sticks the address into the entry's ce_peeraddr if it - * gets one. It returns 1 for "success" and 0 for an uncorrectable - * failure. Note that "success" includes try again errors. You can - * tell that you got a try again since ce_peeraddr will still be zero. + * Given one of {ce_peeraddr,ce_name}, find the other one. + * It returns 1 for "success" and 0 for an uncorrectable failure. + * Note that "success" includes try again errors. You can tell that you + * got a "try again" since {ce_peeraddr,ce_name} will still be zero. */ static int findhostaddr( @@ -388,31 +446,80 @@ findhostaddr( ) { struct hostent *hp; + struct in_addr in; checkparent(); /* make sure our guy is still running */ - hp = gethostbyname(entry->ce_name); + if (entry->ce_name && entry->ce_peeraddr) { + /* HMS: Squawk? */ + msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined..."); + return 1; + } + + if (!entry->ce_name && !entry->ce_peeraddr) { + msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!"); + return 0; + } + + if (entry->ce_name) { +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, "findhostaddr: Resolving <%s>", + entry->ce_name); +#endif /* DEBUG */ + hp = gethostbyname(entry->ce_name); + } else { +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, "findhostaddr: Resolving %x>", + entry->ce_peeraddr); +#endif + in.s_addr = entry->ce_peeraddr; + hp = gethostbyaddr((const char *)&in, + sizeof entry->ce_peeraddr, + AF_INET); + } if (hp == NULL) { -#ifndef NODNS /* * If the resolver is in use, see if the failure is * temporary. If so, return success. */ if (h_errno == TRY_AGAIN) return (1); -#endif return (0); } - /* - * 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_name) { +#ifdef DEBUG + 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 = emalloc(s); + strcpy(cp, hp->h_name); + entry->ce_name = cp; + } + return (1); } @@ -460,7 +567,7 @@ openntp(void) #endif /* O_NONBLOCK */ #else /* SYS_WINNT */ { - int on=1; + int on = 1; if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) { msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); exit(1); /* Windows NT - set socket in non-blocking mode */ @@ -470,7 +577,7 @@ openntp(void) if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { - msyslog(LOG_ERR, "connect() failed: %m"); + msyslog(LOG_ERR, "openntp: connect() failed: %m"); exit(1); } } @@ -531,6 +638,11 @@ request( reqpkt.request = REQ_CONFIG; /* configure a new peer */ reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */ reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer)); + /* Make sure mbz_itemsize <= sizeof reqpkt.data */ + if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) { + msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!"); + exit(1); + } memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer)); reqpkt.keyid = htonl(req_keyid); @@ -552,7 +664,7 @@ request( } #else /* In the NT world, documentation seems to indicate that there - * exist _write and _read routines that can be used to so blocking + * exist _write and _read routines that can be used to do blocking * I/O on sockets. Problem is these routines require a socket * handle obtained through the _open_osf_handle C run-time API * of which there is no explanation in the documentation. We need @@ -603,8 +715,8 @@ request( } else if (n == 0) { - if(debug) - msyslog(LOG_DEBUG, "select() returned 0."); + if (debug) + msyslog(LOG_INFO, "select() returned 0."); return 0; } @@ -814,7 +926,7 @@ readconf( register int i; char *token[NUMTOK]; u_long intval[NUMTOK]; - int flags; + u_int flags; char buf[MAXLINESIZE]; char *bp; @@ -830,7 +942,7 @@ readconf( } } - for (i = 1; i < NUMTOK; i++) { + for (i = 1; i < NUMTOK - 1; i++) { if (!atouint(token[i], &intval[i])) { msyslog(LOG_ERR, "format error for integer token `%s', file `%s', quitting", @@ -868,7 +980,7 @@ readconf( } if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER | - FLAG_NOSELECT | FLAG_BURST | FLAG_SKEY)) + FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY)) != 0) { msyslog(LOG_ERR, "invalid flags (%ld) in file %s", intval[TOK_FLAGS], name); @@ -884,6 +996,8 @@ readconf( flags |= CONF_FLAG_NOSELECT; if (intval[TOK_FLAGS] & FLAG_BURST) flags |= CONF_FLAG_BURST; + if (intval[TOK_FLAGS] & FLAG_IBURST) + flags |= CONF_FLAG_IBURST; if (intval[TOK_FLAGS] & FLAG_SKEY) flags |= CONF_FLAG_SKEY; @@ -893,7 +1007,7 @@ readconf( addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE], (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL], (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL], - intval[TOK_KEYID]); + intval[TOK_KEYID], token[TOK_KEYSTR]); } } @@ -909,16 +1023,12 @@ doconfigure( register struct conf_entry *ce; register struct conf_entry *ceremove; -#ifdef DEBUG - if (debug > 1) - msyslog(LOG_INFO, "doconfigure(%d)", dores); -#endif - ce = confentries; while (ce != NULL) { #ifdef DEBUG if (debug > 1) - msyslog(LOG_INFO, "doconfigure: <%s> has peeraddr %#x", + msyslog(LOG_INFO, + "doconfigure: <%s> has peeraddr %#x", ce->ce_name, ce->ce_peeraddr); #endif if (dores && ce->ce_peeraddr == 0) { @@ -931,28 +1041,10 @@ doconfigure( removeentry(ceremove); continue; } -#ifdef DEBUG - if (debug > 1) { - msyslog(LOG_INFO, - "doconfigure:findhostaddr() worked"); - } -#endif } if (ce->ce_peeraddr != 0) { -#ifdef DEBUG - if (debug > 1) { - msyslog(LOG_INFO, - "doconfigure: calling request()"); - } -#endif if (request(&ce->ce_config)) { -#ifdef DEBUG - if (debug > 1) { - msyslog(LOG_INFO, - "doconfigure: request() OK, removing this entry"); - } -#endif ceremove = ce; ce = ceremove->ce_next; removeentry(ceremove); @@ -961,7 +1053,7 @@ doconfigure( #ifdef DEBUG if (debug > 1) { msyslog(LOG_INFO, - "doconfigure: request() FAILED, maybe next time."); + "doconfigure: request() FAILED, maybe next time."); } #endif } diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c index e209d6d..23c0cb7 100644 --- a/contrib/ntp/ntpd/ntp_io.c +++ b/contrib/ntp/ntpd/ntp_io.c @@ -7,15 +7,19 @@ # include <config.h> #endif +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_io.h" +#include "iosignal.h" +#include "ntp_refclock.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + #include <stdio.h> #include <signal.h> -#include <sys/types.h> #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> #endif /* HAVE_SYS_PARAM_H */ -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif @@ -37,14 +41,6 @@ # include <ifaddrs.h> #endif -#include "ntp_machine.h" -#include "ntpd.h" -#include "ntp_io.h" -#include "iosignal.h" -#include "ntp_refclock.h" -#include "ntp_if.h" -#include "ntp_stdlib.h" - #if defined(VMS) /* most likely UCX-specific */ #include <UCX$INETDEF.H> @@ -116,10 +112,10 @@ u_long io_timereset; /* time counters were reset */ /* * Interface stuff */ -struct interface *any_interface; /* pointer to default interface */ -struct interface *loopback_interface; /* point to loopback interface */ -static struct interface inter_list[MAXINTERFACES]; -static int ninterfaces; +struct interface *any_interface; /* default interface */ +struct interface *loopback_interface; /* loopback interface */ +struct interface inter_list[MAXINTERFACES]; +int ninterfaces; #ifdef REFCLOCK /* @@ -241,6 +237,7 @@ create_sockets( 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 @@ -274,46 +271,32 @@ create_sockets( if ((ifap->ifa_flags & IFF_UP) == 0) continue; - if (ifap->ifa_flags & IFF_LOOPBACK) - { + if (ifap->ifa_flags & IFF_LOOPBACK) { sin = (struct sockaddr_in *)ifap->ifa_addr; if (ntohl(sin->sin_addr.s_addr) != 0x7f000001) - { continue; - } } - inter_list[i].flags = 0; if (ifap->ifa_flags & IFF_BROADCAST) - inter_list[i].flags |= INT_BROADCAST; - - (void)strcpy(inter_list[i].name, ifap->ifa_name); - + 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) - { + 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) - { + 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)) - { + if (ifap->ifa_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) { inter_list[i].mask.sin_addr.s_addr = 0xffffffff; - } - else - { + } else { sin = (struct sockaddr_in *)ifap->ifa_netmask; inter_list[i].mask = *sin; } @@ -444,7 +427,7 @@ create_sockets( continue; } # endif /* SYS_WINNT */ - memcpy(&ifreq, ifr, sizeof(ifreq)); + ifreq = *ifr; inter_list[i].flags = 0; /* is it broadcast capable? */ # ifndef SYS_WINNT @@ -614,9 +597,8 @@ create_sockets( maxactivefd = 0; FD_ZERO(&activefds); for (i = 0; i < ninterfaces; i++) { - inter_list[i].fd = - open_socket(&inter_list[i].sin, - inter_list[i].flags & INT_BROADCAST, 0); + inter_list[i].fd = open_socket(&inter_list[i].sin, + inter_list[i].flags & INT_BROADCAST, 0); } /* @@ -653,12 +635,10 @@ create_sockets( */ resmask.sin_addr.s_addr = ~ (u_int32)0; for (i = 1; i < ninterfaces; i++) - hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, - RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); - - any_interface = &inter_list[0]; + hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, + RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); #ifdef DEBUG - if (debug > 2) { + if (debug > 1) { printf("create_sockets: ninterfaces=%d\n", ninterfaces); for (i = 0; i < ninterfaces; i++) { printf("interface %d: fd=%d, bfd=%d, name=%.8s, flags=0x%x\n", @@ -694,17 +674,19 @@ io_setbclient(void) { int i; - for (i = 1; i < ninterfaces; i++) - { + for (i = 1; i < ninterfaces; i++) { if (!(inter_list[i].flags & INT_BROADCAST)) - continue; + continue; + if (inter_list[i].flags & INT_BCASTOPEN) - continue; + continue; + #ifdef SYS_SOLARIS inter_list[i].bcast.sin_addr.s_addr = htonl(INADDR_ANY); #endif #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].bfd = open_socket(&inter_list[i].bcast, + INT_BROADCAST, 1); inter_list[i].flags |= INT_BCASTOPEN; #endif } @@ -728,50 +710,47 @@ io_multicast_add( struct sockaddr_in *sinp; iaddr.s_addr = addr; - - if (!IN_CLASSD(haddr)) - { + if (!IN_CLASSD(haddr)) { msyslog(LOG_ERR, - "cannot add multicast address %s as it is not class D", + "multicast address %s not class D", inet_ntoa(iaddr)); return; } - - for (i = 0; i < ninterfaces; i++) - { + for (i = 0; i < ninterfaces; i++) { /* Already have this address */ - if (inter_list[i].sin.sin_addr.s_addr == addr) return; + if (inter_list[i].sin.sin_addr.s_addr == addr) + 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) break; + inter_list[i].flags == 0) + 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); - /* Try opening a socket for the specified class D address */ - /* This works under SunOS 4.x, but not OSF1 .. :-( */ - if (s < 0) - { + 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 - { + 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)); + sizeof(inter_list[i].name)); inter_list[i].mask.sin_addr.s_addr = htonl(~(u_int32)0); } @@ -781,19 +760,21 @@ io_multicast_add( 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, + (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)); + 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; + if (i >= ninterfaces) + ninterfaces = i+1; #else /* MCAST */ struct in_addr iaddr; iaddr.s_addr = addr; - msyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support", - inet_ntoa(iaddr)); + msyslog(LOG_ERR, + "cannot add multicast address %s as no MCAST support", + inet_ntoa(iaddr)); #endif /* MCAST */ } @@ -886,8 +867,11 @@ open_socket( int turn_off_reuse ) { - int fd, tos; + int 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 */ /* create a datagram (UDP) socket */ if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) @@ -1071,12 +1055,11 @@ close_socket( (void) closesocket(fd); 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; + if (FD_ISSET(i, &activefds)) + newmax = i; maxactivefd = newmax; } } @@ -1096,45 +1079,16 @@ close_file( (void) close(fd); 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; + if (FD_ISSET(i, &activefds)) + newmax = i; maxactivefd = newmax; } } -/* - * findbcastinter - find broadcast interface corresponding to address - */ -struct interface * -findbcastinter( - struct sockaddr_in *addr - ) -{ -#if defined(SIOCGIFCONF) || defined(SYS_WINNT) - register int i; - register u_int32 netnum; - - netnum = NSRCADR(addr); - for (i = 1; i < ninterfaces; i++) - { - if (!(inter_list[i].flags & INT_BROADCAST)) - continue; - if (NSRCADR(&inter_list[i].bcast) == netnum) - return &inter_list[i]; - if ((NSRCADR(&inter_list[i].sin) & NSRCADR(&inter_list[i].mask)) - == (netnum & NSRCADR(&inter_list[i].mask))) - return &inter_list[i]; - } -#endif /* SIOCGIFCONF */ - return any_interface; -} - - /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ /* * sendpkt - send a packet to the specified destination. Maintain a @@ -1172,13 +1126,6 @@ sendpkt( #else #define badaddrs ((struct cache *)0) /* Only used in empty loops! */ #endif - - /* - * check if the source address is a multicast address - replace - * interface with any-interface if so. - */ - if (IN_MULTICAST(ntohl(inter->sin.sin_addr.s_addr))) - inter = any_interface; #ifdef DEBUG if (debug > 1) printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n", @@ -1188,18 +1135,20 @@ sendpkt( #endif #ifdef MCAST - /* for the moment we use the bcast option to set multicast ttl */ - if (ttl >= 0 && ttl != inter->last_ttl) - { + /* + * for the moment we use the bcast option to set multicast ttl + */ + if (ttl > 0 && ttl != inter->last_ttl) { char mttl = ttl; - /* set the multicast ttl for outgoing packets */ + /* + * set the multicast ttl for outgoing packets + */ if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, - &mttl, sizeof(mttl)) == -1) - { + &mttl, sizeof(mttl)) == -1) msyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m"); - } - else inter->last_ttl = ttl; + else + inter->last_ttl = ttl; } #endif /* MCAST */ @@ -1212,7 +1161,7 @@ sendpkt( err = io_completion_port_sendto(inter, pkt, len, dest); if (err != ERROR_SUCCESS) #else - cc = sendto(inter->fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + cc = sendto(inter->fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest, sizeof(struct sockaddr_in)); if (cc == -1) #endif @@ -1480,7 +1429,8 @@ input_handler( } else if (rb->recv_length < 0) { - msyslog(LOG_ERR, "recvfrom() fd=%d: %m", fd); + msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", + inet_ntoa(rb->recv_srcadr.sin_addr), fd); #ifdef DEBUG if (debug) printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); @@ -1490,8 +1440,8 @@ input_handler( } #ifdef DEBUG if (debug > 2) - printf("input_handler: fd=%d length %d from %08lx %s\n", - fd, rb->recv_length, + 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)); @@ -1580,27 +1530,85 @@ input_handler( #endif /* - * findinterface - utility used by other modules to find an interface - * given an address. + * findinterface - find interface corresponding to address */ struct interface * findinterface( struct sockaddr_in *addr ) { - register int i; - register u_int32 saddr; + int s, rtn, i; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + u_int32 xaddr; /* - * Just match the address portion. + * 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 = addr->sin_addr.s_addr; - for (i = 0; i < ninterfaces; i++) - { - if (inter_list[i].sin.sin_addr.s_addr == saddr) - return &inter_list[i]; + 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)); + if (rtn < 0) + return (any_interface); + + rtn = getsockname(s, (struct sockaddr *)&saddr, &saddrlen); + if (rtn < 0) + return (any_interface); + + close(s); + xaddr = NSRCADR(&saddr); + for (i = 1; i < ninterfaces; i++) { + + /* + * We match the unicast address only. + */ + if (NSRCADR(&inter_list[i].sin) == xaddr) + return (&inter_list[i]); } - return (struct interface *)0; + return (any_interface); +} + + +/* + * findbcastinter - find broadcast interface corresponding to address + */ +struct interface * +findbcastinter( + struct sockaddr_in *addr + ) +{ +#if defined(SIOCGIFCONF) || defined(SYS_WINNT) + register int i; + register u_int32 xaddr; + + xaddr = NSRCADR(addr); + for (i = 1; i < ninterfaces; i++) { + + /* + * We match only those interfaces marked as + * broadcastable and either the explicit broadcast + * address or the network portion of the IP address. + * Sloppy. + */ + 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]); + } +#endif /* SIOCGIFCONF */ + return (any_interface); } diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c index 15b625d..c8a86cf 100644 --- a/contrib/ntp/ntpd/ntp_loopfilter.c +++ b/contrib/ntp/ntpd/ntp_loopfilter.c @@ -6,19 +6,17 @@ # include <config.h> #endif +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + #include <stdio.h> #include <ctype.h> -#include <sys/time.h> - #include <signal.h> #include <setjmp.h> -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_stdlib.h" - #if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ #include "ntp_refclock.h" #endif /* VMS */ @@ -36,8 +34,9 @@ */ #define CLOCK_MAX .128 /* default max offset (s) */ #define CLOCK_PANIC 1000. /* default panic offset (s) */ -#define CLOCK_MAXSTAB 2e-6 /* max frequency stability */ +#define CLOCK_MAXSTAB 2e-6 /* max frequency stability (s/s) */ #define CLOCK_MAXERR 1e-2 /* max phase jitter (s) */ +#define CLOCK_PHI 15e-6 /* max frequency error (s/s) */ #define SHIFT_PLL 4 /* PLL loop gain (shift) */ #define CLOCK_AVG 4. /* FLL loop gain */ #define CLOCK_MINSEC 256. /* min FLL update interval (s) */ @@ -51,7 +50,26 @@ /* * Clock discipline state machine. This is used to control the * synchronization behavior during initialization and following a - * timewarp. + * timewarp. + * + * State < max > max Comments + * ==================================================== + * NSET FREQ FREQ no ntp.drift + * + * FSET TSET if (allow) TSET, ntp.drift + * else FREQ + * + * TSET SYNC FREQ time set + * + * FREQ SYNC if (mu < 900) FREQ calculate frequency + * else if (allow) TSET + * else FREQ + * + * SYNC SYNC if (mu < 900) SYNC normal state + * else SPIK + * + * SPIK SYNC if (allow) TSET spike detector + * else FREQ */ #define S_NSET 0 /* clock never set */ #define S_FSET 1 /* frequency set from the drift file */ @@ -72,10 +90,10 @@ * support is used as described above; if false, the kernel is bypassed * entirely and the daemon PLL used instead. * - * Each update to a prefer peer sets pps_update if it survives the + * Each update to a prefer peer sets pps_stratum if it survives the * intersection algorithm and its time is within range. The PPS time * discipline is enabled (STA_PPSTIME bit set in the status word) when - * pps_update is true and the PPS frequency discipline is enabled. If + * pps_stratum is true and the PPS frequency discipline is enabled. If * the PPS time discipline is enabled and the kernel reports a PPS * signal is present, the pps_control variable is set to the current * time. If the current time is later than pps_control by PPS_MAXAGE @@ -91,18 +109,27 @@ #define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */ /* + * 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_phi = CLOCK_PHI; /* dispersion rate (s/s) */ +double clock_minstep = CLOCK_MINSTEP; /* step timeout (s) */ +double allan_xpt = CLOCK_ALLAN; /* minimum Allan intercept (s) */ + +/* * Program variables */ static double clock_offset; /* clock offset adjustment (s) */ -double drift_comp; /* clock frequency (ppm) */ -double clock_stability; /* clock stability (ppm) */ -double clock_max = CLOCK_MAX; /* max offset allowed before step (s) */ -static double clock_panic = CLOCK_PANIC; /* max offset allowed before panic */ +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)); /* state transition function */ +static void rstclock P((int, double, double)); /* transition function */ #ifdef KERNEL_PLL -int pll_status; /* status bits for kernel pll */ +struct timex ntv; /* kernel API parameters */ +int pll_status; /* status bits for kernel pll */ +int pll_nano; /* nanosecond kernel switch */ #endif /* KERNEL_PLL */ /* @@ -111,32 +138,38 @@ int pll_status; /* status bits for kernel pll */ int ntp_enable; /* clock discipline enabled */ int pll_control; /* kernel support available */ int kern_enable; /* kernel support enabled */ +int pps_enable; /* kernel PPS discipline enabled */ int ext_enable; /* external clock enabled */ -int pps_update; /* pps update valid */ -int allow_set_backward = TRUE; /* step corrections allowed */ -int correct_any = FALSE; /* corrections > 1000 s allowed */ - -#ifdef STA_NANO -int pll_nano; /* nanosecond kernel switch */ -#endif /* STA_NANO */ +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_poll; /* log2 of system poll interval */ +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 */ u_long last_time; /* time of last clock update (s) */ double last_offset; /* last clock offset (s) */ -double allan_xpt; /* Allan intercept (s) */ -double sys_error; /* system standard error (s) */ +double sys_jitter; /* system RMS jitter (s) */ + +/* + * Huff-n'-puff filter variables + */ +static double *sys_huffpuff; /* huff-n'-puff filter */ +static int sys_hufflen; /* huff-n'-puff filter stages */ +static int sys_huffptr; /* huff-n'-puff filter pointer */ +static double sys_mindly; /* huff-n'-puff filter min delay */ #if defined(KERNEL_PLL) /* Emacs cc-mode goes nuts if we split the next line... */ #define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \ MOD_STATUS | MOD_TIMECONST) -static void pll_trap P((int)); /* configuration trap */ #ifdef SIGSYS +static void pll_trap P((int)); /* configuration trap */ static struct sigaction sigsys; /* current sigaction status */ static struct sigaction newsigsys; /* new sigaction status */ static sigjmp_buf env; /* environment var. for pll_trap() */ @@ -153,7 +186,7 @@ init_loopfilter(void) * Initialize state variables. Initially, we expect no drift * file, so set the state to S_NSET. */ - rstclock(S_NSET); + rstclock(S_NSET, current_time, 0); } /* @@ -175,30 +208,70 @@ local_clock( double dtemp, etemp; /* double temps */ int retval; /* return value */ -#if defined(KERNEL_PLL) - struct timex ntv; /* kernel interface structure */ -#endif /* KERNEL_PLL */ - + /* + * If the loop is opened, monitor and record the offsets + * anyway in order to determine the open-loop response. + */ #ifdef DEBUG if (debug) printf( - "local_clock: offset %.6f jitter %.6f state %d\n", - fp_offset, SQRT(epsil), state); + "local_clock: assocID %d off %.6f jit %.6f sta %d\n", + peer->associd, fp_offset, SQRT(epsil), state); #endif - if (!ntp_enable) - return(0); + if (!ntp_enable) { + record_loop_stats(fp_offset, drift_comp, SQRT(epsil), + clock_stability, sys_poll); + return (0); + } /* - * If the clock is way off, don't tempt fate by correcting it. + * If the clock is way off, panic is declared. The clock_panic + * defaults to 1000 s; if set to zero, the panic will never + * occur. The allow_panic defaults to FALSE, so the first panic + * will exit. It can be set TRUE by a command line option, in + * which case the clock will be set anyway and time marches on. + * But, allow_panic will be set it FALSE when the update is + * within the step range; so, subsequent panics will exit. */ -#ifndef SYS_WINNT - if (fabs(fp_offset) >= clock_panic && !correct_any) { + if (fabs(fp_offset) > clock_panic && clock_panic > 0 && + !allow_panic) { msyslog(LOG_ERR, - "time error %.0f over %d seconds; set clock manually", - fp_offset, (int)clock_panic); + "time correction of %.0f seconds exceeds sanity limit (%.0f); set clock manually to the correct UTC time.", + fp_offset, clock_panic); return (-1); } -#endif + + /* + * If simulating ntpdate, set the clock directly, rather than + * using the discipline. The clock_max defines the step + * threshold, above which the clock will be stepped instead of + * slewed. The value defaults to 128 ms, but can be set to even + * unreasonable values. If set to zero, the clock will never be + * stepped. + * + * Note that if ntpdate is active, the terminal does not detach, + * so the termination comments print directly to the console. + */ + if (mode_ntpdate) { + if (allow_step && fabs(fp_offset) > clock_max && + clock_max > 0) { + step_systime(fp_offset); + NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) + msyslog(LOG_NOTICE, "time reset %.6f s", + fp_offset); + printf("ntpd: time reset %.6fs\n", fp_offset); + } else { + adj_systime(fp_offset); + NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) + msyslog(LOG_NOTICE, "time slew %.6f s", + fp_offset); + printf("ntpd: time slew %.6fs\n", fp_offset); + } + record_loop_stats(fp_offset, drift_comp, SQRT(epsil), + clock_stability, sys_poll); + exit (0); + } + /* * If the clock has never been set, set it and initialize the * discipline parameters. We then switch to frequency mode to @@ -210,29 +283,60 @@ local_clock( step_systime(fp_offset); NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) msyslog(LOG_NOTICE, "time set %.6f s", fp_offset); - rstclock(S_TSET); - rstclock(S_FREQ); + rstclock(S_FREQ, peer->epoch, fp_offset); return (1); } /* * Update the jitter estimate. */ - oerror = sys_error; - dtemp = SQUARE(sys_error); - sys_error = SQRT(dtemp + (epsil - dtemp) / CLOCK_AVG); + oerror = sys_jitter; + dtemp = SQUARE(sys_jitter); + sys_jitter = SQRT(dtemp + (epsil - dtemp) / CLOCK_AVG); + + /* + * The huff-n'-puff filter finds the lowest delay in the recent + * interval. This is used to correct the offset by one-half the + * difference between the sample delay and minimum delay. This + * is most effective if the delays are highly assymetric and + * clockhopping is avoided and the clock frequency wander is + * relatively small. + */ + if (sys_huffpuff != NULL) { + if (peer->delay < sys_huffpuff[sys_huffptr]) + sys_huffpuff[sys_huffptr] = peer->delay; + if (peer->delay < sys_mindly) + sys_mindly = peer->delay; + if (fp_offset > 0) + dtemp = -(peer->delay - sys_mindly) / 2; + else + dtemp = (peer->delay - sys_mindly) / 2; + fp_offset += dtemp; +#ifdef DEBUG + if (debug) + printf( + "local_clock: size %d mindly %.6f huffpuff %.6f\n", + sys_hufflen, sys_mindly, dtemp); +#endif + } /* * Clock state machine transition function. This is where the * action is and defines how the system reacts to large phase * and frequency errors. There are two main regimes: when the - * phase error exceeds the maximum allowed for ordinary tracking - * and otherwise when it does not. + * offset exceeds the step threshold and when it does not. + * However, if the step threshold is set to zero, a step will + * never occur. See the instruction manual for the details how + * these actions interact with the command line options. */ retval = 0; + if (sys_poll > peer->maxpoll) + sys_poll = peer->maxpoll; + else if (sys_poll < peer->minpoll) + sys_poll = peer->minpoll; clock_frequency = flladj = plladj = 0; - mu = current_time - last_time; - if (fabs(fp_offset) > clock_max) { + mu = peer->epoch - last_time; + if (fabs(fp_offset) > clock_max && clock_max > 0) { switch (state) { /* @@ -243,32 +347,29 @@ local_clock( * to S_FREQ state. */ case S_TSET: - rstclock(S_FREQ); - last_offset = clock_offset = fp_offset; - return (0); + state = S_FREQ; + break; /* * In S_SYNC state we ignore outlyers. At the first - * outlyer after CLOCK_MINSTEP (900 s), switch to S_SPIK + * outlyer after the stepout threshold, switch to S_SPIK * state. */ case S_SYNC: - if (mu < CLOCK_MINSTEP) + if (mu < clock_minstep) return (0); - rstclock(S_SPIK); + state = S_SPIK; return (0); /* * In S_FREQ state we ignore outlyers. At the first - * outlyer after CLOCK_MINSTEP (900 s), compute the - * apparent phase and frequency correction. + * outlyer after 900 s, compute the apparent phase and + * frequency correction. */ case S_FREQ: - if (mu < CLOCK_MINSTEP) + if (mu < clock_minstep) return (0); - clock_frequency = (fp_offset - clock_offset) / - mu; - /* fall through to default */ + /* fall through to S_SPIK */ /* * In S_SPIK state a large correction is necessary. @@ -286,19 +387,19 @@ local_clock( * reset or shaken, but never stirred. */ default: - if (allow_set_backward | correct_any) { + if (allow_step) { step_systime(fp_offset); NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) msyslog(LOG_NOTICE, "time reset %.6f s", fp_offset); - rstclock(S_TSET); + 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); - last_offset = clock_offset = fp_offset; + rstclock(S_FREQ, peer->epoch, + fp_offset); } break; } @@ -306,28 +407,25 @@ local_clock( switch (state) { /* - * If this is the first update, initialize the - * discipline parameters and pretend we had just set the - * clock. We don't want to step the clock unless we have - * to. + * In S_FSET state this is the first update. Adjust the + * phase, but don't adjust the frequency until the next + * update. */ case S_FSET: - rstclock(S_TSET); - last_offset = clock_offset = fp_offset; - return (0); + rstclock(S_TSET, peer->epoch, fp_offset); + break; /* - * In S_FREQ state we ignore updates until CLOCK_MINSTEP - * (900 s). After that, correct the phase and frequency - * and switch to S_SYNC state. + * In S_FREQ state ignore updates until the stepout + * threshold. After that, correct the phase and + * frequency and switch to S_SYNC state. */ case S_FREQ: - if (mu < CLOCK_MINSTEP) + if (mu < clock_minstep) return (0); clock_frequency = (fp_offset - clock_offset) / mu; - clock_offset = fp_offset; - rstclock(S_SYNC); + rstclock(S_SYNC, peer->epoch, fp_offset); break; /* @@ -337,7 +435,7 @@ local_clock( */ case S_TSET: case S_SPIK: - rstclock(S_SYNC); + state = S_SYNC; /* fall through to default */ /* @@ -349,14 +447,17 @@ local_clock( * and ignore it. */ default: + allow_panic = TRUE; if (fabs(fp_offset - last_offset) > CLOCK_SGATE * oerror && mu < ULOGTOD(sys_poll + 1)) { #ifdef DEBUG if (debug) printf( - "local_clock: popcorn %.6f %.6f\n", - fp_offset, last_offset); + "local_clock: popcorn %.6f %.6f\n", + fabs(fp_offset - + last_offset), CLOCK_SGATE * + oerror); #endif last_offset = fp_offset; return (0); @@ -366,29 +467,32 @@ local_clock( * Compute the FLL and PLL frequency adjustments * conditioned on intricate weighting factors. * For the FLL, the averaging interval is - * clamped not to decrease below the Allan - * intercept and the gain is decreased from - * unity for mu above CLOCK_MINSEC (1024 s) to - * zero below CLOCK_MINSEC (256 s). For the PLL, - * the averaging interval is clamped not to - * exceed the sustem poll interval. These - * measures insure stability of the clock - * discipline even when the rules of fair - * engagement are broken. + * clamped to a minimum of 1024 s and the gain + * is decreased from unity for mu above 1024 s + * to zero below 256 s. For the PLL, the + * averaging interval is clamped not to exceed + * the sustem poll interval. No gain factor is + * necessary, since the frequency steering above + * 1024 s 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. */ dtemp = max(mu, allan_xpt); etemp = min(max(0, mu - CLOCK_MINSEC) / - CLOCK_ALLAN, 1.); + allan_xpt, 1.); flladj = fp_offset * etemp / (dtemp * CLOCK_AVG); dtemp = ULOGTOD(SHIFT_PLL + 2 + sys_poll); etemp = min(mu, ULOGTOD(sys_poll)); plladj = fp_offset * etemp / (dtemp * dtemp); - clock_offset = fp_offset; + last_time = peer->epoch; + last_offset = clock_offset = fp_offset; break; } } +#if defined(KERNEL_PLL) /* * This code segment works when clock adjustments are made using * precision time kernel support and the ntp_adjtime() system @@ -399,7 +503,6 @@ local_clock( * modifications provide a true microsecond clock and nanosecond * clock, respectively. */ -#if defined(KERNEL_PLL) if (pll_control && kern_enable) { /* @@ -413,7 +516,7 @@ local_clock( * frequency offsets for jitter and stability values and * to update the drift file. */ - memset((char *)&ntv, 0, sizeof ntv); + memset(&ntv, 0, sizeof(ntv)); if (ext_enable) { ntv.modes = MOD_STATUS; } else { @@ -422,25 +525,21 @@ local_clock( dtemp = -.5; else dtemp = .5; -#ifdef STA_NANO - if (pll_nano) + if (pll_nano) { ntv.offset = (int32)(clock_offset * 1e9 + dtemp); - else -#endif /* STA_NANO */ + ntv.constant = sys_poll; + } else { ntv.offset = (int32)(clock_offset * 1e6 + dtemp); + ntv.constant = sys_poll - 4; + } if (clock_frequency != 0) { ntv.modes |= MOD_FREQUENCY; ntv.freq = (int32)((clock_frequency + drift_comp) * 65536e6); } -#ifdef STA_NANO - ntv.constant = sys_poll; -#else - ntv.constant = sys_poll - 4; -#endif /* STA_NANO */ - ntv.esterror = (u_int32)(sys_error * 1e6); + ntv.esterror = (u_int32)(sys_jitter * 1e6); ntv.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdispersion) * 1e6); ntv.status = STA_PLL; @@ -467,63 +566,53 @@ local_clock( */ if (sys_poll > NTP_MAXDPOLL) ntv.status |= STA_FLL; - } - /* - * Wiggle the PPS bits according to the health of the - * prefer peer. - */ - if (pll_status & STA_PPSSIGNAL) - ntv.status |= STA_PPSFREQ; - if (pll_status & STA_PPSFREQ && pps_update) - ntv.status |= STA_PPSTIME; + /* + * If the PPS signal is up and enabled, light + * the frequency bit. If the PPS driver is + * working, light the phase bit as well. If not, + * douse the lights, since somebody else may + * have left the switch on. + */ + if (pps_enable && pll_status & STA_PPSSIGNAL) { + ntv.status |= STA_PPSFREQ; + if (pps_stratum < STRATUM_UNSPEC) + ntv.status |= STA_PPSTIME; + } else { + ntv.status &= ~(STA_PPSFREQ | + STA_PPSTIME); + } + } /* - * Update the offset and frequency from the kernel - * variables. + * Pass the stuff to the kernel. If it squeals, turn off + * the pigs. In any case, fetch the kernel offset and + * frequency and pretend we did it here. */ if (ntp_adjtime(&ntv) == TIME_ERROR) { if (ntv.status != pll_status) msyslog(LOG_ERR, - "kernel pll status change %x", + "kernel time discipline status change %x", ntv.status); + ntv.status &= ~(STA_PPSFREQ | STA_PPSTIME); } pll_status = ntv.status; -#ifdef STA_NANO if (pll_nano) clock_offset = ntv.offset / 1e9; else -#endif /* STA_NANO */ clock_offset = ntv.offset / 1e6; -#ifdef STA_NANO - sys_poll = ntv.constant; -#else - sys_poll = ntv.constant + 4; -#endif /* STA_NANO */ clock_frequency = ntv.freq / 65536e6 - drift_comp; flladj = plladj = 0; /* - * If the kernel pps discipline is working, monitor its - * performance. + * If the kernel PPS is lit, monitor its performance. */ if (ntv.status & STA_PPSTIME) { - if (!pps_control) - NLOG(NLOG_SYSEVENT)msyslog(LOG_INFO, - "pps sync enabled"); pps_control = current_time; -#ifdef STA_NANO if (pll_nano) - record_peer_stats( - &loopback_interface->sin, - ctlsysstatus(), ntv.offset / 1e9, - 0., ntv.jitter / 1e9, 0.); + sys_jitter = ntv.jitter / 1e9; else -#endif /* STA_NANO */ - record_peer_stats( - &loopback_interface->sin, - ctlsysstatus(), ntv.offset / 1e6, - 0., ntv.jitter / 1e6, 0.); + sys_jitter = ntv.jitter / 1e6; } } #endif /* KERNEL_PLL */ @@ -537,21 +626,26 @@ local_clock( */ etemp = clock_frequency + flladj + plladj; drift_comp += etemp; - if (drift_comp > sys_maxfreq) - drift_comp = sys_maxfreq; - else if (drift_comp <= -sys_maxfreq) - drift_comp = -sys_maxfreq; + if (drift_comp > NTP_MAXFREQ) + drift_comp = NTP_MAXFREQ; + else if (drift_comp <= -NTP_MAXFREQ) + drift_comp = -NTP_MAXFREQ; dtemp = SQUARE(clock_stability); etemp = SQUARE(etemp) - dtemp; clock_stability = SQRT(dtemp + etemp / CLOCK_AVG); - allan_xpt = max(CLOCK_ALLAN, clock_stability * CLOCK_ADF); /* - * In SYNC state, adjust the poll interval. + * In SYNC state, adjust the poll interval. The trick here is to + * compare the apparent frequency change induced by the system + * jitter over the poll interval, or fritter, to the frequency + * stability. If the fritter is greater than the stability, + * phase noise predominates and the averaging interval is + * increased; otherwise, it is decreased. A bit of hysteresis + * helps calm the dance. Works best using burst mode. */ if (state == S_SYNC) { - if (clock_stability < CLOCK_MAXSTAB && - fabs(clock_offset) < CLOCK_PGATE * sys_error) { + if (sys_jitter / ULOGTOD(sys_poll) > clock_stability && + fabs(clock_offset) < CLOCK_PGATE * sys_jitter) { tc_counter += sys_poll; if (tc_counter > CLOCK_LIMIT) { tc_counter = CLOCK_LIMIT; @@ -575,25 +669,17 @@ local_clock( /* * Update the system time variables. */ - last_time = current_time; - last_offset = clock_offset; - dtemp = peer->disp + SQRT(peer->variance + SQUARE(sys_error)); + dtemp = peer->disp + sys_jitter; if ((peer->flags & FLAG_REFCLOCK) == 0 && dtemp < MINDISPERSE) dtemp = MINDISPERSE; sys_rootdispersion = peer->rootdispersion + dtemp; - (void)record_loop_stats(); -#ifdef DEBUG - if (debug) - printf( - "local_clock: mu %.0f allan %.0f fadj %.3f fll %.3f pll %.3f\n", - mu, allan_xpt, clock_frequency * 1e6, flladj * 1e6, - plladj * 1e6); -#endif /* DEBUG */ + record_loop_stats(last_offset, drift_comp, sys_jitter, + clock_stability, sys_poll); #ifdef DEBUG if (debug) printf( - "local_clock: jitter %.6f freq %.3f stab %.3f poll %d count %d\n", - sys_error, drift_comp * 1e6, clock_stability * 1e6, + "local_clock: mu %.0f noi %.3f stb %.3f pol %d cnt %d\n", + mu, sys_jitter * 1e6 / mu, clock_stability * 1e6, sys_poll, tc_counter); #endif /* DEBUG */ return (retval); @@ -620,7 +706,7 @@ adj_host_clock( * maximum error and the local clock driver will pick it up and * pass to the common refclock routines. Very elegant. */ - sys_rootdispersion += CLOCK_PHI; + sys_rootdispersion += clock_phi; /* * Declare PPS kernel unsync if the pps signal has not been @@ -665,51 +751,35 @@ adj_host_clock( */ static void rstclock( - int trans /* new state */ + int trans, /* new state */ + double epoch, /* last time */ + double offset /* last offset */ ) { - correct_any = FALSE; + tc_counter = 0; + sys_poll = NTP_MINPOLL; state = trans; - switch (state) { - - /* - * Frequency mode. The clock has ben set, but the frequency has - * not yet been determined. Note that the Allan intercept is set - * insure the clock filter considers only the most recent - * measurements. - */ - case S_FREQ: - sys_poll = NTP_MINDPOLL; - allan_xpt = CLOCK_ALLAN; - last_time = current_time; - break; + last_time = epoch; + last_offset = clock_offset = offset; +} - /* - * Synchronized mode. Discipline the poll interval. - */ - case S_SYNC: - sys_poll = NTP_MINDPOLL; - allan_xpt = CLOCK_ALLAN; - tc_counter = 0; - break; - /* - * Don't do anything in S_SPIK state; just continue from S_SYNC - * state. - */ - case S_SPIK: - break; +/* + * huff-n'-puff filter + */ +void +huffpuff() +{ + int i; - /* - * S_NSET, S_FSET and S_TSET states. These transient states set - * the time reference for future frequency updates. - */ - default: - sys_poll = NTP_MINDPOLL; - allan_xpt = CLOCK_ALLAN; - last_time = current_time; - last_offset = clock_offset = 0; - break; + if (sys_huffpuff == NULL) + return; + sys_huffptr = (sys_huffptr + 1) % sys_hufflen; + sys_huffpuff[sys_huffptr] = 1e9; + sys_mindly = 1e9; + for (i = 0; i < sys_hufflen; i++) { + if (sys_huffpuff[i] < sys_mindly) + sys_mindly = sys_huffpuff[i]; } } @@ -723,111 +793,148 @@ loop_config( double freq ) { -#if defined(KERNEL_PLL) - struct timex ntv; -#endif /* KERNEL_PLL */ + int i; -#ifdef DEBUG - if (debug) - printf("loop_config: state %d freq %.3f\n", item, freq * - 1e6); -#endif switch (item) { - case LOOP_DRIFTINIT: - case LOOP_DRIFTCOMP: + case LOOP_DRIFTINIT: - /* - * The drift file is present and the initial frequency - * is available, so set the state to S_FSET - */ - rstclock(S_FSET); - drift_comp = freq; - if (drift_comp > sys_maxfreq) - drift_comp = sys_maxfreq; - if (drift_comp < -sys_maxfreq) - drift_comp = -sys_maxfreq; #ifdef KERNEL_PLL /* - * If the phase-lock code is implemented in the kernel, - * give the time_constant and saved frequency offset to - * the kernel. If not, no harm is done. Note the initial - * time constant is zero, but the first clock update - * will fix that. + * Assume the kernel supports the ntp_adjtime() syscall. + * If that syscall works, initialize the kernel + * variables. Otherwise, continue leaving no harm + * behind. While at it, ask to set nanosecond mode. If + * the kernel agrees, rejoice; othewise, it does only + * microseconds. */ - memset((char *)&ntv, 0, sizeof ntv); pll_control = 1; -#ifdef MOD_NANO - ntv.modes = MOD_NANO; -#endif /* MOD_NANO */ + memset(&ntv, 0, sizeof(ntv)); +#ifdef STA_NANO + ntv.modes = MOD_BITS | MOD_NANO; +#else + ntv.modes = MOD_BITS; +#endif /* STA_NANO */ + ntv.maxerror = MAXDISPERSE; + ntv.esterror = MAXDISPERSE; + ntv.status = STA_UNSYNC; #ifdef SIGSYS + /* + * Use sigsetjmp() to save state and then call + * ntp_adjtime(); if it fails, then siglongjmp() is used + * to return control + */ newsigsys.sa_handler = pll_trap; newsigsys.sa_flags = 0; if (sigaction(SIGSYS, &newsigsys, &sigsys)) { msyslog(LOG_ERR, "sigaction() fails to save SIGSYS trap: %m"); pll_control = 0; - return; } - - /* - * Use sigsetjmp() to save state and then call - * ntp_adjtime(); if it fails, then siglongjmp() is used - * to return control - */ if (sigsetjmp(env, 1) == 0) - (void)ntp_adjtime(&ntv); + ntp_adjtime(&ntv); if ((sigaction(SIGSYS, &sigsys, (struct sigaction *)NULL))) { msyslog(LOG_ERR, "sigaction() fails to restore SIGSYS trap: %m"); pll_control = 0; - return; } #else /* SIGSYS */ - if (ntp_adjtime(&ntv) < 0) { - msyslog(LOG_ERR, - "loop_config: ntp_adjtime() failed: %m"); - pll_control = 0; - } + ntp_adjtime(&ntv); #endif /* SIGSYS */ - - /* - * If the kernel support is available and enabled, - * initialize the parameters, but only if the external - * clock is not present. - */ - if (pll_control && kern_enable) { - msyslog(LOG_NOTICE, - "using kernel phase-lock loop %04x", - ntv.status); + pll_status = ntv.status; + if (pll_control) { #ifdef STA_NANO - if (ntv.status & STA_NANO) + if (pll_status & STA_NANO) pll_nano = 1; + if (pll_status & STA_CLK) + ext_enable = 1; #endif /* STA_NANO */ -#ifdef STA_CLK + msyslog(LOG_NOTICE, + "kernel time discipline status %04x", + pll_status); + } +#endif /* KERNEL_PLL */ + break; - if (ntv.status & STA_CLK) { - ext_enable = 1; - } else { - ntv.modes = MOD_BITS | MOD_FREQUENCY; + case LOOP_DRIFTCOMP: + + /* + * 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. + */ + 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; + +#ifdef KERNEL_PLL + /* + * Sanity check. If the kernel is enabled, load the + * frequency and light up the loop. If not, set the + * kernel frequency to zero and leave the loop dark. In + * either case set the time to zero to cancel any + * previous nonsense. + */ + if (pll_control) { + memset((char *)&ntv, 0, sizeof(ntv)); + ntv.modes = MOD_OFFSET | MOD_FREQUENCY; + if (kern_enable) { + ntv.modes |= MOD_STATUS; + ntv.status = STA_PLL; ntv.freq = (int32)(drift_comp * 65536e6); - ntv.maxerror = MAXDISPERSE; - ntv.esterror = MAXDISPERSE; - ntv.status = STA_UNSYNC | STA_PLL; - (void)ntp_adjtime(&ntv); } -#else - ntv.modes = MOD_BITS | MOD_FREQUENCY; - ntv.freq = (int32)(drift_comp * 65536e6); - ntv.maxerror = MAXDISPERSE; - ntv.esterror = MAXDISPERSE; - ntv.status = STA_UNSYNC | STA_PLL; (void)ntp_adjtime(&ntv); -#endif /* STA_CLK */ } #endif /* KERNEL_PLL */ + break; + + /* + * Special tinker variables for Ulrich Windl. Very dangerous. + */ + case LOOP_MAX: /* step threshold */ + clock_max = freq; + break; + + case LOOP_PANIC: /* panic exit threshold */ + clock_panic = freq; + break; + + case LOOP_PHI: /* dispersion rate */ + clock_phi = freq; + break; + + case LOOP_MINSTEP: /* watchdog bark */ + 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 = freq; + break; + + case LOOP_HUFFPUFF: /* huff-n'-puff filter length */ + if (freq < HUFFPUFF) + freq = HUFFPUFF; + sys_hufflen = (int)(freq / HUFFPUFF); + sys_huffpuff = (double *)emalloc(sizeof(double) * + sys_hufflen); + for (i = 0; i < sys_hufflen; i++) + sys_huffpuff[i] = 1e9; + sys_mindly = 1e9; + break; } } diff --git a/contrib/ntp/ntpd/ntp_monitor.c b/contrib/ntp/ntpd/ntp_monitor.c index 64dfb3e..8526aac 100644 --- a/contrib/ntp/ntpd/ntp_monitor.c +++ b/contrib/ntp/ntpd/ntp_monitor.c @@ -1,23 +1,22 @@ /* * ntp_monitor.c - monitor who is using the ntpd server */ + #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif -#include <stdio.h> -#include <sys/types.h> -#include <signal.h> -# ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -# endif -# include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_if.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <signal.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + /* * I'm still not sure I like what I've done here. It certainly consumes * memory like it is going out of style, and also may not be as low diff --git a/contrib/ntp/ntpd/ntp_peer.c b/contrib/ntp/ntpd/ntp_peer.c index 90646ab..b164181 100644 --- a/contrib/ntp/ntpd/ntp_peer.c +++ b/contrib/ntp/ntpd/ntp_peer.c @@ -10,6 +10,9 @@ #include "ntpd.h" #include "ntp_stdlib.h" +#ifdef AUTOKEY +#include "ntp_crypto.h" +#endif /* AUTOKEY */ /* * Table of valid association combinations @@ -27,15 +30,13 @@ * CONTROL | e 0 0 0 0 0 * PRIVATE | e 0 0 0 0 0 * BCLIENT | e 0 0 0 e 1 - * MCLIENT | e 0 0 0 0 0 * - * One point to note here: - * a packet in BCAST mode can potentially match a peer in CLIENT - * mode, but we that is a special case and we check for that early - * in the decision process. This avoids having to keep track of - * what kind of associations are possible etc... We actually - * circumvent that problem by requiring that the first b(m)roadcast - * received after the change back to BCLIENT mode sets the clock. + * One point to note here: a packet in BCAST mode can potentially match + * a peer in CLIENT mode, but we that is a special case and we check for + * that early in the decision process. This avoids having to keep track + * of what kind of associations are possible etc... We actually + * circumvent that problem by requiring that the first b(m)roadcast + * received after the change back to BCLIENT mode sets the clock. */ int AM[AM_MODES][AM_MODES] = { @@ -58,82 +59,59 @@ int AM[AM_MODES][AM_MODES] = { /*PRIV*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_ERR, AM_PROCPKT}, - -/*MCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH} }; #define MATCH_ASSOC(x,y) AM[(x)][(y)] /* * These routines manage the allocation of memory to peer structures - * and the maintenance of the peer hash table. The two main entry - * points are findpeer(), which looks for corresponding peer data - * in the peer list, newpeer(), which allocates a new peer structure - * and adds it to the list, and unpeer(), which demobilizes the association + * and the maintenance of the peer hash table. The two main entry + * points are findpeer(), which looks for matching peer sturctures in + * the peer list, newpeer(), which allocates a new peer structure and + * adds it to the list, and unpeer(), which demobilizes the association * and deallocates the structure. */ - -/* - * The peer hash table (imported by the protocol module). - */ -struct peer *peer_hash[HASH_SIZE]; -int peer_hash_count[HASH_SIZE]; /* count of peers in each bucket */ - /* - * The association ID hash table. Used for lookups by association ID + * Peer hash tables */ -struct peer *assoc_hash[HASH_SIZE]; -int assoc_hash_count[HASH_SIZE]; +struct peer *peer_hash[HASH_SIZE]; /* peer hash table */ +int peer_hash_count[HASH_SIZE]; /* peers in each bucket */ +struct peer *assoc_hash[HASH_SIZE]; /* association ID hash table */ +int assoc_hash_count[HASH_SIZE]; /* peers in each bucket */ +static struct peer *peer_free; /* peer structures free list */ +int peer_free_count; /* count of free structures */ /* - * The free list. Clean structures only, please. - */ -static struct peer *peer_free; -int peer_free_count; - -/* - * Association ID. We initialize this value randomly, the assign a new + * Association ID. We initialize this value randomly, then assign a new * value every time the peer structure is incremented. */ -static u_short current_association_ID; +static associd_t current_association_ID; /* association ID */ /* * Memory allocation watermarks. */ -#define INIT_PEER_ALLOC 15 /* initialize space for 15 peers */ -#define INC_PEER_ALLOC 5 /* when we run out, add 5 more */ +#define INIT_PEER_ALLOC 15 /* initialize for 15 peers */ +#define INC_PEER_ALLOC 5 /* when run out, add 5 more */ /* * Miscellaneous statistic counters which may be queried. */ -u_long peer_timereset; /* time stat counters were zeroed */ -u_long findpeer_calls; /* number of calls to findpeer */ -u_long assocpeer_calls; /* number of calls to findpeerbyassoc */ -u_long peer_allocations; /* number of allocations from the free list */ -u_long peer_demobilizations; /* number of structs freed to free list */ -int total_peer_structs; /* number of peer structs in circulation */ -int peer_associations; /* number of active associations */ - -/* - * Our initial allocation of peer space - */ -static struct peer init_peer_alloc[INIT_PEER_ALLOC]; - -/* - * Initialization data. When configuring peers at initialization time, - * we try to get their poll update timers initialized to different values - * to prevent us from sending big clumps of data all at once. - */ -/* static u_long init_peer_starttime; */ +u_long peer_timereset; /* time stat counters zeroed */ +u_long findpeer_calls; /* calls to findpeer */ +u_long assocpeer_calls; /* calls to findpeerbyassoc */ +u_long peer_allocations; /* allocations from free list */ +u_long peer_demobilizations; /* structs freed to free list */ +int total_peer_structs; /* peer structs */ +int peer_associations; /* active associations */ +static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */ static void getmorepeermem P((void)); -static void key_expire P((struct peer *)); /* * init_peer - initialize peer data structures and counters * - * N.B. We use the random number routine in here. It had better be - * initialized prior to getting here. + * N.B. We use the random number routine in here. It had better be + * initialized prior to getting here. */ void init_peer(void) @@ -157,11 +135,6 @@ init_peer(void) assocpeer_calls = peer_demobilizations = 0; /* - * Initialization counter. - */ - /* init_peer_starttime = 0; */ - - /* * Initialize peer memory. */ peer_free = 0; @@ -175,7 +148,7 @@ init_peer(void) /* * Initialize our first association ID */ - current_association_ID = (u_short)ranp2(16); + current_association_ID = (associd_t)ranp2(16); if (current_association_ID == 0) current_association_ID = 1; } @@ -190,7 +163,8 @@ getmorepeermem(void) register int i; register struct peer *peer; - peer = (struct peer *)emalloc(INC_PEER_ALLOC*sizeof(struct peer)); + peer = (struct peer *)emalloc(INC_PEER_ALLOC * + sizeof(struct peer)); for (i = 0; i < INC_PEER_ALLOC; i++) { peer->next = peer_free; peer_free = peer; @@ -202,7 +176,6 @@ getmorepeermem(void) } - /* * findexistingpeer - return a pointer to a peer in the hash table */ @@ -220,22 +193,21 @@ findexistingpeer( * same peer through different interfaces in the hash table. */ if (start_peer == 0) - peer = peer_hash[HASH_ADDR(addr)]; + peer = peer_hash[HASH_ADDR(addr)]; else - peer = start_peer->next; + peer = start_peer->next; while (peer != 0) { if (NSRCADR(addr) == NSRCADR(&peer->srcadr) && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) { if (mode == -1) - return peer; + return (peer); else if (peer->hmode == mode) break; } peer = peer->next; } - - return peer; + return (peer); } @@ -259,50 +231,46 @@ findpeer( for (peer = peer_hash[hash]; peer != 0; peer = peer->next) { if (NSRCADR(srcadr) == NSRCADR(&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. + * if the association matching rules determine + * that this is not a valid combination, then + * look for the next valid peer association. */ *action = MATCH_ASSOC(peer->hmode, pkt_mode); /* * Sigh! Check if BCLIENT peer in client - * server mode, else return error + * server mode, else return error. */ - if ((*action == AM_POSSBCL) && - !(peer->cast_flags & FLAG_MCAST1)) { + if ((*action == AM_POSSBCL) && !(peer->flags & + FLAG_MCAST)) *action = AM_ERR; - } - /* if an error was returned, exit back right here */ + /* + * if an error was returned, exit back right + * here. + */ if (*action == AM_ERR) - return (struct peer *)0; + return ((struct peer *)0); - /* if a match is found, we stop our search */ + /* + * if a match is found, we stop our search. + */ if (*action != AM_NOMATCH) break; } } -#ifdef DEBUG - if (debug > 1) - printf("pkt_mode %d action %d\n", pkt_mode, *action); -#endif - /* if no matching association is found */ + /* + * If no matching association is found + */ if (peer == 0) { *action = MATCH_ASSOC(NO_PEER, pkt_mode); -#ifdef DEBUG - if (debug > 1) - printf("pkt_mode %d action %d\n", pkt_mode, *action); -#endif - return (struct peer *)0; + return ((struct peer *)0); } - - /* reset the default interface to something more meaningful */ - if ((peer->dstadr == any_interface)) - peer->dstadr = dstadr; - return peer; + peer->dstadr = dstadr; + return (peer); } /* @@ -310,7 +278,7 @@ findpeer( */ struct peer * findpeerbyassoc( - int assoc + u_int assoc ) { register struct peer *peer; @@ -319,101 +287,41 @@ findpeerbyassoc( assocpeer_calls++; hash = assoc & HASH_MASK; - for (peer = assoc_hash[hash]; peer != 0; peer = peer->ass_next) { - if ((u_short)assoc == peer->associd) - return peer; /* got it! */ + for (peer = assoc_hash[hash]; peer != 0; peer = + peer->ass_next) { + if (assoc == peer->associd) + return (peer); } - - /* - * Out of luck. Return 0. - */ - return (struct peer *)0; + return (NULL); } -/* - * findmanycastpeer - find and return an manycast peer if it exists - * - * - * the current implementation loops across all hash-buckets - * - * *** THERE IS AN URGENT NEED TO CHANGE THIS *** - */ -struct peer * -findmanycastpeer( - l_fp *p_org - ) -{ - register struct peer *peer; - register struct peer *manycast_peer = 0; - int i = 0; - - for (i = 0; i < HASH_SIZE; i++) { - if (peer_hash_count[i] == 0) - continue; - - for (peer = peer_hash[i]; peer != 0; peer = peer->next) { - if (peer->cast_flags & MDF_ACAST && - peer->flags & FLAG_CONFIG) { - if (L_ISEQU(&peer->xmt, p_org)) - return peer; /* got it */ - else - manycast_peer = peer; - } - } - } - - /* - * Out of luck. Return the manycastpeer for what it is worth. - */ - return manycast_peer; -} - -/* - * key_expire - garbage collect keys - */ -static void -key_expire( - struct peer *peer - ) -{ - int i; - - if (peer->keylist != 0) { - for (i = 0; i <= peer->keynumber; i++) - authtrust(peer->keylist[i], 0); - free(peer->keylist); - peer->keylist = 0; - } - if (peer->keyid > NTP_MAXKEY) { - authtrust(peer->keyid, 0); - peer->keyid = 0; - } -} /* - * key_rekey - expire all keys and roll a new private value. Note the - * 32-bit mask is necessary for 64-bit u_longs. + * clear_all - flush all time values for all associations */ void -key_expire_all( - ) +clear_all(void) { struct peer *peer, *next_peer; int n; + /* + * This routine is called when the clock is stepped, and so all + * previously saved time values are untrusted. + */ for (n = 0; n < HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; - key_expire(peer); + peer_clear(peer); } } - sys_private = (u_long)RANDOM & 0xffffffff; #ifdef DEBUG if (debug) - printf("key_expire_all: at %lu private %08lx\n", - current_time, sys_private); + printf("clear_all: at %lu\n", current_time); #endif } + + /* * unpeer - remove peer structure from hash table and free structure */ @@ -424,16 +332,16 @@ unpeer( { int hash; + peer_associations--; #ifdef DEBUG - if (debug > 1) - printf("demobilize %u\n", peer_to_remove->associd); + if (debug) + printf("demobilize %u %d\n", peer_to_remove->associd, + peer_associations); #endif - key_expire(peer_to_remove); + peer_clear(peer_to_remove); hash = HASH_ADDR(&peer_to_remove->srcadr); peer_hash_count[hash]--; peer_demobilizations++; - peer_associations--; - #ifdef REFCLOCK /* * If this peer is actually a clock, shut it down first @@ -490,7 +398,7 @@ unpeer( /* - * peer_config - configure a new peer + * peer_config - configure a new association */ struct peer * peer_config( @@ -500,63 +408,83 @@ peer_config( int version, int minpoll, int maxpoll, - int flags, + u_int flags, int ttl, - u_long key + keyid_t key, + u_char *keystr ) { register struct peer *peer; + u_int cast_flags; /* - * See if we have this guy in the tables already. If - * so just mark him configured. + * First search from the beginning for an association with given + * remote address and mode. If an interface is given, search + * from there to find the association which matches that + * destination. */ peer = findexistingpeer(srcadr, (struct peer *)0, hmode); if (dstadr != 0) { while (peer != 0) { if (peer->dstadr == dstadr) - break; + break; peer = findexistingpeer(srcadr, peer, hmode); } } /* - * If we found one, just change his mode and mark him configured. + * We do a dirty little jig to figure the cast flags. This is + * probably not the best place to do this, at least until the + * configure code is rebuilt. Note only one flag can be set. + */ + switch (hmode) { + + case MODE_BROADCAST: + if (IN_CLASSD(ntohl(srcadr->sin_addr.s_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; + + default: + cast_flags = MDF_UCAST; + break; + } + + /* + * If the peer is already configured, some dope has a duplicate + * configureation entry or another dope is wiggling from afar. */ if (peer != 0) { peer->hmode = (u_char)hmode; peer->version = (u_char)version; peer->minpoll = (u_char)minpoll; peer->maxpoll = (u_char)maxpoll; - peer->hpoll = peer->minpoll; - peer->ppoll = peer->minpoll; + peer->hpoll = peer->kpoll = peer->minpoll; + peer->ppoll = peer->maxpoll; peer->flags = flags | FLAG_CONFIG | (peer->flags & FLAG_REFCLOCK); - peer->cast_flags = (hmode == MODE_BROADCAST) ? - IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) ? MDF_MCAST : MDF_BCAST : MDF_UCAST; - peer->ttl = (u_char)ttl; + peer->cast_flags = cast_flags; + peer->ttlmax = ttl; peer->keyid = key; - peer->keynumber = 0; - return peer; + return (peer); } /* - * If we're here this guy is unknown to us. Make a new peer - * structure for him. + * Here no match has been found, so presumably this is a new + * persistent association. Mobilize the thing and initialize its + * variables. */ peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, - ttl, key); - if (peer != 0) { - peer->flags |= flags | FLAG_CONFIG; -#ifdef DEBUG - if (debug) - printf("peer_config: %s mode %d vers %d min %d max %d flags 0x%04x ttl %d key %lu\n", - ntoa(&peer->srcadr), peer->hmode, peer->version, - peer->minpoll, peer->maxpoll, peer->flags, - peer->ttl, peer->keyid); -#endif - } - return peer; + flags | FLAG_CONFIG, cast_flags, ttl, key); + return (peer); } @@ -571,74 +499,63 @@ newpeer( int version, int minpoll, int maxpoll, + u_int flags, + u_int cast_flags, int ttl, - u_long key + keyid_t key ) { register struct peer *peer; register int i; /* - * Some dirt here. Some of the initialization requires - * knowlege of our system state. + * Allocate a new peer structure. Some dirt here, since some of + * the initialization requires knowlege of our system state. */ if (peer_free_count == 0) - getmorepeermem(); - + getmorepeermem(); peer = peer_free; peer_free = peer->next; peer_free_count--; peer_associations++; + memset((char *)peer, 0, sizeof(struct peer)); /* - * Initialize the structure. This stuff is sort of part of - * the receive procedure and part of the clear procedure rolled - * into one. - * - * Zero the whole thing for now. We might be pickier later. + * Initialize the peer structure and dance the interface jig. + * Reference clocks step the loopback waltz, the others + * squaredance around the interface list looking for a buddy. If + * the dance peters out, there is always the wildcard interface. + * This might happen in some systems and would preclude proper + * operation with public key cryptography. */ - memset((char *)peer, 0, sizeof(struct peer)); - - peer->srcadr = *srcadr; - if (dstadr != 0) - peer->dstadr = dstadr; - else if (hmode == MODE_BROADCAST) + if (ISREFCLOCKADR(srcadr)) + peer->dstadr = loopback_interface; + else if (cast_flags & MDF_BCLNT) peer->dstadr = findbcastinter(srcadr); + else if (dstadr != any_interface) + peer->dstadr = dstadr; else - peer->dstadr = any_interface; - peer->cast_flags = (hmode == MODE_BROADCAST) ? - (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) ? MDF_MCAST : - MDF_BCAST : (hmode == MODE_BCLIENT || hmode == MODE_MCLIENT) ? - (peer->dstadr->flags & INT_MULTICAST) ? MDF_MCAST : MDF_BCAST : - MDF_UCAST; - /* Set manycast flags if appropriate */ - if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) && hmode == MODE_CLIENT) - peer->cast_flags = MDF_ACAST; + peer->dstadr = findinterface(srcadr); + peer->srcadr = *srcadr; peer->hmode = (u_char)hmode; - peer->keyid = key; peer->version = (u_char)version; - peer->minpoll = (u_char)minpoll; - peer->maxpoll = (u_char)maxpoll; - peer->hpoll = peer->minpoll; - peer->ppoll = peer->minpoll; - peer->ttl = ttl; - peer->leap = LEAP_NOTINSYNC; + 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->cast_flags = cast_flags; + peer->ttlmax = ttl; + peer->keyid = key; peer->precision = sys_precision; - peer->variance = MAXDISPERSE; - peer->epoch = current_time; - peer->stratum = STRATUM_UNSPEC; peer_clear(peer); - peer->update = peer->outdate = current_time; - peer->nextdate = peer->outdate + RANDPOLL(NTP_MINPOLL); - if (peer->flags & FLAG_BURST) - peer->burst = NTP_SHIFT; + if (mode_ntpdate) + peer_ntpdate++; /* - * Assign him an association ID and increment the system variable + * Assign an association ID and increment the system variable. */ peer->associd = current_association_ID; if (++current_association_ID == 0) - ++current_association_ID; + ++current_association_ID; /* * Note time on statistics timers. @@ -646,7 +563,6 @@ newpeer( peer->timereset = current_time; peer->timereachable = current_time; peer->timereceived = current_time; - #ifdef REFCLOCK if (ISREFCLOCKADR(&peer->srcadr)) { /* @@ -662,29 +578,32 @@ newpeer( peer->next = peer_free; peer_free = peer; peer_free_count++; - return 0; + return (NULL); } } #endif /* - * Put him in the hash tables. + * Put the new peer in the hash tables. */ i = HASH_ADDR(&peer->srcadr); peer->next = peer_hash[i]; peer_hash[i] = peer; peer_hash_count[i]++; - i = peer->associd & HASH_MASK; peer->ass_next = assoc_hash[i]; assoc_hash[i] = peer; assoc_hash_count[i]++; #ifdef DEBUG - if (debug > 1) - printf("mobilize %u next %lu\n", peer->associd, - peer->nextdate - peer->outdate); + 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), + peer->hmode, peer->version, peer->minpoll, + peer->maxpoll, peer->flags, peer->cast_flags, + peer->ttlmax, peer->keyid); #endif - return peer; + return (peer); } @@ -707,14 +626,15 @@ peer_unconfig( if (peer->flags & FLAG_CONFIG && (dstadr == 0 || peer->dstadr == dstadr)) { num_found++; + /* - * Tricky stuff here. If the peer is polling us - * in active mode, turn off the configuration bit - * and make the mode passive. This allows us to - * avoid dumping a lot of history for peers we - * might choose to keep track of in passive mode. - * The protocol will eventually terminate undesirables - * on its own. + * Tricky stuff here. If the peer is polling us + * in active mode, turn off the configuration + * bit and make the mode passive. This allows us + * to avoid dumping a lot of history for peers + * we might choose to keep track of in passive + * mode. The protocol will eventually terminate + * undesirables on its own. */ if (peer->hmode == MODE_ACTIVE && peer->pmode == MODE_ACTIVE) { @@ -727,21 +647,7 @@ peer_unconfig( } peer = findexistingpeer(srcadr, peer, mode); } - return num_found; -} - -/* - * peer_copy_manycast - copy manycast peer variables to new association - * (right now it simply copies the transmit timestamp) - */ -void -peer_config_manycast( - struct peer *peer1, - struct peer *peer2 - ) -{ - peer2->cast_flags = MDF_ACAST; - peer2->xmt = peer1->xmt; + return (num_found); } /* @@ -775,7 +681,6 @@ peer_reset( peer->oldpkt = 0; peer->seldisptoolarge = 0; peer->selbroken = 0; - peer->seltooold = 0; peer->timereset = current_time; } @@ -793,3 +698,114 @@ peer_all_reset(void) for (peer = peer_hash[hash]; peer != 0; peer = peer->next) peer_reset(peer); } + + +#ifdef AUTOKEY +/* + * expire_all - flush all crypto data and update timestamps. + */ +void +expire_all(void) +{ + struct peer *peer, *next_peer; + int n; + + /* + * This routine is called about once per day from the timer + * routine and when the client is first synchronized. Search the + * peer list for all associations and flush only the key list + * and cookie. If a manycast client association, flush + * everything. Then, recompute and sign the agreement public + * value, if present. + */ + 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 { + key_expire(peer); + peer->pcookie.tstamp = 0; +#endif /* AUTOKEY */ + } + + } + } + 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 +} +#endif /* AUTOKEY */ + + +/* + * findmanycastpeer - find and return a manycast peer + */ +struct peer * +findmanycastpeer( + struct recvbuf *rbufp + ) +{ + register struct peer *peer; + struct pkt *pkt; + l_fp p_org; + int i; + + /* + * This routine is called upon arrival of a client-mode message + * from a manycast server. Search the peer list for a manycast + * client association where the last transmit timestamp matches + * the originate timestamp. This assumes the transmit timestamps + * for possibly more than one manycast association are unique. + */ + pkt = &rbufp->recv_pkt; + for (i = 0; i < HASH_SIZE; i++) { + if (peer_hash_count[i] == 0) + continue; + + for (peer = peer_hash[i]; peer != 0; peer = + peer->next) { + if (peer->cast_flags & MDF_ACAST) { + NTOHL_FP(&pkt->org, &p_org); + if (L_ISEQU(&peer->xmt, &p_org)) + return (peer); + } + } + } + return (NULL); +} + + +/* + * resetmanycast - reset all manycast clients + */ +void +resetmanycast(void) +{ + register struct peer *peer; + int i; + + /* + * This routine is called when the number of client associations + * falls below the minimum. Search the peer list for manycast + * client associations and reset the ttl and poll interval. + */ + for (i = 0; i < HASH_SIZE; i++) { + if (peer_hash_count[i] == 0) + continue; + + for (peer = peer_hash[i]; peer != 0; peer = + peer->next) { + if (peer->cast_flags & MDF_ACAST) { + peer->ttl = 0; + poll_update(peer, peer->hpoll); + } + } + } +} diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c index a24c0e3..4962057 100644 --- a/contrib/ntp/ntpd/ntp_proto.c +++ b/contrib/ntp/ntpd/ntp_proto.c @@ -5,15 +5,14 @@ #include <config.h> #endif -#include <stdio.h> -#include <sys/types.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_stdlib.h" #include "ntp_unixtime.h" #include "ntp_control.h" #include "ntp_string.h" +#include "ntp_crypto.h" + +#include <stdio.h> #if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ #include "ntp_refclock.h" @@ -24,19 +23,22 @@ #endif /* - * System variables are declared here. See Section 3.2 of the + * System variables are declared here. See Section 3.2 of the * specification. */ u_char sys_leap; /* system leap indicator */ u_char sys_stratum; /* stratum of system */ s_char sys_precision; /* local clock precision */ -double sys_rootdelay; /* distance to current sync source */ -double sys_rootdispersion; /* dispersion of system clock */ +double sys_rootdelay; /* roundtrip delay to primary source */ +double sys_rootdispersion; /* dispersion to primary source */ u_int32 sys_refid; /* reference source for local clock */ 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_prefer; /* our cherished peer */ +#ifdef AUTOKEY u_long sys_automax; /* maximum session key lifetime */ +#endif /* AUTOKEY */ /* * Nonspecified system state variables. @@ -47,10 +49,15 @@ 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_char leap_consensus; /* consensus of survivor leap bits */ -static double sys_maxd; /* select error (squares) */ -static double sys_epsil; /* system error (squares) */ -u_long sys_private; /* private value for session seed */ -int sys_manycastserver; /* 1 => respond to manycast client pkts */ +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 +char *sys_hostname; /* gethostname() name */ +#endif /* AUTOKEY */ /* * Statistics counters @@ -68,12 +75,10 @@ u_long sys_limitrejected; /* pkts rejected due to client count per net */ static double root_distance P((struct peer *)); static double clock_combine P((struct peer **, int)); static void peer_xmit P((struct peer *)); -static void fast_xmit P((struct recvbuf *, int, u_long)); +static void fast_xmit P((struct recvbuf *, int, keyid_t, int)); static void clock_update P((void)); int default_get_precision P((void)); -#ifdef MD5 -static void make_keylist P((struct peer *)); -#endif /* MD5 */ + /* * transmit - Transmit Procedure. See Section 3.4.2 of the @@ -91,116 +96,173 @@ transmit( u_char oreach; /* - * Determine reachability and diddle things if we - * haven't heard from the host for a while. If the peer - * is not configured and not likely to stay around, - * we exhaust it. + * 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... */ + if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) { + + /* + * 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 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 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)) { + unpeer(peer); + clock_select(); + return; + + } else { + peer_clear(peer); + hpoll++; + } + } oreach = peer->reach; - if (oreach & 0x01) - peer->valid++; - if (oreach & 0x80) - peer->valid--; - if (!(peer->flags & FLAG_CONFIG) && peer->valid > - NTP_SHIFT / 2 && (peer->reach & 0x80) && - peer->status < CTL_PST_SEL_SYNCCAND) - peer->reach = 0; peer->reach <<= 1; if (peer->reach == 0) { /* - * If this is an uncofigured association and - * has become unreachable, demobilize it. + * If this association has become unreachable, + * clear it and raise a trap. */ if (oreach != 0) { report_event(EVNT_UNREACH, peer); peer->timereachable = current_time; - peer_clear(peer); if (!(peer->flags & FLAG_CONFIG)) { unpeer(peer); + clock_select(); return; + } else { + peer_clear(peer); + hpoll = peer->minpoll; } } - - /* - * We would like to respond quickly when the - * peer comes back to life. If the probes since - * becoming unreachable are less than - * NTP_UNREACH, clamp the poll interval to the - * minimum. In order to minimize the network - * traffic, the interval gradually ramps up the - * the maximum after that. - */ - peer->ppoll = peer->maxpoll; - if (peer->unreach < NTP_UNREACH) { - if (peer->hmode == MODE_CLIENT) - peer->unreach++; - hpoll = peer->minpoll; - } else { - hpoll++; - } - if (peer->flags & FLAG_BURST) - peer->burst = 2; - + if (peer->flags & FLAG_IBURST) + peer->burst = NTP_SHIFT; } else { /* - * Here the peer is reachable. If there is no - * system peer or if the stratum of the system - * peer is greater than this peer, clamp the - * poll interval to the minimum. If less than - * two samples are in the reachability register, - * reduce the interval; if more than six samples - * are in the register, increase the interval. + * 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. */ - peer->unreach = 0; - if (sys_peer == 0) - hpoll = peer->minpoll; - else if (sys_peer->stratum > peer->stratum) - hpoll = peer->minpoll; - if ((peer->reach & 0x03) == 0) { + if (!(peer->reach & 0x07)) { clock_filter(peer, 0., 0., MAXDISPERSE); clock_select(); } - if (peer->valid <= 2) - hpoll--; - else if (peer->valid >= NTP_SHIFT - 2) + if ((peer->stratum > 1 && peer->refid == + peer->dstadr->sin.sin_addr.s_addr) || + peer->stratum >= STRATUM_UNSPEC) hpoll++; + else + hpoll = sys_poll; if (peer->flags & FLAG_BURST) peer->burst = NTP_SHIFT; } } else { peer->burst--; if (peer->burst == 0) { - if (peer->flags & FLAG_MCAST2) { - peer->flags &= ~FLAG_BURST; + + /* + * If a broadcast client at this point, the + * burst has concluded, so we switch to client + * mode and purge the keylist, since no further + * transmissions will be made. + */ + if (peer->cast_flags & MDF_BCLNT) { peer->hmode = MODE_BCLIENT; +#ifdef AUTOKEY + key_expire(peer); +#endif /* AUTOKEY */ } - clock_select(); 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); + } return; + } } + peer->outdate = current_time; + poll_update(peer, hpoll); /* - * We need to be very careful about honking uncivilized time. If - * not operating in broadcast mode, honk in all except broadcast - * client mode. If operating in broadcast mode and synchronized - * to a real source, honk except when the peer is the local- - * clock driver and the prefer flag is not set. In other words, - * in broadcast mode we never honk unless known to be - * synchronized to real time. + * 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. */ - if (peer->hmode != MODE_BROADCAST) { - if (peer->hmode != MODE_BCLIENT) - peer_xmit(peer); - } else if (sys_peer != 0 && sys_leap != LEAP_NOTINSYNC) { - if (!(sys_peer->refclktype == REFCLK_LOCALCLOCK && - !(sys_peer->flags & FLAG_PREFER))) - peer_xmit(peer); + if (peer->hmode == MODE_BCLIENT || peer->flash & TEST4) { + return; + } else if (peer->hmode == MODE_BROADCAST) { + if (sys_peer == NULL) + return; } - peer->outdate = current_time; - poll_update(peer, hpoll); + peer_xmit(peer); } /* @@ -216,482 +278,552 @@ receive( int hismode; int oflags; int restrict_mask; - int has_mac; /* has MAC field */ - int authlen; /* length of MAC field */ + int has_mac; /* length of MAC field */ + int authlen; /* offset of MAC field */ int is_authentic; /* cryptosum ok */ - int is_mystic; /* session key exists */ - int is_error; /* parse error */ -/* u_long pkeyid; */ - u_long skeyid, tkeyid; + 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; int retcode = AM_NOMATCH; /* - * Monitor the packet and get restrictions + * Monitor the packet and get restrictions. Note that the packet + * length for control and private mode packets must be checked + * by the service routines. Note that no statistics counters are + * recorded for restrict violations, since these counters are in + * the restriction routine. Note the careful distinctions here + * between a packet with a format error and a packet that is + * simply discarded without prejudice. Some restrictions have to + * be handled later in order to generate a kiss-of-death packet. */ ntp_monitor(rbufp); restrict_mask = restrictions(&rbufp->recv_srcadr); #ifdef DEBUG - if (debug > 1) - printf("receive: from %s restrict %02x\n", + if (debug > 2) + printf("receive: at %ld %s<-%s restrict %02x\n", + current_time, ntoa(&rbufp->dstadr->sin), ntoa(&rbufp->recv_srcadr), restrict_mask); #endif if (restrict_mask & RES_IGNORE) - return; - - /* - * Discard packets with invalid version number. - */ + return; /* no anything */ + if (!(SRCPORT(&rbufp->recv_srcadr) == NTP_PORT || + SRCPORT(&rbufp->recv_srcadr) >= IPPORT_RESERVED)) { + sys_badlength++; + return; /* invalid port */ + } pkt = &rbufp->recv_pkt; - if (PKT_VERSION(pkt->li_vn_mode) >= NTP_VERSION) - sys_newversionpkt++; - else if (PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) - sys_oldversionpkt++; - else { + 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; + return; /* invalid version */ } - - /* - * Restrict control/private mode packets. Note that packet - * length has to be checked in the control/private mode protocol - * module. - */ if (PKT_MODE(pkt->li_vn_mode) == MODE_PRIVATE) { if (restrict_mask & RES_NOQUERY) - return; + 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) - return; + return; /* no query control */ process_control(rbufp, restrict_mask); return; } + if (rbufp->recv_length < LEN_PKT_NOMAC) { + sys_badlength++; + return; /* runt packet */ + } /* - * Restrict revenue packets. - */ - if (restrict_mask & RES_DONTSERVE) - return; - - /* - * See if we only accept limited number of clients from the net - * this guy is from. Note: the flag is determined dynamically - * within restrictions() + * Validate mode. Note that NTPv1 is no longer supported. */ - if (restrict_mask & RES_LIMITED) { - sys_limitrejected++; - return; - } + hismode = (int)PKT_MODE(pkt->li_vn_mode); + if (hismode == MODE_UNSPEC) { + sys_badlength++; + return; /* invalid mode */ + } /* - * If we are not a broadcast client, ignore broadcast packets. + * Discard broadcast packets received on the wildcard interface + * or if not enabled as broadcast client. */ - if ((PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST && - !sys_bclient)) + if (PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST && + (rbufp->dstadr == any_interface || !sys_bclient)) return; /* - * This is really awful ugly. We figure out whether an extension - * field is present and then measure the MAC size. If the number - * of words following the packet header is less than or equal to - * 5, no extension field is present and these words constitute - * the MAC. If the number of words is greater than 5, an - * extension field is present and the first word contains the - * length of the extension field and the MAC follows that. + * Parse the extension field if present. We figure out whether + * an extension field is present by measuring the MAC size. If + * the number of words following the packet header is 0 or 1, no + * MAC is present and the packet is not authenticated. If 1, the + * packet is a reply to a previous request that failed to + * authenticate. If 3, the packet is authenticated with DES; if + * 5, the packet is authenticated with MD5. If greater than 5, + * an extension field is present. If 2 or 4, the packet is a + * runt and goes poof! with a brilliant flash. */ - has_mac = 0; -/* pkeyid = 0; */ - skeyid = tkeyid = 0; + skeyid = 0; +#ifdef AUTOKEY + pkeyid = tkeyid = 0; +#endif /* AUTOKEY */ authlen = LEN_PKT_NOMAC; - has_mac = rbufp->recv_length - authlen; - if (has_mac <= 5 * sizeof(u_int32)) { - skeyid = (u_long)ntohl(pkt->keyid1) & 0xffffffff; - } else { - authlen += (u_long)ntohl(pkt->keyid1) & 0xffffffff; - has_mac = rbufp->recv_length - authlen; - if (authlen <= 0) { + while ((has_mac = rbufp->recv_length - authlen) > 0) { + int temp; + + if (has_mac % 4 != 0 || has_mac < 0) { sys_badlength++; return; } + if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac == + MAX_MAC_LEN) { + skeyid = ntohl(((u_int32 *)pkt)[authlen / 4]); + break; - /* - * Note that keyid3 is actually the key ident of the - * MAC itself. - */ -/* pkeyid = (u_long)ntohl(pkt->keyid2) & 0xffffffff; */ - skeyid = tkeyid = (u_long)ntohl(pkt->keyid3) & - 0xffffffff; - } - - /* - * Figure out his mode and validate it. - */ - hismode = (int)PKT_MODE(pkt->li_vn_mode); - if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION && hismode == - 0) { - /* - * Easy. If it is from the NTP port it is - * a sym act, else client. - */ - if (SRCPORT(&rbufp->recv_srcadr) == NTP_PORT) - hismode = MODE_ACTIVE; - else - hismode = MODE_CLIENT; - } else { - if (hismode != MODE_ACTIVE && hismode != MODE_PASSIVE && - hismode != MODE_SERVER && hismode != MODE_CLIENT && - hismode != MODE_BROADCAST) + } else if (has_mac > MAX_MAC_LEN) { + temp = ntohl(((u_int32 *)pkt)[authlen / 4]) & + 0xffff; + if (temp < 4 || temp % 4 != 0) { + sys_badlength++; + return; + } + authlen += temp; + } else { + sys_badlength++; return; + } } /* - * If he included a mac field, decrypt it to see if it is - * authentic. + * 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 + * matching association and that's okay. + * + * More on the autokey mambo. Normally the local interface is + * found when the association was mobilized with respect to a + * designated remote address. We assume packets arriving from + * the remote address arrive via this interface and the local + * address used to construct the autokey is the unicast address + * of the interface. However, if the sender is a broadcaster, + * the interface broadcast address is used instead. + * Notwithstanding this technobabble, if the sender is a + * multicaster, the broadcast address is null, so we use the + * unicast address anyway. Don't ask. */ - is_authentic = is_mystic = 0; + peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd, + hismode, &retcode); + is_authentic = 0; + dstadr_sin = &rbufp->dstadr->sin; if (has_mac == 0) { #ifdef DEBUG if (debug) - printf("receive: at %ld from %s mode %d\n", - current_time, ntoa(&rbufp->recv_srcadr), - hismode); + printf("receive: at %ld %s<-%s mode %d code %d\n", + current_time, ntoa(&rbufp->dstadr->sin), + ntoa(&rbufp->recv_srcadr), hismode, retcode); #endif } else { - is_mystic = authistrusted(skeyid); -#ifdef MD5 - if (skeyid > NTP_MAXKEY && !is_mystic) { - +#ifdef AUTOKEY + /* + * For autokey modes, generate the session key + * and install in the key cache. Use the socket + * broadcast or unicast address as appropriate. + */ + if (skeyid > NTP_MAXKEY) { + /* - * For multicast mode, generate the session key - * and install in the key cache. For client - * mode, generate the session key for the - * unicast address. For server mode, the session - * key should already be in the key cache, since - * it was generated when the last request was - * sent. + * More on the autokey dance (AKD). A cookie is + * constructed from public and private values. + * For broadcast packets, the cookie is public + * (zero). For packets that match no + * association, the cookie is hashed from the + * addresses and private value. For server + * packets, the cookie was previously obtained + * from the server. For symmetric modes, the + * cookie was previously constructed using an + * agreement protocol; however, should PKI be + * unavailable, we construct a fake agreement as + * the EXOR of the peer and host cookies. + * + * hismode ephemeral persistent + * ======================================= + * active 0 cookie# + * passive 0% cookie# + * client sys cookie 0% + * server 0% sys cookie + * broadcast 0 0 + * + * # if unsync, 0 + * % can't happen */ if (hismode == MODE_BROADCAST) { + + /* + * For broadcaster, use the interface + * broadcast address when available; + * otherwise, use the unicast address + * found when the association was + * mobilized. + */ + pkeyid = 0; + if (rbufp->dstadr->bcast.sin_addr.s_addr + != 0) + dstadr_sin = + &rbufp->dstadr->bcast; + } else if (peer == NULL) { + pkeyid = session_key( + &rbufp->recv_srcadr, dstadr_sin, 0, + sys_private, 0); + } else { + pkeyid = peer->pcookie.key; + } + + /* + * The session key includes both the public + * values and cookie. In case of an extension + * field, the cookie used for authentication + * purposes is zero. Note the hash is saved for + * use later in the autokey mambo. + */ + if (authlen > LEN_PKT_NOMAC && pkeyid != 0) { + session_key(&rbufp->recv_srcadr, + dstadr_sin, skeyid, 0, 2); tkeyid = session_key( - ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), - ntohl(rbufp->dstadr->bcast.sin_addr.s_addr), - skeyid, (u_long)(4 * (1 << pkt->ppoll))); - } else if (hismode != MODE_SERVER) { + &rbufp->recv_srcadr, dstadr_sin, + skeyid, pkeyid, 0); + } else { tkeyid = session_key( - ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), - ntohl(rbufp->dstadr->sin.sin_addr.s_addr), - skeyid, (u_long)(4 * (1 << pkt->ppoll))); + &rbufp->recv_srcadr, dstadr_sin, + skeyid, pkeyid, 2); } } -#endif /* MD5 */ +#endif /* AUTOKEY */ /* * Compute the cryptosum. Note a clogging attack may - * succceed in bloating the key cache. + * succeed in bloating the key cache. If an autokey, + * purge it immediately, since we won't be needing it + * again. */ if (authdecrypt(skeyid, (u_int32 *)pkt, authlen, has_mac)) is_authentic = 1; else sys_badauth++; +#ifdef AUTOKEY + if (skeyid > NTP_MAXKEY) + authtrust(skeyid, 0); +#endif /* AUTOKEY */ #ifdef DEBUG if (debug) printf( - "receive: at %ld %s mode %d keyid %08lx mac %d auth %d\n", - current_time, ntoa(&rbufp->recv_srcadr), - hismode, skeyid, has_mac, is_authentic); + "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, + skeyid, authlen, has_mac, + is_authentic); #endif } /* - * Find the peer. This will return a null if this guy isn't in - * the database. + * The association matching rules are implemented by a set of + * routines and a table in ntp_peer.c. A packet matching an + * 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... */ - peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd, - hismode, &retcode); - /* - * The new association matching rules are driven by a table - * specified in ntp.h. We have replaced the *default* behaviour - * of replying to bogus packets in server mode in this version. - * A packet must now match an association in order to be - * processed. In the event that no association exists, then an - * association is mobilized if need be. Two different - * associations can be mobilized a) passive associations b) - * client associations due to broadcasts or manycasts. - */ - is_error = 0; switch (retcode) { case AM_FXMIT: /* - * If the client is configured purely as a broadcast - * client and not as an manycast server, it has no - * business being a server. Simply go home. Otherwise, - * send a MODE_SERVER response and go home. Note that we - * don't do a 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. + * This is a client mode packet not matching a known + * association. If from a manycast client we run a few + * sanity checks before deciding to send a unicast + * server response. Otherwise, it must be a client + * request, so send a server response and go home. */ - if (!sys_bclient || sys_manycastserver) { - if (is_authentic) - fast_xmit(rbufp, MODE_SERVER, skeyid); - else - fast_xmit(rbufp, MODE_SERVER, 0); + if (sys_manycastserver && (rbufp->dstadr->flags & + 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. + */ + 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; } /* - * We can't get here if an association is mobilized, so - * just toss the key, if appropriate. + * 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. */ - if (!is_mystic && skeyid > NTP_MAXKEY) - authtrust(skeyid, 0); - return; + if (is_authentic) + fast_xmit(rbufp, MODE_SERVER, skeyid, + restrict_mask); + else + fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); + return; case AM_MANYCAST: /* - * This could be in response to a multicast packet sent - * by the "manycast" mode association. Find peer based - * on the originate timestamp in the packet. Note that - * we don't mobilize a new association, unless the - * packet is properly authenticated. The response must - * be properly authenticated and it's darn funny of the - * manycaster isn't around now. + * This is a server mode packet returned in response to + * a client mode packet sent to a multicast group + * address. The originate timestamp is a good nonce to + * reliably associate the reply with what was sent. If + * there is no match, that's curious and could be an + * intruder attempting to clog, so we just ignore it. + * + * 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. + * + * There is an implosion hazard at the manycast client, + * since the manycast servers send the server packet + * immediately. */ - if ((sys_authenticate && !is_authentic)) { - is_error = 1; - break; - } - peer2 = (struct peer *)findmanycastpeer(&pkt->org); - if (peer2 == 0) { - is_error = 1; - break; - } + if ((restrict_mask & (RES_DONTSERVE | RES_LIMITED | + RES_NOPEER)) || (sys_authenticate && + !is_authentic)) + return; + + peer2 = findmanycastpeer(rbufp); + if (peer2 == 0) + return; - /* - * Create a new association and copy the peer variables - * to it. If something goes wrong, carefully pry the new - * association away and return its marbles to the candy - * store. - */ peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); - if (peer == 0) { - is_error = 1; - break; - } - peer_config_manycast(peer2, peer); - break; - - case AM_ERR: - - /* - * Something bad happened. Dirty floor will be mopped by - * the code at the end of this adventure. - */ - is_error = 1; + sys_minpoll, NTP_MAXDPOLL, FLAG_IBURST | + (peer2->flags & (FLAG_AUTHENABLE | FLAG_SKEY)), + MDF_UCAST, 0, skeyid); + if (peer == NULL) + return; break; case AM_NEWPASS: /* - * Okay, we're going to keep him around. Allocate him - * some memory. But, don't do that unless the packet is - * properly authenticated. + * 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. */ - if ((sys_authenticate && !is_authentic)) { - is_error = 1; - break; + if ((restrict_mask & (RES_DONTSERVE | RES_LIMITED | + RES_NOPEER)) || (sys_authenticate && + !is_authentic)) { + fast_xmit(rbufp, MODE_PASSIVE, 0, + restrict_mask); + return; } peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); + sys_minpoll, NTP_MAXDPOLL, sys_authenticate ? + FLAG_AUTHENABLE : 0, MDF_UCAST, 0, skeyid); + if (peer == NULL) + return; break; case AM_NEWBCL: /* - * Broadcast client being set up now. Do this only if - * the packet is properly authenticated. + * 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. */ - if ((restrict_mask & RES_NOPEER) || !sys_bclient || - (sys_authenticate && !is_authentic)) { - is_error = 1; - break; - } + if ((restrict_mask & (RES_DONTSERVE | RES_LIMITED | + RES_NOPEER)) || (sys_authenticate && + !is_authentic) || !sys_bclient) + return; + peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_MCLIENT, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); - if (peer == 0) - break; - peer->flags |= FLAG_MCAST1 | FLAG_MCAST2 | FLAG_BURST; - peer->hmode = MODE_CLIENT; - break; + 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 */ + return; case AM_POSSBCL: case AM_PROCPKT: /* - * It seems like it is okay to process the packet now + * Happiness and nothing broke. Earn some revenue. */ break; default: /* - * shouldn't be getting here, but simply return anyway! + * Invalid mode combination. Leave the island + * immediately. */ - is_error = 1; - } - if (is_error) { - - /* - * Error stub. If we get here, something broke. We - * scuttle the autokey if necessary and sink the ship. - * This can occur only upon mobilization, so we can - * throw the structure away without fear of breaking - * anything. - */ - if (!is_mystic && skeyid > NTP_MAXKEY) - authtrust(skeyid, 0); - if (peer != 0) - if (!(peer->flags & FLAG_CONFIG)) - unpeer(peer); #ifdef DEBUG if (debug) - printf("match error code %d assoc %d\n", - retcode, peer_associations); + printf("receive: bad protocol %d\n", retcode); #endif return; } /* - * If the peer isn't configured, set his keyid and authenable - * status based on the packet. + * 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. */ oflags = peer->flags; peer->timereceived = current_time; + peer->received++; if (!(peer->flags & FLAG_CONFIG) && has_mac) { peer->flags |= FLAG_AUTHENABLE; - if (skeyid > NTP_MAXKEY) { - if (peer->flags & FLAG_MCAST2) - peer->keyid = skeyid; - else - peer->flags |= FLAG_SKEY; - } +#ifdef AUTOKEY + if (skeyid > NTP_MAXKEY) + peer->flags |= FLAG_SKEY; +#endif /* AUTOKEY */ } /* - * Determine if this guy is basically trustable. If not, flush - * the bugger. If this is the first packet that is - * authenticated, flush the clock filter. This is to foil - * clogging attacks that might starve the poor dear. + * 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. */ peer->flash = 0; - if (is_authentic) + if (is_authentic) { peer->flags |= FLAG_AUTHENTIC; - else + } else { peer->flags &= ~FLAG_AUTHENTIC; - if (peer->hmode == MODE_BROADCAST && (restrict_mask & - RES_DONTTRUST)) - peer->flash |= TEST10; /* access denied */ + } + 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)) + if (!(peer->flags & FLAG_AUTHENTIC)) /* test 5 */ peer->flash |= TEST5; /* auth failed */ - else if (skeyid == 0) - peer->flash |= TEST9; /* peer not auth */ - else if (!(oflags & FLAG_AUTHENABLE)) { - peer_clear(peer); + else if (!(oflags & FLAG_AUTHENABLE)) report_event(EVNT_PEERAUTH, peer); - } } - if ((peer->flash & ~(u_int)TEST9) != 0) { - - /* - * The packet is bogus, so we throw it away before - * becoming a denial-of-service hazard. We don't throw - * the current association away if it is configured or - * if it has prior reachable friends. - */ - if (!is_mystic && skeyid > NTP_MAXKEY) - authtrust(skeyid, 0); - if (!(peer->flags & FLAG_CONFIG) && peer->reach == 0) - unpeer(peer); + if (peer->flash) { #ifdef DEBUG if (debug) - printf( - "invalid packet 0x%02x code %d assoc %d\n", - peer->flash, retcode, peer_associations); + printf("receive: bad auth %03x\n", peer->flash); #endif return; } -#ifdef MD5 +#ifdef AUTOKEY /* - * The autokey dance. The cha-cha requires that the hash of the - * current session key matches the previous key identifier. - * Heaps of trouble if the steps falter. + * 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 + * self-authenticated and we sit the dance. + * + * 3. 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 + * 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 (skeyid > NTP_MAXKEY) { - int i; - - /* - * In the case of a new autokey, verify the hash matches - * one of the previous four hashes. If not, raise the - * authentication flasher and hope the next one works. - */ + if (peer->flags & FLAG_SKEY) { + peer->flash |= TEST10; + crypto_recv(peer, rbufp); + poll_update(peer, peer->hpoll); if (hismode == MODE_SERVER) { - peer->pkeyid = peer->keyid; - } else if (peer->flags & FLAG_MCAST2) { - if (peer->pkeyid > NTP_MAXKEY) - authtrust(peer->pkeyid, 0); - for (i = 0; i < 4 && tkeyid != peer->pkeyid; - i++) { - tkeyid = session_key( - ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), - ntohl(rbufp->dstadr->bcast.sin_addr.s_addr), - tkeyid, 0); - } + if (skeyid == peer->keyid) + peer->flash &= ~TEST10; + } else if (!peer->flash & TEST10) { + peer->pkeyid = skeyid; } else { - if (peer->pkeyid > NTP_MAXKEY) - authtrust(peer->pkeyid, 0); - for (i = 0; i < 4 && tkeyid != peer->pkeyid; - i++) { + int i; + + for (i = 0; ; i++) { + if (tkeyid == peer->pkeyid || + tkeyid == peer->recauto.key) { + peer->flash &= ~TEST10; + peer->pkeyid = skeyid; + break; + } + if (i > peer->recauto.seq) + break; tkeyid = session_key( - ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), - ntohl(rbufp->dstadr->sin.sin_addr.s_addr), - tkeyid, 0); + &rbufp->recv_srcadr, dstadr_sin, + tkeyid, pkeyid, 0); } } -#ifdef XXX /* temp until certificate code is mplemented */ - if (tkeyid != peer->pkeyid) - peer->flash |= TEST9; /* peer not authentic */ +#ifdef PUBKEY + + /* + * 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 (!(peer->flags & FLAG_PROVEN)) + peer->flash |= TEST11; + if (peer->flash && peer->reach) { +#ifdef DEBUG + if (debug) + printf("packet: bad autokey %03x\n", + peer->flash); #endif - peer->pkeyid = skeyid; + return; + } +#endif /* PUBKEY */ } -#endif /* MD5 */ +#endif /* AUTOKEY */ /* - * Gawdz, it's come to this. Process the dang packet. If - * something breaks and the association doesn't deserve to live, - * toss it. Be careful in active mode and return a packet - * anyway. + * 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. */ - process_packet(peer, pkt, &(rbufp->recv_time)); - if (!(peer->flags & FLAG_CONFIG) && peer->reach == 0) { - if (peer->hmode == MODE_PASSIVE) { - if (is_authentic) - fast_xmit(rbufp, MODE_PASSIVE, skeyid); - else - fast_xmit(rbufp, MODE_PASSIVE, 0); - } - unpeer(peer); - } + process_packet(peer, pkt, &rbufp->recv_time); } @@ -701,7 +833,7 @@ receive( * reasonable expectation that we will be having a long term * relationship with this host. */ -int +void process_packet( register struct peer *peer, register struct pkt *pkt, @@ -713,10 +845,13 @@ process_packet( double dtemp; l_fp p_rec, p_xmt, p_org, p_reftime; l_fp ci; - int pmode; + int pmode, pleap, pstratum; /* - * Swap header fields and keep the books. + * Swap header fields and keep the books. The books amount to + * the receive timestamp and poll interval in the header. We + * need these even if there are other problems in order to crank + * up the state machine. */ sys_processed++; peer->processed++; @@ -729,84 +864,115 @@ process_packet( NTOHL_FP(&pkt->org, &p_org); else p_org = peer->rec; - peer->rec = *recv_ts; - peer->ppoll = pkt->ppoll; - pmode = PKT_MODE(pkt->li_vn_mode); /* - * Test for old or duplicate packets (tests 1 through 3). + * Test for old, duplicate or unsynch packets (tests 1-3). */ + 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)) /* test 1 */ - peer->flash |= TEST1; /* duplicate packet */ - if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) { - if (!L_ISEQU(&peer->xmt, &p_org)) { /* test 2 */ - peer->bogusorg++; - peer->flash |= TEST2; /* bogus packet */ - } - if (L_ISZERO(&p_rec) || L_ISZERO(&p_org)) - peer->flash |= TEST3; /* unsynchronized */ - } else { - if (L_ISZERO(&p_org)) - peer->flash |= TEST3; /* unsynchronized */ + 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 */ + peer->flash |= TEST3; /* unsynch */ peer->org = p_xmt; /* - * Test for valid header (tests 5 through 10) + * 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 (peer->flash) { +#ifdef DEBUG + if (debug) + printf("packet: bad data %03x\n", + peer->flash); +#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; + } + + /* + * Test for valid peer data (tests 6-8) */ ci = p_xmt; L_SUB(&ci, &p_reftime); LFPTOD(&ci, dtemp); - if (PKT_LEAP(pkt->li_vn_mode) == LEAP_NOTINSYNC || /* test 6 */ - PKT_TO_STRATUM(pkt->stratum) >= NTP_MAXSTRATUM || - dtemp < 0) - peer->flash |= TEST6; /* peer clock unsynchronized */ - if (!(peer->flags & FLAG_CONFIG) && sys_peer != 0) { /* test 7 */ - if (PKT_TO_STRATUM(pkt->stratum) > sys_stratum) { - peer->flash |= TEST7; /* peer stratum too high */ + if (pleap == LEAP_NOTINSYNC || /* 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) { + peer->flash |= TEST7; /* bad stratum */ sys_badstratum++; } } - if (fabs(p_del) >= MAXDISPERSE /* test 8 */ - || p_disp >= MAXDISPERSE) - peer->flash |= TEST8; /* delay/dispersion too high */ - - /* - * If the packet header is invalid (tests 5 through 10), exit. - * XXX we let TEST9 sneak by until the certificate code is - * implemented, but only to mobilize the association. - */ - if (peer->flash & (TEST5 | TEST6 | TEST7 | TEST8 | TEST10)) { + if (p_del < 0 || p_disp < 0 || p_del / /* 8 */ + 2 + p_disp >= MAXDISPERSE) + peer->flash |= TEST8; /* bad peer distance */ + if (peer->flash) { #ifdef DEBUG if (debug) - printf( - "invalid packet header 0x%02x mode %d\n", - peer->flash, pmode); + printf("packet: bad header %03x\n", + peer->flash); #endif - return (0); + return; } /* - * Valid header; update our state. + * The header is valid. Capture the remaining header values and + * mark as reachable. */ - record_raw_stats(&peer->srcadr, &peer->dstadr->sin, - &p_org, &p_rec, &p_xmt, &peer->rec); - - peer->leap = PKT_LEAP(pkt->li_vn_mode); - peer->pmode = pmode; /* unspec */ - peer->stratum = PKT_TO_STRATUM(pkt->stratum); + 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 == 0) { + if (!(peer->reach)) { report_event(EVNT_REACH, peer); peer->timereachable = current_time; } peer->reach |= 1; + peer->unreach = 0; poll_update(peer, peer->hpoll); /* @@ -827,34 +993,25 @@ process_packet( 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); + p_disp = clock_phi * (peer->rec.l_ui - p_org.l_ui); /* * If running in a broadcast association, the clock offset is * (t1 - t0) corrected by the one-way delay, but we can't - * measure that directly; therefore, we start up in - * client/server mode, calculate the clock offset, using the - * engineered refinement algorithms, while also receiving - * broadcasts. When a broadcast is received in client/server - * mode, we calculate a correction factor to use after switching - * back to broadcast mode. We know NTP_SKEWFACTOR == 16, which - * accounts for the simplified ei calculation. - * - * If FLAG_MCAST2 is set, we are a broadcast/multicast client. - * If FLAG_MCAST1 is set, we haven't calculated the propagation - * delay. If hmode is MODE_CLIENT, we haven't set the local - * clock in client/server mode. Initially, we come up - * MODE_CLIENT. When the clock is first updated and FLAG_MCAST2 - * is set, we switch from MODE_CLIENT to MODE_BCLIENT. + * measure that directly. Therefore, we start up in MODE_CLIENT + * mode, set FLAG_MCAST and exchange eight messages to determine + * the clock offset. When the last message is sent, we switch to + * MODE_BCLIENT mode. The next broadcast message after that + * computes the broadcast offset and clears FLAG_MCAST. */ if (pmode == MODE_BROADCAST) { - if (peer->flags & FLAG_MCAST1) { - if (peer->hmode == MODE_BCLIENT) - peer->flags &= ~FLAG_MCAST1; + if (peer->flags & FLAG_MCAST) { LFPTOD(&ci, p_offset); peer->estbdelay = peer->offset - p_offset; - return (1); + if (peer->hmode == MODE_CLIENT) + return; + peer->flags &= ~FLAG_MCAST; } DTOLFP(peer->estbdelay, &t10); L_ADD(&ci, &t10); @@ -865,32 +1022,29 @@ process_packet( L_SUB(&t23, &t10); LFPTOD(&t23, p_del); } + p_del = max(p_del, LOGTOD(sys_precision)); LFPTOD(&ci, p_offset); - if (fabs(p_del) >= MAXDISPERSE || p_disp >= MAXDISPERSE) /* test 4 */ - peer->flash |= TEST4; /* delay/dispersion too big */ + if ((peer->rootdelay + p_del) / 2. + peer->rootdispersion + + p_disp >= MAXDISPERSE) /* 9 */ + peer->flash |= TEST9; /* bad peer distance */ /* - * If the packet data are invalid (tests 1 through 4), exit. + * If any flasher bits remain set at this point, abandon ship. + * Otherwise, forward to the clock filter. */ if (peer->flash) { #ifdef DEBUG if (debug) - printf("invalid packet data 0x%02x mode %d\n", - peer->flash, pmode); + printf("packet: bad packet data %03x\n", + peer->flash); #endif - return(1); + return; } - - - /* - * This one is valid. Mark it so, give it to clock_filter(). - */ - clock_filter(peer, p_offset, p_del, fabs(p_disp)); + clock_filter(peer, p_offset, p_del, p_disp); clock_select(); record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), peer->offset, peer->delay, peer->disp, - SQRT(peer->variance)); - return(1); + SQRT(peer->jitter)); } @@ -902,15 +1056,13 @@ clock_update(void) { u_char oleap; u_char ostratum; - int i; - struct peer *peer; /* * 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. */ - if (sys_peer == 0) + if (sys_peer == NULL) return; if (sys_peer->pollsw == FALSE || sys_peer->burst > 0) return; @@ -922,60 +1074,58 @@ clock_update(void) #endif oleap = sys_leap; ostratum = sys_stratum; - switch (local_clock(sys_peer, sys_offset, sys_epsil)) { + switch (local_clock(sys_peer, sys_offset, sys_syserr)) { - case -1: - /* - * Clock is too screwed up. Just exit for now. - */ + /* + * Clock is too screwed up. Just exit for now. + */ + case -1: report_event(EVNT_SYSFAULT, (struct peer *)0); exit(1); /*NOTREACHED*/ - case 1: - /* - * Clock was stepped. Clear filter registers - * of all peers. - */ - for (i = 0; i < HASH_SIZE; i++) { - for (peer = peer_hash[i]; peer != 0; - peer =peer->next) - peer_clear(peer); - } - NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, "synchronisation lost"); - sys_peer = 0; + /* + * Clock was stepped. Flush all time values of all peers. + */ + case 1: + clear_all(); + sys_peer = NULL; sys_stratum = STRATUM_UNSPEC; + sys_poll = NTP_MINPOLL; + NLOG(NLOG_SYNCSTATUS) + msyslog(LOG_INFO, "synchronisation lost"); report_event(EVNT_CLOCKRESET, (struct peer *)0); break; - default: - /* - * Update the system stratum, leap bits, root delay, - * root dispersion, reference ID and reference time. We - * also update select dispersion and max frequency - * error. - */ + /* + * Update the system stratum, leap bits, root delay, root + * dispersion, reference ID and reference time. We also update + * select dispersion and max frequency error. If the leap + * changes, we gotta reroll the keys. + */ + default: sys_stratum = sys_peer->stratum + 1; if (sys_stratum == 1) sys_refid = sys_peer->refid; else sys_refid = sys_peer->srcadr.sin_addr.s_addr; sys_reftime = sys_peer->rec; - sys_rootdelay = sys_peer->rootdelay + - fabs(sys_peer->delay); + sys_rootdelay = sys_peer->rootdelay + sys_peer->delay; sys_leap = leap_consensus; } - if (oleap != sys_leap) + if (oleap == LEAP_NOTINSYNC) { report_event(EVNT_SYNCCHG, (struct peer *)0); +#ifdef AUTOKEY + expire_all(); +#endif /* AUTOKEY */ + } if (ostratum != sys_stratum) report_event(EVNT_PEERSTCHG, (struct peer *)0); } /* - * poll_update - update peer poll interval. See Section 3.4.9 of the - * spec. + * poll_update - update peer poll interval */ void poll_update( @@ -983,46 +1133,83 @@ poll_update( int hpoll ) { - long update; +#ifdef AUTOKEY + int oldpoll; +#endif /* AUTOKEY */ /* - * The wiggle-the-poll-interval dance. Broadcasters dance only - * the minpoll beat. Reference clock partners sit this one out. - * Dancers surviving the clustering algorithm beat to the system - * clock. Broadcast clients are usually lead by their broadcast - * partner, but faster in the initial mating dance. + * A little foxtrot to determine what controls the poll + * interval. If the peer is reachable, but the last four polls + * have not been answered, use the minimum. If declared + * truechimer, use the system poll interval. This allows each + * association to ramp up the poll interval for useless sources + * and to clamp it to the minimum when first starting up. */ - if (peer->hmode == MODE_BROADCAST) { +#ifdef AUTOKEY + oldpoll = peer->kpoll; +#endif /* AUTOKEY */ + if (hpoll > peer->maxpoll) + peer->hpoll = peer->maxpoll; + else if (hpoll < peer->minpoll) peer->hpoll = peer->minpoll; - } else if (peer->flags & FLAG_SYSPEER) { - peer->hpoll = sys_poll; - } else { - if (hpoll > peer->maxpoll) - peer->hpoll = peer->maxpoll; - else if (hpoll < peer->minpoll) - peer->hpoll = peer->minpoll; - else - peer->hpoll = hpoll; - } + else + peer->hpoll = 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. + * + * 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. + */ if (peer->burst > 0) { if (peer->nextdate != current_time) return; - if (peer->flags & FLAG_REFCLOCK) +#ifdef REFCLOCK + else if (peer->flags & FLAG_REFCLOCK) peer->nextdate++; +#endif else if (peer->reach & 0x1) peer->nextdate += RANDPOLL(BURST_INTERVAL2); else peer->nextdate += RANDPOLL(BURST_INTERVAL1); + } else if (peer->cast_flags & MDF_ACAST) { + if (sys_survivors < NTP_MINCLOCK) + peer->kpoll = peer->hpoll; + else + peer->kpoll = peer->hpoll + 3; + peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); } else { - update = max(min(peer->ppoll, peer->hpoll), + peer->kpoll = max(min(peer->ppoll, peer->hpoll), peer->minpoll); - peer->nextdate = peer->outdate + RANDPOLL(update); + peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); } + if (peer->nextdate < current_time) + peer->nextdate = current_time; +#ifdef AUTOKEY + /* + * Bit of crass arrogance at this point. If the poll interval + * has changed and we have a keylist, the lifetimes in the + * keylist are probably bogus. In this case purge the keylist + * and regenerate it later. + */ + if (peer->kpoll != oldpoll) + key_expire(peer); +#endif /* AUTOKEY */ #ifdef DEBUG if (debug > 1) - printf("poll_update: at %lu %s poll %d burst %d last %lu next %lu\n", - current_time, ntoa(&peer->srcadr), hpoll, - peer->burst, peer->outdate, peer->nextdate); + printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n", + current_time, ntoa(&peer->srcadr), peer->flags, + peer->kpoll, peer->burst, peer->outdate, + peer->nextdate); #endif } @@ -1036,28 +1223,72 @@ peer_clear( ) { register int i; + u_long u_rand; + /* + * If cryptographic credentials have been acquired, toss them to + * Valhalla. Note that autokeys are ephemeral, in that they are + * tossed immediately upon use. Therefore, the keylist can be + * purged anytime without needing to preserve random keys. Note + * that, if the peer is purged, the cryptographic variables are + * 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 + 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 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. + */ + if (peer->cast_flags & MDF_BCLNT) { + peer->flags |= FLAG_MCAST; + peer->hmode = MODE_CLIENT; + } + peer->flags &= ~(FLAG_AUTOKEY | FLAG_ASSOC); peer->estbdelay = sys_bdelay; - peer->hpoll = peer->minpoll; + peer->hpoll = peer->kpoll = peer->minpoll; + peer->ppoll = peer->maxpoll; peer->pollsw = FALSE; - peer->variance = MAXDISPERSE; + peer->jitter = MAXDISPERSE; peer->epoch = current_time; +#ifdef REFCLOCK + if (!(peer->flags & FLAG_REFCLOCK)) { + peer->leap = LEAP_NOTINSYNC; + peer->stratum = STRATUM_UNSPEC; + } +#endif for (i = 0; i < NTP_SHIFT; i++) { peer->filter_order[i] = i; peer->filter_disp[i] = MAXDISPERSE; peer->filter_epoch[i] = current_time; } - poll_update(peer, peer->minpoll); /* - * Since we have a chance to correct possible funniness in - * our selection of interfaces on a multihomed host, do so - * by setting us to no particular interface. - * WARNING: do so only in non-broadcast mode! + * Randomize the first poll over 1-16s to avoid bunching. */ - if (peer->hmode != MODE_BROADCAST) - peer->dstadr = any_interface; + peer->update = peer->outdate = current_time; + u_rand = RANDOM; + peer->nextdate = current_time + (u_rand & ((1 << + BURST_INTERVAL1) - 1)) + 1; } @@ -1067,130 +1298,172 @@ peer_clear( */ void clock_filter( - register struct peer *peer, - double sample_offset, - double sample_delay, - double sample_disp + register struct peer *peer, /* peer structure pointer */ + double sample_offset, /* clock offset */ + double sample_delay, /* roundtrip delay */ + double sample_disp /* dispersion */ ) { - register int i, j, k, n = 0; - register u_char *ord; - double distance[NTP_SHIFT]; - double x, y, z, off; + double dst[NTP_SHIFT]; /* distance vector */ + int ord[NTP_SHIFT]; /* index vector */ + register int i, j, k, m; + double dsp, jit, dtemp, etemp; /* - * Update error bounds and calculate distances. Also initialize - * sort index vector. + * Shift the new sample into the register and discard the oldest + * one. The new offset and delay come directly from the + * timestamp calculations. The dispersion grows from the last + * outbound packet or reference clock update to the present time + * and increased by the sum of the peer precision and the system + * precision. The delay can sometimes swing negative due to + * frequency skew, so it is clamped non-negative. */ - x = CLOCK_PHI * (current_time - peer->update); - peer->update = current_time; - ord = peer->filter_order; + dsp = min(LOGTOD(peer->precision) + LOGTOD(sys_precision) + + sample_disp, MAXDISPERSE); j = peer->filter_nextpt; - for (i = 0; i < NTP_SHIFT; i++) { - peer->filter_disp[j] += x; - if (peer->filter_disp[j] > MAXDISPERSE) - peer->filter_disp[j] = MAXDISPERSE; - distance[i] = fabs(peer->filter_delay[j]) / 2 + - peer->filter_disp[j]; - ord[i] = j; - if (--j < 0) - j += NTP_SHIFT; - } + 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; /* - * Insert the new sample at the beginning of the register. + * Update dispersions since the last update and at the same + * time initialize the distance and index lists. The distance + * list uses a compound metric. If the sample is valid and + * younger than the minimum Allan intercept, use delay; + * otherwise, use biased dispersion. */ - peer->filter_offset[peer->filter_nextpt] = sample_offset; - peer->filter_delay[peer->filter_nextpt] = sample_delay; - x = LOGTOD(peer->precision) + LOGTOD(sys_precision) + - sample_disp; - peer->filter_disp[peer->filter_nextpt] = min(x, MAXDISPERSE); - peer->filter_epoch[peer->filter_nextpt] = current_time; - distance[0] = min(x + fabs(sample_delay) / 2, MAXDISTANCE); - peer->filter_nextpt++; - if (peer->filter_nextpt >= NTP_SHIFT) - peer->filter_nextpt = 0; + dtemp = clock_phi * (current_time - peer->update); + peer->update = current_time; + for (i = NTP_SHIFT - 1; i >= 0; i--) { + if (i != 0) { + peer->filter_disp[j] += dtemp; + if (peer->filter_disp[j] > MAXDISPERSE) + 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]; + ord[i] = j; + j++; j %= NTP_SHIFT; + } - /* - * Sort the samples in the register by distance. The winning - * sample will be in ord[0]. Sort the samples only if they - * are younger than the Allen intercept. + /* + * Sort the samples in both lists by distance. */ - y = min(allan_xpt, NTP_SHIFT * ULOGTOD(sys_poll)); - for (n = 0; n < NTP_SHIFT && current_time - - peer->filter_epoch[ord[n]] <= y; n++) { - for (j = 0; j < n; j++) { - if (distance[j] > distance[n]) { - x = distance[j]; + for (i = 1; i < NTP_SHIFT; i++) { + for (j = 0; j < i; j++) { + if (dst[j] > dst[i]) { k = ord[j]; - distance[j] = distance[n]; - ord[j] = ord[n]; - distance[n] = x; - ord[n] = k; + ord[j] = ord[i]; + ord[i] = k; + etemp = dst[j]; + dst[j] = dst[i]; + dst[i] = etemp; } } - } + } + + /* + * Copy the index list to the association structure so ntpq + * can see it later. Prune the distance list to samples less + * than MAXDISTANCE, but keep at least two valid samples for + * jitter calculation. + */ + m = 0; + for (i = 0; i < NTP_SHIFT; i++) { + peer->filter_order[i] = ord[i]; + if (dst[i] >= MAXDISPERSE || (m >= 2 && dst[i] >= + MAXDISTANCE)) + continue; + m++; + } /* - * Compute the error bound and standard error. + * Compute the dispersion and jitter squares. The dispersion + * is weighted exponentially by NTP_FWEIGHT (0.5) so it is + * 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. */ - x = y = z = off = 0.; + jit = 0; + peer->disp = 0; + k = ord[0]; for (i = NTP_SHIFT - 1; i >= 0; i--) { - x = NTP_FWEIGHT * (x + peer->filter_disp[ord[i]]); - if (i < n) { - z += 1. / distance[i]; - off += peer->filter_offset[ord[i]] / - distance[i]; - y += DIFF(peer->filter_offset[ord[i]], - peer->filter_offset[ord[0]]); - } + + j = ord[i]; + peer->disp = NTP_FWEIGHT * (peer->disp + + peer->filter_disp[j]); + if (i < m) + jit += DIFF(peer->filter_offset[j], + peer->filter_offset[k]); } - peer->delay = peer->filter_delay[ord[0]]; - peer->variance = min(y / n, MAXDISPERSE); - peer->disp = min(x, MAXDISPERSE); - peer->epoch = current_time; - x = peer->offset; - if (peer->flags & FLAG_BURST) - peer->offset = off / z; - else - peer->offset = peer->filter_offset[ord[0]]; + + /* + * If no acceptable samples remain in the shift register, + * quietly tiptoe home leaving only the dispersion. Otherwise, + * save the offset, delay and jitter average. Note the jitter + * must not be less than the system precision. + */ + if (m == 0) + return; + etemp = peer->offset; + peer->offset = peer->filter_offset[k]; + peer->delay = peer->filter_delay[k]; + if (m > 1) + jit /= m - 1; + peer->jitter = max(jit, SQUARE(LOGTOD(sys_precision))); /* * A new sample is useful only if it is younger than the last * one used. */ - if (peer->filter_epoch[ord[0]] > peer->epoch) { + if (peer->filter_epoch[k] <= peer->epoch) { #ifdef DEBUG if (debug) printf("clock_filter: discard %lu\n", - peer->filter_epoch[ord[0]] - peer->epoch); + peer->epoch - peer->filter_epoch[k]); #endif return; } /* - * If the offset exceeds the dispersion 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 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, + * consider the update a popcorn spike and ignore it. */ - if (fabs(x - peer->offset) > CLOCK_SGATE && - peer->filter_epoch[ord[0]] - peer->epoch < (1 << - (sys_poll + 1))) { + if (m > 1 && fabs(peer->offset - etemp) > SQRT(peer->jitter) * + CLOCK_SGATE && peer->filter_epoch[k] - peer->epoch < + (1 << (sys_poll + 1))) { #ifdef DEBUG if (debug) - printf("clock_filter: popcorn spike %.6f\n", x); + printf("clock_filter: n %d popcorn spike %.6f jitter %.6f\n", + m, peer->offset, SQRT(peer->jitter)); #endif return; } - peer->epoch = peer->filter_epoch[ord[0]]; + + /* + * The mitigated sample statistics are saved for later + * processing, but can be processed only once. + */ + peer->epoch = peer->filter_epoch[k]; peer->pollsw = TRUE; #ifdef DEBUG if (debug) printf( - "clock_filter: offset %.6f delay %.6f disp %.6f std %.6f, age %lu\n", - peer->offset, peer->delay, peer->disp, - SQRT(peer->variance), current_time - peer->epoch); + "clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f, age %lu\n", + m, peer->offset, peer->delay, peer->disp, + SQRT(peer->jitter), peer->update - peer->epoch); #endif } @@ -1202,35 +1475,34 @@ void clock_select(void) { register struct peer *peer; - int i; - int nlist, nl3; + int i, j, k, n; + int nreach, nlist, nl3; double d, e, f; - int j; - int n; - int allow, found, k; + int allow, found, sw; double high, low; double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; struct peer *osys_peer; - struct peer *typeacts = 0; - struct peer *typelocal = 0; - struct peer *typepps = 0; - struct peer *typeprefer = 0; - struct peer *typesystem = 0; + struct peer *typeacts = NULL; + struct peer *typelocal = NULL; + struct peer *typepps = NULL; + struct peer *typesystem = NULL; static int list_alloc = 0; static struct endpoint *endpoint = NULL; - static int *index = NULL; + static int *indx = NULL; static struct peer **peer_list = NULL; static u_int endpoint_size = 0; - static u_int index_size = 0; + static u_int indx_size = 0; static u_int peer_list_size = 0; /* - * Initialize. If a prefer peer does not survive this thing, - * the pps_update switch will remain zero. + * Initialize and create endpoint, index and peer lists big + * enough to handle all associations. */ - pps_update = 0; - nlist = 0; + osys_peer = sys_peer; + sys_peer = NULL; + sys_prefer = NULL; + nreach = nlist = 0; low = 1e9; high = -1e9; for (n = 0; n < HASH_SIZE; n++) @@ -1238,49 +1510,58 @@ clock_select(void) if (nlist > list_alloc) { if (list_alloc > 0) { free(endpoint); - free(index); + free(indx); free(peer_list); } while (list_alloc < nlist) { list_alloc += 5; - endpoint_size += 5 * 3 * sizeof *endpoint; - index_size += 5 * 3 * sizeof *index; - peer_list_size += 5 * sizeof *peer_list; + endpoint_size += 5 * 3 * sizeof(*endpoint); + indx_size += 5 * 3 * sizeof(*indx); + peer_list_size += 5 * sizeof(*peer_list); } endpoint = (struct endpoint *)emalloc(endpoint_size); - index = (int *)emalloc(index_size); + indx = (int *)emalloc(indx_size); peer_list = (struct peer **)emalloc(peer_list_size); } /* - * This first chunk of code is supposed to go through all - * peers we know about to find the peers which are most likely - * to succeed. We run through the list doing the sanity checks - * and trying to insert anyone who looks okay. + * Initially, we populate the island with all the rifraff peers + * that happen to be lying around. Those with seriously + * defective clocks are immediately booted off the island. Then, + * 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. */ nlist = nl3 = 0; /* none yet */ for (n = 0; n < HASH_SIZE; n++) { - for (peer = peer_hash[n]; peer != 0; peer = peer->next) { + for (peer = peer_hash[n]; peer != NULL; peer = + peer->next) { peer->flags &= ~FLAG_SYSPEER; peer->status = CTL_PST_SEL_REJECT; - if (peer->flags & FLAG_NOSELECT) - continue; /* noselect (survey) */ - if (peer->reach == 0) - continue; /* unreachable */ - if (peer->stratum > 1 && peer->refid == - peer->dstadr->sin.sin_addr.s_addr) - continue; /* sync loop */ - if (root_distance(peer) >= MAXDISTANCE + 2 * - CLOCK_PHI * ULOGTOD(sys_poll)) { - peer->seldisptoolarge++; - continue; /* noisy or broken */ - } /* - * Don't allow the local-clock or acts drivers + * 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))) + continue; + + /* + * Don't allow the local clock or modem drivers * in the kitchen at this point, unless the * prefer peer. Do that later, but only if - * nobody else is around. + * nobody else is around. These guys are all + * configured, so we never throw them away. */ if (peer->refclktype == REFCLK_LOCALCLOCK #if defined(VMS) && defined(VMS_LOCALUNIT) @@ -1299,9 +1580,11 @@ clock_select(void) } /* - * If we get this far, we assume the peer is - * acceptable. + * If we get this far, the peer can stay on the + * island, but does not yet have the immunity + * idol. */ + nreach++; peer->status = CTL_PST_SEL_SANE; peer_list[nlist++] = peer; @@ -1313,40 +1596,41 @@ clock_select(void) f = root_distance(peer); e = e + f; for (i = nl3 - 1; i >= 0; i--) { - if (e >= endpoint[index[i]].val) + if (e >= endpoint[indx[i]].val) break; - index[i + 3] = index[i]; + indx[i + 3] = indx[i]; } - index[i + 3] = nl3; + indx[i + 3] = nl3; endpoint[nl3].type = 1; endpoint[nl3++].val = e; e = e - f; /* Center point */ for ( ; i >= 0; i--) { - if (e >= endpoint[index[i]].val) + if (e >= endpoint[indx[i]].val) break; - index[i + 2] = index[i]; + indx[i + 2] = indx[i]; } - index[i + 2] = nl3; + indx[i + 2] = nl3; endpoint[nl3].type = 0; endpoint[nl3++].val = e; e = e - f; /* Lower end */ for ( ; i >= 0; i--) { - if (e >= endpoint[index[i]].val) + if (e >= endpoint[indx[i]].val) break; - index[i + 1] = index[i]; + indx[i + 1] = indx[i]; } - index[i + 1] = nl3; + indx[i + 1] = nl3; endpoint[nl3].type = -1; endpoint[nl3++].val = e; } } #ifdef DEBUG - if (debug > 1) + if (debug > 2) for (i = 0; i < nl3; i++) - printf("select: endpoint %2d %.6f\n", - endpoint[index[i]].type, endpoint[index[i]].val); + printf("select: endpoint %2d %.6f\n", + endpoint[indx[i]].type, + endpoint[indx[i]].val); #endif i = 0; j = nl3 - 1; @@ -1355,30 +1639,30 @@ clock_select(void) while (allow > 0) { allow--; for (n = 0; i <= j; i++) { - n += endpoint[index[i]].type; + n += endpoint[indx[i]].type; if (n < 0) break; - if (endpoint[index[i]].type == 0) + if (endpoint[indx[i]].type == 0) found++; } for (n = 0; i <= j; j--) { - n += endpoint[index[j]].type; + n += endpoint[indx[j]].type; if (n > 0) break; - if (endpoint[index[j]].type == 0) + if (endpoint[indx[j]].type == 0) found++; } if (found > allow) break; - low = endpoint[index[i++]].val; - high = endpoint[index[j--]].val; + low = endpoint[indx[i++]].val; + high = endpoint[indx[j--]].val; } /* - * If no survivors remain at this point, check if the acts or - * local clock drivers have been found. If so, nominate one of - * them as the only survivor. Otherwise, give up and declare us - * unsynchronized. + * 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. */ if ((allow << 1) >= nlist) { if (typeacts != 0) { @@ -1390,35 +1674,45 @@ clock_select(void) peer_list[0] = typelocal; nlist = 1; } else { - if (sys_peer != 0) { - report_event(EVNT_PEERSTCHG, - (struct peer *)0); + if (osys_peer != NULL) { + sys_poll = NTP_MINPOLL; NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, + msyslog(LOG_INFO, "synchronisation lost"); + report_event(EVNT_PEERSTCHG, + (struct peer *)0); } - sys_peer = 0; + sys_survivors = 0; +#ifdef AUTOKEY + resetmanycast(); +#endif /* AUTOKEY */ return; } } #ifdef DEBUG - if (debug > 1) + if (debug > 2) printf("select: low %.6f high %.6f\n", low, high); #endif /* - * Clustering algorithm. Process intersection list to discard - * outlyers. Construct candidate list in cluster order - * determined by the sum of peer synchronization distance plus - * scaled stratum. We must find at least one peer. + * 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. */ j = 0; for (i = 0; i < nlist; i++) { peer = peer_list[i]; - if (nlist > 1 && (low >= peer->offset || - peer->offset >= high)) + if (nlist > 1 && (low >= peer->offset || peer->offset >= + high)) { + if (!(peer->flags & FLAG_CONFIG)) + unpeer(peer); continue; - peer->status = CTL_PST_SEL_CORRECT; + } + peer->status = CTL_PST_SEL_DISTSYSPEER; d = root_distance(peer) + peer->stratum * MAXDISPERSE; if (j >= NTP_MAXCLOCK) { if (d >= synch[j - 1]) @@ -1429,77 +1723,98 @@ clock_select(void) for (k = j; k > 0; k--) { if (d >= synch[k - 1]) break; - synch[k] = synch[k - 1]; peer_list[k] = peer_list[k - 1]; + error[k] = error[k - 1]; + synch[k] = synch[k - 1]; } peer_list[k] = peer; + error[k] = peer->jitter; synch[k] = d; j++; } nlist = j; + for (i = 0; i < nlist; i++) { + peer_list[i]->status = CTL_PST_SEL_SELCAND; #ifdef DEBUG - if (debug > 1) - for (i = 0; i < nlist; i++) + if (debug > 2) printf("select: %s distance %.6f\n", ntoa(&peer_list[i]->srcadr), synch[i]); #endif + } /* - * Now, prune outlyers by root dispersion. Continue as long as - * there are more than NTP_MINCLOCK survivors and the minimum - * select dispersion is greater than the maximum peer - * dispersion. Stop if we are about to discard a prefer peer. + * 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 + * 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. */ - for (i = 0; i < nlist; i++) { - peer = peer_list[i]; - error[i] = peer->variance; - if (i < NTP_CANCLOCK) - peer->status = CTL_PST_SEL_SELCAND; - else - peer->status = CTL_PST_SEL_DISTSYSPEER; - } while (1) { - sys_maxd = 0; - d = error[0]; - for (k = i = nlist - 1; i >= 0; i--) { - double sdisp = 0; - - for (j = nlist - 1; j > 0; j--) { - sdisp = NTP_SWEIGHT * (sdisp + - DIFF(peer_list[i]->offset, - peer_list[j]->offset)); + d = 1e9; + e = -1e9; + k = 0; + for (i = 0; i < nlist; i++) { + + if (error[i] < d) + d = error[i]; + f = 0; + if (nlist > 1) { + for (j = 0; j < nlist; j++) + f += DIFF(peer_list[j]->offset, + peer_list[i]->offset); + f /= nlist - 1; } - if (sdisp > sys_maxd) { - sys_maxd = sdisp; + f = max(f, SQUARE(LOGTOD(sys_precision))); + if (f * synch[i] > e) { + sys_selerr = f; + e = f * synch[i]; k = i; } - if (error[i] < d) - d = error[i]; } #ifdef DEBUG - if (debug > 1) + if (debug > 2) printf( "select: survivors %d select %.6f peer %.6f\n", - nlist, SQRT(sys_maxd), SQRT(d)); + k, SQRT(sys_selerr), SQRT(d)); #endif - if (nlist <= NTP_MINCLOCK || sys_maxd <= d || - peer_list[k]->flags & FLAG_PREFER) + if (nlist <= NTP_MINCLOCK || sys_selerr <= d || + peer_list[k]->flags & FLAG_PREFER) break; + if (!(peer_list[k]->flags & FLAG_CONFIG)) + unpeer(peer_list[k]); for (j = k + 1; j < nlist; j++) { peer_list[j - 1] = peer_list[j]; error[j - 1] = error[j]; } 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 > 1) { + 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); + ntoa(&peer_list[i]->srcadr), + peer_list[i]->offset, synch[i], + peer_list[i]->pollsw); } #endif @@ -1518,27 +1833,30 @@ clock_select(void) * him. We 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. */ + if (osys_peer == NULL && 2 * nlist < min(nreach, NTP_MINCLOCK)) + return; leap_consensus = 0; for (i = nlist - 1; i >= 0; i--) { - peer_list[i]->status = CTL_PST_SEL_SYNCCAND; - peer_list[i]->flags |= FLAG_SYSPEER; - poll_update(peer_list[i], peer_list[i]->hpoll); - if (peer_list[i]->stratum == peer_list[0]->stratum) { - leap_consensus |= peer_list[i]->leap; - if (peer_list[i]->refclktype == REFCLK_ATOM_PPS) - typepps = peer_list[i]; - if (peer_list[i] == sys_peer) - typesystem = peer_list[i]; - if (peer_list[i]->flags & FLAG_PREFER) { - typeprefer = peer_list[i]; - if (fabs(typeprefer->offset) < - clock_max) - pps_update = 1; - } - } else { - if (peer_list[i] == sys_peer) - sys_peer = 0; + peer = peer_list[i]; + peer->status = CTL_PST_SEL_SYNCCAND; + 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; } } @@ -1554,38 +1872,45 @@ clock_select(void) * stated. Note that all of these must be at the lowest stratum, * i.e., the stratum of the head of the survivor list. */ - osys_peer = sys_peer; - if (typeprefer && (typeprefer->refclktype == REFCLK_LOCALCLOCK - || typeprefer->sstclktype == CTL_SST_TS_TELEPHONE || - !typepps)) { - sys_peer = typeprefer; + if (sys_prefer) + sw = sys_prefer->refclktype == REFCLK_LOCALCLOCK || + sys_prefer->sstclktype == CTL_SST_TS_TELEPHONE || + !typepps; + else + sw = 0; + if (sw) { + sys_peer = sys_prefer; sys_peer->status = CTL_PST_SEL_SYSPEER; sys_offset = sys_peer->offset; - sys_epsil = sys_peer->variance; + sys_syserr = sys_peer->jitter; #ifdef DEBUG if (debug > 1) printf("select: prefer offset %.6f\n", sys_offset); #endif - } else if (typepps && pps_update) { + } else if (typepps) { sys_peer = typepps; sys_peer->status = CTL_PST_SEL_PPS; sys_offset = sys_peer->offset; - sys_epsil = sys_peer->variance; + sys_syserr = sys_peer->jitter; if (!pps_control) - NLOG(NLOG_SYSEVENT) /* conditional syslog */ - msyslog(LOG_INFO, "pps sync enabled"); + NLOG(NLOG_SYSEVENT) + msyslog(LOG_INFO, + "pps sync enabled"); pps_control = current_time; #ifdef DEBUG if (debug > 1) - printf("select: pps offset %.6f\n", sys_offset); + printf("select: pps offset %.6f\n", + sys_offset); #endif } else { - if (!typesystem) + if (typesystem) + sys_peer = osys_peer; + else sys_peer = peer_list[0]; sys_peer->status = CTL_PST_SEL_SYSPEER; sys_offset = clock_combine(peer_list, nlist); - sys_epsil = sys_peer->variance + sys_maxd; + sys_syserr = sys_peer->jitter + sys_selerr; #ifdef DEBUG if (debug > 1) printf("select: combine offset %.6f\n", @@ -1625,10 +1950,14 @@ root_distance( struct peer *peer ) { - return ((fabs(peer->delay) + peer->rootdelay) / 2 + - peer->rootdispersion + peer->disp + - SQRT(peer->variance) + CLOCK_PHI * (current_time - - peer->update)); + /* + * Careful squeak here. The value returned must be greater than + * zero blamed on the peer jitter, which must be at least the + * square of sys_precision. + */ + return ((peer->rootdelay + peer->delay) / 2 + + peer->rootdispersion + peer->disp + clock_phi * + (current_time - peer->update) + SQRT(peer->jitter)); } /* @@ -1639,279 +1968,518 @@ peer_xmit( struct peer *peer /* peer structure pointer */ ) { - struct pkt xpkt; - int find_rtt = (peer->cast_flags & MDF_MCAST) && - peer->hmode != MODE_BROADCAST; - int sendlen; + struct pkt xpkt; /* transmit packet */ + int sendlen, authlen; + keyid_t xkeyid; /* transmit key ID */ + l_fp xmt_tx; /* - * Initialize protocol fields. + * Initialize transmit packet header fields. */ - xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, - peer->version, peer->hmode); + xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, peer->version, + peer->hmode); xpkt.stratum = STRATUM_TO_PKT(sys_stratum); xpkt.ppoll = peer->hpoll; xpkt.precision = sys_precision; xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); - xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion + - LOGTOD(sys_precision))); + xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion)); xpkt.refid = sys_refid; HTONL_FP(&sys_reftime, &xpkt.reftime); HTONL_FP(&peer->org, &xpkt.org); HTONL_FP(&peer->rec, &xpkt.rec); /* - * Authenticate the packet if enabled and either configured or - * the previous packet was authenticated. If for some reason the - * key associated with the key identifier is not in the key - * cache, then honk key zero. + * If the received packet contains a MAC, the transmitted packet + * is authenticated and contains a MAC. If not, the transmitted + * packet is not authenticated. + * + * In the current I/O semantics the default interface is set + * until after receiving a packet and setting the right + * interface. So, the first packet goes out unauthenticated. + * That's why the really icky test next is here. */ sendlen = LEN_PKT_NOMAC; - if (peer->flags & FLAG_AUTHENABLE) { - u_long xkeyid; - l_fp xmt_tx; + if (!(peer->flags & FLAG_AUTHENABLE)) { + get_systime(&peer->xmt); + HTONL_FP(&peer->xmt, &xpkt.xmt); + sendpkt(&peer->srcadr, peer->dstadr, 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); +#endif + return; + } + + /* + * The received packet contains a MAC, so the transmitted packet + * must be authenticated. If autokey is enabled, fuss with the + * various modes; otherwise, private key cryptography is used. + */ +#ifdef AUTOKEY + if ((peer->flags & FLAG_SKEY)) { + u_int cmmd; /* - * Transmit encrypted packet compensated for the - * encryption delay. + * The Public Key Dance (PKD): Cryptographic credentials + * are contained in extension fields, each including a + * 4-octet length/code word followed by a 4-octet + * association ID and optional additional data. Optional + * data includes a 4-octet data length field followed by + * the data itself. Request messages are sent from a + * configured association; response messages can be sent + * from a configured association or can take the fast + * path without ever matching an association. Response + * messages have the same code as the request, but have + * a response bit and possibly an error bit set. In this + * implementation, a message may contain no more than + * one command and no more than one response. + * + * Cryptographic session keys include both a public and + * a private componet. Request and response messages + * using extension fields are always sent with the + * private component set to zero. Packets without + * extension fields indlude the private component when + * the session key is generated. */ -#ifdef MD5 - if (peer->flags & FLAG_SKEY) { - + while (1) { + /* - * In autokey mode, allocate and initialize a - * key list if not already done. Then, use the - * list in inverse order, discarding keys once - * used. Keep the latest key around until the - * next one, so clients can use client/server - * packets to compute propagation delay. Note we - * have to wait until the receive side of the - * socket is bound and the server address - * confirmed. + * Allocate and initialize a keylist if not + * already done. Then, use the list in inverse + * order, discarding keys once used. Keep the + * latest key around until the next one, so + * clients can use client/server packets to + * compute propagation delay. + * + * Note that once a key is used from the list, + * it is retained in the key cache until the + * next key is used. This is to allow a client + * to retrieve the encrypted session key + * identifier to verify authenticity. + * + * If for some reason a key is no longer in the + * key cache, a birthday has happened and the + * pseudo-random sequence is probably broken. In + * that case, purge the keylist and regenerate + * it. */ - if (ntohl(peer->dstadr->sin.sin_addr.s_addr) == - 0 && - ntohl(peer->dstadr->bcast.sin_addr.s_addr) == 0) - peer->keyid = 0; - else { - if (peer->keylist == 0) { - make_keylist(peer); - } else { - authtrust(peer->keylist[peer->keynumber], 0); - if (peer->keynumber == 0) - make_keylist(peer); - else { - peer->keynumber--; - xkeyid = peer->keylist[peer->keynumber]; - if (!authistrusted(xkeyid)) - make_keylist(peer); - } - } - peer->keyid = peer->keylist[peer->keynumber]; - xpkt.keyid1 = htonl(2 * sizeof(u_int32)); - xpkt.keyid2 = htonl(sys_private); - sendlen += 2 * sizeof(u_int32); - } + if (peer->keynumber == 0) + make_keylist(peer, peer->dstadr); + else + peer->keynumber--; + xkeyid = peer->keylist[peer->keynumber]; + if (authistrusted(xkeyid)) + break; + else + key_expire(peer); } -#endif /* MD5 */ - xkeyid = peer->keyid; - get_systime(&peer->xmt); - L_ADD(&peer->xmt, &sys_authdelay); - HTONL_FP(&peer->xmt, &xpkt.xmt); - sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, - sendlen); - get_systime(&xmt_tx); - sendpkt(&peer->srcadr, find_rtt ? any_interface : - peer->dstadr, ((peer->cast_flags & MDF_MCAST) && - !find_rtt) ? ((peer->cast_flags & MDF_ACAST) ? -7 : - peer->ttl) : -7, &xpkt, sendlen); + peer->keyid = xkeyid; + switch (peer->hmode) { /* - * Calculate the encryption delay. Keep the minimum over - * the latest two samples. + * 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. */ - L_SUB(&xmt_tx, &peer->xmt); - L_ADD(&xmt_tx, &sys_authdelay); - sys_authdly[1] = sys_authdly[0]; - sys_authdly[0] = xmt_tx.l_uf; - if (sys_authdly[0] < sys_authdly[1]) - sys_authdelay.l_uf = sys_authdly[0]; - else - sys_authdelay.l_uf = sys_authdly[1]; - peer->sent++; -#ifdef DEBUG - if (debug) - printf( - "transmit: at %ld to %s mode %d keyid %08lx index %d\n", - current_time, ntoa(&peer->srcadr), - peer->hmode, xkeyid, peer->keynumber); -#endif - } else { + case MODE_BROADCAST: + if (peer->flags & FLAG_ASSOC) + cmmd = CRYPTO_AUTO | CRYPTO_RESP; + else + cmmd = CRYPTO_ASSOC | CRYPTO_RESP; + sendlen += crypto_xmit((u_int32 *)&xpkt, + sendlen, cmmd, 0, peer->associd); + break; + /* - * Transmit non-authenticated packet. + * 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. */ - get_systime(&(peer->xmt)); - HTONL_FP(&peer->xmt, &xpkt.xmt); - sendpkt(&(peer->srcadr), find_rtt ? any_interface : - peer->dstadr, ((peer->cast_flags & MDF_MCAST) && - !find_rtt) ? ((peer->cast_flags & MDF_ACAST) ? -7 : - peer->ttl) : -8, &xpkt, sendlen); - peer->sent++; + 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->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; + 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 + * 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. + */ + 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->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) && + (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; + break; + } + + /* + * If extension fields are present, we must use a + * 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 */ + 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; + return; + } + sendlen += authlen; +#ifdef AUTOKEY + if (xkeyid > NTP_MAXKEY) + authtrust(xkeyid, 0); +#endif /* AUTOKEY */ + get_systime(&xmt_tx); + if (sendlen > sizeof(xpkt)) { + msyslog(LOG_ERR, "buffer overflow %u", sendlen); + exit(-1); + } + sendpkt(&peer->srcadr, peer->dstadr, peer->ttl, &xpkt, sendlen); + + /* + * Calculate the encryption delay. Keep the minimum over + * the latest two samples. + */ + L_SUB(&xmt_tx, &peer->xmt); + L_ADD(&xmt_tx, &sys_authdelay); + sys_authdly[1] = sys_authdly[0]; + sys_authdly[0] = xmt_tx.l_uf; + if (sys_authdly[0] < sys_authdly[1]) + sys_authdelay.l_uf = sys_authdly[0]; + else + sys_authdelay.l_uf = sys_authdly[1]; + peer->sent++; +#ifdef AUTOKEY #ifdef DEBUG - if (debug) - printf("transmit: at %ld to %s mode %d\n", - current_time, ntoa(&peer->srcadr), - peer->hmode); + 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); #endif - } +#else +#ifdef DEBUG + if (debug) + 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); +#endif +#endif /* AUTOKEY */ } + /* - * fast_xmit - Send packet for nonpersistent association. + * fast_xmit - Send packet for nonpersistent association. Note that + * neither the source or destination can be a broadcast address. */ static void fast_xmit( struct recvbuf *rbufp, /* receive packet pointer */ int xmode, /* transmit mode */ - u_long xkeyid /* transmit key ID */ + keyid_t xkeyid, /* transmit key ID */ + int mask /* restrict mask */ ) { - struct pkt xpkt; - struct pkt *rpkt; - int sendlen; - l_fp xmt_ts; + 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; /* - * Initialize transmit packet header fields in the receive - * buffer provided. We leave some fields intact as received. + * Initialize transmit packet header fields from the receive + * buffer provided. We leave some fields intact as received. If + * the gazinta was from a multicast address, the gazouta must go + * out another way. */ rpkt = &rbufp->recv_pkt; - xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, - PKT_VERSION(rpkt->li_vn_mode), xmode); - xpkt.stratum = STRATUM_TO_PKT(sys_stratum); + if (rbufp->dstadr->flags & INT_MULTICAST) + rbufp->dstadr = findinterface(&rbufp->recv_srcadr); + + /* + * If the caller is restricted, return a kiss-of-death packet; + * otherwise, smooch politely. + */ + 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); + } + } else { + xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, + PKT_VERSION(rpkt->li_vn_mode), xmode); + xpkt.stratum = STRATUM_TO_PKT(sys_stratum); + xpkt.refid = sys_refid; + } xpkt.ppoll = rpkt->ppoll; xpkt.precision = sys_precision; xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); - xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion + - LOGTOD(sys_precision))); - xpkt.refid = sys_refid; + xpkt.rootdispersion = + HTONS_FP(DTOUFP(sys_rootdispersion)); HTONL_FP(&sys_reftime, &xpkt.reftime); xpkt.org = rpkt->xmt; HTONL_FP(&rbufp->recv_time, &xpkt.rec); - sendlen = LEN_PKT_NOMAC; - if (rbufp->recv_length > sendlen) { - l_fp xmt_tx; - /* - * Transmit encrypted packet compensated for the - * encryption delay. - */ - if (xkeyid > NTP_MAXKEY) { - xpkt.keyid1 = htonl(2 * sizeof(u_int32)); - xpkt.keyid2 = htonl(sys_private); - sendlen += 2 * sizeof(u_int32); - } + /* + * If the received packet contains a MAC, the transmitted packet + * is authenticated and contains a MAC. If not, the transmitted + * packet is not authenticated. + */ + sendlen = LEN_PKT_NOMAC; + if (rbufp->recv_length == sendlen) { get_systime(&xmt_ts); - L_ADD(&xmt_ts, &sys_authdelay); HTONL_FP(&xmt_ts, &xpkt.xmt); - sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, + sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen); - get_systime(&xmt_tx); - sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -9, &xpkt, - sendlen); - - /* - * Calculate the encryption delay. Keep the minimum over - * the latest two samples. - */ - L_SUB(&xmt_tx, &xmt_ts); - L_ADD(&xmt_tx, &sys_authdelay); - sys_authdly[1] = sys_authdly[0]; - sys_authdly[0] = xmt_tx.l_uf; - if (sys_authdly[0] < sys_authdly[1]) - sys_authdelay.l_uf = sys_authdly[0]; - else - sys_authdelay.l_uf = sys_authdly[1]; #ifdef DEBUG if (debug) - printf( - "transmit: at %ld to %s mode %d keyid %08lx\n", - current_time, ntoa(&rbufp->recv_srcadr), - xmode, xkeyid); + printf("transmit: at %ld %s->%s mode %d\n", + current_time, ntoa(&rbufp->dstadr->sin), + ntoa(&rbufp->recv_srcadr), xmode); #endif - } else { + return; + } + + /* + * The received packet contains a MAC, so the transmitted packet + * must be authenticated. For private-key cryptography, use the + * predefined private keys to generate the cryptosum. For + * autokey cryptography, use the server private value to + * generate the cookie, which is unique for every source- + * destination-key ID combination. + */ +#ifdef AUTOKEY + if (xkeyid > NTP_MAXKEY) { + keyid_t cookie; + u_int code, associd; /* - * Transmit non-authenticated packet. + * The only way to get here is a reply to a legitimate + * client request message, so the mode must be + * MODE_SERVER. If an extension field is present, there + * can be only one and that must be a command. Do what + * needs, but with private value of zero so the poor + * jerk can decode it. If no extension field is present, + * use the cookie to generate the session key. */ - get_systime(&xmt_ts); - HTONL_FP(&xmt_ts, &xpkt.xmt); - sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -10, &xpkt, - sendlen); + 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)) { + session_key(&rbufp->dstadr->sin, + &rbufp->recv_srcadr, xkeyid, 0, 2); + sendlen += crypto_xmit((u_int32 *)&xpkt, + sendlen, code, cookie, associd); + } else { + session_key(&rbufp->dstadr->sin, + &rbufp->recv_srcadr, xkeyid, cookie, 2); + } + } +#endif /* AUTOKEY */ + 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 + if (xkeyid > NTP_MAXKEY) + authtrust(xkeyid, 0); +#endif /* AUTOKEY */ + get_systime(&xmt_tx); + if (sendlen > sizeof(xpkt)) { + msyslog(LOG_ERR, "buffer overflow %u", sendlen); + exit(-1); + } + sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen); + + /* + * Calculate the encryption delay. Keep the minimum over the + * latest two samples. + */ + L_SUB(&xmt_tx, &xmt_ts); + L_ADD(&xmt_tx, &sys_authdelay); + sys_authdly[1] = sys_authdly[0]; + sys_authdly[0] = xmt_tx.l_uf; + if (sys_authdly[0] < sys_authdly[1]) + sys_authdelay.l_uf = sys_authdly[0]; + else + sys_authdelay.l_uf = sys_authdly[1]; #ifdef DEBUG - if (debug) - printf("transmit: at %ld to %s mode %d\n", - current_time, ntoa(&rbufp->recv_srcadr), - xmode); + if (debug) + 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); #endif - } } -#ifdef MD5 + +#ifdef AUTOKEY /* - * Compute key list + * key_expire - purge the key list */ -static void -make_keylist( - struct peer *peer +void +key_expire( + struct peer *peer /* peer structure pointer */ ) { int i; - u_long keyid; - u_long ltemp; - /* - * Allocate the key list if necessary. - */ - if (peer->keylist == 0) - peer->keylist = (u_long *)emalloc(sizeof(u_long) * - NTP_MAXSESSION); - - /* - * Generate an initial key ID which is unique and greater than - * NTP_MAXKEY. - */ - while (1) { - keyid = (u_long)RANDOM & 0xffffffff; - if (keyid <= NTP_MAXKEY) - continue; - if (authhavekey(keyid)) - continue; - break; - } - - /* - * Generate up to NTP_MAXSESSION session keys. Stop if the - * next one would not be unique or not a session key ID or if - * it would expire before the next poll. - */ - ltemp = sys_automax; - for (i = 0; i < NTP_MAXSESSION; i++) { - peer->keylist[i] = keyid; - peer->keynumber = i; - keyid = session_key( - ntohl(peer->dstadr->sin.sin_addr.s_addr), - (peer->hmode == MODE_BROADCAST || (peer->flags & - FLAG_MCAST2)) ? - ntohl(peer->dstadr->bcast.sin_addr.s_addr): - ntohl(peer->srcadr.sin_addr.s_addr), keyid, ltemp); - ltemp -= 1 << peer->hpoll; - if (auth_havekey(keyid) || keyid <= NTP_MAXKEY || - ltemp <= (1 << (peer->hpoll + 1))) - break; + 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; +#ifdef DEBUG + if (debug) + printf("key_expire: at %lu\n", current_time); +#endif } -#endif /* MD5 */ +#endif /* AUTOKEY */ /* * Find the precision of this particular machine @@ -2031,19 +2599,17 @@ init_proto(void) sys_leap = LEAP_NOTINSYNC; sys_stratum = STRATUM_UNSPEC; 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 = 0; + sys_peer = NULL; + sys_survivors = 0; get_systime(&dummy); sys_bclient = 0; sys_bdelay = DEFBROADDELAY; -#if defined(DES) || defined(MD5) sys_authenticate = 1; -#else - sys_authenticate = 0; -#endif L_CLR(&sys_authdelay); sys_authdly[0] = sys_authdly[1] = 0; sys_stattime = 0; @@ -2055,7 +2621,9 @@ init_proto(void) sys_processed = 0; sys_badauth = 0; sys_manycastserver = 0; +#ifdef AUTOKEY sys_automax = 1 << NTP_AUTOMAX; +#endif /* AUTOKEY */ /* * Default these to enable @@ -2064,11 +2632,12 @@ init_proto(void) #ifndef KERNEL_FLL_BUG kern_enable = 1; #endif - msyslog(LOG_DEBUG, "kern_enable is %d", kern_enable); + pps_enable = 0; stats_control = 1; /* - * Some system clocks should only be adjusted in 10ms increments. + * Some system clocks should only be adjusted in 10ms + * increments. */ #if defined RELIANTUNIX_CLOCK systime_10ms_ticks = 1; /* Reliant UNIX */ @@ -2174,6 +2743,24 @@ proto_config( sys_authenticate = (int)value; break; + case PROTO_PPS: + + /* + * Turn on/off PPS discipline + */ + pps_enable = (int)value; + break; + +#ifdef REFCLOCK + case PROTO_CAL: + + /* + * Turn on/off refclock calibrate + */ + cal_enable = (int)value; + break; +#endif + default: /* diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c index c47031c..2205b6c 100644 --- a/contrib/ntp/ntpd/ntp_refclock.c +++ b/contrib/ntp/ntpd/ntp_refclock.c @@ -5,23 +5,25 @@ # include <config.h> #endif -#include <stdio.h> -#include <sys/types.h> -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif /* HAVE_SYS_IOCTL_H */ - #include "ntpd.h" #include "ntp_io.h" #include "ntp_unixtime.h" +#include "ntp_tty.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" +#include <stdio.h> + +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif /* HAVE_SYS_IOCTL_H */ + #ifdef REFCLOCK #ifdef TTYCLK # ifdef HAVE_SYS_CLKDEFS_H # include <sys/clkdefs.h> +# include <stropts.h> # endif # ifdef HAVE_SYS_SIO_H # include <sys/sio.h> @@ -32,15 +34,9 @@ #include <sys/ppsclock.h> #endif /* HAVE_PPSCLOCK_H */ -#ifdef HAVE_PPSAPI -# ifdef HAVE_TIMEPPS_H -# include <timepps.h> -# else -# ifdef HAVE_SYS_TIMEPPS_H -# include <sys/timepps.h> -# endif -# endif -#endif /* HAVE_PPSAPI */ +#ifdef KERNEL_PLL +#include "ntp_syscall.h" +#endif /* KERNEL_PLL */ /* * Reference clock support is provided here by maintaining the fiction @@ -72,24 +68,12 @@ * refclockproc structure pointer from the table typeunit[type][unit]. * This interface is strongly discouraged and may be abandoned in * future. - * - * The routines include support for the 1-pps signal provided by some - * radios and connected via a level converted described in the gadget - * directory. The signal is captured using a serial port and one of - * three STREAMS modules described in the refclock_atom.c file. For the - * highest precision, the signal is captured using the carrier-detect - * line of a serial port and either the ppsclock or ppsapi streams - * module or some devilish ioctl() folks keep slipping in as a patch. Be - * advised ALL support for other than the duly standardized ppsapi - * interface will eventually be withdrawn. */ #define MAXUNIT 4 /* max units */ +#define FUDGEFAC .1 /* fudge correction factor */ -#if defined(PPS) || defined(HAVE_PPSAPI) int fdpps; /* pps file descriptor */ -#endif /* PPS HAVE_PPSAPI */ - -#define FUDGEFAC .1 /* fudge correction factor */ +int cal_enable; /* enable refclock calibrate */ /* * Type/unit peer index. Used to find the peer structure for control and @@ -108,11 +92,6 @@ static int refclock_cmpl_fp P((const double *, const double *)); #endif /* QSORT_USES_VOID_P */ static int refclock_sample P((struct refclockproc *)); -#ifdef HAVE_PPSAPI -extern int pps_assert; /* capture edge 1:assert, 0:clear */ -extern int pps_hardpps; /* PPS kernel 1:on, 0:off */ -#endif /* HAVE_PPSAPI */ - /* * refclock_report - note the occurance of an event * @@ -222,7 +201,6 @@ refclock_newpeer( clktype); return (0); } - refclock_unpeer(peer); /* * Allocate and initialize interface structure @@ -247,14 +225,6 @@ refclock_newpeer( pp->timestarted = current_time; /* - * If the interface has been set to any_interface, set it to the - * loopback address if we have one. This is so that peers which - * are unreachable are easy to see in the peer display. - */ - if (peer->dstadr == any_interface && loopback_interface != 0) - peer->dstadr = loopback_interface; - - /* * Set peer.pmode based on the hmode. For appearances only. */ switch (peer->hmode) { @@ -273,7 +243,7 @@ refclock_newpeer( * can be wiggled, then finish up for consistency. */ if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { - free(pp); + refclock_unpeer(peer); return (0); } peer->hpoll = peer->minpoll; @@ -354,25 +324,21 @@ refclock_transmit( * network code. */ oreach = peer->reach; - if (oreach & 0x01) - peer->valid++; - if (oreach & 0x80) - peer->valid--; - peer->reach <<= 1; - if (peer->reach == 0) { - if (oreach != 0) { + peer->reach <<= 1; + if (!peer->reach) { + if (oreach) { report_event(EVNT_UNREACH, peer); peer->timereachable = current_time; peer_clear(peer); } } else { - if ((oreach & 0x03) == 0) { + if (!(oreach & 0x03)) { clock_filter(peer, 0., 0., MAXDISPERSE); clock_select(); } - if (peer->valid <= 2) { + if (!(oreach & 0x0f)) { hpoll--; - } else if (peer->valid > NTP_SHIFT - 2) + } else if ((oreach & 0x0f) == 0x0f) hpoll++; if (peer->flags & FLAG_BURST) peer->burst = NSTAGE; @@ -383,7 +349,6 @@ refclock_transmit( if (refclock_conf[clktype]->clock_poll != noentry) (refclock_conf[clktype]->clock_poll)(unit, peer); peer->outdate = next; - poll_update(peer, hpoll); if (peer->burst > 0) peer->burst--; poll_update(peer, hpoll); @@ -428,7 +393,9 @@ refclock_cmpl_fp( /* * refclock_process_offset - update median filter * - * This routine uses the given offset and timestamps to construct a new entry in the median filter circular buffer. Samples that overflow the filter are quietly discarded. + * This routine uses the given offset and timestamps to construct a new + * entry in the median filter circular buffer. Samples that overflow the + * filter are quietly discarded. */ void refclock_process_offset( @@ -442,7 +409,6 @@ refclock_process_offset( pp->lastref = offset; pp->lastrec = lastrec; - pp->variance = 0; L_SUB(&offset, &lastrec); LFPTOD(&offset, doffset); SAMPLE(doffset + fudge); @@ -490,18 +456,18 @@ refclock_process( * * This routine implements a recursive median filter to suppress spikes * in the data, as well as determine a performance statistic. It - * calculates the mean offset and mean-square variance. A time - * adjustment fudgetime1 can be added to the final offset to compensate - * for various systematic errors. The routine returns the number of - * samples processed, which could be 0. + * calculates the mean offset and jitter (squares). A time adjustment + * fudgetime1 can be added to the final offset to compensate for various + * systematic errors. The routine returns the number of samples + * processed, which could be zero. */ static int refclock_sample( struct refclockproc *pp ) { - int i, j, k, n; - double offset, disp; + int i, j, k, m, n; + double offset; double off[MAXSTAGE]; /* @@ -514,15 +480,15 @@ refclock_sample( while (pp->codeproc != pp->coderecv) off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE]; if (n > 1) - qsort((char *)off, n, sizeof(double), refclock_cmpl_fp); + qsort((char *)off, (size_t)n, sizeof(double), refclock_cmpl_fp); /* * Reject the furthest from the median of the samples until * approximately 60 percent of the samples remain. */ i = 0; j = n; - k = n - (n * 2) / NSTAGE; - while ((j - i) > k) { + m = n - (n * 2) / NSTAGE; + while ((j - i) > m) { offset = off[(j + i) / 2]; if (off[j - 1] - offset < offset - off[i]) i++; /* reject low end */ @@ -531,21 +497,21 @@ refclock_sample( } /* - * Determine the offset and variance. + * Determine the offset and jitter. */ - offset = disp = 0; - for (; i < j; i++) { - offset += off[i]; - disp += SQUARE(off[i]); - } - offset /= k; - pp->offset = offset; - pp->variance += disp / k - SQUARE(offset); + offset = 0; + for (k = i; k < j; k++) + offset += off[k]; + pp->offset = offset / m; + if (m > 1) + pp->jitter = SQUARE(off[i] - off[j - 1]); + else + pp->jitter = 0; #ifdef DEBUG if (debug) printf( - "refclock_sample: n %d offset %.6f disp %.6f std %.6f\n", - n, pp->offset, pp->disp, SQRT(pp->variance)); + "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", + n, pp->offset, pp->disp, SQRT(pp->jitter)); #endif return (n); } @@ -587,21 +553,29 @@ refclock_receive( refclock_report(peer, CEVNT_FAULT); return; } - if (peer->reach == 0) + if (!peer->reach) report_event(EVNT_REACH, peer); peer->reach |= 1; peer->reftime = peer->org = pp->lastrec; - peer->rootdispersion = pp->disp + SQRT(pp->variance); + peer->rootdispersion = pp->disp + SQRT(pp->jitter); get_systime(&peer->rec); if (!refclock_sample(pp)) return; - clock_filter(peer, pp->offset, 0., 0.); + clock_filter(peer, pp->offset, 0., pp->jitter); clock_select(); record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), - peer->offset, peer->delay, CLOCK_PHI * (current_time - - peer->epoch), SQRT(peer->variance)); - if (pps_control && pp->sloppyclockflag & CLK_FLAG1) - pp->fudgetime1 -= pp->offset * FUDGEFAC; + peer->offset, peer->delay, clock_phi * (current_time - + peer->epoch), SQRT(peer->jitter)); + if (cal_enable && last_offset < MINDISPERSE) { +#ifdef KERNEL_PLL + if (peer != sys_peer || pll_status & STA_PPSTIME) +#else + if (peer != sys_peer) +#endif /* KERNEL_PLL */ + pp->fudgetime1 -= pp->offset * FUDGEFAC; + else + pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC; + } } /* @@ -619,21 +593,13 @@ refclock_gtlin( struct recvbuf *rbufp, /* receive buffer pointer */ char *lineptr, /* current line pointer */ int bmax, /* remaining characters in line */ - l_fp *tsptr /* pointer to timestamp returned */ + l_fp *tsptr /* pointer to timestamp returned */ ) { char *dpt, *dpend, *dp; int i; l_fp trtmp, tstmp; char c; -#ifdef TIOCDCDTIMESTAMP - struct timeval dcd_time; -#endif /* TIOCDCDTIMESTAMP */ -#ifdef HAVE_PPSAPI - pps_info_t pi; - struct timespec timeout, *tsp; - double a; -#endif /* HAVE_PPSAPI */ /* * Check for the presence of a timestamp left by the tty_clock @@ -646,58 +612,6 @@ refclock_gtlin( dpend = dpt + rbufp->recv_length; trtmp = rbufp->recv_time; -#ifdef HAVE_PPSAPI - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - if ((rbufp->fd == fdpps) && - (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &pi, &timeout) >= 0)) { - if(pps_assert) - tsp = &pi.assert_timestamp; - else - tsp = &pi.clear_timestamp; - a = tsp->tv_nsec; - a /= 1e9; - tstmp.l_uf = a * 4294967296.0; - tstmp.l_ui = tsp->tv_sec; - tstmp.l_ui += JAN_1970; - L_SUB(&trtmp, &tstmp); - if (trtmp.l_ui == 0) { -#ifdef DEBUG - if (debug > 1) { - printf( - "refclock_gtlin: fd %d time_pps_fetch %s", - fdpps, lfptoa(&tstmp, 6)); - printf(" sigio %s\n", lfptoa(&trtmp, 6)); - } -#endif - trtmp = tstmp; - goto gotit; - } else - trtmp = rbufp->recv_time; - } -#endif /* HAVE_PPSAPI */ -#ifdef TIOCDCDTIMESTAMP - if(ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) { - TVTOTS(&dcd_time, &tstmp); - tstmp.l_ui += JAN_1970; - L_SUB(&trtmp, &tstmp); - if (trtmp.l_ui == 0) { -#ifdef DEBUG - if (debug > 1) { - printf( - "refclock_gtlin: fd %d DCDTIMESTAMP %s", - rbufp->fd, lfptoa(&tstmp, 6)); - printf(" sigio %s\n", lfptoa(&trtmp, 6)); - } -#endif - trtmp = tstmp; - goto gotit; - } else - trtmp = rbufp->recv_time; - } - else - /* XXX fallback to old method if kernel refuses TIOCDCDTIMESTAMP */ -#endif /* TIOCDCDTIMESTAMP */ if (dpend >= dpt + 8) { if (buftvtots(dpend - 8, &tstmp)) { L_SUB(&trtmp, &tstmp); @@ -719,9 +633,6 @@ refclock_gtlin( } } -#if defined(HAVE_PPSAPI) || defined(TIOCDCDTIMESTAMP) -gotit: -#endif /* * Edit timecode to remove control chars. Don't monkey with the * line buffer if the input buffer contains no ASCII printing @@ -767,36 +678,42 @@ refclock_open( { int fd, i; int flags; -#ifdef HAVE_TERMIOS - struct termios ttyb, *ttyp; -#endif /* HAVE_TERMIOS */ -#ifdef HAVE_SYSV_TTYS - struct termio ttyb, *ttyp; -#endif /* HAVE_SYSV_TTYS */ -#ifdef HAVE_BSD_TTYS - struct sgttyb ttyb, *ttyp; -#endif /* HAVE_BSD_TTYS */ + TTY ttyb, *ttyp; #ifdef TIOCMGET u_long ltemp; #endif /* TIOCMGET */ + int omode; /* * Open serial port and set default options */ flags = lflags; - if (strcmp(dev, pps_device) == 0) - flags |= LDISC_PPS; + + omode = O_RDWR; #ifdef O_NONBLOCK - fd = open(dev, O_RDWR | O_NONBLOCK, 0777); -#else - fd = open(dev, O_RDWR, 0777); -#endif /* O_NONBLOCK */ - if (fd == -1) { + omode |= O_NONBLOCK; +#endif +#ifdef O_NOCTTY + omode |= O_NOCTTY; +#endif + + fd = open(dev, omode, 0777); + + if (fd < 0) { msyslog(LOG_ERR, "refclock_open: %s: %m", dev); return (0); } /* + * This little jewel lights up the PPS file descriptor if the + * device name matches the name in the pps line in the + * configuration file. This is so the atom driver can glom onto + * the right device. Very silly. + */ + if (strcmp(dev, pps_device) == 0) + fdpps = fd; + + /* * The following sections initialize the serial line port in * canonical (line-oriented) mode and set the specified line * speed, 8 bits and no parity. The modem control, break, erase @@ -958,9 +875,8 @@ refclock_open( * This routine attempts to hide the internal, system-specific details * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD * (sgtty) interfaces with varying degrees of success. The routine sets - * up optional features such as tty_clk, ppsclock and ppsapi, as well as - * their many other variants. The routine returns 1 if success and 0 if - * failure. + * up optional features such as tty_clk. The routine returns 1 if + * success and 0 if failure. */ int refclock_ioctl( @@ -973,45 +889,13 @@ refclock_ioctl( #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) #ifdef TTYCLK -#ifdef HAVE_TERMIOS - struct termios ttyb, *ttyp; -#endif /* HAVE_TERMIOS */ -#ifdef HAVE_SYSV_TTYS - struct termio ttyb, *ttyp; -#endif /* HAVE_SYSV_TTYS */ -#ifdef HAVE_BSD_TTYS - struct sgttyb ttyb, *ttyp; -#endif /* HAVE_BSD_TTYS */ + TTY ttyb, *ttyp; #endif /* TTYCLK */ #ifdef DEBUG if (debug) printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags); #endif - - /* - * The following sections select optional features, such as - * modem control, PPS capture and so forth. Some require - * specific operating system support in the form of STREAMS - * modules, which can be loaded and unloaded at run time without - * rebooting the kernel. The STREAMS modules require System - * V STREAMS support. The checking frenzy is attenuated here, - * since the device is already open. - * - * Note that the tty_clk and ppsclock modules are optional; if - * configured and unavailable, the dang thing still works, but - * the accuracy improvement using them will not be available. - * The only known implmentations of these moldules are specific - * to SunOS 4.x. Use the ppsclock module ONLY with Sun baseboard - * ttya or ttyb. Using it with the SPIF multipexor crashes the - * kernel. - * - * The preferred way to capture PPS timestamps is using the - * ppsapi interface, which is machine independent. The SunOS 4.x - * and Digital Unix 4.x interfaces use STREAMS modules and - * support both the ppsapi specification and ppsclock - * functionality, but other systems may vary widely. - */ if (flags == 0) return (1); #if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS)) @@ -1061,104 +945,6 @@ refclock_ioctl( } } #endif /* TTYCLK */ - -#if defined(PPS) && !defined(HAVE_PPSAPI) - /* - * The PPS option provides timestamping at the driver level. - * It uses a 1-pps signal and level converter (gadget box) and - * requires the ppsclock streams module and System V STREAMS - * support. This option has been superseded by the ppsapi - * option and may be withdrawn in future. - */ - if (flags & LDISC_PPS) { - int rval = 0; -#ifdef HAVE_TIOCSPPS /* Solaris */ - int one = 1; -#endif /* HAVE_TIOCSPPS */ - - if (fdpps > 0) { - msyslog(LOG_ERR, - "refclock_ioctl: PPS already configured"); - return (0); - } -#ifdef HAVE_TIOCSPPS /* Solaris */ - if (ioctl(fd, TIOCSPPS, &one) < 0) { - msyslog(LOG_NOTICE, - "refclock_ioctl: TIOCSPPS failed: %m"); - return (0); - } - if (debug) - printf("refclock_ioctl: fd %d TIOCSPPS %d\n", - fd, rval); -#else - if (ioctl(fd, I_PUSH, "ppsclock") < 0) { - msyslog(LOG_NOTICE, - "refclock_ioctl: I_PUSH ppsclock failed: %m"); - return (0); - } - if (debug) - printf("refclock_ioctl: fd %d ppsclock %d\n", - fd, rval); -#endif /* not HAVE_TIOCSPPS */ - fdpps = fd; - } -#endif /* PPS HAVE_PPSAPI */ - -#ifdef HAVE_PPSAPI - /* - * The PPSAPI option provides timestamping at the driver level. - * It uses a 1-pps signal and level converter (gadget box) and - * requires ppsapi compiled into the kernel on non STREAMS - * systems. This is the preferred way to capture PPS timestamps - * and is expected to become an IETF cross-platform standard. - */ - if (flags & (LDISC_PPS | LDISC_CLKPPS)) { - pps_params_t pp; - int mode, temp; - pps_handle_t handle; - - memset((char *)&pp, 0, sizeof(pp)); - if (fdpps > 0) { - msyslog(LOG_ERR, - "refclock_ioctl: ppsapi already configured"); - return (0); - } - if (time_pps_create(fd, &handle) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_create failed: %m"); - return (0); - } - if (time_pps_getcap(handle, &mode) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_getcap failed: %m"); - return (0); - } - pp.mode = mode & PPS_CAPTUREBOTH; - if (time_pps_setparams(handle, &pp) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_setparams failed: %m"); - return (0); - } - if (!pps_hardpps) - temp = 0; - else if (pps_assert) - temp = mode & PPS_CAPTUREASSERT; - else - temp = mode & PPS_CAPTURECLEAR; - if (time_pps_kcbind(handle, PPS_KC_HARDPPS, temp, - PPS_TSFMT_TSPEC) < 0) { - msyslog(LOG_ERR, - "refclock_ioctl: time_pps_kcbind failed: %m"); - return (0); - } - (void)time_pps_getparams(handle, &pp); - fdpps = (int)handle; - if (debug) - printf( - "refclock_ioctl: fd %d ppsapi vers %d mode 0x%x cap 0x%x\n", - fdpps, pp.api_version, pp.mode, mode); - } -#endif /* HAVE_PPSAPI */ #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ #endif /* SYS_VXWORKS SYS_WINNT */ return (1); @@ -1196,6 +982,8 @@ refclock_control( return; if (!(peer = typeunit[clktype][unit])) return; + if (peer->procptr == NULL) + return; pp = peer->procptr; /* diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c index 3743118..6f5e153 100644 --- a/contrib/ntp/ntpd/ntp_request.c +++ b/contrib/ntp/ntpd/ntp_request.c @@ -2,14 +2,9 @@ * ntp_request.c - respond to information requests */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif -#include <sys/types.h> -#include <stdio.h> -#include <signal.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_request.h" @@ -17,6 +12,12 @@ #include "ntp_refclock.h" #include "ntp_if.h" #include "ntp_stdlib.h" + +#include <stdio.h> +#include <signal.h> +#include <netinet/in.h> +#include <arpa/inet.h> + #include "recvbuff.h" #ifdef KERNEL_PLL @@ -60,6 +61,7 @@ static void mem_stats P((struct sockaddr_in *, struct interface *, struct req_pk 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 *)); @@ -77,7 +79,7 @@ static void reset_peer P((struct sockaddr_in *, struct interface *, struct req_p 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 *, int)); +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 reset_auth_stats P((void)); static void req_get_traps P((struct sockaddr_in *, struct interface *, struct req_pkt *)); @@ -112,6 +114,7 @@ static struct req_proc ntp_codes[] = { { 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 }, @@ -150,7 +153,7 @@ static struct req_proc ntp_codes[] = { * Authentication keyid used to authenticate requests. Zero means we * don't allow writing anything. */ -u_long info_auth_keyid; +keyid_t info_auth_keyid; /* * Statistic counters to keep track of requests and responses. @@ -379,6 +382,7 @@ process_private( struct sockaddr_in *srcadr; struct interface *inter; struct req_proc *proc; + int ec; /* * Initialize pointers, for convenience @@ -389,7 +393,7 @@ process_private( #ifdef DEBUG if (debug > 2) - printf("prepare_pkt: impl %d req %d\n", + printf("process_private: impl %d req %d\n", inpkt->implementation, inpkt->request); #endif @@ -397,15 +401,18 @@ process_private( * Do some sanity checks on the packet. Return a format * error if it fails. */ - if (ISRESPONSE(inpkt->rm_vn_mode) - || ISMORE(inpkt->rm_vn_mode) - || INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION - || INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION - || INFO_SEQ(inpkt->auth_seq) != 0 - || INFO_ERR(inpkt->err_nitems) != 0 - || INFO_MBZ(inpkt->mbz_itemsize) != 0 - || rbufp->recv_length > REQ_LEN_MAC - || rbufp->recv_length < REQ_LEN_NOMAC) { + ec = 0; + if ( (++ec, ISRESPONSE(inpkt->rm_vn_mode)) + || (++ec, ISMORE(inpkt->rm_vn_mode)) + || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION) + || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION) + || (++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_NOMAC) + ) { + msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test %d failed", ec); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -424,7 +431,6 @@ process_private( return; } - /* * Search the list for the request codes. If it isn't one * we know, return an error. @@ -478,6 +484,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); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -520,16 +528,21 @@ process_private( * don't, check to see that there is none (picky, picky). */ if (INFO_ITEMSIZE(inpkt->mbz_itemsize) != proc->sizeofitem) { + 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"); @@ -610,14 +623,16 @@ 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->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; @@ -686,14 +701,16 @@ peer_info ( 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->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); ip->srcport = NSRCPORT(&pp->srcadr); ip->flags = 0; @@ -721,7 +738,6 @@ peer_info ( ip->hpoll = pp->hpoll; ip->precision = pp->precision; ip->version = pp->version; - ip->valid = pp->valid; ip->reach = pp->reach; ip->unreach = pp->unreach; ip->flash = (u_char)pp->flash; @@ -752,7 +768,7 @@ peer_info ( HTONL_FP(<mp, &ip->offset); ip->delay = HTONS_FP(DTOFP(pp->delay)); ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp))); - ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->variance))); + ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter))); ip = (struct info_peer *)more_pkt(); } flush_pkt(); @@ -788,14 +804,16 @@ peer_stats ( 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: - 3 : 7; + 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); ip->srcport = NSRCPORT(&pp->srcadr); ip->flags = 0; @@ -860,7 +878,7 @@ sys_info( extern double sys_bdelay; extern l_fp sys_authdelay; extern double clock_stability; - extern double sys_error; + extern double sys_jitter; is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt, sizeof(struct info_sys)); @@ -877,7 +895,7 @@ sys_info( is->precision = sys_precision; is->rootdelay = htonl(DTOFP(sys_rootdelay)); is->rootdispersion = htonl(DTOUFP(sys_rootdispersion)); - is->frequency = htonl(DTOFP(sys_error)); + is->frequency = htonl(DTOFP(sys_jitter)); is->stability = htonl(DTOUFP(clock_stability * 1e6)); is->refid = sys_refid; HTONL_FP(&sys_reftime, &is->reftime); @@ -1114,10 +1132,10 @@ do_conf( struct req_pkt *inpkt ) { + u_int fl; register struct conf_peer *cp; register int items; struct sockaddr_in peeraddr; - int fl; /* * Do a check of everything to see that it looks @@ -1136,13 +1154,15 @@ do_conf( && cp->hmode != MODE_CLIENT && cp->hmode != MODE_BROADCAST) fl = 1; - if (cp->flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER - | CONF_FLAG_NOSELECT | CONF_FLAG_BURST | CONF_FLAG_SKEY)) + if (cp->flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER | + CONF_FLAG_NOSELECT | CONF_FLAG_BURST | CONF_FLAG_IBURST | + CONF_FLAG_SKEY)) fl = 1; cp++; } if (fl) { + msyslog(LOG_ERR, "do_conf: fl is nonzero!"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1164,6 +1184,11 @@ do_conf( !ISREFCLOCKADR(&peeraddr) && #endif ISBADADR(&peeraddr)) { +#ifdef REFCLOCK + msyslog(LOG_ERR, "do_conf: !ISREFCLOCK && ISBADADR"); +#else + msyslog(LOG_ERR, "do_conf: ISBADADR"); +#endif req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1171,20 +1196,22 @@ do_conf( while (items-- > 0) { fl = 0; if (cp->flags & CONF_FLAG_AUTHENABLE) - fl |= FLAG_AUTHENABLE; + fl |= FLAG_AUTHENABLE; if (cp->flags & CONF_FLAG_PREFER) - fl |= FLAG_PREFER; + fl |= FLAG_PREFER; if (cp->flags & CONF_FLAG_NOSELECT) - fl |= FLAG_NOSELECT; + fl |= FLAG_NOSELECT; if (cp->flags & CONF_FLAG_BURST) - fl |= 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, (struct interface *)0, - cp->hmode, cp->version, cp->minpoll, cp->maxpoll, - fl, cp->ttl, cp->keyid) == 0) { + if (peer_config(&peeraddr, any_interface, cp->hmode, + cp->version, cp->minpoll, cp->maxpoll, fl, cp->ttl, + cp->keyid, cp->keystr) == 0) { req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; } @@ -1196,6 +1223,100 @@ do_conf( /* + * dns_a - Snarf DNS info for an association ID + */ +static void +dns_a( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_dns_assoc *dp; + register int items; + struct sockaddr_in peeraddr; + + /* + * Do a check of everything to see that it looks + * okay. If not, complain about it. Note we are + * very picky here. + */ + items = INFO_NITEMS(inpkt->err_nitems); + dp = (struct info_dns_assoc *)inpkt->data; + + /* + * Looks okay, try it out + */ + items = INFO_NITEMS(inpkt->err_nitems); + dp = (struct info_dns_assoc *)inpkt->data; + memset((char *)&peeraddr, 0, sizeof(struct sockaddr_in)); + peeraddr.sin_family = AF_INET; + peeraddr.sin_port = htons(NTP_PORT); + + /* + * Make sure the address is valid + */ + if ( +#ifdef REFCLOCK + !ISREFCLOCKADR(&peeraddr) && +#endif + ISBADADR(&peeraddr)) { +#ifdef REFCLOCK + msyslog(LOG_ERR, "dns_a: !ISREFCLOCK && ISBADADR"); +#else + msyslog(LOG_ERR, "dns_a: ISBADADR"); +#endif + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + while (items-- > 0) { + associd_t associd; + size_t hnl; + struct peer *peer; + int bogon = 0; + + associd = dp->associd; + peer = findpeerbyassoc(associd); + if (peer == 0 || peer->flags & FLAG_REFCLOCK) { + msyslog(LOG_ERR, "dns_a: %s", + (peer == 0) + ? "peer == 0" + : "peer->flags & FLAG_REFCLOCK"); + ++bogon; + } + peeraddr.sin_addr.s_addr = dp->peeraddr; + for (hnl = 0; dp->hostname[hnl] && hnl < sizeof dp->hostname; ++hnl) ; + if (hnl >= sizeof dp->hostname) { + msyslog(LOG_ERR, "dns_a: hnl (%ld) >= %ld", + (long)hnl, (long)sizeof dp->hostname); + ++bogon; + } + + msyslog(LOG_INFO, "dns_a: <%s> for %s, AssocID %d, bogon %d", + dp->hostname, inet_ntoa(peeraddr.sin_addr), associd, + bogon); + + if (bogon) { + /* If it didn't work */ + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } else { +#if 0 +#ifdef PUBKEY + crypto_public(peer, dp->hostname); +#endif /* PUBKEY */ +#endif + } + + dp++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* * do_unconf - remove a peer from the configuration list */ static void @@ -1300,26 +1421,31 @@ setclr_flags( u_long set ) { - register u_long flags; + register u_int flags; if (INFO_NITEMS(inpkt->err_nitems) > 1) { + msyslog(LOG_ERR, "setclr_flags: err_nitems > 1"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } flags = ((struct conf_sys_flags *)inpkt->data)->flags; - if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_AUTHENTICATE | + if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN)) { + msyslog(LOG_ERR, "setclr_flags: extra flags: %#x", + flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | + SYS_FLAG_NTP | SYS_FLAG_KERNEL | + SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN)); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } if (flags & SYS_FLAG_BCLIENT) proto_config(PROTO_BROADCLIENT, set, 0.); - if (flags & SYS_FLAG_AUTHENTICATE) - proto_config(PROTO_AUTHENTICATE, set, 0.); + if (flags & SYS_FLAG_PPS) + proto_config(PROTO_PPS, set, 0.); if (flags & SYS_FLAG_NTP) proto_config(PROTO_NTP, set, 0.); if (flags & SYS_FLAG_KERNEL) @@ -1440,15 +1566,16 @@ do_restrict( bad = 0; while (items-- > 0 && !bad) { if (cr->mflags & ~(RESM_NTPONLY)) - bad = 1; + bad |= 1; if (cr->flags & ~(RES_ALLFLAGS)) - bad = 1; + bad |= 2; if (cr->addr == htonl(INADDR_ANY) && cr->mask != htonl(INADDR_ANY)) - bad = 1; + bad |= 4; cr++; } if (bad) { + msyslog(LOG_ERR, "do_restrict: bad = %#x", bad); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1606,6 +1733,7 @@ reset_stats( struct reset_entry *rent; if (INFO_NITEMS(inpkt->err_nitems) > 1) { + msyslog(LOG_ERR, "reset_stats: err_nitems > 1"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1613,6 +1741,8 @@ reset_stats( flags = ((struct reset_flags *)inpkt->data)->flags; if (flags & ~RESET_ALLFLAGS) { + msyslog(LOG_ERR, "reset_stats: reset leaves %#lx", + flags & ~RESET_ALLFLAGS); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1736,7 +1866,7 @@ do_trustkey( struct sockaddr_in *srcadr, struct interface *inter, struct req_pkt *inpkt, - int trust + u_long trust ) { register u_long *kp; @@ -1928,6 +2058,7 @@ do_setclr_trap( * the error reporting problem. */ if (INFO_NITEMS(inpkt->err_nitems) > 1) { + msyslog(LOG_ERR, "do_setclr_trap: err_nitems > 1"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -1980,12 +2111,13 @@ set_request_keyid( struct req_pkt *inpkt ) { - u_long keyid; + keyid_t keyid; /* * Restrict ourselves to one item only. */ if (INFO_NITEMS(inpkt->err_nitems) > 1) { + msyslog(LOG_ERR, "set_request_keyid: err_nitems > 1"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -2007,13 +2139,14 @@ set_control_keyid( struct req_pkt *inpkt ) { - u_long keyid; - extern u_long ctl_auth_keyid; + keyid_t keyid; + extern keyid_t ctl_auth_keyid; /* * Restrict ourselves to one item only. */ if (INFO_NITEMS(inpkt->err_nitems) > 1) { + msyslog(LOG_ERR, "set_control_keyid: err_nitems > 1"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } @@ -2256,6 +2389,7 @@ set_clock_fudge( (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4); break; default: + msyslog(LOG_ERR, "set_clock_fudge: default!"); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } diff --git a/contrib/ntp/ntpd/ntp_resolver.c b/contrib/ntp/ntpd/ntp_resolver.c new file mode 100644 index 0000000..84b2583 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_resolver.c @@ -0,0 +1,987 @@ +/* +** Ancestor was ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92 +** +** The previous resolver only needed to do forward lookups, and all names +** were known before we started the resolver process. +** +** The new code must be able to handle reverse lookups, and the requests can +** show up at any time. +** +** Here's the drill for the new logic. +** +** We want to be able to do forward or reverse lookups. Forward lookups +** require one set of information to be sent back to the daemon, reverse +** lookups require a different set of information. The caller knows this. +** +** The daemon must not block. This includes communicating with the resolver +** process (if the resolver process is a separate task). +** +** Current resolver code blocks waiting for the response, so the +** alternatives are: +** +** - Find a nonblocking resolver library +** - Do each (initial) lookup in a separate process +** - - subsequent lookups *could* be handled by a different process that has +** a queue of pending requests +** +** We could use nonblocking lookups in a separate process (just to help out +** with timers). +** +** If we don't have nonblocking resolver calls we have more opportunities +** for denial-of-service problems. +** +** - too many fork()s +** - communications path +** +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_request.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +#include <stdio.h> +#include <ctype.h> +#include <netdb.h> +#include <signal.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Each item we are to resolve and configure gets one of these + * structures defined for it. + */ +struct dns_entry { + int de_done; +#define DE_NAME 001 +#define DE_ADDR 002 +#define DE_NA (DE_NAME | DE_ADDR) +#define DE_PENDING 000 +#define DE_GOT 010 +#define DE_FAIL 020 +#define DE_RESULT (DE_PENDING | DE_GOT | DE_FAIL) + struct dns_entry *de_next; + struct info_dns_assoc de_info; /* DNS info for peer */ +}; +#define de_associd de_info.associd +#define de_peeraddr de_info.peeraddr +#define de_hostname de_info.hostname + +/* + * dns_entries is a pointer to the list of configuration entries + * we have left to do. + */ +static struct dns_entry *dns_entries = NULL; + +/* + * We take an interrupt every thirty seconds, at which time we decrement + * config_timer and resolve_timer. The former is set to 2, so we retry + * unsucessful reconfigurations every minute. The latter is set to + * an exponentially increasing value which starts at 2 and increases to + * 32. When this expires we retry failed name resolutions. + * + * We sleep SLEEPTIME seconds before doing anything, to give the server + * time to arrange itself. + */ +#define MINRESOLVE 2 +#define MAXRESOLVE 32 +#define CONFIG_TIME 2 +#define ALARM_TIME 30 + +#define SLEEPTIME 2 + +static volatile int config_timer = 0; +static volatile int resolve_timer = 0; + +static int resolve_value; /* next value of resolve timer */ + +/* + * Big hack attack + */ +#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */ +#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */ + +/* + * Select time out. Set to 2 seconds. The server is on the local machine, + * after all. + */ +#define TIMEOUT_SEC 2 +#define TIMEOUT_USEC 0 + +/* + * File descriptor for ntp request code. + */ +static int sockfd = -1; + +/* + * Pipe descriptors + */ +int p_fd[2] = { -1, -1 }; + +/* stuff to be filled in by caller */ + +extern keyid_t req_keyid; /* request keyid */ + +/* end stuff to be filled in */ + +void ntp_res P((void)); +static RETSIGTYPE bong P((int)); +static void checkparent P((void)); +static void removeentry P((struct dns_entry *)); +static void addentry P((char *, u_int32, u_short)); +static void findhostaddr P((struct dns_entry *)); +static void openntp P((void)); +static int tell_ntpd P((struct info_dns_assoc *)); +static void doconfigure P((int)); + +struct ntp_res_t_pkt { /* Tagged packet: */ + void *tag; /* For the caller */ + u_int32 paddr; /* IP to look up, or 0 */ + char name[NTP_MAXHOSTNAME]; /* Name to look up (if 1st byte is not 0) */ +}; + +struct ntp_res_c_pkt { /* Control packet: */ + char name[NTP_MAXHOSTNAME]; + u_int32 paddr; + int mode; + int version; + int minpoll; + int maxpoll; + int flags; + int ttl; + keyid_t keyid; + u_char keystr[MAXFILENAME]; +}; + +/* + * ntp_res_name + */ + +void +ntp_res_name( + u_int32 paddr, /* Address to resolve */ + u_short associd /* Association ID */ + ) +{ + pid_t pid; + + /* + * fork. + * - parent returns + * - child stuffs data and calls ntp_res() + */ + + for (pid = -1; pid == -1;) { +#ifdef RES_TEST + pid = 0; +#else + pid = fork(); +#endif + if (pid == -1) { + msyslog(LOG_ERR, "ntp_res_name: fork() failed: %m"); + sleep(2); + } + } + switch (pid) { + case -1: /* Error */ + msyslog(LOG_INFO, "ntp_res_name: error..."); + /* Can't happen */ + break; + + case 0: /* Child */ + closelog(); + kill_asyncio(); + (void) signal_no_reset(SIGCHLD, SIG_DFL); +#ifndef LOG_DAEMON + openlog("ntp_res", LOG_PID); +# else /* LOG_DAEMON */ +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog("ntp_res_name", LOG_PID | LOG_NDELAY, LOG_NTP); +#endif + + addentry(NULL, paddr, associd); + ntp_res(); + break; + + default: /* Parent */ + /* Nothing to do. (In Real Life, this never happens.) */ + return; + } +} + +/* + * ntp_res needs; + * + * req_key(???), req_keyid valid + * syslog still open + */ + +void +ntp_res(void) +{ +#ifdef HAVE_SIGSUSPEND + sigset_t set; + + sigemptyset(&set); +#endif /* HAVE_SIGSUSPEND */ + +#ifdef DEBUG + if (debug) { + msyslog(LOG_INFO, "NTP_RESOLVER running"); + } +#endif + + /* check out auth stuff */ + if (sys_authenticate) { + if (!authistrusted(req_keyid)) { + msyslog(LOG_ERR, "invalid request keyid %08x", + req_keyid ); + exit(1); + } + } + + /* + * Make a first cut at resolving the bunch + */ + doconfigure(1); + if (dns_entries == NULL) { + if (debug) { + msyslog(LOG_INFO, "NTP_RESOLVER done!"); + } +#if defined SYS_WINNT + ExitThread(0); /* Don't want to kill whole NT process */ +#else + exit(0); /* done that quick */ +#endif + } + + /* + * Here we've got some problem children. Set up the timer + * and wait for it. + */ + resolve_value = resolve_timer = MINRESOLVE; + config_timer = CONFIG_TIME; +#ifndef SYS_WINNT + (void) signal_no_reset(SIGALRM, bong); + alarm(ALARM_TIME); +#endif /* SYS_WINNT */ + + for (;;) { + if (dns_entries == NULL) + exit(0); + + checkparent(); + + if (resolve_timer == 0) { + if (resolve_value < MAXRESOLVE) + resolve_value <<= 1; + resolve_timer = resolve_value; +#ifdef DEBUG + msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer); +#endif + config_timer = CONFIG_TIME; + doconfigure(1); + continue; + } else if (config_timer == 0) { + config_timer = CONFIG_TIME; +#ifdef DEBUG + msyslog(LOG_INFO, "config_timer: 0->%d", config_timer); +#endif + doconfigure(0); + continue; + } +#ifndef SYS_WINNT + /* + * There is a race in here. Is okay, though, since + * all it does is delay things by 30 seconds. + */ +# ifdef HAVE_SIGSUSPEND + sigsuspend(&set); +# else + sigpause(0); +# endif /* HAVE_SIGSUSPEND */ +#else + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + sleep(ALARM_TIME); +#endif /* SYS_WINNT */ + } +} + + +#ifndef SYS_WINNT +/* + * bong - service and reschedule an alarm() interrupt + */ +static RETSIGTYPE +bong( + int sig + ) +{ + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + alarm(ALARM_TIME); +} +#endif /* SYS_WINNT */ + +/* + * checkparent - see if our parent process is still running + * + * No need to worry in the Windows NT environment whether the + * main thread is still running, because if it goes + * down it takes the whole process down with it (in + * which case we won't be running this thread either) + * Turn function into NOP; + */ + +static void +checkparent(void) +{ +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) + + /* + * If our parent (the server) has died we will have been + * inherited by init. If so, exit. + */ + if (getppid() == 1) { + msyslog(LOG_INFO, "parent died before we finished, exiting"); + exit(0); + } +#endif /* SYS_WINNT && SYS_VXWORKS*/ +} + + +/* + * removeentry - we are done with an entry, remove it from the list + */ +static void +removeentry( + struct dns_entry *entry + ) +{ + register struct dns_entry *de; + + de = dns_entries; + if (de == entry) { + dns_entries = de->de_next; + return; + } + + while (de != NULL) { + if (de->de_next == entry) { + de->de_next = entry->de_next; + return; + } + de = de->de_next; + } +} + + +/* + * addentry - add an entry to the configuration list + */ +static void +addentry( + char *name, + u_int32 paddr, + u_short associd + ) +{ + register struct dns_entry *de; + +#ifdef DEBUG + if (debug > 1) { + struct in_addr si; + + si.s_addr = paddr; + msyslog(LOG_INFO, + "ntp_res_name: <%s> %s associd %d\n", + (name) ? name : "", inet_ntoa(si), associd); + } +#endif + + de = (struct dns_entry *)emalloc(sizeof(struct dns_entry)); + if (name) { + strncpy(de->de_hostname, name, sizeof de->de_hostname); + de->de_done = DE_PENDING | DE_ADDR; + } else { + de->de_hostname[0] = 0; + de->de_done = DE_PENDING | DE_NAME; + } + de->de_peeraddr = paddr; + de->de_associd = associd; + de->de_next = NULL; + + if (dns_entries == NULL) { + dns_entries = de; + } else { + register struct dns_entry *dep; + + for (dep = dns_entries; dep->de_next != NULL; + dep = dep->de_next) + /* nothing */; + dep->de_next = de; + } +} + + +/* + * findhostaddr - resolve a host name into an address (Or vice-versa) + * + * sets entry->de_done appropriately when we're finished. We're finished if + * we either successfully look up the missing name or address, or if we get a + * "permanent" failure on the lookup. + * + */ +static void +findhostaddr( + struct dns_entry *entry + ) +{ + struct hostent *hp; + + checkparent(); /* make sure our guy is still running */ + + /* + * The following should never trip - this subroutine isn't + * called if hostname and peeraddr are "filled". + */ + if (entry->de_hostname[0] && entry->de_peeraddr) { + struct in_addr si; + + si.s_addr = entry->de_peeraddr; + msyslog(LOG_ERR, "findhostaddr: both de_hostname and de_peeraddr are defined: <%s>/%s: state %#x", + &entry->de_hostname[0], inet_ntoa(si), entry->de_done); + return; + } + + /* + * The following should never trip. + */ + if (!entry->de_hostname[0] && !entry->de_peeraddr) { + msyslog(LOG_ERR, "findhostaddr: both de_hostname and de_peeraddr are undefined!"); + entry->de_done |= DE_FAIL; + return; + } + + if (entry->de_hostname[0]) { +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, "findhostaddr: Resolving <%s>", + &entry->de_hostname[0]); +#endif /* DEBUG */ + hp = gethostbyname(&entry->de_hostname[0]); + } else { +#ifdef DEBUG + if (debug > 2) { + struct in_addr si; + + si.s_addr = entry->de_peeraddr; + msyslog(LOG_INFO, "findhostaddr: Resolving %s", + inet_ntoa(si)); + } +#endif + hp = gethostbyaddr((const char *)&entry->de_peeraddr, + sizeof entry->de_peeraddr, + AF_INET); + } + + if (hp == NULL) { + /* + * Bail if we should TRY_AGAIN. + * Otherwise, we have a permanent failure. + */ + if (h_errno == TRY_AGAIN) + return; + entry->de_done |= DE_FAIL; + } else { + entry->de_done |= DE_GOT; + } + + if (entry->de_done & DE_GOT) { + switch (entry->de_done & DE_NA) { + case DE_NAME: +#ifdef DEBUG + 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->de_peeraddr), + (char *)hp->h_addr, + sizeof(struct in_addr)); + break; + case DE_ADDR: +#ifdef DEBUG + if (debug > 2) + msyslog(LOG_INFO, + "findhostaddr: address resolved."); +#endif + strncpy(&entry->de_hostname[0], hp->h_name, + sizeof entry->de_hostname); + break; + default: + msyslog(LOG_ERR, "findhostaddr: Bogus de_done: %#x", + entry->de_done); + break; + } + } else { +#ifdef DEBUG + if (debug > 2) { + struct in_addr si; + const char *hes; +#ifndef HAVE_HSTRERROR + char hnum[20]; + + switch (h_errno) { + case HOST_NOT_FOUND: + hes = "Authoritive Answer Host not found"; + break; + case TRY_AGAIN: + hes = "Non-Authoritative Host not found, or SERVERFAIL"; + break; + case NO_RECOVERY: + hes = "Non recoverable errors, FORMERR, REFUSED, NOTIMP"; + break; + case NO_DATA: + hes = "Valid name, no data record of requested type"; + break; + default: + snprintf(hnum, sizeof hnum, "%d", h_errno); + hes = hnum; + break; + } +#else + hes = hstrerror(h_errno); +#endif + + si.s_addr = entry->de_peeraddr; + msyslog(LOG_INFO, + "findhostaddr: Failed resolution on <%s>/%s: %s", + entry->de_hostname, inet_ntoa(si), hes); + } +#endif + /* Send a NAK message back to the daemon */ + } + return; +} + + +/* + * openntp - open a socket to the ntp server + */ +static void +openntp(void) +{ + struct sockaddr_in saddr; + + if (sockfd >= 0) + return; + + sockfd = socket(AF_INET, SOCK_DGRAM, 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() + */ +#ifndef SYS_WINNT +# if defined(O_NONBLOCK) + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); + exit(1); + } +# else +# if defined(FNDELAY) + if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { + msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); + exit(1); + } +# else +# include "Bletch: NEED NON BLOCKING IO" +# endif /* FNDDELAY */ +# endif /* O_NONBLOCK */ +#else /* SYS_WINNT */ + { + int on = 1; + + if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) { + msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); + exit(1); /* Windows NT - set socket in non-blocking mode */ + } + } +#endif /* SYS_WINNT */ + + if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + msyslog(LOG_ERR, "openntp: connect() failed: %m"); + exit(1); + } +} + + +/* + * tell_ntpd: Tell ntpd what we discovered. + */ +static int +tell_ntpd( + struct info_dns_assoc *conf + ) +{ + fd_set fdset; + struct timeval tvout; + struct req_pkt reqpkt; + l_fp ts; + int n; +#ifdef SYS_WINNT + HANDLE hReadWriteEvent = NULL; + BOOL ret; + DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait; + OVERLAPPED overlap; +#endif /* SYS_WINNT */ + + checkparent(); /* make sure our guy is still running */ + + if (sockfd < 0) + openntp(); + +#ifdef SYS_WINNT + hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif /* SYS_WINNT */ + + /* + * Try to clear out any previously received traffic so it + * doesn't fool us. Note the socket is nonblocking. + */ + tvout.tv_sec = 0; + tvout.tv_usec = 0; + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) > + 0) { + recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + } + + /* + * Make up a request packet with the configuration info + */ + memset((char *)&reqpkt, 0, sizeof(reqpkt)); + + reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); + reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */ + reqpkt.implementation = IMPL_XNTPD; /* local implementation */ + reqpkt.request = REQ_HOSTNAME_ASSOCID; /* Hostname for associd */ + reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */ + reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct info_dns_assoc)); + memmove(reqpkt.data, (char *)conf, sizeof(struct info_dns_assoc)); + reqpkt.keyid = htonl(req_keyid); + + get_systime(&ts); + L_ADDUF(&ts, SKEWTIME); + HTONL_FP(&ts, &reqpkt.tstamp); + n = 0; + if (sys_authenticate) + n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC); + + /* + * Done. Send it. + */ +#ifndef SYS_WINNT + n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0); + if (n < 0) { + msyslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; /* maybe should exit */ + } +#else + /* In the NT world, documentation seems to indicate that there + * exist _write and _read routines that can be used to do blocking + * I/O on sockets. Problem is these routines require a socket + * handle obtained through the _open_osf_handle C run-time API + * of which there is no explanation in the documentation. We need + * nonblocking write's and read's anyway for our purpose here. + * We're therefore forced to deviate a little bit from the Unix + * model here and use the ReadFile and WriteFile Win32 I/O API's + * on the socket + */ + overlap.Offset = overlap.OffsetHigh = (DWORD)0; + overlap.hEvent = hReadWriteEvent; + ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n, + (LPDWORD)&NumberOfBytesWritten, (LPOVERLAPPED)&overlap); + if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { + msyslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; + } + dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); + if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { + if (dwWait == WAIT_FAILED) + msyslog(LOG_ERR, "WaitForSingleObject failed: %m"); + return 0; + } +#endif /* SYS_WINNT */ + + + /* + * Wait for a response. A weakness of the mode 7 protocol used + * is that there is no way to associate a response with a + * particular request, i.e. the response to this configuration + * request is indistinguishable from that to any other. I should + * fix this some day. In any event, the time out is fairly + * pessimistic to make sure that if an answer is coming back + * at all, we get it. + */ + for (;;) { + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + tvout.tv_sec = TIMEOUT_SEC; + tvout.tv_usec = TIMEOUT_USEC; + + n = select(sockfd + 1, &fdset, (fd_set *)0, + (fd_set *)0, &tvout); + + if (n < 0) + { + msyslog(LOG_ERR, "select() fails: %m"); + return 0; + } + else if (n == 0) + { + if(debug) + msyslog(LOG_INFO, "select() returned 0."); + return 0; + } + +#ifndef SYS_WINNT + n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); + if (n <= 0) { + if (n < 0) { + msyslog(LOG_ERR, "recv() fails: %m"); + return 0; + } + continue; + } +#else /* Overlapped I/O used on non-blocking sockets on Windows NT */ + ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC, + (LPDWORD)&NumberOfBytesRead, (LPOVERLAPPED)&overlap); + if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { + msyslog(LOG_ERR, "ReadFile() fails: %m"); + return 0; + } + dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); + if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { + if (dwWait == WAIT_FAILED) { + msyslog(LOG_ERR, "WaitForSingleObject fails: %m"); + return 0; + } + continue; + } + n = NumberOfBytesRead; +#endif /* SYS_WINNT */ + + /* + * Got one. Check through to make sure it is what + * we expect. + */ + if (n < RESP_HEADER_SIZE) { + msyslog(LOG_ERR, "received runt response (%d octets)", + n); + continue; + } + + if (!ISRESPONSE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "received non-response packet"); +#endif + continue; + } + + if (ISMORE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "received fragmented packet"); +#endif + continue; + } + + if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2) + || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION)) + || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "version (%d/%d) or mode (%d/%d) incorrect", + INFO_VERSION(reqpkt.rm_vn_mode), + NTP_VERSION, + INFO_MODE(reqpkt.rm_vn_mode), + MODE_PRIVATE); +#endif + continue; + } + + if (INFO_SEQ(reqpkt.auth_seq) != 0) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "nonzero sequence number (%d)", + INFO_SEQ(reqpkt.auth_seq)); +#endif + continue; + } + + if (reqpkt.implementation != IMPL_XNTPD || + reqpkt.request != REQ_HOSTNAME_ASSOCID) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "implementation (%d/%d) or request (%d/%d) incorrect", + reqpkt.implementation, IMPL_XNTPD, + reqpkt.request, REQ_HOSTNAME_ASSOCID); +#endif + continue; + } + + if (INFO_NITEMS(reqpkt.err_nitems) != 0 || + INFO_MBZ(reqpkt.mbz_itemsize) != 0 || + INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "nitems (%d) mbz (%d) or itemsize (%d) nonzero", + INFO_NITEMS(reqpkt.err_nitems), + INFO_MBZ(reqpkt.mbz_itemsize), + INFO_ITEMSIZE(reqpkt.mbz_itemsize)); +#endif + continue; + } + + n = INFO_ERR(reqpkt.err_nitems); + switch (n) { + case INFO_OKAY: + /* success */ + return 1; + + case INFO_ERR_IMPL: + msyslog(LOG_ERR, + "server reports implementation mismatch!!"); + return 0; + + case INFO_ERR_REQ: + msyslog(LOG_ERR, + "server claims configuration request is unknown"); + return 0; + + case INFO_ERR_FMT: + msyslog(LOG_ERR, + "server indicates a format error occurred(!!)"); + return 0; + + case INFO_ERR_NODATA: + msyslog(LOG_ERR, + "server indicates no data available (shouldn't happen)"); + return 0; + + case INFO_ERR_AUTH: + msyslog(LOG_ERR, + "server returns a permission denied error"); + return 0; + + default: + msyslog(LOG_ERR, + "server returns unknown error code %d", n); + return 0; + } + } +} + + +/* + * doconfigure - attempt to resolve names/addresses + */ +static void +doconfigure( + int dores + ) +{ + register struct dns_entry *de; + register struct dns_entry *deremove; + char *done_msg = ""; + + de = dns_entries; + while (de != NULL) { +#ifdef DEBUG + if (debug > 1) { + struct in_addr si; + + si.s_addr = de->de_peeraddr; + msyslog(LOG_INFO, + "doconfigure: name: <%s> peeraddr: %s", + de->de_hostname, inet_ntoa(si)); + } +#endif + if (dores && (de->de_hostname[0] == 0 || de->de_peeraddr == 0)) { + findhostaddr(de); + } + + switch (de->de_done & DE_RESULT) { + case DE_PENDING: + done_msg = ""; + break; + case DE_GOT: + done_msg = "succeeded"; + break; + case DE_FAIL: + done_msg = "failed"; + break; + default: + done_msg = "(error - shouldn't happen)"; + break; + } + if (done_msg[0]) { + /* Send the answer */ + if (tell_ntpd(&de->de_info)) { + struct in_addr si; + + si.s_addr = de->de_peeraddr; +#ifdef DEBUG + if (debug > 1) { + msyslog(LOG_INFO, + "DNS resolution on <%s>/%s %s", + de->de_hostname, inet_ntoa(si), + done_msg); + } +#endif + deremove = de; + de = deremove->de_next; + removeentry(deremove); + } + } else { + de = de->de_next; + } + } +} diff --git a/contrib/ntp/ntpd/ntp_timer.c b/contrib/ntp/ntpd/ntp_timer.c index 0e2dc88..71a84e2 100644 --- a/contrib/ntp/ntpd/ntp_timer.c +++ b/contrib/ntp/ntpd/ntp_timer.c @@ -5,20 +5,26 @@ # include <config.h> #endif +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_stdlib.h" + #include <stdio.h> -#include <sys/types.h> -#include <sys/time.h> #include <signal.h> #include <sys/signal.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif -#include "ntp_machine.h" -#include "ntpd.h" -#include "ntp_stdlib.h" #if defined(HAVE_IO_COMPLETION_PORT) # include "ntp_iocompletionport.h" # 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 @@ -41,8 +47,11 @@ volatile int alarm_flag; 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 static u_long revoke_timer; /* keys revoke timer */ -u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout */ +u_long sys_revoke = 1 << KEY_REVOKE; /* keys revoke timeout */ +#endif /* AUTOKEY */ /* * Statistics counter for the interested. @@ -101,6 +110,7 @@ init_timer(void) alarm_overflow = 0; adjust_timer = 1; hourly_timer = HOUR; + huffpuff_timer = 0; current_time = 0; timer_overflows = 0; timer_xmtcalls = 0; @@ -206,7 +216,7 @@ void timer(void) { register struct peer *peer, *next_peer; - int n; + u_int n; current_time += (1<<EVENT_TIMEOUT); @@ -250,12 +260,27 @@ timer(void) } /* - * Garbage collect revoked keys + * Huff-n'-puff filter + */ + if (huffpuff_timer <= current_time) { + huffpuff_timer += HUFFPUFF; + huffpuff(); + } + +#ifdef AUTOKEY + /* + * Garbage collect old keys and generate new private value */ if (revoke_timer <= current_time) { - revoke_timer += RANDPOLL(sys_revoke); - key_expire_all(); + revoke_timer += sys_revoke; + expire_all(); +#ifdef DEBUG + if (debug) + printf("key expire: at %lu next %lu\n", + current_time, revoke_timer); +#endif } +#endif /* AUTOKEY */ /* * Finally, call the hourly routine. diff --git a/contrib/ntp/ntpd/ntp_util.c b/contrib/ntp/ntpd/ntp_util.c index c53255a..f86e930 100644 --- a/contrib/ntp/ntpd/ntp_util.c +++ b/contrib/ntp/ntpd/ntp_util.c @@ -1,18 +1,11 @@ /* * ntp_util.c - stuff I didn't have any other place for */ + #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -# ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -# endif -# include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_unixtime.h" @@ -20,6 +13,20 @@ #include "ntp_if.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + +#ifdef HAVE_IEEEFP_H +# include <ieeefp.h> +#endif +#ifdef HAVE_MATH_H +# include <math.h> +#endif + #ifdef DOSYNCTODR #if !defined(VMS) #include <sys/resource.h> @@ -218,7 +225,8 @@ hourly_stats(void) NLOG(NLOG_SYSSTATIST) msyslog(LOG_INFO, "offset %.6f sec freq %.3f ppm error %.6f poll %d", - last_offset, drift_comp * 1e6, sys_error, sys_poll); + last_offset, drift_comp * 1e6, sys_jitter, sys_poll); + if (stats_drift_file != 0) { if ((fp = fopen(stats_temp_file, "w")) == NULL) { @@ -341,12 +349,27 @@ stats_config( break; } if (fscanf(fp, "%lf", &old_drift) != 1) { - msyslog(LOG_ERR, "invalid frequency from %s", + msyslog(LOG_ERR, "Un-parsable frequency in %s", stats_drift_file); (void) fclose(fp); break; } (void) fclose(fp); + if ( +#ifdef HAVE_FINITE + !finite(old_drift) +#else /* not HAVE_FINITE */ +# ifdef HAVE_ISFINITE + !isfinite(old_drift) +# else /* not HAVE_ISFINITE */ + 0 +# endif /* not HAVE_ISFINITE */ +#endif /* not HAVE_FINITE */ + || (fabs(old_drift) > (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); loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); @@ -466,7 +489,13 @@ record_peer_stats( * time constant (log base 2) */ void -record_loop_stats(void) +record_loop_stats( + double offset, + double freq, + double jitter, + double stability, + int poll + ) { struct timeval tv; #ifdef HAVE_GETCLOCK @@ -490,8 +519,8 @@ record_loop_stats(void) filegen_setup(&loopstats, (u_long)(tv.tv_sec + JAN_1970)); if (loopstats.fp != NULL) { fprintf(loopstats.fp, "%lu %lu.%03lu %.9f %.6f %.9f %.6f %d\n", - day, sec, msec, last_offset, drift_comp * 1e6, - sys_error, clock_stability * 1e6, sys_poll); + day, sec, msec, offset, freq * 1e6, jitter, + stability * 1e6, poll); fflush(loopstats.fp); } } diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c index 3dbef60..aab9881 100644 --- a/contrib/ntp/ntpd/ntpd.c +++ b/contrib/ntp/ntpd/ntpd.c @@ -1,11 +1,15 @@ /* * ntpd.c - main program for the fixed point NTP daemon */ + #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include <sys/types.h> +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_stdlib.h" + #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -21,7 +25,6 @@ # ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> # endif /* HAVE_SYS_IOCTL_H */ -# include <sys/time.h> # ifdef HAVE_SYS_RESOURCE_H # include <sys/resource.h> # endif /* HAVE_SYS_RESOURCE_H */ @@ -68,11 +71,8 @@ # include <apollo/base.h> #endif /* SYS_DOMAINOS */ -#include "ntpd.h" -#include "ntp_io.h" - -#include "ntp_stdlib.h" #include "recvbuff.h" +#include "ntp_cmdargs.h" #if 0 /* HMS: I don't think we need this. 961223 */ #ifdef LOCK_PROCESS @@ -85,13 +85,17 @@ #endif #ifdef _AIX -#include <ulimit.h> +# include <ulimit.h> #endif /* _AIX */ #ifdef SCO5_CLOCK -#include <sys/ci/ciioctl.h> +# include <sys/ci/ciioctl.h> #endif +#ifdef PUBKEY +#include "ntp_crypto.h" +#endif /* PUBKEY */ + /* * Signals we catch for debugging. If not debugging we ignore them. */ @@ -102,10 +106,10 @@ * Signals which terminate us gracefully. */ #ifndef SYS_WINNT -#define SIGDIE1 SIGHUP -#define SIGDIE3 SIGQUIT -#define SIGDIE2 SIGINT -#define SIGDIE4 SIGTERM +# define SIGDIE1 SIGHUP +# define SIGDIE3 SIGQUIT +# define SIGDIE2 SIGINT +# define SIGDIE4 SIGTERM #endif /* SYS_WINNT */ #if defined SYS_WINNT @@ -122,7 +126,12 @@ static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType); /* * Scheduling priority we run at */ -# define NTPD_PRIO (-12) +#define NTPD_PRIO (-12) + +int priority_done = 2; /* 0 - Set priority */ + /* 1 - priority is OK where it is */ + /* 2 - Don't set priority */ + /* 1 and 2 are pretty much the same */ /* * Debugging flag @@ -223,39 +232,23 @@ catch_danger(int signo) static void set_process_priority(void) { - int done = 0; - -#ifdef SYS_WINNT - DWORD SingleCPUMask = 0; - DWORD ProcessAffinityMask, SystemAffinityMask; - if (!GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask)) - msyslog(LOG_ERR, "GetProcessAffinityMask: %m"); - else { - SingleCPUMask = 1; -# ifdef DEBUG - msyslog(LOG_INFO, "System AffinityMask = %x", SystemAffinityMask ); -# endif - } - while (SingleCPUMask && !(SingleCPUMask & SystemAffinityMask)) { - SingleCPUMask = SingleCPUMask << 1; - } - if (!SingleCPUMask) - msyslog(LOG_ERR, "Can't set Processor Affinity Mask"); - else if (!SetProcessAffinityMask(GetCurrentProcess(), SingleCPUMask)) - msyslog(LOG_ERR, "SetProcessAffinityMask: %m"); -# ifdef DEBUG - else msyslog(LOG_INFO,"ProcessorAffinity Mask: %x", SingleCPUMask ); -# endif +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>", + ((priority_done) + ? "Leave priority alone" + : "Attempt to set priority" + ), + priority_done); +#endif /* DEBUG */ - if (!SetPriorityClass(GetCurrentProcess(), (DWORD) REALTIME_PRIORITY_CLASS)) - msyslog(LOG_ERR, "SetPriorityClass: %m"); - else - ++done; +#ifdef SYS_WINNT + priority_done += NT_set_process_priority(); #endif -# if defined(HAVE_SCHED_SETSCHEDULER) - if (!done) { +#if defined(HAVE_SCHED_SETSCHEDULER) + if (!priority_done) { extern int config_priority_override, config_priority; int pmax, pmin; struct sched_param sched; @@ -274,12 +267,12 @@ set_process_priority(void) if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) msyslog(LOG_ERR, "sched_setscheduler(): %m"); else - ++done; + ++priority_done; } -# endif /* HAVE_SCHED_SETSCHEDULER */ -# if defined(HAVE_RTPRIO) -# ifdef RTP_SET - if (!done) { +#endif /* HAVE_SCHED_SETSCHEDULER */ +#if defined(HAVE_RTPRIO) +# ifdef RTP_SET + if (!priority_done) { struct rtprio srtp; srtp.type = RTP_PRIO_REALTIME; /* was: RTP_PRIO_NORMAL */ @@ -288,37 +281,37 @@ set_process_priority(void) if (rtprio(RTP_SET, getpid(), &srtp) < 0) msyslog(LOG_ERR, "rtprio() error: %m"); else - ++done; + ++priority_done; } -# else /* not RTP_SET */ - if (!done) { +# else /* not RTP_SET */ + if (!priority_done) { if (rtprio(0, 120) < 0) msyslog(LOG_ERR, "rtprio() error: %m"); else - ++done; + ++priority_done; } -# endif /* not RTP_SET */ -# endif /* HAVE_RTPRIO */ -# if defined(NTPD_PRIO) && NTPD_PRIO != 0 -# ifdef HAVE_ATT_NICE - if (!done) { +# endif /* not RTP_SET */ +#endif /* HAVE_RTPRIO */ +#if defined(NTPD_PRIO) && NTPD_PRIO != 0 +# ifdef HAVE_ATT_NICE + if (!priority_done) { errno = 0; if (-1 == nice (NTPD_PRIO) && errno != 0) msyslog(LOG_ERR, "nice() error: %m"); else - ++done; + ++priority_done; } -# endif /* HAVE_ATT_NICE */ -# ifdef HAVE_BSD_NICE - if (!done) { +# endif /* HAVE_ATT_NICE */ +# ifdef HAVE_BSD_NICE + if (!priority_done) { if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO)) msyslog(LOG_ERR, "setpriority() error: %m"); else - ++done; + ++priority_done; } -# endif /* HAVE_BSD_NICE */ -# endif /* NTPD_PRIO && NTPD_PRIO != 0 */ - if (!done) +# endif /* HAVE_BSD_NICE */ +#endif /* NTPD_PRIO && NTPD_PRIO != 0 */ + if (!priority_done) msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority"); } @@ -335,6 +328,10 @@ 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? */ @@ -347,7 +344,7 @@ ntpdmain( #ifdef HAVE_UMASK { - unsigned int uv; + mode_t uv; uv = umask(0); if(uv) @@ -378,10 +375,13 @@ ntpdmain( } addSourceToRegistry("NTP", szMsgPath); #endif + getstartup(argc, argv); /* startup configuration, may set debug */ + /* + * Initialize random generator and public key pair + */ get_systime(&now); SRANDOM((int)(now.l_i * now.l_uf)); - getstartup(argc, argv); /* startup configuration, may set debug */ #if !defined(VMS) # ifndef NODETACH @@ -395,9 +395,9 @@ ntpdmain( # endif /* DEBUG */ { # ifndef SYS_WINNT -# ifdef HAVE_DAEMON +# ifdef HAVE_DAEMON daemon(0, 0); -# else /* not HAVE_DAEMON */ +# else /* not HAVE_DAEMON */ if (fork()) /* HMS: What about a -1? */ exit(0); @@ -417,11 +417,11 @@ ntpdmain( msyslog(LOG_ERR, "ntpd: failed to close open files(): %m"); #else /* not F_CLOSEM */ -#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) +# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) max_fd = sysconf(_SC_OPEN_MAX); -#else /* HAVE_SYSCONF && _SC_OPEN_MAX */ +# else /* HAVE_SYSCONF && _SC_OPEN_MAX */ max_fd = getdtablesize(); -#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ +# endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ for (s = 0; s < max_fd; s++) (void) close((int)s); #endif /* not F_CLOSEM */ @@ -473,8 +473,8 @@ ntpdmain( (void) sigaction(SIGDANGER, &sa, NULL); #endif /* _AIX */ } -#endif /* not HAVE_DAEMON */ -#else /* SYS_WINNT */ +# endif /* not HAVE_DAEMON */ +# else /* SYS_WINNT */ { SERVICE_TABLE_ENTRY dispatchTable[] = { @@ -489,10 +489,10 @@ ntpdmain( ExitProcess(2); } } -#endif /* SYS_WINNT */ +# endif /* SYS_WINNT */ } -#endif /* NODETACH */ -#if defined(SYS_WINNT) && !defined(NODETACH) +# endif /* NODETACH */ +# if defined(SYS_WINNT) && !defined(NODETACH) else service_main(argc, argv); return 0; /* must return a value */ @@ -513,7 +513,10 @@ service_main( char *cp; struct recvbuf *rbuflist; struct recvbuf *rbuf; - +#ifdef AUTOKEY + u_int n; + char hostname[MAXFILENAME]; +#endif /* AUTOKEY */ if(!debug) { /* register our service control handler */ @@ -541,7 +544,7 @@ service_main( } } /* debug */ -#endif /* defined(SYS_WINNT) && !defined(NODETACH) */ +# endif /* defined(SYS_WINNT) && !defined(NODETACH) */ #endif /* VMS */ /* @@ -638,15 +641,15 @@ service_main( if (plock(PROCLOCK) < 0) msyslog(LOG_ERR, "plock(PROCLOCK): %m"); # else /* not PROCLOCK */ -# ifdef TXTLOCK +# ifdef TXTLOCK /* * Lock text into ram */ if (plock(TXTLOCK) < 0) msyslog(LOG_ERR, "plock(TXTLOCK) error: %m"); -# else /* not TXTLOCK */ +# else /* not TXTLOCK */ msyslog(LOG_ERR, "plock() - don't know what to lock!"); -# endif /* not TXTLOCK */ +# endif /* not TXTLOCK */ # endif /* not PROCLOCK */ # endif /* HAVE_PLOCK */ #endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ @@ -715,27 +718,38 @@ service_main( init_refclock(); #endif set_process_priority(); - init_proto(); + init_proto(); /* Call at high priority */ init_io(); init_loopfilter(); - - mon_start(MON_ON); /* monitor on by default now */ + mon_start(MON_ON); /* monitor on by default now */ /* turn off in config if unwanted */ /* * Get configuration. This (including argument list parsing) is * done in a separate module since this will definitely be different - * for the gizmo board. + * for the gizmo board. While at it, save the host name for later + * along with the length. The crypto needs this. */ +#ifdef DEBUG + 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 + crypto_setup(); +#endif /* PUBKEY */ +#endif /* AUTOKEY */ initializing = 0; #if defined(SYS_WINNT) && !defined(NODETACH) # if defined(DEBUG) if(!debug) { -#endif +# endif /* report to the service control manager that the service is running */ ssStatus.dwCurrentState = SERVICE_RUNNING; ssStatus.dwWin32ExitCode = NO_ERROR; @@ -750,7 +764,7 @@ service_main( } # if defined(DEBUG) } -#endif +# endif #endif /* @@ -773,7 +787,7 @@ service_main( * and - lacking a hardware reference clock - I have * yet to learn about anything else that is. */ -# if defined(HAVE_IO_COMPLETION_PORT) +#if defined(HAVE_IO_COMPLETION_PORT) WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */ WaitHandles[1] = get_timer_handle(); @@ -805,21 +819,21 @@ service_main( } /* switch */ rbuflist = getrecvbufs(); /* get received buffers */ -# else /* normal I/O */ +#else /* normal I/O */ was_alarmed = 0; rbuflist = (struct recvbuf *)0; for (;;) { -# if !defined(HAVE_SIGNALED_IO) +# if !defined(HAVE_SIGNALED_IO) extern fd_set activefds; extern int maxactivefd; fd_set rdfdes; int nfound; -# elif defined(HAVE_SIGNALED_IO) +# elif defined(HAVE_SIGNALED_IO) block_io_and_alarm(); -# endif +# endif rbuflist = getrecvbufs(); /* get received buffers */ if (alarm_flag) /* alarmed? */ @@ -833,9 +847,9 @@ service_main( /* * Nothing to do. Wait for something. */ -#ifndef HAVE_SIGNALED_IO +# ifndef HAVE_SIGNALED_IO rdfdes = activefds; -# if defined(VMS) || defined(SYS_VXWORKS) +# if defined(VMS) || defined(SYS_VXWORKS) /* make select() wake up after one second */ { struct timeval t1; @@ -844,10 +858,10 @@ service_main( nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, (fd_set *)0, &t1); } -# else +# else nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, (fd_set *)0, (struct timeval *)0); -# endif /* VMS */ +# endif /* VMS */ if (nfound > 0) { l_fp ts; @@ -858,15 +872,13 @@ service_main( } else if (nfound == -1 && errno != EINTR) msyslog(LOG_ERR, "select() error: %m"); - else if (debug) { -# if !defined SYS_VXWORKS && !defined SCO5_CLOCK /* to unclutter log */ + else if (debug > 2) { msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); -# endif } -# else /* HAVE_SIGNALED_IO */ +# else /* HAVE_SIGNALED_IO */ wait_for_signal(); -# endif /* HAVE_SIGNALED_IO */ +# endif /* HAVE_SIGNALED_IO */ if (alarm_flag) /* alarmed? */ { was_alarmed = 1; @@ -888,7 +900,7 @@ service_main( was_alarmed = 0; } -# endif /* HAVE_IO_COMPLETION_PORT */ +#endif /* HAVE_IO_COMPLETION_PORT */ /* * Call the data procedure to handle each received * packet. @@ -900,11 +912,11 @@ service_main( (rbuf->receiver)(rbuf); freerecvbuf(rbuf); } -# if defined DEBUG && defined SYS_WINNT +#if defined DEBUG && defined SYS_WINNT if (debug > 4) printf("getrecvbufs: %ld handler interrupts, %ld frames\n", handler_calls, handler_pkts); -# endif +#endif /* * Go around again @@ -929,11 +941,11 @@ finish( switch (sig) { -#ifdef SIGBUS +# ifdef SIGBUS case SIGBUS: printf("\nfinish(SIGBUS)\n"); exit(0); -#endif +# endif case 0: /* Should never happen... */ return; default: diff --git a/contrib/ntp/ntpd/refclock_acts.c b/contrib/ntp/ntpd/refclock_acts.c index 9c367b5..efdf536 100644 --- a/contrib/ntp/ntpd/refclock_acts.c +++ b/contrib/ntp/ntpd/refclock_acts.c @@ -9,13 +9,6 @@ #if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS)) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif /* HAVE_SYS_IOCTL_H */ - #include "ntpd.h" #include "ntp_io.h" #include "ntp_unixtime.h" @@ -23,6 +16,12 @@ #include "ntp_stdlib.h" #include "ntp_control.h" +#include <stdio.h> +#include <ctype.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif /* HAVE_SYS_IOCTL_H */ + /* MUST BE AFTER LAST #include <config.h> !!! */ #if defined(CLOCK_ACTS) && defined(CLOCK_PTBACTS) @@ -655,19 +654,22 @@ acts_receive ( (void)write(pp->io.fd, &flag, 1); /* - * Yes, I know this code incorrectly thinks that 2000 is a leap - * year. The ACTS timecode format croaks then anyway. Life is - * short. Would only the timecode mavens resist the urge to - * express months of the year and days of the month in favor of - * days of the year. - * NOTE: year 2000 IS a leap year!!! ghealton Y2KFixes + * The ACTS timecode format croaks in 2000. Life is short. + * Would only the timecode mavens resist the urge to express months + * of the year and days of the month in favor of days of the year. */ if (month < 1 || month > 12 || day < 1) { refclock_report(peer, CEVNT_BADTIME); return; } - if ( pp->year <= YEAR_PIVOT ) pp->year += 100; /* Y2KFixes */ - if ( !isleap_tm(pp->year) ) { /* Y2KFixes */ + + /* + * Depending on the driver, at this point we have a two-digit year + * or a four-digit year. Make sure we have a four-digit year. + */ + if ( pp->year < YEAR_PIVOT ) pp->year += 100; /* Y2KFixes */ + if ( pp->year < YEAR_BREAK ) pp->year += 1900; /* Y2KFixes */ + if ( !isleap_4(pp->year) ) { /* Y2KFixes */ if (day > day1tab[month - 1]) { refclock_report(peer, CEVNT_BADTIME); return; @@ -798,7 +800,7 @@ acts_timeout ( acts_disc(peer); return; } - switch (peer->ttl) { + switch (peer->ttlmax) { /* * 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 045a93a..cdbe2ee 100644 --- a/contrib/ntp/ntpd/refclock_arbiter.c +++ b/contrib/ntp/ntpd/refclock_arbiter.c @@ -9,15 +9,14 @@ #if defined(REFCLOCK) && defined(CLOCK_ARBITER) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports the Arbiter 1088A/B Satellite Controlled Clock. * The claimed accuracy of this clock is 100 ns relative to the PPS diff --git a/contrib/ntp/ntpd/refclock_arc.c b/contrib/ntp/ntpd/refclock_arc.c index 1db8a9a..c771f47 100644 --- a/contrib/ntp/ntpd/refclock_arc.c +++ b/contrib/ntp/ntpd/refclock_arc.c @@ -303,10 +303,13 @@ Also note h<cr> command which starts a resync to MSF signal. */ +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" #include <stdio.h> #include <ctype.h> -#include <sys/time.h> #if defined(HAVE_BSD_TTYS) #include <sgtty.h> @@ -320,11 +323,6 @@ Also note h<cr> command which starts a resync to MSF signal. #include <termios.h> #endif -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" - /* * This driver supports the ARCRON MSF Radio Controlled Clock */ diff --git a/contrib/ntp/ntpd/refclock_as2201.c b/contrib/ntp/ntpd/refclock_as2201.c index 2c10440..516f7ad 100644 --- a/contrib/ntp/ntpd/refclock_as2201.c +++ b/contrib/ntp/ntpd/refclock_as2201.c @@ -8,16 +8,15 @@ #if defined(REFCLOCK) && defined(CLOCK_AS2201) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports the Austron 2200A/2201A GPS Receiver with * Buffered RS-232-C Interface Module. Note that the original 2200/2201 diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c index 764f6e0..56f86b3 100644 --- a/contrib/ntp/ntpd/refclock_atom.c +++ b/contrib/ntp/ntpd/refclock_atom.c @@ -5,8 +5,6 @@ #include <config.h> #endif -#if defined(REFCLOCK) && defined(CLOCK_ATOM) - #include <stdio.h> #include <ctype.h> @@ -16,15 +14,8 @@ #include "ntp_refclock.h" #include "ntp_stdlib.h" -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif -#ifdef HAVE_SYS_TERMIOS_H -# include <sys/termios.h> -#endif -#ifdef HAVE_SYS_PPSCLOCK_H -# include <sys/ppsclock.h> -#endif +#if defined(REFCLOCK) && defined(CLOCK_ATOM) + #ifdef HAVE_PPSAPI # ifdef HAVE_TIMEPPS_H # include <timepps.h> @@ -37,120 +28,109 @@ /* * This driver furnishes an interface for pulse-per-second (PPS) signals - * produced by a cesium clock, timing receiver or related equipment. It + * produced by a cesium clock, timing receiver or related equipment. It * can be used to remove accumulated jitter and retime a secondary * server when synchronized to a primary server over a congested, wide- * area network and before redistributing the time to local clients. * - * In order for this driver to work, the local clock must be set to + * Before this driver becomes active, the local clock must be set to * within +-500 ms by another means, such as a radio clock or NTP - * itself. The 1-pps signal is connected via a serial port and gadget - * box consisting of a one-shot flopflop and RS232 level converter. - * Conntection is either via the carrier detect (DCD) lead or via the - * receive data (RD) lead. The incidental jitter using the DCD lead is - * essentially the interrupt latency. The incidental jitter using the RD - * lead has an additional component due to the line sampling clock. When - * operated at 38.4 kbps, this arrangement has a worst-case jitter less - * than 26 us. + * itself. There are two ways to connect the PPS signal, normally at TTL + * levels, to the computer. One is to shift to EIA levels and connect to + * pin 8 (DCD) of a serial port. This requires a level converter and + * may require a one-shot flipflop to lengthen the pulse. The other is + * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell + * port. These methods are architecture dependent. * - * There are four ways in which this driver can be used. They are - * described in decreasing order of merit below. The first way uses the - * ppsapi STREAMS module and the LDISC_PPS line discipline, while the - * second way uses the ppsclock STREAMS module and the LDISC_PPS line - * discipline. Either of these works only for the baseboard serial ports - * of the Sun SPARC IPC and clones. However, the ppsapi uses the - * proposed IETF interface expected to become standard for PPS signals. - * The serial port to be used is specified by the pps command in the - * configuration file. This driver reads the timestamp directly by a - * designated ioctl() system call. + * Both methods require a modified device driver and kernel interface + * compatible with the Pulse-per-Second API for Unix-like Operating + * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are + * available for FreeBSD, Linux, SunOS, Solaris and Alpha. However, at + * present only the Alpha implementation provides the full generality of + * the API with multiple PPS drivers and multiple handles per driver. * - * The third way uses the LDISC_CLKPPS line discipline and works for - * any architecture supporting a serial port. If after a few seconds - * this driver finds no ppsclock module configured, it attempts to open - * a serial port device /dev/pps%d, where %d is the unit number, and - * assign the LDISC_CLKPPS line discipline to it. If the line discipline - * fails, no harm is done except the accuracy is reduced somewhat. The - * pulse generator in the gadget box is adjusted to produce a start bit - * of length 26 usec at 38400 bps. Used with the LDISC_CLKPPS line - * discipline, this produces an ASCII DEL character ('\377') followed by - * a timestamp at each seconds epoch. + * In many configurations a single port is used for the radio timecode + * and PPS signal. In order to provide for this configuration and others + * involving dedicated multiple serial/parallel ports, the driver first + * attempts to open the device /dev/pps%d, where %d is the unit number. + * If this fails, the driver attempts to open the device specified by + * the pps configuration command. If a port is to be shared, the pps + * command must be placed before the radio device(s) and the radio + * device(s) must be placed before the PPS driver(s) in the + * configuration file. * - * The fourth way involves an auxiliary radio clock driver which calls - * the PPS driver with a timestamp captured by that driver. This use is - * documented in the source code for the driver(s) involved. Note that - * some drivers collect the sample information themselves before calling - * pps_sample(), and others call knowing only that they are running - * shortly after an on-time tick and they expect to retrieve the PPS - * offset, fudge their result, and insert it into the timestream. + * This driver normally uses the PLL/FLL clock discipline implemented in + * the ntpd code. If kernel support is available, the kernel PLL/FLL + * clock discipline is used instead. The default configuration is not to + * use the kernel PPS discipline, if present. The kernel PPS discipline + * can be enabled using the pps command. * * Fudge Factors * * There are no special fudge factors other than the generic. The fudge - * time1 parameter can be used to compensate for miscellaneous UART and - * OS delays. Allow about 247 us for uart delays at 38400 bps and about - * 1 ms for STREAMS nonsense with older workstations. Velocities may - * vary with modern workstations. + * time1 parameter can be used to compensate for miscellaneous device + * driver and OS delays. */ /* * Interface definitions */ #ifdef HAVE_PPSAPI -extern int pps_assert; +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 */ -#ifdef TTYCLK -#define DEVICE "/dev/pps%d" /* device name and unit */ -#ifdef B38400 -#define SPEED232 B38400 /* uart speed (38400 baud) */ -#else -#define SPEED232 EXTB /* as above */ -#endif -#endif /* TTYCLK */ #define PRECISION (-20) /* precision assumed (about 1 us) */ #define REFID "PPS\0" /* reference ID */ #define DESCRIPTION "PPS Clock Discipline" /* WRU */ +#define NANOSECOND 1000000000 /* one second (ns) */ +#define RANGEGATE 500000 /* range gate (ns) */ +#define ASTAGE 8 /* filter stages */ -#define FLAG_TTY 0x01 /* tty_clk heard from */ -#define FLAG_PPS 0x02 /* ppsclock heard from */ -#define FLAG_AUX 0x04 /* auxiliary PPS source */ - -static struct peer *pps_peer; /* atom driver for auxiliary PPS sources */ - -#ifdef TTYCLK -static void atom_receive P((struct recvbuf *)); -#endif /* TTYCLK */ +static struct peer *pps_peer; /* atom driver for PPS sources */ +#ifdef HAVE_PPSAPI /* - * Unit control structure + * PPS unit control structure */ -struct atomunit { -#ifdef HAVE_PPSAPI - pps_info_t pps_info; /* pps_info control */ -#endif /* HAVE_PPSAPI */ -#ifdef PPS - struct ppsclockev ev; /* ppsclock control */ -#endif /* PPS */ - int flags; /* flags that wave */ +struct ppsunit { + struct timespec ts; /* last timestamp */ + int fddev; /* pps device descriptor */ + pps_params_t pps_params; /* pps parameters */ + pps_info_t pps_info; /* last pps data */ + pps_handle_t handle; /* pps handlebars */ }; +#endif /* HAVE_PPSAPI */ /* * Function prototypes */ static int atom_start P((int, struct peer *)); -static void atom_shutdown P((int, struct peer *)); static void atom_poll P((int, struct peer *)); -#if defined(PPS) || defined(HAVE_PPSAPI) +#ifdef HAVE_PPSAPI +static void atom_shutdown P((int, struct peer *)); +static void atom_control P((int, struct refclockstat *, struct + refclockstat *, struct peer *)); static int atom_pps P((struct peer *)); -#endif /* PPS || HAVE_PPSAPI */ +static int atom_ppsapi P((struct peer *, int, int)); +#endif /* HAVE_PPSAPI */ /* * Transfer vector */ struct refclock refclock_atom = { atom_start, /* start up driver */ +#ifdef HAVE_PPSAPI atom_shutdown, /* shut down driver */ +#else + noentry, /* shut down driver */ +#endif /* HAVE_PPSAPI */ atom_poll, /* transmit poll message */ - noentry, /* not used (old atom_control) */ +#ifdef HAVE_PPSAPI + atom_control, /* fudge control */ +#else + noentry, /* fudge control */ +#endif /* HAVE_PPSAPI */ noentry, /* initialize driver */ noentry, /* not used (old atom_buginfo) */ NOFLAGS /* not used */ @@ -162,74 +142,142 @@ struct refclock refclock_atom = { */ static int atom_start( - int unit, - struct peer *peer + int unit, /* unit number (not used) */ + struct peer *peer /* peer structure pointer */ ) { - register struct atomunit *up; struct refclockproc *pp; - int flags; -#ifdef TTYCLK - int fd = 0; - char device[20]; - int ldisc = LDISC_CLKPPS; -#endif /* TTYCLK */ +#ifdef HAVE_PPSAPI + register struct ppsunit *up; + char device[80]; +#endif /* HAVE_PPSAPI */ + /* + * Allocate and initialize unit structure + */ pps_peer = peer; - flags = 0; + pp = peer->procptr; + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + 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)); + pp->unitptr = (caddr_t)up; -#ifdef TTYCLK -# if defined(SCO5_CLOCK) - ldisc = LDISC_RAW; /* DCD timestamps without any line discipline */ -# endif /* - * Open serial port. Use LDISC_CLKPPS line discipline only - * if the LDISC_PPS line discipline is not availble, + * Open PPS device. If this fails and some driver has already + * opened the associated radio device, fdpps has the file + * descriptor for it. */ -# if defined(PPS) || defined(HAVE_PPSAPI) - if (fdpps <= 0) -# endif - { - (void)sprintf(device, DEVICE, unit); - if ((fd = refclock_open(device, SPEED232, ldisc)) != 0) - flags |= FLAG_TTY; + sprintf(device, DEVICE, unit); + up->fddev = open(device, O_RDWR, 0777); + if (up->fddev <= 0 && fdpps > 0) { + strcpy(device, pps_device); + up->fddev = fdpps; + } + if (up->fddev <= 0) { + msyslog(LOG_ERR, + "refclock_atom: %s: %m", device); + return (0); } -#endif /* TTYCLK */ /* - * Allocate and initialize unit structure + * Light off the PPSAPI interface. If this PPS device is shared + * with the radio device, take the default options from the pps + * command. This is for legacy purposes. */ - if (!(up = (struct atomunit *)emalloc(sizeof(struct atomunit)))) { -#ifdef TTYCLK - if (flags & FLAG_TTY) - (void) close(fd); -#endif /* TTYCLK */ + if (time_pps_create(up->fddev, &up->handle) < 0) { + msyslog(LOG_ERR, + "refclock_atom: time_pps_create failed: %m"); return (0); } - memset((char *)up, 0, sizeof(struct atomunit)); + return (atom_ppsapi(peer, pps_assert, pps_hardpps)); +#else /* HAVE_PPSAPI */ + return (1); +#endif /* HAVE_PPSAPI */ +} + + +#ifdef HAVE_PPSAPI +/* + * atom_control - fudge control + */ +static void +atom_control( + int unit, /* unit (not used */ + struct refclockstat *in, /* input parameters (not uded) */ + struct refclockstat *out, /* output parameters (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + pp = peer->procptr; - pp->unitptr = (caddr_t)up; -#ifdef TTYCLK - if (flags & FLAG_TTY) { - pp->io.clock_recv = atom_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); + atom_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2, + pp->sloppyclockflag & CLK_FLAG3); +} + + +/* + * Initialize PPSAPI + */ +int +atom_ppsapi( + struct peer *peer, /* peer structure pointer */ + int enb_clear, /* clear enable */ + int enb_hardpps /* hardpps enable */ + ) +{ + struct refclockproc *pp; + register struct ppsunit *up; + int capability; + + pp = peer->procptr; + up = (struct ppsunit *)pp->unitptr; + if (time_pps_getcap(up->handle, &capability) < 0) { + msyslog(LOG_ERR, + "refclock_atom: time_pps_getcap failed: %m"); + return (0); + } + memset(&up->pps_params, 0, sizeof(pps_params_t)); + if (enb_clear) + up->pps_params.mode = capability & PPS_CAPTURECLEAR; + else + up->pps_params.mode = capability & PPS_CAPTUREASSERT; + if (!up->pps_params.mode) { + msyslog(LOG_ERR, + "refclock_atom: invalid capture edge %d", + pps_assert); + return (0); + } + up->pps_params.mode |= PPS_TSFMT_TSPEC; + if (time_pps_setparams(up->handle, &up->pps_params) < 0) { + msyslog(LOG_ERR, + "refclock_atom: time_pps_setparams failed: %m"); + return (0); + } + if (enb_hardpps) { + if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, + up->pps_params.mode & ~PPS_TSFMT_TSPEC, + PPS_TSFMT_TSPEC) < 0) { + msyslog(LOG_ERR, + "refclock_atom: time_pps_kcbind failed: %m"); return (0); } + pps_enable = 1; } -#endif /* TTYCLK */ - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->flags = flags; +#if DEBUG + if (debug) { + time_pps_getparams(up->handle, &up->pps_params); + printf( + "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x kern %d\n", + up->fddev, capability, up->pps_params.api_version, + up->pps_params.mode, enb_hardpps); + } +#endif return (1); } @@ -239,181 +287,122 @@ atom_start( */ static void atom_shutdown( - int unit, - struct peer *peer + int unit, /* unit number (not used) */ + struct peer *peer /* peer structure pointer */ ) { - register struct atomunit *up; struct refclockproc *pp; + register struct ppsunit *up; pp = peer->procptr; - up = (struct atomunit *)pp->unitptr; -#ifdef TTYCLK - if (up->flags & FLAG_TTY) - io_closeclock(&pp->io); -#endif /* TTYCLK */ + up = (struct ppsunit *)pp->unitptr; + if (up->fddev > 0) + close(up->fddev); + if (up->handle != 0) + time_pps_destroy(up->handle); if (pps_peer == peer) pps_peer = 0; free(up); } -#if defined(PPS) || defined(HAVE_PPSAPI) /* - * atom_pps - receive data from the LDISC_PPS discipline + * atom_pps - receive data from the PPSAPI interface + * + * This routine is called once per second when the PPSAPI interface is + * present. It snatches the PPS timestamp from the kernel and saves the + * sign-extended fraction in a circular buffer for processing at the + * next poll event. */ static int atom_pps( - struct peer *peer + struct peer *peer /* peer structure pointer */ ) { - register struct atomunit *up; + register struct ppsunit *up; struct refclockproc *pp; -#ifdef HAVE_PPSAPI - struct timespec timeout; -# ifdef HAVE_TIMESPEC - struct timespec ts; -# else - struct timeval ts; -# endif /* HAVE_TIMESPEC */ -#endif /* HAVE_PPSAPI */ - l_fp lftmp; - double doffset; - int i; -#if !defined(HAVE_PPSAPI) - int request = -# ifdef HAVE_CIOGETEV - CIOGETEV -# endif -# ifdef HAVE_TIOCGPPSEV - TIOCGPPSEV -# endif - ; -#endif /* HAVE_PPSAPI */ + pps_info_t pps_info; + struct timespec timeout, ts; + double dtemp; /* - * This routine is called once per second when the LDISC_PPS - * discipline is present. It snatches the pps timestamp from the - * kernel and saves the sign-extended fraction in a circular - * buffer for processing at the next poll event. - */ - pp = peer->procptr; - up = (struct atomunit *)pp->unitptr; - - /* - * Convert the timeval to l_fp and save for billboards. Sign- - * extend the fraction and stash in the buffer. No harm is done - * if previous data are overwritten. If the discipline comes bum - * or the data grow stale, just forget it. Round the nanoseconds - * to microseconds with great care. + * Convert the timespec nanoseconds field to signed double and + * save in the median filter. for billboards. No harm is done if + * previous data are overwritten. If the discipline comes bum or + * the data grow stale, just forget it. A range gate rejects new + * samples if less than a jiggle time from the next second. */ - if (fdpps <= 0) - return (1); -#ifdef HAVE_PPSAPI + pp = peer->procptr; + up = (struct ppsunit *)pp->unitptr; + if (up->handle == 0) + return (-1); timeout.tv_sec = 0; timeout.tv_nsec = 0; - i = up->pps_info.assert_sequence; - if (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &up->pps_info, &timeout) - < 0) - return (2); - if (i == up->pps_info.assert_sequence) - return (3); - if (pps_assert) + memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); + if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, + &timeout) < 0) + return (-1); + if (up->pps_params.mode & PPS_CAPTUREASSERT) { + if (pps_info.assert_sequence == + up->pps_info.assert_sequence) + return (1); ts = up->pps_info.assert_timestamp; - else + } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { + if (pps_info.clear_sequence == + up->pps_info.clear_sequence) + return (1); ts = up->pps_info.clear_timestamp; - pp->lastrec.l_ui = ts.tv_sec + JAN_1970; - ts.tv_nsec = (ts.tv_nsec + 500) / 1000; - if (ts.tv_nsec > 1000000) { - ts.tv_nsec -= 1000000; - ts.tv_sec++; + } else { + return (-1); } - TVUTOTSF(ts.tv_nsec, pp->lastrec.l_uf); -#else - i = up->ev.serial; - if (ioctl(fdpps, request, (caddr_t)&up->ev) < 0) - return (2); - if (i == up->ev.serial) - return (3); - pp->lastrec.l_ui = up->ev.tv.tv_sec + JAN_1970; - TVUTOTSF(up->ev.tv.tv_usec, pp->lastrec.l_uf); -#endif /* HAVE_PPSAPI */ - up->flags |= FLAG_PPS; - L_CLR(&lftmp); - L_ADDF(&lftmp, pp->lastrec.l_f); - LFPTOD(&lftmp, doffset); - SAMPLE(-doffset + pp->fudgetime1); + if (!((ts.tv_sec == up->ts.tv_sec && ts.tv_nsec - + up->ts.tv_nsec > NANOSECOND - RANGEGATE) || + (ts.tv_sec - up->ts.tv_sec == 1 && ts.tv_nsec - + up->ts.tv_nsec < RANGEGATE))) { + up->ts = ts; + return (1); + } + up->ts = ts; + pp->lastrec.l_ui = ts.tv_sec + JAN_1970; + dtemp = ts.tv_nsec * FRAC / 1e9; + if (dtemp >= FRAC) + pp->lastrec.l_ui++; + pp->lastrec.l_uf = (u_int32)dtemp; + if (ts.tv_nsec > NANOSECOND / 2) + ts.tv_nsec -= NANOSECOND; + dtemp = -(double)ts.tv_nsec / NANOSECOND; + SAMPLE(dtemp + pp->fudgetime1); +#ifdef DEBUG + if (debug > 1) + printf("atom_pps %f %f\n", dtemp, pp->fudgetime1); +#endif return (0); } -#endif /* PPS || HAVE_PPSAPI */ - -#ifdef TTYCLK -/* - * atom_receive - receive data from the LDISC_CLK discipline - */ -static void -atom_receive( - struct recvbuf *rbufp - ) -{ - register struct atomunit *up; - struct refclockproc *pp; - struct peer *peer; - l_fp lftmp; - double doffset; - - /* - * This routine is called once per second when the serial - * interface is in use. It snatches the timestamp from the - * buffer and saves the sign-extended fraction in a circular - * buffer for processing at the next poll event. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct atomunit *)pp->unitptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, - &pp->lastrec); +#endif /* HAVE_PPSAPI */ - /* - * Save the timestamp for billboards. Sign-extend the fraction - * and stash in the buffer. No harm is done if previous data are - * overwritten. Do this only if the ppsclock gizmo is not - * working. - */ - if (up->flags & FLAG_PPS) - return; - L_CLR(&lftmp); - L_ADDF(&lftmp, pp->lastrec.l_f); - LFPTOD(&lftmp, doffset); - SAMPLE(-doffset + pp->fudgetime1); -} -#endif /* TTYCLK */ /* * pps_sample - receive PPS data from some other clock driver + * + * This routine is called once per second when the external clock driver + * processes PPS information. It processes the PPS timestamp and saves + * the sign-extended fraction in a circular buffer for processing at the + * next poll event. This works only for a single PPS device. */ int pps_sample( - l_fp *offset + l_fp *offset /* PPS offset */ ) { register struct peer *peer; - register struct atomunit *up; struct refclockproc *pp; l_fp lftmp; double doffset; - /* - * This routine is called once per second when the external - * clock driver processes PPS information. It processes the pps - * timestamp and saves the sign-extended fraction in a circular - * buffer for processing at the next poll event. - */ peer = pps_peer; if (peer == 0) /* nobody home */ - return 1; + return (1); pp = peer->procptr; - up = (struct atomunit *)pp->unitptr; /* * Convert the timeval to l_fp and save for billboards. Sign- @@ -421,7 +410,6 @@ pps_sample( * if previous data are overwritten. If the discipline comes bum * or the data grow stale, just forget it. */ - up->flags |= FLAG_AUX; pp->lastrec = *offset; L_CLR(&lftmp); L_ADDF(&lftmp, pp->lastrec.l_f); @@ -432,63 +420,81 @@ pps_sample( /* * atom_poll - called by the transmit procedure + * + * This routine is called once per second when in burst mode to save PPS + * sample offsets in the median filter. At the end of the burst period + * the samples are processed as a heap and the clock filter updated. */ static void atom_poll( - int unit, - struct peer *peer + int unit, /* unit number (not used) */ + struct peer *peer /* peer structure pointer */ ) { -#if defined(PPS) || defined(HAVE_PPSAPI) - register struct atomunit *up; -#endif /* PPS || HAVE_PPSAPI */ struct refclockproc *pp; +#ifdef HAVE_PPSAPI + int err; +#endif /* HAVE_PPSAPI */ /* - * Accumulate samples in the median filter. At the end of each - * poll interval, do a little bookeeping and process the - * samples. + * Accumulate samples in the median filter. If a noise sample, + * return with no prejudice; if a protocol error, get mean; + * otherwise, cool. At the end of each poll interval, do a + * little bookeeping and process the surviving samples. */ pp = peer->procptr; -#if defined(PPS) || defined(HAVE_PPSAPI) - up = (struct atomunit *)pp->unitptr; - if (!(up->flags & !(FLAG_AUX | FLAG_TTY))) { - int err; - - err = atom_pps(peer); - if (err > 0) { - refclock_report(peer, CEVNT_FAULT); - return; - } - } -#endif /* PPS || HAVE_PPSAPI */ pp->polls++; - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); +#ifdef HAVE_PPSAPI + err = atom_pps(peer); + if (err < 0) { + refclock_report(peer, CEVNT_FAULT); return; } +#endif /* HAVE_PPSAPI */ /* - * Valid time (leap bits zero) is returned only if the prefer - * peer has survived the intersection algorithm and within - * clock_max of local time and not too long ago. This ensures - * the pps time is within +-0.5 s of the local time and the - * seconds numbering is unambiguous. + * Valid time is returned only if the prefer peer has survived + * the intersection algorithm and within clock_max of local time + * and not too long ago. This ensures the PPS time is within + * +-0.5 s of the local time and the seconds numbering is + * unambiguous. Note that the leap bits are set no-warning on + * the first valid update and the stratum is set at the prefer + * peer. */ - if (pps_update) { - pp->leap = LEAP_NOWARNING; - } else { - pp->leap = LEAP_NOTINSYNC; + if (peer->burst > 0) + return; + peer->stratum = STRATUM_UNSPEC; + if (pp->codeproc == pp->coderecv) { + refclock_report(peer, CEVNT_TIMEOUT); + peer->burst = ASTAGE; + return; + + } else if (!sys_prefer) { + pp->codeproc = pp->coderecv; + peer->burst = ASTAGE; + return; + + } else if (fabs(sys_prefer->offset) > clock_max) { + pp->codeproc = pp->coderecv; + peer->burst = ASTAGE; return; } - pp->variance = 0; - record_clock_stats(&peer->srcadr, pp->a_lastcode); + peer->stratum = sys_prefer->stratum; + if (peer->stratum <= 1) + peer->refid = pp->refid; + else + peer->refid = peer->srcadr.sin_addr.s_addr; + pp->leap = LEAP_NOWARNING; refclock_receive(peer); - peer->burst = MAXSTAGE; + peer->burst = ASTAGE; } - #else int refclock_atom_bs; +int +pps_sample( + l_fp *offset /* PPS offset */ + ) +{ + return 1; +} #endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_bancomm.c b/contrib/ntp/ntpd/refclock_bancomm.c index 95c211b..a3debcb 100644 --- a/contrib/ntp/ntpd/refclock_bancomm.c +++ b/contrib/ntp/ntpd/refclock_bancomm.c @@ -32,12 +32,6 @@ #endif #if defined(REFCLOCK) && defined(CLOCK_BANC) -#include <stdio.h> -#include <syslog.h> -#include <ctype.h> -#include <string.h> -#include <strings.h> -#include <sys/time.h> #include "ntpd.h" #include "ntp_io.h" @@ -45,6 +39,10 @@ #include "ntp_unixtime.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> + /* STUFF BY RES */ struct btfp_time /* Structure for reading 5 time words */ /* in one ioctl(2) operation. */ @@ -83,11 +81,6 @@ struct vmedate { /* structure returned by get_vmetime.c */ /* END OF STUFF FROM RES */ /* - * Definitions - */ -#define MAXUNITS 2 /* max number of VME units */ - -/* * VME interface parameters. */ #define VMEPRECISION (-21) /* precision assumed (1 us) */ @@ -119,14 +112,6 @@ struct vmeunit { }; /* - * Keep the fudge factors separately so they can be set even - * when no clock is configured. - */ -static double fudgefactor[MAXUNITS]; -static u_char stratumtouse[MAXUNITS]; -static u_char sloppyclockflag[MAXUNITS]; - -/* * Function prototypes */ static void vme_init (void); @@ -140,35 +125,18 @@ struct vmedate *get_datumtime(struct vmedate *); * Transfer vector */ struct refclock refclock_bancomm = { - vme_start, - vme_shutdown, - vme_poll, - noentry, /* not used (old vme_control) */ - vme_init, - noentry, /* not used (old vme_buginfo) */ - NOFLAGS + vme_start, /* start up driver */ + vme_shutdown, /* shut down driver */ + vme_poll, /* transmit poll message */ + noentry, /* not used (old vme_control) */ + noentry, /* initialize driver */ + noentry, /* not used (old vme_buginfo) */ + NOFLAGS /* not used */ }; int fd_vme; /* file descriptor for ioctls */ int regvalue; -/* - * vme_init - initialize internal vme driver data - */ -static void -vme_init(void) -{ - register int i; - - /* - * Initialize fudge factors to default. - */ - for (i = 0; i < MAXUNITS; i++) { - fudgefactor[i] = 0.0; - stratumtouse[i] = 0; - sloppyclockflag[i] = 0; - } -} /* * vme_start - open the VME device and initialize data for processing @@ -185,14 +153,6 @@ vme_start( char vmedev[20]; /* - * Check configuration info. - */ - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_start: unit %d invalid", unit); - return (0); - } - - /* * Open VME device */ #ifdef DEBUG @@ -236,13 +196,8 @@ vme_start( * return success. Note that root delay and root dispersion are * always zero for this clock. */ - pp->leap = LEAP_NOWARNING; peer->precision = VMEPRECISION; - peer->stratum = stratumtouse[unit]; - memcpy( (char *)&peer->refid, USNOREFID,4); - - peer->refid = htonl(VMEHSREFID); - + memcpy(&pp->refid, USNOREFID,4); return (1); } @@ -258,17 +213,11 @@ vme_shutdown( { register struct vmeunit *vme; struct refclockproc *pp; - - pp = peer->procptr; - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit); - return; - } /* * Tell the I/O module to turn us off. We're history. */ + pp = peer->procptr; vme = (struct vmeunit *)pp->unitptr; io_closeclock(&pp->io); pp->unitptr = NULL; diff --git a/contrib/ntp/ntpd/refclock_chronolog.c b/contrib/ntp/ntpd/refclock_chronolog.c index 2982ecc..9273a84 100644 --- a/contrib/ntp/ntpd/refclock_chronolog.c +++ b/contrib/ntp/ntpd/refclock_chronolog.c @@ -13,17 +13,15 @@ #if defined(REFCLOCK) && defined(CLOCK_CHRONOLOG) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#include <time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports the Chronolog K-series WWVB receiver. * diff --git a/contrib/ntp/ntpd/refclock_chu.c b/contrib/ntp/ntpd/refclock_chu.c index 4235b8e..10fcea5 100644 --- a/contrib/ntp/ntpd/refclock_chu.c +++ b/contrib/ntp/ntpd/refclock_chu.c @@ -7,20 +7,19 @@ #if defined(REFCLOCK) && defined(CLOCK_CHU) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#include <time.h> -#include <math.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" -#ifdef AUDIO_CHU + +#include <stdio.h> +#include <ctype.h> +#include <math.h> + +#ifdef HAVE_AUDIO #include "audio.h" -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ #define ICOM 1 /* undefine to suppress ICOM code */ @@ -173,10 +172,18 @@ * Fudge flag3 enables audio monitoring of the input signal. For this * purpose, the speaker volume must be set before the driver is started. * - * The ICOM code is normally compiled in the driver. It isn't used, - * unless the mode keyword on the server configuration command specifies - * a nonzero ICOM ID select code. The C-IV trace is turned on if the - * debug level is greater than one. + * 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. + * 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 + * specifies a nonzero mode (ICOM ID select code). The C-IV speed is + * 9600 bps if the high order 0x80 bit of the mode is zero and 1200 bps + * if one. The C-IV trace is turned on if the debug level is greater + * than one. */ /* * Interface definitions @@ -184,12 +191,13 @@ #define SPEED232 B300 /* uart speed (300 baud) */ #define PRECISION (-10) /* precision assumed (about 1 ms) */ #define REFID "CHU" /* reference ID */ +#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 NCHAN 3 /* number of channels */ #endif /* ICOM */ -#ifdef AUDIO_CHU -#define DESCRIPTION "CHU Modem Receiver" /* WRU */ +#ifdef HAVE_AUDIO /* * Audio demodulator definitions @@ -202,11 +210,11 @@ #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 */ #else -#define DEVICE "/dev/chu%d" /* device name and unit */ -#define SPEED232 B300 /* UART speed (300 baud) */ -#define DESCRIPTION "CHU Audio Receiver" /* WRU */ -#endif /* AUDIO_CHU */ +#define DESCRIPTION "CHU Modem Receiver" /* WRU */ +#endif /* HAVE_AUDIO */ /* * Decoder definitions @@ -255,14 +263,14 @@ #define DECERR 0x04 /* data decoding error */ #define TSPERR 0x08 /* insufficient data */ -#ifdef AUDIO_CHU +#ifdef HAVE_AUDIO struct surv { double shift[12]; /* mark register */ double es_max, es_min; /* max/min envelope signals */ double dist; /* sample distance */ int uart; /* decoded character */ }; -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ /* * CHU unit control structure @@ -279,9 +287,9 @@ struct chuunit { int bufptr; /* buffer index pointer */ char ident[10]; /* transmitter frequency */ #ifdef ICOM + int fd_icom; /* ICOM file descriptor */ int chan; /* frequency identifier */ int dwell; /* dwell minutes at current frequency */ - int fd_icom; /* ICOM file descriptor */ #endif /* ICOM */ /* @@ -304,10 +312,11 @@ struct chuunit { int tai; /* TAI - UTC correction */ int dst; /* Canadian DST code */ -#ifdef AUDIO_CHU +#ifdef HAVE_AUDIO /* * Audio codec variables */ + int fd_audio; /* audio port file descriptor */ double comp[SIZE]; /* decompanding table */ int port; /* codec port */ int gain; /* codec gain */ @@ -333,7 +342,7 @@ struct chuunit { struct surv surv[8]; /* UART survivor structures */ int decptr; /* decode pointer */ int dbrk; /* holdoff counter */ -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ }; /* @@ -354,11 +363,13 @@ 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 *)); -#ifdef AUDIO_CHU +#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 *)); -#endif /* AUDIO_CHU */ +static void chu_audio_receive P((struct recvbuf *rbufp)); +#endif /* HAVE_AUDIO */ +static void chu_serial_receive P((struct recvbuf *rbufp)); /* * Global variables @@ -393,43 +404,52 @@ chu_start( { struct chuunit *up; struct refclockproc *pp; + char device[20]; /* device name */ int fd; /* file descriptor */ #ifdef ICOM char tbuf[80]; /* trace buffer */ int temp; #endif /* ICOM */ -#ifdef AUDIO_CHU +#ifdef HAVE_AUDIO + int fd_audio; /* audio port file descriptor */ int i; /* index */ double step; /* codec adjustment */ /* - * Open audio device + * Open audio device. */ - fd = audio_init(); - if (fd < 0) - return (0); + fd_audio = audio_init(DEVICE_AUDIO); #ifdef DEBUG - if (debug) + if (fd_audio > 0 && debug) audio_show(); #endif -#else - char device[20]; /* device name */ /* * Open serial port in raw mode. */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_RAW))) { - return (0); + if (fd_audio > 0) { + fd = fd_audio; + } else { + sprintf(device, DEVICE, unit); + fd = refclock_open(device, SPEED232, LDISC_RAW); } -#endif /* AUDIO_CHU */ +#else /* HAVE_AUDIO */ + + /* + * Open serial port in raw mode. + */ + sprintf(device, DEVICE, unit); + fd = refclock_open(device, SPEED232, LDISC_RAW); +#endif /* HAVE_AUDIO */ + if (fd <= 0) + return (0); /* * Allocate and initialize unit structure */ if (!(up = (struct chuunit *) emalloc(sizeof(struct chuunit)))) { - (void) close(fd); + close(fd); return (0); } memset((char *)up, 0, sizeof(struct chuunit)); @@ -440,7 +460,7 @@ chu_start( pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { - (void)close(fd); + close(fd); free(up); return (0); } @@ -452,13 +472,15 @@ chu_start( pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); DTOLFP(CHAR, &up->charstamp); -#ifdef AUDIO_CHU - up->gain = 127; +#ifdef HAVE_AUDIO /* * The companded samples are encoded sign-magnitude. The table - * contains all the 256 values in the interest of speed. + * contains all the 256 values in the interest of speed. We do + * this even if the audio codec is not available. C'est la lazy. */ + up->fd_audio = fd_audio; + up->gain = 127; up->comp[0] = up->comp[OFFSET] = 0.; up->comp[1] = 1; up->comp[OFFSET + 1] = -1.; up->comp[2] = 3; up->comp[OFFSET + 2] = -3.; @@ -470,7 +492,7 @@ chu_start( step *= 2.; } DTOLFP(1. / SECOND, &up->tick); -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ strcpy(up->ident, "X"); #ifdef ICOM temp = 0; @@ -478,8 +500,8 @@ chu_start( if (debug > 1) temp = P_TRACE; #endif - if (peer->ttl > 0) { - if (peer->ttl & 0x80) + if (peer->ttlmax > 0) { + if (peer->ttlmax & 0x80) up->fd_icom = icom_init("/dev/icom", B1200, temp); else @@ -487,7 +509,7 @@ chu_start( temp); } if (up->fd_icom > 0) { - if (icom_freq(up->fd_icom, peer->ttl & 0x7f, + if (icom_freq(up->fd_icom, peer->ttlmax & 0x7f, qsy[up->chan]) < 0) { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) msyslog(LOG_ERR, @@ -524,22 +546,58 @@ chu_shutdown( pp = peer->procptr; up = (struct chuunit *)pp->unitptr; + if (up == NULL) + return; io_closeclock(&pp->io); if (up->fd_icom > 0) close(up->fd_icom); free(up); } -#ifdef AUDIO_CHU - /* - * chu_receive - receive data from the audio device + * chu_receive - receive data from the audio or serial device */ static void chu_receive( struct recvbuf *rbufp /* receive buffer structure pointer */ ) { +#ifdef HAVE_AUDIO + struct chuunit *up; + struct refclockproc *pp; + struct peer *peer; + + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * If the audio codec is warmed up, the buffer contains codec + * samples which need to be demodulated and decoded into CHU + * characters using the software UART. Otherwise, the buffer + * contains CHU characters from the serial port, so the software + * UART is bypassed. In this case the CPU will probably run a + * few degrees cooler. + */ + if (up->fd_audio > 0) + chu_audio_receive(rbufp); + else + chu_serial_receive(rbufp); +#else + chu_serial_receive(rbufp); +#endif /* HAVE_AUDIO */ +} + +#ifdef HAVE_AUDIO + +/* + * chu_audio_receive - receive data from the audio device + */ +static void +chu_audio_receive( + struct recvbuf *rbufp /* receive buffer structure pointer */ + ) +{ struct chuunit *up; struct refclockproc *pp; struct peer *peer; @@ -712,9 +770,9 @@ chu_rf( up->disc[up->discptr] = limit; up->discptr = (up->discptr + 1 ) % LAG; if (disc >= 0) - disc = sqrt(disc); + disc = SQRT(disc); else - disc = -sqrt(-disc); + disc = -SQRT(-disc); /* * Lowpass filter. Raised cosine, Ts = 1 / 300, beta = 0.1. @@ -849,14 +907,14 @@ chu_uart( sp->es_min = es_min; sp->dist = dist / (11 * (es_max - es_min)); } +#endif /* HAVE_AUDIO */ -#else /* AUDIO_CHU */ /* - * chu_receive - receive data from the serial interface + * chu_serial_receive - receive data from the serial device */ static void -chu_receive( +chu_serial_receive( struct recvbuf *rbufp /* receive buffer structure pointer */ ) { @@ -877,11 +935,10 @@ chu_receive( dpt = (u_char *)&rbufp->recv_space; chu_decode(peer, *dpt); } -#endif /* AUDIO_CHU */ /* - * chu_decode - decode the data + * chu_decode - decode the character data */ static void chu_decode( @@ -1108,14 +1165,20 @@ chu_a( if (temp > 9 || k + 9 >= nchar || temp != ((up->cbuf[k + 9] >> 4) & 0xf)) temp = 0; -#ifdef AUDIO_CHU - sprintf(tbuf, "chuA %04x %4.0f %2d %2d %2d %2d %1d ", - up->status, up->maxsignal, nchar, up->burdist, k, - up->syndist, temp); +#ifdef HAVE_AUDIO + if (up->fd_audio) + sprintf(tbuf, "chuA %04x %4.0f %2d %2d %2d %2d %1d ", + up->status, up->maxsignal, nchar, up->burdist, k, + up->syndist, temp); + else + sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", + up->status, nchar, up->burdist, k, up->syndist, + temp); + #else sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", up->status, nchar, up->burdist, k, up->syndist, temp); -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ for (i = 0; i < nchar; i++) sprintf(&tbuf[strlen(tbuf)], "%02x", up->cbuf[i]); @@ -1221,7 +1284,7 @@ chu_poll( } else if (up->fd_icom > 0) { up->dwell = 0; up->chan = (up->chan + 1) % NCHAN; - icom_freq(up->fd_icom, peer->ttl & 0x7f, qsy[up->chan]); + 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); @@ -1255,19 +1318,28 @@ chu_poll( } else { pp->leap = LEAP_NOWARNING; } -#ifdef AUDIO_CHU - sprintf(pp->a_lastcode, - "%c%1X %4d %3d %02d:%02d:%02d.000 %c%x %+d %d %d %s %d %d %d %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); +#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", + 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); + else + sprintf(pp->a_lastcode, + "%c%1X %4d %3d %02d:%02d:%02d.000 %c%x %+d %d %s %d %d %d %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); #else sprintf(pp->a_lastcode, "%c%1X %4d %3d %02d:%02d:%02d.000 %c%x %+d %d %s %d %d %d %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); -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ pp->lencode = strlen(pp->a_lastcode); /* @@ -1390,7 +1462,6 @@ chu_major( return (0); } pp->lastref = offset; - pp->variance = 0; for (i = 0; i < up->ntstamp; i++) { toffset = offset; L_SUB(&toffset, &up->tstamp[i]); @@ -1462,7 +1533,7 @@ chu_dist( } -#ifdef AUDIO_CHU +#ifdef HAVE_AUDIO /* * chu_gain - adjust codec gain * @@ -1500,7 +1571,7 @@ chu_gain( audio_gain(up->gain, up->port); up->clipcnt = 0; } -#endif /* AUDIO_CHU */ +#endif /* HAVE_AUDIO */ #else diff --git a/contrib/ntp/ntpd/refclock_conf.c b/contrib/ntp/ntpd/refclock_conf.c index 71140c8..0e6c927 100644 --- a/contrib/ntp/ntpd/refclock_conf.c +++ b/contrib/ntp/ntpd/refclock_conf.c @@ -24,7 +24,7 @@ extern struct refclock refclock_local; #define refclock_local refclock_none #endif -#ifdef CLOCK_TRAK +#if defined(CLOCK_TRAK) && defined(PPS) extern struct refclock refclock_trak; #else #define refclock_trak refclock_none @@ -60,7 +60,7 @@ extern struct refclock refclock_parse; #define refclock_parse refclock_none #endif -#if defined(CLOCK_MX4200) && defined(PPS) +#if defined(CLOCK_MX4200) && defined(HAVE_PPSAPI) extern struct refclock refclock_mx4200; #else #define refclock_mx4200 refclock_none @@ -186,7 +186,7 @@ extern struct refclock refclock_palisade; #define refclock_palisade refclock_none #endif -#ifdef CLOCK_ONCORE +#if defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI) extern struct refclock refclock_oncore; #else #define refclock_oncore refclock_none @@ -228,6 +228,17 @@ extern struct refclock refclock_fg; #define refclock_fg refclock_none #endif +#ifdef CLOCK_HOPF_SERIAL +extern struct refclock refclock_hopfser; +#else +#define refclock_hopfser refclock_none +#endif + +#ifdef CLOCK_HOPF_PCI +extern struct refclock refclock_hopfpci; +#else +#define refclock_hopfpci refclock_none +#endif /* * Order is clock_start(), clock_shutdown(), clock_poll(), @@ -273,7 +284,9 @@ struct refclock *refclock_conf[] = { &refclock_ulink, /* 34 REFCLOCK_ULINK */ &refclock_pcf, /* 35 REFCLOCK_PCF */ &refclock_wwv, /* 36 REFCLOCK_WWV_AUDIO */ - &refclock_fg /* 37 REFCLOCK_FG */ + &refclock_fg, /* 37 REFCLOCK_FG */ + &refclock_hopfser, /* 38 REFCLK_HOPF_SERIAL */ + &refclock_hopfpci /* 39 REFCLK_HOPF_PCI */ }; u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *); diff --git a/contrib/ntp/ntpd/refclock_datum.c b/contrib/ntp/ntpd/refclock_datum.c index 74a37db..db03c95 100644 --- a/contrib/ntp/ntpd/refclock_datum.c +++ b/contrib/ntp/ntpd/refclock_datum.c @@ -17,16 +17,15 @@ ** Include Files */ -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + #if defined(HAVE_BSD_TTYS) #include <sgtty.h> #endif /* HAVE_BSD_TTYS */ @@ -45,10 +44,6 @@ #endif /* WWVBCLK */ #endif /* STREAM */ -#if defined (WWVBPPS) -#include <sys/ppsclock.h> -#endif /* WWVBPPS */ - #include "ntp_stdlib.h" /* @@ -120,8 +115,8 @@ */ -#define PTSPRECISION (-10) /* precision assumed 1/1024 ms */ -#define DATMREFID "DATM" /* reference id */ +#define PRECISION (-10) /* precision assumed 1/1024 ms */ +#define REFID "DATM" /* reference id */ #define DATUM_DISPERSION 0 /* fixed dispersion = 0 ms */ #define DATUM_MAX_ERROR 0.100 /* limits on sigma squared */ @@ -238,7 +233,6 @@ datum_pts_start( { struct datum_pts_unit **temp_datum_pts_unit; struct datum_pts_unit *datum_pts; - #ifdef HAVE_TERMIOS struct termios arg; #endif @@ -304,6 +298,10 @@ datum_pts_start( msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver"); (void)close(datum_pts->PTS_fd); + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + return 0; #endif @@ -331,10 +329,6 @@ datum_pts_start( return 0; } - peer->precision = PTSPRECISION; - peer->stratum = 0; - memcpy((char *)&peer->refid, DATMREFID, 4); - /* ** Now add one to the number of units and return a successful code */ @@ -438,7 +432,7 @@ datum_pts_poll( ) { int i; - int index; + int unit_index; int error_code; struct datum_pts_unit *datum_pts; @@ -451,10 +445,10 @@ datum_pts_poll( ** Find the right unit and send out a time request once it is found. */ - index = -1; + unit_index = -1; for (i=0; i<nunits; i++) { if (datum_pts_unit[i]->unit == unit) { - index = i; + unit_index = i; datum_pts = datum_pts_unit[i]; error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6); if (error_code != 6) perror("TIME_REQUEST"); @@ -467,7 +461,7 @@ datum_pts_poll( ** Print out an error message if we could not find the right unit. */ - if (index == -1) { + if (unit_index == -1) { #ifdef DEBUG_DATUM_PTC if (debug) diff --git a/contrib/ntp/ntpd/refclock_dumbclock.c b/contrib/ntp/ntpd/refclock_dumbclock.c index 8138d9e..c439646 100644 --- a/contrib/ntp/ntpd/refclock_dumbclock.c +++ b/contrib/ntp/ntpd/refclock_dumbclock.c @@ -14,17 +14,15 @@ #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#include <time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports a generic dumb clock that only outputs hh:mm:ss, * in local time, no less. diff --git a/contrib/ntp/ntpd/refclock_fg.c b/contrib/ntp/ntpd/refclock_fg.c index f1320b0..655b6bc 100644 --- a/contrib/ntp/ntpd/refclock_fg.c +++ b/contrib/ntp/ntpd/refclock_fg.c @@ -8,8 +8,6 @@ #if defined(REFCLOCK) && defined(CLOCK_FG) -#include <time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" diff --git a/contrib/ntp/ntpd/refclock_gpsvme.c b/contrib/ntp/ntpd/refclock_gpsvme.c index b37466b..42eb2f9 100644 --- a/contrib/ntp/ntpd/refclock_gpsvme.c +++ b/contrib/ntp/ntpd/refclock_gpsvme.c @@ -16,19 +16,18 @@ #endif #if defined(REFCLOCK) && defined(CLOCK_GPSVME) -#include <stdio.h> -#include <syslog.h> -#include <ctype.h> -#include <string.h> -#include <strings.h> -#include <sys/time.h> -#include "gps.h" #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" + +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> + +#include "gps.h" #include "/etc/conf/h/io.h" /* GLOBAL STUFF BY RES */ diff --git a/contrib/ntp/ntpd/refclock_heath.c b/contrib/ntp/ntpd/refclock_heath.c index 9d297d1..ef4db5a 100644 --- a/contrib/ntp/ntpd/refclock_heath.c +++ b/contrib/ntp/ntpd/refclock_heath.c @@ -1,5 +1,5 @@ /* - * refclock_heath - clock driver for Heath GC-1000 Most Accurate Clock + * refclock_heath - clock driver for Heath GC-1000 and and GC-1000 II */ #ifdef HAVE_CONFIG_H #include <config.h> @@ -7,27 +7,18 @@ #if defined(REFCLOCK) && defined(CLOCK_HEATH) +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + #include <stdio.h> #include <ctype.h> -#ifdef TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# ifdef TM_IN_SYS_TIME -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif + #ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> #endif /* not HAVE_SYS_IOCTL_H */ -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" - /* * This driver supports the Heath GC-1000 Most Accurate Clock, with * RS232C Output Accessory. This is a WWV/WWVH receiver somewhat less @@ -41,15 +32,21 @@ * occasionally being rudely stepped when the offset exceeds the default * clock_max of 128 ms. * - * The internal DIPswitches should be set to operate at 1200 baud in - * MANUAL mode and the current year. The external DIPswitches should be - * set to GMT and 24-hour format, or to the host local time zone (with - * DST) and 12-hour format. It is very important that the year be - * set correctly in the DIPswitches. Otherwise, the day of year will be - * incorrect after 28 April[?] of a normal or leap year. In 12-hour mode - * with DST selected the clock will be incorrect by an hour for an - * indeterminate amount of time between 0000Z and 0200 on the day DST - * changes. + * There are two GC-1000 versions supported by this driver. The original + * GC-1000 with RS-232 output first appeared in 1983, but dissapeared + * from the market a few years later. The GC-1000 II with RS-232 output + * first appeared circa 1990, but apparently is no longer manufactured. + * The two models differ considerably, both in interface and commands. + * The GC-1000 has a pseudo-bipolar timecode output triggered by a RTS + * transition. The timecode includes both the day of year and time of + * day. The GC-1000 II has a true bipolar output and a complement of + * single character commands. The timecode includes only the time of + * day. + * + * GC-1000 + * + * The internal DIPswitches should be set to operate in MANUAL mode. The + * external DIPswitches should be set to GMT and 24-hour format. * * In MANUAL mode the clock responds to a rising edge of the request to * send (RTS) modem control line by sending the timecode. Therefore, it @@ -81,6 +78,72 @@ * established and hh:mm:ss.? once synchronization is established and * then lost again for about a day. * + * GC-1000 II + * + * Commands consist of a single letter and are case sensitive. When + * enterred in lower case, a description of the action performed is + * displayed. When enterred in upper case the action is performed. + * Following is a summary of descriptions as displayed by the clock: + * + * The clock responds with a command The 'A' command returns an ASCII + * local time string: HH:MM:SS.T xx<CR>, where + * + * HH = hours + * MM = minutes + * SS = seconds + * T = tenths-of-seconds + * xx = 'AM', 'PM', or ' ' + * <CR> = carriage return + * + * The 'D' command returns 24 pairs of bytes containing the variable + * divisor value at the end of each of the previous 24 hours. This + * allows the timebase trimming process to be observed. UTC hour 00 is + * always returned first. The first byte of each pair is the high byte + * of (variable divisor * 16); the second byte is the low byte of + * (variable divisor * 16). For example, the byte pair 3C 10 would be + * returned for a divisor of 03C1 hex (961 decimal). + * + * The 'I' command returns: | TH | TL | ER | DH | DL | U1 | I1 | I2 | , + * where + * + * TH = minutes since timebase last trimmed (high byte) + * TL = minutes since timebase last trimmed (low byte) + * ER = last accumulated error in 1.25 ms increments + * DH = high byte of (current variable divisor * 16) + * DL = low byte of (current variable divisor * 16) + * U1 = UT1 offset (/.1 s): | + | 4 | 2 | 1 | 0 | 0 | 0 | 0 | + * I1 = information byte 1: | W | C | D | I | U | T | Z | 1 | , + * where + * + * W = set by WWV(H) + * C = CAPTURE LED on + * D = TRIM DN LED on + * I = HI SPEC LED on + * U = TRIM UP LED on + * T = DST switch on + * Z = UTC switch on + * 1 = UT1 switch on + * + * I2 = information byte 2: | 8 | 8 | 4 | 2 | 1 | D | d | S | , + * where + * + * 8, 8, 4, 2, 1 = TIME ZONE switch settings + * D = DST bit (#55) in last-received frame + * d = DST bit (#2) in last-received frame + * S = clock is in simulation mode + * + * The 'P' command returns 24 bytes containing the number of frames + * received without error during UTC hours 00 through 23, providing an + * indication of hourly propagation. These bytes are updated each hour + * to reflect the previous 24 hour period. UTC hour 00 is always + * returned first. + * + * The 'T' command returns the UTC time: | HH | MM | SS | T0 | , where + * HH = tens-of-hours and hours (packed BCD) + * MM = tens-of-minutes and minutes (packed BCD) + * SS = tens-of-seconds and seconds (packed BCD) + * T = tenths-of-seconds (BCD) + * * Fudge Factors * * A fudge time1 value of .04 s appears to center the clock offset @@ -93,12 +156,12 @@ * Interface definitions */ #define DEVICE "/dev/heath%d" /* device name and unit */ -#define SPEED232 B1200 /* uart speed (1200 baud) */ #define PRECISION (-4) /* precision assumed (about 100 ms) */ #define REFID "WWV\0" /* reference ID */ #define DESCRIPTION "Heath GC-1000 Most Accurate Clock" /* WRU */ -#define LENHEATH 23 /* min timecode length */ +#define LENHEATH1 23 /* min timecode length */ +#define LENHEATH2 13 /* min timecode length */ /* * Tables to compute the ddd of year form icky dd/mm timecode. Viva la @@ -108,6 +171,12 @@ 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}; /* + * Baud rate table. The GC-1000 supports 1200, 2400 and 4800; the + * GC-1000 II supports only 9600. + */ +static int speed[] = {B1200, B2400, B4800, B9600}; + +/* * Unit control structure */ struct heathunit { @@ -136,65 +205,6 @@ struct refclock refclock_heath = { NOFLAGS /* not used */ }; -#if 0 -/* - * Gee, Unix so thoughfully omitted code to convert from a struct tm to - * a long, so I'll just have to ferret out the inverse myself, the hard way. - * (Newton's method.) - */ -#define timelocal(x) invert(x, localtime) -/* - * comparetm compares two tm structures and returns -1 if the first - * is less than the second, 0 if they are equal, and +1 if the first - * is greater than the second. Only the year, month, day, hour, minute - * and second are compared. The yearday (Julian), day of week, and isdst - * are not compared. - */ - -static int -comparetm( - struct tm *a, - struct tm *b - ) -{ - if (a->tm_year < b->tm_year ) return -1; - if (a->tm_year > b->tm_year ) return 1; - if (a->tm_mon < b->tm_mon ) return -1; - if (a->tm_mon > b->tm_mon ) return 1; - if (a->tm_mday < b->tm_mday ) return -1; - if (a->tm_mday > b->tm_mday ) return 1; - if (a->tm_hour < b->tm_hour ) return -1; - if (a->tm_hour > b->tm_hour ) return 1; - if (a->tm_min < b->tm_min ) return -1; - if (a->tm_min > b->tm_min ) return 1; - if (a->tm_sec < b->tm_sec ) return -1; - if (a->tm_sec > b->tm_sec ) return 1; - return 0; -} - -static long -invert ( - struct tm *x, - struct tm *(*func)() - ) -{ - struct tm *y; - int result; - long trial; - long lower=0L; - long upper=(long)((unsigned long)(~lower) >> 1); - - do { - trial = (upper + lower) / 2L; - y = (*func)(&trial); - result = comparetm(x, y); - if (result < 0) upper = trial; - if (result > 0) lower = trial; - } while (result != 0); - return trial; -} -#endif /* 0 */ - /* * heath_start - open the devices and initialize data for processing @@ -214,7 +224,7 @@ heath_start( * Open serial port */ (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, 0))) + if (!(fd = refclock_open(device, speed[peer->ttlmax & 0x3], 0))) return (0); /* @@ -291,7 +301,8 @@ 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); + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, + &trtmp); /* * We get a buffer and timestamp for each <cr>; however, we use @@ -314,76 +325,37 @@ heath_receive( * its contents. If the timecode has invalid length or is not in * proper format, we declare bad format and exit. */ - if (pp->lencode < LENHEATH) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } + switch (pp->lencode) { /* - * Timecode format: "hh:mm:ss.f AM mm/dd/yy" + * GC-1000 timecode format: "hh:mm:ss.f AM mm/dd/yy" + * GC-1000 II timecode format: "hh:mm:ss.f " */ - if (sscanf(pp->a_lastcode, "%2d:%2d:%2d.%c%5c%2d/%2d/%2d", - &pp->hour, &pp->minute, &pp->second, &dsec, a, &month, &day, - &pp->year) != 8) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * If AM or PM is received, assume the clock is displaying local - * time. First, convert to 24-hour format. - */ - - switch (a[1]) { - case 'P': - if (12 > pp->hour) - pp->hour += 12; - break; - - case 'A': - if (12 == pp->hour) - pp->hour -= 12; + case LENHEATH1: + if (sscanf(pp->a_lastcode, + "%2d:%2d:%2d.%c%5c%2d/%2d/%2d", &pp->hour, + &pp->minute, &pp->second, &dsec, a, &month, &day, + &pp->year) != 8) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } break; - } /* - * Now make a struct tm out of it, convert to UTC, and - * repopulate pp-> + * GC-1000 II timecode format: "hh:mm:ss.f " */ - - if (' ' != a[1]) { - struct tm t, *q; - time_t l; - - t.tm_sec = pp->second; - t.tm_min = pp->minute; - t.tm_hour = pp->hour; - t.tm_mday = day; /* not converted to yday yet */ - t.tm_mon = month-1; /* ditto */ - t.tm_year = pp->year; - if ( t.tm_year < YEAR_PIVOT ) t.tm_year += 100; /* Y2KFixes */ - - t.tm_wday = -1; /* who knows? */ - t.tm_yday = -1; /* who knows? */ - t.tm_isdst = -1; /* who knows? */ - - l = mktime(&t); - if (l == -1) { - /* HMS: do we want to do this? */ - refclock_report(peer, CEVNT_BADTIME); + case LENHEATH2: + if (sscanf(pp->a_lastcode, "%2d:%2d:%2d.%c", &pp->hour, + &pp->minute, &pp->second, &dsec) != 4) { + refclock_report(peer, CEVNT_BADREPLY); return; } - q = gmtime(&l); - - pp->year = q->tm_year; - month = q->tm_mon+1; - day = q->tm_mday; /* still not converted */ - pp->hour = q->tm_hour; - /* pp->minute = q->tm_min; GC-1000 cannot adjust timezone */ - /* pp->second = q->tm_sec; by other than hour increments */ - } + break; - + default: + refclock_report(peer, CEVNT_BADREPLY); + return; + } /* * We determine the day of the year from the DIPswitches. This @@ -396,11 +368,6 @@ heath_receive( * timecode accordingly. Icky pooh. This bit of nonsense could * be avoided if the engineers had been required to write a * device driver before finalizing the timecode format. - * - * Yes, I know this code incorrectly thinks that 2000 is a leap - * year; but, the latest year that can be set by the DIPswitches - * is 1997 anyay. Life is short. - * Hey! Year 2000 IS a leap year! Y2KFixes */ if (month < 1 || month > 12 || day < 1) { refclock_report(peer, CEVNT_BADTIME); @@ -460,17 +427,20 @@ heath_poll( pp->polls++; /* - * We toggle the RTS modem control lead to kick a timecode loose - * from the radio. This code works only for POSIX and SYSV - * interfaces. With bsd you are on your own. We take a timestamp - * between the up and down edges to lengthen the pulse, which - * should be about 50 usec on a Sun IPC. With hotshot CPUs, the - * pulse might get too short. Later. + * We toggle the RTS modem control lead (GC-1000) and sent a T + * (GC-1000 II) to kick a timecode loose from the radio. This + * code works only for POSIX and SYSV interfaces. With bsd you + * are on your own. We take a timestamp between the up and down + * edges to lengthen the pulse, which should be about 50 usec on + * a Sun IPC. With hotshot CPUs, the pulse might get too short. + * Later. */ 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); + if (write(pp->io.fd, "T", 1) != 1) + refclock_report(peer, CEVNT_FAULT); if (peer->burst > 0) return; if (pp->coderecv == pp->codeproc) { diff --git a/contrib/ntp/ntpd/refclock_hopfpci.c b/contrib/ntp/ntpd/refclock_hopfpci.c new file mode 100644 index 0000000..a9deb21 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_hopfpci.c @@ -0,0 +1,274 @@ +/* + * refclock_hopfpci.c + * + * - clock driver for hopf 6039 PCI board (GPS or DCF77) + * Bernd Altmeier altmeier@atlsoft.de + * + * latest source and further information can be found at: + * http://www.ATLSoft.de/ntp + * + * In order to run this driver you have to install and test + * the PCI-board driver for your system first. + * + * On Linux/UNIX + * + * The driver attempts to open the device /dev/hopf6039 . + * The device entry will be made by the installation process of + * the kernel module for the PCI-bus board. The driver sources + * belongs to the delivery equipment of the PCI-board. + * + * On Windows NT/2000 + * + * The driver attempts to open the device by calling the function + * "OpenHopfDevice()". This function will be installed by the + * Device Driver for the PCI-bus board. The driver belongs to the + * delivery equipment of the PCI-board. + * + * + * Start 21.03.2000 Revision: 01.20 + * changes 22.12.2000 Revision: 01.40 flag1 = 1 sync even if Quarz + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined(REFCLOCK) && defined(CLOCK_HOPF_PCI) + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#undef fileno +#include <ctype.h> +#undef fileno + +#ifndef SYS_WINNT +# include <sys/ipc.h> +# include <assert.h> +# include <unistd.h> +# include <stdio.h> +# include "hopf6039.h" +#else +# include "hopf_PCI_io.h" +#endif + +/* + * hopfpci interface definitions + */ +#define PRECISION (-10) /* precision assumed (1 ms) */ +#define REFID "hopf" /* reference ID */ +#define DESCRIPTION "hopf Elektronik PCI radio board" + +#define NSAMPLES 3 /* stages of median filter */ +#ifndef SYS_WINNT +# define DEVICE "/dev/hopf6039" /* device name inode*/ +#else +# define DEVICE "hopf6039" /* device name WinNT */ +#endif + +#define LEWAPWAR 0x20 /* leap second warning bit */ + +#define HOPF_OPMODE 0xC0 /* operation mode mask */ +#define HOPF_INVALID 0x00 /* no time code available */ +#define HOPF_INTERNAL 0x40 /* internal clock */ +#define HOPF_RADIO 0x80 /* radio clock */ +#define HOPF_RADIOHP 0xC0 /* high precision radio clock */ + + +/* + * hopfclock unit control structure. + */ +struct hopfclock_unit { + short unit; /* NTP refclock unit number */ + char leap_status; /* leap second flag */ +}; +int fd; /* file descr. */ + +/* + * Function prototypes + */ +static int hopfpci_start (int, struct peer *); +static void hopfpci_shutdown (int, struct peer *); +static void hopfpci_poll (int unit, struct peer *); + +/* + * Transfer vector + */ +struct refclock refclock_hopfpci = { + hopfpci_start, /* start up driver */ + hopfpci_shutdown, /* shut down driver */ + hopfpci_poll, /* transmit poll message */ + noentry, /* not used */ + noentry, /* initialize driver (not used) */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + +/* + * hopfpci_start - attach to hopf PCI board 6039 + */ +static int +hopfpci_start( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + struct hopfclock_unit *up; + + /* + * Allocate and initialize unit structure + */ + up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit)); + + if (!(up)) { + msyslog(LOG_ERR, "hopfPCIClock(%d) emalloc: %m",unit); +#ifdef DEBUG + printf("hopfPCIClock(%d) emalloc\n",unit); +#endif + return (0); + } + memset((char *)up, 0, sizeof(struct hopfclock_unit)); + +#ifndef SYS_WINNT + + fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */ + +#else + if (!OpenHopfDevice()){ + msyslog(LOG_ERR,"Start: %s unit: %d failed!",DEVICE,unit); + return (0); + } +#endif + + pp = peer->procptr; + pp->io.clock_recv = noentry; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = -1; + pp->unitptr = (caddr_t)up; + + get_systime(&pp->lastrec); + + /* + * Initialize miscellaneous peer variables + */ + if (pp->unitptr!=0) { + memcpy((char *)&pp->refid, REFID, 4); + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + up->leap_status = 0; + up->unit = (short) unit; + return (1); + } + else { + return 0; + } +} + + +/* + * hopfpci_shutdown - shut down the clock + */ +static void +hopfpci_shutdown( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + register struct hopfpciTime *up; + + pp = peer->procptr; + up = (struct hopfpciTime *)pp->unitptr; + +#ifndef SYS_WINNT + close(fd); +#else + CloseHopfDevice(); +// UnmapViewOfFile (up); +#endif +} + + +/* + * hopfpci_poll - called by the transmit procedure + */ +static void +hopfpci_poll( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + register struct hopfpciTime *up; + HOPFTIME m_time; + + pp = peer->procptr; + up = (struct hopfpciTime *)pp->unitptr; + +#ifndef SYS_WINNT + ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time); +#else + GetHopfSystemTime(&m_time); +#endif + pp->polls++; + + pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay); + pp->hour = m_time.wHour; + pp->minute = m_time.wMinute; + pp->second = m_time.wSecond; + pp->msec=m_time.wMilliseconds; + pp->usec=0; + 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); + + get_systime(&pp->lastrec); + + /* + * If clock has no valid status then report error and exit + */ + if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */ + refclock_report(peer, CEVNT_BADTIME); + pp->leap = LEAP_NOTINSYNC; + return; + } + + /* + * Test if time is running on internal quarz + * if CLK_FLAG1 is set, sychronize even if no radio operation + */ + + if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){ + if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { + refclock_report(peer, CEVNT_BADTIME); + pp->leap = LEAP_NOTINSYNC; + return; + } + } + + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); + + record_clock_stats(&peer->srcadr, pp->a_lastcode); + + return; +} + +#else +int refclock_hopfpci_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_hopfser.c b/contrib/ntp/ntpd/refclock_hopfser.c new file mode 100644 index 0000000..a9d74dd --- /dev/null +++ b/contrib/ntp/ntpd/refclock_hopfser.c @@ -0,0 +1,372 @@ +/* + * + * refclock_hopfser.c + * - clock driver for hopf serial boards (GPS or DCF77) + * + * Date: 30.03.2000 Revision: 01.10 + * + * latest source and further information can be found at: + * http://www.ATLSoft.de/ntp + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL)) + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_control.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#if defined HAVE_SYS_MODEM_H +# include <sys/modem.h> +# define TIOCMSET MCSETA +# define TIOCMGET MCGETA +# define TIOCM_RTS MRTS +#endif + +#ifdef HAVE_TERMIOS_H +# ifdef TERMIOS_NEEDS__SVID3 +# define _SVID3 +# endif +# include <termios.h> +# ifdef TERMIOS_NEEDS__SVID3 +# undef _SVID3 +# endif +#endif + +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + +/* + * clock definitions + */ +#define DESCRIPTION "hopf Elektronik serial clock" /* Long name */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#define REFID "hopf\0" /* reference ID */ +/* + * I/O definitions + */ +#define DEVICE "/dev/hopfclock%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ + + +#define STX 0x02 +#define ETX 0x03 +#define CR 0x0c +#define LF 0x0a + +/* parse states */ +#define REC_QUEUE_EMPTY 0 +#define REC_QUEUE_FULL 1 + +#define HOPF_OPMODE 0x0C /* operation mode mask */ +#define HOPF_INVALID 0x00 /* no time code available */ +#define HOPF_INTERNAL 0x04 /* internal clock */ +#define HOPF_RADIO 0x08 /* radio clock */ +#define HOPF_RADIOHP 0x0C /* high precision radio clock */ + +/* + * hopfclock unit control structure. + */ +struct hopfclock_unit { + l_fp laststamp; /* last receive timestamp */ + short unit; /* NTP refclock unit number */ + u_long polled; /* flag to detect noreplies */ + char leap_status; /* leap second flag */ + int rpt_next; +}; + +/* + * Function prototypes + */ + +static int hopfserial_start P((int, struct peer *)); +static void hopfserial_shutdown P((int, struct peer *)); +static void hopfserial_receive P((struct recvbuf *)); +static void hopfserial_poll P((int, struct peer *)); +/* static void hopfserial_io P((struct recvbuf *)); */ +/* + * Transfer vector + */ +struct refclock refclock_hopfser = { + hopfserial_start, /* start up driver */ + hopfserial_shutdown, /* shut down driver */ + hopfserial_poll, /* transmit poll message */ + noentry, /* not used */ + noentry, /* initialize driver (not used) */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + +/* + * hopfserial_start - open the devices and initialize data for processing + */ +static int +hopfserial_start ( + int unit, + struct peer *peer + ) +{ + register struct hopfclock_unit *up; + struct refclockproc *pp; + int fd; + char gpsdev[20]; + +#ifdef SYS_WINNT + (void) sprintf(gpsdev, "COM%d:", unit); +#else + (void) sprintf(gpsdev, DEVICE, unit); +#endif + /* LDISC_STD, LDISC_RAW + * Open serial port. Use CLK line discipline, if available. + */ + fd = refclock_open(gpsdev, SPEED232, LDISC_CLK); + if (fd <= 0) { +#ifdef DEBUG + printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev); +#endif + return 0; + } + + msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd, + gpsdev); + + /* + * Allocate and initialize unit structure + */ + up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit)); + + if (!(up)) { + msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit); +#ifdef DEBUG + printf("hopfSerialClock(%d) emalloc\n",unit); +#endif + (void) close(fd); + return (0); + } + + memset((char *)up, 0, sizeof(struct hopfclock_unit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = hopfserial_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { +#ifdef DEBUG + printf("hopfSerialClock(%d) io_addclock\n",unit); +#endif + (void) close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + pp->clockdesc = DESCRIPTION; + peer->precision = PRECISION; + peer->burst = NSTAGE; + memcpy((char *)&pp->refid, REFID, 4); + + up->leap_status = 0; + up->unit = (short) unit; + + return (1); +} + + +/* + * hopfserial_shutdown - shut down the clock + */ +static void +hopfserial_shutdown ( + int unit, + struct peer *peer + ) +{ + register struct hopfclock_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct hopfclock_unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + + +/* + * hopfserial_receive - receive data from the serial interface + */ + +static void +hopfserial_receive ( + struct recvbuf *rbufp + ) +{ + struct hopfclock_unit *up; + struct refclockproc *pp; + struct peer *peer; + + int sync; /* synchronization indicator */ + int DoW; /* Dow */ + + int day, month; /* ddd conversion */ + + /* + * Initialize pointers and read the timecode and timestamp. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct hopfclock_unit *)pp->unitptr; + + if (up->rpt_next == 0 ) + return; + + + up->rpt_next = 0; /* wait until next poll interval occur */ + + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); + + if (pp->lencode == 0) + return; + + sscanf(pp->a_lastcode, +#if 1 + "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */ +#else + "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ +#endif + &sync, + &DoW, + &pp->hour, + &pp->minute, + &pp->second, + &day, + &month, + &pp->year); + + + /* + Validate received values at least enough to prevent internal + array-bounds problems, etc. + */ + if((pp->hour < 0) || (pp->hour > 23) || + (pp->minute < 0) || (pp->minute > 59) || + (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || + (day < 1) || (day > 31) || + (month < 1) || (month > 12) || + (pp->year < 0) || (pp->year > 99)) { + /* Data out of range. */ + refclock_report(peer, CEVNT_BADREPLY); + return; + } + /* + some preparations + */ + pp->day = ymd2yd(pp->year,month,day); + pp->leap=0; + + /* Year-2000 check! */ + /* wrap 2-digit date into 4-digit */ + + if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */ + pp->year += 1900; + + /* preparation for timecode ntpq rl command ! */ + +#if 0 + wsprintf(pp->a_lastcode, + "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", + sync, + DoW, + day, + month, + pp->year, + pp->hour, + pp->minute, + pp->second); + + pp->lencode = strlen(pp->a_lastcode); + if ((sync && 0xc) == 0 ){ /* time ok? */ + refclock_report(peer, CEVNT_BADTIME); + pp->leap = LEAP_NOTINSYNC; + return; + } +#endif + /* + * If clock has no valid status then report error and exit + */ + if ((sync & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ + refclock_report(peer, CEVNT_BADTIME); + pp->leap = LEAP_NOTINSYNC; + return; + } + + /* + * Test if time is running on internal quarz + * if CLK_FLAG1 is set, sychronize even if no radio operation + */ + + if ((sync & HOPF_OPMODE) == HOPF_INTERNAL){ + if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { + refclock_report(peer, CEVNT_BADTIME); + pp->leap = LEAP_NOTINSYNC; + return; + } + } + + + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); + +#if 0 + msyslog(LOG_ERR, " D:%x D:%d D:%d",sync,pp->minute,pp->second); +#endif + + record_clock_stats(&peer->srcadr, pp->a_lastcode); + + return; +} + + +/* + * hopfserial_poll - called by the transmit procedure + * + */ +static void +hopfserial_poll ( + int unit, + struct peer *peer + ) +{ + register struct hopfclock_unit *up; + struct refclockproc *pp; + pp = peer->procptr; + + up = (struct hopfclock_unit *)pp->unitptr; + + pp->polls++; + up->rpt_next = 1; + +#if 0 + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#endif + + return; +} + +#else +int refclock_hopfser_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_hpgps.c b/contrib/ntp/ntpd/refclock_hpgps.c index 30aa494..7a506cf 100644 --- a/contrib/ntp/ntpd/refclock_hpgps.c +++ b/contrib/ntp/ntpd/refclock_hpgps.c @@ -1,21 +1,21 @@ /* * refclock_hpgps - clock driver for HP 58503A GPS receiver */ + #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #if defined(REFCLOCK) && defined(CLOCK_HPGPS) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* Version 0.1 April 1, 1995 * 0.2 April 25, 1995 * tolerant of missing timecode response prompt and sends diff --git a/contrib/ntp/ntpd/refclock_irig.c b/contrib/ntp/ntpd/refclock_irig.c index ab4b525..7efd57e 100644 --- a/contrib/ntp/ntpd/refclock_irig.c +++ b/contrib/ntp/ntpd/refclock_irig.c @@ -7,19 +7,19 @@ #if defined(REFCLOCK) && defined(CLOCK_IRIG) +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + #include <stdio.h> #include <ctype.h> -#include <sys/time.h> #include <math.h> #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #endif /* HAVE_SYS_IOCTL_H */ -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_calendar.h" -#include "ntp_stdlib.h" #include "audio.h" /* @@ -140,6 +140,7 @@ /* * Interface definitions */ +#define DEVICE_AUDIO "/dev/audio" /* audio device name */ #define PRECISION (-17) /* precision assumed (about 10 us) */ #define REFID "IRIG" /* reference ID */ #define DESCRIPTION "Generic IRIG Audio Driver" /* WRU */ @@ -310,7 +311,7 @@ irig_start( /* * Open audio device */ - fd = audio_init(); + fd = audio_init(DEVICE_AUDIO); if (fd < 0) return (0); #ifdef DEBUG diff --git a/contrib/ntp/ntpd/refclock_jupiter.c b/contrib/ntp/ntpd/refclock_jupiter.c index b337e0c..4d1d4c2 100644 --- a/contrib/ntp/ntpd/refclock_jupiter.c +++ b/contrib/ntp/ntpd/refclock_jupiter.c @@ -37,10 +37,6 @@ #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(PPS) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" @@ -48,6 +44,9 @@ #include "ntp_stdlib.h" #include "ntp_calendar.h" +#include <stdio.h> +#include <ctype.h> + #include "jupiter.h" #include <sys/ppsclock.h> @@ -681,7 +680,7 @@ jupiter_process(register struct peer *peer) */ for (i = 0; i < NSAMPLES; i++) off[i] = up->filter[i]; - qsort((char *)off, NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp); + qsort((char *)off, (size_t)NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp); /* * Reject the furthest from the median of NSAMPLES samples until diff --git a/contrib/ntp/ntpd/refclock_leitch.c b/contrib/ntp/ntpd/refclock_leitch.c index edee3f8..42b02fc 100644 --- a/contrib/ntp/ntpd/refclock_leitch.c +++ b/contrib/ntp/ntpd/refclock_leitch.c @@ -1,21 +1,21 @@ /* * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock */ + #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #if defined(REFCLOCK) && defined(CLOCK_LEITCH) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" +#include <stdio.h> +#include <ctype.h> + #ifdef STREAM #include <stropts.h> #if defined(LEITCHCLK) diff --git a/contrib/ntp/ntpd/refclock_local.c b/contrib/ntp/ntpd/refclock_local.c index 12184db..a3e5773 100644 --- a/contrib/ntp/ntpd/refclock_local.c +++ b/contrib/ntp/ntpd/refclock_local.c @@ -8,14 +8,14 @@ #endif #ifdef REFCLOCK -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> #include "ntpd.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + #ifdef KERNEL_PLL #include "ntp_syscall.h" #endif @@ -34,7 +34,7 @@ * particular server's clock as the clock of last resort when all other * normal synchronization sources have gone away. This is especially * useful if that server has an ovenized oscillator. For this you would - * configure this driver at a higher stratum (say 3 or 4) to prevent the + * configure this driver at a higher stratum (say 5) to prevent the * server's stratum from falling below that. * * A third application for this driver is when an external discipline @@ -69,7 +69,7 @@ * * Fudge Factors * - * The stratum for this driver set at 3 by default, but it can be changed + * 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 @@ -96,7 +96,7 @@ #define REFID "LCL\0" /* reference ID */ #define DESCRIPTION "Undisciplined local clock" /* WRU */ -#define STRATUM 3 /* default stratum */ +#define STRATUM 5 /* default stratum */ #define DISPERSION .01 /* default dispersion (10 ms) */ /* @@ -213,7 +213,7 @@ local_poll( refclock_process_offset(pp, pp->lastrec, pp->lastrec, pp->fudgetime1); pp->leap = LEAP_NOWARNING; pp->disp = DISPERSION; - pp->variance = 0; + pp->jitter = 0; #if defined(KERNEL_PLL) && defined(STA_CLK) /* @@ -246,7 +246,7 @@ local_poll( pp->leap = LEAP_NOTINSYNC; } pp->disp = ntv.maxerror / 1e6; - pp->variance = SQUARE(ntv.esterror / 1e6); + pp->jitter = SQUARE(ntv.esterror / 1e6); } } else { ext_enable = 0; diff --git a/contrib/ntp/ntpd/refclock_msfees.c b/contrib/ntp/ntpd/refclock_msfees.c index db6c6b1..b1aaa56 100644 --- a/contrib/ntp/ntpd/refclock_msfees.c +++ b/contrib/ntp/ntpd/refclock_msfees.c @@ -11,16 +11,13 @@ * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk */ -#include <ctype.h> -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_calendar.h" + +#include <ctype.h> #if defined(HAVE_BSD_TTYS) #include <sgtty.h> #endif /* HAVE_BSD_TTYS */ @@ -1287,7 +1284,7 @@ ees_process( if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:"); /* Sort the offsets, trim off the extremes, then choose one. */ - qsort((char *) coffs, (u_int)samples, sizeof(l_fp), offcompare); + qsort((char *) coffs, (size_t)samples, sizeof(l_fp), offcompare); noff = samples; i = 0; diff --git a/contrib/ntp/ntpd/refclock_mx4200.c b/contrib/ntp/ntpd/refclock_mx4200.c index f08bb23..3c520b0 100644 --- a/contrib/ntp/ntpd/refclock_mx4200.c +++ b/contrib/ntp/ntpd/refclock_mx4200.c @@ -47,11 +47,7 @@ # include <config.h> #endif -#if defined(REFCLOCK) && defined(CLOCK_MX4200) && defined(PPS) - -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> +#if defined(REFCLOCK) && defined(CLOCK_MX4200) && defined(HAVE_PPSAPI) #include "ntpd.h" #include "ntp_io.h" @@ -59,11 +55,11 @@ #include "ntp_unixtime.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + #include "mx4200.h" -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif #ifdef HAVE_SYS_TERMIOS_H # include <sys/termios.h> #endif @@ -73,7 +69,7 @@ #ifndef HAVE_STRUCT_PPSCLOCKEV struct ppsclockev { -# ifdef HAVE_TIMESPEC +# ifdef HAVE_STRUCT_TIMESPEC struct timespec tv; # else struct timeval tv; @@ -82,6 +78,14 @@ struct ppsclockev { }; #endif /* ! HAVE_STRUCT_PPSCLOCKEV */ +#ifdef HAVE_TIMEPPS_H +# include <timepps.h> +#else +# ifdef HAVE_SYS_TIMEPPS_H +# include <sys/timepps.h> +# endif +#endif + /* * This driver supports the Magnavox Model MX 4200 GPS Receiver * adapted to precision timing applications. It requires the @@ -97,7 +101,7 @@ struct ppsclockev { /* * Check this every time you edit the code! */ -#define YEAR_RIGHT_NOW 1998 +#define YEAR_LAST_MODIFIED 2000 /* * GPS Definitions @@ -117,13 +121,6 @@ struct ppsclockev { /* * Position Averaging. - * Reference: Dr. Thomas A. Clark's Totally Accurate Clock (TAC) files at - * ftp://aleph.gsfc.nasa.gov/GPS/totally.accurate.clock/ - * For a 6-channel Motorola Oncore, he indicates that good nominal - * HDOP and VDOP are 1.50 and 2.00 respectively. Given the relationship - * HDOP^2 = NDOP^2 + EDOP^2 and assuming EDOP and NDOP are equal, we - * have a nominal NDOP = EDOP = sqrt((HDOP*HDOP)/2). An 8-channel - * Oncore does well with HDOP=1.20 and VDOP=1.70. */ #define INTERVAL 1 /* Interval between position measurements (s) */ #define AVGING_TIME 24 /* Number of hours to average */ @@ -141,18 +138,16 @@ struct mx4200unit { double avg_lon; /* average longitude */ double avg_alt; /* average height */ double central_meridian; /* central meridian */ - double filt_lat; /* latitude filter length */ - double filt_lon; /* longitude filter length */ - double filt_alt; /* height filter length */ - double edop; /* EDOP (east DOP) */ - double ndop; /* NDOP (north DOP) */ - double vdop; /* VDOP (vertical DOP) */ + double N_fixes; /* Number of position measurements */ int last_leap; /* leap second warning */ u_int moving; /* mobile platform? */ u_long sloppyclockflag; /* fudge flags */ u_int known; /* position known yet? */ u_long clamp_time; /* when to stop postion averaging */ u_long log_time; /* when to print receiver status */ + pps_handle_t pps_h; + pps_params_t pps_p; + pps_info_t pps_i; }; static char pmvxg[] = "PMVXG"; @@ -181,14 +176,13 @@ static void mx4200_poll P((int, struct peer *)); static char * mx4200_parse_t P((struct peer *)); static char * mx4200_parse_p P((struct peer *)); -static char * mx4200_parse_d P((struct peer *)); static char * mx4200_parse_s P((struct peer *)); #ifdef QSORT_USES_VOID_P int mx4200_cmpl_fp P((const void *, const void *)); #else int mx4200_cmpl_fp P((const l_fp *, const l_fp *)); #endif /* not QSORT_USES_VOID_P */ -static void mx4200_config P((struct peer *)); +static int mx4200_config P((struct peer *)); static void mx4200_ref P((struct peer *)); static void mx4200_send P((struct peer *, char *, ...)) __attribute__ ((format (printf, 2, 3))); @@ -239,6 +233,7 @@ mx4200_start( * Allocate unit structure */ if (!(up = (struct mx4200unit *) emalloc(sizeof(struct mx4200unit)))) { + perror("emalloc"); (void) close(fd); return (0); } @@ -263,8 +258,7 @@ mx4200_start( memcpy((char *)&pp->refid, REFID, 4); /* Ensure the receiver is properly configured */ - mx4200_config(peer); - return (1); + return mx4200_config(peer); } @@ -290,7 +284,7 @@ mx4200_shutdown( /* * mx4200_config - Configure the receiver */ -static void +static int mx4200_config( struct peer *peer ) @@ -299,6 +293,7 @@ mx4200_config( int add_mode; register struct mx4200unit *up; struct refclockproc *pp; + int mode; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; @@ -324,16 +319,52 @@ mx4200_config( up->avg_lon = 0.0; up->avg_alt = 0.0; up->central_meridian = NOT_INITIALIZED; - up->filt_lat = 0.0; - up->filt_lon = 0.0; - up->filt_alt = 0.0; - up->edop = 1; - up->ndop = 1; - up->vdop = 1; + up->N_fixes = 0.0; up->last_leap = 0; /* LEAP_NOWARNING */ up->clamp_time = current_time + (AVGING_TIME * 60 * 60); up->log_time = current_time + SLEEPTIME; + if (time_pps_create(pp->io.fd, &up->pps_h) < 0) { + perror("time_pps_create"); + msyslog(LOG_ERR, + "mx4200_config: time_pps_create failed: %m"); + return (0); + } + if (time_pps_getcap(up->pps_h, &mode) < 0) { + msyslog(LOG_ERR, + "mx4200_config: time_pps_getcap failed: %m"); + return (0); + } + + if (time_pps_getparams(up->pps_h, &up->pps_p) < 0) { + msyslog(LOG_ERR, + "mx4200_config: time_pps_getparams failed: %m"); + return (0); + } + + /* nb. only turn things on, if someone else has turned something + * on before we get here, leave it alone! + */ + + up->pps_p.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC; + up->pps_p.mode &= mode; /* only set what is legal */ + + if (time_pps_setparams(up->pps_h, &up->pps_p) < 0) { + perror("time_pps_setparams"); + msyslog(LOG_ERR, + "mx4200_config: time_pps_setparams failed: %m"); + exit(1); + } + + if (time_pps_kcbind(up->pps_h, PPS_KC_HARDPPS, PPS_CAPTUREASSERT, + PPS_TSFMT_TSPEC) < 0) { + perror("time_pps_kcbind"); + msyslog(LOG_ERR, + "mx4200_config: time_pps_kcbind failed: %m"); + exit(1); + } + + /* * "007" Control Port Configuration * Zero the output list (do it twice to flush possible junk) @@ -419,7 +450,7 @@ mx4200_config( 500, /* max time error in ns */ 0, /* user bias in ns */ 1); /* output "830" sentences to control port */ - /* Multi-satellite mode */ + /* Multi-satellite mode */ /* * Output position information (to calculate fixed installation @@ -431,21 +462,6 @@ mx4200_config( add_mode = 1; /* add to list */ } - /* - * "007" Control Port Configuration - * Output "022" DOPs - */ - mx4200_send(peer, "%s,%03d,%03d,%d,%d,,%d,,,", pmvxg, - PMVXG_S_PORTCONF, - PMVXG_D_DOPS, /* control port output block Label */ - 0, /* clear current output control list (0=no) */ - add_mode, /* add/delete sentences from list (1=add, 2=del) */ - /* must be null */ - INTERVAL); /* sentence output rate (sec) */ - /* precision for position output */ - /* nmea version for cga & gll output */ - /* pass-through control */ - /* * "007" Control Port Configuration @@ -456,11 +472,13 @@ mx4200_config( PMVXG_D_PHV, /* control port output block Label */ 0, /* clear current output control list (0=no) */ add_mode, /* add/delete sentences from list (1=add, 2=del) */ - /* must be null */ + /* must be null */ INTERVAL); /* sentence output rate (sec) */ - /* precision for position output */ - /* nmea version for cga & gll output */ - /* pass-through control */ + /* precision for position output */ + /* nmea version for cga & gll output */ + /* pass-through control */ + + return (1); } /* @@ -490,21 +508,6 @@ mx4200_ref( /* * "007" Control Port Configuration - * Stop outputting "022" DOPs - */ - mx4200_send(peer, "%s,%03d,%03d,%d,%d,,,,,", pmvxg, - PMVXG_S_PORTCONF, - PMVXG_D_DOPS, /* control port output block Label */ - 0, /* clear current output control list (0=no) */ - 2); /* add/delete sentences from list (2=delete) */ - /* must be null */ - /* sentence output rate (sec) */ - /* precision for position output */ - /* nmea version for cga & gll output */ - /* pass-through control */ - - /* - * "007" Control Port Configuration * Stop outputting "021" position, height, velocity reports */ mx4200_send(peer, "%s,%03d,%03d,%d,%d,,,,,", pmvxg, @@ -590,7 +593,7 @@ mx4200_ref( lons, /* longitude DDDMM.MMMM */ ewc, /* east/west */ alt, /* Altitude */ - 1); /* Altitude Reference (0=WGS84 ellipsoid, 1=MSL geoid) */ + 1); /* Altitude Reference (0=WGS84 ellipsoid, 1=MSL geoid)*/ msyslog(LOG_DEBUG, "mx4200: reconfig to fixed location: %s %c, %s %c, %.2f m", @@ -766,10 +769,14 @@ mx4200_receive( sentence_type = strtol(cp, &cp, 10); /* - * "000" Status message + * Process the sentence according to its type. */ + switch (sentence_type) { - if (sentence_type == PMVXG_D_STATUS) { + /* + * "000" Status message + */ + case PMVXG_D_STATUS: /* * XXX * Since we configure the receiver to not give us status @@ -785,52 +792,35 @@ mx4200_receive( } mx4200_debug(peer, "mx4200_receive: reset receiver\n"); mx4200_config(peer); - return; - } + break; /* * "021" Position, Height, Velocity message, * if we are still averaging our position */ - if (sentence_type == PMVXG_D_PHV && !up->known) { - /* - * Parse the message, calculating our averaged position. - */ - if ((cp = mx4200_parse_p(peer)) != NULL) { - mx4200_debug(peer, "mx4200_receive: pos: %s\n", cp); - return; - } - mx4200_debug(peer, - "mx4200_receive: position avg %.9f %.9f %.4f\n", - up->avg_lat, up->avg_lon, up->avg_alt); - mx4200_debug(peer, - "mx4200_receive: position len %.4f %.4f %.4f\n", - up->filt_lat, up->filt_lon, up->filt_alt); - mx4200_debug(peer, - "mx4200_receive: position dop %.1f %.1f %.1f\n", - up->ndop, up->edop, up->vdop); - /* - * Reinitialize as a reference station - * if position is well known. - */ - if (current_time > up->clamp_time) { - up->known++; - mx4200_debug(peer, "mx4200_receive: reconfiguring!\n"); - mx4200_ref(peer); - } - return; - } - - /* - * "022" DOPs, if we are still averaging our position - */ - if (sentence_type == PMVXG_D_DOPS && !up->known) { - if ((cp = mx4200_parse_d(peer)) != NULL) { - mx4200_debug(peer, "mx4200_receive: dop: %s\n", cp); - return; + case PMVXG_D_PHV: + if (!up->known) { + /* + * Parse the message, calculating our averaged position. + */ + if ((cp = mx4200_parse_p(peer)) != NULL) { + mx4200_debug(peer, "mx4200_receive: pos: %s\n", cp); + return; + } + mx4200_debug(peer, + "mx4200_receive: position avg %f %.9f %.9f %.4f\n", + up->N_fixes, up->avg_lat, up->avg_lon, up->avg_alt); + /* + * Reinitialize as a reference station + * if position is well known. + */ + if (current_time > up->clamp_time) { + up->known++; + mx4200_debug(peer, "mx4200_receive: reconfiguring!\n"); + mx4200_ref(peer); + } } - return; - } + break; /* * Print to the syslog: @@ -838,21 +828,20 @@ mx4200_receive( * "030" Software Configuration * "523" Time Recovery Parameters Currently in Use */ - if (sentence_type == PMVXG_D_MODEDATA || - sentence_type == PMVXG_D_SOFTCONF || - sentence_type == PMVXG_D_TRECOVUSEAGE ) { + case PMVXG_D_MODEDATA: + case PMVXG_D_SOFTCONF: + case PMVXG_D_TRECOVUSEAGE: + if ((cp = mx4200_parse_s(peer)) != NULL) { mx4200_debug(peer, "mx4200_receive: multi-record: %s\n", cp); - return; } - return; - } + break; /* * "830" Time Recovery Results message */ - if (sentence_type == PMVXG_D_TRECOVOUT) { + case PMVXG_D_TRECOVOUT: /* * Capture the last PPS signal. @@ -911,12 +900,16 @@ mx4200_receive( * Turn off the flag and return */ up->polled = 0; - return; - } + break; /* * Ignore all other sentence types */ + default: + break; + + } /* switch (sentence_type) */ + return; } @@ -969,17 +962,19 @@ mx4200_parse_t( struct mx4200unit *up; char time_mark_valid, time_sync, op_mode; int sentence_type, valid; - int year, day_of_year, month, day_of_month, hour, minute, second, leapsec; + int year, day_of_year, month, day_of_month; + int hour, minute, second, leapsec; int oscillator_offset, time_mark_error, time_bias; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; leapsec = 0; /* Not all receivers output leap second warnings (!) */ - sscanf(pp->a_lastcode, "$PMVXG,%d,%c,%d,%d,%d,%d:%d:%d,%c,%c,%d,%d,%d,%d", + sscanf(pp->a_lastcode, + "$PMVXG,%d,%c,%d,%d,%d,%d:%d:%d,%c,%c,%d,%d,%d,%d", &sentence_type, &time_mark_valid, &year, &month, &day_of_month, - &hour, &minute, &second, &time_sync, &op_mode, &oscillator_offset, - &time_mark_error, &time_bias, &leapsec); + &hour, &minute, &second, &time_sync, &op_mode, + &oscillator_offset, &time_mark_error, &time_bias, &leapsec); if (sentence_type != PMVXG_D_TRECOVOUT) return ("wrong rec-type"); @@ -1029,7 +1024,7 @@ mx4200_parse_t( * (Certainly can't be any year before this code was last altered!) */ if (day_of_month > 31 || month > 12 || - day_of_month < 1 || month < 1 || year < YEAR_RIGHT_NOW) { + day_of_month < 1 || month < 1 || year < YEAR_LAST_MODIFIED) { mx4200_debug(peer, "mx4200_parse_t: bad date (%4d-%02d-%02d)\n", year, month, day_of_month); @@ -1250,7 +1245,7 @@ mx4200_parse_p( struct refclockproc *pp; struct mx4200unit *up; int sentence_type, mode; - double mtime, lat, lon, alt, geoid, vele, veln, weight; + double mtime, lat, lon, alt, geoid, vele, veln; char north_south, east_west; pp = peer->procptr; @@ -1259,9 +1254,10 @@ mx4200_parse_p( /* Should never happen! */ if (up->moving) return ("mobile platform - no pos!"); - sscanf ( pp->a_lastcode, "$PMVXG,%d,%lf,%lf,%c,%lf,%c,%lf,%lf,%lf,%lf,%d", - &sentence_type, &mtime, &lat, &north_south, &lon, &east_west, &alt, - &geoid, &vele, &veln, &mode); + sscanf ( pp->a_lastcode, + "$PMVXG,%d,%lf,%lf,%c,%lf,%c,%lf,%lf,%lf,%lf,%d", + &sentence_type, &mtime, &lat, &north_south, &lon, &east_west, + &alt, &geoid, &vele, &veln, &mode); /* Sentence type */ if (sentence_type != PMVXG_D_PHV) @@ -1324,92 +1320,22 @@ mx4200_parse_p( if (lon > 180.0) lon -= 360.0; /* - * Calculate running weighted averages + * Calculate running averages */ - weight = 1. / up->edop; - weight *= weight; - up->avg_lon = (up->filt_lon * up->avg_lon) + (weight * lon); - up->filt_lon += weight; - up->avg_lon = up->avg_lon / up->filt_lon; - - weight = 1. / up->ndop; - weight *= weight; - up->avg_lat = (up->filt_lat * up->avg_lat) + (weight * lat); - up->filt_lat += weight; - up->avg_lat = up->avg_lat / up->filt_lat; - - weight = 1. / up->vdop; - weight *= weight; - up->avg_alt = (up->filt_alt * up->avg_alt) + (weight * alt); - up->filt_alt += weight; - up->avg_alt = up->avg_alt / up->filt_alt; - mx4200_debug(peer, - "mx4200_receive: position rdg %.9f %.9f %.4f (CM=%.9f)\n", - lat, lon, alt, up->central_meridian); + up->avg_lon = (up->N_fixes * up->avg_lon) + lon; + up->avg_lat = (up->N_fixes * up->avg_lat) + lat; + up->avg_alt = (up->N_fixes * up->avg_alt) + alt; - return (NULL); -} + up->N_fixes += 1.0; -/* - * Parse a mx4200 DOP sentence. - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,022,SSSSSS.SSEE.E,NN.N,VV.V,XX,XX,XX,XX,XX,XX - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 022=DOPs. The DOP values in this sentence - * correspond to the satellites listed. The PRNs in - * the message are listed in receiver channel number order - * 1 UTC measurement time (seconds into week) - * 2 EDOP (east DOP) - * 3 NDOP (north DOP) - * 4 VDOP (vertical DOP) - * 5 PRN on channel 1 - * 6 PRN on channel 2 - * 7 PRN on channel 3 - * 8 PRN on channel 4 - * 9 PRN on channel 5 - * 10 PRN on channel 6 - * 11 PRN on channel 7 (12-channel receivers only) - * 12 PRN on channel 8 (12-channel receivers only) - * 13 PRN on channel 9 (12-channel receivers only) - * 14 PRN on channel 10 (12-channel receivers only) - * 15 PRN on channel 11 (12-channel receivers only) - * 16 PRN on channel 12 (12-channel receivers only) - */ -static char * -mx4200_parse_d( - struct peer *peer - ) -{ - struct refclockproc *pp; - struct mx4200unit *up; - int sentence_type; - double mtime, edop, ndop, vdop; + up->avg_lon /= up->N_fixes; + up->avg_lat /= up->N_fixes; + up->avg_alt /= up->N_fixes; - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* Should never happen! */ - if (up->moving) return ("mobile platform - no dop!"); - - sscanf ( pp->a_lastcode, "$PMVXG,%d,%lf,%lf,%lf,%lf", - &sentence_type, &mtime, &edop, &ndop, &vdop); - - /* Sentence type */ - if (sentence_type != PMVXG_D_DOPS) - return ("wrong rec-type"); - - /* Update values */ - if (edop <= 0.0 || ndop <= 0.0 || vdop <= 0.0) - return ("nonpositive dop"); - up->edop = edop; - up->ndop = ndop; - up->vdop = vdop; + mx4200_debug(peer, + "mx4200_receive: position rdg %.0f: %.9f %.9f %.4f (CM=%.9f)\n", + up->N_fixes, lat, lon, alt, up->central_meridian); return (NULL); } @@ -1551,19 +1477,19 @@ mx4200_parse_s( case PMVXG_D_STATUS: msyslog(LOG_DEBUG, - "mx4200: status: %s", pp->a_lastcode); + "mx4200: status: %s", pp->a_lastcode); break; case PMVXG_D_MODEDATA: msyslog(LOG_DEBUG, - "mx4200: mode data: %s", pp->a_lastcode); + "mx4200: mode data: %s", pp->a_lastcode); break; case PMVXG_D_SOFTCONF: msyslog(LOG_DEBUG, - "mx4200: firmware configuration: %s", pp->a_lastcode); + "mx4200: firmware configuration: %s", pp->a_lastcode); break; case PMVXG_D_TRECOVUSEAGE: msyslog(LOG_DEBUG, - "mx4200: time recovery parms: %s", pp->a_lastcode); + "mx4200: time recovery parms: %s", pp->a_lastcode); break; default: return ("wrong rec-type"); @@ -1573,7 +1499,7 @@ mx4200_parse_s( } /* - * Process a PPS signal, returning a timestamp. + * Process a PPS signal, placing a timestamp in pp->lastrec. */ static int mx4200_pps( @@ -1584,13 +1510,7 @@ mx4200_pps( struct refclockproc *pp; struct mx4200unit *up; - int request; -#ifdef HAVE_CIOGETEV - request = CIOGETEV; -#endif -#ifdef HAVE_TIOCGPPSEV - request = TIOCGPPSEV; -#endif + struct timespec timeout; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; @@ -1598,41 +1518,47 @@ mx4200_pps( /* * Grab the timestamp of the PPS signal. */ - temp_serial = up->ppsev.serial; - if (ioctl(fdpps, request, (caddr_t)&up->ppsev) < 0) { - /* XXX Actually, if this fails, we're pretty much screwed */ + temp_serial = up->pps_i.assert_sequence; + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + if (time_pps_fetch(up->pps_h, PPS_TSFMT_TSPEC, &(up->pps_i), + &timeout) < 0) { mx4200_debug(peer, - "mx4200_pps: CIOGETEV/TIOCGPPSEV: serial=%d, fdpps=%d, %s\n", - up->ppsev.serial, fdpps, strerror(errno)); + "mx4200_pps: time_pps_fetch: serial=%d, %s\n", + up->pps_i.assert_sequence, strerror(errno)); refclock_report(peer, CEVNT_FAULT); return(1); } - if (temp_serial == up->ppsev.serial) { + if (temp_serial == up->pps_i.assert_sequence) { mx4200_debug(peer, - "mx4200_pps: ppsev serial not incrementing: %d\n", - up->ppsev.serial); + "mx4200_pps: assert_sequence serial not incrementing: %d\n", + up->pps_i.assert_sequence); refclock_report(peer, CEVNT_FAULT); return(1); } - /* * Check pps serial number against last one */ - if (up->lastserial + 1 != up->ppsev.serial && up->lastserial != 0) { - if (up->ppsev.serial == up->lastserial) + if (up->lastserial + 1 != up->pps_i.assert_sequence && + up->lastserial != 0) { + if (up->pps_i.assert_sequence == up->lastserial) { mx4200_debug(peer, "mx4200_pps: no new pps event\n"); - else + } else { mx4200_debug(peer, "mx4200_pps: missed %d pps events\n", - up->ppsev.serial - up->lastserial - 1); + up->pps_i.assert_sequence - up->lastserial - 1); + } refclock_report(peer, CEVNT_FAULT); } - up->lastserial = up->ppsev.serial; + up->lastserial = up->pps_i.assert_sequence; /* * Return the timestamp in pp->lastrec */ - up->ppsev.tv.tv_sec += (u_int32) JAN_1970; - TVTOTS(&up->ppsev.tv,&pp->lastrec); + + pp->lastrec.l_ui = up->pps_i.assert_timestamp.tv_sec + + (u_int32) JAN_1970; + pp->lastrec.l_uf = ((double)(up->pps_i.assert_timestamp.tv_nsec) * + 4.2949672960) + 0.5; return(0); } diff --git a/contrib/ntp/ntpd/refclock_nmea.c b/contrib/ntp/ntpd/refclock_nmea.c index d90f71c..e9304ee 100644 --- a/contrib/ntp/ntpd/refclock_nmea.c +++ b/contrib/ntp/ntpd/refclock_nmea.c @@ -9,16 +9,25 @@ #if defined(REFCLOCK) && defined(CLOCK_NMEA) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#include <time.h> - #include "ntpd.h" #include "ntp_io.h" +#include "ntp_unixtime.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + +#ifdef HAVE_PPSAPI +# ifdef HAVE_TIMEPPS_H +# include <timepps.h> +# else +# ifdef HAVE_SYS_TIMEPPS_H +# include <sys/timepps.h> +# endif +# endif +#endif /* HAVE_PPSAPI */ + /* * This driver supports the NMEA GPS Receiver with * @@ -27,6 +36,23 @@ * The receiver used spits out the NMEA sentences for boat navigation. * And you thought it was an information superhighway. Try a raging river * filled with rapids and whirlpools that rip away your data and warp time. + * + * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in. + * On startup if initialization of the PPSAPI fails, it will fall back + * to the "normal" timestamps. + * + * The PPSAPI part of the driver understands fudge flag2 and flag3. If + * flag2 is set, it will use the clear edge of the pulse. If flag3 is + * set, kernel hardpps is enabled. + * + * GPS sentences other than RMC (the default) may be enabled by setting + * the relevent bits of 'mode' in the server configuration line + * server 127.127.20.x mode X + * + * bit 0 - enables RMC (1) + * bit 1 - enables GGA (2) + * bit 2 - enables GLL (4) + * multiple sentences may be selected */ /* @@ -39,9 +65,11 @@ #endif #define SPEED232 B4800 /* uart speed (4800 bps) */ #define PRECISION (-9) /* precision assumed (about 2 ms) */ -#define DCD_PRECISION (-20) /* precision assumed (about 1 us) */ +#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ #define REFID "GPS\0" /* reference id */ #define DESCRIPTION "NMEA GPS Clock" /* who we are */ +#define NANOSECOND 1000000000 /* one second (ns) */ +#define RANGEGATE 500000 /* range gate (ns) */ #define LENNMEA 75 /* min timecode length */ @@ -59,6 +87,12 @@ struct nmeaunit { int pollcnt; /* poll message counter */ int polled; /* Hand in a sample? */ l_fp tstamp; /* timestamp of last poll */ +#ifdef HAVE_PPSAPI + struct timespec ts; /* last timestamp */ + pps_params_t pps_params; /* pps parameters */ + pps_info_t pps_info; /* last pps data */ + pps_handle_t handle; /* pps handlebars */ +#endif /* HAVE_PPSAPI */ }; /* @@ -66,6 +100,12 @@ struct nmeaunit { */ static int nmea_start P((int, struct peer *)); static void nmea_shutdown P((int, struct peer *)); +#ifdef HAVE_PPSAPI +static void nmea_control P((int, struct refclockstat *, struct + refclockstat *, struct peer *)); +static int nmea_ppsapi P((struct peer *, int, int)); +static int nmea_pps P((struct nmeaunit *, l_fp *)); +#endif /* HAVE_PPSAPI */ static void nmea_receive P((struct recvbuf *)); static void nmea_poll P((int, struct peer *)); static void gps_send P((int, const char *, struct peer *)); @@ -78,7 +118,11 @@ struct refclock refclock_nmea = { nmea_start, /* start up driver */ nmea_shutdown, /* shut down driver */ nmea_poll, /* transmit poll message */ - noentry, /* handle control */ +#ifdef HAVE_PPSAPI + nmea_control, /* fudge control */ +#else + noentry, /* fudge control */ +#endif /* HAVE_PPSAPI */ noentry, /* initialize driver */ noentry, /* buginfo */ NOFLAGS /* not used */ @@ -130,13 +174,27 @@ nmea_start( /* * Initialize miscellaneous variables */ - peer->precision = DCD_PRECISION; + peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); up->pollcnt = 2; gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); +#ifdef HAVE_PPSAPI + /* + * Start the PPSAPI interface if it is there. Default to use + * the assert edge and do not enable the kernel hardpps. + */ + if (time_pps_create(fd, &up->handle) < 0) { + up->handle = 0; + msyslog(LOG_ERR, + "refclock_nmea: time_pps_create failed: %m"); + return (1); + } + return(nmea_ppsapi(peer, 0, 0)); +#else return (1); +#endif /* HAVE_PPSAPI */ } /* @@ -153,10 +211,149 @@ nmea_shutdown( pp = peer->procptr; up = (struct nmeaunit *)pp->unitptr; +#ifdef HAVE_PPSAPI + if (up->handle != 0) + time_pps_destroy(up->handle); +#endif /* HAVE_PPSAPI */ io_closeclock(&pp->io); free(up); } +#ifdef HAVE_PPSAPI +/* + * nmea_control - fudge control + */ +static void +nmea_control( + int unit, /* unit (not used */ + struct refclockstat *in, /* input parameters (not uded) */ + struct refclockstat *out, /* output parameters (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + + pp = peer->procptr; + nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2, + pp->sloppyclockflag & CLK_FLAG3); +} + + +/* + * Initialize PPSAPI + */ +int +nmea_ppsapi( + struct peer *peer, /* peer structure pointer */ + int enb_clear, /* clear enable */ + int enb_hardpps /* hardpps enable */ + ) +{ + struct refclockproc *pp; + struct nmeaunit *up; + int capability; + + pp = peer->procptr; + up = (struct nmeaunit *)pp->unitptr; + if (time_pps_getcap(up->handle, &capability) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_getcap failed: %m"); + return (0); + } + memset(&up->pps_params, 0, sizeof(pps_params_t)); + if (enb_clear) + up->pps_params.mode = capability & PPS_CAPTURECLEAR; + else + up->pps_params.mode = capability & PPS_CAPTUREASSERT; + if (!up->pps_params.mode) { + msyslog(LOG_ERR, + "refclock_nmea: invalid capture edge %d", + !enb_clear); + return (0); + } + up->pps_params.mode |= PPS_TSFMT_TSPEC; + if (time_pps_setparams(up->handle, &up->pps_params) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_setparams failed: %m"); + return (0); + } + if (enb_hardpps) { + if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, + up->pps_params.mode & ~PPS_TSFMT_TSPEC, + PPS_TSFMT_TSPEC) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_kcbind failed: %m"); + return (0); + } + pps_enable = 1; + } + peer->precision = PPS_PRECISION; + +#if DEBUG + if (debug) { + time_pps_getparams(up->handle, &up->pps_params); + printf( + "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n", + capability, up->pps_params.api_version, + up->pps_params.mode, enb_hardpps); + } +#endif + + return (1); +} + +/* + * Get PPSAPI timestamps. + * + * Return 0 on failure and 1 on success. + */ +static int +nmea_pps( + struct nmeaunit *up, + l_fp *tsptr + ) +{ + pps_info_t pps_info; + struct timespec timeout, ts; + double dtemp; + l_fp tstmp; + + /* + * Convert the timespec nanoseconds field to ntp l_fp units. + */ + if (up->handle == 0) + return (0); + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); + if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, + &timeout) < 0) + return (0); + if (up->pps_params.mode & PPS_CAPTUREASSERT) { + if (pps_info.assert_sequence == + up->pps_info.assert_sequence) + return (0); + ts = up->pps_info.assert_timestamp; + } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { + if (pps_info.clear_sequence == + up->pps_info.clear_sequence) + return (0); + ts = up->pps_info.clear_timestamp; + } else { + return (0); + } + if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec)) + return (0); + up->ts = ts; + + tstmp.l_ui = ts.tv_sec + JAN_1970; + dtemp = ts.tv_nsec * FRAC / 1e9; + tstmp.l_uf = (u_int32)dtemp; + *tsptr = tstmp; + return (1); +} +#endif /* HAVE_PPSAPI */ + /* * nmea_receive - receive data from the serial interface */ @@ -168,11 +365,14 @@ nmea_receive( register struct nmeaunit *up; struct refclockproc *pp; struct peer *peer; - l_fp trtmp; int month, day; int i; char *cp, *dp; int cmdtype; + /* Use these variables to hold data until we decide its worth keeping */ + char rd_lastcode[BMAX]; + l_fp rd_tmp; + u_short rd_lencode; /* * Initialize pointers and read the timecode and timestamp @@ -180,23 +380,18 @@ nmea_receive( peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct nmeaunit *)pp->unitptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); /* * There is a case that a <CR><LF> gives back a "blank" line */ - if (pp->lencode == 0) + if (rd_lencode == 0) return; - /* - * We get a buffer and timestamp for each <cr>. - */ - pp->lastrec = up->tstamp = trtmp; - up->pollcnt = 2; #ifdef DEBUG if (debug) - printf("nmea: timecode %d %s\n", pp->lencode, - pp->a_lastcode); + printf("nmea: gpsread %d %s\n", rd_lencode, + rd_lastcode); #endif /* @@ -204,18 +399,31 @@ nmea_receive( * we only care about a few of them. The most important being * the $GPRMC format * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC - * $GPGGA,162617.0,4548.339,N,00837.719,E,1,07,0.97,00262,M,048,M,,*5D + * For Magellan (ColorTrak) GLL probably datum (order of sentences) + * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL + * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21 + * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F + * $GPRMB,... + * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77 + * $GPAPB,... + * $GPGSA,... + * $GPGSV,... + * $GPGSV,... */ -#define GPRMC 0 -#define GPXXX 1 -#define GPGCA 2 - cp = pp->a_lastcode; +#define GPXXX 0 +#define GPRMC 1 +#define GPGGA 2 +#define GPGLL 4 + cp = rd_lastcode; cmdtype=0; if(strncmp(cp,"$GPRMC",6)==0) { cmdtype=GPRMC; } else if(strncmp(cp,"$GPGGA",6)==0) { - cmdtype=GPGCA; + cmdtype=GPGGA; + } + else if(strncmp(cp,"$GPGLL",6)==0) { + cmdtype=GPGLL; } else if(strncmp(cp,"$GPXXX",6)==0) { cmdtype=GPXXX; @@ -223,14 +431,84 @@ nmea_receive( else return; + + /* See if I want to process this message type */ + if ( ((peer->ttlmax == 0) && (cmdtype != GPRMC)) + || ((peer->ttlmax != 0) && !(cmdtype & peer->ttlmax)) ) + return; + + pp->lencode = rd_lencode; + strcpy(pp->a_lastcode,rd_lastcode); + cp = pp->a_lastcode; + + pp->lastrec = up->tstamp = rd_tmp; + up->pollcnt = 2; + +#ifdef DEBUG + if (debug) + printf("nmea: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + + /* Grab field depending on clock string type */ switch( cmdtype ) { case GPRMC: - case GPGCA: /* - * Check time code format of NMEA + * Test for synchronization. Check for quality byte. + */ + dp = field_parse(cp,2); + if( dp[0] != 'A') + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; + + /* Now point at the time field */ + dp = field_parse(cp,1); + break; + + + case GPGGA: + /* + * Test for synchronization. Check for quality byte. */ + dp = field_parse(cp,6); + if( dp[0] == '0') + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; + /* Now point at the time field */ dp = field_parse(cp,1); + break; + + + case GPGLL: + /* + * Test for synchronization. Check for quality byte. + */ + dp = field_parse(cp,6); + if( dp[0] != 'A') + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; + + /* Now point at the time field */ + dp = field_parse(cp,5); + break; + + + case GPXXX: + return; + default: + return; + + } + + /* + * Check time code format of NMEA + */ + if( !isdigit((int)dp[0]) || !isdigit((int)dp[1]) || !isdigit((int)dp[2]) || @@ -242,40 +520,55 @@ nmea_receive( return; } - /* - * Test for synchronization. Check for quality byte. - */ - dp = field_parse(cp,2); - if( dp[0] != 'A') { - refclock_report(peer, CEVNT_BADREPLY); - return; + + /* + * Convert time and check values. + */ + pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; + pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; + pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; + /* Default to 0 milliseconds, if decimal convert milliseconds in + one, two or three digits + */ + pp->msec = 0; + if (dp[6] == '.') { + if (isdigit((int)dp[7])) { + pp->msec = (dp[7] - '0') * 100; + if (isdigit((int)dp[8])) { + pp->msec += (dp[8] - '0') * 10; + if (isdigit((int)dp[9])) { + pp->msec += (dp[9] - '0'); + } + } } - break; - case GPXXX: - return; - default: - return; + } + if (pp->hour > 23 || pp->minute > 59 || pp->second > 59 + || pp->msec > 1000) { + refclock_report(peer, CEVNT_BADTIME); + return; } - if (cmdtype ==GPGCA) { - /* only time */ - time_t tt = time(NULL); - struct tm * t = gmtime(&tt); - day = t->tm_mday; - month = t->tm_mon + 1; - pp->year= t->tm_year; - } else { - dp = field_parse(cp,9); + /* * Convert date and check values. */ - day = dp[0] - '0'; - day = (day * 10) + dp[1] - '0'; - month = dp[2] - '0'; - month = (month * 10) + dp[3] - '0'; - pp->year = dp[4] - '0'; - pp->year = (pp->year * 10) + dp[5] - '0'; + if (cmdtype==GPRMC) { + dp = field_parse(cp,9); + day = dp[0] - '0'; + day = (day * 10) + dp[1] - '0'; + month = dp[2] - '0'; + month = (month * 10) + dp[3] - '0'; + pp->year = dp[4] - '0'; + pp->year = (pp->year * 10) + dp[5] - '0'; + } + else { + /* only time */ + time_t tt = time(NULL); + struct tm * t = gmtime(&tt); + day = t->tm_mday; + month = t->tm_mon + 1; + pp->year= t->tm_year; } if (month < 1 || month > 12 || day < 1) { @@ -283,6 +576,9 @@ nmea_receive( return; } + /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */ + /* good thing that 2000 is a leap year */ + /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */ if (pp->year % 4) { if (day > day1tab[month - 1]) { refclock_report(peer, CEVNT_BADTIME); @@ -300,19 +596,17 @@ nmea_receive( } pp->day = day; - dp = field_parse(cp,1); + +#ifdef HAVE_PPSAPI /* - * Convert time and check values. + * If the PPSAPI is working, rather use its timestamps. + * assume that the PPS occurs on the second so blow any msec */ - pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; - pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; - pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; - pp->msec = 0; - - if (pp->hour > 23 || pp->minute > 59 || pp->second > 59) { - refclock_report(peer, CEVNT_BADTIME); - return; + if (nmea_pps(up, &rd_tmp) == 1) { + pp->lastrec = up->tstamp = rd_tmp; + pp->msec = 0; } +#endif /* HAVE_PPSAPI */ /* * Process the new sample in the median filter and determine the @@ -322,11 +616,14 @@ nmea_receive( * time, which may cause a paranoid protocol module to chuck out * the data. */ + if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } + + /* * Only go on if we had been polled. */ @@ -336,7 +633,11 @@ nmea_receive( refclock_receive(peer); + /* If we get here - what we got from the clock is OK, so say so */ + refclock_report(peer, CEVNT_NOMINAL); + record_clock_stats(&peer->srcadr, pp->a_lastcode); + } /* diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c index e0ba177..dbb9f5d 100644 --- a/contrib/ntp/ntpd/refclock_oncore.c +++ b/contrib/ntp/ntpd/refclock_oncore.c @@ -9,6 +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. + * The receivers without position hold (GT, GT+) will be less accurate. * * Tested with: * @@ -24,28 +27,40 @@ * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 * 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 + * HDWR P/N # _ HWDR P/N # 1 + * SERIAL # SSG0226478 SERIAL # P003UD + * MANUFACTUR DATE 7E02 MANUFACTUR DATE 0C27 + * OPTIONS LIST IB + * * -------------------------------------------------------------------------- * This code uses the two devices - * /dev/oncore.serial.n - * /dev/oncore.pps.n + * /dev/oncore.serial.n + * /dev/oncore.pps.n * which may be linked to the same device. * and can read initialization data from the file - * /etc/ntp.oncoreN (where n and N are the unit number, viz 127.127.30.N) - * or /etc/ntp.oncore + * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where + * n or N are the unit number, viz 127.127.30.N. * -------------------------------------------------------------------------- * Reg.Clemens <reg@dwf.com> Sep98. * Original code written for FreeBSD. - * With these mods it works on SunOS, Solaris (untested) and Linux - * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + changes). + * With these mods it works on FreeBSD, SunOS, Solaris and Linux + * (SunOS 4.1.3 + ppsclock) + * (Solaris7 + MU4) + * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). * * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the * state machine state) are printed to CLOCKSTATS if that file is enabled * in /etc/ntp.conf. * * -------------------------------------------------------------------------- - */ - -/* + * * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) * doing an average of 10000 valid 2D and 3D fixes is what the automatic * site survey mode does. Looking at the output from the receiver @@ -58,20 +73,26 @@ /* * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a * "STATUS" line in the oncore config file, which contains the most recent - * copy of all types of messages we recognize. This file can be mmap(2)'ed + * copy of all types of messages we recognize. This file can be mmap(2)'ed * by monitoring and statistics programs. + * + * See separate HTML documentation for this option. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#if defined(REFCLOCK) && defined(CLOCK_ONCORE) +#if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI) + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" #include <stdio.h> #include <ctype.h> -#include <sys/types.h> -#include <sys/time.h> #include <sys/stat.h> #ifdef ONCORE_SHMEM_STATUS # ifdef HAVE_SYS_MMAN_H @@ -83,11 +104,11 @@ #endif /* ONCORE_SHMEM_STATUS */ #ifdef HAVE_PPSAPI -# ifdef HAVE_TIMEPPS_H -# include <timepps.h> +# ifdef HAVE_TIMEPPS_H +# include <timepps.h> # else # ifdef HAVE_SYS_TIMEPPS_H -# include <sys/timepps.h> +# include <sys/timepps.h> # endif # endif #endif @@ -96,14 +117,8 @@ # include <sys/sio.h> #endif -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" - #ifdef HAVE_SYS_TERMIOS_H -#include <sys/termios.h> +# include <sys/termios.h> #endif #ifdef HAVE_SYS_PPSCLOCK_H @@ -112,7 +127,7 @@ #ifndef HAVE_STRUCT_PPSCLOCKEV struct ppsclockev { -# ifdef HAVE_TIMESPEC +# ifdef HAVE_STRUCT_TIMESPEC struct timespec tv; # else struct timeval tv; @@ -123,90 +138,163 @@ struct ppsclockev { enum receive_state { ONCORE_NO_IDEA, + ONCORE_ID_SENT, ONCORE_RESET_SENT, ONCORE_TEST_SENT, - ONCORE_ID_SENT, + ONCORE_INIT, ONCORE_ALMANAC, ONCORE_RUN }; enum site_survey_state { ONCORE_SS_UNKNOWN, + ONCORE_SS_TESTING, ONCORE_SS_HW, ONCORE_SS_SW, ONCORE_SS_DONE }; +/* Model Name, derived from the @@Cj message. + * Used to initialize some variables. + */ + +enum oncore_model { + ONCORE_BASIC, + ONCORE_PVT6, + ONCORE_VP, + ONCORE_UT, + ONCORE_UTPLUS, + ONCORE_GT, + ONCORE_GTPLUS, + ONCORE_SL, + ONCORE_M12, + ONCORE_UNKNOWN +}; + +/* the bits that describe these properties are in the same place + * on the VP/UT, but have moved on the M12. As such we extract + * them, and use them from this struct. + * + */ + +struct RSM { + u_char posn0D; + u_char posn2D; + u_char posn3D; + u_char bad_almanac; + u_char bad_fix; +}; + +/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to + * see what mode it is in. The bits on the M12 are multiplexed with + * other messages, so we have to 'keep' the last known mode here. + */ + +enum posn_mode { + MODE_UNKNOWN, + MODE_0D, + MODE_2D, + MODE_3D +}; + struct instance { int unit; /* 127.127.30.unit */ + struct refclockproc *pp; + struct peer *peer; + int ttyfd; /* TTY file descriptor */ int ppsfd; /* PPS file descriptor */ int statusfd; /* Status shm descriptor */ - u_char *shmem; #ifdef HAVE_PPSAPI pps_handle_t pps_h; pps_params_t pps_p; #endif enum receive_state o_state; /* Receive state */ - + enum posn_mode mode; /* 0D, 2D, 3D */ enum site_survey_state site_survey; /* Site Survey state */ - struct refclockproc *pp; - struct peer *peer; - int Bj_day; - long delay; /* ns */ + u_long delay; /* ns */ long offset; /* ns */ + u_char *shmem; + char *shmem_fname; + u_int shmem_Cb; + u_int shmem_Ba; + u_int shmem_Ea; + u_int shmem_Ha; + u_char shmem_first; + u_char shmem_reset; + u_char shmem_Posn; + double ss_lat; double ss_long; double ss_ht; + double dH; int ss_count; - u_char ss_ht_type; - u_char posn_set; + u_char posn_set; - u_char printed; - u_char polled; + enum oncore_model model; + u_int version; + 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 */ + u_char traim_delay; /* seconds counter, waiting for reply */ + + struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ + u_char printed; + u_char polled; int pollcnt; u_int ev_serial; int Rcvptr; u_char Rcvbuf[500]; - u_char Ea[77]; - u_char En[70]; + u_char Ea[160]; /* Ba, Ea or Ha */ + u_char En[70]; /* Bn or En */ u_char Cj[300]; u_char As; u_char Ay; u_char Az; + u_char have_dH; u_char init_type; s_char saw_tooth; - u_char timeout; /* flag to retry Cj after Fa reset */ - s_char assert; + u_int timeout; /* count to retry Cj after Fa self-test */ + u_char count; /* cycles thru Ea before starting */ + s_char assert; + u_int saw_At; }; #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 *, u_int)); -static void oncore_shutdown P((int, struct peer *)); -static int oncore_start P((int, struct peer *)); - -static void oncore_msg_any P((struct instance *, u_char *, u_int, int)); -static void oncore_msg_As P((struct instance *, u_char *, u_int)); -static void oncore_msg_At P((struct instance *, u_char *, u_int)); -static void oncore_msg_Ay P((struct instance *, u_char *, u_int)); -static void oncore_msg_Az P((struct instance *, u_char *, u_int)); -static void oncore_msg_Bj P((struct instance *, u_char *, u_int)); -static void oncore_msg_Cb P((struct instance *, u_char *, u_int)); -static void oncore_msg_Cf P((struct instance *, u_char *, u_int)); -static void oncore_msg_Cj P((struct instance *, u_char *, u_int)); -static void oncore_msg_Ea P((struct instance *, u_char *, u_int)); -static void oncore_msg_En P((struct instance *, u_char *, u_int)); -static void oncore_msg_Fa P((struct instance *, u_char *, u_int)); +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 void oncore_msg_any P((struct instance *, u_char *, size_t, int)); +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_Bj P((struct instance *, u_char *, size_t)); +static void oncore_msg_BnEn 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_Gj P((struct instance *, u_char *, size_t)); +static void oncore_msg_Sz P((struct instance *, u_char *, size_t)); struct refclock refclock_oncore = { oncore_start, /* start up driver */ @@ -220,65 +308,83 @@ struct refclock refclock_oncore = { /* * Understanding the next bit here is not easy unless you have a manual - * for the the UT or VP Oncore. + * for the the various Oncore Models. */ static struct msg_desc { const char flag[3]; const int len; - void (*handler) P((struct instance *, u_char *, u_int)); + void (*handler) P((struct instance *, u_char *, size_t)); const char *fmt; int shmem; } oncore_messages[] = { - /* Ea and En first since they're most common */ - { "Ea", 76, oncore_msg_Ea, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, - { "En", 69, oncore_msg_En, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, - { "Ab", 10, 0, "" }, - { "Ac", 11, 0, "" }, - { "Ad", 11, 0, "" }, - { "Ae", 11, 0, "" }, - { "Af", 15, 0, "" }, - { "As", 20, oncore_msg_As, "" }, - { "At", 8, oncore_msg_At, "" }, - { "Aw", 8, 0, "" }, - { "Ay", 11, oncore_msg_Ay, "" }, - { "Az", 11, oncore_msg_Az, "" }, - { "AB", 8, 0, "" }, - { "Bb", 92, 0, "" }, - { "Bj", 8, oncore_msg_Bj, "" }, - { "Cb", 33, oncore_msg_Cb, "" }, - { "Cf", 7, oncore_msg_Cf, "" }, - { "Cg", 8, 0, "" }, - { "Ch", 9, 0, "" }, - { "Cj", 294, oncore_msg_Cj, "" }, - { "Ek", 71, 0, "" }, - { "Fa", 9, oncore_msg_Fa, "" }, - { "Sz", 8, 0, "" }, - { {0}, 7, 0, ""} + /* Ea and En first since they're most common */ + { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, + { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, + { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, + { "En", 69, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, + { "Bn", 59, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, + { "Ab", 10, 0, "" }, + { "Ac", 11, 0, "" }, + { "Ad", 11, 0, "" }, + { "Ae", 11, 0, "" }, + { "Af", 15, 0, "" }, + { "As", 20, oncore_msg_As, "" }, + { "At", 8, oncore_msg_At, "" }, + { "Au", 12, 0, "" }, + { "Av", 8, 0, "" }, + { "Aw", 8, 0, "" }, + { "Ay", 11, oncore_msg_Ay, "" }, + { "Az", 11, oncore_msg_Az, "" }, + { "AB", 8, 0, "" }, + { "Bb", 92, 0, "" }, + { "Bj", 8, oncore_msg_Bj, "" }, + { "Ca", 9, oncore_msg_CaFaIa, "" }, + { "Cb", 33, oncore_msg_Cb, "" }, + { "Cf", 7, oncore_msg_Cf, "" }, + { "Cg", 8, 0, "" }, + { "Ch", 9, 0, "" }, + { "Cj", 294, oncore_msg_Cj, "" }, + { "Ek", 71, 0, "" }, + { "Fa", 9, oncore_msg_CaFaIa, "" }, + { "Gd", 8, 0, "" }, + { "Gj", 21, oncore_msg_Gj, "" }, + { "Ia", 10, oncore_msg_CaFaIa, "" }, + { "Sz", 8, oncore_msg_Sz, "" }, + { {0}, 7, 0, "" } }; -static unsigned int oncore_shmem_Cb; - /* * 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_At[] = { 'A', 't', 2 }; +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 */ /* - * Position-Hold Position + * 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). @@ -317,6 +423,7 @@ u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; * Request message once */ u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; +u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* * Set to Defaults @@ -337,7 +444,11 @@ 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_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 @@ -351,12 +462,17 @@ u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ * Alarm limit 1us * PPS on when we have the first sat */ -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_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_Fa[] = { 'F', 'a' }; +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 */ #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ @@ -370,7 +486,7 @@ static u_char oncore_cmd_Fa[] = { 'F', 'a' }; */ /* to buffer, int w, u_char *buf */ -#define w32_buf(buf,w) { unsigned int i_tmp; \ +#define w32_buf(buf,w) { u_int i_tmp; \ i_tmp = (w<0) ? (~(-w)+1) : (w); \ (buf)[0] = (i_tmp >> 24) & 0xff; \ (buf)[1] = (i_tmp >> 16) & 0xff; \ @@ -390,9 +506,11 @@ extern int pps_assert; extern int pps_hardpps; + /* * oncore_start - initialize data for processing */ + static int oncore_start( int unit, @@ -452,22 +570,44 @@ oncore_start( } } - /* Devices now open, initialize instance structure */ + /* Devices now open, create instance structure for this unit */ - if (!(instance = (struct instance *)emalloc(sizeof *instance))) { + if (!(instance = (struct instance *) malloc(sizeof *instance))) { perror("malloc"); close(fd1); return (0); } memset((char *) instance, 0, sizeof *instance); + + /* link instance up and down */ + pp = peer->procptr; - pp->unitptr = (caddr_t)instance; - instance->unit = unit; + pp->unitptr = (caddr_t) instance; + instance->pp = pp; + instance->unit = unit; + instance->peer = peer; + + /* initialize miscellaneous variables */ + + instance->o_state = ONCORE_NO_IDEA; + cp = "state = ONCORE_NO_IDEA"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->ttyfd = fd1; instance->ppsfd = fd2; instance->Bj_day = -1; instance->assert = pps_assert; + instance->traim = -1; + instance->model = ONCORE_UNKNOWN; + instance->mode = MODE_UNKNOWN; + instance->site_survey = ONCORE_SS_UNKNOWN; + + peer->precision = -26; + peer->minpoll = 4; + peer->maxpoll = 4; + pp->clockdesc = "Motorola Oncore GPS Receiver"; + memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); /* go read any input data in /etc/ntp.oncoreX */ @@ -492,10 +632,10 @@ oncore_start( } /* nb. only turn things on, if someone else has turned something - * on before we get here, leave it alone! + * on before we get here, leave it alone! */ - if (instance->assert) { /* nb, default or ON */ + if (instance->assert) { /* nb, default or ON */ instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT; instance->pps_p.assert_offset.tv_sec = 0; instance->pps_p.assert_offset.tv_nsec = 0; @@ -505,7 +645,7 @@ oncore_start( instance->pps_p.clear_offset.tv_nsec = 0; } instance->pps_p.mode |= PPS_TSFMT_TSPEC; - instance->pps_p.mode &= mode; /* only do it if it is legal */ + instance->pps_p.mode &= mode; /* only set what is legal */ if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { perror("time_pps_setparams"); @@ -517,17 +657,17 @@ oncore_start( perror("ONCORE: stat pps_device"); return(0); } - + /* must have hardpps ON, and fd2 must be the same device as on the pps line */ - + if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) { - int i; - + int i; + 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) { @@ -535,27 +675,12 @@ oncore_start( "refclock_ioctl: time_pps_kcbind failed: %m"); return (0); } + pps_enable = 1; } } } #endif - instance->pp = pp; - instance->peer = peer; - instance->o_state = ONCORE_NO_IDEA; - cp = "state = ONCORE_NO_IDEA"; - record_clock_stats(&(instance->peer->srcadr), cp); - - /* - * Initialize miscellaneous variables - */ - - peer->precision = -26; - peer->minpoll = 4; - peer->maxpoll = 4; - pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver"; - memcpy((char *)&pp->refid, "GPS\0", 4); - pp->io.clock_recv = oncore_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; @@ -566,26 +691,16 @@ oncore_start( free(instance); return (0); } - pp->unitptr = (caddr_t)instance; /* - * This will start the Oncore receiver. - * We send info from config to Oncore later. + * This will return the Model Number of the Oncore receiver. */ - instance->timeout = 1; - mode = instance->init_type; - if (mode == 3 || mode == 4) { - 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 { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); - 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)); + instance->o_state = ONCORE_ID_SENT; + cp = "state = ONCORE_ID SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->timeout = 4; instance->pollcnt = 2; return (1); @@ -593,94 +708,25 @@ oncore_start( -static void -oncore_init_shmem(struct instance *instance, char *filename) -{ -#ifdef ONCORE_SHMEM_STATUS - int i, l, n; - char *buf; - struct msg_desc *mp; - static unsigned int oncore_shmem_length; - - if (oncore_messages[0].shmem == 0) { - n = 1; - for (mp = oncore_messages; mp->flag[0]; mp++) { - mp->shmem = n; - /* Allocate space for multiplexed almanac */ - if (!strcmp(mp->flag, "Cb")) { - oncore_shmem_Cb = n; - n += (mp->len + 2) * 34; - } - n += mp->len + 2; - } - oncore_shmem_length = n + 2; - fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", oncore_shmem_length); - } - instance->statusfd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644); - if (instance->statusfd < 0) { - perror(filename); - exit(4); - } - buf = malloc(oncore_shmem_length); - if (buf == NULL) { - perror("malloc"); - exit(4); - } - memset(buf, 0, sizeof(buf)); - i = write(instance->statusfd, buf, oncore_shmem_length); - if (i != oncore_shmem_length) { - perror(filename); - exit(4); - } - 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 == MAP_FAILED) { - instance->shmem = 0; - close (instance->statusfd); - exit(4); - } - 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] = '@'; - instance->shmem[l + 3] = '@'; - instance->shmem[l + 4] = mp->flag[0]; - instance->shmem[l + 5] = mp->flag[1]; - if (!strcmp(mp->flag, "Cb")) { - for (i = 1; i < 35; i++) { - instance->shmem[l + i * 35 + 0] = mp->len >> 8; - instance->shmem[l + i * 35 + 1] = mp->len & 0xff; - instance->shmem[l + i * 35 + 2] = '@'; - instance->shmem[l + i * 35 + 3] = '@'; - instance->shmem[l + i * 35 + 4] = mp->flag[0]; - instance->shmem[l + i * 35 + 5] = mp->flag[1]; - } - } - } -#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/ntp.oncoreN, where - * N is the unit number viz 127.127.30.N. - * If we don't find it, then we try the file /etc/ntp.oncore. + * First we try to open the configuration file + * /etc/oncoreN + * where N is the unit number viz 127.127.30.N. + * If we don't find it we try + * /etc/ntp.oncore.N + * and then + * /etc/ntp.oncore * - * If we find NEITHER then we don't have the cable delay or PPS offset + * If we don't find any then we don't have the cable delay or PPS offset * and we choose MODE (4) below. * * Five Choices for MODE @@ -705,7 +751,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 + * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, 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). * @@ -723,26 +770,47 @@ oncore_read_config( * DDD MMM.mmm * DDD MMM SSS.sss * - * Expect to see one line with 'HT' (or 'HTMSL' or 'HTGPS') 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 same as HTGPS. - * HTMSL = HT above mean_sea_level, - * HTGPS = HT above GPS ellipse. + * 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 + * the difference GPS-MSL on the clockstats file. * - * There are two optional lines, starting with DELAY and OFFSET, followed + * There is an optional line, starting with DELAY, followed * by 1 or two fields. The first is a number (a time) the second is * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. - * DELAY is cable delay, typically a few tens of ns. - * OFFSET is the offset of the PPS pulse from 0. (only fully implemented + * DELAY is cable delay, typically a few tens of ns. + * + * There is an optional line, starting with OFFSET, followed + * by 1 or two fields. The first is a number (a time) the second is + * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. + * OFFSET is the offset of the PPS pulse from 0. (only fully implemented * with the PPSAPI, we need to be able to tell the Kernel about this * offset if the Kernel PLL is in use, but can only do this presently * when using the PPSAPI interface. If not using the Kernel PLL, * then there is no problem. * - * There is another optional line, with either ASSERT or CLEAR on it, which + * 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. * + * 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. + * 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. + * + * 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. + * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be + * followed by YES or NO. + * * So acceptable input would be * # these are my coordinates (RWC) * LON -106 34.610 @@ -752,16 +820,20 @@ oncore_read_config( */ FILE *fd; - char *cp, *cc, *ca, line[100], units[2], device[20]; + char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160]; int i, sign, lat_flg, long_flg, ht_flg, mode; double f1, f2, f3; - sprintf(device, "%s%d", INIT_FILE, instance->unit); - if ((fd=fopen(device, "r")) == NULL) - if ((fd=fopen(INIT_FILE, "r")) == NULL) { - instance->init_type = 4; - return; + sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */ + if ((fd=fopen(device, "r")) == NULL) { /* it was in the original documentation */ + sprintf(device, "%s.%d", INIT_FILE, instance->unit); /* then try "ntp.oncore.0 */ + if ((fd=fopen(device, "r")) == NULL) { + if ((fd=fopen(INIT_FILE, "r")) == NULL) { /* and finally "ntp.oncore" */ + instance->init_type = 4; + return; + } } + } mode = 0; lat_flg = long_flg = ht_flg = 0; @@ -770,7 +842,7 @@ oncore_read_config( /* Remove comments */ if ((cp = strchr(line, '#'))) *cp = '\0'; - + /* Remove trailing space */ for (i = strlen(line); i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]); @@ -785,24 +857,30 @@ oncore_read_config( if (!*cc) continue; - /* Lowercase the command and find the arg */ + /* Uppercase the command and find the arg */ for (ca = cc; *ca; ca++) { - if (isascii((int)*ca) && islower((int)*ca)) { - *ca = toupper(*ca); - } else if (isascii((int)*ca) && isspace((int)*ca)) { - break; - } else if (*ca == '=') { - *ca = ' '; - break; + if (isascii((int)*ca)) { + if (islower((int)*ca)) { + *ca = toupper(*ca); + } else if (isspace((int)*ca) || (*ca == '=')) + break; } } - - /* Remove space leading the arg */ - for (; *ca && isascii((int)*ca) && isspace((int)*ca); ca++) + + /* Remove space (and possible =) leading the arg */ + for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++) continue; - if (!strncmp(cc, "STATUS", 6)) { - oncore_init_shmem(instance, ca); + /* + * 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)); + strcpy(instance->shmem_fname, ca); continue; } @@ -811,7 +889,7 @@ oncore_read_config( if (isascii((int)*cp) && islower((int)*cp)) *cp = toupper(*cp); - if (!strncmp(cc, "LAT", 3)) { + if (!strncmp(cc, "LAT", (size_t) 3)) { f1 = f2 = f3 = 0; sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); sign = 1; @@ -821,7 +899,7 @@ oncore_read_config( } instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ lat_flg++; - } else if (!strncmp(cc, "LON", 3)) { + } else if (!strncmp(cc, "LON", (size_t) 3)) { f1 = f2 = f3 = 0; sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); sign = 1; @@ -831,13 +909,7 @@ oncore_read_config( } instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ long_flg++; - } else if (!strncmp(cc, "HT", 2)) { - if (!strncmp(cc, "HTGPS", 5)) - instance->ss_ht_type = 0; - else if (!strncmp(cc, "HTMSL", 5)) - instance->ss_ht_type = 1; - else - instance->ss_ht_type = 0; + } else if (!strncmp(cc, "HT", (size_t) 2)) { f1 = 0; units[0] = '\0'; sscanf(ca, "%lf %1s", &f1, units); @@ -845,7 +917,7 @@ oncore_read_config( f1 = 0.3048 * f1; instance->ss_ht = 100 * f1; /* cm */ ht_flg++; - } else if (!strncmp(cc, "DELAY", 5)) { + } else if (!strncmp(cc, "DELAY", (size_t) 5)) { f1 = 0; units[0] = '\0'; sscanf(ca, "%lf %1s", &f1, units); @@ -859,8 +931,12 @@ oncore_read_config( f1 = 1000000000 * f1; if (f1 < 0 || f1 > 1.e9) f1 = 0; - instance->delay = f1; /* delay in ns */ - } else if (!strncmp(cc, "OFFSET", 6)) { + if (f1 < 0 || f1 > 999999) { + sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1); + record_clock_stats(&(instance->peer->srcadr), Msg); + } else + instance->delay = f1; /* delay in ns */ + } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { f1 = 0; units[0] = '\0'; sscanf(ca, "%lf %1s", &f1, units); @@ -874,16 +950,31 @@ oncore_read_config( f1 = 1000000000 * f1; if (f1 < 0 || f1 > 1.e9) f1 = 0; - instance->offset = f1; /* offset in ns */ - } else if (!strncmp(cc, "MODE", 4)) { + if (f1 < 0 || f1 > 999999999.) { + sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1); + record_clock_stats(&(instance->peer->srcadr), Msg); + } else + instance->offset = f1; /* offset in ns */ + } else if (!strncmp(cc, "MODE", (size_t) 4)) { sscanf(ca, "%d", &mode); if (mode < 0 || mode > 4) mode = 4; - instance->init_type = mode; - } else if (!strncmp(cc, "ASSERT", 6)) { + } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { instance->assert = 1; - } else if (!strncmp(cc, "CLEAR", 5)) { + } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { instance->assert = 0; + } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { + instance->shmem_Posn = 2; + } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { + instance->shmem_Posn = 3; + } else if (!strncmp(cc, "CHAN", (size_t) 4)) { + sscanf(ca, "%d", &i); + if ((i == 6) || (i == 8) || (i == 12)) + instance->chan = i; + } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { + instance->traim = 1; /* so TRAIM alone is YES */ + if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ + instance->traim = 0; } } fclose(fd); @@ -897,9 +988,116 @@ oncore_read_config( if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) { printf("ONCORE: incomplete data on %s\n", INIT_FILE); instance->posn_set = 0; - if (mode == 1 || mode == 3) - instance->init_type++; + if (mode == 1 || mode == 3) { + sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1); + record_clock_stats(&(instance->peer->srcadr), Msg); + mode++; + } } + instance->init_type = mode; + + sprintf(Msg, "Input mode = %d", mode); + record_clock_stats(&(instance->peer->srcadr), Msg); +} + + + +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 */ } @@ -907,6 +1105,7 @@ oncore_read_config( /* * oncore_shutdown - shut down the clock */ + static void oncore_shutdown( int unit, @@ -918,6 +1117,9 @@ oncore_shutdown( pp = peer->procptr; instance = (struct instance *) pp->unitptr; + + io_closeclock(&pp->io); + free(instance); } @@ -926,6 +1128,7 @@ oncore_shutdown( /* * oncore_poll - called by the transmit procedure */ + static void oncore_poll( int unit, @@ -936,12 +1139,18 @@ oncore_poll( instance = (struct instance *) peer->procptr->unitptr; if (instance->timeout) { - char *cp; + char *cp; - 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--; + 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; } @@ -956,14 +1165,15 @@ oncore_poll( /* - * move dta from NTP to buffer (toss in unlikely case it wont fit) + * move data from NTP to buffer (toss in unlikely case it wont fit) */ + static void oncore_receive( struct recvbuf *rbufp ) { - u_int i; + size_t i; u_char *p; struct peer *peer; struct instance *instance; @@ -999,6 +1209,7 @@ oncore_receive( /* * Deal with any complete messages */ + static void oncore_consume( struct instance *instance @@ -1014,49 +1225,65 @@ oncore_consume( if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') break; if (debug > 4) - printf("ONCORE: >>> skipping %d chars\n", i); + printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i); if (i != rcvptr) - memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i)); + memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); rcvptr -= i; + continue; } /* Ok, we have a header now */ l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; for(m=0; m<l; m++) - if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), 2)) + if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) break; + if (m == l) { + if (debug > 4) + printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]); + memcpy(rcvbuf, rcvbuf+4, (size_t) 4); + rcvptr -= 4; + continue; + } + l = oncore_messages[m].len; #if 0 if (debug > 3) - printf("ONCORE: GOT: %c%c %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m); + printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m); #endif /* Got the entire message ? */ if (rcvptr < l) return; - /* Check the checksum */ - - j = 0; - for (i = 2; i < l-3; i++) - j ^= rcvbuf[i]; - if (j == rcvbuf[l-3]) { - if (instance->shmem != NULL) - memcpy(instance->shmem + oncore_messages[m].shmem + 2, - rcvbuf, l); - oncore_msg_any(instance, rcvbuf, (unsigned) (l-3), m); - if (oncore_messages[m].handler) - oncore_messages[m].handler(instance, rcvbuf, (unsigned) (l-3)); - } else if (debug) { - printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]); - printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]); - for (i=4; i<l; i++) - printf("%03o ", rcvbuf[i]); - printf("\n"); + /* are we at the end of message? should be <Cksum><CR><LF> */ + + if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { + if (debug) + printf("ONCORE[%d]: NO <CR><LF> 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 (instance->shmem != NULL) { + instance->shmem[oncore_messages[m].shmem + 2]++; + memcpy(instance->shmem + oncore_messages[m].shmem + 3, + rcvbuf, (size_t) l); + } + oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); + 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]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]); + for (i=4; i<l; i++) + printf("%03o ", rcvbuf[i]); + printf("\n"); + } } if (l != rcvptr) - memcpy(rcvbuf, rcvbuf+l, (unsigned) (rcvptr-l)); + memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); rcvptr -= l; } } @@ -1066,42 +1293,56 @@ oncore_consume( /* * write message to Oncore. */ + static void oncore_sendmsg( int fd, u_char *ptr, - u_int len + size_t len ) { u_char cs = 0; - printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], len); - write(fd, "@@", 2); + 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, 1); - write(fd, "\r\n", 2); + write(fd, &cs, (size_t) 1); + write(fd, "\r\n", (size_t) 2); } +/* + * print Oncore response message. + */ + static void oncore_msg_any( struct instance *instance, u_char *buf, - u_int len, + 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; +#else GETTIMEOFDAY(&tv, 0); - printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec); +#endif + printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec); if (!*fmt) { printf(">>@@%c%c ", buf[2], buf[3]); @@ -1130,11 +1371,12 @@ oncore_msg_any( /* * Demultiplex the almanac into shmem */ + static void oncore_msg_Cb( struct instance *instance, u_char *buf, - u_int len + size_t len ) { int i; @@ -1142,7 +1384,7 @@ oncore_msg_Cb( if (instance->shmem == NULL) return; - if (buf[4] == 5) + if (buf[4] == 5) i = buf[5]; else if (buf[4] == 4 && buf[5] <= 5) i = buf[5] + 24; @@ -1150,88 +1392,63 @@ oncore_msg_Cb( i = buf[5] + 23; else i = 34; - i *= 35; - memcpy(instance->shmem + oncore_shmem_Cb + i + 2, buf, len + 3); + i *= 36; + instance->shmem[instance->shmem_Cb + i + 2]++; + memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); } -/* - * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup - * not so for VP (eeprom) or UT with battery - */ -static void -oncore_msg_Cf( - struct instance *instance, - u_char *buf, - u_int len - ) -{ - const char *cp; - if (instance->o_state == ONCORE_RESET_SENT) { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } -} +/* + * 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. + */ -/* there are good reasons NOT to do a @@Fa command with the ONCORE. - * Doing it, 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 - * been cleared, we reissue the @@Ca that is issued below. +/* + * 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. */ static void -oncore_msg_Fa( +oncore_msg_Cj( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - const char *cp; - - if (instance->o_state == ONCORE_TEST_SENT) { - if (debug > 2) - printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]); - if (buf[4] || buf[5]) { - printf("ONCORE: SELF TEST FAILED\n"); - exit(1); - } + memcpy(instance->Cj, buf, len); - 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 = 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); } -/* - * preliminaries out of the way, this is the REAL start of initialization +/* The information on determing a Oncore 'Model', viz VP, UT, etc, from + * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> + * and from Motorola. Until recently Rick was the only source of + * this information as Motorola didnt give the information out. */ + static void -oncore_msg_Cj( +oncore_msg_Cj_id( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - char *cp, *cp1; + char *cp, *cp1, *cp2, Model[21], Msg[160]; int mode; - instance->timeout = 0; - if (instance->o_state != ONCORE_ID_SENT) - return; - - memcpy(instance->Cj, buf, len); - - /* Write Receiver ID to clockstats file */ + /* Write Receiver ID message to clockstats file */ instance->Cj[294] = '\0'; for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { @@ -1243,6 +1460,114 @@ oncore_msg_Cj( *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 (!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; + } + } 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; + } + + 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) + instance->traim = 0; + } + + sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan, + ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF"))); + record_clock_stats(&(instance->peer->srcadr), Msg); + + /* 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 + */ + +/*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); + } + + /* + * we now know model number and have zeroed + * instance->shmem_fname if SHMEM is not supported + */ + + if (instance->shmem_fname); + oncore_init_shmem(instance); + + if (instance->shmem) + cp = "SHMEM is available"; + else + cp = "SHMEM is NOT available"; + record_clock_stats(&(instance->peer->srcadr), cp); + #ifdef HAVE_PPSAPI if (instance->assert) cp = "Timing on Assert."; @@ -1251,72 +1576,180 @@ oncore_msg_Cj( record_clock_stats(&(instance->peer->srcadr), cp); #endif - 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 off */ - 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 */ + 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)); + + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->timeout = 4; + } +} + + + +static void +oncore_msg_Cj_init( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char *cp, Cmd[20], Msg[160]; + int mode; + + /* 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: INIT mode = %d\n", mode); + if (debug) { + printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode); + printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan); + } /* 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 Site Survey. + * 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; + } + } + + switch (mode) { case 0: /* NO initialization, don't change anything */ instance->site_survey = ONCORE_SS_DONE; break; case 1: - case 3: - w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); - w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); - w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); - oncore_cmd_As[14] = instance->ss_ht_type; - oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); - + case 3: /* Use given Position */ instance->site_survey = ONCORE_SS_DONE; - oncore_cmd_At[2] = 1; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); - record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); break; case 2: - case 4: - if (instance->posn_set) { - w32_buf(&oncore_cmd_Ad[2], (int) instance->ss_lat); - w32_buf(&oncore_cmd_Ae[2], (int) instance->ss_long); - w32_buf(&oncore_cmd_Af[2], (int) instance->ss_ht); - oncore_cmd_Af[6] = instance->ss_ht_type; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ad, sizeof oncore_cmd_Ad); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ae, sizeof oncore_cmd_Ae); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Af, sizeof oncore_cmd_Af); + 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)); } - instance->site_survey = ONCORE_SS_UNKNOWN; - oncore_cmd_At[2] = 2; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); break; } if (mode != 0) { /* cable delay in ns */ - w32_buf(&oncore_cmd_Az[2], instance->delay); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Az, sizeof oncore_cmd_Az); + 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 */ - w32_buf(&oncore_cmd_Ay[2], instance->offset); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ay, sizeof oncore_cmd_Ay); + 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; + } + } } - /* 8chan - Position/Status/Data Output Message, 1/s */ - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof oncore_cmd_Ea); - + /* 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"; record_clock_stats(&(instance->peer->srcadr), cp); @@ -1324,104 +1757,412 @@ oncore_msg_Cj( +/* + * 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) { + 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)); + + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } +} + + + +/* 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 + * 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 + * 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 + * after the @@Fa for all Oncores (and it was in this posn in the + * original code). + */ + +static void +oncore_msg_CaFaIa( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char *cp; + + if (instance->o_state == ONCORE_TEST_SENT) { + int antenna; + + instance->timeout = 0; + + if (debug > 2) { + if (buf[2] == 'I') + printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]); + else + printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]); + } + + antenna = buf[4] & 0xc0; + antenna >>= 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); + oncore_shutdown(instance->unit, instance->peer); + return; + } + if (antenna) { + char *cp1, Msg[160]; + + cp1 = (antenna == 0x1) ? "(Over Current)" : + ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)"); + + cp = "ONCORE: Self Test, NonFatal Antenna Problems "; + strcpy(Msg, cp); + strcat(Msg, cp1); + record_clock_stats(&(instance->peer->srcadr), Msg); + } + + 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); + } +} + + + +/* Ba, Ea and Ha come here */ + static void -oncore_msg_Ea( +oncore_msg_BaEaHa( struct instance *instance, u_char *buf, - u_int len + size_t len ) { const char *cp; - char Msg[160]; + char Msg[160], Cmd[20]; + u_char *vp; /* pointer to start of shared mem for Ba/Ea/Ha */ + size_t Len; + + /* 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->count) { + if (instance->count++ < 5) /* make sure results are stable, using position */ + return; + instance->count = 0; + } if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) return; - memcpy(instance->Ea, buf, len); + 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; + + 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; + } + + 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 + } + + /* 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.; + + if (MSL) { /* not set ! */ + sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH); + record_clock_stats(&(instance->peer->srcadr), Msg); + } - /* When we have an almanac, start the En messages */ + /* stuck in here as it only gets done once */ + + if (instance->chan != 12 && !instance->saw_At) { + cp = "Not Good, no @@At command, must be a GT/GT+"; + 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->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 */ + } + + if (instance->shmem) { + int i; + + 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); + } + } + + /* Almanac mode, waiting for Almanac, cant do anything till we have it */ + /* When we have an almanac, start the En/Bn messages */ if (instance->o_state == ONCORE_ALMANAC) { - if ((instance->Ea[72] & 1)) { + if (instance->rsm.bad_almanac) { if (debug) printf("ONCORE: waiting for almanac\n"); return; - } else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof oncore_cmd_En); + } 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); } } - /* must be ONCORE_RUN if we are here */ - /* First check if Hardware SiteSurvey has Finished */ + /* + * 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); + } + } + + /* + * must be ONCORE_RUN if we are here. + */ + + 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. + */ if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) { - instance->site_survey = ONCORE_SS_DONE; record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); + instance->site_survey = ONCORE_SS_DONE; } - if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { /* will print to clockstat when all */ - instance->printed = 1; /* three messages respond */ - /* Read back Position Hold Params */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof oncore_cmd_Asx); + 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) model */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof oncore_cmd_Ayx); + /* Nb. This will fail silently for early UT (no plus) and M12 models */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); + /* Read back Cable Delay for Output */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof oncore_cmd_Azx); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); } - /* Check the leap second status once per day */ + /* + * Check the leap second status once per day. + */ + + if (instance->Bj_day != buf[5]) { /* do this 1/day */ + instance->Bj_day = buf[5]; + + 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)); + } + } /* - * 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 - * 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 are usually a single bit). + * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. */ - if ((buf[4] == 6) || (buf[4] == 12)) { - if (instance->Bj_day != buf[5]) { /* do this 1/day */ - instance->Bj_day = buf[5]; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof oncore_cmd_Bj); + 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)); + } } } - 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]; + + if (instance->traim == 0) /* NO traim, go get tick */ + oncore_get_timestamp(instance, instance->offset, instance->offset); 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. */ - /* We only take PDOP/3D fixes */ - - if (instance->Ea[37] & 1) + if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ return; - /* Not if poor geometry or less than 3 sats */ - - if (instance->Ea[72] & 0x52) - return; - - /* Only 3D fix */ - - if (!(instance->Ea[72] & 0x20)) + if (instance->mode != MODE_3D) /* Only 3D Fix */ return; 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 ellipse */ + instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipsoid */ instance->ss_count++; if (instance->ss_count != POS_HOLD_AVERAGE) @@ -1435,14 +2176,33 @@ oncore_msg_Ea( instance->ss_lat, instance->ss_long, instance->ss_ht); record_clock_stats(&(instance->peer->srcadr), Msg); - w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); - w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); - w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); - oncore_cmd_As[14] = 0; - oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); + /* set newly determined position as 3D Position hold position */ + + 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)); + + /* 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 */ + + 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)); + } - oncore_cmd_At[2] = 1; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); instance->site_survey = ONCORE_SS_DONE; } @@ -1450,21 +2210,60 @@ oncore_msg_Ea( static void -oncore_msg_En( +oncore_msg_BnEn( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - int j; + long dt1, dt2; + char *cp; + + if (instance->o_state != ONCORE_RUN) + return; + + if (instance->traim_delay) { /* flag that @@En/@@Bn returned */ + instance->traim = 1; + instance->traim_delay = 0; + cp = "ONCORE: Detected TRAIM, TRAIM = ON"; + record_clock_stats(&(instance->peer->srcadr), cp); + } + + 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); +} + + + +static void +oncore_get_timestamp( + struct instance *instance, + long dt1, /* tick offset THIS time step */ + long dt2 /* tick offset NEXT time step */ + ) +{ + int Rsm; + u_long i, j; l_fp ts, ts_tmp; double dmy; -#ifdef HAVE_TIMESPEC +#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 */ @@ -1481,19 +2280,12 @@ oncore_msg_En( #endif #endif /* ! HAVE_PPS_API */ - if (instance->o_state != ONCORE_RUN) + if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) return; - memcpy(instance->En, buf, len); - /* Don't do anything without an almanac to define the GPS->UTC delta */ - if (instance->Ea[72] & 1) - return; - - /* If Time RAIM doesn't like it, don't trust it */ - - if (instance->En[21]) + if (instance->rsm.bad_almanac) return; #ifdef HAVE_PPSAPI @@ -1509,24 +2301,40 @@ oncore_msg_En( if (instance->assert) { tsp = &pps_i.assert_timestamp; - if (debug > 2) - printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", - pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec); + 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_msg_En, error serial pps\n"); + 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) - printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", - pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec); + 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_msg_En, error serial pps\n"); + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); return; } instance->ev_serial = pps_i.clear_sequence; @@ -1561,11 +2369,16 @@ oncore_msg_En( 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_msg_En, error serial pps\n"); + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); return; } instance->ev_serial = ev.serial; @@ -1587,7 +2400,7 @@ oncore_msg_En( # endif #endif /* now have timestamp in ts */ - /* add in saw_tooth and offset */ + /* 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. */ @@ -1595,26 +2408,57 @@ oncore_msg_En( /* offset in ns, and is positive (late), we subtract */ /* to put the PPS time transition back where it belongs */ - j = instance->saw_tooth + instance->offset; - instance->saw_tooth = (s_char) buf[25]; /* update for next time */ #ifdef HAVE_PPSAPI - /* must hand this offset off to the Kernel to do the addition */ - /* so that the Kernel PLL sees the offset too */ + /* 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 = - -(instance->saw_tooth + instance->offset); - } else { - instance->pps_p.clear_offset.tv_nsec = - -(instance->saw_tooth + instance->offset); + 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; } - if (time_pps_setparams(instance->pps_h, &instance->pps_p)) + /* 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 do it */ + /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */ + /* offset for THIS second */ - dmy = -1.0e-9*j; + dmy = -1.0e-9*dt1; DTOLFP(dmy, &ts_tmp); L_ADD(&ts, &ts_tmp); #endif @@ -1625,28 +2469,55 @@ oncore_msg_En( instance->pp->msec = 0; 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 */ - sprintf(instance->pp->a_lastcode, - "%u.%09u %d %d %2d %2d %2d %2ld rstat %02x dop %d nsat %2d,%d raim %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, - - instance->Ea[72], instance->Ea[37], instance->Ea[38], instance->Ea[39], instance->En[21], - /*rstat dop nsat visible, nsat tracked, raim */ - instance->En[23]*256+instance->En[24], (s_char) buf[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] - ); + 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->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 i; - i = strlen(instance->pp->a_lastcode); - printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode); + int n; + n = strlen(instance->pp->a_lastcode); + printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode); } if (!refclock_process(instance->pp)) { @@ -1672,35 +2543,21 @@ oncore_msg_En( * 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, - u_int len + size_t len ) { - if (instance->site_survey != ONCORE_SS_UNKNOWN) - return; - - if (buf[4] == 2) { - record_clock_stats(&(instance->peer->srcadr), - "Initiating hardware 3D site survey"); - instance->site_survey = ONCORE_SS_HW; - } else { - char Msg[160]; - /* - * Probably a VP or an older UT which can't do site-survey. - * 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); - instance->site_survey = ONCORE_SS_SW; - - oncore_cmd_At[2] = 0; - instance->ss_lat = instance->ss_long = instance->ss_ht = 0; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); + 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; + } } } @@ -1720,7 +2577,7 @@ static void oncore_msg_Bj( struct instance *instance, u_char *buf, - u_int len + size_t len ) { const char *cp; @@ -1743,41 +2600,97 @@ oncore_msg_Bj( record_clock_stats(&(instance->peer->srcadr), cp); } +/* Leap Second for M12, gives all info from satellite message */ + +static void +oncore_msg_Gj( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + 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 */ + + dt = buf[5] - buf[4]; + +#if 1 + sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", + instance->unit, + buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10], + (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))), + buf[15], buf[16], buf[17]); + record_clock_stats(&(instance->peer->srcadr), Msg); +#endif + if (dt) { + sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d", + instance->unit, + dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7], + buf[15], buf[16], buf[17]); + record_clock_stats(&(instance->peer->srcadr), Msg); + } + + /* Only raise warning within a month of the leap second */ + + instance->peer->leap = LEAP_NOWARNING; + cp = "Set peer.leap to LEAP_NOWARNING"; + + 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"; + } + } + } + record_clock_stats(&(instance->peer->srcadr), cp); +} + /* * get Position hold position */ + static void oncore_msg_As( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - char Msg[120], ew, ns; - const char *Ht; - double xd, xm, xs, yd, ym, ys, hm, hft; - int idx, idy, is, imx, imy; - long lat, lon, ht; - if (!instance->printed || instance->As) return; instance->As = 1; - lat = buf_w32(&buf[4]); - instance->ss_lat = lat; + instance->ss_lat = buf_w32(&buf[4]); + instance->ss_long = buf_w32(&buf[8]); + instance->ss_ht = buf_w32(&buf[12]); - lon = buf_w32(&buf[8]); - instance->ss_long = lon; + /* Print out Position */ + oncore_print_As(instance); +} - ht = buf_w32(&buf[12]); - instance->ss_ht = ht; - instance->ss_ht_type = buf[16]; - /* Print out Position */ +static void +oncore_print_As( + struct instance *instance + ) +{ + char Msg[120], ew, ns; + double xd, xm, xs, yd, ym, ys, hm, hft; + int idx, idy, is, imx, imy; + long lat, lon; record_clock_stats(&(instance->peer->srcadr), "Posn:"); ew = 'E'; @@ -1796,11 +2709,10 @@ oncore_msg_As( hm = instance->ss_ht/100.; hft= hm/0.3048; - Ht = instance->ss_ht_type ? "MSL" : "GPS"; xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ yd = lon/3600000.; - sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) %s", ns, xd, ew, yd, hm, hft, Ht); + sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft); record_clock_stats(&(instance->peer->srcadr), Msg); idx = xd; @@ -1809,7 +2721,7 @@ oncore_msg_As( imy = lon%3600000; xm = imx/60000.; ym = imy/60000.; - sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %5.2fm (%5.2fft) %s", ns, idx, xm, ew, idy, ym, hm, hft, Ht); + sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft); record_clock_stats(&(instance->peer->srcadr), Msg); imx = xm; @@ -1818,7 +2730,7 @@ oncore_msg_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 = %5.2fm (%5.2fft) %s", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft, Ht); + 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); } @@ -1828,11 +2740,12 @@ oncore_msg_As( * 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, - u_int len + size_t len ) { char Msg[120]; @@ -1853,11 +2766,12 @@ oncore_msg_Ay( /* * get Cable Delay */ + static void oncore_msg_Az( struct instance *instance, u_char *buf, - u_int len + size_t len ) { char Msg[120]; @@ -1872,6 +2786,23 @@ oncore_msg_Az( sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); record_clock_stats(&(instance->peer->srcadr), Msg); } + +static void +oncore_msg_Sz( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + const char *cp; + + cp = "Oncore: System Failure at Power On"; + if (instance && instance->peer) { + record_clock_stats(&(instance->peer->srcadr), cp); + oncore_shutdown(instance->unit, instance->peer); + } +} + #else int refclock_oncore_bs; #endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_palisade.c b/contrib/ntp/ntpd/refclock_palisade.c index bedf6e8..d8ce411 100644 --- a/contrib/ntp/ntpd/refclock_palisade.c +++ b/contrib/ntp/ntpd/refclock_palisade.c @@ -2,7 +2,7 @@ * This software was developed by the Software and Component Technologies * group of Trimble Navigation, Ltd. * - * Copyright (c) 1997, 1998, 1999 Trimble Navigation Ltd. + * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/contrib/ntp/ntpd/refclock_palisade.h b/contrib/ntp/ntpd/refclock_palisade.h index b78d988..cc37716 100644 --- a/contrib/ntp/ntpd/refclock_palisade.h +++ b/contrib/ntp/ntpd/refclock_palisade.h @@ -2,7 +2,7 @@ * This software was developed by the Software and Component Technologies * group of Trimble Navigation, Ltd. * - * Copyright (c) 1997, 1998, 1999 Trimble Navigation Ltd. + * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,8 +91,8 @@ #define DESCRIPTION "Trimble Palisade GPS" /* Long name */ #define PRECISION (-20) /* precision assumed (about 1 us) */ #define REFID "GPS\0" /* reference ID */ -#define TRMB_MINPOLL 5 /* 16 seconds */ -#define TRMB_MAXPOLL 7 /* 64 seconds */ +#define TRMB_MINPOLL 4 /* 16 seconds */ +#define TRMB_MAXPOLL 5 /* 32 seconds */ /* * I/O Definitions diff --git a/contrib/ntp/ntpd/refclock_parse.c b/contrib/ntp/ntpd/refclock_parse.c index 95b93aa..cfb9904 100644 --- a/contrib/ntp/ntpd/refclock_parse.c +++ b/contrib/ntp/ntpd/refclock_parse.c @@ -767,8 +767,6 @@ static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE } #define COMPUTIME_SAMPLES 5 #define COMPUTIME_KEEP 3 -static poll_info_t we400a_pollinfo = { 60, "T", 1 }; - /* * Varitext Radio Clock Receiver */ @@ -1169,18 +1167,18 @@ static struct parse_clockinfo }, { /* mode 15 */ 0, /* operation flags (io modes) */ - poll_dpoll, /* active poll routine */ - poll_init, /* active poll init routine */ + NO_POLL, /* active poll routine */ + NO_INIT, /* active poll init routine */ NO_EVENT, /* special event handling (e.g. reset clock) */ NO_END, /* active poll end routine */ NO_MESSAGE, /* process a lower layer message */ - ((void *)(&we400a_pollinfo)), /* local data area for "poll" mechanism */ + NO_DATA, /* local data area for "poll" mechanism */ 0, /* rootdelay */ - 1.0 / 960, /* current offset by which the RS232 + 11.0 /* bits */ / 9600, /* current offset by which the RS232 time code is delayed from the actual time */ DCF_ID, /* ID code */ "WHARTON 400A Series clock", /* device name */ - "WHARTON 400A Series clock Output Format 5", /* fixed format */ + "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 */ @@ -1242,10 +1240,10 @@ static struct parse_clockinfo static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); -#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) +#define CLK_REALTYPE(x) ((int)(((x)->ttlmax) & 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)->ttl) & 0x80) +#define CLK_PPS(x) (((x)->ttlmax) & 0x80) /* * Other constant stuff @@ -5150,16 +5148,24 @@ rawdcf_init_1( struct parseunit *parse ) { + /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ /* * You can use the RS232 to supply the power for a DCF77 receiver. * Here a voltage between the DTR and the RTS line is used. Unfortunately * the name has changed from CIOCM_DTR to TIOCM_DTR recently. */ - + int sl232; + + if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) + { + msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); + return 0; + } + #ifdef TIOCM_DTR - int sl232 = TIOCM_DTR; /* turn on DTR for power supply */ + sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ #else - int sl232 = CIOCM_DTR; /* turn on DTR for power supply */ + sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ #endif if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) @@ -5189,16 +5195,24 @@ rawdcf_init_2( struct parseunit *parse ) { + /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ /* * You can use the RS232 to supply the power for a DCF77 receiver. * Here a voltage between the DTR and the RTS line is used. Unfortunately * the name has changed from CIOCM_DTR to TIOCM_DTR recently. */ - + int sl232; + + if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) + { + msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); + return 0; + } + #ifdef TIOCM_RTS - int sl232 = TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ + sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ #else - int sl232 = CIOCM_RTS; /* turn on DTR for power supply */ + sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ #endif if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) diff --git a/contrib/ntp/ntpd/refclock_pcf.c b/contrib/ntp/ntpd/refclock_pcf.c index c882404..ff2b28e 100644 --- a/contrib/ntp/ntpd/refclock_pcf.c +++ b/contrib/ntp/ntpd/refclock_pcf.c @@ -8,8 +8,6 @@ #if defined(REFCLOCK) && defined(CLOCK_PCF) -#include <time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" @@ -17,18 +15,20 @@ #include "ntp_stdlib.h" /* - * This driver supports the parallel port radio clocks sold by Conrad + * This driver supports the parallel port radio clock sold by Conrad * Electronic under order numbers 967602 and 642002. * * It requires that the local timezone be CET/CEST and that the pcfclock - * device driver be installed. A device driver for Linux 2.2 is available - * at http://home.pages.de/~voegele/pcf.html. + * device driver be installed. A device driver for Linux is available at + * http://home.pages.de/~voegele/pcf.html. Information about a FreeBSD + * driver is available at http://schumann.cx/pcfclock/. */ /* * Interface definitions */ -#define DEVICE "/dev/pcfclock%d" +#define DEVICE "/dev/pcfclocks/%d" +#define OLDDEVICE "/dev/pcfclock%d" #define PRECISION (-1) /* precision assumed (about 0.5 s) */ #define REFID "PCF" #define DESCRIPTION "Conrad parallel port radio clock" @@ -67,17 +67,22 @@ pcf_start( { struct refclockproc *pp; int fd; - char device[20]; + char device[128]; /* * Open device file for reading. */ (void)sprintf(device, DEVICE, unit); + fd = open(device, O_RDONLY); + if (fd == -1) { + (void)sprintf(device, OLDDEVICE, unit); + fd = open(device, O_RDONLY); + } #ifdef DEBUG if (debug) printf ("starting PCF with device %s\n",device); #endif - if ((fd = open(device, O_RDONLY)) == -1) { + if (fd == -1) { return (0); } @@ -92,6 +97,9 @@ pcf_start( */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; + /* one transmission takes 172.5 milliseconds since the radio clock + transmits 69 bits with a period of 2.5 milliseconds per bit */ + pp->fudgetime1 = 0.1725; memcpy((char *)&pp->refid, REFID, 4); return (1); @@ -142,7 +150,7 @@ pcf_poll( tm.tm_hour = buf[7] * 10 + buf[6]; tm.tm_min = buf[5] * 10 + buf[4]; tm.tm_sec = buf[3] * 10 + buf[2]; - tm.tm_isdst = -1; + tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1; /* * Y2K convert the 2-digit year @@ -204,7 +212,7 @@ pcf_poll( return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); - if (buf[1] & 1) + if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2)) pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; diff --git a/contrib/ntp/ntpd/refclock_pst.c b/contrib/ntp/ntpd/refclock_pst.c index 6af4382..b92a2e0 100644 --- a/contrib/ntp/ntpd/refclock_pst.c +++ b/contrib/ntp/ntpd/refclock_pst.c @@ -8,15 +8,14 @@ #if defined(REFCLOCK) && defined(CLOCK_PST) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports the PSTI 1010 and Traconex 1020 WWV/WWVH * Receivers. No specific claim of accuracy is made for these receiver, diff --git a/contrib/ntp/ntpd/refclock_shm.c b/contrib/ntp/ntpd/refclock_shm.c index a8094c8..3747ce0 100644 --- a/contrib/ntp/ntpd/refclock_shm.c +++ b/contrib/ntp/ntpd/refclock_shm.c @@ -13,12 +13,6 @@ #if defined(REFCLOCK) && defined(CLOCK_SHM) -#undef fileno -#include <ctype.h> -#undef fileno -#include <sys/time.h> -#undef fileno - #include "ntpd.h" #undef fileno #include "ntp_io.h" @@ -29,15 +23,16 @@ #undef fileno #include "ntp_stdlib.h" +#undef fileno +#include <ctype.h> +#undef fileno + #ifndef SYS_WINNT -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#include <assert.h> -#include <time.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> +# include <sys/ipc.h> +# include <sys/shm.h> +# include <assert.h> +# include <unistd.h> +# include <stdio.h> #endif /* @@ -94,35 +89,19 @@ struct shmTime { }; struct shmTime *getShmTime (int unit) { #ifndef SYS_WINNT - extern char *sys_errlist[ ]; - extern int sys_nerr; int shmid=0; assert (unit<10); /* MAXUNIT is 4, so should never happen */ shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|(unit<2?0700:0777)); if (shmid==-1) { /*error */ - char buf[20]; - char *pe=buf; - if (errno<sys_nerr) - pe=sys_errlist[errno]; - else { - sprintf (buf,"errno=%d",errno); - } - msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,pe); + msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno)); return 0; } else { /* no error */ struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); if ((int)(long)p==-1) { /* error */ - char buf[20]; - char *pe=buf; - if (errno<sys_nerr) - pe=sys_errlist[errno]; - else { - sprintf (buf,"errno=%d",errno); - } - msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,pe); + msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno)); return 0; } return p; @@ -285,6 +264,7 @@ shm_poll( up->valid=0; if (ok) { TVTOTS(&tvr,&pp->lastrec); + pp->lastrec.l_ui += JAN_1970; /* pp->lasttime = current_time; */ pp->polls++; t=gmtime (&tvt.tv_sec); diff --git a/contrib/ntp/ntpd/refclock_tpro.c b/contrib/ntp/ntpd/refclock_tpro.c index a29383a..159f817 100644 --- a/contrib/ntp/ntpd/refclock_tpro.c +++ b/contrib/ntp/ntpd/refclock_tpro.c @@ -8,10 +8,6 @@ #if defined(REFCLOCK) && defined(CLOCK_TPRO) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" @@ -19,6 +15,9 @@ #include "sys/tpro.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports the KSI/Odetecs TPRO-S IRIG-B reader and TPRO- * SAT GPS receiver for the Sun Microsystems SBus. It requires that the diff --git a/contrib/ntp/ntpd/refclock_trak.c b/contrib/ntp/ntpd/refclock_trak.c index e7833af..326a8e9 100644 --- a/contrib/ntp/ntpd/refclock_trak.c +++ b/contrib/ntp/ntpd/refclock_trak.c @@ -10,13 +10,7 @@ #include <config.h> #endif -#if defined(REFCLOCK) && defined(CLOCK_TRAK) - -#include <stdio.h> -#include <ctype.h> -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif +#if defined(REFCLOCK) && defined(CLOCK_TRAK) && defined(PPS) #include "ntpd.h" #include "ntp_io.h" @@ -24,6 +18,9 @@ #include "ntp_stdlib.h" #include "ntp_unixtime.h" +#include <stdio.h> +#include <ctype.h> + #ifdef HAVE_SYS_TERMIOS_H # include <sys/termios.h> #endif diff --git a/contrib/ntp/ntpd/refclock_true.c b/contrib/ntp/ntpd/refclock_true.c index b841f72..dcc362d 100644 --- a/contrib/ntp/ntpd/refclock_true.c +++ b/contrib/ntp/ntpd/refclock_true.c @@ -12,16 +12,15 @@ #if defined(REFCLOCK) && defined(CLOCK_TRUETIME) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* This should be an atom clock but those are very hard to build. * * The PCL720 from P C Labs has an Intel 8253 lookalike, as well as a bunch @@ -62,11 +61,12 @@ * * Quality codes indicate possible error of * 468-DC GOES Receiver: - * GPS-TM/TMD Receiver: - * ? +/- 500 milliseconds # +/- 50 milliseconds - * * +/- 5 milliseconds . +/- 1 millisecond - * space less than 1 millisecond - * OM-DC OMEGA Receiver: + * GPS-TM/TMD Receiver: (default quality codes for XL-DC) + * ? +/- 1 milliseconds # +/- 100 microseconds + * * +/- 10 microseconds . +/- 1 microsecond + * space less than 1 microsecond + * OM-DC OMEGA Receiver: (default quality codes for OMEGA) + * WARNING OMEGA navigation system is no longer existent * > >+- 5 seconds * ? >+/- 500 milliseconds # >+/- 50 milliseconds * * >+/- 5 milliseconds . >+/- 1 millisecond @@ -109,6 +109,7 @@ * flag4 - use the PCL-720 (BSD/OS only) */ + /* * Definitions */ @@ -211,11 +212,12 @@ true_debug(struct peer *peer, const char *fmt, ...) if (want_debugging != now_debugging) { if (want_debugging) { - char filename[20]; + char filename[40]; + int fd; - sprintf(filename, "/tmp/true%d.debug", up->unit); - up->debug = fopen(filename, "w"); - if (up->debug) { + snprintf(filename, sizeof(filename), "/tmp/true%d.debug", up->unit); + fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0600); + if (fd >= 0 && (up->debug = fdopen(fd, "r+"))) { #ifdef HAVE_SETVBUF static char buf[BUFSIZ]; setvbuf(up->debug, buf, _IOLBF, BUFSIZ); @@ -247,13 +249,13 @@ true_start( { register struct true_unit *up; struct refclockproc *pp; - char device[20]; + char device[40]; int fd; /* * Open serial port */ - (void)sprintf(device, DEVICE, unit); + (void)snprintf(device, sizeof(device), DEVICE, unit); if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) return (0); @@ -325,6 +327,10 @@ true_receive( char synced; int i; int lat, lon, off; /* GOES Satellite position */ + /* Use these variable to hold data until we decide its worth keeping */ + char rd_lastcode[BMAX]; + l_fp rd_tmp; + u_short rd_lencode; /* * Get the clock this applies to and pointers to the data. @@ -336,14 +342,17 @@ true_receive( /* * Read clock output. Automatically handles STREAMS, CLKLDISC. */ - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); + rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); + rd_lastcode[rd_lencode] = '\0'; /* * There is a case where <cr><lf> generates 2 timestamps. */ - if (pp->lencode == 0) - return; - pp->a_lastcode[pp->lencode] = '\0'; + if (rd_lencode == 0) + return; + pp->lencode = rd_lencode; + strcpy(pp->a_lastcode, rd_lastcode); + pp->lastrec = rd_tmp; true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode); up->pollcnt = 2; @@ -360,7 +369,8 @@ true_receive( /* * Clock misunderstood our last command? */ - if (pp->a_lastcode[0] == '?') { + if (pp->a_lastcode[0] == '?' || + strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) { true_doevent(peer, e_Huh); return; } @@ -428,13 +438,14 @@ true_receive( } /* - * Timecode: " TRUETIME Mk III" - * (from a TM/TMD clock during initialization.) + * Timecode: " TRUETIME Mk III" or " TRUETIME XL" + * (from a TM/TMD/XL clock during initialization.) */ - if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0) { + if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 || + strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) { true_doevent(peer, e_F18); NLOG(NLOG_CLOCKSTATUS) { - msyslog(LOG_INFO, "TM/TMD: %s", pp->a_lastcode); + msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode); } return; } @@ -467,9 +478,12 @@ true_receive( /* * Adjust the synchronize indicator according to timecode + * say were OK, and then say not if we really are not OK */ - if (synced != ' ' && synced != '.' && synced != '*') + if (synced == '>' || synced == '#' || synced == '?') pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; true_doevent(peer, e_TS); @@ -527,6 +541,11 @@ true_receive( refclock_report(peer, CEVNT_BADTIME); return; } + /* + * If clock is good we send a NOMINAL message so that + * any previous BAD messages are nullified + */ + refclock_report(peer, CEVNT_NOMINAL); refclock_receive(peer); /* diff --git a/contrib/ntp/ntpd/refclock_ulink.c b/contrib/ntp/ntpd/refclock_ulink.c index 347040d..5bf569a 100644 --- a/contrib/ntp/ntpd/refclock_ulink.c +++ b/contrib/ntp/ntpd/refclock_ulink.c @@ -1,12 +1,25 @@ /* - * refclock_ulink - clock driver for Ultralink Model 320 WWVB receivers - * By Dave Strout <dstrout@linuxfoundary.com> - * - * Latest version is always on www.linuxfoundary.com - * - * Based on the Spectracom driver + * refclock_ulink - clock driver for Ultralink WWVB receiver + * */ +/*********************************************************************** + * * + * Copyright (c) David L. Mills 1992-1998 * + * * + * Permission to use, copy, modify, and distribute this software and * + * its documentation for any purpose and without fee is hereby * + * granted, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission * + * notice appear in supporting documentation, and that the name * + * University of Delaware not be used in advertising or publicity * + * pertaining to distribution of the software without specific, * + * written prior permission. The University of Delaware makes no * + * representations about the suitability this software for any * + * purpose. It is provided "as is" without express or implied * + * warranty. * + **********************************************************************/ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -15,8 +28,6 @@ #include <stdio.h> #include <ctype.h> -#include <sys/time.h> -#include <time.h> #include "ntpd.h" #include "ntp_io.h" @@ -25,63 +36,66 @@ #include "ntp_stdlib.h" /* - * This driver supports the Ultralink Model 320 WWVB receiver. The Model 320 is - * an RS-232 powered unit which consists of two parts: a DB-25 shell that contains - * a microprocessor, and an approx 2"x4" plastic box that contains the antenna. - * The two are connected by a 6-wire RJ-25 cable of length up to 1000'. The - * microprocessor steals power from the RS-232 port, which means that the port must - * be kept open all of the time. The unit also has an internal clock for loss of signal - * periods. Claimed accuracy is 0.1 sec. - * - * The timecode format is: + * This driver supports ultralink Model 320,330,331,332 WWVB radios * - * <cr><lf>SQRYYYYDDD+HH:MM:SS.mmLT<cr> + * this driver was based on the refclock_wwvb.c driver + * in the ntp distribution. * - * where: + * Fudge Factors * - * S = 'S' -- sync'd in last hour, '0'-'9' - hours x 10 since last update, else '?' - * Q = Number of correlating time-frames, from 0 to 5 - * R = 'R' -- reception in progress, 'N' -- Noisy reception, ' ' -- standby mode - * YYYY = year from 1990 to 2089 - * DDD = current day from 1 to 366 - * + = '+' if current year is a leap year, else ' ' - * HH = UTC hour 0 to 23 - * MM = Minutes of current hour from 0 to 59 - * SS = Seconds of current minute from 0 to 59 - * mm = 10's milliseconds of the current second from 00 to 99 - * L = Leap second pending at end of month -- 'I' = inset, 'D'=delete - * T = DST <-> STD transition indicators + * fudge flag1 0 don't poll clock + * 1 send poll character * - * Note that this driver does not do anything with the L or T flags. + * revision history: + * 99/9/09 j.c.lang original edit's + * 99/9/11 j.c.lang changed timecode parse to + * match what the radio actually + * sends. + * 99/10/11 j.c.lang added support for continous + * time code mode (dipsw2) + * 99/11/26 j.c.lang added support for 320 decoder + * (taken from Dave Strout's + * Model 320 driver) + * 99/11/29 j.c.lang added fudge flag 1 to control + * clock polling + * 99/12/15 j.c.lang fixed 320 quality flag + * 01/02/21 s.l.smith fixed 33x quality flag + * added more debugging stuff + * updated 33x time code explanation * - * The M320 also has a 'U' command which returns UT1 correction information. It - * is not used in this driver. + * Questions, bugs, ideas send to: + * Joseph C. Lang + * tcnojl1@earthlink.net * - */ + * Dave Strout + * dstrout@linuxfoundry.com + * + * + * on the Ultralink model 33X decoder Dip switch 2 controls + * polled or continous timecode + * set fudge flag1 if using polled (needed for model 320) + * dont set fudge flag1 if dip switch 2 is set on model 33x decoder +*/ + /* * Interface definitions */ -#define DEVICE "/dev/ulink%d" /* device name and unit */ +#define DEVICE "/dev/wwvb%d" /* device name and unit */ #define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-13) /* precision assumed (about 100 us) */ -#define REFID "M320" /* reference ID */ +#define PRECISION (-10) /* precision assumed (about 10 ms) */ +#define REFID "WWVB" /* reference ID */ #define DESCRIPTION "Ultralink WWVB Receiver" /* WRU */ -#define LENWWVB0 28 /* format 0 timecode length */ -#define LENWWVB2 24 /* format 2 timecode length */ -#define LENWWVB3 29 /* format 3 timecode length */ - -#define MONLIN 15 /* number of monitoring lines */ +#define LEN33X 32 /* timecode length Model 325 & 33X */ +#define LEN320 24 /* timecode length Model 320 */ /* - * ULINK unit control structure + * unit control structure */ struct ulinkunit { u_char tcswitch; /* timecode switch */ l_fp laststamp; /* last receive timestamp */ - u_char lasthour; /* last hour (for monitor) */ - u_char linect; /* count ignored lines (for monitor */ }; /* @@ -91,7 +105,6 @@ static int ulink_start P((int, struct peer *)); static void ulink_shutdown P((int, struct peer *)); static void ulink_receive P((struct recvbuf *)); static void ulink_poll P((int, struct peer *)); -static int fd; /* We need to keep the serial port open to power the ULM320 */ /* * Transfer vector @@ -100,10 +113,10 @@ struct refclock refclock_ulink = { ulink_start, /* start up driver */ ulink_shutdown, /* shut down driver */ ulink_poll, /* transmit poll message */ - noentry, /* not used (old wwvb_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old wwvb_buginfo) */ - NOFLAGS /* not used */ + noentry, /* not used */ + noentry, /* not used */ + noentry, /* not used */ + NOFLAGS }; @@ -118,8 +131,9 @@ ulink_start( { register struct ulinkunit *up; struct refclockproc *pp; + int fd; char device[20]; - fprintf(stderr, "Starting Ulink driver\n"); + /* * Open serial port. Use CLK line discipline, if available. */ @@ -152,7 +166,6 @@ ulink_start( * Initialize miscellaneous variables */ peer->precision = PRECISION; - peer->flags |= FLAG_BURST; peer->burst = NSTAGE; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); @@ -176,7 +189,6 @@ ulink_shutdown( up = (struct ulinkunit *)pp->unitptr; io_closeclock(&pp->io); free(up); - close(fd); } @@ -193,11 +205,12 @@ ulink_receive( struct peer *peer; l_fp trtmp; /* arrival timestamp */ + int quality; /* quality indicator */ + int temp; /* int temp */ char syncchar; /* synchronization indicator */ - char qualchar; /* quality indicator */ - char modechar; /* Modes: 'R'=rx, 'N'=noise, ' '=standby */ char leapchar; /* leap indicator */ - int temp; /* int temp */ + char modechar; /* model 320 mode flag */ + char char_quality[2]; /* temp quality flag */ /* * Initialize pointers and read the timecode and timestamp @@ -209,13 +222,7 @@ ulink_receive( /* * Note we get a buffer and timestamp for both a <cr> and <lf>, - * but only the <cr> timestamp is retained. Note: in format 0 on - * a Netclock/2 or upgraded 8170 the start bit is delayed 100 - * +-50 us relative to the pps; however, on an unmodified 8170 - * the start bit can be delayed up to 10 ms. In format 2 the - * reading precision is only to the millisecond. Thus, unless - * you have a pps gadget and don't have to have the year, format - * 0 provides the lowest jitter. + * but only the <cr> timestamp is retained. */ if (temp == 0) { if (up->tcswitch == 0) { @@ -237,40 +244,217 @@ ulink_receive( /* * We get down to business, check the timecode format and decode - * its contents. This code uses the timecode length to determine - * whether format 0 or format 2. If the timecode has invalid - * length or is not in proper format, we declare bad format and - * exit. + * its contents. If the timecode has invalid length or is not in + * proper format, we declare bad format and exit. */ - syncchar = qualchar = leapchar = ' '; + syncchar = leapchar = modechar = ' '; pp->msec = 0; + + switch (pp->lencode ) { + case LEN33X: + /* + * Model 33X decoder: + * Timecode format from January 29, 2001 datasheet is: + * <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5 + * S WWVB decoder sync indicator. S for in-sync(?) + * or N for noisy signal. + * 9+ RF signal level in S-units, 0-9 followed by + * a space (0x20). The space turns to '+' if the + * level is over 9. + * D Data bit 0, 1, 2 (position mark), or + * 3 (unknown). + * space Space character (0x20) + * 00 Hours since last good WWVB frame sync. Will + * be 00-23 hrs, or '1d' to '7d'. Will be 'Lk' + * if currently in sync. + * space Space character (0x20) + * YYYY Current year, 1990-2089 + * + Leap year indicator. '+' if a leap year, + * a space (0x20) if not. + * DDD Day of year, 001 - 366. + * UTC Timezone (always 'UTC'). + * S Daylight savings indicator + * S - standard time (STD) in effect + * O - during STD to DST day 0000-2400 + * D - daylight savings time (DST) in effect + * I - during DST to STD day 0000-2400 + * space Space character (0x20) + * HH Hours 00-23 + * : This is the REAL in sync indicator (: = insync) + * MM Minutes 00-59 + * : : = in sync ? = NOT in sync + * SS Seconds 00-59 + * L Leap second flag. Changes from space (0x20) + * to '+' or '-' during month preceding leap + * second adjustment. + * +5 UT1 correction (sign + digit )) + */ + + if (sscanf(pp->a_lastcode, + "%*4c %2c %4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c", + char_quality, &pp->year, &pp->day, + &pp->hour, &syncchar, &pp->minute, &pp->second, + &leapchar) == 8) { + + if (char_quality[0] == 'L') { + quality = 0; + } else if (char_quality[0] == '0') { + quality = (char_quality[1] & 0x0f); + } else { + quality = 99; + } +/* +#ifdef DEBUG + if (debug) { + printf("ulink: char_quality %c %c\n", + char_quality[0], char_quality[1]); + printf("ulink: quality %d\n", quality); + printf("ulink: syncchar %x\n", syncchar); + printf("ulink: leapchar %x\n", leapchar); + } +#endif +*/ + + break; + } + + case LEN320: + /* + * Model 320 Decoder + * The timecode format is: + * + * <cr><lf>SQRYYYYDDD+HH:MM:SS.mmLT<cr> + * + * where: + * + * S = 'S' -- sync'd in last hour, + * '0'-'9' - hours x 10 since last update, + * '?' -- not in sync + * Q = Number of correlating time-frames, from 0 to 5 + * R = 'R' -- reception in progress, + * 'N' -- Noisy reception, + * ' ' -- standby mode + * YYYY = year from 1990 to 2089 + * DDD = current day from 1 to 366 + * + = '+' if current year is a leap year, else ' ' + * HH = UTC hour 0 to 23 + * MM = Minutes of current hour from 0 to 59 + * SS = Seconds of current minute from 0 to 59 + * mm = 10's milliseconds of the current second from 00 to 99 + * L = Leap second pending at end of month + * 'I' = insert, 'D'= delete + * T = DST <-> STD transition indicators + * + */ + if (sscanf(pp->a_lastcode, "%c%1d%c%4d%3d%*c%2d:%2d:%2d.%2d%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 */ + if (leapchar == 'I' ) leapchar = '+'; + if (leapchar == 'D' ) leapchar = '-'; + if (syncchar != '?' ) syncchar = ':'; + + break; + } + + default: + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* - * Timecode format SQRYYYYDDD+HH:MM:SS.mmLT + * Decode quality indicator + * For the 325 & 33x series, the lower the number the "better" + * the time is. I used the dispersion as the measure of time + * quality. The quality indicator in the 320 is the number of + * correlating time frames (the more the better) */ - sscanf(pp->a_lastcode, "%c%c%c%4d%3d%c%2d:%2d:%2d.%2d", - &syncchar, &qualchar, &modechar, &pp->year, &pp->day, - &leapchar,&pp->hour, &pp->minute, &pp->second,&pp->msec); - pp->msec *= 10; /* M320 returns 10's of msecs */ - qualchar = ' '; + /* + * The spec sheet for the 325 & 33x series states the clock will + * maintain +/-0.002 seconds accuracy when locked to WWVB. This + * is indicated by 'Lk' in the quality portion of the incoming + * string. When not in lock, a drift of +/-0.015 seconds should + * be allowed for. + * With the quality indicator decoding scheme above, the 'Lk' + * condition will produce a quality value of 0. If the quality + * indicator starts with '0' then the second character is the + * number of hours since we were last locked. If the first + * character is anything other than 'L' or '0' then we have been + * out of lock for more than 9 hours so we assume the worst and + * force a quality value that selects the 'default' maximum + * dispersion. The dispersion values below are what came with the + * driver. They're not unreasonable so they've not been changed. + */ + + if (pp->lencode == LEN33X) { + switch (quality) { + case 0 : + pp->disp=.002; + break; + case 1 : + pp->disp=.02; + break; + case 2 : + pp->disp=.04; + break; + case 3 : + pp->disp=.08; + break; + default: + pp->disp=MAXDISPERSE; + break; + } + } else { + switch (quality) { + case 5 : + pp->disp=.002; + break; + case 4 : + pp->disp=.02; + break; + case 3 : + pp->disp=.04; + break; + case 2 : + pp->disp=.08; + break; + case 1 : + pp->disp=.16; + break; + default: + pp->disp=MAXDISPERSE; + break; + } + + } /* - * Decode synchronization, quality and leap characters. If + * Decode synchronization, and leap characters. If * unsynchronized, set the leap bits accordingly and exit. * Otherwise, set the leap bits according to the leap character. - * Once synchronized, the dispersion depends only on the - * quality character. */ - pp->disp = .001; - pp->leap = LEAP_NOWARNING; + + if (syncchar != ':') + pp->leap = LEAP_NOTINSYNC; + else if (leapchar == '+') + pp->leap = LEAP_ADDSECOND; + else if (leapchar == '-') + pp->leap = LEAP_DELSECOND; + else + pp->leap = LEAP_NOWARNING; /* * Process the new sample in the median filter and determine the * timecode timestamp. */ - if (!refclock_process(pp)) + if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); + } + } @@ -283,35 +467,30 @@ ulink_poll( struct peer *peer ) { - register struct ulinkunit *up; - struct refclockproc *pp; - char pollchar; - - pp = peer->procptr; - up = (struct ulinkunit *)pp->unitptr; - 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; + struct refclockproc *pp; + char pollchar; + + pp = peer->procptr; + pollchar = 'T'; + if (pp->sloppyclockflag & CLK_FLAG1) { + if (write(pp->io.fd, &pollchar, 1) != 1) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; } - record_clock_stats(&peer->srcadr, pp->a_lastcode); - refclock_receive(peer); - peer->burst = NSTAGE; + 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; - /* - * If the monitor flag is set (flag4), we dump the internal - * quality table at the first timecode beginning the day. - */ - if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour < - (int)up->lasthour) - up->linect = MONLIN; - up->lasthour = pp->hour; } #else diff --git a/contrib/ntp/ntpd/refclock_usno.c b/contrib/ntp/ntpd/refclock_usno.c index cf404e7..30a1330 100644 --- a/contrib/ntp/ntpd/refclock_usno.c +++ b/contrib/ntp/ntpd/refclock_usno.c @@ -9,13 +9,6 @@ #if defined(REFCLOCK) && defined(CLOCK_USNO) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif /* HAVE_SYS_IOCTL_H */ - #include "ntpd.h" #include "ntp_io.h" #include "ntp_unixtime.h" @@ -23,6 +16,12 @@ #include "ntp_stdlib.h" #include "ntp_control.h" +#include <stdio.h> +#include <ctype.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif /* HAVE_SYS_IOCTL_H */ + /* * This driver supports the Naval Observatory dialup at +1 202 653 0351. * It is a hacked-up version of the ACTS driver. @@ -438,7 +437,7 @@ usno_timeout( peer->nextdate = current_time + ANSWER; return; } - switch (peer->ttl) { + switch (peer->ttlmax) { /* * 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 52e76e6..b1d05c7 100644 --- a/contrib/ntp/ntpd/refclock_wwv.c +++ b/contrib/ntp/ntpd/refclock_wwv.c @@ -7,14 +7,6 @@ #if defined(REFCLOCK) && defined(CLOCK_WWV) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#include <math.h> -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif /* HAVE_SYS_IOCTL_H */ - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" @@ -22,6 +14,13 @@ #include "ntp_stdlib.h" #include "audio.h" +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif /* HAVE_SYS_IOCTL_H */ + #define ICOM 1 /* undefine to suppress ICOM code */ #ifdef ICOM @@ -64,6 +63,7 @@ /* * Interface definitions */ +#define DEVICE_AUDIO "/dev/audio" /* audio device name */ #define PRECISION (-10) /* precision assumed (about 1 ms) */ #define REFID "NONE" /* reference ID */ #define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */ @@ -646,7 +646,7 @@ wwv_start( /* * Open audio device */ - fd = audio_init(); + fd = audio_init(DEVICE_AUDIO); if (fd < 0) return (0); #ifdef DEBUG @@ -739,8 +739,8 @@ wwv_start( if (debug > 1) temp = P_TRACE; #endif - if (peer->ttl != 0) { - if (peer->ttl & 0x80) + if (peer->ttlmax != 0) { + if (peer->ttlmax & 0x80) up->fd_icom = icom_init("/dev/icom", B1200, temp); else @@ -1443,8 +1443,8 @@ wwv_qrz( sp->select &= ~JITRNG; if (abs(sp->jitter) > AWND * MS) sp->select |= JITRNG; - sp->sigmax = sqrt(sp->sigmax); - sp->noise = sqrt(sp->noise); + sp->sigmax = SQRT(sp->sigmax); + sp->noise = SQRT(sp->noise); if (up->status & MSYNC) { /* @@ -1769,9 +1769,9 @@ wwv_epoch( cp = &up->mitig[up->achan]; if (up->rphase == 800 * MS) { sp = &cp->wwv; - sp->synamp = sqrt(sp->amp); + sp->synamp = SQRT(sp->amp); sp = &cp->wwvh; - sp->synamp = sqrt(sp->amp); + sp->synamp = SQRT(sp->amp); } if (up->rsec == 0) { @@ -1787,7 +1787,7 @@ wwv_epoch( up->noiamp += (up->irig - up->noiamp) / (MINAVG << up->avgint); else - cp->noiamp += (sqrt(up->irig * + cp->noiamp += (SQRT(up->irig * up->irig + up->qrig * up->qrig) - cp->noiamp) / 8; @@ -1817,7 +1817,7 @@ wwv_epoch( up->datapt += 80; } } else { - up->sigamp = sqrt(up->irig * up->irig + + up->sigamp = SQRT(up->irig * up->irig + up->qrig * up->qrig); up->datsnr = wwv_snr(up->sigamp, cp->noiamp); @@ -2586,7 +2586,8 @@ wwv_newchan( up->sptr = sp; up->status |= sp->select & (SELV | SELH); memcpy((char *)&pp->refid, sp->refid, 4); - memcpy((char *)&peer->refid, sp->refid, 4); + if (peer->stratum <= 1) + memcpy((char *)&peer->refid, sp->refid, 4); wwv_qsy(peer, up->dchan); } } @@ -2614,7 +2615,7 @@ wwv_qsy( up->mitig[up->achan].gain = up->gain; #ifdef ICOM if (up->fd_icom > 0) - rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, + rval = icom_freq(up->fd_icom, peer->ttlmax & 0x7f, qsy[chan]); #endif /* ICOM */ up->achan = chan; @@ -2645,7 +2646,10 @@ wwv_qsy( * agc audio gain (0-255) * iden station identifier (station and frequency) * comp minute sync compare counter - * errs bit errors in last minute * freq frequency offset (PPM) * avgt averaging time (s) */ + * errs bit errors in last minute + * freq frequency offset (PPM) + * avgt averaging time (s) + */ static int timecode( struct wwvunit *up, /* driver structure pointer */ diff --git a/contrib/ntp/ntpd/refclock_wwvb.c b/contrib/ntp/ntpd/refclock_wwvb.c index 63d6e0b..0ca9f75 100644 --- a/contrib/ntp/ntpd/refclock_wwvb.c +++ b/contrib/ntp/ntpd/refclock_wwvb.c @@ -8,17 +8,15 @@ #if defined(REFCLOCK) && defined(CLOCK_SPECTRACOM) -#include <stdio.h> -#include <ctype.h> -#include <sys/time.h> -#include <time.h> - #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" +#include <stdio.h> +#include <ctype.h> + /* * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB * Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB @@ -187,9 +185,9 @@ wwvb_start( * Initialize miscellaneous variables */ peer->precision = PRECISION; - peer->burst = NSTAGE; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); + peer->burst = NSTAGE; return (1); } @@ -233,6 +231,7 @@ wwvb_receive( char qualchar; /* quality indicator */ char leapchar; /* leap indicator */ char dstchar; /* daylight/standard indicator */ + char tmpchar; /* trashbin */ /* * Initialize pointers and read the timecode and timestamp @@ -287,16 +286,15 @@ wwvb_receive( * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" */ if (sscanf(pp->a_lastcode, - "%c %3d %2d:%2d:%2d %cTZ=%2d", + "%c %3d %2d:%2d:%2d%c%cTZ=%2d", &syncchar, &pp->day, &pp->hour, &pp->minute, - &pp->second, &dstchar, &tz) == 7) + &pp->second, &tmpchar, &dstchar, &tz) == 8) break; case LENWWVB2: /* - * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" - */ + * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */ if (sscanf(pp->a_lastcode, "%c%c %2d %3d %2d:%2d:%2d.%3d %c", &syncchar, &qualchar, &pp->year, &pp->day, |