diff options
author | roberto <roberto@FreeBSD.org> | 2008-08-17 17:37:33 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 2008-08-17 17:37:33 +0000 |
commit | 4ded1c1fa0bc21c61f91a2dbe864835986745121 (patch) | |
tree | 16d100fbc9dae63888d48b464e471ba0e5065193 /contrib/ntp/ntpd | |
parent | 8b5a86d4fda08a9c68231415812edcb26be52f79 (diff) | |
download | FreeBSD-src-4ded1c1fa0bc21c61f91a2dbe864835986745121.zip FreeBSD-src-4ded1c1fa0bc21c61f91a2dbe864835986745121.tar.gz |
Flatten the dist and various 4.n.n trees in preparation of future ntp imports.
Diffstat (limited to 'contrib/ntp/ntpd')
67 files changed, 0 insertions, 70079 deletions
diff --git a/contrib/ntp/ntpd/Makefile.am b/contrib/ntp/ntpd/Makefile.am deleted file mode 100644 index 0fa4e21..0000000 --- a/contrib/ntp/ntpd/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies -AUTOMAKE_OPTIONS = ../util/ansi2knr -bin_PROGRAMS = ntpd @MAKE_NTPDSIM@ -noinst_LIBRARIES = libntpd.a -INCLUDES = -I$(top_srcdir)/include -I../include -# LDADD might need RESLIB and ADJLIB. -# If LIBPARSE, we need libntpd.a 2wagain afterwards... -LDADD = version.o libntpd.a @LIBPARSE@ libntpd.a -# ntpd may need: -# log10 refclock_wwv.o -# sqrt ntp_control.o -# floor refclock_wwv.o -# which are (usually) provided by -lm. -ntpd_LDADD = $(LDADD) ../libntp/libntp.a -lm @LCRYPTO@ -ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a -lm @LCRYPTO@ -ntpdsim_CFLAGS = $(CFLAGS) -DSIM -check_y2k_LDADD = $(LDADD) ../libntp/libntp.a -DISTCLEANFILES = .version version.c -#EXTRA_DIST = ntpd.mak -ETAGS_ARGS = Makefile.am -### Y2Kfixes -check_PROGRAMS = @MAKE_CHECK_Y2K@ -EXTRA_PROGRAMS = check_y2k ntpdsim - -check-local: @MAKE_CHECK_Y2K@ - test -z "@MAKE_CHECK_Y2K@" || ./@MAKE_CHECK_Y2K@ - -# SIM: cmd_args.c ntp_config.c ntp_io.c ntpd.c + ntpsim.c (include/ntpsim.h) -# ntp_resolver.c is presently unused... -ntpd_SOURCES = cmd_args.c ntp_config.c ntp_io.c ntpd.c -ntpdsim_SOURCES = $(ntpd_SOURCES) ntpsim.c -libntpd_a_SOURCES = jupiter.h map_vme.c ntp_control.c \ - ntp_crypto.c ntp_filegen.c \ - ntp_intres.c ntp_loopfilter.c ntp_monitor.c ntp_peer.c \ - ntp_proto.c ntp_refclock.c ntp_request.c \ - ntp_restrict.c ntp_timer.c ntp_util.c \ - refclock_acts.c refclock_arbiter.c refclock_arc.c refclock_as2201.c \ - refclock_atom.c refclock_bancomm.c refclock_chronolog.c \ - refclock_chu.c refclock_conf.c refclock_datum.c refclock_dumbclock.c \ - refclock_fg.c refclock_gpsvme.c refclock_heath.c refclock_hopfser.c \ - refclock_hopfpci.c refclock_hpgps.c refclock_irig.c refclock_jjy.c \ - refclock_jupiter.c refclock_leitch.c refclock_local.c \ - refclock_msfees.c refclock_mx4200.c refclock_nmea.c refclock_oncore.c \ - refclock_palisade.c refclock_palisade.h refclock_parse.c \ - refclock_pcf.c refclock_pst.c refclock_ptbacts.c refclock_shm.c \ - refclock_tpro.c refclock_trak.c refclock_true.c refclock_tt560.c \ - refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \ - refclock_zyfer.c refclock_ripencc.c refclock_neoclock4x.c - -$(PROGRAMS): $(LDADD) - -../libntp/libntp.a: - cd ../libntp && $(MAKE) - -../libparse/libparse.a: - cd ../libparse && $(MAKE) - -version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ Makefile $(top_srcdir)/version - env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpd - $(COMPILE) -c version.c diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in deleted file mode 100644 index eef0774..0000000 --- a/contrib/ntp/ntpd/Makefile.in +++ /dev/null @@ -1,960 +0,0 @@ -# Makefile.in generated by automake 1.7.7 from Makefile.am. -# @configure_input@ - -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 -# Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. - -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -target_triplet = @target@ -ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ -AMTAR = @AMTAR@ -ARLIB_DIR = @ARLIB_DIR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CHUTEST = @CHUTEST@ -CLKTEST = @CLKTEST@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DCFD = @DCFD@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EF_LIBS = @EF_LIBS@ -EF_PROGS = @EF_PROGS@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LCRYPTO = @LCRYPTO@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBPARSE = @LIBPARSE@ -LIBS = @LIBS@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MAKE_ADJTIMED = @MAKE_ADJTIMED@ -MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ -MAKE_LIBNTPSIM = @MAKE_LIBNTPSIM@ -MAKE_LIBPARSE = @MAKE_LIBPARSE@ -MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ -MAKE_NTPDSIM = @MAKE_NTPDSIM@ -MAKE_NTPTIME = @MAKE_NTPTIME@ -MAKE_NTP_KEYGEN = @MAKE_NTP_KEYGEN@ -MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ -MAKE_SNTP = @MAKE_SNTP@ -MAKE_TICKADJ = @MAKE_TICKADJ@ -MAKE_TIMETRIM = @MAKE_TIMETRIM@ -OBJEXT = @OBJEXT@ -OPENSSL = @OPENSSL@ -OPENSSL_INC = @OPENSSL_INC@ -OPENSSL_LIB = @OPENSSL_LIB@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_PERL = @PATH_PERL@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PATH_SH = @PATH_SH@ -PROPDELAY = @PROPDELAY@ -RANLIB = @RANLIB@ -READLINE_LIBS = @READLINE_LIBS@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -TESTDCF = @TESTDCF@ -U = @U@ -VERSION = @VERSION@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -datadir = @datadir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -oldincludedir = @oldincludedir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -subdirs = @subdirs@ -sysconfdir = @sysconfdir@ -target = @target@ -target_alias = @target_alias@ -target_cpu = @target_cpu@ -target_os = @target_os@ -target_vendor = @target_vendor@ - -#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies -AUTOMAKE_OPTIONS = ../util/ansi2knr -bin_PROGRAMS = ntpd @MAKE_NTPDSIM@ -noinst_LIBRARIES = libntpd.a -INCLUDES = -I$(top_srcdir)/include -I../include -# LDADD might need RESLIB and ADJLIB. -# If LIBPARSE, we need libntpd.a 2wagain afterwards... -LDADD = version.o libntpd.a @LIBPARSE@ libntpd.a -# ntpd may need: -# log10 refclock_wwv.o -# sqrt ntp_control.o -# floor refclock_wwv.o -# which are (usually) provided by -lm. -ntpd_LDADD = $(LDADD) ../libntp/libntp.a -lm @LCRYPTO@ -ntpdsim_LDADD = $(LDADD) ../libntp/libntpsim.a -lm @LCRYPTO@ -ntpdsim_CFLAGS = $(CFLAGS) -DSIM -check_y2k_LDADD = $(LDADD) ../libntp/libntp.a -DISTCLEANFILES = .version version.c -#EXTRA_DIST = ntpd.mak -ETAGS_ARGS = Makefile.am -### Y2Kfixes -check_PROGRAMS = @MAKE_CHECK_Y2K@ -EXTRA_PROGRAMS = check_y2k ntpdsim - -# SIM: cmd_args.c ntp_config.c ntp_io.c ntpd.c + ntpsim.c (include/ntpsim.h) -# ntp_resolver.c is presently unused... -ntpd_SOURCES = cmd_args.c ntp_config.c ntp_io.c ntpd.c -ntpdsim_SOURCES = $(ntpd_SOURCES) ntpsim.c -libntpd_a_SOURCES = jupiter.h map_vme.c ntp_control.c \ - ntp_crypto.c ntp_filegen.c \ - ntp_intres.c ntp_loopfilter.c ntp_monitor.c ntp_peer.c \ - ntp_proto.c ntp_refclock.c ntp_request.c \ - ntp_restrict.c ntp_timer.c ntp_util.c \ - refclock_acts.c refclock_arbiter.c refclock_arc.c refclock_as2201.c \ - refclock_atom.c refclock_bancomm.c refclock_chronolog.c \ - refclock_chu.c refclock_conf.c refclock_datum.c refclock_dumbclock.c \ - refclock_fg.c refclock_gpsvme.c refclock_heath.c refclock_hopfser.c \ - refclock_hopfpci.c refclock_hpgps.c refclock_irig.c refclock_jjy.c \ - refclock_jupiter.c refclock_leitch.c refclock_local.c \ - refclock_msfees.c refclock_mx4200.c refclock_nmea.c refclock_oncore.c \ - refclock_palisade.c refclock_palisade.h refclock_parse.c \ - refclock_pcf.c refclock_pst.c refclock_ptbacts.c refclock_shm.c \ - refclock_tpro.c refclock_trak.c refclock_true.c refclock_tt560.c \ - refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \ - refclock_zyfer.c refclock_ripencc.c refclock_neoclock4x.c - -subdir = ntpd -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -LIBRARIES = $(noinst_LIBRARIES) - -libntpd_a_AR = $(AR) cru -libntpd_a_LIBADD = -am_libntpd_a_OBJECTS = map_vme$U.$(OBJEXT) ntp_control$U.$(OBJEXT) \ - ntp_crypto$U.$(OBJEXT) ntp_filegen$U.$(OBJEXT) \ - ntp_intres$U.$(OBJEXT) ntp_loopfilter$U.$(OBJEXT) \ - ntp_monitor$U.$(OBJEXT) ntp_peer$U.$(OBJEXT) \ - ntp_proto$U.$(OBJEXT) ntp_refclock$U.$(OBJEXT) \ - ntp_request$U.$(OBJEXT) ntp_restrict$U.$(OBJEXT) \ - ntp_timer$U.$(OBJEXT) ntp_util$U.$(OBJEXT) \ - refclock_acts$U.$(OBJEXT) refclock_arbiter$U.$(OBJEXT) \ - refclock_arc$U.$(OBJEXT) refclock_as2201$U.$(OBJEXT) \ - refclock_atom$U.$(OBJEXT) refclock_bancomm$U.$(OBJEXT) \ - refclock_chronolog$U.$(OBJEXT) refclock_chu$U.$(OBJEXT) \ - refclock_conf$U.$(OBJEXT) refclock_datum$U.$(OBJEXT) \ - refclock_dumbclock$U.$(OBJEXT) refclock_fg$U.$(OBJEXT) \ - refclock_gpsvme$U.$(OBJEXT) refclock_heath$U.$(OBJEXT) \ - refclock_hopfser$U.$(OBJEXT) refclock_hopfpci$U.$(OBJEXT) \ - refclock_hpgps$U.$(OBJEXT) refclock_irig$U.$(OBJEXT) \ - refclock_jjy$U.$(OBJEXT) refclock_jupiter$U.$(OBJEXT) \ - refclock_leitch$U.$(OBJEXT) refclock_local$U.$(OBJEXT) \ - refclock_msfees$U.$(OBJEXT) refclock_mx4200$U.$(OBJEXT) \ - refclock_nmea$U.$(OBJEXT) refclock_oncore$U.$(OBJEXT) \ - refclock_palisade$U.$(OBJEXT) refclock_parse$U.$(OBJEXT) \ - refclock_pcf$U.$(OBJEXT) refclock_pst$U.$(OBJEXT) \ - refclock_ptbacts$U.$(OBJEXT) refclock_shm$U.$(OBJEXT) \ - refclock_tpro$U.$(OBJEXT) refclock_trak$U.$(OBJEXT) \ - refclock_true$U.$(OBJEXT) refclock_tt560$U.$(OBJEXT) \ - refclock_ulink$U.$(OBJEXT) refclock_usno$U.$(OBJEXT) \ - refclock_wwv$U.$(OBJEXT) refclock_wwvb$U.$(OBJEXT) \ - refclock_zyfer$U.$(OBJEXT) refclock_ripencc$U.$(OBJEXT) \ - refclock_neoclock4x$U.$(OBJEXT) -libntpd_a_OBJECTS = $(am_libntpd_a_OBJECTS) -EXTRA_PROGRAMS = check_y2k$(EXEEXT) ntpdsim$(EXEEXT) -bin_PROGRAMS = ntpd$(EXEEXT) @MAKE_NTPDSIM@ -check_PROGRAMS = @MAKE_CHECK_Y2K@ -PROGRAMS = $(bin_PROGRAMS) - -check_y2k_SOURCES = check_y2k.c -check_y2k_OBJECTS = check_y2k$U.$(OBJEXT) -check_y2k_DEPENDENCIES = version.o libntpd.a libntpd.a \ - ../libntp/libntp.a -check_y2k_LDFLAGS = -am_ntpd_OBJECTS = cmd_args$U.$(OBJEXT) ntp_config$U.$(OBJEXT) \ - ntp_io$U.$(OBJEXT) ntpd$U.$(OBJEXT) -ntpd_OBJECTS = $(am_ntpd_OBJECTS) -ntpd_DEPENDENCIES = version.o libntpd.a libntpd.a ../libntp/libntp.a -ntpd_LDFLAGS = -am__objects_1 = ntpdsim-cmd_args$U.$(OBJEXT) \ - ntpdsim-ntp_config$U.$(OBJEXT) ntpdsim-ntp_io$U.$(OBJEXT) \ - ntpdsim-ntpd$U.$(OBJEXT) -am_ntpdsim_OBJECTS = $(am__objects_1) ntpdsim-ntpsim$U.$(OBJEXT) -ntpdsim_OBJECTS = $(am_ntpdsim_OBJECTS) -ntpdsim_DEPENDENCIES = version.o libntpd.a libntpd.a \ - ../libntp/libntpsim.a -ntpdsim_LDFLAGS = - -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/check_y2k$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/cmd_args$U.Po ./$(DEPDIR)/map_vme$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_config$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_control$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_crypto$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_filegen$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_intres$U.Po ./$(DEPDIR)/ntp_io$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_loopfilter$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_monitor$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_peer$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_proto$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_refclock$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_request$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_restrict$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_timer$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntp_util$U.Po ./$(DEPDIR)/ntpd$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-cmd_args$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntp_config$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntp_io$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntpd$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntpdsim-ntpsim$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_acts$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_arbiter$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_arc$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_as2201$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_atom$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_bancomm$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_chronolog$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_chu$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_conf$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_datum$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_dumbclock$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_fg$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_gpsvme$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_heath$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_hopfpci$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_hopfser$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_hpgps$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_irig$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_jjy$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_jupiter$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_leitch$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_local$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_msfees$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_mx4200$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_neoclock4x$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_nmea$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_oncore$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_palisade$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_parse$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_pcf$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_pst$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_ptbacts$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_ripencc$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_shm$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_tpro$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_trak$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_true$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_tt560$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_ulink$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_usno$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_wwv$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_wwvb$U.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/refclock_zyfer$U.Po -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -DIST_SOURCES = $(libntpd_a_SOURCES) check_y2k.c $(ntpd_SOURCES) \ - $(ntpdsim_SOURCES) -DIST_COMMON = $(srcdir)/Makefile.in Makefile.am -SOURCES = $(libntpd_a_SOURCES) check_y2k.c $(ntpd_SOURCES) $(ntpdsim_SOURCES) - -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .o .obj -$(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) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) - -AR = ar - -clean-noinstLIBRARIES: - -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) -libntpd.a: $(libntpd_a_OBJECTS) $(libntpd_a_DEPENDENCIES) - -rm -f libntpd.a - $(libntpd_a_AR) libntpd.a $(libntpd_a_OBJECTS) $(libntpd_a_LIBADD) - $(RANLIB) libntpd.a -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(bindir) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ - $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ - rm -f $(DESTDIR)$(bindir)/$$f; \ - done - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -clean-checkPROGRAMS: - -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) -check_y2k$(EXEEXT): $(check_y2k_OBJECTS) $(check_y2k_DEPENDENCIES) - @rm -f check_y2k$(EXEEXT) - $(LINK) $(check_y2k_LDFLAGS) $(check_y2k_OBJECTS) $(check_y2k_LDADD) $(LIBS) -ntpd$(EXEEXT): $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES) - @rm -f ntpd$(EXEEXT) - $(LINK) $(ntpd_LDFLAGS) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS) -ntpdsim$(EXEEXT): $(ntpdsim_OBJECTS) $(ntpdsim_DEPENDENCIES) - @rm -f ntpdsim$(EXEEXT) - $(LINK) $(ntpdsim_LDFLAGS) $(ntpdsim_OBJECTS) $(ntpdsim_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) core *.core - -distclean-compile: - -rm -f *.tab.c - -ANSI2KNR = ../util/ansi2knr -../util/ansi2knr: - cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr - -mostlyclean-kr: - -test "$U" = "" || rm -f *_.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_y2k$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd_args$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map_vme$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_config$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_control$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_crypto$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_filegen$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_intres$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_io$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_loopfilter$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_monitor$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_peer$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_proto$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_refclock$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_request$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_restrict$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_timer$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp_util$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpd$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-cmd_args$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_config$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntp_io$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpd$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdsim-ntpsim$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_acts$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_arbiter$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_arc$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_as2201$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_atom$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_bancomm$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_chronolog$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_chu$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_conf$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_datum$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_dumbclock$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_fg$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_gpsvme$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_heath$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hopfpci$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hopfser$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_hpgps$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_irig$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_jjy$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_jupiter$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_leitch$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_local$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_msfees$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_mx4200$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_neoclock4x$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_nmea$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_oncore$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_palisade$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_parse$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_pcf$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_pst$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ptbacts$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ripencc$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_shm$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tpro$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_trak$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_true$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_tt560$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_ulink$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_usno$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_wwv$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_wwvb$U.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refclock_zyfer$U.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ -@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< - -.c.obj: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ -@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` - -ntpdsim-cmd_args$U.o: cmd_args$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-cmd_args$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-cmd_args$U.o `test -f 'cmd_args$U.c' || echo '$(srcdir)/'`cmd_args$U.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo" "$(DEPDIR)/ntpdsim-cmd_args$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmd_args$U.c' object='ntpdsim-cmd_args$U.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-cmd_args$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-cmd_args$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-cmd_args$U.o `test -f 'cmd_args$U.c' || echo '$(srcdir)/'`cmd_args$U.c - -ntpdsim-cmd_args$U.obj: cmd_args$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-cmd_args$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-cmd_args$U.obj `if test -f 'cmd_args$U.c'; then $(CYGPATH_W) 'cmd_args$U.c'; else $(CYGPATH_W) '$(srcdir)/cmd_args$U.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo" "$(DEPDIR)/ntpdsim-cmd_args$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-cmd_args$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmd_args$U.c' object='ntpdsim-cmd_args$U.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-cmd_args$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-cmd_args$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-cmd_args$U.obj `if test -f 'cmd_args$U.c'; then $(CYGPATH_W) 'cmd_args$U.c'; else $(CYGPATH_W) '$(srcdir)/cmd_args$U.c'; fi` - -ntpdsim-ntp_config$U.o: ntp_config$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_config$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntp_config$U.o `test -f 'ntp_config$U.c' || echo '$(srcdir)/'`ntp_config$U.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_config$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_config$U.c' object='ntpdsim-ntp_config$U.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_config$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_config$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_config$U.o `test -f 'ntp_config$U.c' || echo '$(srcdir)/'`ntp_config$U.c - -ntpdsim-ntp_config$U.obj: ntp_config$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_config$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntp_config$U.obj `if test -f 'ntp_config$U.c'; then $(CYGPATH_W) 'ntp_config$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_config$U.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_config$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_config$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_config$U.c' object='ntpdsim-ntp_config$U.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_config$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_config$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_config$U.obj `if test -f 'ntp_config$U.c'; then $(CYGPATH_W) 'ntp_config$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_config$U.c'; fi` - -ntpdsim-ntp_io$U.o: ntp_io$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_io$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntp_io$U.o `test -f 'ntp_io$U.c' || echo '$(srcdir)/'`ntp_io$U.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_io$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_io$U.c' object='ntpdsim-ntp_io$U.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_io$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_io$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_io$U.o `test -f 'ntp_io$U.c' || echo '$(srcdir)/'`ntp_io$U.c - -ntpdsim-ntp_io$U.obj: ntp_io$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntp_io$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntp_io$U.obj `if test -f 'ntp_io$U.c'; then $(CYGPATH_W) 'ntp_io$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_io$U.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo" "$(DEPDIR)/ntpdsim-ntp_io$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntp_io$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntp_io$U.c' object='ntpdsim-ntp_io$U.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntp_io$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntp_io$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntp_io$U.obj `if test -f 'ntp_io$U.c'; then $(CYGPATH_W) 'ntp_io$U.c'; else $(CYGPATH_W) '$(srcdir)/ntp_io$U.c'; fi` - -ntpdsim-ntpd$U.o: ntpd$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntpd$U.o `test -f 'ntpd$U.c' || echo '$(srcdir)/'`ntpd$U.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" "$(DEPDIR)/ntpdsim-ntpd$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd$U.c' object='ntpdsim-ntpd$U.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpd$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpd$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd$U.o `test -f 'ntpd$U.c' || echo '$(srcdir)/'`ntpd$U.c - -ntpdsim-ntpd$U.obj: ntpd$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpd$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntpd$U.obj `if test -f 'ntpd$U.c'; then $(CYGPATH_W) 'ntpd$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpd$U.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo" "$(DEPDIR)/ntpdsim-ntpd$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpd$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpd$U.c' object='ntpdsim-ntpd$U.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpd$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpd$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpd$U.obj `if test -f 'ntpd$U.c'; then $(CYGPATH_W) 'ntpd$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpd$U.c'; fi` - -ntpdsim-ntpsim$U.o: ntpsim$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim$U.o -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntpsim$U.o `test -f 'ntpsim$U.c' || echo '$(srcdir)/'`ntpsim$U.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" "$(DEPDIR)/ntpdsim-ntpsim$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpsim$U.c' object='ntpdsim-ntpsim$U.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpsim$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpsim$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpsim$U.o `test -f 'ntpsim$U.c' || echo '$(srcdir)/'`ntpsim$U.c - -ntpdsim-ntpsim$U.obj: ntpsim$U.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -MT ntpdsim-ntpsim$U.obj -MD -MP -MF "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" \ -@am__fastdepCC_TRUE@ -c -o ntpdsim-ntpsim$U.obj `if test -f 'ntpsim$U.c'; then $(CYGPATH_W) 'ntpsim$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpsim$U.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo" "$(DEPDIR)/ntpdsim-ntpsim$U.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/ntpdsim-ntpsim$U.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntpsim$U.c' object='ntpdsim-ntpsim$U.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ntpdsim-ntpsim$U.Po' tmpdepfile='$(DEPDIR)/ntpdsim-ntpsim$U.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntpdsim_CFLAGS) $(CFLAGS) -c -o ntpdsim-ntpsim$U.obj `if test -f 'ntpsim$U.c'; then $(CYGPATH_W) 'ntpsim$U.c'; else $(CYGPATH_W) '$(srcdir)/ntpsim$U.c'; fi` -check_y2k_.c: check_y2k.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/check_y2k.c; then echo $(srcdir)/check_y2k.c; else echo check_y2k.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -cmd_args_.c: cmd_args.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/cmd_args.c; then echo $(srcdir)/cmd_args.c; else echo cmd_args.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -map_vme_.c: map_vme.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/map_vme.c; then echo $(srcdir)/map_vme.c; else echo map_vme.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_config_.c: ntp_config.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_config.c; then echo $(srcdir)/ntp_config.c; else echo ntp_config.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_control_.c: ntp_control.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_control.c; then echo $(srcdir)/ntp_control.c; else echo ntp_control.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_crypto_.c: ntp_crypto.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_crypto.c; then echo $(srcdir)/ntp_crypto.c; else echo ntp_crypto.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_filegen_.c: ntp_filegen.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_filegen.c; then echo $(srcdir)/ntp_filegen.c; else echo ntp_filegen.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_intres_.c: ntp_intres.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_intres.c; then echo $(srcdir)/ntp_intres.c; else echo ntp_intres.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_io_.c: ntp_io.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_io.c; then echo $(srcdir)/ntp_io.c; else echo ntp_io.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_loopfilter_.c: ntp_loopfilter.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_loopfilter.c; then echo $(srcdir)/ntp_loopfilter.c; else echo ntp_loopfilter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_monitor_.c: ntp_monitor.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_monitor.c; then echo $(srcdir)/ntp_monitor.c; else echo ntp_monitor.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_peer_.c: ntp_peer.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_peer.c; then echo $(srcdir)/ntp_peer.c; else echo ntp_peer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_proto_.c: ntp_proto.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_proto.c; then echo $(srcdir)/ntp_proto.c; else echo ntp_proto.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_refclock_.c: ntp_refclock.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_refclock.c; then echo $(srcdir)/ntp_refclock.c; else echo ntp_refclock.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_request_.c: ntp_request.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_request.c; then echo $(srcdir)/ntp_request.c; else echo ntp_request.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_restrict_.c: ntp_restrict.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_restrict.c; then echo $(srcdir)/ntp_restrict.c; else echo ntp_restrict.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_timer_.c: ntp_timer.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_timer.c; then echo $(srcdir)/ntp_timer.c; else echo ntp_timer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntp_util_.c: ntp_util.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_util.c; then echo $(srcdir)/ntp_util.c; else echo ntp_util.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntpd_.c: ntpd.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpd.c; then echo $(srcdir)/ntpd.c; else echo ntpd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -ntpsim_.c: ntpsim.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpsim.c; then echo $(srcdir)/ntpsim.c; else echo ntpsim.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_acts_.c: refclock_acts.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_acts.c; then echo $(srcdir)/refclock_acts.c; else echo refclock_acts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_arbiter_.c: refclock_arbiter.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_arbiter.c; then echo $(srcdir)/refclock_arbiter.c; else echo refclock_arbiter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_arc_.c: refclock_arc.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_arc.c; then echo $(srcdir)/refclock_arc.c; else echo refclock_arc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_as2201_.c: refclock_as2201.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_as2201.c; then echo $(srcdir)/refclock_as2201.c; else echo refclock_as2201.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_atom_.c: refclock_atom.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_atom.c; then echo $(srcdir)/refclock_atom.c; else echo refclock_atom.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_bancomm_.c: refclock_bancomm.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_bancomm.c; then echo $(srcdir)/refclock_bancomm.c; else echo refclock_bancomm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_chronolog_.c: refclock_chronolog.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_chronolog.c; then echo $(srcdir)/refclock_chronolog.c; else echo refclock_chronolog.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_chu_.c: refclock_chu.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_chu.c; then echo $(srcdir)/refclock_chu.c; else echo refclock_chu.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_conf_.c: refclock_conf.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_conf.c; then echo $(srcdir)/refclock_conf.c; else echo refclock_conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_datum_.c: refclock_datum.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_datum.c; then echo $(srcdir)/refclock_datum.c; else echo refclock_datum.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_dumbclock_.c: refclock_dumbclock.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_dumbclock.c; then echo $(srcdir)/refclock_dumbclock.c; else echo refclock_dumbclock.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_fg_.c: refclock_fg.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_fg.c; then echo $(srcdir)/refclock_fg.c; else echo refclock_fg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_gpsvme_.c: refclock_gpsvme.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_gpsvme.c; then echo $(srcdir)/refclock_gpsvme.c; else echo refclock_gpsvme.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_heath_.c: refclock_heath.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_heath.c; then echo $(srcdir)/refclock_heath.c; else echo refclock_heath.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_hopfpci_.c: refclock_hopfpci.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hopfpci.c; then echo $(srcdir)/refclock_hopfpci.c; else echo refclock_hopfpci.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_hopfser_.c: refclock_hopfser.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hopfser.c; then echo $(srcdir)/refclock_hopfser.c; else echo refclock_hopfser.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_hpgps_.c: refclock_hpgps.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hpgps.c; then echo $(srcdir)/refclock_hpgps.c; else echo refclock_hpgps.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_irig_.c: refclock_irig.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_irig.c; then echo $(srcdir)/refclock_irig.c; else echo refclock_irig.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_jjy_.c: refclock_jjy.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_jjy.c; then echo $(srcdir)/refclock_jjy.c; else echo refclock_jjy.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_jupiter_.c: refclock_jupiter.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_jupiter.c; then echo $(srcdir)/refclock_jupiter.c; else echo refclock_jupiter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_leitch_.c: refclock_leitch.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_leitch.c; then echo $(srcdir)/refclock_leitch.c; else echo refclock_leitch.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_local_.c: refclock_local.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_local.c; then echo $(srcdir)/refclock_local.c; else echo refclock_local.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_msfees_.c: refclock_msfees.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_msfees.c; then echo $(srcdir)/refclock_msfees.c; else echo refclock_msfees.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_mx4200_.c: refclock_mx4200.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_mx4200.c; then echo $(srcdir)/refclock_mx4200.c; else echo refclock_mx4200.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_neoclock4x_.c: refclock_neoclock4x.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_neoclock4x.c; then echo $(srcdir)/refclock_neoclock4x.c; else echo refclock_neoclock4x.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_nmea_.c: refclock_nmea.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_nmea.c; then echo $(srcdir)/refclock_nmea.c; else echo refclock_nmea.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_oncore_.c: refclock_oncore.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_oncore.c; then echo $(srcdir)/refclock_oncore.c; else echo refclock_oncore.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_palisade_.c: refclock_palisade.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_palisade.c; then echo $(srcdir)/refclock_palisade.c; else echo refclock_palisade.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_parse_.c: refclock_parse.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_parse.c; then echo $(srcdir)/refclock_parse.c; else echo refclock_parse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_pcf_.c: refclock_pcf.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_pcf.c; then echo $(srcdir)/refclock_pcf.c; else echo refclock_pcf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_pst_.c: refclock_pst.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_pst.c; then echo $(srcdir)/refclock_pst.c; else echo refclock_pst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_ptbacts_.c: refclock_ptbacts.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ptbacts.c; then echo $(srcdir)/refclock_ptbacts.c; else echo refclock_ptbacts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_ripencc_.c: refclock_ripencc.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ripencc.c; then echo $(srcdir)/refclock_ripencc.c; else echo refclock_ripencc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_shm_.c: refclock_shm.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_shm.c; then echo $(srcdir)/refclock_shm.c; else echo refclock_shm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_tpro_.c: refclock_tpro.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_tpro.c; then echo $(srcdir)/refclock_tpro.c; else echo refclock_tpro.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_trak_.c: refclock_trak.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_trak.c; then echo $(srcdir)/refclock_trak.c; else echo refclock_trak.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_true_.c: refclock_true.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_true.c; then echo $(srcdir)/refclock_true.c; else echo refclock_true.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_tt560_.c: refclock_tt560.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_tt560.c; then echo $(srcdir)/refclock_tt560.c; else echo refclock_tt560.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_ulink_.c: refclock_ulink.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ulink.c; then echo $(srcdir)/refclock_ulink.c; else echo refclock_ulink.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_usno_.c: refclock_usno.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_usno.c; then echo $(srcdir)/refclock_usno.c; else echo refclock_usno.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_wwv_.c: refclock_wwv.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_wwv.c; then echo $(srcdir)/refclock_wwv.c; else echo refclock_wwv.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_wwvb_.c: refclock_wwvb.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_wwvb.c; then echo $(srcdir)/refclock_wwvb.c; else echo refclock_wwvb.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -refclock_zyfer_.c: refclock_zyfer.c $(ANSI2KNR) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_zyfer.c; then echo $(srcdir)/refclock_zyfer.c; else echo refclock_zyfer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ -check_y2k_.$(OBJEXT) cmd_args_.$(OBJEXT) map_vme_.$(OBJEXT) \ -ntp_config_.$(OBJEXT) ntp_control_.$(OBJEXT) ntp_crypto_.$(OBJEXT) \ -ntp_filegen_.$(OBJEXT) ntp_intres_.$(OBJEXT) ntp_io_.$(OBJEXT) \ -ntp_loopfilter_.$(OBJEXT) ntp_monitor_.$(OBJEXT) ntp_peer_.$(OBJEXT) \ -ntp_proto_.$(OBJEXT) ntp_refclock_.$(OBJEXT) ntp_request_.$(OBJEXT) \ -ntp_restrict_.$(OBJEXT) ntp_timer_.$(OBJEXT) ntp_util_.$(OBJEXT) \ -ntpd_.$(OBJEXT) ntpsim_.$(OBJEXT) refclock_acts_.$(OBJEXT) \ -refclock_arbiter_.$(OBJEXT) refclock_arc_.$(OBJEXT) \ -refclock_as2201_.$(OBJEXT) refclock_atom_.$(OBJEXT) \ -refclock_bancomm_.$(OBJEXT) refclock_chronolog_.$(OBJEXT) \ -refclock_chu_.$(OBJEXT) refclock_conf_.$(OBJEXT) \ -refclock_datum_.$(OBJEXT) refclock_dumbclock_.$(OBJEXT) \ -refclock_fg_.$(OBJEXT) refclock_gpsvme_.$(OBJEXT) \ -refclock_heath_.$(OBJEXT) refclock_hopfpci_.$(OBJEXT) \ -refclock_hopfser_.$(OBJEXT) refclock_hpgps_.$(OBJEXT) \ -refclock_irig_.$(OBJEXT) refclock_jjy_.$(OBJEXT) \ -refclock_jupiter_.$(OBJEXT) refclock_leitch_.$(OBJEXT) \ -refclock_local_.$(OBJEXT) refclock_msfees_.$(OBJEXT) \ -refclock_mx4200_.$(OBJEXT) refclock_neoclock4x_.$(OBJEXT) \ -refclock_nmea_.$(OBJEXT) refclock_oncore_.$(OBJEXT) \ -refclock_palisade_.$(OBJEXT) refclock_parse_.$(OBJEXT) \ -refclock_pcf_.$(OBJEXT) refclock_pst_.$(OBJEXT) \ -refclock_ptbacts_.$(OBJEXT) refclock_ripencc_.$(OBJEXT) \ -refclock_shm_.$(OBJEXT) refclock_tpro_.$(OBJEXT) \ -refclock_trak_.$(OBJEXT) refclock_true_.$(OBJEXT) \ -refclock_tt560_.$(OBJEXT) refclock_ulink_.$(OBJEXT) \ -refclock_usno_.$(OBJEXT) refclock_wwv_.$(OBJEXT) \ -refclock_wwvb_.$(OBJEXT) refclock_zyfer_.$(OBJEXT) : $(ANSI2KNR) -uninstall-info-am: - -ETAGS = etags -ETAGSFLAGS = - -CTAGS = ctags -CTAGSFLAGS = - -tags: TAGS - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique - -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) - -top_distdir = .. -distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkinstalldirs) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ - if test -d $$d/$$file; then \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-am -all-am: Makefile $(LIBRARIES) $(PROGRAMS) - -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 - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -rm -f $(CONFIG_CLEAN_FILES) - -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." -clean: clean-am - -clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ - clean-noinstLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile - -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -info: info-am - -info-am: - -install-data-am: - -install-exec-am: install-binPROGRAMS - -install-info: install-info-am - -install-man: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile - -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS uninstall-info-am - -.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \ - clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ - clean-noinstLIBRARIES ctags distclean distclean-compile \ - distclean-generic distclean-tags distdir dvi dvi-am info \ - info-am install install-am install-binPROGRAMS install-data \ - install-data-am install-exec install-exec-am install-info \ - install-info-am install-man install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-kr pdf pdf-am ps ps-am tags \ - uninstall uninstall-am uninstall-binPROGRAMS uninstall-info-am - - -check-local: @MAKE_CHECK_Y2K@ - test -z "@MAKE_CHECK_Y2K@" || ./@MAKE_CHECK_Y2K@ - -$(PROGRAMS): $(LDADD) - -../libntp/libntp.a: - cd ../libntp && $(MAKE) - -../libparse/libparse.a: - cd ../libparse && $(MAKE) - -version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ Makefile $(top_srcdir)/version - env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpd - $(COMPILE) -c version.c -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/contrib/ntp/ntpd/check_y2k.c b/contrib/ntp/ntpd/check_y2k.c deleted file mode 100644 index 6b83115..0000000 --- a/contrib/ntp/ntpd/check_y2k.c +++ /dev/null @@ -1,627 +0,0 @@ -/* check_y2k.c -- test ntp code constructs for Y2K correctness Y2KFixes [*/ - - /* - Code invoked by `make check`. Not part of ntpd and not to be - installed. - - On any code I even wonder about, I've cut and pasted the code - here and ran it as a test case just to be sure. - - For code not in "ntpd" proper, we have tried to call most - repaired functions from herein to properly test them - (something never done before!). This has found several bugs, - not normal Y2K bugs, that will strike in Y2K so repair them - we did. - - Program exits with 0 on success, 1 on Y2K failure (stdout messages). - Exit of 2 indicates internal logic bug detected OR failure of - what should be our correct formulas. - - While "make check" should only check logic for source within that - specific directory, this check goes outside the scope of the local - directory. It's not a perfect world (besides, there is a lot of - interdependence here, and it really needs to be tested in - a controled order). - */ - -/* { definitions lifted from ntpd.c to allow us to complie with - "#include ntp.h". I have not taken the time to reduce the clutter. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include "ntpd.h" - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#ifdef HAVE_SYS_STAT_H -# include <sys/stat.h> -#endif -#include <stdio.h> -#include <errno.h> -#ifndef SYS_WINNT -# if !defined(VMS) /*wjm*/ -# include <sys/param.h> -# endif /* VMS */ -# if HAVE_SYS_SIGNAL_H -# include <sys/signal.h> -# endif /* HAVE_SYS_SIGNAL_H */ -# include <sys/signal.h> -# ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -# endif /* HAVE_SYS_IOCTL_H */ -# if !defined(VMS) /*wjm*/ -# include <sys/resource.h> -# endif /* VMS */ -#else -# include <signal.h> -# include <process.h> -# include <io.h> -# include "../libntp/log.h" -#endif /* SYS_WINNT */ -#if defined(HAVE_RTPRIO) -# ifdef HAVE_SYS_RESOURCE_H -# include <sys/resource.h> -# endif -# ifdef HAVE_SYS_LOCK_H -# include <sys/lock.h> -# endif -# include <sys/rtprio.h> -#else -# ifdef HAVE_PLOCK -# ifdef HAVE_SYS_LOCK_H -# include <sys/lock.h> -# endif -# endif -#endif -#if defined(HAVE_SCHED_SETSCHEDULER) -# ifdef HAVE_SCHED_H -# include <sched.h> -# else -# ifdef HAVE_SYS_SCHED_H -# include <sys/sched.h> -# endif -# endif -#endif -#if defined(HAVE_SYS_MMAN_H) -# include <sys/mman.h> -#endif - -#ifdef HAVE_TERMIOS_H -# include <termios.h> -#endif - -#ifdef SYS_DOMAINOS -# include <apollo/base.h> -#endif /* SYS_DOMAINOS */ - -/* } end definitions lifted from ntpd.c */ - -#include "ntp_calendar.h" -#include "parse.h" - -#define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 ) - -volatile int debug = 0; /* debugging requests for parse stuff */ -char const *progname = "check_y2k"; - -long -Days ( int Year ) /* return number of days since year "0" */ -{ - long Return; - /* this is a known to be good algorithm */ - Return = Year * 365; /* first aproximation to the value */ - if ( Year >= 1 ) - { /* see notes in libparse/parse.c if you want a PROPER - * **generic algorithm. */ - Return += (Year+3) / 4; /* add in (too many) leap days */ - Return -= (Year-1) / 100; /* reduce by (too many) centurys */ - Return += (Year-1) / 400; /* get final answer */ - } - - return Return; -} - -static int year0 = 1900; /* sarting year for NTP time */ -static int yearend; /* ending year we test for NTP time. - * 32-bit systems: through 2036, the - **year in which NTP time overflows. - * 64-bit systems: a reasonable upper - **limit (well, maybe somewhat beyond - **reasonable, but well before the - **max time, by which time the earth - **will be dead.) */ -static time_t Time; -static struct tm LocalTime; - -#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \ - Warnings++; else Fatals++ - -int -main( void ) -{ - int Fatals; - int Warnings; - int year; - - Time = time( (time_t *)NULL ) -#ifdef TESTTIMEOFFSET - + test_time_offset -#endif - ; - LocalTime = *localtime( &Time ); - - year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */ - ? ( 400 * 3 ) /* three greater gregorian cycles */ - : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/ - /* NOTE: will automacially expand test years on - * 64 bit machines.... this may cause some of the - * existing ntp logic to fail for years beyond - * 2036 (the current 32-bit limit). If all checks - * fail ONLY beyond year 2036 you may ignore such - * errors, at least for a decade or so. */ - yearend = year0 + year; - - puts( " internal self check" ); - { /* verify our own logic used to verify repairs */ - unsigned long days; - - if ( year0 >= yearend ) - { - fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n", - (int)year0, (int)yearend, (int)year ); - exit(2); - } - - { - int save_year; - - save_year = LocalTime.tm_year; /* save current year */ - - year = 1980; - LocalTime.tm_year = year - 1900; - Fatals = Warnings = 0; - Error(year); /* should increment Fatals */ - if ( Fatals == 0 ) - { - fprintf( stdout, - "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n", - (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings ); - exit(2); - } - - year = 2100; /* test year > limit but CURRENT year < limit */ - Fatals = Warnings = 0; - Error(year); /* should increment Fatals */ - if ( Warnings == 0 ) - { - fprintf( stdout, - "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n", - (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings ); - exit(2); - } - Fatals = Warnings = 0; - LocalTime.tm_year = year - 1900; /* everything > limit */ - Error(1980); /* should increment Fatals */ - if ( Fatals == 0 ) - { - fprintf( stdout, - "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n", - (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings ); - exit(2); - } - - LocalTime.tm_year = save_year; - } - - days = 365+1; /* days in year 0 + 1 more day */ - for ( year = 1; year <= 2500; year++ ) - { - long Test; - Test = Days( year ); - if ( days != Test ) - { - fprintf( stdout, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n", - year, (long)days, (long)Test ); - exit(2); /* would throw off many other tests */ - } - - Test = julian0(year); /* compare with julian0() macro */ - if ( days != Test ) - { - fprintf( stdout, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n", - year, (long)days, (long)Test ); - exit(2); /* would throw off many other tests */ - } - - days += 365; - if ( isleap_4(year) ) days++; - } - - if ( isleap_4(1999) ) - { - fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" ); - exit(2); - } - if ( !isleap_4(2000) ) - { - fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" ); - exit(2); - } - if ( isleap_4(2001) ) - { - fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" ); - exit(2); - } - - if ( !isleap_tm(2000-1900) ) - { - fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" ); - exit(2); - } - } - - Fatals = Warnings = 0; - - puts( " include/ntp.h" ); - { /* test our new isleap_*() #define "functions" */ - - for ( year = 1400; year <= 2200; year++ ) - { - int LeapSw; - int IsLeapSw; - - LeapSw = GoodLeap(year); - IsLeapSw = isleap_4(year); - - if ( !!LeapSw != !!IsLeapSw ) - { - Error(year); - fprintf( stdout, - " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw ); - break; - } - - IsLeapSw = isleap_tm(year-1900); - - if ( !!LeapSw != !!IsLeapSw ) - { - Error(year); - fprintf( stdout, - " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw ); - break; - } - } - } - - puts( " include/ntp_calendar.h" ); - { /* I belive this is good, but just to be sure... */ - - /* we are testing this #define */ -#define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0))) - - for ( year = 1400; year <= 2200; year++ ) - { - int LeapSw; - - LeapSw = GoodLeap(year); - - if ( !(!LeapSw) != !(!is_leapyear(year)) ) - { - Error(year); - fprintf( stdout, - " %4d %2d *** ERROR\n", year, LeapSw ); - break; - } - } - } - - - puts( " libparse/parse.c" ); - { - long Days1970; /* days from 1900 to 1970 */ - - struct ParseTime /* womp up a test structure to all cut/paste code */ - { - int year; - } Clock_Time, *clock_time; - - clock_time = &Clock_Time; - - /* first test this #define */ -#define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366)) - - for ( year = 1400; year <= 2200; year++ ) - { - int LeapSw; - int DayCnt; - - LeapSw = GoodLeap(year); - DayCnt = (int)days_per_year(year); - - if ( ( LeapSw ? 366 : 365 ) != DayCnt ) - { - Error(year); - fprintf( stdout, - " days_per_year() %4d %2d %3d *** ERROR\n", - year, LeapSw, DayCnt ); - break; - } - } - - /* test (what is now julian0) calculations */ - - Days1970 = Days( 1970 ); /* get days since 1970 using a known good */ - - for ( year = 1970; year < yearend; year++ ) - { - unsigned long t; - long DaysYear ; - - clock_time->year = year; - - /* here is the code we are testing, cut and pasted out of the source */ -#if 0 /* old BUGGY code that has Y2K (and many other) failures */ - /* ghealton: this logic FAILED with great frequency when run - * over a period of time, including for year 2000. True, it - * had more successes than failures, but that's not really good - * enough for critical time distribution software. - * It is so awful I wonder if it has had a history of failure - * and fixes? */ - t = (clock_time->year - 1970) * 365; - t += (clock_time->year >> 2) - (1970 >> 2); - t -= clock_time->year / 100 - 1970 / 100; - t += clock_time->year / 400 - 1970 / 400; - - /* (immediate feare of rounding errors on integer - * **divisions proved well founded) */ - -#else - /* my replacement, based on Days() above */ - t = julian0(year) - julian0(1970); -#endif - - /* compare result in t against trusted calculations */ - DaysYear = Days( year ); /* get days to this year */ - if ( t != DaysYear - Days1970 ) - { - Error(year); - fprintf( stdout, - " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n", - year, (long)Days1970, - year, - (long)DaysYear, - (long)(DaysYear - Days1970), - (long)t ); - } - } - -#if 1 /* { */ - { - debug = 1; /* enable debugging */ - for ( year = 1970; year < yearend; year++ ) - { /* (limited by theory unix 2038 related bug lives by, but - * ends in yearend) */ - clocktime_t ct; - time_t Observed; - time_t Expected; - u_long Flag; - unsigned long t; - - ct.day = 1; - ct.month = 1; - ct.year = year; - ct.hour = ct.minute = ct.second = ct.usecond = 0; - ct.utcoffset = 0; - ct.utctime = 0; - ct.flags = 0; - - Flag = 0; - Observed = parse_to_unixtime( &ct, &Flag ); - if ( ct.year != year ) - { - fprintf( stdout, - "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n", - (int)year, (int)Flag, (int)ct.year ); - Error(year); - break; - } - t = julian0(year) - julian0(1970); /* Julian day from 1970 */ - Expected = t * 24 * 60 * 60; - if ( Observed != Expected || Flag ) - { /* time difference */ - fprintf( stdout, - "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", - year, (int)Flag, - (unsigned long)Observed, (unsigned long)Expected, - ((long)Observed - (long)Expected) ); - Error(year); - break; - } - - if ( year >= YEAR_PIVOT+1900 ) - { - /* check year % 100 code we put into parse_to_unixtime() */ - ct.utctime = 0; - ct.year = year % 100; - Flag = 0; - - Observed = parse_to_unixtime( &ct, &Flag ); - - if ( Observed != Expected || Flag ) - { /* time difference */ - fprintf( stdout, -"%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", - year, (int)ct.year, (int)Flag, - (unsigned long)Observed, (unsigned long)Expected, - ((long)Observed - (long)Expected) ); - Error(year); - break; - } - - /* check year - 1900 code we put into parse_to_unixtime() */ - ct.utctime = 0; - ct.year = year - 1900; - Flag = 0; - - Observed = parse_to_unixtime( &ct, &Flag ); - - if ( Observed != Expected || Flag ) - { /* time difference */ - fprintf( stdout, -"%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", - year, (int)ct.year, (int)Flag, - (unsigned long)Observed, (unsigned long)Expected, - ((long)Observed - (long)Expected) ); - Error(year); - break; - } - - - } - } -#endif /* } */ - } - } - - puts( " libntp/caljulian.c" ); - { /* test caljulian() */ - struct calendar ot; - u_long ntp_time; /* NTP time */ - - year = year0; /* calculate the basic year */ - printf( " starting year %04d\n", (int)year0 ); - printf( " ending year %04d\n", (int)yearend ); - - - ntp_time = julian0( year0 ); /* NTP starts in 1900-01-01 */ -#if DAY_NTP_STARTS == 693596 - ntp_time -= 365; /* BIAS required for successful test */ -#endif - if ( DAY_NTP_STARTS != ntp_time ) - { - Error(year); - fprintf( stdout, - "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n", - (int)year0, - (long)DAY_NTP_STARTS, (long)ntp_time, - (long)DAY_NTP_STARTS - (long)ntp_time ); - } - - for ( ; year < yearend; year++ ) - { - - /* 01-01 for the current year */ - ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */ - ntp_time *= 24 * 60 * 60; /* convert into seconds */ - caljulian( ntp_time, &ot ); /* convert January 1 */ - if ( ot.year != year - || ot.month != 1 - || ot.monthday != 1 ) - { - Error(year); - fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n", - (unsigned long)ntp_time, - year, - (int)ot.year, (int)ot.month, (int)ot.monthday ); - break; - } - - ntp_time += (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */ - caljulian( ntp_time, &ot ); /* convert Feb 28 */ - if ( ot.year != year - || ot.month != 2 - || ot.monthday != 28 ) - { - Error(year); - fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n", - (unsigned long)ntp_time, - year, - (int)ot.year, (int)ot.month, (int)ot.monthday ); - break; - } - - { - int m; /* expected month */ - int d; /* expected day */ - - m = isleap_4(year) ? 2 : 3; - d = isleap_4(year) ? 29 : 1; - - ntp_time += ( 24 * 60 * 60 ); /* advance to the next day */ - caljulian( ntp_time, &ot ); /* convert this day */ - if ( ot.year != year - || ot.month != m - || ot.monthday != d ) - { - Error(year); - fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n", - (unsigned long)ntp_time, - year, m, d, - (int)ot.year, (int)ot.month, (int)ot.monthday ); - break; - } - - } - } - } - - puts( " libntp/caltontp.c" ); - { /* test caltontp() */ - struct calendar ot; - u_long ntp_time; /* NTP time */ - - year = year0; /* calculate the basic year */ - printf( " starting year %04d\n", (int)year0 ); - printf( " ending year %04d\n", (int)yearend ); - - - for ( ; year < yearend; year++ ) - { - u_long ObservedNtp; - - /* 01-01 for the current year */ - ot.year = year; - ot.month = ot.monthday = 1; /* unused, but set anyway JIC */ - ot.yearday = 1; /* this is the magic value used by caltontp() */ - ot.hour = ot.minute = ot.second = 0; - - ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */ - ntp_time *= 24 * 60 * 60; /* convert into seconds */ - ObservedNtp = caltontp( &ot ); - if ( ntp_time != ObservedNtp ) - { - Error(year); - fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n", - (int)year, - (unsigned long)ntp_time, (unsigned long)ObservedNtp , - (long)ntp_time - (long)ObservedNtp ); - - break; - } - - /* now call caljulian as a type of failsafe supercheck */ - caljulian( ObservedNtp, &ot ); /* convert January 1 */ - if ( ot.year != year - || ot.month != 1 - || ot.monthday != 1 ) - { - Error(year); - fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n", - (unsigned long)ObservedNtp, - year, - (int)ot.year, (int)ot.month, (int)ot.monthday ); - break; - } - } - } - - if ( Warnings > 0 ) - fprintf( stdout, "%d WARNINGS\n", Warnings ); - if ( Fatals > 0 ) - fprintf( stdout, "%d FATAL ERRORS\n", Fatals ); - return Fatals ? 1 : 0; -} - /* Y2KFixes ] */ diff --git a/contrib/ntp/ntpd/cmd_args.c b/contrib/ntp/ntpd/cmd_args.c deleted file mode 100644 index 3ed9b66..0000000 --- a/contrib/ntp/ntpd/cmd_args.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * 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" - -#ifdef SIM -#include "ntpsim.h" -#endif /* SIM */ - -/* - * Definitions of things either imported from or exported to outside - */ -extern char const *progname; -int listen_to_virtual_ips = 1; - -#ifdef SYS_WINNT -extern BOOL NoWinService; -#endif - -static const char *ntp_options = "aAbB:c:C:dD:f:gi:k:l:LmnNO:p:P:qr:s:S:t:T:W:u:v:V:xY:Z:-:"; - -#ifdef HAVE_NETINFO -extern int check_netinfo; -#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\n"); - ++errflg; - break; -#endif - case 'L': - listen_to_virtual_ips = 0; - break; - case 'l': - { - FILE *new_file; - - if(strcmp(ntp_optarg, "stderr") == 0) - new_file = stderr; - else if(strcmp(ntp_optarg, "stdout") == 0) - new_file = stdout; - else - new_file = fopen(ntp_optarg, "a"); - if (new_file != NULL) { - NLOG(NLOG_SYSINFO) - msyslog(LOG_NOTICE, "logging to file %s", ntp_optarg); - 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; -#ifdef SYS_WINNT - NoWinService = TRUE; -#endif - break; - - case 'N': - priority_done = 0; - break; - - case '?': - ++errflg; - break; - - case '-': - if ( ! strcmp(ntp_optarg, "version") ) { - printf("%.80s: %.80s\n", progname, Version); - exit(0); - } else if ( ! strcmp(ntp_optarg, "help") ) { - /* usage(); */ - /* exit(0); */ - ++errflg; - } else if ( ! strcmp(ntp_optarg, "copyright") ) { - printf("unknown\n"); - exit(0); - } else { - fprintf(stderr, "%.80s: Error unknown argument '--%.80s'\n", - progname, - ntp_optarg); - exit(12); - } - break; - - default: - break; - } - - 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 -#ifdef HAVE_CLOCKCTL - (void) fprintf(stderr, "\t\t[ -u user[:group] ] [ -i chrootdir ]\n"); -#endif - exit(2); - } - ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */ - -#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; - struct sockaddr_in inaddrntp; - 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., NULL); - break; - - case 'A': - proto_config(PROTO_AUTHENTICATE, 0, 0., NULL); - break; - - case 'b': - proto_config(PROTO_BROADCLIENT, 1, 0., NULL); - 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 'i': -#ifdef HAVE_CLOCKCTL - if (!ntp_optarg) - errflg++; - else - chrootdir = ntp_optarg; - break; -#else - errflg++; -#endif - case 'k': - getauthkeys(ntp_optarg); - break; - - case 'L': /* already done at pre-scan */ - case 'l': /* already done at pre-scan */ - break; - - case 'm': - inaddrntp.sin_family = AF_INET; - inaddrntp.sin_port = htons(NTP_PORT); - inaddrntp.sin_addr.s_addr = htonl(INADDR_NTP); - proto_config(PROTO_MULTICAST_ADD, 0, 0., (struct sockaddr_storage*)&inaddrntp); - sys_bclient = 1; - break; - - 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, NULL); - } - } while (0); - break; - - case 'u': -#ifdef HAVE_CLOCKCTL - user = malloc(strlen(ntp_optarg) + 1); - if ((user == NULL) || (ntp_optarg == NULL)) - errflg++; - (void)strncpy(user, ntp_optarg, strlen(ntp_optarg) + 1); - group = rindex(user, ':'); - if (group) - *group++ = '\0'; /* get rid of the ':' */ -#else - errflg++; -#endif - break; - case 's': - stats_config(STATS_STATSDIR, ntp_optarg); - break; - - 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, - (u_short) (RW | ((c == 'V') ? DEF : 0))); - break; - - case 'x': - clock_max = 600; - break; -#ifdef SIM - case 'B': - sscanf(ntp_optarg, "%lf", &ntp_node.bdly); - break; - - case 'C': - sscanf(ntp_optarg, "%lf", &ntp_node.snse); - break; - - case 'H': - sscanf(ntp_optarg, "%lf", &ntp_node.slew); - break; - - case 'O': - sscanf(ntp_optarg, "%lf", &ntp_node.clk_time); - break; - - case 'S': - sscanf(ntp_optarg, "%lf", &ntp_node.sim_time); - break; - - case 'T': - sscanf(ntp_optarg, "%lf", &ntp_node.ferr); - break; - - case 'W': - sscanf(ntp_optarg, "%lf", &ntp_node.fnse); - break; - - case 'Y': - sscanf(ntp_optarg, "%lf", &ntp_node.ndly); - break; - - case 'Z': - sscanf(ntp_optarg, "%lf", &ntp_node.pdly); - break; - -#endif /* SIM */ - default: - errflg++; - break; - } - } - - 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 -#ifdef HAVE_CLOCKCTL - (void) fprintf(stderr, "\t\t[ -u user[:group] ] [ -i chrootdir ]\n"); -#endif - exit(2); - } - return; -} diff --git a/contrib/ntp/ntpd/jupiter.h b/contrib/ntp/ntpd/jupiter.h deleted file mode 100644 index ed80b0c..0000000 --- a/contrib/ntp/ntpd/jupiter.h +++ /dev/null @@ -1,255 +0,0 @@ -/* @(#) $Header$ (LBL) */ - -/* - * Rockwell Jupiter GPS receiver definitions - * - * This is all based on the "Zodiac GPS Receiver Family Designer's - * Guide" (dated 12/96) - */ - -#define JUPITER_SYNC 0x81ff /* sync word (book says 0xff81 !?!?) */ -#define JUPITER_ALL 0xffff /* disable all output messages */ - -/* Output messages (sent by the Jupiter board) */ -#define JUPITER_O_GPOS 1000 /* geodetic position status */ -#define JUPITER_O_EPOS 1001 /* ECEF position status */ -#define JUPITER_O_CHAN 1002 /* channel summary */ -#define JUPITER_O_VIS 1003 /* visible satellites */ -#define JUPITER_O_DGPS 1005 /* differential GPS status */ -#define JUPITER_O_MEAS 1007 /* channel measurement */ -#define JUPITER_O_ID 1011 /* receiver id */ -#define JUPITER_O_USER 1012 /* user-settings output */ -#define JUPITER_O_TEST 1100 /* built-in test results */ -#define JUPITER_O_MARK 1102 /* measurement time mark */ -#define JUPITER_O_PULSE 1108 /* UTC time mark pulse output */ -#define JUPITER_O_PORT 1130 /* serial port com parameters in use */ -#define JUPITER_O_EUP 1135 /* EEPROM update */ -#define JUPITER_O_ESTAT 1136 /* EEPROM status */ - -/* Input messages (sent to the Jupiter board) */ -#define JUPITER_I_PVTINIT 1200 /* geodetic position and velocity */ -#define JUPITER_I_USER 1210 /* user-defined datum */ -#define JUPITER_I_MAPSEL 1211 /* map datum select */ -#define JUPITER_I_ELEV 1212 /* satellite elevation mask control */ -#define JUPITER_I_CAND 1213 /* satellite candidate select */ -#define JUPITER_I_DGPS 1214 /* differential GPS control */ -#define JUPITER_I_COLD 1216 /* cold start control */ -#define JUPITER_I_VALID 1217 /* solution validity criteria */ -#define JUPITER_I_ALT 1219 /* user-entered altitude input */ -#define JUPITER_I_PLAT 1220 /* application platform control */ -#define JUPITER_I_NAV 1221 /* nav configuration */ -#define JUPITER_I_TEST 1300 /* preform built-in test command */ -#define JUPITER_I_RESTART 1303 /* restart command */ -#define JUPITER_I_PORT 1330 /* serial port com parameters */ -#define JUPITER_I_PROTO 1331 /* message protocol control */ -#define JUPITER_I_RDGPS 1351 /* raw DGPS RTCM SC-104 data */ - -struct jheader { - u_short sync; /* (JUPITER_SYNC) */ - u_short id; /* message id */ - u_short len; /* number of data short wordss (w/o cksum) */ - u_char reqid; /* JUPITER_REQID_MASK bits available as id */ - u_char flags; /* flags */ - u_short hsum; /* header cksum */ -}; - -#define JUPITER_REQID_MASK 0x3f /* bits available as id */ -#define JUPITER_FLAG_NAK 0x01 /* negative acknowledgement */ -#define JUPITER_FLAG_ACK 0x02 /* acknowledgement */ -#define JUPITER_FLAG_REQUEST 0x04 /* request ACK or NAK */ -#define JUPITER_FLAG_QUERY 0x08 /* request one shot output message */ -#define JUPITER_FLAG_LOG 0x20 /* request periodic output message */ -#define JUPITER_FLAG_CONN 0x40 /* enable periodic message */ -#define JUPITER_FLAG_DISC 0x80 /* disable periodic message */ - -#define JUPITER_H_FLAG_BITS \ - "\020\1NAK\2ACK\3REQUEST\4QUERY\5MBZ\6LOG\7CONN\10DISC" - -/* Log request messages (data payload when using JUPITER_FLAG_LOG) */ -struct jrequest { - u_short trigger; /* if 0, trigger on time trigger on - update (e.g. new almanac) */ - u_short interval; /* frequency in seconds */ - u_short offset; /* offset into minute */ - u_short dsum; /* checksum */ -}; - -/* JUPITER_O_GPOS (1000) */ -struct jgpos { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - u_short sseq; /* sat measurement sequence number */ - u_short navval; /* navigation soltuion validity */ - u_short navtype; /* navigation solution type */ - u_short nmeas; /* # of measurements used in solution */ - u_short polar; /* if 1 then polar navigation */ - u_short gweek; /* GPS week number */ - u_short sweek[2]; /* GPS seconds into week */ - u_short nsweek[2]; /* GPS nanoseconds into second */ - u_short utcday; /* 1 to 31 */ - u_short utcmon; /* 1 to 12 */ - u_short utcyear; /* 1980 to 2079 */ - u_short utchour; /* 0 to 23 */ - u_short utcmin; /* 0 to 59 */ - u_short utcsec; /* 0 to 59 */ - u_short utcnsec[2]; /* 0 to 999999999 */ - u_short lat[2]; /* latitude (radians) */ - u_short lon[2]; /* longitude (radians) */ - u_short height[2]; /* height (meters) */ - u_short gsep; /* geoidal separation */ - u_short speed[2]; /* ground speed (meters/sec) */ - u_short course; /* true course (radians) */ - u_short mvar; - u_short climb; - u_short mapd; - u_short herr[2]; - u_short verr[2]; - u_short terr[2]; - u_short hverr; - u_short bias[2]; - u_short biassd[2]; - u_short drift[2]; - u_short driftsd[2]; - u_short dsum; /* checksum */ -}; -#define JUPITER_O_GPOS_NAV_NOALT 0x01 /* altitude used */ -#define JUPITER_O_GPOS_NAV_NODGPS 0x02 /* no differential GPS */ -#define JUPITER_O_GPOS_NAV_NOSAT 0x04 /* not enough satellites */ -#define JUPITER_O_GPOS_NAV_MAXH 0x08 /* exceeded max EHPE */ -#define JUPITER_O_GPOS_NAV_MAXV 0x10 /* exceeded max EVPE */ - -/* JUPITER_O_CHAN (1002) */ -struct jchan { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - u_short sseq; /* sat measurement sequence number */ - u_short gweek; /* GPS week number */ - u_short sweek[2]; /* GPS seconds into week */ - u_short gpsns[2]; /* GPS nanoseconds from epoch */ - struct jchan2 { - u_short flags; /* flags */ - u_short prn; /* satellite PRN */ - u_short chan; /* channel number */ - } sat[12]; - u_short dsum; -}; - -/* JUPITER_O_VIS (1003) */ -struct jvis { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - u_short gdop; /* best possible GDOP */ - u_short pdop; /* best possible PDOP */ - u_short hdop; /* best possible HDOP */ - u_short vdop; /* best possible VDOP */ - u_short tdop; /* best possible TDOP */ - u_short nvis; /* number of visible satellites */ - struct jvis2 { - u_short prn; /* satellite PRN */ - u_short azi; /* satellite azimuth (radians) */ - u_short elev; /* satellite elevation (radians) */ - } sat[12]; - u_short dsum; /* checksum */ -}; - -/* JUPITER_O_ID (1011) */ -struct jid { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - char chans[20]; /* number of channels (ascii) */ - char vers[20]; /* software version (ascii) */ - char date[20]; /* software date (ascii) */ - char opts[20]; /* software options (ascii) */ - char reserved[20]; - u_short dsum; /* checksum */ -}; - -/* JUPITER_O_USER (1012) */ -struct juser { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - u_short status; /* operatinoal status */ - u_short coldtmo; /* cold start time-out */ - u_short dgpstmo; /* DGPS correction time-out*/ - u_short emask; /* elevation mask */ - u_short selcand[2]; /* selected candidate */ - u_short solflags; /* solution validity criteria */ - u_short nsat; /* number of satellites in track */ - u_short herr[2]; /* minimum expected horizontal error */ - u_short verr[2]; /* minimum expected vertical error */ - u_short platform; /* application platform */ - u_short dsum; /* checksum */ -}; - -/* JUPITER_O_PULSE (1108) */ -struct jpulse { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - u_short reserved[5]; - u_short sweek[2]; /* GPS seconds into week */ - short offs; /* GPS to UTC time offset (seconds) */ - u_short offns[2]; /* GPS to UTC offset (nanoseconds) */ - u_short flags; /* flags */ - u_short dsum; /* checksum */ -}; -#define JUPITER_O_PULSE_VALID 0x1 /* time mark validity */ -#define JUPITER_O_PULSE_UTC 0x2 /* GPS/UTC sync */ - -/* JUPITER_O_EUP (1135) */ -struct jeup { - u_short stime[2]; /* set time (10 ms ticks) */ - u_short seq; /* sequence number */ - u_char dataid; /* data id */ - u_char prn; /* satellite PRN */ - u_short dsum; /* checksum */ -}; - -/* JUPITER_I_RESTART (1303) */ -struct jrestart { - u_short seq; /* sequence number */ - u_short flags; - u_short dsum; /* checksum */ -}; -#define JUPITER_I_RESTART_INVRAM 0x01 -#define JUPITER_I_RESTART_INVEEPROM 0x02 -#define JUPITER_I_RESTART_INVRTC 0x04 -#define JUPITER_I_RESTART_COLD 0x80 - -/* JUPITER_I_PVTINIT (1200) */ -struct jpvtinit { - u_short flags; - u_short gweek; /* GPS week number */ - u_short sweek[2]; /* GPS seconds into week */ - u_short utcday; /* 1 to 31 */ - u_short utcmon; /* 1 to 12 */ - u_short utcyear; /* 1980 to 2079 */ - u_short utchour; /* 0 to 23 */ - u_short utcmin; /* 0 to 59 */ - u_short utcsec; /* 0 to 59 */ - u_short lat[2]; /* latitude (radians) */ - u_short lon[2]; /* longitude (radians) */ - u_short height[2]; /* height (meters) */ - u_short speed[2]; /* ground speed (meters/sec) */ - u_short course; /* true course (radians) */ - u_short climb; - u_short dsum; -}; -#define JUPITER_I_PVTINIT_FORCE 0x01 -#define JUPITER_I_PVTINIT_GPSVAL 0x02 -#define JUPITER_I_PVTINIT_UTCVAL 0x04 -#define JUPITER_I_PVTINIT_POSVAL 0x08 -#define JUPITER_I_PVTINIT_ALTVAL 0x10 -#define JUPITER_I_PVTINIT_SPDVAL 0x12 -#define JUPITER_I_PVTINIT_MAGVAL 0x14 -#define JUPITER_I_PVTINIT_CLIMBVAL 0x18 - -/* JUPITER_I_PLAT (1220) */ -struct jplat { - u_short seq; /* sequence number */ - u_short platform; /* application platform */ - u_short dsum; -}; -#define JUPITER_I_PLAT_DEFAULT 0 /* default dynamics */ -#define JUPITER_I_PLAT_LOW 2 /* pedestrian */ -#define JUPITER_I_PLAT_MED 5 /* land (e.g. automobile) */ -#define JUPITER_I_PLAT_HIGH 6 /* air */ diff --git a/contrib/ntp/ntpd/map_vme.c b/contrib/ntp/ntpd/map_vme.c deleted file mode 100644 index e4569ce..0000000 --- a/contrib/ntp/ntpd/map_vme.c +++ /dev/null @@ -1,135 +0,0 @@ -/********************************************************/ -/* map_vme.c */ -/* VME control of TrueTime VME-SG sync gen card */ -/* and TrueTime GPS-VME receiver card */ -/* Version for 700 series HPUX 9.0 */ -/* Richard E.Schmidt, US Naval Observatory, Washington */ -/* 27 March 94 */ -/********************************************************/ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_GPSVME) -#include <stdio.h> -#include <errno.h> -#include <time.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/file.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/sysmacros.h> -#include <sys/rtprio.h> /* for rtprio */ -#include <sys/lock.h> /* for plock */ -#include "/etc/conf/machine/vme2.h" -#include "/etc/conf/h/io.h" -#include "gps.h" - -/* GLOBALS */ -void *gps_base; -unsigned short *greg[NREGS]; -struct vme2_map_addr ma; /* memory mapped structure */ -int fd; /* file descriptor for VME */ - -void unmap_vme (); - -caddr_t -map_vme ( - char *filename - ) -{ - int ret; - caddr_t base; - struct vme2_io_testx tx; - caddr_t cp; - -#define VME_START_ADDR 0x00000 /* Starting address in A16N VME Space */ -#define VMESIZE 0xFF /* 256 bytes of A16N space length */ - - /* - To create the HP9000/700 series device file, /dev/vme2: - mknod /dev/vme2 c 44 0x0; chmod 600 /dev/vme2 - - Then must create /etc/vme.CFG and run /etc/vme_config and reboot. - */ - if ((fd = open (filename, O_RDWR)) < 0) { - printf("ERROR: VME bus adapter open failed. errno:%d\n", - errno); - if(errno == ENODEV) { - printf("ENODEV. Is driver in kernel? vme2 in dfile?\n"); - } - exit(errno); - } - tx.card_type = VME_A16; - tx.vme_addr = VME_START_ADDR; - tx.width = SHORT_WIDE; - - if(ioctl(fd, VME2_IO_TESTR, &tx)) { - printf("ioctl to test VME space failed. Errno: %d\n", - errno); - exit(errno); - } - if(tx.error) - printf("io_testr failed internal error %d\n",tx.error); - if(tx.access_result < 0) { - printf("io_testr failed\n"); - exit(2); - } - - /* If successful mmap the device */ - /* NOW MAP THE CARD */ - ma.card_type = VME_A16; - ma.vme_addr = VME_START_ADDR; - ma.size = VMESIZE; - - if(ioctl(fd, VME2_MAP_ADDR, &ma)) { - printf("ioctl to map VME space failed. Errno: %d\n", - errno); - exit(errno); - } - if(ma.error) { - printf("ioctl to map VME failed\n"); - exit(ENOMEM); - } - base = ma.user_addr; - return(base); -} - - -void -unmap_vme(void) -{ - if(ioctl(fd, VME2_UNMAP_ADDR, &ma)) - printf("ioctl to unmap VME space failed. Errno: %d\n", - errno); - close(fd); - return; -} - - -int -init_vme(boid) -{ - /* set up address offsets */ - - gps_base = map_vme (GPS_VME); - -/* offsets from base address: */ - - greg[0] = (unsigned short *)gps_base + GFRZ1; - greg[1] = (unsigned short *)gps_base + GUFRZ1; - greg[2] = (unsigned short *)gps_base + GREG1A; - greg[3] = (unsigned short *)gps_base + GREG1B; - greg[4] = (unsigned short *)gps_base + GREG1C; - greg[5] = (unsigned short *)gps_base + GREG1D; - greg[6] = (unsigned short *)gps_base + GREG1E; - - return (0); -} - -#else /* not (REFCLOCK && CLOCK_GPSVME) */ -int map_vme_bs; -#endif /* not (REFCLOCK && CLOCK_GPSVME) */ diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c deleted file mode 100644 index f1428b1..0000000 --- a/contrib/ntp/ntpd/ntp_config.c +++ /dev/null @@ -1,2371 +0,0 @@ -/* - * ntp_config.c - read and apply configuration information - */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#ifdef HAVE_NETINFO -# include <netinfo/ni.h> -#endif - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_refclock.h" -#include "ntp_filegen.h" -#include "ntp_stdlib.h" -#include "ntp_config.h" -#include "ntp_cmdargs.h" - -#include <stdio.h> -#include <ctype.h> -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#include <signal.h> -#ifndef SIGCHLD -# define SIGCHLD SIGCLD -#endif -#if !defined(VMS) -# ifdef HAVE_SYS_WAIT_H -# include <sys/wait.h> -# endif -#endif /* VMS */ - -#ifdef SYS_WINNT -# include <io.h> -extern HANDLE ResolverThreadHandle; -#endif /* SYS_WINNT */ - -#include <netdb.h> - -extern int priority_done; - -/* - * These routines are used to read the configuration file at - * startup time. An entry in the file must fit on a single line. - * Entries are processed as multiple tokens separated by white space - * Lines are considered terminated when a '#' is encountered. Blank - * lines are ignored. - */ -/* - * Translation table - keywords to function index - */ -struct keyword { - const char *text; - int keytype; -}; - -/* - * Command keywords - */ -static struct keyword keywords[] = { - { "automax", CONFIG_AUTOMAX }, - { "broadcast", CONFIG_BROADCAST }, - { "broadcastclient", CONFIG_BROADCASTCLIENT }, - { "broadcastdelay", CONFIG_BDELAY }, - { "calldelay", CONFIG_CDELAY}, -#ifdef OPENSSL - { "crypto", CONFIG_CRYPTO }, -#endif /* OPENSSL */ - { "controlkey", CONFIG_CONTROLKEY }, - { "disable", CONFIG_DISABLE }, - { "driftfile", CONFIG_DRIFTFILE }, - { "enable", CONFIG_ENABLE }, - { "filegen", CONFIG_FILEGEN }, - { "fudge", CONFIG_FUDGE }, - { "includefile", CONFIG_INCLUDEFILE }, - { "keys", CONFIG_KEYS }, - { "keysdir", CONFIG_KEYSDIR }, - { "logconfig", CONFIG_LOGCONFIG }, - { "logfile", CONFIG_LOGFILE }, - { "manycastclient", CONFIG_MANYCASTCLIENT }, - { "manycastserver", CONFIG_MANYCASTSERVER }, - { "multicastclient", CONFIG_MULTICASTCLIENT }, - { "peer", CONFIG_PEER }, - { "phone", CONFIG_PHONE }, - { "pidfile", CONFIG_PIDFILE }, - { "discard", CONFIG_DISCARD }, - { "requestkey", CONFIG_REQUESTKEY }, - { "restrict", CONFIG_RESTRICT }, - { "revoke", CONFIG_REVOKE }, - { "server", CONFIG_SERVER }, - { "setvar", CONFIG_SETVAR }, - { "statistics", CONFIG_STATISTICS }, - { "statsdir", CONFIG_STATSDIR }, - { "tick", CONFIG_ADJ }, - { "tinker", CONFIG_TINKER }, - { "tos", CONFIG_TOS }, - { "trap", CONFIG_TRAP }, - { "trustedkey", CONFIG_TRUSTEDKEY }, - { "ttl", CONFIG_TTL }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "peer", "server", "broadcast" modifier keywords - */ -static struct keyword mod_keywords[] = { - { "autokey", CONF_MOD_SKEY }, - { "burst", CONF_MOD_BURST }, - { "iburst", CONF_MOD_IBURST }, - { "key", CONF_MOD_KEY }, - { "maxpoll", CONF_MOD_MAXPOLL }, - { "minpoll", CONF_MOD_MINPOLL }, - { "mode", CONF_MOD_MODE }, /* refclocks */ - { "noselect", CONF_MOD_NOSELECT }, - { "prefer", CONF_MOD_PREFER }, - { "ttl", CONF_MOD_TTL }, /* NTP peers */ - { "version", CONF_MOD_VERSION }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "restrict" modifier keywords - */ -static struct keyword res_keywords[] = { - { "ignore", CONF_RES_IGNORE }, - { "limited", CONF_RES_LIMITED }, - { "kod", CONF_RES_DEMOBILIZE }, - { "lowpriotrap", CONF_RES_LPTRAP }, - { "mask", CONF_RES_MASK }, - { "nomodify", CONF_RES_NOMODIFY }, - { "nopeer", CONF_RES_NOPEER }, - { "noquery", CONF_RES_NOQUERY }, - { "noserve", CONF_RES_NOSERVE }, - { "notrap", CONF_RES_NOTRAP }, - { "notrust", CONF_RES_NOTRUST }, - { "ntpport", CONF_RES_NTPPORT }, - { "version", CONF_RES_VERSION }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "trap" modifier keywords - */ -static struct keyword trap_keywords[] = { - { "port", CONF_TRAP_PORT }, - { "interface", CONF_TRAP_INTERFACE }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "fudge" modifier keywords - */ -static struct keyword fudge_keywords[] = { - { "flag1", CONF_FDG_FLAG1 }, - { "flag2", CONF_FDG_FLAG2 }, - { "flag3", CONF_FDG_FLAG3 }, - { "flag4", CONF_FDG_FLAG4 }, - { "refid", CONF_FDG_REFID }, - { "stratum", CONF_FDG_STRATUM }, - { "time1", CONF_FDG_TIME1 }, - { "time2", CONF_FDG_TIME2 }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "filegen" modifier keywords - */ -static struct keyword filegen_keywords[] = { - { "disable", CONF_FGEN_FLAG_DISABLE }, - { "enable", CONF_FGEN_FLAG_ENABLE }, - { "file", CONF_FGEN_FILE }, - { "link", CONF_FGEN_FLAG_LINK }, - { "nolink", CONF_FGEN_FLAG_NOLINK }, - { "type", CONF_FGEN_TYPE }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "type" modifier keywords - */ -static struct keyword fgen_types[] = { - { "age", FILEGEN_AGE }, - { "day", FILEGEN_DAY }, - { "month", FILEGEN_MONTH }, - { "none", FILEGEN_NONE }, - { "pid", FILEGEN_PID }, - { "week", FILEGEN_WEEK }, - { "year", FILEGEN_YEAR }, - { "", CONFIG_UNKNOWN} -}; - -/* - * "enable", "disable" modifier keywords - */ -static struct keyword flags_keywords[] = { - { "auth", PROTO_AUTHENTICATE }, - { "bclient", PROTO_BROADCLIENT }, - { "calibrate", PROTO_CAL }, - { "kernel", PROTO_KERNEL }, - { "monitor", PROTO_MONITOR }, - { "ntp", PROTO_NTP }, - { "pps", PROTO_PPS }, - { "stats", PROTO_FILEGEN }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "discard" modifier keywords - */ -static struct keyword discard_keywords[] = { - { "average", CONF_DISCARD_AVERAGE }, - { "minimum", CONF_DISCARD_MINIMUM }, - { "monitor", CONF_DISCARD_MONITOR }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "tinker" modifier keywords - */ -static struct keyword tinker_keywords[] = { - { "step", CONF_CLOCK_MAX }, - { "panic", CONF_CLOCK_PANIC }, - { "dispersion", CONF_CLOCK_PHI }, - { "stepout", CONF_CLOCK_MINSTEP }, - { "allan", CONF_CLOCK_ALLAN }, - { "huffpuff", CONF_CLOCK_HUFFPUFF }, - { "freq", CONF_CLOCK_FREQ }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "tos" modifier keywords - */ -static struct keyword tos_keywords[] = { - { "minclock", CONF_TOS_MINCLOCK }, - { "minsane", CONF_TOS_MINSANE }, - { "floor", CONF_TOS_FLOOR }, - { "ceiling", CONF_TOS_CEILING }, - { "cohort", CONF_TOS_COHORT }, - { "", CONFIG_UNKNOWN } -}; - -#ifdef OPENSSL -/* - * "crypto" modifier keywords - */ -static struct keyword crypto_keywords[] = { - { "cert", CONF_CRYPTO_CERT }, - { "gqpar", CONF_CRYPTO_GQPAR }, - { "host", CONF_CRYPTO_RSA }, - { "iffpar", CONF_CRYPTO_IFFPAR }, - { "leap", CONF_CRYPTO_LEAP }, - { "mvpar", CONF_CRYPTO_MVPAR }, - { "pw", CONF_CRYPTO_PW }, - { "randfile", CONF_CRYPTO_RAND }, - { "sign", CONF_CRYPTO_SIGN }, - { "", CONFIG_UNKNOWN } -}; -#endif /* OPENSSL */ - -/* - * Address type selection, IPv4 or IPv4. - * Used on various lines. - */ -static struct keyword addr_type[] = { - { "-4", CONF_ADDR_IPV4 }, - { "-6", CONF_ADDR_IPV6 }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "logconfig" building blocks - */ -struct masks { - const char *name; - unsigned long mask; -}; - -static struct masks logcfg_class[] = { - { "clock", NLOG_OCLOCK }, - { "peer", NLOG_OPEER }, - { "sync", NLOG_OSYNC }, - { "sys", NLOG_OSYS }, - { (char *)0, 0 } -}; - -static struct masks logcfg_item[] = { - { "info", NLOG_INFO }, - { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO }, - { "events", NLOG_EVENT }, - { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT }, - { "status", NLOG_STATUS }, - { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS }, - { "statistics", NLOG_STATIST }, - { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST }, - { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK }, - { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER }, - { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS }, - { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC }, - { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK }, - { (char *)0, 0 } -}; - -/* - * Limits on things - */ -#define MAXTOKENS 20 /* 20 tokens on line */ -#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 MAXINCLUDELEVEL 5 /* maximum include file levels */ - -/* - * Miscellaneous macros - */ -#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) -#define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0') -#define ISSPACE(c) ((c) == ' ' || (c) == '\t') -#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) - -#define KEY_TYPE_MD5 4 - -/* - * File descriptor used by the resolver save routines, and temporary file - * name. - */ -int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */ -static FILE *res_fp; -#ifndef SYS_WINNT -static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */ -#define RES_TEMPFILE "/tmp/ntpXXXXXX" -#else -static char res_file[MAX_PATH]; -#endif /* SYS_WINNT */ - -/* - * Definitions of things either imported from or exported to outside - */ -char const *progname; -char sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */ -char *keysdir = NTP_KEYSDIR; /* crypto keys directory */ -char pps_device[MAXPPS + 1]; /* PPS device name */ -#if defined(HAVE_SCHED_SETSCHEDULER) -int config_priority_override = 0; -int config_priority; -#endif - -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 -/* - * NetInfo configuration state - */ -struct netinfo_config_state { - void *domain; /* domain with config */ - ni_id config_dir; /* ID config dir */ - int prop_index; /* current property */ - int val_index; /* current value */ - char **val_list; /* value list */ -}; -#endif - -/* - * Function prototypes - */ -static unsigned long get_pfxmatch P((char **, struct masks *)); -static unsigned long get_match P((char *, struct masks *)); -static unsigned long get_logmask P((char *)); -#ifdef HAVE_NETINFO -static struct netinfo_config_state *get_netinfo_config P((void)); -static void free_netinfo_config P((struct netinfo_config_state *)); -static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *)); -#endif -static int gettokens P((FILE *, char *, char **, int *)); -static int matchkey P((char *, struct keyword *, int)); -static int getnetnum P((const char *, struct sockaddr_storage *, int)); -static void save_resolve P((char *, int, int, int, int, u_int, int, - keyid_t, u_char *)); -static void do_resolve_internal P((void)); -static void abort_resolve P((void)); -#if !defined(VMS) && !defined(SYS_WINNT) -static RETSIGTYPE catchchild P((int)); -#endif /* VMS */ - -/* - * get_pfxmatch - find value for prefixmatch - * and update char * accordingly - */ -static unsigned long -get_pfxmatch( - char ** s, - struct masks *m - ) -{ - while (m->name) { - if (strncmp(*s, m->name, strlen(m->name)) == 0) { - *s += strlen(m->name); - return m->mask; - } else { - m++; - } - } - return 0; -} - -/* - * get_match - find logmask value - */ -static unsigned long -get_match( - char *s, - struct masks *m - ) -{ - while (m->name) { - if (strcmp(s, m->name) == 0) { - return m->mask; - } else { - m++; - } - } - return 0; -} - -/* - * get_logmask - build bitmask for ntp_syslogmask - */ -static unsigned long -get_logmask( - char *s - ) -{ - char *t; - unsigned long offset; - unsigned long mask; - - t = s; - offset = get_pfxmatch(&t, logcfg_class); - mask = get_match(t, logcfg_item); - - if (mask) - return mask << offset; - else - msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s); - - return 0; -} - - -/* - * getconfig - get command line options and read the configuration file - */ -void -getconfig( - int argc, - char *argv[] - ) -{ - register int i; - int c; - int errflg; - int istart; - int peerversion; - int minpoll; - int maxpoll; - int ttl; - long stratum; - unsigned long ul; - keyid_t peerkey; - u_char *peerkeystr; - u_long fudgeflag; - u_int peerflags; - int hmode; - struct sockaddr_storage peeraddr; - struct sockaddr_storage maskaddr; - FILE *fp[MAXINCLUDELEVEL+1]; - FILE *includefile; - int includelevel = 0; - char line[MAXLINE]; - char *(tokens[MAXTOKENS]); - int ntokens = 0; - int tok = CONFIG_UNKNOWN; - struct interface *localaddr; - struct refclockstat clock_stat; - FILEGEN *filegen; - - /* - * Initialize, initialize - */ - errflg = 0; - /* HMS: don't initialize debug to 0 here! */ -#ifndef SYS_WINNT - config_file = CONFIG_FILE; -#else - temp = CONFIG_FILE; - if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { - msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); - exit(1); - } - config_file = config_file_storage; - - temp = ALT_CONFIG_FILE; - if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { - msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); - exit(1); - } - alt_config_file = alt_config_file_storage; - -#endif /* SYS_WINNT */ - progname = argv[0]; - res_fp = NULL; - memset((char *)sys_phone, 0, sizeof(sys_phone)); - ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */ - - /* - * install a non default variable with this daemon version - */ - (void) sprintf(line, "daemon_version=\"%s\"", Version); - set_sys_var(line, strlen(line)+1, RO); - - /* - * Say how we're setting the time of day - */ - (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using); - set_sys_var(line, strlen(line)+1, RO); - - /* - * Initialize the loop. - */ - loop_config(LOOP_DRIFTINIT, 0.); - - getCmdOpts(argc, argv); - - if ( - (fp[0] = fopen(FindConfig(config_file), "r")) == NULL -#ifdef HAVE_NETINFO - /* If there is no config_file, try NetInfo. */ - && check_netinfo && !(config_netinfo = get_netinfo_config()) -#endif /* HAVE_NETINFO */ - ) { - fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); - msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); -#ifdef SYS_WINNT - /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ - - if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) { - - /* - * Broadcast clients can sometimes run without - * a configuration file. - */ - - fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); - msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); - return; - } -#else /* not SYS_WINNT */ - return; -#endif /* not SYS_WINNT */ - } - - for (;;) { - 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) { - if (includelevel > 0) { - fclose(fp[includelevel--]); - continue; - } else { - break; - } - } - - switch(tok) { - case CONFIG_PEER: - case CONFIG_SERVER: - case CONFIG_MANYCASTCLIENT: - case CONFIG_BROADCAST: - if (tok == CONFIG_PEER) - hmode = MODE_ACTIVE; - else if (tok == CONFIG_SERVER) - hmode = MODE_CLIENT; - else if (tok == CONFIG_MANYCASTCLIENT) - hmode = MODE_CLIENT; - else - hmode = MODE_BROADCAST; - - if (ntokens < 2) { - msyslog(LOG_ERR, - "No address for %s, line ignored", - tokens[0]); - break; - } - - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - switch (matchkey(tokens[istart], addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; - break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; - break; - } - - if (!getnetnum(tokens[istart], &peeraddr, 0)) { - errflg = -1; - } else { - errflg = 0; - - if ( -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - ISBADADR(&peeraddr)) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - stoa(&peeraddr)); - break; - } - /* - * Shouldn't be able to specify multicast - * address for server/peer! - * and unicast address for manycastclient! - */ - if (peeraddr.ss_family == AF_INET) { - if (((tok == CONFIG_SERVER) || - (tok == CONFIG_PEER)) && -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - stoa(&peeraddr)); - break; - } - if ((tok == CONFIG_MANYCASTCLIENT) && - !IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - stoa(&peeraddr)); - break; - } - } - else if(peeraddr.ss_family == AF_INET6) { - if (((tok == CONFIG_SERVER) || - (tok == CONFIG_PEER)) && -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) { - msyslog(LOG_ERR, - "attempt to configure in valid address %s", - stoa(&peeraddr)); - break; - } - if ((tok == CONFIG_MANYCASTCLIENT) && - !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) { - msyslog(LOG_ERR, - "attempt to configure in valid address %s", - stoa(&peeraddr)); - break; - } - } - } - - peerversion = NTP_VERSION; - minpoll = NTP_MINDPOLL; - maxpoll = NTP_MAXDPOLL; - peerkey = 0; - peerkeystr = (u_char *)"*"; - peerflags = 0; - ttl = 0; - istart++; - for (i = istart; i < ntokens; i++) - switch (matchkey(tokens[i], mod_keywords, 1)) { - case CONF_MOD_VERSION: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "peer/server version requires an argument"); - errflg = 1; - break; - } - peerversion = atoi(tokens[++i]); - if ((u_char)peerversion > NTP_VERSION - || (u_char)peerversion < NTP_OLDVERSION) { - msyslog(LOG_ERR, - "inappropriate version number %s, line ignored", - tokens[i]); - errflg = 1; - } - break; - - case CONF_MOD_KEY: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "key: argument required"); - errflg = 1; - break; - } - peerkey = (int)atol(tokens[++i]); - peerflags |= FLAG_AUTHENABLE; - break; - - case CONF_MOD_MINPOLL: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "minpoll: argument required"); - errflg = 1; - break; - } - minpoll = atoi(tokens[++i]); - if (minpoll < NTP_MINPOLL) { - msyslog(LOG_INFO, - "minpoll: provided value (%d) is below minimum (%d)", - minpoll, NTP_MINPOLL); - minpoll = NTP_MINPOLL; - } - break; - - case CONF_MOD_MAXPOLL: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "maxpoll: argument required" - ); - errflg = 1; - break; - } - maxpoll = atoi(tokens[++i]); - if (maxpoll > NTP_MAXPOLL) { - msyslog(LOG_INFO, - "maxpoll: provided value (%d) is above maximum (%d)", - maxpoll, NTP_MAXPOLL); - maxpoll = NTP_MAXPOLL; - } - break; - - case CONF_MOD_PREFER: - peerflags |= FLAG_PREFER; - break; - - case CONF_MOD_NOSELECT: - peerflags |= FLAG_NOSELECT; - break; - - case CONF_MOD_BURST: - peerflags |= FLAG_BURST; - break; - - case CONF_MOD_IBURST: - peerflags |= FLAG_IBURST; - break; -#ifdef OPENSSL - case CONF_MOD_SKEY: - peerflags |= FLAG_SKEY | - FLAG_AUTHENABLE; - break; -#endif /* OPENSSL */ - - case CONF_MOD_TTL: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "ttl: argument required"); - errflg = 1; - break; - } - ttl = atoi(tokens[++i]); - if (ttl >= MAX_TTL) { - msyslog(LOG_ERR, - "ttl: invalid argument"); - errflg = 1; - } - break; - - case CONF_MOD_MODE: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "mode: argument required"); - errflg = 1; - break; - } - ttl = atoi(tokens[++i]); - break; - - case CONFIG_UNKNOWN: - errflg = 1; - break; - } - if (minpoll > maxpoll) { - msyslog(LOG_ERR, - "config error: minpoll > maxpoll"); - errflg = 1; - } - if (errflg == 0) { - if (peer_config(&peeraddr, - ANY_INTERFACE_CHOOSE(&peeraddr), hmode, - peerversion, minpoll, maxpoll, peerflags, - ttl, peerkey, peerkeystr) == 0) { - msyslog(LOG_ERR, - "configuration of %s failed", - stoa(&peeraddr)); - } - if (tok == CONFIG_MANYCASTCLIENT) - proto_config(PROTO_MULTICAST_ADD, - 0, 0., &peeraddr); - - } else if (errflg == -1) { - save_resolve(tokens[1], hmode, peerversion, - minpoll, maxpoll, peerflags, ttl, - peerkey, peerkeystr); - } - break; - - case CONFIG_DRIFTFILE: - if (ntokens >= 2) - stats_config(STATS_FREQ_FILE, tokens[1]); - else - stats_config(STATS_FREQ_FILE, (char *)0); - break; - - case CONFIG_PIDFILE: - if (ntokens >= 2) - stats_config(STATS_PID_FILE, tokens[1]); - else - 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 */ - msyslog(LOG_NOTICE, "logging to file %s", tokens[1]); - 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", - tokens[1]); - } - else - msyslog(LOG_ERR, "logfile needs one argument"); - break; - - case CONFIG_LOGCONFIG: - for (i = 1; i < ntokens; i++) - { - int add = 1; - int equals = 0; - char * s = &tokens[i][0]; - - switch (*s) { - case '+': - case '-': - case '=': - add = *s == '+'; - equals = *s == '='; - s++; - break; - - default: - break; - } - if (equals) { - ntp_syslogmask = get_logmask(s); - } else { - if (add) { - ntp_syslogmask |= get_logmask(s); - } else { - ntp_syslogmask &= ~get_logmask(s); - } - } -#ifdef DEBUG - if (debug) - printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]); -#endif - } - break; - - case CONFIG_BROADCASTCLIENT: - proto_config(PROTO_BROADCLIENT, 1, 0., NULL); - break; - - case CONFIG_MULTICASTCLIENT: - case CONFIG_MANYCASTSERVER: - if (ntokens > 1) { - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - switch (matchkey(tokens[istart], - addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; - break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; - break; - } - /* - * Abuse maskaddr to store the prefered ip - * version. - */ - memset((char *)&maskaddr, 0, sizeof(maskaddr)); - maskaddr.ss_family = peeraddr.ss_family; - - for (i = istart; i < ntokens; i++) { - memset((char *)&peeraddr, 0, - sizeof(peeraddr)); - peeraddr.ss_family = maskaddr.ss_family; - if (getnetnum(tokens[i], &peeraddr, 1)) - proto_config(PROTO_MULTICAST_ADD, - 0, 0., &peeraddr); - } - } else - proto_config(PROTO_MULTICAST_ADD, - 0, 0., NULL); - if (tok == CONFIG_MULTICASTCLIENT) - sys_bclient = 1; - else if (tok == CONFIG_MANYCASTSERVER) - sys_manycastserver = 1; - break; - - case CONFIG_KEYS: - if (ntokens >= 2) { - getauthkeys(tokens[1]); - } - break; - - case CONFIG_KEYSDIR: - if (ntokens < 2) { - msyslog(LOG_ERR, - "Keys directory name required"); - break; - } - keysdir = emalloc(strlen(tokens[1]) + 1); - strcpy(keysdir, tokens[1]); - break; - - case CONFIG_TINKER: - for (i = 1; i < ntokens; i++) { - int temp; - double ftemp; - - temp = matchkey(tokens[i++], tinker_keywords, 1); - 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_ALLAN: - loop_config(LOOP_ALLAN, ftemp); - break; - - case CONF_CLOCK_HUFFPUFF: - loop_config(LOOP_HUFFPUFF, ftemp); - break; - - case CONF_CLOCK_FREQ: - loop_config(LOOP_FREQ, ftemp); - break; - } - } - break; - - case CONFIG_TOS: - for (i = 1; i < ntokens; i++) { - int temp; - double ftemp; - - temp = matchkey(tokens[i++], tos_keywords, 1); - if (i > ntokens - 1) { - msyslog(LOG_ERR, - "tinker: missing argument"); - errflg++; - break; - } - sscanf(tokens[i], "%lf", &ftemp); - switch(temp) { - - case CONF_TOS_MINCLOCK: - proto_config(PROTO_MINCLOCK, 0, ftemp, NULL); - break; - - case CONF_TOS_MINSANE: - proto_config(PROTO_MINSANE, 0, ftemp, NULL); - break; - - case CONF_TOS_FLOOR: - proto_config(PROTO_FLOOR, 0, ftemp, NULL); - break; - - case CONF_TOS_CEILING: - proto_config(PROTO_CEILING, 0, ftemp, NULL); - break; - - case CONF_TOS_COHORT: - proto_config(PROTO_COHORT, 0, ftemp, NULL); - break; - } - } - break; - - case CONFIG_TTL: - for (i = 1; i < ntokens && i < MAX_TTL; i++) { - sys_ttl[i - 1] = (u_char) atoi(tokens[i]); - sys_ttlmax = i - 1; - } - break; - - case CONFIG_DISCARD: - for (i = 1; i < ntokens; i++) { - int temp; - - temp = matchkey(tokens[i++], - discard_keywords, 1); - if (i > ntokens - 1) { - msyslog(LOG_ERR, - "discard: missing argument"); - errflg++; - break; - } - switch(temp) { - case CONF_DISCARD_AVERAGE: - res_avg_interval = atoi(tokens[i++]); - break; - - case CONF_DISCARD_MINIMUM: - res_min_interval = atoi(tokens[i++]); - break; - - case CONF_DISCARD_MONITOR: - mon_age = atoi(tokens[i++]); - break; - - default: - msyslog(LOG_ERR, - "discard: unknown keyword"); - break; - } - } - break; - -#ifdef OPENSSL - case CONFIG_REVOKE: - if (ntokens >= 2) - sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE); - break; - - case CONFIG_AUTOMAX: - if (ntokens >= 2) - sys_automax = 1 << max(atoi(tokens[1]), 10); - break; - - case CONFIG_CRYPTO: - if (ntokens == 1) { - crypto_config(CRYPTO_CONF_NONE, NULL); - break; - } - for (i = 1; i < ntokens; i++) { - int temp; - - temp = matchkey(tokens[i++], - crypto_keywords, 1); - if (i > ntokens - 1) { - msyslog(LOG_ERR, - "crypto: missing argument"); - errflg++; - break; - } - switch(temp) { - - case CONF_CRYPTO_CERT: - crypto_config(CRYPTO_CONF_CERT, - tokens[i]); - break; - - case CONF_CRYPTO_RSA: - crypto_config(CRYPTO_CONF_PRIV, - tokens[i]); - break; - - case CONF_CRYPTO_IFFPAR: - crypto_config(CRYPTO_CONF_IFFPAR, - tokens[i]); - break; - - case CONF_CRYPTO_GQPAR: - crypto_config(CRYPTO_CONF_GQPAR, - tokens[i]); - break; - - case CONF_CRYPTO_MVPAR: - crypto_config(CRYPTO_CONF_MVPAR, - tokens[i]); - break; - - case CONF_CRYPTO_LEAP: - crypto_config(CRYPTO_CONF_LEAP, - tokens[i]); - break; - - case CONF_CRYPTO_PW: - crypto_config(CRYPTO_CONF_PW, - tokens[i]); - break; - - case CONF_CRYPTO_RAND: - crypto_config(CRYPTO_CONF_RAND, - tokens[i]); - break; - - case CONF_CRYPTO_SIGN: - crypto_config(CRYPTO_CONF_SIGN, - tokens[i]); - break; - - default: - msyslog(LOG_ERR, - "crypto: unknown keyword"); - break; - } - } - break; -#endif /* OPENSSL */ - - case CONFIG_RESTRICT: - if (ntokens < 2) { - msyslog(LOG_ERR, "restrict requires an address"); - break; - } - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - switch (matchkey(tokens[istart], addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; - break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; - break; - } - - /* - * Assume default means an IPv4 address, except - * if forced by a -4 or -6. - */ - if (STREQ(tokens[istart], "default")) { - if (peeraddr.ss_family == 0) - peeraddr.ss_family = AF_INET; - } else if (!getnetnum(tokens[istart], &peeraddr, 1)) - break; - - /* - * Use peerversion as flags, peerkey as mflags. Ick. - */ - peerversion = 0; - peerkey = 0; - errflg = 0; - SET_HOSTMASK(&maskaddr, peeraddr.ss_family); - istart++; - for (i = istart; i < ntokens; i++) { - switch (matchkey(tokens[i], res_keywords, 1)) { - case CONF_RES_MASK: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "mask keyword needs argument"); - errflg++; - break; - } - i++; - if (!getnetnum(tokens[i], &maskaddr, 1)) - errflg++; - break; - - case CONF_RES_IGNORE: - peerversion |= RES_IGNORE; - break; - - case CONF_RES_NOSERVE: - peerversion |= RES_DONTSERVE; - break; - - case CONF_RES_NOTRUST: - peerversion |= RES_DONTTRUST; - break; - - case CONF_RES_NOQUERY: - peerversion |= RES_NOQUERY; - break; - - case CONF_RES_NOMODIFY: - peerversion |= RES_NOMODIFY; - break; - - case CONF_RES_NOPEER: - peerversion |= RES_NOPEER; - break; - - case CONF_RES_NOTRAP: - peerversion |= RES_NOTRAP; - break; - - case CONF_RES_LPTRAP: - peerversion |= RES_LPTRAP; - break; - - case CONF_RES_NTPPORT: - 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; - - case CONFIG_UNKNOWN: - errflg++; - break; - } - } - if (SOCKNUL(&peeraddr)) - ANYSOCK(&maskaddr); - if (!errflg) - hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr, - (int)peerkey, peerversion); - break; - - case CONFIG_BDELAY: - if (ntokens >= 2) { - double tmp; - - if (sscanf(tokens[1], "%lf", &tmp) != 1) { - msyslog(LOG_ERR, - "broadcastdelay value %s undecodable", - tokens[1]); - } else { - proto_config(PROTO_BROADDELAY, 0, tmp, NULL); - } - } - break; - - case CONFIG_CDELAY: - if (ntokens >= 2) { - u_long ui; - - if (sscanf(tokens[1], "%ld", &ui) != 1) - msyslog(LOG_ERR, - "illegal value - line ignored"); - else - proto_config(PROTO_CALLDELAY, ui, 0, NULL); - } - break; - - case CONFIG_TRUSTEDKEY: - for (i = 1; i < ntokens; i++) { - keyid_t tkey; - - tkey = atol(tokens[i]); - if (tkey == 0) { - msyslog(LOG_ERR, - "trusted key %s unlikely", - tokens[i]); - } else { - authtrust(tkey, 1); - } - } - break; - - case CONFIG_REQUESTKEY: - if (ntokens >= 2) { - if (!atouint(tokens[1], &ul)) { - msyslog(LOG_ERR, - "%s is undecodable as request key", - tokens[1]); - } else if (ul == 0) { - msyslog(LOG_ERR, - "%s makes a poor request keyid", - tokens[1]); - } else { -#ifdef DEBUG - if (debug > 3) - printf( - "set info_auth_key to %08lx\n", ul); -#endif - info_auth_keyid = (keyid_t)ul; - } - } - break; - - case CONFIG_CONTROLKEY: - if (ntokens >= 2) { - keyid_t ckey; - - ckey = atol(tokens[1]); - if (ckey == 0) { - msyslog(LOG_ERR, - "%s makes a poor control keyid", - tokens[1]); - } else { - ctl_auth_keyid = ckey; - } - } - break; - - case CONFIG_TRAP: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no address for trap command, line ignored"); - break; - } - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - switch (matchkey(tokens[istart], addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; - break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; - break; - } - - if (!getnetnum(tokens[istart], &peeraddr, 1)) - break; - - /* - * Use peerversion for port number. Barf. - */ - errflg = 0; - peerversion = 0; - localaddr = 0; - istart++; - for (i = istart; i < ntokens-1; i++) - switch (matchkey(tokens[i], trap_keywords, 1)) { - case CONF_TRAP_PORT: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "trap port requires an argument"); - errflg = 1; - break; - } - peerversion = atoi(tokens[++i]); - if (peerversion <= 0 - || peerversion > 32767) { - msyslog(LOG_ERR, - "invalid port number %s, trap ignored", - tokens[i]); - errflg = 1; - } - break; - - case CONF_TRAP_INTERFACE: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "trap interface requires an argument"); - errflg = 1; - break; - } - - memset((char *)&maskaddr, 0, - sizeof(maskaddr)); - maskaddr.ss_family = peeraddr.ss_family; - if (!getnetnum(tokens[++i], - &maskaddr, 1)) { - errflg = 1; - break; - } - - localaddr = findinterface(&maskaddr); - if (localaddr == NULL) { - msyslog(LOG_ERR, - "can't find interface with address %s", - stoa(&maskaddr)); - errflg = 1; - } - break; - - case CONFIG_UNKNOWN: - errflg++; - break; - } - - if (!errflg) { - if (peerversion != 0) - ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion); - else - ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT); - if (localaddr == NULL) - localaddr = ANY_INTERFACE_CHOOSE(&peeraddr); - if (!ctlsettrap(&peeraddr, localaddr, 0, - NTP_VERSION)) - msyslog(LOG_ERR, - "can't set trap for %s, no resources", - stoa(&peeraddr)); - } - break; - - case CONFIG_FUDGE: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no address for fudge command, line ignored"); - break; - } - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - if (!getnetnum(tokens[1], &peeraddr, 1)) - break; - - if (!ISREFCLOCKADR(&peeraddr)) { - msyslog(LOG_ERR, - "%s is inappropriate address for the fudge command, line ignored", - stoa(&peeraddr)); - break; - } - - memset((void *)&clock_stat, 0, sizeof clock_stat); - fudgeflag = 0; - errflg = 0; - for (i = 2; i < ntokens-1; i++) { - switch (c = matchkey(tokens[i], - fudge_keywords, 1)) { - case CONF_FDG_TIME1: - if (sscanf(tokens[++i], "%lf", - &clock_stat.fudgetime1) != 1) { - msyslog(LOG_ERR, - "fudge %s time1 value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - clock_stat.haveflags |= CLK_HAVETIME1; - break; - - case CONF_FDG_TIME2: - if (sscanf(tokens[++i], "%lf", - &clock_stat.fudgetime2) != 1) { - msyslog(LOG_ERR, - "fudge %s time2 value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - clock_stat.haveflags |= CLK_HAVETIME2; - break; - - - case CONF_FDG_STRATUM: - if (!atoint(tokens[++i], &stratum)) - { - msyslog(LOG_ERR, - "fudge %s stratum value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - clock_stat.fudgeval1 = stratum; - clock_stat.haveflags |= CLK_HAVEVAL1; - break; - - case CONF_FDG_REFID: - /* HMS: Endianness and 0 bytes? */ - /* XXX */ - strncpy((char *)&clock_stat.fudgeval2, - tokens[++i], 4); - clock_stat.haveflags |= CLK_HAVEVAL2; - break; - - case CONF_FDG_FLAG1: - case CONF_FDG_FLAG2: - case CONF_FDG_FLAG3: - case CONF_FDG_FLAG4: - if (!atouint(tokens[++i], &fudgeflag) - || fudgeflag > 1) { - msyslog(LOG_ERR, - "fudge %s flag value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - switch(c) { - case CONF_FDG_FLAG1: - c = CLK_FLAG1; - clock_stat.haveflags|=CLK_HAVEFLAG1; - break; - case CONF_FDG_FLAG2: - c = CLK_FLAG2; - clock_stat.haveflags|=CLK_HAVEFLAG2; - break; - case CONF_FDG_FLAG3: - c = CLK_FLAG3; - clock_stat.haveflags|=CLK_HAVEFLAG3; - break; - case CONF_FDG_FLAG4: - c = CLK_FLAG4; - clock_stat.haveflags|=CLK_HAVEFLAG4; - break; - } - if (fudgeflag == 0) - clock_stat.flags &= ~c; - else - clock_stat.flags |= c; - break; - - case CONFIG_UNKNOWN: - errflg = -1; - break; - } - } - -#ifdef REFCLOCK - /* - * If reference clock support isn't defined the - * fudge line will still be accepted and syntax - * checked, but will essentially do nothing. - */ - if (!errflg) { - refclock_control(&peeraddr, &clock_stat, - (struct refclockstat *)0); - } -#endif - break; - - case CONFIG_STATSDIR: - if (ntokens >= 2) - stats_config(STATS_STATSDIR,tokens[1]); - break; - - case CONFIG_STATISTICS: - for (i = 1; i < ntokens; i++) { - filegen = filegen_get(tokens[i]); - - if (filegen == NULL) { - msyslog(LOG_ERR, - "no statistics named %s available", - tokens[i]); - continue; - } -#ifdef DEBUG - if (debug > 3) - printf("enabling filegen for %s statistics \"%s%s\"\n", - tokens[i], filegen->prefix, filegen->basename); -#endif - filegen->flag |= FGEN_FLAG_ENABLED; - } - break; - - case CONFIG_FILEGEN: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no id for filegen command, line ignored"); - break; - } - - filegen = filegen_get(tokens[1]); - if (filegen == NULL) { - msyslog(LOG_ERR, - "unknown filegen \"%s\" ignored", - tokens[1]); - break; - } - /* - * peerversion is (ab)used for filegen file (index) - * peerkey is (ab)used for filegen type - * peerflags is (ab)used for filegen flags - */ - peerversion = 0; - peerkey = filegen->type; - peerflags = filegen->flag; - errflg = 0; - - for (i = 2; i < ntokens; i++) { - switch (matchkey(tokens[i], - filegen_keywords, 1)) { - case CONF_FGEN_FILE: - if (i >= ntokens - 1) { - msyslog(LOG_ERR, - "filegen %s file requires argument", - tokens[1]); - errflg = i; - break; - } - peerversion = ++i; - break; - case CONF_FGEN_TYPE: - if (i >= ntokens -1) { - msyslog(LOG_ERR, - "filegen %s type requires argument", - tokens[1]); - errflg = i; - break; - } - peerkey = matchkey(tokens[++i], - fgen_types, 1); - if (peerkey == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "filegen %s unknown type \"%s\"", - tokens[1], tokens[i]); - errflg = i; - break; - } - break; - - case CONF_FGEN_FLAG_LINK: - peerflags |= FGEN_FLAG_LINK; - break; - - case CONF_FGEN_FLAG_NOLINK: - peerflags &= ~FGEN_FLAG_LINK; - break; - - case CONF_FGEN_FLAG_ENABLE: - peerflags |= FGEN_FLAG_ENABLED; - break; - - case CONF_FGEN_FLAG_DISABLE: - peerflags &= ~FGEN_FLAG_ENABLED; - break; - } - } - if (!errflg) - filegen_config(filegen, tokens[peerversion], - (u_char)peerkey, (u_char)peerflags); - break; - - case CONFIG_SETVAR: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no value for setvar command - line ignored"); - } else { - set_sys_var(tokens[1], strlen(tokens[1])+1, - (u_short) (RW | - ((((ntokens > 2) - && !strcmp(tokens[2], - "default"))) - ? DEF - : 0))); - } - break; - - case CONFIG_ENABLE: - for (i = 1; i < ntokens; i++) { - int flag; - - flag = matchkey(tokens[i], flags_keywords, 1); - if (flag == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "enable unknown flag %s", - tokens[i]); - errflg = 1; - break; - } - proto_config(flag, 1, 0., NULL); - } - break; - - case CONFIG_DISABLE: - for (i = 1; i < ntokens; i++) { - int flag; - - flag = matchkey(tokens[i], flags_keywords, 1); - if (flag == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "disable unknown flag %s", - tokens[i]); - errflg = 1; - break; - } - proto_config(flag, 0, 0., NULL); - } - break; - - case CONFIG_PHONE: - for (i = 1; i < ntokens && i < MAXPHONE; i++) { - (void)strncpy(sys_phone[i - 1], - tokens[i], MAXDIAL); - } - sys_phone[i - 1][0] = '\0'; - break; - - case CONFIG_ADJ: { - double ftemp; - - sscanf(tokens[1], "%lf", &ftemp); - proto_config(PROTO_ADJ, 0, ftemp, NULL); - } - break; - - } - } - if (fp[0]) - (void)fclose(fp[0]); - -#ifdef HAVE_NETINFO - if (config_netinfo) - free_netinfo_config(config_netinfo); -#endif /* HAVE_NETINFO */ - -#if !defined(VMS) && !defined(SYS_VXWORKS) - /* find a keyid */ - if (info_auth_keyid == 0) - req_keyid = 65535; - else - req_keyid = info_auth_keyid; - - /* if doesn't exist, make up one at random */ - if (!authhavekey(req_keyid)) { - char rankey[9]; - int j; - - for (i = 0; i < 8; i++) - for (j = 1; j < 100; ++j) { - rankey[i] = (char) (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) { - if (call_resolver) { - /* - * Need name resolution - */ - do_resolve_internal(); - } - } -} - - -#ifdef HAVE_NETINFO - -/* - * get_netinfo_config - find the nearest NetInfo domain with an ntp - * configuration and initialize the configuration state. - */ -static struct netinfo_config_state * -get_netinfo_config() -{ - ni_status status; - void *domain; - ni_id config_dir; - struct netinfo_config_state *config; - - if (ni_open(NULL, ".", &domain) != NI_OK) return NULL; - - while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) { - void *next_domain; - if (ni_open(domain, "..", &next_domain) != NI_OK) { - ni_free(next_domain); - break; - } - ni_free(domain); - domain = next_domain; - } - if (status != NI_OK) { - ni_free(domain); - return NULL; - } - - config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state)); - config->domain = domain; - config->config_dir = config_dir; - config->prop_index = 0; - config->val_index = 0; - config->val_list = NULL; - - return config; -} - - - -/* - * free_netinfo_config - release NetInfo configuration state - */ -static void -free_netinfo_config(struct netinfo_config_state *config) -{ - ni_free(config->domain); - free(config); -} - - - -/* - * gettokens_netinfo - return tokens from NetInfo - */ -static int -gettokens_netinfo ( - struct netinfo_config_state *config, - char **tokenlist, - int *ntokens - ) -{ - int prop_index = config->prop_index; - int val_index = config->val_index; - char **val_list = config->val_list; - - /* - * Iterate through each keyword and look for a property that matches it. - */ - again: - if (!val_list) { - for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++) - { - ni_namelist namelist; - struct keyword current_prop = keywords[prop_index]; - - /* - * For each value associated in the property, we're going to return - * a separate line. We squirrel away the values in the config state - * so the next time through, we don't need to do this lookup. - */ - NI_INIT(&namelist); - if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) { - ni_index index; - - /* Found the property, but it has no values */ - if (namelist.ni_namelist_len == 0) continue; - - if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1)))) - { msyslog(LOG_ERR, "out of memory while configuring"); break; } - - for (index = 0; index < namelist.ni_namelist_len; index++) { - char *value = namelist.ni_namelist_val[index]; - - if (! (val_list[index] = (char*)malloc(strlen(value)+1))) - { msyslog(LOG_ERR, "out of memory while configuring"); break; } - - strcpy(val_list[index], value); - } - val_list[index] = NULL; - - break; - } - ni_namelist_free(&namelist); - } - config->prop_index = prop_index; - } - - /* No list; we're done here. */ - if (!val_list) return CONFIG_UNKNOWN; - - /* - * We have a list of values for the current property. - * Iterate through them and return each in order. - */ - if (val_list[val_index]) - { - int ntok = 1; - int quoted = 0; - char *tokens = val_list[val_index]; - - msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]); - - (const char*)tokenlist[0] = keywords[prop_index].text; - for (ntok = 1; ntok < MAXTOKENS; ntok++) { - tokenlist[ntok] = tokens; - while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted)) - quoted ^= (*tokens++ == '"'); - - if (ISEOL(*tokens)) { - *tokens = '\0'; - break; - } else { /* must be space */ - *tokens++ = '\0'; - while (ISSPACE(*tokens)) tokens++; - if (ISEOL(*tokens)) break; - } - } - *ntokens = ntok + 1; - - config->val_index++; - - return keywords[prop_index].keytype; - } - - /* We're done with the current property. */ - prop_index = ++config->prop_index; - - /* Free val_list and reset counters. */ - for (val_index = 0; val_list[val_index]; val_index++) - free(val_list[val_index]); - free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0; - - goto again; -} - -#endif /* HAVE_NETINFO */ - - -/* - * gettokens - read a line and return tokens - */ -static int -gettokens ( - FILE *fp, - char *line, - char **tokenlist, - int *ntokens - ) -{ - register char *cp; - register int ntok; - register int quoted = 0; - - /* - * Find start of first token - */ - again: - while ((cp = fgets(line, MAXLINE, fp)) != NULL) { - cp = line; - while (ISSPACE(*cp)) - cp++; - if (!ISEOL(*cp)) - break; - } - if (cp == NULL) { - *ntokens = 0; - return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */ - } - - /* - * Now separate out the tokens - */ - for (ntok = 0; ntok < MAXTOKENS; ntok++) { - tokenlist[ntok] = cp; - while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted)) - quoted ^= (*cp++ == '"'); - - if (ISEOL(*cp)) { - *cp = '\0'; - break; - } else { /* must be space */ - *cp++ = '\0'; - while (ISSPACE(*cp)) - cp++; - if (ISEOL(*cp)) - break; - } - } - - /* - * Return the match - */ - *ntokens = ntok + 1; - ntok = matchkey(tokenlist[0], keywords, 1); - if (ntok == CONFIG_UNKNOWN) - goto again; - return ntok; -} - - - -/* - * matchkey - match a keyword to a list - */ -static int -matchkey( - register char *word, - register struct keyword *keys, - int complain - ) -{ - for (;;) { - if (keys->keytype == CONFIG_UNKNOWN) { - if (complain) - msyslog(LOG_ERR, - "configure: keyword \"%s\" unknown, line ignored", - word); - return CONFIG_UNKNOWN; - } - if (STRSAME(word, keys->text)) - return keys->keytype; - keys++; - } -} - - -/* - * getnetnum - return a net number (this is crude, but careful) - */ -static int -getnetnum( - const char *num, - struct sockaddr_storage *addr, - int complain - ) -{ - struct addrinfo hints; - struct addrinfo *ptr; - - /* Get host address. Looking for UDP datagram connection */ - memset(&hints, 0, sizeof (hints)); - if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6) - hints.ai_family = addr->ss_family; - else - hints.ai_family = AF_UNSPEC; - - hints.ai_socktype = SOCK_DGRAM; -#ifdef DEBUG - if (debug > 3) - printf("getaddrinfo %s\n", num); -#endif - if (getaddrinfo(num, "ntp", &hints, &ptr)!=0) { - if (complain) - msyslog(LOG_ERR, - "getaddrinfo: \"%s\" invalid host address, line ignored", - num); -#ifdef DEBUG - if (debug > 3) - printf( - "getaddrinfo: \"%s\" invalid host address%s.\n", - num, (complain) - ? ", line ignored" - : ""); -#endif - return 0; - } - - memcpy(addr, ptr->ai_addr, ptr->ai_addrlen); -#ifdef DEBUG - if (debug > 1) - printf("getnetnum given %s, got %s \n", - num, stoa(addr)); -#endif - freeaddrinfo(ptr); - return 1; -} - - -#if !defined(VMS) && !defined(SYS_WINNT) -/* - * catchchild - receive the resolver's exit status - */ -static RETSIGTYPE -catchchild( - int sig - ) -{ - /* - * We only start up one child, and if we're here - * it should have already exited. Hence the following - * shouldn't hang. If it does, please tell me. - */ -#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS) - (void) wait(0); -#endif /* SYS_WINNT && VXWORKS*/ -} -#endif /* VMS */ - - -/* - * save_resolve - save configuration info into a file for later name resolution - */ -static void -save_resolve( - char *name, - int mode, - int version, - int minpoll, - int maxpoll, - u_int flags, - int ttl, - keyid_t keyid, - u_char *keystr - ) -{ -#ifndef SYS_VXWORKS - if (res_fp == NULL) { -#ifndef SYS_WINNT - (void) strcpy(res_file, RES_TEMPFILE); -#else - /* no /tmp directory under NT */ - { - if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) { - msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m"); - return; - } - (void) strcat(res_file, "ntpdXXXXXX"); - } -#endif /* SYS_WINNT */ -#ifdef HAVE_MKSTEMP - { - int fd; - - res_fp = NULL; - if ((fd = mkstemp(res_file)) != -1) - res_fp = fdopen(fd, "r+"); - } -#else - (void) mktemp(res_file); - res_fp = fopen(res_file, "w"); -#endif - if (res_fp == NULL) { - msyslog(LOG_ERR, "open failed for %s: %m", res_file); - return; - } - } -#ifdef DEBUG - if (debug) { - printf("resolving %s\n", name); - } -#endif - - (void)fprintf(res_fp, "%s %d %d %d %d %d %d %u %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 %u %s\n", name, mode, - version, minpoll, maxpoll, flags, ttl, keyid, keystr); -#endif - -#else /* SYS_VXWORKS */ - /* save resolve info to a struct */ -#endif /* SYS_VXWORKS */ -} - - -/* - * abort_resolve - terminate the resolver stuff and delete the file - */ -static void -abort_resolve(void) -{ - /* - * In an ideal world we would might reread the file and - * log the hosts which aren't getting configured. Since - * this is too much work, however, just close and delete - * the temp file. - */ - if (res_fp != NULL) - (void) fclose(res_fp); - res_fp = NULL; - -#ifndef SYS_VXWORKS /* we don't open the file to begin with */ -#if !defined(VMS) - (void) unlink(res_file); -#else - (void) delete(res_file); -#endif /* VMS */ -#endif /* SYS_VXWORKS */ -} - - -/* - * do_resolve_internal - start up the resolver function (not program) - */ -/* - * On VMS, this routine will simply refuse to resolve anything. - * - * Possible implementation: keep `res_file' in memory, do async - * name resolution via QIO, update from within completion AST. - * I'm unlikely to find the time for doing this, though. -wjm - */ -static void -do_resolve_internal(void) -{ - int i; - - if (res_fp == NULL) { - /* belch */ - msyslog(LOG_ERR, - "do_resolve_internal: Fatal: res_fp == NULL"); - exit(1); - } - - /* we are done with this now */ - (void) fclose(res_fp); - res_fp = NULL; - -#if !defined(VMS) && !defined (SYS_VXWORKS) - req_file = res_file; /* set up pointer to res file */ -#ifndef SYS_WINNT - (void) signal_no_reset(SIGCHLD, catchchild); - -#ifndef SYS_VXWORKS - i = fork(); - if (i == 0) { - /* - * this used to close everything - * I don't think this is necessary - */ - /* - * To the unknown commenter above: - * Well, I think it's better to clean up - * after oneself. I have had problems with - * refclock-io when intres was running - things - * where fine again when ntpintres was gone. - * So some systems react erratic at least. - * - * Frank Kardel - * - * 94-11-16: - * Further debugging has proven that the above is - * absolutely harmful. The internal resolver - * is still in the SIGIO process group and the lingering - * async io information causes it to process requests from - * all file decriptor causing a race between the NTP daemon - * and the resolver. which then eats data when it wins 8-(. - * It is absolutly necessary to kill any IO associations - * shared with the NTP daemon. - * - * We also block SIGIO (currently no ports means to - * disable the signal handle for IO). - * - * Thanks to wgstuken@informatik.uni-erlangen.de to notice - * that it is the ntp-resolver child running into trouble. - * - * THUS: - */ - - closelog(); - kill_asyncio(0); - - (void) signal_no_reset(SIGCHLD, SIG_DFL); - -#ifdef DEBUG - if (0) - debug = 2; -#endif - -# ifndef LOG_DAEMON - openlog("ntpd_initres", LOG_PID); -# else /* LOG_DAEMON */ - -# ifndef LOG_NTP -# define LOG_NTP LOG_DAEMON -# endif - openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP); -#ifndef SYS_CYGWIN32 -# ifdef DEBUG - if (debug) - setlogmask(LOG_UPTO(LOG_DEBUG)); - else -# endif /* DEBUG */ - setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ -# endif /* LOG_DAEMON */ -#endif - - ntp_intres(); - - /* - * If we got here, the intres code screwed up. - * Print something so we don't die without complaint - */ - msyslog(LOG_ERR, "call to ntp_intres lost"); - abort_resolve(); - exit(1); - } -#else - /* vxWorks spawns a thread... -casey */ - i = sp (ntp_intres); - /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/ -#endif - if (i == -1) { - msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m"); - (void) signal_no_reset(SIGCHLD, SIG_DFL); - abort_resolve(); - } -#else /* SYS_WINNT */ - { - /* NT's equivalent of fork() is _spawn(), but the start point - * of the new process is an executable filename rather than - * a function name as desired here. - */ - DWORD dwThreadId; - fflush(stdout); - ResolverThreadHandle = CreateThread( - NULL, /* no security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */ - NULL, /* argument to thread function */ - 0, /* use default creation flags */ - &dwThreadId); /* returns the thread identifier */ - if (ResolverThreadHandle == NULL) { - msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres"); - abort_resolve(); - } - } -#endif /* SYS_WINNT */ -#else /* VMS VX_WORKS */ - msyslog(LOG_ERR, - "Name resolution not implemented for VMS - use numeric addresses"); - abort_resolve(); -#endif /* VMS VX_WORKS */ -} diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c deleted file mode 100644 index 0ac0404..0000000 --- a/contrib/ntp/ntpd/ntp_control.c +++ /dev/null @@ -1,2928 +0,0 @@ -/* - * ntp_control.c - respond to control messages and send async traps - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#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> - -/* - * Structure to hold request procedure information - */ -#define NOAUTH 0 -#define AUTH 1 - -#define NO_REQUEST (-1) - -struct ctl_proc { - short control_code; /* defined request code */ - u_short flags; /* flags word */ - void (*handler) P((struct recvbuf *, int)); /* handle request */ -}; - -/* - * Only one flag. Authentication required or not. - */ -#define NOAUTH 0 -#define AUTH 1 - -/* - * Request processing routines - */ -static void ctl_error P((int)); -#ifdef REFCLOCK -static u_short ctlclkstatus P((struct refclockstat *)); -#endif -static void ctl_flushpkt P((int)); -static void ctl_putdata P((const char *, unsigned int, int)); -static void ctl_putstr P((const char *, const char *, - unsigned int)); -static void ctl_putdbl P((const char *, double)); -static void ctl_putuint P((const char *, u_long)); -static void ctl_puthex P((const char *, u_long)); -static void ctl_putint P((const char *, long)); -static void ctl_putts P((const char *, l_fp *)); -static void ctl_putadr P((const char *, u_int32, struct sockaddr_storage*)); -static void ctl_putid P((const char *, char *)); -static void ctl_putarray P((const char *, double *, int)); -static void ctl_putsys P((int)); -static void ctl_putpeer P((int, struct peer *)); -#ifdef 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 void control_unspec P((struct recvbuf *, int)); -static void read_status P((struct recvbuf *, int)); -static void read_variables P((struct recvbuf *, int)); -static void write_variables P((struct recvbuf *, int)); -static void read_clock_status P((struct recvbuf *, int)); -static void write_clock_status P((struct recvbuf *, int)); -static void set_trap P((struct recvbuf *, int)); -static void unset_trap P((struct recvbuf *, int)); -static struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *, - struct interface *)); - -static struct ctl_proc control_codes[] = { - { CTL_OP_UNSPEC, NOAUTH, control_unspec }, - { CTL_OP_READSTAT, NOAUTH, read_status }, - { CTL_OP_READVAR, NOAUTH, read_variables }, - { CTL_OP_WRITEVAR, AUTH, write_variables }, - { CTL_OP_READCLOCK, NOAUTH, read_clock_status }, - { CTL_OP_WRITECLOCK, NOAUTH, write_clock_status }, - { CTL_OP_SETTRAP, NOAUTH, set_trap }, - { CTL_OP_UNSETTRAP, NOAUTH, unset_trap }, - { NO_REQUEST, 0 } -}; - -/* - * System variable values. The array can be indexed by the variable - * index to find the textual name. - */ -static struct ctl_var sys_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CS_LEAP, RW, "leap" }, /* 1 */ - { CS_STRATUM, RO, "stratum" }, /* 2 */ - { CS_PRECISION, RO, "precision" }, /* 3 */ - { CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */ - { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */ - { CS_REFID, RO, "refid" }, /* 6 */ - { CS_REFTIME, RO, "reftime" }, /* 7 */ - { CS_POLL, RO, "poll" }, /* 8 */ - { CS_PEERID, RO, "peer" }, /* 9 */ - { CS_STATE, RO, "state" }, /* 10 */ - { CS_OFFSET, RO, "offset" }, /* 11 */ - { CS_DRIFT, RO, "frequency" }, /* 12 */ - { CS_JITTER, RO, "jitter" }, /* 13 */ - { CS_CLOCK, RO, "clock" }, /* 14 */ - { CS_PROCESSOR, RO, "processor" }, /* 15 */ - { CS_SYSTEM, RO, "system" }, /* 16 */ - { CS_VERSION, RO, "version" }, /* 17 */ - { CS_STABIL, RO, "stability" }, /* 18 */ - { CS_VARLIST, RO, "sys_var_list" }, /* 19 */ -#ifdef OPENSSL - { CS_FLAGS, RO, "flags" }, /* 20 */ - { CS_HOST, RO, "hostname" }, /* 21 */ - { CS_PUBLIC, RO, "hostkey" }, /* 22 */ - { CS_CERTIF, RO, "cert" }, /* 23 */ - { CS_REVTIME, RO, "refresh" }, /* 24 */ - { CS_LEAPTAB, RO, "leapseconds" }, /* 25 */ - { CS_TAI, RO, "tai" }, /* 26 */ - { CS_DIGEST, RO, "signature" }, /* 27 */ -#endif /* OPENSSL */ - { 0, EOV, "" } /* 28 */ -}; - -static struct ctl_var *ext_sys_var = (struct ctl_var *)0; - -/* - * 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, - CS_STRATUM, - CS_PRECISION, - CS_ROOTDELAY, - CS_ROOTDISPERSION, - CS_PEERID, - CS_REFID, - CS_REFTIME, - CS_POLL, - CS_CLOCK, - CS_STATE, - CS_OFFSET, - CS_DRIFT, - CS_JITTER, - CS_STABIL, -#ifdef OPENSSL - CS_HOST, - CS_DIGEST, - CS_FLAGS, - CS_PUBLIC, - CS_REVTIME, - CS_LEAPTAB, - CS_CERTIF, -#endif /* OPENSSL */ - 0 -}; - - -/* - * 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 */ - { 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, "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_RANK, RO, "rank" }, /* 37 */ - { CP_VARLIST, RO, "peer_var_list" }, /* 38 */ -#ifdef OPENSSL - { CP_FLAGS, RO, "flags" }, /* 39 */ - { CP_HOST, RO, "hostname" }, /* 40 */ - { CP_INITSEQ, RO, "initsequence" }, /* 41 */ - { CP_INITKEY, RO, "initkey" }, /* 42 */ - { CP_INITTSP, RO, "timestamp" }, /* 43 */ - { CP_DIGEST, RO, "signature" }, /* 44 */ - { CP_IDENT, RO, "identity" }, /* 45 */ -#endif /* OPENSSL */ - { 0, EOV, "" } /* 39/46 */ -}; - - -/* - * Peer variables we print by default - */ -static u_char def_peer_var[] = { - CP_SRCADR, - CP_SRCPORT, - CP_DSTADR, - CP_DSTPORT, - CP_LEAP, - CP_STRATUM, - CP_PRECISION, - CP_ROOTDELAY, - CP_ROOTDISPERSION, - CP_REFID, - CP_REACH, - CP_VALID, - CP_HMODE, - CP_PMODE, - CP_HPOLL, - CP_PPOLL, - CP_FLASH, - CP_KEYID, - CP_TTL, - CP_OFFSET, - CP_DELAY, - CP_DISPERSION, - CP_JITTER, - CP_REFTIME, - CP_ORG, - CP_REC, - CP_XMT, - CP_FILTDELAY, - CP_FILTOFFSET, - CP_FILTERROR, -#ifdef OPENSSL - CP_HOST, - CP_DIGEST, - CP_FLAGS, - CP_IDENT, - CP_INITSEQ, -#endif /* OPENSSL */ - 0 -}; - - -#ifdef REFCLOCK -/* - * 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, "" } /* 14 */ -}; - - -/* - * Clock variables printed by default - */ -static u_char def_clock_var[] = { - CC_DEVICE, - CC_TYPE, /* won't be output if device = known */ - CC_TIMECODE, - CC_POLL, - CC_NOREPLY, - CC_BADFORMAT, - CC_BADDATA, - CC_FUDGETIME1, - CC_FUDGETIME2, - CC_FUDGEVAL1, - CC_FUDGEVAL2, - CC_FLAGS, - 0 -}; -#endif - - -/* - * System and processor definitions. - */ -#ifndef HAVE_UNAME -# ifndef STR_SYSTEM -# define STR_SYSTEM "UNIX" -# endif -# ifndef STR_PROCESSOR -# define STR_PROCESSOR "unknown" -# endif - -static char str_system[] = STR_SYSTEM; -static char str_processor[] = STR_PROCESSOR; -#else -# include <sys/utsname.h> -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. - */ -/* ntp_request.c */ -struct ctl_trap ctl_trap[CTL_MAXTRAPS]; -int num_ctl_traps; - -/* - * Type bits, for ctlsettrap() call. - */ -#define TRAP_TYPE_CONFIG 0 /* used by configuration code */ -#define TRAP_TYPE_PRIO 1 /* priority trap */ -#define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */ - - -/* - * 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. - */ -static u_char clocktypes[] = { - CTL_SST_TS_NTP, /* REFCLK_NONE (0) */ - CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */ - CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */ - CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */ - CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */ - CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */ - CTL_SST_TS_HF, /* REFCLK_CHU (7) */ - CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */ - CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */ - CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */ - CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */ - CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */ - CTL_SST_TS_UHF, /* REFCLK_TRUETIME (15) */ - CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */ - CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */ - CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_PTB_ACTS (23) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_USNO (24) */ - CTL_SST_TS_UHF, /* REFCLK_TRUETIME (25) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */ - CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */ - CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */ - CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */ - CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */ - 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_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) */ - CTL_SST_TS_LF, /* REFCLK_JJY (40) */ - CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */ - CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */ - CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */ - CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */ -}; - - -/* - * Keyid used for authenticating write requests. - */ -keyid_t ctl_auth_keyid; - -/* - * We keep track of the last error reported by the system internally - */ -static u_char ctl_sys_last_event; -static u_char ctl_sys_num_events; - - -/* - * Statistic counters to keep track of requests and responses. - */ -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 numctlerrors; /* number of error responses sent */ -u_long numctltooshort; /* number of too short input packets */ -u_long numctlinputresp; /* number of responses on input */ -u_long numctlinputfrag; /* number of fragments on input */ -u_long 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 numasyncmsgs; /* number of async messages we've sent */ - -/* - * 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 - * use the extra buffer and copy. - */ -static struct ntp_control rpkt; -static u_char res_version; -static u_char res_opcode; -static associd_t res_associd; -static int res_offset; -static u_char * datapt; -static u_char * dataend; -static int datalinelen; -static int datanotbinflag; -static struct sockaddr_storage *rmt_addr; -static struct interface *lcl_inter; - -static u_char res_authenticate; -static u_char res_authokay; -static keyid_t res_keyid; - -#define MAXDATALINELEN (72) - -static u_char res_async; /* set to 1 if this is async trap response */ - -/* - * Pointers for saving state when decoding request packets - */ -static char *reqpt; -static char *reqend; - -/* - * init_control - initialize request data - */ -void -init_control(void) -{ - int i; - -#ifdef HAVE_UNAME - uname(&utsnamebuf); -#endif /* HAVE_UNAME */ - - ctl_clr_stats(); - - ctl_auth_keyid = 0; - ctl_sys_last_event = EVNT_UNSPEC; - ctl_sys_num_events = 0; - - num_ctl_traps = 0; - for (i = 0; i < CTL_MAXTRAPS; i++) - ctl_trap[i].tr_flags = 0; -} - - -/* - * ctl_error - send an error response for the current request - */ -static void -ctl_error( - int errcode - ) -{ -#ifdef DEBUG - if (debug >= 4) - printf("sending control error %d\n", errcode); -#endif - /* - * Fill in the fields. We assume rpkt.sequence and rpkt.associd - * have already been filled in. - */ - rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & - CTL_OP_MASK)); - rpkt.status = htons((u_short) ((errcode<<8) & 0xff00)); - rpkt.count = 0; - - /* - * send packet and bump counters - */ - if (res_authenticate && sys_authenticate) { - int maclen; - - *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) = - htonl(res_keyid); - maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, - CTL_HEADER_LEN); - sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt, - CTL_HEADER_LEN + maclen); - } else { - sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt, - CTL_HEADER_LEN); - } - numctlerrors++; -} - - -/* - * process_control - process an incoming control message - */ -void -process_control( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register struct ntp_control *pkt; - register int req_count; - register int req_data; - register struct ctl_proc *cc; - int properlen; - int maclen; - -#ifdef DEBUG - if (debug > 2) - printf("in process_control()\n"); -#endif - - /* - * Save the addresses for error responses - */ - numctlreq++; - rmt_addr = &rbufp->recv_srcadr; - lcl_inter = rbufp->dstadr; - pkt = (struct ntp_control *)&rbufp->recv_pkt; - - /* - * If the length is less than required for the header, or - * it is a response or a fragment, ignore this. - */ - if (rbufp->recv_length < CTL_HEADER_LEN - || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) - || pkt->offset != 0) { -#ifdef DEBUG - if (debug) - printf("invalid format in control packet\n"); -#endif - if (rbufp->recv_length < CTL_HEADER_LEN) - numctltooshort++; - if (pkt->r_m_e_op & CTL_RESPONSE) - numctlinputresp++; - if (pkt->r_m_e_op & CTL_MORE) - numctlinputfrag++; - if (pkt->r_m_e_op & CTL_ERROR) - numctlinputerr++; - if (pkt->offset != 0) - numctlbadoffset++; - return; - } - res_version = PKT_VERSION(pkt->li_vn_mode); - if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) { -#ifdef DEBUG - if (debug) - printf("unknown version %d in control packet\n", - res_version); -#endif - numctlbadversion++; - return; - } - - /* - * Pull enough data from the packet to make intelligent - * responses - */ - 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; - rpkt.status = 0; - res_offset = 0; - res_associd = htons(pkt->associd); - res_async = 0; - res_authenticate = 0; - res_keyid = 0; - res_authokay = 0; - req_count = (int)htons(pkt->count); - datanotbinflag = 0; - datalinelen = 0; - datapt = rpkt.data; - 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. - */ - req_data = rbufp->recv_length - CTL_HEADER_LEN; - if (req_data < req_count || rbufp->recv_length & 0x3) { - ctl_error(CERR_BADFMT); - numctldatatooshort++; - return; - } - - properlen = req_count + CTL_HEADER_LEN; -#ifdef DEBUG - if (debug > 2 && (rbufp->recv_length & 0x3) != 0) - printf("Packet length %d unrounded\n", - rbufp->recv_length); -#endif - /* round up proper len to a 8 octet boundary */ - - properlen = (properlen + 7) & ~7; - maclen = rbufp->recv_length - properlen; - if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 && - maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN && - sys_authenticate) { - res_authenticate = 1; - res_keyid = ntohl(*(u_int32 *)((u_char *)pkt + - properlen)); - -#ifdef DEBUG - if (debug > 2) - printf( - "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n", - rbufp->recv_length, properlen, res_keyid, maclen); -#endif - if (!authistrusted(res_keyid)) { -#ifdef DEBUG - if (debug > 2) - printf("invalid keyid %08x\n", - res_keyid); -#endif - } else if (authdecrypt(res_keyid, (u_int32 *)pkt, - rbufp->recv_length - maclen, maclen)) { -#ifdef DEBUG - if (debug > 2) - printf("authenticated okay\n"); -#endif - res_authokay = 1; - } else { -#ifdef DEBUG - if (debug > 2) - printf("authentication failed\n"); -#endif - res_keyid = 0; - } - } - - /* - * Set up translate pointers - */ - reqpt = (char *)pkt->data; - reqend = reqpt + req_count; - - /* - * Look for the opcode processor - */ - for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) { - if (cc->control_code == res_opcode) { -#ifdef DEBUG - if (debug > 2) - printf("opcode %d, found command handler\n", - res_opcode); -#endif - if (cc->flags == AUTH && (!res_authokay || - res_keyid != ctl_auth_keyid)) { - ctl_error(CERR_PERMISSION); - return; - } - (cc->handler)(rbufp, restrict_mask); - return; - } - } - - /* - * Can't find this one, return an error. - */ - numctlbadop++; - ctl_error(CERR_BADOP); - return; -} - - -/* - * ctlpeerstatus - return a status word for this peer - */ -u_short -ctlpeerstatus( - register struct peer *peer - ) -{ - register u_short status; - - status = peer->status; - if (peer->flags & FLAG_CONFIG) - status |= CTL_PST_CONFIG; - if (peer->flags & FLAG_AUTHENABLE) - status |= CTL_PST_AUTHENABLE; - if (peer->flags & FLAG_AUTHENTIC) - status |= CTL_PST_AUTHENTIC; - if (peer->reach != 0) - status |= CTL_PST_REACH; - return (u_short)CTL_PEER_STATUS(status, peer->num_events, - peer->last_event); -} - - -/* - * ctlclkstatus - return a status word for this clock - */ -#ifdef REFCLOCK -static u_short -ctlclkstatus( - struct refclockstat *this_clock - ) -{ - return ((u_short)(((this_clock->currentstatus) << 8) | - (this_clock->lastevent))); -} -#endif - - -/* - * ctlsysstatus - return the system status word - */ -u_short -ctlsysstatus(void) -{ - register u_char this_clock; - - this_clock = CTL_SST_TS_UNSPEC; - if (sys_peer != 0) { - if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) { - this_clock = sys_peer->sstclktype; - if (pps_control) - this_clock |= CTL_SST_TS_PPS; - } else { - if (sys_peer->refclktype < sizeof(clocktypes)) - this_clock = - clocktypes[sys_peer->refclktype]; - if (pps_control) - this_clock |= CTL_SST_TS_PPS; - } - } - return (u_short)CTL_SYS_STATUS(sys_leap, this_clock, - ctl_sys_num_events, ctl_sys_last_event); -} - - -/* - * ctl_flushpkt - write out the current packet and prepare - * another if necessary. - */ -static void -ctl_flushpkt( - int more - ) -{ - int dlen; - int sendlen; - - if (!more && datanotbinflag) { - /* - * Big hack, output a trailing \r\n - */ - *datapt++ = '\r'; - *datapt++ = '\n'; - } - dlen = datapt - (u_char *)rpkt.data; - sendlen = dlen + CTL_HEADER_LEN; - - /* - * Pad to a multiple of 32 bits - */ - while (sendlen & 0x3) { - *datapt++ = '\0'; - sendlen++; - } - - /* - * Fill in the packet with the current info - */ - rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode & - CTL_OP_MASK)); - rpkt.count = htons((u_short) dlen); - rpkt.offset = htons( (u_short) res_offset); - if (res_async) { - register int i; - - 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); - sendpkt(&ctl_trap[i].tr_addr, - ctl_trap[i].tr_localaddr, -4, - (struct pkt *)&rpkt, sendlen); - if (!more) - ctl_trap[i].tr_sequence++; - numasyncmsgs++; - } - } - } else { - if (res_authenticate && sys_authenticate) { - int maclen; - int totlen = sendlen; - 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. - */ - 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); - } else { - sendpkt(rmt_addr, lcl_inter, -6, - (struct pkt *)&rpkt, sendlen); - } - if (more) - numctlfrags++; - else - numctlresponses++; - } - - /* - * Set us up for another go around. - */ - res_offset += dlen; - datapt = (u_char *)rpkt.data; -} - - -/* - * ctl_putdata - write data into the packet, fragmenting and starting - * another if this one is full. - */ -static void -ctl_putdata( - const char *dp, - unsigned int dlen, - int bin /* set to 1 when data is binary */ - ) -{ - int overhead; - - overhead = 0; - if (!bin) { - datanotbinflag = 1; - overhead = 3; - if (datapt != rpkt.data) { - *datapt++ = ','; - datalinelen++; - if ((dlen + datalinelen + 1) >= MAXDATALINELEN) - { - *datapt++ = '\r'; - *datapt++ = '\n'; - datalinelen = 0; - } else { - *datapt++ = ' '; - datalinelen++; - } - } - } - - /* - * Save room for trailing junk - */ - if (dlen + overhead + datapt > dataend) { - /* - * Not enough room in this one, flush it out. - */ - ctl_flushpkt(CTL_MORE); - } - memmove((char *)datapt, dp, (unsigned)dlen); - datapt += dlen; - datalinelen += dlen; -} - - -/* - * ctl_putstr - write a tagged string into the response packet - */ -static void -ctl_putstr( - const char *tag, - const char *data, - unsigned int len - ) -{ - register char *cp; - register const char *cq; - char buffer[400]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - if (len > 0) { - *cp++ = '='; - *cp++ = '"'; - if (len > (int) (sizeof(buffer) - (cp - buffer) - 1)) - len = sizeof(buffer) - (cp - buffer) - 1; - memmove(cp, data, (unsigned)len); - cp += len; - *cp++ = '"'; - } - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putdbl - write a tagged, signed double into the response packet - */ -static void -ctl_putdbl( - const char *tag, - double ts - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - *cp++ = '='; - (void)sprintf(cp, "%.3f", ts); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - -/* - * ctl_putuint - write a tagged unsigned integer into the response - */ -static void -ctl_putuint( - const char *tag, - u_long uval - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "%lu", uval); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_puthex - write a tagged unsigned integer, in hex, into the response - */ -static void -ctl_puthex( - const char *tag, - u_long uval - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "0x%lx", uval); - while (*cp != '\0') - cp++; - ctl_putdata(buffer,(unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putint - write a tagged signed integer into the response - */ -static void -ctl_putint( - const char *tag, - long ival - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "%ld", ival); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putts - write a tagged timestamp, in hex, into the response - */ -static void -ctl_putts( - const char *tag, - l_fp *ts - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui & 0xffffffffL, - ts->l_uf & 0xffffffffL); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putadr - write an IP address into the response - */ -static void -ctl_putadr( - const char *tag, - u_int32 addr32, - struct sockaddr_storage* addr - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - if (addr == NULL) - cq = numtoa(addr32); - else - cq = stoa(addr); - while (*cq != '\0') - *cp++ = *cq++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putid - write a tagged clock ID into the response - */ -static void -ctl_putid( - const char *tag, - char *id - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - cq = id; - while (*cq != '\0' && (cq - id) < 4) - *cp++ = *cq++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putarray - write a tagged eight element double array into the response - */ -static void -ctl_putarray( - const char *tag, - double *arr, - int start - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - int i; - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - i = start; - do { - if (i == 0) - i = NTP_SHIFT; - i--; - (void)sprintf(cp, " %.2f", arr[i] * 1e3); - while (*cp != '\0') - cp++; - } while(i != start); - ctl_putdata(buffer, (unsigned)(cp - buffer), 0); -} - - -/* - * ctl_putsys - output a system variable - */ -static void -ctl_putsys( - int varid - ) -{ - l_fp tmp; - char str[256]; -#ifdef OPENSSL - struct cert_info *cp; - char cbuf[256]; -#endif /* OPENSSL */ - - switch (varid) { - - case CS_LEAP: - ctl_putuint(sys_var[CS_LEAP].text, sys_leap); - break; - - case CS_STRATUM: - ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum); - break; - - 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); - break; - - case CS_ROOTDISPERSION: - ctl_putdbl(sys_var[CS_ROOTDISPERSION].text, - sys_rootdispersion * 1e3); - break; - - case CS_REFID: - if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC) - ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL); - else - ctl_putid(sys_var[CS_REFID].text, - (char *)&sys_refid); - break; - - case CS_REFTIME: - ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime); - break; - - case CS_POLL: - ctl_putuint(sys_var[CS_POLL].text, sys_poll); - break; - - 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: - ctl_putuint(sys_var[CS_STATE].text, (unsigned)state); - break; - - case CS_OFFSET: - ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3); - break; - - case CS_DRIFT: - ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6); - break; - - case CS_JITTER: - ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3); - break; - - case CS_CLOCK: - get_systime(&tmp); - ctl_putts(sys_var[CS_CLOCK].text, &tmp); - break; - - case CS_PROCESSOR: -#ifndef HAVE_UNAME - ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor, - sizeof(str_processor) - 1); -#else - ctl_putstr(sys_var[CS_PROCESSOR].text, - utsnamebuf.machine, strlen(utsnamebuf.machine)); -#endif /* HAVE_UNAME */ - break; - - case CS_SYSTEM: -#ifndef HAVE_UNAME - ctl_putstr(sys_var[CS_SYSTEM].text, str_system, - sizeof(str_system) - 1); -#else - sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release); - ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str)); -#endif /* HAVE_UNAME */ - break; - - case CS_VERSION: - ctl_putstr(sys_var[CS_VERSION].text, Version, - strlen(Version)); - 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; - - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } - - for (k = ext_sys_var; k && !(k->flags &EOV); - k++) { - if (k->flags & PADDING) - continue; - - ss = k->text; - if (!ss) - continue; - - while (*ss && *ss != '=') - ss++; - 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) - break; - - *s++ = '"'; - *s = '\0'; - - ctl_putdata(buf, (unsigned)( s - buf ), - 0); - } - break; - -#ifdef OPENSSL - case CS_FLAGS: - if (crypto_flags) { - ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags); - } - break; - - case CS_DIGEST: - if (crypto_flags) { - const EVP_MD *dp; - - dp = EVP_get_digestbynid(crypto_flags >> 16); - strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp))); - ctl_putstr(sys_var[CS_DIGEST].text, str, - strlen(str)); - } - break; - - case CS_HOST: - if (sys_hostname != NULL) - ctl_putstr(sys_var[CS_HOST].text, sys_hostname, - strlen(sys_hostname)); - break; - - case CS_CERTIF: - for (cp = cinfo; cp != NULL; cp = cp->link) { - sprintf(cbuf, "%s %s 0x%x %u", cp->subject, - cp->issuer, cp->flags, - ntohl(cp->cert.fstamp)); - ctl_putstr(sys_var[CS_CERTIF].text, cbuf, - strlen(cbuf)); - } - break; - - case CS_PUBLIC: - if (hostval.fstamp != 0) - ctl_putuint(sys_var[CS_PUBLIC].text, - ntohl(hostval.fstamp)); - break; - - case CS_REVTIME: - if (hostval.tstamp != 0) - ctl_putuint(sys_var[CS_REVTIME].text, - ntohl(hostval.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 /* OPENSSL */ - } -} - - -/* - * ctl_putpeer - output a peer variable - */ -static void -ctl_putpeer( - int varid, - struct peer *peer - ) -{ -#ifdef OPENSSL - char str[256]; - struct autokey *ap; -#endif /* OPENSSL */ - - switch (varid) { - - case CP_CONFIG: - ctl_putuint(peer_var[CP_CONFIG].text, - (unsigned)((peer->flags & FLAG_CONFIG) != 0)); - break; - - case CP_AUTHENABLE: - ctl_putuint(peer_var[CP_AUTHENABLE].text, - (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0)); - break; - - case CP_AUTHENTIC: - ctl_putuint(peer_var[CP_AUTHENTIC].text, - (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0)); - break; - - case CP_SRCADR: - ctl_putadr(peer_var[CP_SRCADR].text, 0, - &peer->srcadr); - break; - - case CP_SRCPORT: - ctl_putuint(peer_var[CP_SRCPORT].text, - ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port)); - break; - - case CP_DSTADR: - ctl_putadr(peer_var[CP_DSTADR].text, 0, - &(peer->dstadr->sin)); - break; - - case CP_DSTPORT: - ctl_putuint(peer_var[CP_DSTPORT].text, - (u_long)(peer->dstadr ? - ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0)); - break; - - case CP_LEAP: - ctl_putuint(peer_var[CP_LEAP].text, peer->leap); - break; - - case CP_HMODE: - ctl_putuint(peer_var[CP_HMODE].text, peer->hmode); - break; - - case CP_STRATUM: - ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum); - break; - - case CP_PPOLL: - ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll); - break; - - 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); - break; - - case CP_ROOTDELAY: - ctl_putdbl(peer_var[CP_ROOTDELAY].text, - peer->rootdelay * 1e3); - break; - - case CP_ROOTDISPERSION: - ctl_putdbl(peer_var[CP_ROOTDISPERSION].text, - peer->rootdispersion * 1e3); - break; - - case CP_REFID: - if (peer->flags & FLAG_REFCLOCK) { - if (peer->stratum > 0 && peer->stratum < - STRATUM_UNSPEC) - ctl_putadr(peer_var[CP_REFID].text, - peer->refid, NULL); - else - ctl_putid(peer_var[CP_REFID].text, - (char *)&peer->refid); - } else { - if (peer->stratum > 1 && peer->stratum < - STRATUM_UNSPEC) - ctl_putadr(peer_var[CP_REFID].text, - peer->refid, NULL); - else - ctl_putid(peer_var[CP_REFID].text, - (char *)&peer->refid); - } - break; - - case CP_REFTIME: - ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime); - break; - - case CP_ORG: - ctl_putts(peer_var[CP_ORG].text, &peer->org); - break; - - case CP_REC: - ctl_putts(peer_var[CP_REC].text, &peer->rec); - break; - - case CP_XMT: - ctl_putts(peer_var[CP_XMT].text, &peer->xmt); - break; - - case CP_REACH: - ctl_puthex(peer_var[CP_REACH].text, peer->reach); - break; - - case CP_FLASH: - ctl_puthex(peer_var[CP_FLASH].text, peer->flash); - break; - - case CP_TTL: - ctl_putint(peer_var[CP_TTL].text, sys_ttl[peer->ttl]); - break; - - case CP_VALID: - ctl_putuint(peer_var[CP_VALID].text, peer->unreach); - break; - - case CP_RANK: - ctl_putuint(peer_var[CP_RANK].text, peer->rank); - break; - - case CP_TIMER: - ctl_putuint(peer_var[CP_TIMER].text, - peer->nextdate - current_time); - break; - - 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); - break; - - case CP_JITTER: - ctl_putdbl(peer_var[CP_JITTER].text, - SQRT(peer->jitter) * 1e3); - break; - - case CP_DISPERSION: - ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp * - 1e3); - break; - - case CP_KEYID: - ctl_putuint(peer_var[CP_KEYID].text, peer->keyid); - break; - - case CP_FILTDELAY: - ctl_putarray(peer_var[CP_FILTDELAY].text, - peer->filter_delay, (int)peer->filter_nextpt); - break; - - case CP_FILTOFFSET: - ctl_putarray(peer_var[CP_FILTOFFSET].text, - peer->filter_offset, (int)peer->filter_nextpt); - break; - - case CP_FILTERROR: - ctl_putarray(peer_var[CP_FILTERROR].text, - peer->filter_disp, (int)peer->filter_nextpt); - break; - - case CP_PMODE: - ctl_putuint(peer_var[CP_PMODE].text, peer->pmode); - break; - - case CP_RECEIVED: - ctl_putuint(peer_var[CP_RECEIVED].text, peer->received); - break; - - 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 */ - - strcpy(s, peer_var[CP_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - for (k = peer_var; !(k->flags &EOV); k++) { - if (k->flags & PADDING) - continue; - - i = strlen(k->text); - if (s + i + 1 >= be) - break; - - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } - if (s+2 >= be) - break; - - *s++ = '"'; - *s = '\0'; - ctl_putdata(buf, (unsigned)(s - buf), 0); - } - break; -#ifdef OPENSSL - case CP_FLAGS: - if (peer->crypto) - ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto); - break; - - case CP_DIGEST: - if (peer->crypto) { - const EVP_MD *dp; - - dp = EVP_get_digestbynid(peer->crypto >> 16); - strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp))); - ctl_putstr(peer_var[CP_DIGEST].text, str, - strlen(str)); - } - break; - - case CP_HOST: - if (peer->subject != NULL) - ctl_putstr(peer_var[CP_HOST].text, peer->subject, - strlen(peer->subject)); - break; - - case CP_IDENT: - if (peer->issuer != NULL) - ctl_putstr(peer_var[CP_IDENT].text, peer->issuer, - strlen(peer->issuer)); - break; - - case CP_INITSEQ: - if ((ap = (struct autokey *)peer->recval.ptr) == NULL) - break; - ctl_putint(peer_var[CP_INITSEQ].text, ap->seq); - ctl_puthex(peer_var[CP_INITKEY].text, ap->key); - ctl_putuint(peer_var[CP_INITTSP].text, - ntohl(peer->recval.tstamp)); - break; -#endif /* OPENSSL */ - } -} - - -#ifdef REFCLOCK -/* - * ctl_putclock - output clock variables - */ -static void -ctl_putclock( - int varid, - struct refclockstat *clock_stat, - int mustput - ) -{ - switch(varid) { - - 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); - break; - - 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); - break; - - 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); - break; - - case CC_FUDGETIME1: - if (mustput || (clock_stat->haveflags & CLK_HAVETIME1)) - ctl_putdbl(clock_var[CC_FUDGETIME1].text, - 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); - break; - - case CC_FUDGEVAL1: - if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1)) - ctl_putint(clock_var[CC_FUDGEVAL1].text, - clock_stat->fudgeval1); - break; - - case CC_FUDGEVAL2: - if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) { - if (clock_stat->fudgeval1 > 1) - ctl_putadr(clock_var[CC_FUDGEVAL2].text, - (u_int32)clock_stat->fudgeval2, NULL); - else - 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); - break; - - case CC_DEVICE: - if (clock_stat->clockdesc == NULL || - *(clock_stat->clockdesc) == '\0') { - if (mustput) - ctl_putstr(clock_var[CC_DEVICE].text, - "", 0); - } else { - 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 */ - - strcpy(s, clock_var[CC_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - - for (k = clock_var; !(k->flags &EOV); k++) { - if (k->flags & PADDING) - continue; - - i = strlen(k->text); - if (s + i + 1 >= be) - break; - - 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) - continue; - - while (*ss && *ss != '=') - ss++; - 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++ = '"'; - *s = '\0'; - ctl_putdata(buf, (unsigned)( s - buf ), 0); - } - break; - } -} -#endif - - - -/* - * ctl_getitem - get the next data item from the incoming packet - */ -static struct ctl_var * -ctl_getitem( - struct ctl_var *var_list, - char **data - ) -{ - register struct ctl_var *v; - register char *cp; - register char *tp; - static struct ctl_var eol = { 0, EOV, }; - static char buf[128]; - - /* - * Delete leading commas and white space - */ - while (reqpt < reqend && (*reqpt == ',' || - isspace((int)*reqpt))) - reqpt++; - if (reqpt >= reqend) - return (0); - - if (var_list == (struct ctl_var *)0) - return (&eol); - - /* - * Look for a first character match on the tag. If we find - * one, see if it is a full match. - */ - v = var_list; - cp = reqpt; - while (!(v->flags & EOV)) { - if (!(v->flags & PADDING) && *cp == *(v->text)) { - tp = v->text; - while (*tp != '\0' && *tp != '=' && cp < - reqend && *cp == *tp) { - cp++; - tp++; - } - if ((*tp == '\0') || (*tp == '=')) { - while (cp < reqend && isspace((int)*cp)) - cp++; - if (cp == reqend || *cp == ',') { - buf[0] = '\0'; - *data = buf; - if (cp < reqend) - cp++; - reqpt = cp; - return v; - } - if (*cp == '=') { - cp++; - tp = buf; - while (cp < reqend && isspace((int)*cp)) - 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", - stoa(rmt_addr), SRCPORT(rmt_addr) - ); - return (0); - } - } - if (cp < reqend) - cp++; - *tp-- = '\0'; - while (tp >= buf) { - if (!isspace((int)(*tp))) - break; - *tp-- = '\0'; - } - reqpt = cp; - *data = buf; - return (v); - } - } - cp = reqpt; - } - v++; - } - return v; -} - - -/* - * control_unspec - response to an unspecified op-code - */ -/*ARGSUSED*/ -static void -control_unspec( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - struct peer *peer; - - /* - * What is an appropriate response to an unspecified op-code? - * I return no errors and no data, unless a specified assocation - * doesn't exist. - */ - if (res_associd != 0) { - if ((peer = findpeerbyassoc(res_associd)) == 0) { - ctl_error(CERR_BADASSOC); - return; - } - rpkt.status = htons(ctlpeerstatus(peer)); - } else { - rpkt.status = htons(ctlsysstatus()); - } - ctl_flushpkt(0); -} - - -/* - * read_status - return either a list of associd's, or a particular - * peer's status. - */ -/*ARGSUSED*/ -static void -read_status( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register int i; - register struct peer *peer; - u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)]; - -#ifdef DEBUG - if (debug > 2) - printf("read_status: ID %d\n", res_associd); -#endif - /* - * 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. - */ - if (res_associd == 0) { - register int n; - - n = 0; - rpkt.status = htons(ctlsysstatus()); - for (i = 0; i < HASH_SIZE; i++) { - for (peer = assoc_hash[i]; peer != 0; - peer = peer->ass_next) { - ass_stat[n++] = htons(peer->associd); - ass_stat[n++] = - htons(ctlpeerstatus(peer)); - if (n == - CTL_MAX_DATA_LEN/sizeof(u_short)) { - ctl_putdata((char *)ass_stat, - n * sizeof(u_short), 1); - n = 0; - } - } - } - - if (n != 0) - ctl_putdata((char *)ass_stat, n * - sizeof(u_short), 1); - ctl_flushpkt(0); - } else { - peer = findpeerbyassoc(res_associd); - if (peer == 0) { - ctl_error(CERR_BADASSOC); - } else { - register u_char *cp; - - rpkt.status = htons(ctlpeerstatus(peer)); - if (res_authokay) - peer->num_events = 0; - /* - * For now, output everything we know about the - * peer. May be more selective later. - */ - for (cp = def_peer_var; *cp != 0; cp++) - ctl_putpeer((int)*cp, peer); - ctl_flushpkt(0); - } - } -} - - -/* - * read_variables - return the variables the caller asks for - */ -/*ARGSUSED*/ -static void -read_variables( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register struct ctl_var *v; - register int i; - char *valuep; - u_char *wants; - unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE + - 1) : (CP_MAXCODE + 1); - if (res_associd == 0) { - /* - * Wants system variables. Figure out which he wants - * and give them to him. - */ - rpkt.status = htons(ctlsysstatus()); - if (res_authokay) - ctl_sys_num_events = 0; - gotvar += count_var(ext_sys_var); - wants = (u_char *)emalloc(gotvar); - memset((char *)wants, 0, gotvar); - gotvar = 0; - while ((v = ctl_getitem(sys_var, &valuep)) != 0) { - if (v->flags & EOV) { - if ((v = ctl_getitem(ext_sys_var, - &valuep)) != 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - free((char *)wants); - return; - } - wants[CS_MAXCODE + 1 + - v->code] = 1; - gotvar = 1; - continue; - } else { - break; /* shouldn't happen ! */ - } - } - wants[v->code] = 1; - gotvar = 1; - } - if (gotvar) { - for (i = 1; i <= CS_MAXCODE; i++) - if (wants[i]) - ctl_putsys(i); - for (i = 0; ext_sys_var && - !(ext_sys_var[i].flags & EOV); i++) - if (wants[i + CS_MAXCODE + 1]) - ctl_putdata(ext_sys_var[i].text, - strlen(ext_sys_var[i].text), - 0); - } else { - register u_char *cs; - register struct ctl_var *kv; - - for (cs = def_sys_var; *cs != 0; cs++) - ctl_putsys((int)*cs); - for (kv = ext_sys_var; kv && !(kv->flags & EOV); - kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, - strlen(kv->text), 0); - } - free((char *)wants); - } else { - register struct peer *peer; - - /* - * Wants info for a particular peer. See if we know - * the guy. - */ - peer = findpeerbyassoc(res_associd); - if (peer == 0) { - ctl_error(CERR_BADASSOC); - return; - } - rpkt.status = htons(ctlpeerstatus(peer)); - if (res_authokay) - peer->num_events = 0; - wants = (u_char *)emalloc(gotvar); - memset((char*)wants, 0, gotvar); - gotvar = 0; - while ((v = ctl_getitem(peer_var, &valuep)) != 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - free((char *)wants); - return; - } - wants[v->code] = 1; - gotvar = 1; - } - if (gotvar) { - for (i = 1; i <= CP_MAXCODE; i++) - if (wants[i]) - ctl_putpeer(i, peer); - } else { - register u_char *cp; - - for (cp = def_peer_var; *cp != 0; cp++) - ctl_putpeer((int)*cp, peer); - } - free((char *)wants); - } - ctl_flushpkt(0); -} - - -/* - * write_variables - write into variables. We only allow leap bit - * writing this way. - */ -/*ARGSUSED*/ -static void -write_variables( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register struct ctl_var *v; - register int ext_var; - char *valuep; - long val = 0; - - /* - * If he's trying to write into a peer tell him no way - */ - if (res_associd != 0) { - ctl_error(CERR_PERMISSION); - return; - } - - /* - * Set status - */ - rpkt.status = htons(ctlsysstatus()); - - /* - * 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->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - return; - } - ext_var = 1; - } else { - break; - } - } - if (!(v->flags & CAN_WRITE)) { - ctl_error(CERR_PERMISSION); - return; - } - if (!ext_var && (*valuep == '\0' || !atoint(valuep, - &val))) { - ctl_error(CERR_BADFMT); - return; - } - if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) { - ctl_error(CERR_BADVALUE); - return; - } - - if (ext_var) { - char *s = (char *)emalloc(strlen(v->text) + - strlen(valuep) + 2); - const char *t; - char *tt = s; - - t = v->text; - while (*t && *t != '=') - *tt++ = *t++; - - *tt++ = '='; - strcat(tt, valuep); - set_sys_var(s, strlen(s)+1, v->flags); - free(s); - } else { - /* - * This one seems sane. Save it. - */ - switch(v->code) { - - case CS_LEAP: - default: - ctl_error(CERR_UNSPEC); /* really */ - return; - } - } - } - - /* - * If we got anything, do it. xxx nothing to do *** - */ - /* - if (leapind != ~0 || leapwarn != ~0) { - if (!leap_setleap((int)leapind, (int)leapwarn)) { - ctl_error(CERR_PERMISSION); - return; - } - } - */ - ctl_flushpkt(0); -} - - -/* - * read_clock_status - return clock radio status - */ -/*ARGSUSED*/ -static void -read_clock_status( - struct recvbuf *rbufp, - int restrict_mask - ) -{ -#ifndef REFCLOCK - /* - * If no refclock support, no data to return - */ - ctl_error(CERR_BADASSOC); -#else - register struct ctl_var *v; - register int i; - register struct peer *peer; - char *valuep; - u_char *wants; - unsigned int gotvar; - struct refclockstat clock_stat; - - if (res_associd == 0) { - - /* - * 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)) - { - 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) { - if (peer->flags & FLAG_REFCLOCK) - break; - } - } - if (peer == 0) { - ctl_error(CERR_BADASSOC); - return; - } - } - } else { - peer = findpeerbyassoc(res_associd); - if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) { - ctl_error(CERR_BADASSOC); - return; - } - } - - /* - * 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); - - /* - * Look for variables in the packet. - */ - rpkt.status = htons(ctlclkstatus(&clock_stat)); - gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list); - wants = (u_char *)emalloc(gotvar); - memset((char*)wants, 0, gotvar); - gotvar = 0; - while ((v = ctl_getitem(clock_var, &valuep)) != 0) { - if (v->flags & EOV) { - if ((v = ctl_getitem(clock_stat.kv_list, - &valuep)) != 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - free((char*)wants); - free_varlist(clock_stat.kv_list); - return; - } - wants[CC_MAXCODE + 1 + v->code] = 1; - gotvar = 1; - continue; - } else { - break; /* shouldn't happen ! */ - } - } - wants[v->code] = 1; - gotvar = 1; - } - - if (gotvar) { - for (i = 1; i <= CC_MAXCODE; i++) - if (wants[i]) - ctl_putclock(i, &clock_stat, 1); - for (i = 0; clock_stat.kv_list && - !(clock_stat.kv_list[i].flags & EOV); i++) - if (wants[i + CC_MAXCODE + 1]) - ctl_putdata(clock_stat.kv_list[i].text, - strlen(clock_stat.kv_list[i].text), - 0); - } else { - register u_char *cc; - register struct ctl_var *kv; - - for (cc = def_clock_var; *cc != 0; cc++) - ctl_putclock((int)*cc, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); - kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, strlen(kv->text), - 0); - } - - free((char*)wants); - free_varlist(clock_stat.kv_list); - - ctl_flushpkt(0); -#endif -} - - -/* - * write_clock_status - we don't do this - */ -/*ARGSUSED*/ -static void -write_clock_status( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - ctl_error(CERR_PERMISSION); -} - -/* - * 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 - */ -static void -set_trap( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - int traptype; - - /* - * See if this guy is allowed - */ - if (restrict_mask & RES_NOTRAP) { - ctl_error(CERR_PERMISSION); - return; - } - - /* - * Determine his allowed trap type. - */ - traptype = TRAP_TYPE_PRIO; - if (restrict_mask & RES_LPTRAP) - traptype = TRAP_TYPE_NONPRIO; - - /* - * Call ctlsettrap() to do the work. Return - * an error if it can't assign the trap. - */ - if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype, - (int)res_version)) - ctl_error(CERR_NORESOURCE); - ctl_flushpkt(0); -} - - -/* - * unset_trap - unset a trap in response to a control message - */ -static void -unset_trap( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - 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. - */ - traptype = TRAP_TYPE_PRIO; - if (restrict_mask & RES_LPTRAP) - traptype = TRAP_TYPE_NONPRIO; - - /* - * Call ctlclrtrap() to clear this out. - */ - if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype)) - ctl_error(CERR_BADASSOC); - ctl_flushpkt(0); -} - - -/* - * ctlsettrap - called to set a trap - */ -int -ctlsettrap( - struct sockaddr_storage *raddr, - struct interface *linter, - int traptype, - int version - ) -{ - register struct ctl_trap *tp; - register struct ctl_trap *tptouse; - - /* - * See if we can find this trap. If so, we only need update - * the flags and the time. - */ - if ((tp = ctlfindtrap(raddr, linter)) != NULL) { - switch (traptype) { - - case TRAP_TYPE_CONFIG: - tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED; - break; - - case TRAP_TYPE_PRIO: - if (tp->tr_flags & TRAP_CONFIGURED) - return (1); /* don't change anything */ - tp->tr_flags = TRAP_INUSE; - break; - - case TRAP_TYPE_NONPRIO: - if (tp->tr_flags & TRAP_CONFIGURED) - return (1); /* don't change anything */ - tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO; - break; - } - tp->tr_settime = current_time; - tp->tr_resets++; - 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. - */ - 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 = 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: - if (tptouse == NULL) { - tptouse = tp; - break; - } - if (tptouse->tr_flags & TRAP_NONPRIO && - !(tp->tr_flags & TRAP_NONPRIO)) - break; - - if (!(tptouse->tr_flags & TRAP_NONPRIO) - && tp->tr_flags & TRAP_NONPRIO) { - tptouse = tp; - break; - } - if (tptouse->tr_origtime < - tp->tr_origtime) - tptouse = tp; - break; - - 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 = tp; - } - break; - - case TRAP_TYPE_NONPRIO: - break; - } - } - } - - /* - * If we don't have room for him return an error. - */ - if (tptouse == NULL) - return (0); - - /* - * Set up this structure for him. - */ - tptouse->tr_settime = tptouse->tr_origtime = current_time; - tptouse->tr_count = tptouse->tr_resets = 0; - tptouse->tr_sequence = 1; - tptouse->tr_addr = *raddr; - tptouse->tr_localaddr = linter; - tptouse->tr_version = (u_char) 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); -} - - -/* - * ctlclrtrap - called to clear a trap - */ -int -ctlclrtrap( - struct sockaddr_storage *raddr, - struct interface *linter, - int traptype - ) -{ - register struct ctl_trap *tp; - - if ((tp = ctlfindtrap(raddr, linter)) == NULL) - return (0); - - if (tp->tr_flags & TRAP_CONFIGURED - && traptype != TRAP_TYPE_CONFIG) - return (0); - - tp->tr_flags = 0; - num_ctl_traps--; - return (1); -} - - -/* - * ctlfindtrap - find a trap given the remote and local addresses - */ -static struct ctl_trap * -ctlfindtrap( - struct sockaddr_storage *raddr, - struct interface *linter - ) -{ - register struct ctl_trap *tp; - - for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { - if ((tp->tr_flags & TRAP_INUSE) - && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr)) - && SOCKCMP(raddr, &tp->tr_addr) - && (linter == tp->tr_localaddr) ) - return (tp); - } - return (struct ctl_trap *)NULL; -} - - -/* - * report_event - report an event to the trappers - */ -void -report_event( - int err, - struct peer *peer - ) -{ - register int i; - - /* - * Record error code in proper spots, but have mercy on the - * log file. - */ - if (!(err & (PEER_EVENT | CRPT_EVENT))) { - if (ctl_sys_num_events < CTL_SYS_MAXEVENTS) - ctl_sys_num_events++; - if (ctl_sys_last_event != (u_char)err) { - NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)", - eventstr(err), err, - sysstatstr(ctlsysstatus()), ctlsysstatus()); -#ifdef DEBUG - if (debug) - printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n", - eventstr(err), err, - sysstatstr(ctlsysstatus()), - ctlsysstatus()); -#endif - ctl_sys_last_event = (u_char)err; - } - } else if (peer != 0) { - char *src; - -#ifdef REFCLOCK - if (ISREFCLOCKADR(&peer->srcadr)) - src = refnumtoa(&peer->srcadr); - else -#endif - src = stoa(&peer->srcadr); - - peer->last_event = (u_char)(err & ~PEER_EVENT); - if (peer->num_events < CTL_PEER_MAXEVENTS) - peer->num_events++; - NLOG(NLOG_PEEREVENT) - msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)", - src, eventstr(err), err, - peerstatstr(ctlpeerstatus(peer)), - ctlpeerstatus(peer)); -#ifdef DEBUG - if (debug) - printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n", - src, eventstr(err), err, - peerstatstr(ctlpeerstatus(peer)), - ctlpeerstatus(peer)); -#endif - } else { - msyslog(LOG_ERR, - "report_event: err '%s' (0x%02x), no peer", - eventstr(err), err); -#ifdef DEBUG - printf( - "report_event: peer event '%s' (0x%02x), no peer\n", - eventstr(err), err); -#endif - return; - } - - /* - * If no trappers, return. - */ - if (num_ctl_traps <= 0) - return; - - /* - * Set up the outgoing packet variables - */ - res_opcode = CTL_OP_ASYNCMSG; - res_offset = 0; - res_async = 1; - 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. Don't send crypto strings. - */ - for (i = 1; i <= CS_MAXCODE; i++) { -#ifdef OPENSSL - if (i > CS_VARLIST) - continue; -#endif /* OPENSSL */ - ctl_putsys(i); - } -#ifdef REFCLOCK - /* - * for clock exception events: add clock variables to - * reflect info on exception - */ - if (err == EVNT_CLOCKEXCPT) { - struct refclockstat clock_stat; - struct ctl_var *kv; - - clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, - (struct refclockstat *)0, &clock_stat); - ctl_puthex("refclockstatus", - ctlclkstatus(&clock_stat)); - for (i = 1; i <= CC_MAXCODE; i++) - ctl_putclock(i, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && - !(kv->flags & EOV); kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, - strlen(kv->text), 0); - free_varlist(clock_stat.kv_list); - } -#endif /* REFCLOCK */ - } else { - rpkt.associd = htons(peer->associd); - rpkt.status = htons(ctlpeerstatus(peer)); - - /* - * Dump it all. Later, maybe less. - */ - for (i = 1; i <= CP_MAXCODE; i++) { -#ifdef OPENSSL - if (i > CP_VARLIST) - continue; -#endif /* OPENSSL */ - ctl_putpeer(i, peer); - } -#ifdef REFCLOCK - /* - * for clock exception events: add clock variables to - * reflect info on exception - */ - if (err == EVNT_PEERCLOCK) { - struct refclockstat clock_stat; - struct ctl_var *kv; - - clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, - (struct refclockstat *)0, &clock_stat); - - ctl_puthex("refclockstatus", - ctlclkstatus(&clock_stat)); - - for (i = 1; i <= CC_MAXCODE; i++) - ctl_putclock(i, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && - !(kv->flags & EOV); kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, - strlen(kv->text), 0); - free_varlist(clock_stat.kv_list); - } -#endif /* REFCLOCK */ - } - - /* - * We're done, return. - */ - ctl_flushpkt(0); -} - - -/* - * ctl_clr_stats - clear stat counters - */ -void -ctl_clr_stats(void) -{ - ctltimereset = current_time; - numctlreq = 0; - numctlbadpkts = 0; - numctlresponses = 0; - numctlfrags = 0; - numctlerrors = 0; - numctlfrags = 0; - numctltooshort = 0; - numctlinputresp = 0; - numctlinputfrag = 0; - numctlinputerr = 0; - numctlbadoffset = 0; - numctlbadversion = 0; - numctldatatooshort = 0; - numctlbadop = 0; - numasyncmsgs = 0; -} - -static u_long -count_var( - struct ctl_var *k - ) -{ - register u_long c; - - if (!k) - return (0); - - c = 0; - while (!(k++->flags & EOV)) - c++; - return (c); -} - -char * -add_var( - struct ctl_var **kv, - u_long size, - u_short def - ) -{ - register u_long c; - register struct ctl_var *k; - - c = count_var(*kv); - - k = *kv; - *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var)); - if (k) { - memmove((char *)*kv, (char *)k, - sizeof(struct ctl_var)*c); - free((char *)k); - } - (*kv)[c].code = (u_short) c; - (*kv)[c].text = (char *)emalloc(size); - (*kv)[c].flags = def; - (*kv)[c+1].code = 0; - (*kv)[c+1].text = (char *)0; - (*kv)[c+1].flags = EOV; - return (char *)(*kv)[c].text; -} - -void -set_var( - struct ctl_var **kv, - const char *data, - u_long size, - u_short def - ) -{ - register struct ctl_var *k; - register const char *s; - register const char *t; - char *td; - - if (!data || !size) - return; - - k = *kv; - if (k != NULL) { - while (!(k->flags & EOV)) { - s = data; - t = k->text; - if (t) { - while (*t != '=' && *s - *t == 0) { - s++; - t++; - } - if (*s == *t && ((*t == '=') || !*t)) { - free((void *)k->text); - td = (char *)emalloc(size); - memmove(td, data, size); - k->text =td; - k->flags = def; - return; - } - } else { - td = (char *)emalloc(size); - memmove(td, data, size); - k->text = td; - k->flags = def; - return; - } - k++; - } - } - td = add_var(kv, size, def); - memmove(td, data, size); -} - -void -set_sys_var( - char *data, - u_long size, - u_short def - ) -{ - set_var(&ext_sys_var, data, size, def); -} - -void -free_varlist( - struct ctl_var *kv - ) -{ - struct ctl_var *k; - if (kv) { - for (k = kv; !(k->flags & EOV); k++) - free((void *)k->text); - free((void *)kv); - } -} diff --git a/contrib/ntp/ntpd/ntp_crypto.c b/contrib/ntp/ntpd/ntp_crypto.c deleted file mode 100644 index 3e67703..0000000 --- a/contrib/ntp/ntpd/ntp_crypto.c +++ /dev/null @@ -1,4031 +0,0 @@ -/* - * ntp_crypto.c - NTP version 4 public key routines - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef OPENSSL -#include <stdio.h> -#include <sys/types.h> -#include <sys/param.h> -#include <unistd.h> -#include <fcntl.h> - -#include "ntpd.h" -#include "ntp_stdlib.h" -#include "ntp_unixtime.h" -#include "ntp_string.h" - -#include "openssl/asn1_mac.h" -#include "openssl/bn.h" -#include "openssl/err.h" -#include "openssl/evp.h" -#include "openssl/pem.h" -#include "openssl/rand.h" -#include "openssl/x509v3.h" - -#ifdef KERNEL_PLL -#include "ntp_syscall.h" -#endif /* KERNEL_PLL */ - -/* - * Extension field message format - * - * These are always signed and saved before sending in network byte - * order. They must be converted to and from host byte order for - * processing. - * - * +-------+-------+ - * | op | len | <- extension pointer - * +-------+-------+ - * | assocID | - * +---------------+ - * | timestamp | <- value pointer - * +---------------+ - * | filestamp | - * +---------------+ - * | value len | - * +---------------+ - * | | - * = value = - * | | - * +---------------+ - * | signature len | - * +---------------+ - * | | - * = signature = - * | | - * +---------------+ - * - * The CRYPTO_RESP bit is set to 0 for requests, 1 for responses. - * Requests carry the association ID of the receiver; responses carry - * the association ID of the sender. Some messages include only the - * operation/length and association ID words and so have length 8 - * octets. Ohers include the value structure and associated value and - * signature fields. These messages include the timestamp, filestamp, - * value and signature words and so have length at least 24 octets. The - * signature and/or value fields can be empty, in which case the - * respective length words are zero. An empty value with nonempty - * signature is syntactically valid, but semantically questionable. - * - * The filestamp represents the time when a cryptographic data file such - * as a public/private key pair is created. It follows every reference - * depending on that file and serves as a means to obsolete earlier data - * of the same type. The timestamp represents the time when the - * cryptographic data of the message were last signed. Creation of a - * cryptographic data file or signing a message can occur only when the - * creator or signor is synchronized to an authoritative source and - * proventicated to a trusted authority. - * - * Note there are four conditions required for server trust. First, the - * public key on the certificate must be verified, which involves a - * number of format, content and consistency checks. Next, the server - * identity must be confirmed by one of four schemes: private - * certificate, IFF scheme, GQ scheme or certificate trail hike to a - * self signed trusted certificate. Finally, the server signature must - * be verified. - */ -/* - * Cryptodefines - */ -#define TAI_1972 10 /* initial TAI offset (s) */ -#define MAX_LEAP 100 /* max UTC leapseconds (s) */ -#define VALUE_LEN (6 * 4) /* min response field length */ -#define YEAR (60 * 60 * 24 * 365) /* seconds in year */ - -/* - * Global cryptodata in host byte order - */ -u_int32 crypto_flags = 0x0; /* status word */ -u_int sys_tai; /* current UTC offset from TAI */ - -/* - * Global cryptodata in network byte order - */ -struct cert_info *cinfo = NULL; /* certificate info/value */ -struct value hostval; /* host value */ -struct value pubkey; /* public key */ -struct value tai_leap; /* leapseconds table */ - -/* - * Private cryptodata in host byte order - */ -static char *passwd = NULL; /* private key password */ -static EVP_PKEY *host_pkey = NULL; /* host key */ -static EVP_PKEY *sign_pkey = NULL; /* sign key */ -static EVP_PKEY *iffpar_pkey = NULL; /* IFF parameters */ -static EVP_PKEY *gqpar_pkey = NULL; /* GQ parameters */ -static EVP_PKEY *mvpar_pkey = NULL; /* MV parameters */ -static const EVP_MD *sign_digest = NULL; /* sign digest */ -static u_int sign_siglen; /* sign key length */ -static char *rand_file = NULL; /* random seed file */ -static char *host_file = NULL; /* host key file */ -static char *sign_file = NULL; /* sign key file */ -static char *iffpar_file = NULL; /* IFF parameters file */ -static char *gqpar_file = NULL; /* GQ parameters file */ -static char *mvpar_file = NULL; /* MV parameters file */ -static char *cert_file = NULL; /* certificate file */ -static char *leap_file = NULL; /* leapseconds file */ -static tstamp_t if_fstamp = 0; /* IFF file stamp */ -static tstamp_t gq_fstamp = 0; /* GQ file stamp */ -static tstamp_t mv_fstamp = 0; /* MV file stamp */ - -/* - * Cryptotypes - */ -static int crypto_verify P((struct exten *, struct value *, - struct peer *)); -static int crypto_encrypt P((struct exten *, struct value *, - keyid_t *)); -static int crypto_alice P((struct peer *, struct value *)); -static int crypto_alice2 P((struct peer *, struct value *)); -static int crypto_alice3 P((struct peer *, struct value *)); -static int crypto_bob P((struct exten *, struct value *)); -static int crypto_bob2 P((struct exten *, struct value *)); -static int crypto_bob3 P((struct exten *, struct value *)); -static int crypto_iff P((struct exten *, struct peer *)); -static int crypto_gq P((struct exten *, struct peer *)); -static int crypto_mv P((struct exten *, struct peer *)); -static u_int crypto_send P((struct exten *, struct value *)); -static tstamp_t crypto_time P((void)); -static u_long asn2ntp P((ASN1_TIME *)); -static struct cert_info *cert_parse P((u_char *, u_int, tstamp_t)); -static int cert_sign P((struct exten *, struct value *)); -static int cert_valid P((struct cert_info *, EVP_PKEY *)); -static int cert_install P((struct exten *, struct peer *)); -static void cert_free P((struct cert_info *)); -static EVP_PKEY *crypto_key P((char *, tstamp_t *)); -static int bighash P((BIGNUM *, BIGNUM *)); -static struct cert_info *crypto_cert P((char *)); -static void crypto_tai P((char *)); - -#ifdef SYS_WINNT -int -readlink(char * link, char * file, int len) { - return (-1); -} -#endif - -/* - * 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. - * - * Returns the next key ID - */ -keyid_t -session_key( - struct sockaddr_storage *srcadr, /* source address */ - struct sockaddr_storage *dstadr, /* destination address */ - keyid_t keyno, /* key ID */ - keyid_t private, /* private value */ - u_long lifetime /* key lifetime */ - ) -{ - EVP_MD_CTX ctx; /* message digest context */ - u_char dgst[EVP_MAX_MD_SIZE]; /* message digest */ - keyid_t keyid; /* key identifer */ - u_int32 header[10]; /* data in network byte order */ - u_int hdlen, len; - - /* - * Generate the session key and key ID. If the lifetime is - * greater than zero, install the key and call it trusted. - */ - hdlen = 0; - switch(srcadr->ss_family) { - case AF_INET: - header[0] = ((struct sockaddr_in *)srcadr)->sin_addr.s_addr; - header[1] = ((struct sockaddr_in *)dstadr)->sin_addr.s_addr; - header[2] = htonl(keyno); - header[3] = htonl(private); - hdlen = 4 * sizeof(u_int32); - break; - case AF_INET6: - memcpy(&header[0], &GET_INADDR6(*srcadr), - sizeof(struct in6_addr)); - memcpy(&header[4], &GET_INADDR6(*dstadr), - sizeof(struct in6_addr)); - header[8] = htonl(keyno); - header[9] = htonl(private); - hdlen = 10 * sizeof(u_int32); - break; - } - EVP_DigestInit(&ctx, EVP_md5()); - EVP_DigestUpdate(&ctx, (u_char *)header, hdlen); - EVP_DigestFinal(&ctx, dgst, &len); - memcpy(&keyid, dgst, 4); - keyid = ntohl(keyid); - if (lifetime != 0) { - MD5auth_setkey(keyno, dgst, len); - authtrust(keyno, lifetime); - } -#ifdef DEBUG - if (debug > 1) - printf( - "session_key: %s > %s %08x %08x hash %08x life %lu\n", - stoa(srcadr), stoa(dstadr), 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 */ - ) -{ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; /* NTP timestamp */ - struct autokey *ap; /* autokey pointer */ - struct value *vp; /* value pointer */ - keyid_t keyid = 0; /* next key ID */ - keyid_t cookie; /* private value */ - u_long lifetime; - u_int len; - int i; - - /* - * Allocate the key list if necessary. - */ - tstamp = crypto_time(); - if (peer->keylist == NULL) - peer->keylist = 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. - */ - lifetime = min(sys_automax, (unsigned long) NTP_MAXSESSION * (1 <<(peer->kpoll))); - if (peer->hmode == MODE_BROADCAST) - cookie = 0; - else - cookie = peer->pcookie; - for (i = 0; i < NTP_MAXSESSION; i++) { - peer->keylist[i] = keyid; - peer->keynumber = i; - keyid = session_key(&dstadr->sin, &peer->srcadr, keyid, - cookie, lifetime); - lifetime -= 1 << peer->kpoll; - if (auth_havekey(keyid) || keyid <= NTP_MAXKEY || - lifetime <= (unsigned long)(1 << (peer->kpoll))) - break; - } - - /* - * Save the last session key ID, sequence number and timestamp, - * then sign these values for later retrieval by the clients. Be - * careful not to use invalid key media. Use the public values - * timestamp as filestamp. - */ - vp = &peer->sndval; - if (vp->ptr == NULL) - vp->ptr = emalloc(sizeof(struct autokey)); - ap = (struct autokey *)vp->ptr; - ap->seq = htonl(peer->keynumber); - ap->key = htonl(keyid); - vp->tstamp = htonl(tstamp); - vp->fstamp = hostval.tstamp; - vp->vallen = htonl(sizeof(struct autokey)); - vp->siglen = 0; - if (vp->tstamp != 0) { - if (vp->sig == NULL) - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)vp, 12); - EVP_SignUpdate(&ctx, vp->ptr, sizeof(struct autokey)); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - else - msyslog(LOG_ERR, "make_keys %s\n", - ERR_error_string(ERR_get_error(), NULL)); - peer->flags |= FLAG_ASSOC; - } -#ifdef DEBUG - if (debug) - printf("make_keys: %d %08x %08x ts %u fs %u poll %d\n", - ntohl(ap->seq), ntohl(ap->key), cookie, - ntohl(vp->tstamp), ntohl(vp->fstamp), peer->kpoll); -#endif -} - - -/* - * 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 proventic - * bit is not set. - */ -int -crypto_recv( - struct peer *peer, /* peer structure pointer */ - struct recvbuf *rbufp /* packet buffer pointer */ - ) -{ - const EVP_MD *dp; /* message digest algorithm */ - u_int32 *pkt; /* receive packet pointer */ - struct autokey *ap, *bp; /* autokey pointer */ - struct exten *ep, *fp; /* extension pointers */ - int has_mac; /* length of MAC field */ - int authlen; /* offset of MAC field */ - associd_t associd; /* association ID */ - tstamp_t tstamp = 0; /* timestamp */ - tstamp_t fstamp = 0; /* filestamp */ - u_int len; /* extension field length */ - u_int code; /* extension field opcode */ - u_int vallen = 0; /* value length */ - X509 *cert; /* X509 certificate */ - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - keyid_t cookie; /* crumbles */ - int rval = XEVNT_OK; - u_char *ptr; - u_int32 temp32; -#ifdef KERNEL_PLL -#if NTP_API > 3 - struct timex ntv; /* kernel interface structure */ -#endif /* NTP_API */ -#endif /* KERNEL_PLL */ - - /* - * Initialize. Note that the packet has already been checked for - * valid format and extension field lengths. First extract the - * field length, command code and association ID in host byte - * order. These are used with all commands and modes. Then check - * the version number, which must be 2, and length, which must - * be at least 8 for requests and VALUE_LEN (24) for responses. - * Packets that fail either test sink without a trace. The - * association ID is saved only if nonzero. - */ - authlen = LEN_PKT_NOMAC; - while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) { - pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4; - ep = (struct exten *)pkt; - code = ntohl(ep->opcode) & 0xffff0000; - len = ntohl(ep->opcode) & 0x0000ffff; - associd = (associd_t) ntohl(pkt[1]); - rval = XEVNT_OK; -#ifdef DEBUG - if (debug) - printf( - "crypto_recv: flags 0x%x ext offset %d len %u code %x assocID %d\n", - peer->crypto, authlen, len, code >> 16, - associd); -#endif - - /* - * Check version number and field length. If bad, - * quietly ignore the packet. - */ - if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8 || - (len < VALUE_LEN && (code & CRYPTO_RESP))) { - sys_unknownversion++; - code |= CRYPTO_ERROR; - } - - /* - * Little vulnerability bandage here. If a perp tosses a - * fake association ID over the fence, we better toss it - * out. Only the first one counts. - */ - if (code & CRYPTO_RESP) { - if (peer->assoc == 0) - peer->assoc = associd; - else if (peer->assoc != associd) - code |= CRYPTO_ERROR; - } - if (len >= VALUE_LEN) { - tstamp = ntohl(ep->tstamp); - fstamp = ntohl(ep->fstamp); - vallen = ntohl(ep->vallen); - } - switch (code) { - - /* - * Install status word, host name, signature scheme and - * association ID. In OpenSSL the signature algorithm is - * bound to the digest algorithm, so the NID completely - * defines the signature scheme. Note the request and - * response are identical, but neither is validated by - * signature. The request is processed here only in - * symmetric modes. The server name field would be - * useful to implement access controls in future. - */ - case CRYPTO_ASSOC: - - /* - * Pass the extension field to the transmit - * side. - */ - fp = emalloc(len); - memcpy(fp, ep, len); - temp32 = CRYPTO_RESP; - fp->opcode |= htonl(temp32); - peer->cmmd = fp; - /* fall through */ - - case CRYPTO_ASSOC | CRYPTO_RESP: - - /* - * Discard the message if it has already been - * stored or the server is not synchronized. - */ - if (peer->crypto || !fstamp) - break; - - if (len < VALUE_LEN + vallen) { - rval = XEVNT_LEN; - break; - } - - /* - * Check the identity schemes are compatible. If - * the client has PC, the server must have PC, - * in which case the server public key and - * identity are presumed valid, so we skip the - * certificate and identity exchanges and move - * immediately to the cookie exchange which - * confirms the server signature. If the client - * has IFF or GC or both, the server must have - * the same one or both. Otherwise, the default - * TC scheme is used. - */ - if (crypto_flags & CRYPTO_FLAG_PRIV) { - if (!(fstamp & CRYPTO_FLAG_PRIV)) - rval = XEVNT_KEY; - else - fstamp |= CRYPTO_FLAG_VALID | - CRYPTO_FLAG_VRFY; - } else if (crypto_flags & CRYPTO_FLAG_MASK && - !(crypto_flags & fstamp & - CRYPTO_FLAG_MASK)) { - rval = XEVNT_KEY; - } - - /* - * Discard the message if identity error. - */ - if (rval != XEVNT_OK) - break; - - /* - * Discard the message if the host name length - * is unreasonable or the signature digest NID - * is not supported. - */ - temp32 = (fstamp >> 16) & 0xffff; - dp = - (const EVP_MD *)EVP_get_digestbynid(temp32); - if (vallen == 0 || vallen > MAXHOSTNAME) - rval = XEVNT_LEN; - else if (dp == NULL) - rval = XEVNT_MD; - if (rval != XEVNT_OK) - break; - - /* - * Save status word, host name and message - * digest/signature type. If PC identity, be - * sure not to sign the certificate. - */ - if (crypto_flags & CRYPTO_FLAG_PRIV) - fstamp |= CRYPTO_FLAG_SIGN; - peer->crypto = fstamp; - peer->digest = dp; - peer->subject = emalloc(vallen + 1); - memcpy(peer->subject, ep->pkt, vallen); - peer->subject[vallen] = '\0'; - peer->issuer = emalloc(vallen + 1); - strcpy(peer->issuer, peer->subject); - temp32 = (fstamp >> 16) & 0xffff; - sprintf(statstr, - "flags 0x%x host %s signature %s", fstamp, - peer->subject, OBJ_nid2ln(temp32)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Decode X509 certificate in ASN.1 format and extract - * the data containing, among other things, subject - * name and public key. In the default identification - * scheme, the certificate trail is followed to a self - * signed trusted certificate. - */ - case CRYPTO_CERT | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * already confirmed. - */ - if (peer->crypto & CRYPTO_FLAG_VRFY) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * Scan the certificate list to delete old - * versions and link the newest version first on - * the list. - */ - if ((rval = cert_install(ep, peer)) != XEVNT_OK) - break; - - /* - * If we snatch the certificate before the - * server certificate has been signed by its - * server, it will be self signed. When it is, - * we chase the certificate issuer, which the - * server has, and keep going until a self - * signed trusted certificate is found. Be sure - * to update the issuer field, since it may - * change. - */ - if (peer->issuer != NULL) - free(peer->issuer); - peer->issuer = emalloc(strlen(cinfo->issuer) + - 1); - strcpy(peer->issuer, cinfo->issuer); - - /* - * We plug in the public key and group key in - * the first certificate received. However, note - * that this certificate might not be signed by - * the server, so we can't check the - * signature/digest NID. - */ - if (peer->pkey == NULL) { - ptr = (u_char *)cinfo->cert.ptr; - cert = d2i_X509(NULL, &ptr, - ntohl(cinfo->cert.vallen)); - peer->pkey = X509_get_pubkey(cert); - X509_free(cert); - } - peer->flash &= ~TEST10; - temp32 = cinfo->nid; - sprintf(statstr, "cert %s 0x%x %s (%u) fs %u", - cinfo->subject, cinfo->flags, - OBJ_nid2ln(temp32), temp32, - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Schnorr (IFF)identity scheme. This scheme is designed - * for use with shared secret group keys and where the - * certificate may be generated by a third party. The - * client sends a challenge to the server, which - * performs a calculation and returns the result. A - * positive result is possible only if both client and - * server contain the same secret group key. - */ - case CRYPTO_IFF | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * already confirmed. - */ - if (peer->crypto & CRYPTO_FLAG_VRFY) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * If the the challenge matches the response, - * the certificate public key, as well as the - * server public key, signatyre and identity are - * all verified at the same time. The server is - * declared trusted, so we skip further - * certificate stages and move immediately to - * the cookie stage. - */ - if ((rval = crypto_iff(ep, peer)) != XEVNT_OK) - break; - - peer->crypto |= CRYPTO_FLAG_VRFY | - CRYPTO_FLAG_PROV; - peer->flash &= ~TEST10; - sprintf(statstr, "iff fs %u", - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Guillou-Quisquater (GQ) identity scheme. This scheme - * is designed for use with public certificates carrying - * the GQ public key in an extension field. The client - * sends a challenge to the server, which performs a - * calculation and returns the result. A positive result - * is possible only if both client and server contain - * the same group key and the server has the matching GQ - * private key. - */ - case CRYPTO_GQ | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * already confirmed. - */ - if (peer->crypto & CRYPTO_FLAG_VRFY) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * If the the challenge matches the response, - * the certificate public key, as well as the - * server public key, signatyre and identity are - * all verified at the same time. The server is - * declared trusted, so we skip further - * certificate stages and move immediately to - * the cookie stage. - */ - if ((rval = crypto_gq(ep, peer)) != XEVNT_OK) - break; - - peer->crypto |= CRYPTO_FLAG_VRFY | - CRYPTO_FLAG_PROV; - peer->flash &= ~TEST10; - sprintf(statstr, "gq fs %u", - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * MV - */ - case CRYPTO_MV | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * already confirmed. - */ - if (peer->crypto & CRYPTO_FLAG_VRFY) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * If the the challenge matches the response, - * the certificate public key, as well as the - * server public key, signatyre and identity are - * all verified at the same time. The server is - * declared trusted, so we skip further - * certificate stages and move immediately to - * the cookie stage. - */ - if ((rval = crypto_mv(ep, peer)) != XEVNT_OK) - break; - - peer->crypto |= CRYPTO_FLAG_VRFY | - CRYPTO_FLAG_PROV; - peer->flash &= ~TEST10; - sprintf(statstr, "mv fs %u", - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * X509 certificate sign response. Validate the - * certificate signed by the server and install. Later - * this can be provided to clients of this server in - * lieu of the self signed certificate in order to - * validate the public key. - */ - case CRYPTO_SIGN | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * not confirmed. - */ - if (!(peer->crypto & CRYPTO_FLAG_VRFY)) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * Scan the certificate list to delete old - * versions and link the newest version first on - * the list. - */ - if ((rval = cert_install(ep, peer)) != XEVNT_OK) break; - - peer->crypto |= CRYPTO_FLAG_SIGN; - peer->flash &= ~TEST10; - temp32 = cinfo->nid; - sprintf(statstr, "sign %s 0x%x %s (%u) fs %u", - cinfo->issuer, cinfo->flags, - OBJ_nid2ln(temp32), temp32, - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Cookie request in symmetric modes. Roll a random - * cookie and install in symmetric mode. Encrypt for the - * response, which is transmitted later. - */ - case CRYPTO_COOK: - - /* - * Discard the message if invalid or identity - * not confirmed. - */ - if (!(peer->crypto & CRYPTO_FLAG_VRFY)) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * Pass the extension field to the transmit - * side. If already agreed, walk away. - */ - fp = emalloc(len); - memcpy(fp, ep, len); - temp32 = CRYPTO_RESP; - fp->opcode |= htonl(temp32); - peer->cmmd = fp; - if (peer->crypto & CRYPTO_FLAG_AGREE) { - peer->flash &= ~TEST10; - break; - } - - /* - * Install cookie values and light the cookie - * bit. The transmit side will pick up and - * encrypt it for the response. - */ - key_expire(peer); - peer->cookval.tstamp = ep->tstamp; - peer->cookval.fstamp = ep->fstamp; - RAND_bytes((u_char *)&peer->pcookie, 4); - peer->crypto &= ~CRYPTO_FLAG_AUTO; - peer->crypto |= CRYPTO_FLAG_AGREE; - peer->flash &= ~TEST10; - sprintf(statstr, "cook %x ts %u fs %u", - peer->pcookie, ntohl(ep->tstamp), - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Cookie response in client and symmetric modes. If the - * cookie bit is set, the working cookie is the EXOR of - * the current and new values. - */ - case CRYPTO_COOK | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * not confirmed or signature not verified with - * respect to the cookie values. - */ - if (!(peer->crypto & CRYPTO_FLAG_VRFY)) - break; - - if ((rval = crypto_verify(ep, &peer->cookval, - peer)) != XEVNT_OK) - break; - - /* - * Decrypt the cookie, hunting all the time for - * errors. - */ - if (vallen == (u_int) EVP_PKEY_size(host_pkey)) { - RSA_private_decrypt(vallen, - (u_char *)ep->pkt, - (u_char *)&temp32, - host_pkey->pkey.rsa, - RSA_PKCS1_OAEP_PADDING); - cookie = ntohl(temp32); - } else { - rval = XEVNT_CKY; - break; - } - - /* - * Install cookie values and light the cookie - * bit. If this is not broadcast client mode, we - * are done here. - */ - key_expire(peer); - peer->cookval.tstamp = ep->tstamp; - peer->cookval.fstamp = ep->fstamp; - if (peer->crypto & CRYPTO_FLAG_AGREE) - peer->pcookie ^= cookie; - else - peer->pcookie = cookie; - if (peer->hmode == MODE_CLIENT && - !(peer->cast_flags & MDF_BCLNT)) - peer->crypto |= CRYPTO_FLAG_AUTO; - else - peer->crypto &= ~CRYPTO_FLAG_AUTO; - peer->crypto |= CRYPTO_FLAG_AGREE; - peer->flash &= ~TEST10; - sprintf(statstr, "cook %x ts %u fs %u", - peer->pcookie, ntohl(ep->tstamp), - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Install autokey values in broadcast client and - * symmetric modes. We have to do this every time the - * sever/peer cookie changes or a new keylist is - * rolled. Ordinarily, this is automatic as this message - * is piggybacked on the first NTP packet sent upon - * either of these events. Note that a broadcast client - * or symmetric peer can receive this response without a - * matching request. - */ - case CRYPTO_AUTO | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * not confirmed or signature not verified with - * respect to the receive autokey values. - */ - if (!(peer->crypto & CRYPTO_FLAG_VRFY)) - break; - - if ((rval = crypto_verify(ep, &peer->recval, - peer)) != XEVNT_OK) - break; - - /* - * Install autokey values and light the - * autokey bit. This is not hard. - */ - if (peer->recval.ptr == NULL) - peer->recval.ptr = - emalloc(sizeof(struct autokey)); - bp = (struct autokey *)peer->recval.ptr; - peer->recval.tstamp = ep->tstamp; - peer->recval.fstamp = ep->fstamp; - ap = (struct autokey *)ep->pkt; - bp->seq = ntohl(ap->seq); - bp->key = ntohl(ap->key); - peer->pkeyid = bp->key; - peer->crypto |= CRYPTO_FLAG_AUTO; - peer->flash &= ~TEST10; - sprintf(statstr, - "auto seq %d key %x ts %u fs %u", bp->seq, - bp->key, ntohl(ep->tstamp), - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * Install leapseconds table in symmetric modes. This - * table is proventicated to the NIST primary servers, - * either by copying the file containing the table from - * a NIST server to a trusted server or directly using - * this protocol. While the entire table is installed at - * the server, presently only the current TAI offset is - * provided via the kernel to other applications. - */ - case CRYPTO_TAI: - - /* - * Discard the message if invalid or identity - * not confirmed. - */ - if (!(peer->crypto & CRYPTO_FLAG_VRFY)) - break; - - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) - break; - - /* - * Pass the extension field to the transmit - * side. Continue below if a leapseconds table - * accompanies the message. - */ - fp = emalloc(len); - memcpy(fp, ep, len); - temp32 = CRYPTO_RESP; - fp->opcode |= htonl(temp32); - peer->cmmd = fp; - if (len <= VALUE_LEN) { - peer->flash &= ~TEST10; - break; - } - /* fall through */ - - case CRYPTO_TAI | CRYPTO_RESP: - - /* - * Discard the message if invalid or identity - * not confirmed or signature not verified with - * respect to the leapsecond table values. - */ - if (!(peer->crypto & CRYPTO_FLAG_VRFY)) - break; - - if ((rval = crypto_verify(ep, &peer->tai_leap, - peer)) != XEVNT_OK) - break; - - /* - * Initialize peer variables, leapseconds - * structure and extension field in network byte - * order. Since a filestamp may have changed, - * recompute the signatures. - */ - peer->tai_leap.tstamp = ep->tstamp; - peer->tai_leap.fstamp = ep->fstamp; - peer->tai_leap.vallen = ep->vallen; - - /* - * Install the new table if there is no stored - * table or the new table is more recent than - * the stored table. Since a filestamp may have - * changed, recompute the signatures. - */ - if (ntohl(peer->tai_leap.fstamp) > - ntohl(tai_leap.fstamp)) { - tai_leap.fstamp = ep->fstamp; - tai_leap.vallen = ep->vallen; - if (tai_leap.ptr != NULL) - free(tai_leap.ptr); - tai_leap.ptr = emalloc(vallen); - memcpy(tai_leap.ptr, ep->pkt, vallen); - crypto_update(); - sys_tai = vallen / 4 + TAI_1972 - 1; - } - crypto_flags |= CRYPTO_FLAG_TAI; - peer->crypto |= CRYPTO_FLAG_LEAP; - peer->flash &= ~TEST10; -#ifdef KERNEL_PLL -#if NTP_API > 3 - /* - * If the kernel cooperates, initialize the - * current TAI offset. - */ - ntv.modes = MOD_TAI; - ntv.constant = sys_tai; - (void)ntp_adjtime(&ntv); -#endif /* NTP_API */ -#endif /* KERNEL_PLL */ - sprintf(statstr, "leap %u ts %u fs %u", - vallen, ntohl(ep->tstamp), - ntohl(ep->fstamp)); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - - /* - * We come here in symmetric modes for miscellaneous - * commands that have value fields but are processed on - * the transmit side. All we need do here is check for - * valid field length. Remaining checks are below and on - * the transmit side. - */ - case CRYPTO_IFF: - case CRYPTO_GQ: - case CRYPTO_MV: - case CRYPTO_SIGN: - if (len < VALUE_LEN) { - rval = XEVNT_LEN; - break; - } - - /* fall through */ - - /* - * We come here for miscellaneous requests and unknown - * requests and responses. If an unknown response or - * error, forget it. If a request, save the extension - * field for later. Unknown requests will be caught on - * the transmit side. - */ - default: - if (code & (CRYPTO_RESP | CRYPTO_ERROR)) { - rval = XEVNT_LEN; - } else if ((rval = crypto_verify(ep, NULL, - peer)) == XEVNT_OK) { - fp = emalloc(len); - memcpy(fp, ep, len); - temp32 = CRYPTO_RESP; - fp->opcode |= htonl(temp32); - peer->cmmd = fp; - } - } - - /* - * We log everything except length/format errors and - * duplicates, which are log clogging vulnerabilities. - * The first error found terminates the extension field - * scan and we return the laundry to the caller. - */ - if (rval != XEVNT_OK) { - sprintf(statstr, - "error %x opcode %x ts %u fs %u", rval, - code, tstamp, fstamp); - if (rval > XEVNT_TSP) - record_crypto_stats(&peer->srcadr, - statstr); - report_event(rval, peer); -#ifdef DEBUG - if (debug) - printf("crypto_recv: %s\n", statstr); -#endif - break; - } - authlen += len; - } - return (rval); -} - - -/* - * 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 is to retrieve the - * autokey information, in which case the caller has to provide the - * association ID to match the association. - * - * Returns length of extension field. - */ -int -crypto_xmit( - struct pkt *xpkt, /* transmit packet pointer */ - struct sockaddr_storage *srcadr_sin, /* active runway */ - int start, /* offset to extension field */ - struct exten *ep, /* extension pointer */ - keyid_t cookie /* session cookie */ - ) -{ - u_int32 *pkt; /* packet pointer */ - struct peer *peer; /* peer structure pointer */ - u_int opcode; /* extension field opcode */ - struct exten *fp; /* extension pointers */ - struct cert_info *cp; /* certificate info/value pointer */ - char certname[MAXHOSTNAME + 1]; /* subject name buffer */ - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - u_int vallen; - u_int len; - struct value vtemp; - associd_t associd; - int rval; - keyid_t tcookie; - - /* - * Generate the requested extension field request code, length - * and association ID. If this is a response and the host is not - * synchronized, light the error bit and go home. - */ - pkt = (u_int32 *)xpkt + start / 4; - fp = (struct exten *)pkt; - opcode = ntohl(ep->opcode); - associd = (associd_t) ntohl(ep->associd); - fp->associd = htonl(associd); - len = 8; - rval = XEVNT_OK; - switch (opcode & 0xffff0000) { - - /* - * Send association request and response with status word and - * host name. Note, this message is not signed and the filestamp - * contains only the status word. We check at this point whether - * the identity schemes are compatible to save tears later on. - */ - case CRYPTO_ASSOC | CRYPTO_RESP: - case CRYPTO_ASSOC: - len += crypto_send(fp, &hostval); - if (crypto_time() == 0) - fp->fstamp = 0; - else - fp->fstamp = htonl(crypto_flags); - break; - - /* - * Send certificate request. Use the values from the extension - * field. - */ - case CRYPTO_CERT: - memset(&vtemp, 0, sizeof(vtemp)); - vtemp.tstamp = ep->tstamp; - vtemp.fstamp = ep->fstamp; - vtemp.vallen = ep->vallen; - vtemp.ptr = (unsigned char *)ep->pkt; - len += crypto_send(fp, &vtemp); - break; - - /* - * Send certificate response or sign request. Use the values - * from the certificate. If the request contains no subject - * name, assume the name of this host. This is for backwards - * compatibility. Light the error bit if no certificate with - * the given subject name is found. Of course, private - * certificates are never sent. - */ - case CRYPTO_SIGN: - case CRYPTO_CERT | CRYPTO_RESP: - vallen = ntohl(ep->vallen); - if (vallen == 8) { - strcpy(certname, sys_hostname); - } else if (vallen == 0 || vallen > MAXHOSTNAME) { - opcode |= CRYPTO_ERROR; - break; - - } else { - memcpy(certname, ep->pkt, vallen); - certname[vallen] = '\0'; - } - for (cp = cinfo; cp != NULL; cp = cp->link) { - if (cp->flags & CERT_PRIV) - continue; - if (strcmp(certname, cp->subject) == 0) { - len += crypto_send(fp, &cp->cert); - break; - } - } - if (cp == NULL) - opcode |= CRYPTO_ERROR; - break; - - /* - * Send challenge in Schnorr (IFF) identity scheme. - */ - case CRYPTO_IFF: - if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { - opcode |= CRYPTO_ERROR; - break; - } - if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send response in Schnorr (IFF) identity scheme. - */ - case CRYPTO_IFF | CRYPTO_RESP: - if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send challenge in Guillou-Quisquater (GQ) identity scheme. - */ - case CRYPTO_GQ: - if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { - opcode |= CRYPTO_ERROR; - break; - } - if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send response in Guillou-Quisquater (GQ) identity scheme. - */ - case CRYPTO_GQ | CRYPTO_RESP: - if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send challenge in MV identity scheme. - */ - case CRYPTO_MV: - if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { - opcode |= CRYPTO_ERROR; - break; - } - if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send response in MV identity scheme. - */ - case CRYPTO_MV | CRYPTO_RESP: - if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send certificate sign response. The integrity of the request - * certificate has already been verified on the receive side. - * Sign the response using the local server key. Use the - * filestamp from the request and use the timestamp as the - * current time. Light the error bit if the certificate is - * invalid or contains an unverified signature. - */ - case CRYPTO_SIGN | CRYPTO_RESP: - if ((rval = cert_sign(ep, &vtemp)) == XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Send public key and signature. Use the values from the public - * key. - */ - case CRYPTO_COOK: - len += crypto_send(fp, &pubkey); - break; - - /* - * Encrypt and send cookie and signature. Light the error bit if - * anything goes wrong. - */ - case CRYPTO_COOK | CRYPTO_RESP: - if ((opcode & 0xffff) < VALUE_LEN) { - opcode |= CRYPTO_ERROR; - break; - } - if (PKT_MODE(xpkt->li_vn_mode) == MODE_SERVER) { - tcookie = cookie; - } else { - if ((peer = findpeerbyassoc(associd)) == NULL) { - opcode |= CRYPTO_ERROR; - break; - } - tcookie = peer->pcookie; - } - if ((rval = crypto_encrypt(ep, &vtemp, &tcookie)) == - XEVNT_OK) - len += crypto_send(fp, &vtemp); - value_free(&vtemp); - break; - - /* - * Find peer and send autokey data and signature in broadcast - * server and symmetric modes. Use the values in the autokey - * structure. If no association is found, either the server has - * restarted with new associations or some perp has replayed an - * old message, in which case light the error bit. - */ - case CRYPTO_AUTO | CRYPTO_RESP: - if ((peer = findpeerbyassoc(associd)) == NULL) { - opcode |= CRYPTO_ERROR; - break; - } - peer->flags &= ~FLAG_ASSOC; - len += crypto_send(fp, &peer->sndval); - break; - - /* - * Send leapseconds table and signature. Use the values from the - * tai structure. If no table has been loaded, just send a - * request. - */ - case CRYPTO_TAI: - case CRYPTO_TAI | CRYPTO_RESP: - if (crypto_flags & CRYPTO_FLAG_TAI) - len += crypto_send(fp, &tai_leap); - break; - - /* - * Default - Fall through for requests; for unknown responses, - * flag as error. - */ - default: - if (opcode & CRYPTO_RESP) - opcode |= CRYPTO_ERROR; - } - - /* - * We ignore length/format errors and duplicates. Other errors - * are reported to the log and deny further service. To really - * persistent rascals we toss back a kiss-of-death grenade. - */ - if (rval > XEVNT_TSP) { - opcode |= CRYPTO_ERROR; - sprintf(statstr, "error %x opcode %x", rval, opcode); - record_crypto_stats(srcadr_sin, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_xmit: %s\n", statstr); -#endif - } - - /* - * Round up the field length to a multiple of 8 bytes and save - * the request code and length. - */ - len = ((len + 7) / 8) * 8; - fp->opcode = htonl((opcode & 0xffff0000) | len); -#ifdef DEBUG - if (debug) - printf( - "crypto_xmit: ext offset %d len %u code %x assocID %d\n", - start, len, opcode>> 16, associd); -#endif - return (len); -} - - -/* - * crypto_verify - parse and verify the extension field and value - * - * Returns - * XEVNT_OK success - * XEVNT_LEN bad field format or length - * XEVNT_TSP bad timestamp - * XEVNT_FSP bad filestamp - * XEVNT_PUB bad or missing public key - * XEVNT_SGL bad signature length - * XEVNT_SIG signature not verified - */ -static int -crypto_verify( - struct exten *ep, /* extension pointer */ - struct value *vp, /* value pointer */ - struct peer *peer /* peer structure pointer */ - ) -{ - EVP_PKEY *pkey; /* server public key */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; /* timestamp */ - tstamp_t fstamp; /* filestamp */ - u_int vallen; /* value length */ - u_int siglen; /* signature length */ - u_int opcode, len; - int rval; - int i; - - /* - * We require valid opcode and field length, timestamp, - * filestamp, public key, digest, signature length and - * signature, where relevant. Note that preliminary length - * checks are done in the main loop. - */ - len = ntohl(ep->opcode) & 0x0000ffff; - opcode = ntohl(ep->opcode) & 0xffff0000; - - /* - * Check for valid operation code and protocol. The opcode must - * not have the error bit set. If a response, it must have a - * value header. If a request and does not contain a value - * header, no need for further checking. - */ - if (opcode & CRYPTO_ERROR) - return (XEVNT_LEN); - if (opcode & CRYPTO_RESP) { - if (len < VALUE_LEN) - return (XEVNT_LEN); - } else { - if (len < VALUE_LEN) - return (XEVNT_OK); - } - /* - * We have a value header. Check for valid field lengths. The - * field length must be long enough to contain the value header, - * value and signature. If a request and a previous request of - * the same type is pending, discard the previous request. If a - * request but no signature, there is no need for further - * checking. - */ - vallen = ntohl(ep->vallen); - if (len < ((VALUE_LEN + vallen + 3) / 4) * 4) - return (XEVNT_LEN); - - i = (vallen + 3) / 4; - siglen = ntohl(ep->pkt[i++]); - if (len < VALUE_LEN + vallen + siglen) - return (XEVNT_LEN); - - if (!(opcode & CRYPTO_RESP)) { - if (peer->cmmd != NULL) { - if ((opcode | CRYPTO_RESP) == - (ntohl(peer->cmmd->opcode) & 0xffff0000)) { - free(peer->cmmd); - peer->cmmd = NULL; - } else { - return (XEVNT_LEN); - } - } - if (siglen == 0) - return (XEVNT_OK); - } - - /* - * We have a signature. Check for valid timestamp and filestamp. - * The timestamp must not precede the filestamp. The timestamp - * and filestamp must not precede the corresponding values in - * the value structure. Once the autokey values have been - * installed, the timestamp must always be later than the - * corresponding value in the value structure. Duplicate - * timestamps are illegal once the cookie has been validated. - */ - rval = XEVNT_OK; - if (crypto_flags & peer->crypto & CRYPTO_FLAG_PRIV) - pkey = sign_pkey; - else - pkey = peer->pkey; - tstamp = ntohl(ep->tstamp); - fstamp = ntohl(ep->fstamp); - if (tstamp == 0 || tstamp < fstamp) { - rval = XEVNT_TSP; - } else if (vp != NULL && (tstamp < ntohl(vp->tstamp) || - (tstamp == ntohl(vp->tstamp) && (peer->crypto & - CRYPTO_FLAG_AUTO)))) { - rval = XEVNT_TSP; - } else if (vp != NULL && (tstamp < ntohl(vp->fstamp) || fstamp < - ntohl(vp->fstamp))) { - rval = XEVNT_FSP; - - /* - * If a public key and digest is present, and if valid key - * length, check for valid signature. Note that the first valid - * signature lights the proventic bit. - */ - } else if (pkey == NULL || peer->digest == NULL) { - /* fall through */ - } else if (siglen != (u_int) EVP_PKEY_size(pkey)) { - rval = XEVNT_SGL; - } else { - EVP_VerifyInit(&ctx, peer->digest); - EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + - 12); - if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen, - pkey)) { - if (peer->crypto & CRYPTO_FLAG_VRFY) - peer->crypto |= CRYPTO_FLAG_PROV; - } else { - rval = XEVNT_SIG; - } - } -#ifdef DEBUG - if (debug > 1) - printf( - "crypto_recv: verify %x vallen %u siglen %u ts %u fs %u\n", - rval, vallen, siglen, tstamp, fstamp); -#endif - return (rval); -} - - -/* - * crypto_encrypt - construct encrypted cookie and signature from - * extension field and cookie - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_CKY bad or missing cookie - */ -static int -crypto_encrypt( - struct exten *ep, /* extension pointer */ - struct value *vp, /* value pointer */ - keyid_t *cookie /* server cookie */ - ) -{ - EVP_PKEY *pkey; /* public key */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; /* NTP timestamp */ - u_int32 temp32; - u_int len; - u_char *ptr; - - /* - * Extract the public key from the request. - */ - len = ntohl(ep->vallen); - ptr = (u_char *)ep->pkt; - pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len); - if (pkey == NULL) { - msyslog(LOG_ERR, "crypto_encrypt %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Encrypt the cookie, encode in ASN.1 and sign. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = hostval.tstamp; - len = EVP_PKEY_size(pkey); - vp->vallen = htonl(len); - vp->ptr = emalloc(len); - temp32 = htonl(*cookie); - if (!RSA_public_encrypt(4, (u_char *)&temp32, vp->ptr, - pkey->pkey.rsa, RSA_PKCS1_OAEP_PADDING)) { - msyslog(LOG_ERR, "crypto_encrypt %s\n", - ERR_error_string(ERR_get_error(), NULL)); - EVP_PKEY_free(pkey); - return (XEVNT_CKY); - } - EVP_PKEY_free(pkey); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_ident - construct extension field for identity scheme - * - * This routine determines which identity scheme is in use and - * constructs an extension field for that scheme. - */ -u_int -crypto_ident( - struct peer *peer /* peer structure pointer */ - ) -{ - char filename[MAXFILENAME + 1]; - - /* - * If the server identity has already been verified, no further - * action is necessary. Otherwise, try to load the identity file - * of the certificate issuer. If the issuer file is not found, - * try the host file. If nothing found, declare a cryptobust. - * Note we can't get here unless the trusted certificate has - * been found and the CRYPTO_FLAG_VALID bit is set, so the - * certificate issuer is valid. - */ - if (peer->crypto & CRYPTO_FLAG_VRFY) - return (0); - - if (peer->ident_pkey != NULL) - EVP_PKEY_free(peer->ident_pkey); - if (peer->crypto & CRYPTO_FLAG_GQ) { - snprintf(filename, MAXFILENAME, "ntpkey_gq_%s", - peer->issuer); - peer->ident_pkey = crypto_key(filename, &peer->fstamp); - if (peer->ident_pkey != NULL) - return (CRYPTO_GQ); - - snprintf(filename, MAXFILENAME, "ntpkey_gq_%s", - sys_hostname); - peer->ident_pkey = crypto_key(filename, &peer->fstamp); - if (peer->ident_pkey != NULL) - return (CRYPTO_GQ); - } - if (peer->crypto & CRYPTO_FLAG_IFF) { - snprintf(filename, MAXFILENAME, "ntpkey_iff_%s", - peer->issuer); - peer->ident_pkey = crypto_key(filename, &peer->fstamp); - if (peer->ident_pkey != NULL) - return (CRYPTO_IFF); - - snprintf(filename, MAXFILENAME, "ntpkey_iff_%s", - sys_hostname); - peer->ident_pkey = crypto_key(filename, &peer->fstamp); - if (peer->ident_pkey != NULL) - return (CRYPTO_IFF); - } - if (peer->crypto & CRYPTO_FLAG_MV) { - snprintf(filename, MAXFILENAME, "ntpkey_mv_%s", - peer->issuer); - peer->ident_pkey = crypto_key(filename, &peer->fstamp); - if (peer->ident_pkey != NULL) - return (CRYPTO_MV); - - snprintf(filename, MAXFILENAME, "ntpkey_mv_%s", - sys_hostname); - peer->ident_pkey = crypto_key(filename, &peer->fstamp); - if (peer->ident_pkey != NULL) - return (CRYPTO_MV); - } - - /* - * No compatible identity scheme is available. Use the default - * TC scheme. - */ - msyslog(LOG_INFO, - "crypto_ident: no compatible identity scheme found"); - return (0); -} - - -/* - * crypto_args - construct extension field from arguments - * - * This routine creates an extension field with current timestamps and - * specified opcode, association ID and optional string. Note that the - * extension field is created here, but freed after the crypto_xmit() - * call in the protocol module. - * - * Returns extension field pointer (no errors). - */ -struct exten * -crypto_args( - struct peer *peer, /* peer structure pointer */ - u_int opcode, /* operation code */ - char *str /* argument string */ - ) -{ - tstamp_t tstamp; /* NTP timestamp */ - struct exten *ep; /* extension field pointer */ - u_int len; /* extension field length */ - - tstamp = crypto_time(); - len = sizeof(struct exten); - if (str != NULL) - len += strlen(str); - ep = emalloc(len); - memset(ep, 0, len); - ep->opcode = htonl(opcode + len); - - /* - * If a response, send our ID; if a request, send the - * responder's ID. - */ - if (opcode & CRYPTO_RESP) - ep->associd = htonl(peer->associd); - else - ep->associd = htonl(peer->assoc); - ep->tstamp = htonl(tstamp); - ep->fstamp = hostval.tstamp; - ep->vallen = 0; - if (str != NULL) { - ep->vallen = htonl(strlen(str)); - memcpy((char *)ep->pkt, str, strlen(str)); - } else { - ep->pkt[0] = peer->associd; - } - return (ep); -} - - -/* - * crypto_send - construct extension field from value components - * - * Returns extension field length. Note: it is not polite to send a - * nonempty signature with zero timestamp or a nonzero timestamp with - * empty signature, but these rules are not enforced here. - */ -u_int -crypto_send( - struct exten *ep, /* extension field pointer */ - struct value *vp /* value pointer */ - ) -{ - u_int len, temp32; - int i; - - /* - * Copy data. If the data field is empty or zero length, encode - * an empty value with length zero. - */ - ep->tstamp = vp->tstamp; - ep->fstamp = vp->fstamp; - ep->vallen = vp->vallen; - len = 12; - temp32 = ntohl(vp->vallen); - if (temp32 > 0 && vp->ptr != NULL) - memcpy(ep->pkt, vp->ptr, temp32); - - /* - * Copy signature. If the signature field is empty or zero - * length, encode an empty signature with length zero. - */ - i = (temp32 + 3) / 4; - len += i * 4 + 4; - ep->pkt[i++] = vp->siglen; - temp32 = ntohl(vp->siglen); - if (temp32 > 0 && vp->sig != NULL) - memcpy(&ep->pkt[i], vp->sig, temp32); - len += temp32; - return (len); -} - - -/* - * crypto_update - compute new public value and sign extension fields - * - * This routine runs periodically, like once a day, and when something - * changes. It updates the timestamps on three value structures and one - * value structure list, then signs all the structures: - * - * hostval host name (not signed) - * pubkey public key - * cinfo certificate info/value list - * tai_leap leapseconds file - * - * Filestamps are proventicated data, so this routine is run only when - * the host has been synchronized to a proventicated source. Thus, the - * timestamp is proventicated, too, and can be used to deflect - * clogging attacks and even cook breakfast. - * - * Returns void (no errors) - */ -void -crypto_update(void) -{ - EVP_MD_CTX ctx; /* message digest context */ - struct cert_info *cp, *cpn, **zp; /* certificate info/value */ - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - tstamp_t tstamp; /* NTP timestamp */ - u_int len; - - if ((tstamp = crypto_time()) == 0) - return; - hostval.tstamp = htonl(tstamp); - - /* - * Sign public key and timestamps. The filestamp is derived from - * the host key file extension from wherever the file was - * generated. - */ - if (pubkey.vallen != 0) { - pubkey.tstamp = hostval.tstamp; - pubkey.siglen = 0; - if (pubkey.sig == NULL) - pubkey.sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&pubkey, 12); - EVP_SignUpdate(&ctx, pubkey.ptr, ntohl(pubkey.vallen)); - if (EVP_SignFinal(&ctx, pubkey.sig, &len, sign_pkey)) - pubkey.siglen = htonl(len); - } - - /* - * Sign certificates and timestamps. The filestamp is derived - * from the certificate file extension from wherever the file - * was generated. At the same time expired certificates are - * expunged. - */ - zp = &cinfo; - for (cp = cinfo; cp != NULL; cp = cpn) { - cpn = cp->link; - if (tstamp > cp->last) { - *zp = cpn; - cert_free(cp); - } else { - cp->cert.tstamp = hostval.tstamp; - cp->cert.siglen = 0; - if (cp->cert.sig == NULL) - cp->cert.sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&cp->cert, 12); - EVP_SignUpdate(&ctx, cp->cert.ptr, - ntohl(cp->cert.vallen)); - if (EVP_SignFinal(&ctx, cp->cert.sig, &len, - sign_pkey)) - cp->cert.siglen = htonl(len); - zp = &cp->link; - } - } - - /* - * Sign leapseconds table and timestamps. The filestamp is - * derived from the leapsecond file extension from wherever the - * file was generated. - */ - if (tai_leap.vallen != 0) { - tai_leap.tstamp = hostval.tstamp; - tai_leap.siglen = 0; - if (tai_leap.sig == NULL) - tai_leap.sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&tai_leap, 12); - EVP_SignUpdate(&ctx, tai_leap.ptr, - ntohl(tai_leap.vallen)); - if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey)) - tai_leap.siglen = htonl(len); - } - sprintf(statstr, "update ts %u", ntohl(hostval.tstamp)); - record_crypto_stats(NULL, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_update: %s\n", statstr); -#endif -} - - -/* - * value_free - free value structure components. - * - * Returns void (no errors) - */ -void -value_free( - struct value *vp /* value structure */ - ) -{ - if (vp->ptr != NULL) - free(vp->ptr); - if (vp->sig != NULL) - free(vp->sig); - memset(vp, 0, sizeof(struct value)); -} - - -/* - * crypto_time - returns current NTP time in seconds. - */ -tstamp_t -crypto_time() -{ - l_fp tstamp; /* NTP time */ L_CLR(&tstamp); - - L_CLR(&tstamp); - if (sys_leap != LEAP_NOTINSYNC) - get_systime(&tstamp); - return (tstamp.l_ui); -} - - -/* - * asn2ntp - convert ASN1_TIME time structure to NTP time in seconds. - */ -u_long -asn2ntp ( - ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ - ) -{ - char *v; /* pointer to ASN1_TIME string */ - struct tm tm; /* used to convert to NTP time */ - - /* - * Extract time string YYMMDDHHMMSSZ from ASN1 time structure. - * Note that the YY, MM, DD fields start with one, the HH, MM, - * SS fiels start with zero and the Z character should be 'Z' - * for UTC. Also note that years less than 50 map to years - * greater than 100. Dontcha love ASN.1? Better than MIL-188. - */ - if (asn1time->length > 13) - return ((u_long)(~0)); /* We can't use -1 here. It's invalid */ - v = (char *)asn1time->data; - tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; - if (tm.tm_year < 50) - tm.tm_year += 100; - tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; - tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; - tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; - tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; - tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; - tm.tm_wday = 0; - tm.tm_yday = 0; - tm.tm_isdst = 0; - return (timegm(&tm) + JAN_1970); -} - - -/* - * bigdig() - compute a BIGNUM MD5 hash of a BIGNUM number. - */ -static int -bighash( - BIGNUM *bn, /* BIGNUM * from */ - BIGNUM *bk /* BIGNUM * to */ - ) -{ - EVP_MD_CTX ctx; /* message digest context */ - u_char dgst[EVP_MAX_MD_SIZE]; /* message digest */ - u_char *ptr; /* a BIGNUM as binary string */ - u_int len; - - len = BN_num_bytes(bn); - ptr = emalloc(len); - BN_bn2bin(bn, ptr); - EVP_DigestInit(&ctx, EVP_md5()); - EVP_DigestUpdate(&ctx, ptr, len); - EVP_DigestFinal(&ctx, dgst, &len); - BN_bin2bn(dgst, len, bk); - return (1); -} - - -/* - *********************************************************************** - * * - * The following routines implement the Schnorr (IFF) identity scheme * - * * - *********************************************************************** - * - * The Schnorr (IFF) identity scheme is intended for use when - * the ntp-genkeys program does not generate the certificates used in - * the protocol and the group key cannot be conveyed in the certificate - * itself. For this purpose, new generations of IFF values must be - * securely transmitted to all members of the group before use. The - * scheme is self contained and independent of new generations of host - * keys, sign keys and certificates. - * - * The IFF identity scheme is based on DSA cryptography and algorithms - * described in Stinson p. 285. The IFF values hide in a DSA cuckoo - * structure, but only the primes and generator are used. The p is a - * 512-bit prime, q a 160-bit prime that divides p - 1 and is a qth root - * of 1 mod p; that is, g^q = 1 mod p. The TA rolls primvate random - * group key b disguised as a DSA structure member, then computes public - * key g^(q - b). These values are shared only among group members and - * never revealed in messages. Alice challenges Bob to confirm identity - * using the protocol described below. - * - * How it works - * - * The scheme goes like this. Both Alice and Bob have the public primes - * p, q and generator g. The TA gives private key b to Bob and public - * key v = g^(q - a) mod p to Alice. - * - * Alice rolls new random challenge r and sends to Bob in the IFF - * request message. Bob rolls new random k, then computes y = k + b r - * mod q and x = g^k mod p and sends (y, hash(x)) to Alice in the - * response message. Besides making the response shorter, the hash makes - * it effectivey impossible for an intruder to solve for b by observing - * a number of these messages. - * - * Alice receives the response and computes g^y v^r mod p. After a bit - * of algebra, this simplifies to g^k. If the hash of this result - * matches hash(x), Alice knows that Bob has the group key b. The signed - * response binds this knowledge to Bob's private key and the public key - * previously received in his certificate. - * - * crypto_alice - construct Alice's challenge in IFF scheme - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_ID bad or missing identity parameters - */ -static int -crypto_alice( - struct peer *peer, /* peer pointer */ - struct value *vp /* value pointer */ - ) -{ - DSA *dsa; /* IFF parameters */ - BN_CTX *bctx; /* BIGNUM context */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; - u_int len; - - /* - * The identity parameters must have correct format and content. - */ - if (peer->ident_pkey == NULL) - return (XEVNT_ID); - if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) { - msyslog(LOG_INFO, "crypto_alice: defective key"); - return (XEVNT_PUB); - } - - /* - * Roll new random r (0 < r < q). The OpenSSL library has a bug - * omitting BN_rand_range, so we have to do it the hard way. - */ - bctx = BN_CTX_new(); - len = BN_num_bytes(dsa->q); - if (peer->iffval != NULL) - BN_free(peer->iffval); - peer->iffval = BN_new(); - BN_rand(peer->iffval, len * 8, -1, 1); /* r */ - BN_mod(peer->iffval, peer->iffval, dsa->q, bctx); - BN_CTX_free(bctx); - - /* - * Sign and send to Bob. The filestamp is from the local file. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = htonl(peer->fstamp); - vp->vallen = htonl(len); - vp->ptr = emalloc(len); - BN_bn2bin(peer->iffval, vp->ptr); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_bob - construct Bob's response to Alice's challenge - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - */ -static int -crypto_bob( - struct exten *ep, /* extension pointer */ - struct value *vp /* value pointer */ - ) -{ - DSA *dsa; /* IFF parameters */ - DSA_SIG *sdsa; /* DSA signature context fake */ - BN_CTX *bctx; /* BIGNUM context */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; /* NTP timestamp */ - BIGNUM *bn, *bk, *r; - u_char *ptr; - u_int len; - - /* - * If the IFF parameters are not valid, something awful - * happened or we are being tormented. - */ - if (!(crypto_flags & CRYPTO_FLAG_IFF)) { - msyslog(LOG_INFO, "crypto_bob: scheme unavailable"); - return (XEVNT_PUB); - } - dsa = iffpar_pkey->pkey.dsa; - - /* - * Extract r from the challenge. - */ - len = ntohl(ep->vallen); - if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) { - msyslog(LOG_ERR, "crypto_bob %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Bob rolls random k (0 < k < q), computes y = k + b r mod q - * and x = g^k mod p, then sends (y, hash(x)) to Alice. - */ - bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new(); - sdsa = DSA_SIG_new(); - BN_rand(bk, len * 8, -1, 1); /* k */ - BN_mod_mul(bn, dsa->priv_key, r, dsa->q, bctx); /* b r mod q */ - BN_add(bn, bn, bk); - BN_mod(bn, bn, dsa->q, bctx); /* k + b r mod q */ - sdsa->r = BN_dup(bn); - BN_mod_exp(bk, dsa->g, bk, dsa->p, bctx); /* g^k mod p */ - bighash(bk, bk); - sdsa->s = BN_dup(bk); - BN_CTX_free(bctx); - BN_free(r); BN_free(bn); BN_free(bk); - - /* - * Encode the values in ASN.1 and sign. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = htonl(if_fstamp); - len = i2d_DSA_SIG(sdsa, NULL); - if (len <= 0) { - msyslog(LOG_ERR, "crypto_bob %s\n", - ERR_error_string(ERR_get_error(), NULL)); - DSA_SIG_free(sdsa); - return (XEVNT_PUB); - } - vp->vallen = htonl(len); - ptr = emalloc(len); - vp->ptr = ptr; - i2d_DSA_SIG(sdsa, &ptr); - DSA_SIG_free(sdsa); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_iff - verify Bob's response to Alice's challenge - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_FSP bad filestamp - * XEVNT_ID bad or missing identity parameters - */ -int -crypto_iff( - struct exten *ep, /* extension pointer */ - struct peer *peer /* peer structure pointer */ - ) -{ - DSA *dsa; /* IFF parameters */ - BN_CTX *bctx; /* BIGNUM context */ - DSA_SIG *sdsa; /* DSA parameters */ - BIGNUM *bn, *bk; - u_int len; - const u_char *ptr; - int temp; - - /* - * If the IFF parameters are not valid or no challenge was sent, - * something awful happened or we are being tormented. - */ - if (peer->ident_pkey == NULL) { - msyslog(LOG_INFO, "crypto_iff: scheme unavailable"); - return (XEVNT_PUB); - } - if (ntohl(ep->fstamp) != peer->fstamp) { - msyslog(LOG_INFO, "crypto_iff: invalid filestamp %u", - ntohl(ep->fstamp)); - return (XEVNT_FSP); - } - if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) { - msyslog(LOG_INFO, "crypto_iff: defective key"); - return (XEVNT_PUB); - } - if (peer->iffval == NULL) { - msyslog(LOG_INFO, "crypto_iff: missing challenge"); - return (XEVNT_PUB); - } - - /* - * Extract the k + b r and g^k values from the response. - */ - bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new(); - len = ntohl(ep->vallen); - ptr = (const u_char *)ep->pkt; - if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) { - msyslog(LOG_ERR, "crypto_iff %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Compute g^(k + b r) g^(q - b)r mod p. - */ - BN_mod_exp(bn, dsa->pub_key, peer->iffval, dsa->p, bctx); - BN_mod_exp(bk, dsa->g, sdsa->r, dsa->p, bctx); - BN_mod_mul(bn, bn, bk, dsa->p, bctx); - - /* - * Verify the hash of the result matches hash(x). - */ - bighash(bn, bn); - temp = BN_cmp(bn, sdsa->s); - BN_free(bn); BN_free(bk); BN_CTX_free(bctx); - BN_free(peer->iffval); - peer->iffval = NULL; - DSA_SIG_free(sdsa); - if (temp == 0) - return (XEVNT_OK); - else - return (XEVNT_ID); -} - - -/* - *********************************************************************** - * * - * The following routines implement the Guillou-Quisquater (GQ) * - * identity scheme * - * * - *********************************************************************** - * - * The Guillou-Quisquater (GQ) identity scheme is intended for use when - * the ntp-genkeys program generates the certificates used in the - * protocol and the group key can be conveyed in a certificate extension - * field. The scheme is self contained and independent of new - * generations of host keys, sign keys and certificates. - * - * The GQ identity scheme is based on RSA cryptography and algorithms - * described in Stinson p. 300 (with errors). The GQ values hide in a - * RSA cuckoo structure, but only the modulus is used. The 512-bit - * public modulus is n = p q, where p and q are secret large primes. The - * TA rolls random group key b disguised as a RSA structure member. - * Except for the public key, these values are shared only among group - * members and never revealed in messages. - * - * When rolling new certificates, Bob recomputes the private and - * public keys. The private key u is a random roll, while the public key - * is the inverse obscured by the group key v = (u^-1)^b. These values - * replace the private and public keys normally generated by the RSA - * scheme. Alice challenges Bob to confirm identity using the protocol - * described below. - * - * How it works - * - * The scheme goes like this. Both Alice and Bob have the same modulus n - * and some random b as the group key. These values are computed and - * distributed in advance via secret means, although only the group key - * b is truly secret. Each has a private random private key u and public - * key (u^-1)^b, although not necessarily the same ones. Bob and Alice - * can regenerate the key pair from time to time without affecting - * operations. The public key is conveyed on the certificate in an - * extension field; the private key is never revealed. - * - * Alice rolls new random challenge r and sends to Bob in the GQ - * request message. Bob rolls new random k, then computes y = k u^r mod - * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response - * message. Besides making the response shorter, the hash makes it - * effectivey impossible for an intruder to solve for b by observing - * a number of these messages. - * - * Alice receives the response and computes y^b v^r mod n. After a bit - * of algebra, this simplifies to k^b. If the hash of this result - * matches hash(x), Alice knows that Bob has the group key b. The signed - * response binds this knowledge to Bob's private key and the public key - * previously received in his certificate. - * - * crypto_alice2 - construct Alice's challenge in GQ scheme - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_ID bad or missing identity parameters - */ -static int -crypto_alice2( - struct peer *peer, /* peer pointer */ - struct value *vp /* value pointer */ - ) -{ - RSA *rsa; /* GQ parameters */ - BN_CTX *bctx; /* BIGNUM context */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; - u_int len; - - /* - * The identity parameters must have correct format and content. - */ - if (peer->ident_pkey == NULL) - return (XEVNT_ID); - if ((rsa = peer->ident_pkey->pkey.rsa) == NULL) { - msyslog(LOG_INFO, "crypto_alice2: defective key"); - return (XEVNT_PUB); - } - - /* - * Roll new random r (0 < r < n). The OpenSSL library has a bug - * omitting BN_rand_range, so we have to do it the hard way. - */ - bctx = BN_CTX_new(); - len = BN_num_bytes(rsa->n); - if (peer->iffval != NULL) - BN_free(peer->iffval); - peer->iffval = BN_new(); - BN_rand(peer->iffval, len * 8, -1, 1); /* r mod n */ - BN_mod(peer->iffval, peer->iffval, rsa->n, bctx); - BN_CTX_free(bctx); - - /* - * Sign and send to Bob. The filestamp is from the local file. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = htonl(peer->fstamp); - vp->vallen = htonl(len); - vp->ptr = emalloc(len); - BN_bn2bin(peer->iffval, vp->ptr); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_bob2 - construct Bob's response to Alice's challenge - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - */ -static int -crypto_bob2( - struct exten *ep, /* extension pointer */ - struct value *vp /* value pointer */ - ) -{ - RSA *rsa; /* GQ parameters */ - DSA_SIG *sdsa; /* DSA parameters */ - BN_CTX *bctx; /* BIGNUM context */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; /* NTP timestamp */ - BIGNUM *r, *k, *g, *y; - u_char *ptr; - u_int len; - - /* - * If the GQ parameters are not valid, something awful - * happened or we are being tormented. - */ - if (!(crypto_flags & CRYPTO_FLAG_GQ)) { - msyslog(LOG_INFO, "crypto_bob2: scheme unavailable"); - return (XEVNT_PUB); - } - rsa = gqpar_pkey->pkey.rsa; - - /* - * Extract r from the challenge. - */ - len = ntohl(ep->vallen); - if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) { - msyslog(LOG_ERR, "crypto_bob2 %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Bob rolls random k (0 < k < n), computes y = k u^r mod n and - * x = k^b mod n, then sends (y, hash(x)) to Alice. - */ - bctx = BN_CTX_new(); k = BN_new(); g = BN_new(); y = BN_new(); - sdsa = DSA_SIG_new(); - BN_rand(k, len * 8, -1, 1); /* k */ - BN_mod(k, k, rsa->n, bctx); - BN_mod_exp(y, rsa->p, r, rsa->n, bctx); /* u^r mod n */ - BN_mod_mul(y, k, y, rsa->n, bctx); /* k u^r mod n */ - sdsa->r = BN_dup(y); - BN_mod_exp(g, k, rsa->e, rsa->n, bctx); /* k^b mod n */ - bighash(g, g); - sdsa->s = BN_dup(g); - BN_CTX_free(bctx); - BN_free(r); BN_free(k); BN_free(g); BN_free(y); - - /* - * Encode the values in ASN.1 and sign. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = htonl(gq_fstamp); - len = i2d_DSA_SIG(sdsa, NULL); - if (len <= 0) { - msyslog(LOG_ERR, "crypto_bob2 %s\n", - ERR_error_string(ERR_get_error(), NULL)); - DSA_SIG_free(sdsa); - return (XEVNT_PUB); - } - vp->vallen = htonl(len); - ptr = emalloc(len); - vp->ptr = ptr; - i2d_DSA_SIG(sdsa, &ptr); - DSA_SIG_free(sdsa); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_gq - verify Bob's response to Alice's challenge - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_FSP bad filestamp - * XEVNT_ID bad or missing identity parameters - */ -int -crypto_gq( - struct exten *ep, /* extension pointer */ - struct peer *peer /* peer structure pointer */ - ) -{ - RSA *rsa; /* GQ parameters */ - BN_CTX *bctx; /* BIGNUM context */ - DSA_SIG *sdsa; /* RSA signature context fake */ - BIGNUM *y, *v; - const u_char *ptr; - u_int len; - int temp; - - /* - * If the GQ parameters are not valid or no challenge was sent, - * something awful happened or we are being tormented. - */ - if (peer->ident_pkey == NULL) { - msyslog(LOG_INFO, "crypto_gq: scheme unavailable"); - return (XEVNT_PUB); - } - if (ntohl(ep->fstamp) != peer->fstamp) { - msyslog(LOG_INFO, "crypto_gq: invalid filestamp %u", - ntohl(ep->fstamp)); - return (XEVNT_FSP); - } - if ((rsa = peer->ident_pkey->pkey.rsa) == NULL) { - msyslog(LOG_INFO, "crypto_gq: defective key"); - return (XEVNT_PUB); - } - if (peer->iffval == NULL) { - msyslog(LOG_INFO, "crypto_gq: missing challenge"); - return (XEVNT_PUB); - } - - /* - * Extract the y = k u^r and hash(x = k^b) values from the - * response. - */ - bctx = BN_CTX_new(); y = BN_new(); v = BN_new(); - len = ntohl(ep->vallen); - ptr = (const u_char *)ep->pkt; - if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) { - msyslog(LOG_ERR, "crypto_gq %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Compute v^r y^b mod n. - */ - BN_mod_exp(v, peer->grpkey, peer->iffval, rsa->n, bctx); - /* v^r mod n */ - BN_mod_exp(y, sdsa->r, rsa->e, rsa->n, bctx); /* y^b mod n */ - BN_mod_mul(y, v, y, rsa->n, bctx); /* v^r y^b mod n */ - - /* - * Verify the hash of the result matches hash(x). - */ - bighash(y, y); - temp = BN_cmp(y, sdsa->s); - BN_CTX_free(bctx); BN_free(y); BN_free(v); - BN_free(peer->iffval); - peer->iffval = NULL; - DSA_SIG_free(sdsa); - if (temp == 0) - return (XEVNT_OK); - else - return (XEVNT_ID); -} - - -/* - *********************************************************************** - * * - * The following routines implement the Mu-Varadharajan (MV) identity * - * scheme * - * * - *********************************************************************** - */ -/* - * The Mu-Varadharajan (MV) cryptosystem was originally intended when - * servers broadcast messages to clients, but clients never send - * messages to servers. There is one encryption key for the server and a - * separate decryption key for each client. It operated something like a - * pay-per-view satellite broadcasting system where the session key is - * encrypted by the broadcaster and the decryption keys are held in a - * tamperproof set-top box. - * - * The MV parameters and private encryption key hide in a DSA cuckoo - * structure which uses the same parameters, but generated in a - * different way. The values are used in an encryption scheme similar to - * El Gamal cryptography and a polynomial formed from the expansion of - * product terms (x - x[j]), as described in Mu, Y., and V. - * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, - * 223-231. The paper has significant errors and serious omissions. - * - * Let q be the product of n distinct primes s'[j] (j = 1...n), where - * each s'[j] has m significant bits. Let p be a prime p = 2 * q + 1, so - * that q and each s'[j] divide p - 1 and p has M = n * m + 1 - * significant bits. The elements x mod q of Zq with the elements 2 and - * the primes removed form a field Zq* valid for polynomial arithetic. - * Let g be a generator of Zp; that is, gcd(g, p - 1) = 1 and g^q = 1 - * mod p. We expect M to be in the 500-bit range and n relatively small, - * like 25, so the likelihood of a randomly generated element of x mod q - * of Zq colliding with a factor of p - 1 is very small and can be - * avoided. Associated with each s'[j] is an element s[j] such that s[j] - * s'[j] = s'[j] mod q. We find s[j] as the quotient (q + s'[j]) / - * s'[j]. These are the parameters of the scheme and they are expensive - * to compute. - * - * We set up an instance of the scheme as follows. A set of random - * values x[j] mod q (j = 1...n), are generated as the zeros of a - * polynomial of order n. The product terms (x - x[j]) are expanded to - * form coefficients a[i] mod q (i = 0...n) in powers of x. These are - * used as exponents of the generator g mod p to generate the private - * encryption key A. The pair (gbar, ghat) of public server keys and the - * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used - * to construct the decryption keys. The devil is in the details. - * - * The distinguishing characteristic of this scheme is the capability to - * revoke keys. Included in the calculation of E, gbar and ghat is the - * product s = prod(s'[j]) (j = 1...n) above. If the factor s'[j] is - * subsequently removed from the product and E, gbar and ghat - * recomputed, the jth client will no longer be able to compute E^-1 and - * thus unable to decrypt the block. - * - * How it works - * - * The scheme goes like this. Bob has the server values (p, A, q, gbar, - * ghat) and Alice the client values (p, xbar, xhat). - * - * Alice rolls new random challenge r (0 < r < p) and sends to Bob in - * the MV request message. Bob rolls new random k (0 < k < q), encrypts - * y = A^k mod p (a permutation) and sends (hash(y), gbar^k, ghat^k) to - * Alice. - * - * Alice receives the response and computes the decryption key (the - * inverse permutation) from previously obtained (xbar, xhat) and - * (gbar^k, ghat^k) in the message. She computes the inverse, which is - * unique by reasons explained in the ntp-keygen.c program sources. If - * the hash of this result matches hash(y), Alice knows that Bob has the - * group key b. The signed response binds this knowledge to Bob's - * private key and the public key previously received in his - * certificate. - * - * crypto_alice3 - construct Alice's challenge in MV scheme - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_ID bad or missing identity parameters - */ -static int -crypto_alice3( - struct peer *peer, /* peer pointer */ - struct value *vp /* value pointer */ - ) -{ - DSA *dsa; /* MV parameters */ - BN_CTX *bctx; /* BIGNUM context */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; - u_int len; - - /* - * The identity parameters must have correct format and content. - */ - if (peer->ident_pkey == NULL) - return (XEVNT_ID); - if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) { - msyslog(LOG_INFO, "crypto_alice3: defective key"); - return (XEVNT_PUB); - } - - /* - * Roll new random r (0 < r < q). The OpenSSL library has a bug - * omitting BN_rand_range, so we have to do it the hard way. - */ - bctx = BN_CTX_new(); - len = BN_num_bytes(dsa->p); - if (peer->iffval != NULL) - BN_free(peer->iffval); - peer->iffval = BN_new(); - BN_rand(peer->iffval, len * 8, -1, 1); /* r */ - BN_mod(peer->iffval, peer->iffval, dsa->p, bctx); - BN_CTX_free(bctx); - - /* - * Sign and send to Bob. The filestamp is from the local file. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = htonl(peer->fstamp); - vp->vallen = htonl(len); - vp->ptr = emalloc(len); - BN_bn2bin(peer->iffval, vp->ptr); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_bob3 - construct Bob's response to Alice's challenge - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - */ -static int -crypto_bob3( - struct exten *ep, /* extension pointer */ - struct value *vp /* value pointer */ - ) -{ - DSA *dsa; /* MV parameters */ - DSA *sdsa; /* DSA signature context fake */ - BN_CTX *bctx; /* BIGNUM context */ - EVP_MD_CTX ctx; /* signature context */ - tstamp_t tstamp; /* NTP timestamp */ - BIGNUM *r, *k, *u; - u_char *ptr; - u_int len; - - /* - * If the MV parameters are not valid, something awful - * happened or we are being tormented. - */ - if (!(crypto_flags & CRYPTO_FLAG_MV)) { - msyslog(LOG_INFO, "crypto_bob3: scheme unavailable"); - return (XEVNT_PUB); - } - dsa = mvpar_pkey->pkey.dsa; - - /* - * Extract r from the challenge. - */ - len = ntohl(ep->vallen); - if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) { - msyslog(LOG_ERR, "crypto_bob3 %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Bob rolls random k (0 < k < q), making sure it is not a - * factor of q. He then computes y = A^k r and sends (hash(y), - * gbar^k, ghat^k) to Alice. - */ - bctx = BN_CTX_new(); k = BN_new(); u = BN_new(); - sdsa = DSA_new(); - sdsa->p = BN_new(); sdsa->q = BN_new(); sdsa->g = BN_new(); - while (1) { - BN_rand(k, BN_num_bits(dsa->q), 0, 0); - BN_mod(k, k, dsa->q, bctx); - BN_gcd(u, k, dsa->q, bctx); - if (BN_is_one(u)) - break; - } - BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A r */ - BN_mod_mul(u, u, r, dsa->p, bctx); - bighash(u, sdsa->p); - BN_mod_exp(sdsa->q, dsa->priv_key, k, dsa->p, bctx); /* gbar */ - BN_mod_exp(sdsa->g, dsa->pub_key, k, dsa->p, bctx); /* ghat */ - BN_CTX_free(bctx); BN_free(k); BN_free(r); BN_free(u); - - /* - * Encode the values in ASN.1 and sign. - */ - tstamp = crypto_time(); - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = htonl(mv_fstamp); - len = i2d_DSAparams(sdsa, NULL); - if (len <= 0) { - msyslog(LOG_ERR, "crypto_bob3 %s\n", - ERR_error_string(ERR_get_error(), NULL)); - DSA_free(sdsa); - return (XEVNT_PUB); - } - vp->vallen = htonl(len); - ptr = emalloc(len); - vp->ptr = ptr; - i2d_DSAparams(sdsa, &ptr); - DSA_free(sdsa); - vp->siglen = 0; - if (tstamp == 0) - return (XEVNT_OK); - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); - return (XEVNT_OK); -} - - -/* - * crypto_mv - verify Bob's response to Alice's challenge - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_FSP bad filestamp - * XEVNT_ID bad or missing identity parameters - */ -int -crypto_mv( - struct exten *ep, /* extension pointer */ - struct peer *peer /* peer structure pointer */ - ) -{ - DSA *dsa; /* MV parameters */ - DSA *sdsa; /* DSA parameters */ - BN_CTX *bctx; /* BIGNUM context */ - BIGNUM *k, *u, *v; - u_int len; - const u_char *ptr; - int temp; - - /* - * If the MV parameters are not valid or no challenge was sent, - * something awful happened or we are being tormented. - */ - if (peer->ident_pkey == NULL) { - msyslog(LOG_INFO, "crypto_mv: scheme unavailable"); - return (XEVNT_PUB); - } - if (ntohl(ep->fstamp) != peer->fstamp) { - msyslog(LOG_INFO, "crypto_mv: invalid filestamp %u", - ntohl(ep->fstamp)); - return (XEVNT_FSP); - } - if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) { - msyslog(LOG_INFO, "crypto_mv: defective key"); - return (XEVNT_PUB); - } - if (peer->iffval == NULL) { - msyslog(LOG_INFO, "crypto_mv: missing challenge"); - return (XEVNT_PUB); - } - - /* - * Extract the (hash(y), gbar, ghat) values from the response. - */ - bctx = BN_CTX_new(); k = BN_new(); u = BN_new(); v = BN_new(); - len = ntohl(ep->vallen); - ptr = (const u_char *)ep->pkt; - if ((sdsa = d2i_DSAparams(NULL, &ptr, len)) == NULL) { - msyslog(LOG_ERR, "crypto_mv %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_PUB); - } - - /* - * Compute (gbar^xhat ghat^xbar)^-1 mod p. - */ - BN_mod_exp(u, sdsa->q, dsa->pub_key, dsa->p, bctx); - BN_mod_exp(v, sdsa->g, dsa->priv_key, dsa->p, bctx); - BN_mod_mul(u, u, v, dsa->p, bctx); - BN_mod_inverse(u, u, dsa->p, bctx); - BN_mod_mul(v, u, peer->iffval, dsa->p, bctx); - - /* - * The result should match the hash of r mod p. - */ - bighash(v, v); - temp = BN_cmp(v, sdsa->p); - BN_CTX_free(bctx); BN_free(k); BN_free(u); BN_free(v); - BN_free(peer->iffval); - peer->iffval = NULL; - DSA_free(sdsa); - if (temp == 0) - return (XEVNT_OK); - else - return (XEVNT_ID); -} - - -/* - *********************************************************************** - * * - * The following routines are used to manipulate certificates * - * * - *********************************************************************** - */ -/* - * cert_parse - parse x509 certificate and create info/value structures. - * - * The server certificate includes the version number, issuer name, - * subject name, public key and valid date interval. If the issuer name - * is the same as the subject name, the certificate is self signed and - * valid only if the server is configured as trustable. If the names are - * different, another issuer has signed the server certificate and - * vouched for it. In this case the server certificate is valid if - * verified by the issuer public key. - * - * Returns certificate info/value pointer if valid, NULL if not. - */ -struct cert_info * /* certificate information structure */ -cert_parse( - u_char *asn1cert, /* X509 certificate */ - u_int len, /* certificate length */ - tstamp_t fstamp /* filestamp */ - ) -{ - X509 *cert; /* X509 certificate */ - X509_EXTENSION *ext; /* X509v3 extension */ - struct cert_info *ret; /* certificate info/value */ - BIO *bp; - X509V3_EXT_METHOD *method; - char pathbuf[MAXFILENAME]; - u_char *uptr; - char *ptr; - int temp, cnt, i; - - /* - * Decode ASN.1 objects and construct certificate structure. - */ - uptr = asn1cert; - if ((cert = d2i_X509(NULL, &uptr, len)) == NULL) { - msyslog(LOG_ERR, "cert_parse %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (NULL); - } - - /* - * Extract version, subject name and public key. - */ - ret = emalloc(sizeof(struct cert_info)); - memset(ret, 0, sizeof(struct cert_info)); - if ((ret->pkey = X509_get_pubkey(cert)) == NULL) { - msyslog(LOG_ERR, "cert_parse %s\n", - ERR_error_string(ERR_get_error(), NULL)); - cert_free(ret); - X509_free(cert); - return (NULL); - } - ret->version = X509_get_version(cert); - X509_NAME_oneline(X509_get_subject_name(cert), pathbuf, - MAXFILENAME - 1); - ptr = strstr(pathbuf, "CN="); - if (ptr == NULL) { - msyslog(LOG_INFO, "cert_parse: invalid subject %s", - pathbuf); - cert_free(ret); - X509_free(cert); - return (NULL); - } - ret->subject = emalloc(strlen(ptr) + 1); - strcpy(ret->subject, ptr + 3); - - /* - * Extract remaining objects. Note that the NTP serial number is - * the NTP seconds at the time of signing, but this might not be - * the case for other authority. We don't bother to check the - * objects at this time, since the real crunch can happen only - * when the time is valid but not yet certificated. - */ - ret->nid = OBJ_obj2nid(cert->cert_info->signature->algorithm); - ret->digest = (const EVP_MD *)EVP_get_digestbynid(ret->nid); - ret->serial = - (u_long)ASN1_INTEGER_get(X509_get_serialNumber(cert)); - X509_NAME_oneline(X509_get_issuer_name(cert), pathbuf, - MAXFILENAME); - if ((ptr = strstr(pathbuf, "CN=")) == NULL) { - msyslog(LOG_INFO, "cert_parse: invalid issuer %s", - pathbuf); - cert_free(ret); - X509_free(cert); - return (NULL); - } - ret->issuer = emalloc(strlen(ptr) + 1); - strcpy(ret->issuer, ptr + 3); - ret->first = asn2ntp(X509_get_notBefore(cert)); - ret->last = asn2ntp(X509_get_notAfter(cert)); - - /* - * Extract extension fields. These are ad hoc ripoffs of - * currently assigned functions and will certainly be changed - * before prime time. - */ - cnt = X509_get_ext_count(cert); - for (i = 0; i < cnt; i++) { - ext = X509_get_ext(cert, i); - method = X509V3_EXT_get(ext); - temp = OBJ_obj2nid(ext->object); - switch (temp) { - - /* - * If a key_usage field is present, we decode whether - * this is a trusted or private certificate. This is - * dorky; all we want is to compare NIDs, but OpenSSL - * insists on BIO text strings. - */ - case NID_ext_key_usage: - bp = BIO_new(BIO_s_mem()); - X509V3_EXT_print(bp, ext, 0, 0); - BIO_gets(bp, pathbuf, MAXFILENAME); - BIO_free(bp); -#if DEBUG - if (debug) - printf("cert_parse: %s: %s\n", - OBJ_nid2ln(temp), pathbuf); -#endif - if (strcmp(pathbuf, "Trust Root") == 0) - ret->flags |= CERT_TRUST; - else if (strcmp(pathbuf, "Private") == 0) - ret->flags |= CERT_PRIV; - break; - - /* - * If a NID_subject_key_identifier field is present, it - * contains the GQ public key. - */ - case NID_subject_key_identifier: - ret->grplen = ext->value->length - 2; - ret->grpkey = emalloc(ret->grplen); - memcpy(ret->grpkey, &ext->value->data[2], - ret->grplen); - break; - } - } - - /* - * If certificate is self signed, verify signature. - */ - if (strcmp(ret->subject, ret->issuer) == 0) { - if (!X509_verify(cert, ret->pkey)) { - msyslog(LOG_INFO, - "cert_parse: invalid signature not verified %s", - pathbuf); - cert_free(ret); - X509_free(cert); - return (NULL); - } - } - - /* - * Verify certificate valid times. Note that certificates cannot - * be retroactive. - */ - if (ret->first > ret->last || ret->first < fstamp) { - msyslog(LOG_INFO, - "cert_parse: expired %s", - ret->subject); - cert_free(ret); - X509_free(cert); - return (NULL); - } - - /* - * Build the value structure to sign and send later. - */ - ret->cert.fstamp = htonl(fstamp); - ret->cert.vallen = htonl(len); - ret->cert.ptr = emalloc(len); - memcpy(ret->cert.ptr, asn1cert, len); -#ifdef DEBUG - if (debug > 1) - X509_print_fp(stdout, cert); -#endif - X509_free(cert); - return (ret); -} - - -/* - * cert_sign - sign x509 certificate and update value structure. - * - * The certificate request is a copy of the client certificate, which - * includes the version number, subject name and public key of the - * client. The resulting certificate includes these values plus the - * serial number, issuer name and validity interval of the server. The - * validity interval extends from the current time to the same time one - * year hence. For NTP purposes, it is convenient to use the NTP seconds - * of the current time as the serial number. - * - * Returns - * XEVNT_OK success - * XEVNT_PUB bad or missing public key - * XEVNT_CRT bad or missing certificate - * XEVNT_VFY certificate not verified - */ -static int -cert_sign( - struct exten *ep, /* extension field pointer */ - struct value *vp /* value pointer */ - ) -{ - X509 *req; /* X509 certificate request */ - X509 *cert; /* X509 certificate */ - X509_EXTENSION *ext; /* certificate extension */ - ASN1_INTEGER *serial; /* serial number */ - X509_NAME *subj; /* distinguished (common) name */ - EVP_PKEY *pkey; /* public key */ - EVP_MD_CTX ctx; /* message digest context */ - tstamp_t tstamp; /* NTP timestamp */ - u_int len; - u_char *ptr; - int i, temp; - - /* - * Decode ASN.1 objects and construct certificate structure. - */ - tstamp = crypto_time(); - if (tstamp == 0) - return (XEVNT_TSP); - - ptr = (u_char *)ep->pkt; - if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) { - msyslog(LOG_ERR, "cert_sign %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (XEVNT_CRT); - } - /* - * Extract public key and check for errors. - */ - if ((pkey = X509_get_pubkey(req)) == NULL) { - msyslog(LOG_ERR, "cert_sign %s\n", - ERR_error_string(ERR_get_error(), NULL)); - X509_free(req); - return (XEVNT_PUB); - } - - /* - * Generate X509 certificate signed by this server. For this - * prupose the issuer name is the server name. Also copy any - * extensions that might be present. - */ - cert = X509_new(); - X509_set_version(cert, X509_get_version(req)); - serial = ASN1_INTEGER_new(); - ASN1_INTEGER_set(serial, tstamp); - X509_set_serialNumber(cert, serial); - X509_gmtime_adj(X509_get_notBefore(cert), 0L); - X509_gmtime_adj(X509_get_notAfter(cert), YEAR); - subj = X509_get_issuer_name(cert); - X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, - (unsigned char *) sys_hostname, strlen(sys_hostname), -1, 0); - subj = X509_get_subject_name(req); - X509_set_subject_name(cert, subj); - X509_set_pubkey(cert, pkey); - ext = X509_get_ext(req, 0); - temp = X509_get_ext_count(req); - for (i = 0; i < temp; i++) { - ext = X509_get_ext(req, i); - X509_add_ext(cert, ext, -1); - } - X509_free(req); - - /* - * Sign and verify the certificate. - */ - X509_sign(cert, sign_pkey, sign_digest); - if (!X509_verify(cert, sign_pkey)) { - printf("cert_sign\n%s\n", - ERR_error_string(ERR_get_error(), NULL)); - X509_free(cert); - return (XEVNT_VFY); - } - len = i2d_X509(cert, NULL); - - /* - * Build and sign the value structure. We have to sign it here, - * since the response has to be returned right away. This is a - * clogging hazard. - */ - memset(vp, 0, sizeof(struct value)); - vp->tstamp = htonl(tstamp); - vp->fstamp = ep->fstamp; - vp->vallen = htonl(len); - vp->ptr = emalloc(len); - ptr = vp->ptr; - i2d_X509(cert, &ptr); - vp->siglen = 0; - vp->sig = emalloc(sign_siglen); - EVP_SignInit(&ctx, sign_digest); - EVP_SignUpdate(&ctx, (u_char *)vp, 12); - EVP_SignUpdate(&ctx, vp->ptr, len); - if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey)) - vp->siglen = htonl(len); -#ifdef DEBUG - if (debug > 1) - X509_print_fp(stdout, cert); -#endif - X509_free(cert); - return (XEVNT_OK); -} - - -/* - * cert_valid - verify certificate with given public key - * - * This is pretty ugly, as the certificate has to be verified in the - * OpenSSL X509 structure, not in the DER format in the info/value - * structure. - * - * Returns - * XEVNT_OK success - * XEVNT_VFY certificate not verified - */ -int -cert_valid( - struct cert_info *cinf, /* certificate information structure */ - EVP_PKEY *pkey /* public key */ - ) -{ - X509 *cert; /* X509 certificate */ - u_char *ptr; - - if (cinf->flags & CERT_SIGN) - return (XEVNT_OK); - ptr = (u_char *)cinf->cert.ptr; - cert = d2i_X509(NULL, &ptr, ntohl(cinf->cert.vallen)); - if (!X509_verify(cert, pkey)) - return (XEVNT_VFY); - cinf->flags |= CERT_SIGN; - X509_free(cert); - return (XEVNT_OK); -} - - -/* - * cert - install certificate in certificate list - * - * This routine encodes an extension field into a certificate info/value - * structure. It searches the certificate list for duplicates and - * expunges whichever is older. It then searches the list for other - * certificates that might be verified by this latest one. Finally, it - * inserts this certificate first on the list. - * - * Returns - * XEVNT_OK success - * XEVNT_PER certificate expired - * XEVNT_CRT bad or missing certificate - */ -int -cert_install( - struct exten *ep, /* cert info/value */ - struct peer *peer /* peer structure */ - ) -{ - struct cert_info *cp, *xp, *yp, **zp; - int rval; - tstamp_t tstamp; - - /* - * Parse and validate the signed certificate. If valid, - * construct the info/value structure; otherwise, scamper home. - * Note this allows a certificate not-before time to be in the - * future, but not a not-after time to be in the past. - */ - if ((cp = cert_parse((u_char *)ep->pkt, ntohl(ep->vallen), - ntohl(ep->fstamp))) == NULL) - return (XEVNT_CRT); - - tstamp = crypto_time(); - if (tstamp > cp->last) { - cert_free(cp); - return (XEVNT_PER); - } - - /* - * Scan certificate list looking for another certificate with - * the same subject and issuer. If another is found with the - * same or older filestamp, unlink it and return the goodies to - * the heap. If another is found with a later filetsamp, discard - * the new one and leave the building. - */ - rval = XEVNT_OK; - yp = cp; - zp = &cinfo; - for (xp = cinfo; xp != NULL; xp = xp->link) { - if (strcmp(cp->subject, xp->subject) == 0 && - strcmp(cp->issuer, xp->issuer) == 0) { - if (ntohl(cp->cert.fstamp) <= - ntohl(xp->cert.fstamp)) { - *zp = xp->link;; - cert_free(xp); - } else { - cert_free(cp); - return (XEVNT_TSP); - } - break; - } - zp = &xp->link; - } - yp->link = cinfo; - cinfo = yp; - - /* - * Scan the certificate list to see if Y is signed by X. - */ - for (yp = cinfo; yp != NULL; yp = yp->link) { - for (xp = cinfo; xp != NULL; xp = xp->link) { - if (yp->flags & CERT_ERROR) - continue; - - /* - * If issuer Y matches subject X and signature Y - * is valid using public key X, then Y is valid. - */ - if (strcmp(yp->issuer, xp->subject) != 0) - continue; - - if (cert_valid(yp, xp->pkey) != XEVNT_OK) { - yp->flags |= CERT_ERROR; - continue; - } - xp->flags |= CERT_SIGN; - - /* - * If X is trusted, then Y is trusted. Note that - * we might stumble over a self signed - * certificate that is not trusted, at least - * temporarily. This can happen when a dude - * first comes up, but has not synchronized the - * clock and had its certificate signed by its - * server. In case of broken certificate trail, - * this might result in a loop that could - * persist until timeout. - */ - if (!(xp->flags & CERT_TRUST)) - continue; - - yp->flags |= CERT_TRUST; - - /* - * If subject Y matches the server subject name, - * then Y has completed the certificate trail. - * Save the group key and light the valid bit. - */ - if (strcmp(yp->subject, peer->subject) != 0) - continue; - - if (yp->grpkey != NULL) { - if (peer->grpkey != NULL) - BN_free(peer->grpkey); - peer->grpkey = BN_bin2bn(yp->grpkey, - yp->grplen, NULL); - } - peer->crypto |= CRYPTO_FLAG_VALID; - - /* - * If the server has an an identity scheme, - * fetch the identity credentials. If not, the - * identity is verified only by the trusted - * certificate. The next signature will set the - * server proventic. - */ - if (peer->crypto & (CRYPTO_FLAG_GQ | - CRYPTO_FLAG_IFF | CRYPTO_FLAG_MV)) - continue; - - peer->crypto |= CRYPTO_FLAG_VRFY; - } - } - - /* - * That was awesome. Now update the timestamps and signatures. - */ - crypto_update(); - return (rval); -} - - -/* - * cert_free - free certificate information structure - */ -void -cert_free( - struct cert_info *cinf /* certificate info/value structure */ - ) -{ - if (cinf->pkey != NULL) - EVP_PKEY_free(cinf->pkey); - if (cinf->subject != NULL) - free(cinf->subject); - if (cinf->issuer != NULL) - free(cinf->issuer); - if (cinf->grpkey != NULL) - free(cinf->grpkey); - value_free(&cinf->cert); - free(cinf); -} - - -/* - *********************************************************************** - * * - * The following routines are used only at initialization time * - * * - *********************************************************************** - */ -/* - * crypto_key - load cryptographic parameters and keys from files - * - * This routine loads a PEM-encoded public/private key pair and extracts - * the filestamp from the file name. - * - * Returns public key pointer if valid, NULL if not. Side effect updates - * the filestamp if valid. - */ -static EVP_PKEY * -crypto_key( - char *cp, /* file name */ - tstamp_t *fstamp /* filestamp */ - ) -{ - FILE *str; /* file handle */ - EVP_PKEY *pkey = NULL; /* public/private key */ - char filename[MAXFILENAME]; /* name of key file */ - char linkname[MAXFILENAME]; /* filestamp buffer) */ - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - char *ptr; - - /* - * Open the key file. If the first character of the file name is - * not '/', prepend the keys directory string. If something goes - * wrong, abandon ship. - */ - if (*cp == '/') - strcpy(filename, cp); - else - snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); - str = fopen(filename, "r"); - if (str == NULL) - return (NULL); - - /* - * Read the filestamp, which is contained in the first line. - */ - if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { - msyslog(LOG_ERR, "crypto_key: no data %s\n", - filename); - return (NULL); - } - if ((ptr = strrchr(ptr, '.')) == NULL) { - msyslog(LOG_ERR, "crypto_key: no filestamp %s\n", - filename); - return (NULL); - } - if (sscanf(++ptr, "%u", fstamp) != 1) { - msyslog(LOG_ERR, "crypto_key: invalid timestamp %s\n", - filename); - return (NULL); - } - - /* - * Read and decrypt PEM-encoded private key. - */ - pkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); - fclose(str); - if (pkey == NULL) { - msyslog(LOG_ERR, "crypto_key %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (NULL); - } - - /* - * Leave tracks in the cryptostats. - */ - if ((ptr = strrchr(linkname, '\n')) != NULL) - *ptr = '\0'; - sprintf(statstr, "%s mod %d", &linkname[2], - EVP_PKEY_size(pkey) * 8); - record_crypto_stats(NULL, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_key: %s\n", statstr); - if (debug > 1) { - if (EVP_MD_type(pkey) == EVP_PKEY_DSA) - DSA_print_fp(stdout, pkey->pkey.dsa, 0); - else - RSA_print_fp(stdout, pkey->pkey.rsa, 0); - } -#endif - return (pkey); -} - - -/* - * crypto_cert - load certificate from file - * - * This routine loads a X.509 RSA or DSA certificate from a file and - * constructs a info/cert value structure for this machine. The - * structure includes a filestamp extracted from the file name. Later - * the certificate can be sent to another machine by request. - * - * Returns certificate info/value pointer if valid, NULL if not. - */ -static struct cert_info * /* certificate information */ -crypto_cert( - char *cp /* file name */ - ) -{ - struct cert_info *ret; /* certificate information */ - FILE *str; /* file handle */ - char filename[MAXFILENAME]; /* name of certificate file */ - char linkname[MAXFILENAME]; /* filestamp buffer */ - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - tstamp_t fstamp; /* filestamp */ - long len; - char *ptr; - char *name, *header; - u_char *data; - - /* - * Open the certificate file. If the first character of the file - * name is not '/', prepend the keys directory string. If - * something goes wrong, abandon ship. - */ - if (*cp == '/') - strcpy(filename, cp); - else - snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp); - str = fopen(filename, "r"); - if (str == NULL) - return (NULL); - - /* - * Read the filestamp, which is contained in the first line. - */ - if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { - msyslog(LOG_ERR, "crypto_cert: no data %s\n", - filename); - return (NULL); - } - if ((ptr = strrchr(ptr, '.')) == NULL) { - msyslog(LOG_ERR, "crypto_cert: no filestamp %s\n", - filename); - return (NULL); - } - if (sscanf(++ptr, "%u", &fstamp) != 1) { - msyslog(LOG_ERR, "crypto_cert: invalid filestamp %s\n", - filename); - return (NULL); - } - - /* - * Read PEM-encoded certificate and install. - */ - if (!PEM_read(str, &name, &header, &data, &len)) { - msyslog(LOG_ERR, "crypto_cert %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return (NULL); - } - free(header); - if (strcmp(name, "CERTIFICATE") !=0) { - msyslog(LOG_INFO, "crypto_cert: wrong PEM type %s", - name); - free(name); - free(data); - return (NULL); - } - free(name); - - /* - * Parse certificate and generate info/value structure. - */ - ret = cert_parse(data, len, fstamp); - free(data); - if (ret == NULL) - return (NULL); - if ((ptr = strrchr(linkname, '\n')) != NULL) - *ptr = '\0'; - sprintf(statstr, "%s 0x%x len %lu", &linkname[2], ret->flags, - len); - record_crypto_stats(NULL, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_cert: %s\n", statstr); -#endif - return (ret); -} - - -/* - * crypto_tai - load leapseconds table from file - * - * This routine loads the ERTS leapsecond file in NIST text format, - * converts to a value structure and extracts a filestamp from the file - * name. The data are used to establish the TAI offset from UTC, which - * is provided to the kernel if supported. Later the data can be sent to - * another machine on request. - */ -static void -crypto_tai( - char *cp /* file name */ - ) -{ - FILE *str; /* file handle */ - char buf[NTP_MAXSTRLEN]; /* file line buffer */ - u_int leapsec[MAX_LEAP]; /* NTP time at leaps */ - u_int offset; /* offset at leap (s) */ - char filename[MAXFILENAME]; /* name of leapseconds file */ - char linkname[MAXFILENAME]; /* file link (for filestamp) */ - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - tstamp_t fstamp; /* filestamp */ - u_int len; - char *ptr; - int rval, i; -#ifdef KERNEL_PLL -#if NTP_API > 3 - struct timex ntv; /* kernel interface structure */ -#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); - if ((str = fopen(filename, "r")) == NULL) - return; - - /* - * Extract filestamp if present. - */ - rval = readlink(filename, linkname, MAXFILENAME - 1); - if (rval > 0) { - linkname[rval] = '\0'; - ptr = strrchr(linkname, '.'); - } else { - ptr = strrchr(filename, '.'); - } - if (ptr != NULL) - sscanf(++ptr, "%u", &fstamp); - else - fstamp = 0; - tai_leap.fstamp = htonl(fstamp); - - /* - * We are rather paranoid here, since an intruder might cause a - * coredump by infiltrating naughty values. Empty lines and - * comments are ignored. Other lines must begin with two - * integers followed by junk or comments. The first integer is - * the NTP seconds of leap insertion, the second is the offset - * of TAI relative to UTC after that insertion. The second word - * must equal the initial insertion of ten seconds on 1 January - * 1972 plus one second for each succeeding insertion. - */ - i = 0; - while (i < MAX_LEAP) { - ptr = fgets(buf, NTP_MAXSTRLEN - 1, str); - if (ptr == NULL) - break; - if (strlen(buf) < 1) - continue; - if (*buf == '#') - continue; - if (sscanf(buf, "%u %u", &leapsec[i], &offset) != 2) - continue; - if (i != (int)(offset - TAI_1972)) { - break; - } - i++; - } - fclose(str); - if (ptr != NULL) { - msyslog(LOG_INFO, - "crypto_tai: leapseconds file %s error %d", cp, - rval); - exit (-1); - } - - /* - * The extension field table entries consists of the NTP seconds - * of leap insertion in reverse order, so that the most recent - * insertion is the first entry in the table. - */ - len = i * 4; - tai_leap.vallen = htonl(len); - ptr = emalloc(len); - tai_leap.ptr = (unsigned char *) ptr; - for (; i >= 0; i--) { - *ptr++ = (char) htonl(leapsec[i]); - } - 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_INFO, - "crypto_tai: kernel TAI update failed"); -#endif /* NTP_API */ -#endif /* KERNEL_PLL */ - sprintf(statstr, "%s link %d fs %u offset %u", cp, rval, fstamp, - ntohl(tai_leap.vallen) / 4 + TAI_1972 - 1); - record_crypto_stats(NULL, statstr); -#ifdef DEBUG - if (debug) - printf("crypto_tai: %s\n", statstr); -#endif -} - - -/* - * crypto_setup - load keys, certificate and leapseconds table - * - * This routine loads the public/private host key and certificate. If - * available, it loads the public/private sign key, which defaults to - * the host key, and leapseconds table. The host key must be RSA, but - * the sign key can be either RSA or DSA. In either case, the public key - * on the certificate must agree with the sign key. - */ -void -crypto_setup(void) -{ - EVP_PKEY *pkey; /* private/public key pair */ - char filename[MAXFILENAME]; /* file name buffer */ - l_fp seed; /* crypto PRNG seed as NTP timestamp */ - tstamp_t fstamp; /* filestamp */ - tstamp_t sstamp; /* sign filestamp */ - u_int len, bytes; - u_char *ptr; - - /* - * Initialize structures. - */ - if (!crypto_flags) - return; - gethostname(filename, MAXFILENAME); - bytes = strlen(filename) + 1; - sys_hostname = emalloc(bytes); - memcpy(sys_hostname, filename, bytes); - if (passwd == NULL) - passwd = sys_hostname; - memset(&hostval, 0, sizeof(hostval)); - memset(&pubkey, 0, sizeof(pubkey)); - memset(&tai_leap, 0, sizeof(tai_leap)); - - /* - * Load required random seed file and seed the random number - * generator. Be default, it is found in the user home - * directory. The root home directory may be / or /root, - * depending on the system. Wiggle the contents a bit and write - * it back so the sequence does not repeat when we next restart. - */ - ERR_load_crypto_strings(); - if (rand_file == NULL) { - if ((RAND_file_name(filename, MAXFILENAME)) != NULL) { - rand_file = emalloc(strlen(filename) + 1); - strcpy(rand_file, filename); - } - } else if (*rand_file != '/') { - snprintf(filename, MAXFILENAME, "%s/%s", keysdir, - rand_file); - free(rand_file); - rand_file = emalloc(strlen(filename) + 1); - strcpy(rand_file, filename); - } - if (rand_file == NULL) { - msyslog(LOG_ERR, - "crypto_setup: random seed file not specified"); - exit (-1); - } - if ((bytes = RAND_load_file(rand_file, -1)) == 0) { - msyslog(LOG_ERR, - "crypto_setup: random seed file %s not found\n", - rand_file); - exit (-1); - } - get_systime(&seed); - RAND_seed(&seed, sizeof(l_fp)); - RAND_write_file(rand_file); - OpenSSL_add_all_algorithms(); -#ifdef DEBUG - if (debug) - printf( - "crypto_setup: OpenSSL version %lx random seed file %s bytes read %d\n", - SSLeay(), rand_file, bytes); -#endif - - /* - * Load required host key from file "ntpkey_host_<hostname>". It - * also becomes the default sign key. - */ - if (host_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_host_%s", - sys_hostname); - host_file = emalloc(strlen(filename) + 1); - strcpy(host_file, filename); - } - pkey = crypto_key(host_file, &fstamp); - if (pkey == NULL) { - msyslog(LOG_ERR, - "crypto_setup: host key file %s not found or corrupt", - host_file); - exit (-1); - } - host_pkey = pkey; - sign_pkey = pkey; - sstamp = fstamp; - hostval.fstamp = htonl(fstamp); - if (EVP_MD_type(host_pkey) != EVP_PKEY_RSA) { - msyslog(LOG_ERR, - "crypto_setup: host key is not RSA key type"); - exit (-1); - } - hostval.vallen = htonl(strlen(sys_hostname)); - hostval.ptr = (unsigned char *) sys_hostname; - - /* - * Construct public key extension field for agreement scheme. - */ - len = i2d_PublicKey(host_pkey, NULL); - ptr = emalloc(len); - pubkey.ptr = ptr; - i2d_PublicKey(host_pkey, &ptr); - pubkey.vallen = htonl(len); - pubkey.fstamp = hostval.fstamp; - - /* - * Load optional sign key from file "ntpkey_sign_<hostname>". If - * loaded, it becomes the sign key. - */ - if (sign_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_sign_%s", - sys_hostname); - sign_file = emalloc(strlen(filename) + 1); - strcpy(sign_file, filename); - } - pkey = crypto_key(sign_file, &fstamp); - if (pkey != NULL) { - sign_pkey = pkey; - sstamp = fstamp; - } - sign_siglen = EVP_PKEY_size(sign_pkey); - - /* - * Load optional IFF parameters from file - * "ntpkey_iff_<hostname>". - */ - if (iffpar_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_iff_%s", - sys_hostname); - iffpar_file = emalloc(strlen(filename) + 1); - strcpy(iffpar_file, filename); - } - iffpar_pkey = crypto_key(iffpar_file, &if_fstamp); - if (iffpar_pkey != NULL) - crypto_flags |= CRYPTO_FLAG_IFF; - - /* - * Load optional GQ parameters from file "ntpkey_gq_<hostname>". - */ - if (gqpar_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_gq_%s", - sys_hostname); - gqpar_file = emalloc(strlen(filename) + 1); - strcpy(gqpar_file, filename); - } - gqpar_pkey = crypto_key(gqpar_file, &gq_fstamp); - if (gqpar_pkey != NULL) - crypto_flags |= CRYPTO_FLAG_GQ; - - /* - * Load optional MV parameters from file "ntpkey_mv_<hostname>". - */ - if (mvpar_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_mv_%s", - sys_hostname); - mvpar_file = emalloc(strlen(filename) + 1); - strcpy(mvpar_file, filename); - } - mvpar_pkey = crypto_key(mvpar_file, &mv_fstamp); - if (mvpar_pkey != NULL) - crypto_flags |= CRYPTO_FLAG_MV; - - /* - * Load required certificate from file "ntpkey_cert_<hostname>". - */ - if (cert_file == NULL) { - snprintf(filename, MAXFILENAME, "ntpkey_cert_%s", - sys_hostname); - cert_file = emalloc(strlen(filename) + 1); - strcpy(cert_file, filename); - } - if ((cinfo = crypto_cert(cert_file)) == NULL) { - msyslog(LOG_ERR, - "certificate file %s not found or corrupt", - cert_file); - exit (-1); - } - - /* - * The subject name must be the same as the host name, unless - * the certificate is private, in which case it may have come - * from another host. - */ - if (!(cinfo->flags & CERT_PRIV) && strcmp(cinfo->subject, - sys_hostname) != 0) { - msyslog(LOG_ERR, - "crypto_setup: certificate %s not for this host", - cert_file); - cert_free(cinfo); - exit (-1); - } - - /* - * It the certificate is trusted, the subject must be the same - * as the issuer, in other words it must be self signed. - */ - if (cinfo->flags & CERT_PRIV && strcmp(cinfo->subject, - cinfo->issuer) != 0) { - if (cert_valid(cinfo, sign_pkey) != XEVNT_OK) { - msyslog(LOG_ERR, - "crypto_setup: certificate %s is trusted, but not self signed.", - cert_file); - cert_free(cinfo); - exit (-1); - } - } - sign_digest = cinfo->digest; - if (cinfo->flags & CERT_PRIV) - crypto_flags |= CRYPTO_FLAG_PRIV; - crypto_flags |= cinfo->nid << 16; - - /* - * Load optional leapseconds table from file "ntpkey_leap". If - * the file is missing or defective, the values can later be - * retrieved from a server. - */ - if (leap_file == NULL) - leap_file = "ntpkey_leap"; - crypto_tai(leap_file); -#ifdef DEBUG - if (debug) - printf( - "crypto_setup: flags 0x%x host %s signature %s\n", - crypto_flags, sys_hostname, OBJ_nid2ln(cinfo->nid)); -#endif -} - - -/* - * crypto_config - configure data from crypto configuration command. - */ -void -crypto_config( - int item, /* configuration item */ - char *cp /* file name */ - ) -{ - switch (item) { - - /* - * Set random seed file name. - */ - case CRYPTO_CONF_RAND: - rand_file = emalloc(strlen(cp) + 1); - strcpy(rand_file, cp); - break; - - /* - * Set private key password. - */ - case CRYPTO_CONF_PW: - passwd = emalloc(strlen(cp) + 1); - strcpy(passwd, cp); - break; - - /* - * Set host file name. - */ - case CRYPTO_CONF_PRIV: - host_file = emalloc(strlen(cp) + 1); - strcpy(host_file, cp); - break; - - /* - * Set sign key file name. - */ - case CRYPTO_CONF_SIGN: - sign_file = emalloc(strlen(cp) + 1); - strcpy(sign_file, cp); - break; - - /* - * Set iff parameters file name. - */ - case CRYPTO_CONF_IFFPAR: - iffpar_file = emalloc(strlen(cp) + 1); - strcpy(iffpar_file, cp); - break; - - /* - * Set gq parameters file name. - */ - case CRYPTO_CONF_GQPAR: - gqpar_file = emalloc(strlen(cp) + 1); - strcpy(gqpar_file, cp); - break; - - /* - * Set mv parameters file name. - */ - case CRYPTO_CONF_MVPAR: - mvpar_file = emalloc(strlen(cp) + 1); - strcpy(mvpar_file, cp); - break; - - /* - * Set certificate file name. - */ - case CRYPTO_CONF_CERT: - cert_file = emalloc(strlen(cp) + 1); - strcpy(cert_file, cp); - break; - - /* - * Set leapseconds file name. - */ - case CRYPTO_CONF_LEAP: - leap_file = emalloc(strlen(cp) + 1); - strcpy(leap_file, cp); - break; - } - crypto_flags |= CRYPTO_FLAG_ENAB; -} -# else -int ntp_crypto_bs_pubkey; -# endif /* OPENSSL */ diff --git a/contrib/ntp/ntpd/ntp_filegen.c b/contrib/ntp/ntpd/ntp_filegen.c deleted file mode 100644 index 59a1d91..0000000 --- a/contrib/ntp/ntpd/ntp_filegen.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * ntp_filegen.c,v 3.12 1994/01/25 19:06:11 kardel Exp - * - * implements file generations support for NTP - * logfiles and statistic files - * - * - * Copyright (C) 1992, 1996 by Rainer Pruy - * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany - * - * This code may be modified and used freely - * provided credits remain intact. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_string.h" -#include "ntp_calendar.h" -#include "ntp_filegen.h" -#include "ntp_stdlib.h" - -/* - * NTP is intended to run long periods of time without restart. - * Thus log and statistic files generated by NTP will grow large. - * - * this set of routines provides a central interface - * to generating files using file generations - * - * the generation of a file is changed according to file generation type - */ - - -/* - * redefine this if your system dislikes filename suffixes like - * X.19910101 or X.1992W50 or .... - */ -#define SUFFIX_SEP '.' - -/* - * other constants - */ -#define FGEN_AGE_SECS (24*60*60) /* life time of FILEGEN_AGE in seconds */ - -static void filegen_open P((FILEGEN *, u_long)); -static int valid_fileref P((char *, char *)); -#ifdef UNUSED -static FILEGEN *filegen_unregister P((char *)); -#endif /* UNUSED */ - -/* - * open a file generation according to the current settings of gen - * will also provide a link to basename if requested to do so - */ - -static void -filegen_open( - FILEGEN *gen, - u_long newid - ) -{ - char *filename; - char *basename; - u_int len; - FILE *fp; - struct calendar cal; - - len = strlen(gen->prefix) + strlen(gen->basename) + 1; - basename = (char*)emalloc(len); - sprintf(basename, "%s%s", gen->prefix, gen->basename); - - switch(gen->type) { - default: - msyslog(LOG_ERR, "unsupported file generations type %d for \"%s\" - reverting to FILEGEN_NONE", - gen->type, basename); - gen->type = FILEGEN_NONE; - - /*FALLTHROUGH*/ - case FILEGEN_NONE: - filename = (char*)emalloc(len); - sprintf(filename,"%s", basename); - break; - - case FILEGEN_PID: - filename = (char*)emalloc(len + 1 + 1 + 10); - sprintf(filename,"%s%c#%ld", basename, SUFFIX_SEP, newid); - break; - - case FILEGEN_DAY: - /* You can argue here in favor of using MJD, but - * I would assume it to be easier for humans to interpret dates - * in a format they are used to in everyday life. - */ - caljulian(newid,&cal); - filename = (char*)emalloc(len + 1 + 4 + 2 + 2); - sprintf(filename, "%s%c%04d%02d%02d", - basename, SUFFIX_SEP, cal.year, cal.month, cal.monthday); - break; - - case FILEGEN_WEEK: - /* - * This is still a hack - * - the term week is not correlated to week as it is used - * normally - it just refers to a period of 7 days - * starting at Jan 1 - 'weeks' are counted starting from zero - */ - caljulian(newid,&cal); - filename = (char*)emalloc(len + 1 + 4 + 1 + 2); - sprintf(filename, "%s%c%04dw%02d", - basename, SUFFIX_SEP, cal.year, cal.yearday / 7); - break; - - case FILEGEN_MONTH: - caljulian(newid,&cal); - filename = (char*)emalloc(len + 1 + 4 + 2); - sprintf(filename, "%s%c%04d%02d", - basename, SUFFIX_SEP, cal.year, cal.month); - break; - - case FILEGEN_YEAR: - caljulian(newid,&cal); - filename = (char*)emalloc(len + 1 + 4); - sprintf(filename, "%s%c%04d", basename, SUFFIX_SEP, cal.year); - break; - - case FILEGEN_AGE: - filename = (char*)emalloc(len + 1 + 2 + 10); - sprintf(filename, "%s%ca%08ld", basename, SUFFIX_SEP, newid); - break; - } - - if (gen->type != FILEGEN_NONE) { - /* - * check for existence of a file with name 'basename' - * as we disallow such a file - * if FGEN_FLAG_LINK is set create a link - */ - struct stat stats; - /* - * try to resolve name collisions - */ - static u_long conflicts = 0; - -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) -#endif - if (stat(basename, &stats) == 0) { - /* Hm, file exists... */ - if (S_ISREG(stats.st_mode)) { - if (stats.st_nlink <= 1) { - /* - * Oh, it is not linked - try to save it - */ - char *savename = (char*)emalloc(len + 1 + 1 + 10 + 10); - sprintf(savename, "%s%c%dC%lu", - basename, - SUFFIX_SEP, - (int) getpid(), - (u_long)conflicts++); - if (rename(basename, savename) != 0) - msyslog(LOG_ERR," couldn't save %s: %m", basename); - free(savename); - } else { - /* - * there is at least a second link tpo this file - * just remove the conflicting one - */ - if ( -#if !defined(VMS) - unlink(basename) != 0 -#else - delete(basename) != 0 -#endif - ) - msyslog(LOG_ERR, "couldn't unlink %s: %m", basename); - } - } else { - /* - * Ehh? Not a regular file ?? strange !!!! - */ - msyslog(LOG_ERR, "expected regular file for %s (found mode 0%lo)", - basename, (unsigned long)stats.st_mode); - } - } else { - /* - * stat(..) failed, but it is absolutely correct for - * 'basename' not to exist - */ - if (errno != ENOENT) - msyslog(LOG_ERR,"stat(%s) failed: %m", basename); - } - } - - /* - * now, try to open new file generation... - */ - fp = fopen(filename, "a"); - -#ifdef DEBUG - if (debug > 3) - printf("opening filegen (type=%d/id=%lu) \"%s\"\n", - gen->type, (u_long)newid, filename); -#endif - - if (fp == NULL) { - /* open failed -- keep previous state - * - * If the file was open before keep the previous generation. - * This will cause output to end up in the 'wrong' file, - * but I think this is still better than losing output - * - * ignore errors due to missing directories - */ - - if (errno != ENOENT) - msyslog(LOG_ERR, "can't open %s: %m", filename); - } else { - if (gen->fp != NULL) { - fclose(gen->fp); - } - gen->fp = fp; - gen->id = newid; - - if (gen->flag & FGEN_FLAG_LINK) { - /* - * need to link file to basename - * have to use hardlink for now as I want to allow - * gen->basename spanning directory levels - * this would make it more complex to get the correct - * filename for symlink - * - * Ok, it would just mean taking the part following - * the last '/' in the name.... Should add it later.... - */ - - /* Windows NT does not support file links -Greg Schueman 1/18/97 */ - -#if defined SYS_WINNT || defined SYS_VXWORKS - SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */ -#elif defined(VMS) - errno = 0; /* On VMS, don't support FGEN_FLAG_LINK */ -#else /* not (VMS) / VXWORKS / WINNT ; DO THE LINK) */ - if (link(filename, basename) != 0) - if (errno != EEXIST) - msyslog(LOG_ERR, "can't link(%s, %s): %m", filename, basename); -#endif /* SYS_WINNT || VXWORKS */ - } /* flags & FGEN_FLAG_LINK */ - } /* else fp == NULL */ - - free(basename); - free(filename); - return; -} - -/* - * this function sets up gen->fp to point to the correct - * generation of the file for the time specified by 'now' - * - * 'now' usually is interpreted as second part of a l_fp as is in the cal... - * library routines - */ - -void -filegen_setup( - FILEGEN *gen, - u_long now - ) -{ - u_long new_gen = ~ (u_long) 0; - struct calendar cal; - - if (!(gen->flag & FGEN_FLAG_ENABLED)) { - if (gen->fp != NULL) - fclose(gen->fp); - return; - } - - switch (gen->type) { - case FILEGEN_NONE: - if (gen->fp != NULL) return; /* file already open */ - break; - - case FILEGEN_PID: - new_gen = getpid(); - break; - - case FILEGEN_DAY: - caljulian(now, &cal); - cal.hour = cal.minute = cal.second = 0; - new_gen = caltontp(&cal); - break; - - case FILEGEN_WEEK: - /* Would be nice to have a calweekstart() routine */ - /* so just use a hack ... */ - /* just round time to integral 7 day period for actual year */ - new_gen = now - (now - calyearstart(now)) % TIMES7(SECSPERDAY) - + 60; - /* - * just to be sure - - * the computation above would fail in the presence of leap seconds - * so at least carry the date to the next day (+60 (seconds)) - * and go back to the start of the day via calendar computations - */ - caljulian(new_gen, &cal); - cal.hour = cal.minute = cal.second = 0; - new_gen = caltontp(&cal); - break; - - case FILEGEN_MONTH: - caljulian(now, &cal); - cal.yearday = (u_short) (cal.yearday - cal.monthday + 1); - cal.monthday = 1; - cal.hour = cal.minute = cal.second = 0; - new_gen = caltontp(&cal); - break; - - case FILEGEN_YEAR: - new_gen = calyearstart(now); - break; - - case FILEGEN_AGE: - new_gen = current_time - (current_time % FGEN_AGE_SECS); - break; - } - /* - * try to open file if not yet open - * reopen new file generation file on change of generation id - */ - if (gen->fp == NULL || gen->id != new_gen) { - filegen_open(gen, new_gen); - } -} - - -/* - * change settings for filegen files - */ -void -filegen_config( - FILEGEN *gen, - char *basename, - u_int type, - u_int flag - ) -{ - /* - * if nothing would be changed... - */ - if ((basename == gen->basename || strcmp(basename,gen->basename) == 0) && - type == gen->type && - flag == gen->flag) - return; - - /* - * validate parameters - */ - if (!valid_fileref(gen->prefix,basename)) - return; - - if (gen->fp != NULL) - fclose(gen->fp); - -#ifdef DEBUG - if (debug > 2) - printf("configuring filegen:\n\tprefix:\t%s\n\tbasename:\t%s -> %s\n\ttype:\t%d -> %d\n\tflag: %x -> %x\n", - gen->prefix, gen->basename, basename, gen->type, type, gen->flag, flag); -#endif - if (gen->basename != basename || strcmp(gen->basename, basename) != 0) { - free(gen->basename); - gen->basename = (char*)emalloc(strlen(basename) + 1); - strcpy(gen->basename, basename); - } - gen->type = (u_char) type; - gen->flag = (u_char) flag; - - /* - * make filegen use the new settings - * special action is only required when a generation file - * is currently open - * otherwise the new settings will be used anyway at the next open - */ - if (gen->fp != NULL) { - l_fp now; - - get_systime(&now); - filegen_setup(gen, now.l_ui); - } -} - - -/* - * check whether concatenating prefix and basename - * yields a legal filename - */ -static int -valid_fileref( - char *prefix, - char *basename - ) -{ - /* - * prefix cannot be changed dynamically - * (within the context of filegen) - * so just reject basenames containing '..' - * - * ASSUMPTION: - * file system parts 'below' prefix may be - * specified without infringement of security - * - * restricing prefix to legal values - * has to be ensured by other means - * (however, it would be possible to perform some checks here...) - */ - register char *p = basename; - - /* - * Just to catch, dumb errors opening up the world... - */ - if (prefix == NULL || *prefix == '\0') - return 0; - - if (basename == NULL) - return 0; - - for (p = basename; p; p = strchr(p, '/')) { - if (*p == '.' && *(p+1) == '.' && (*(p+2) == '\0' || *(p+2) == '/')) - return 0; - } - - return 1; -} - - -/* - * filegen registry - */ - -static struct filegen_entry { - char *name; - FILEGEN *filegen; - struct filegen_entry *next; -} *filegen_registry = NULL; - - -FILEGEN * -filegen_get( - char *name - ) -{ - struct filegen_entry *f = filegen_registry; - - while(f) { - if (f->name == name || strcmp(name, f->name) == 0) { -#ifdef XXX /* this gives the Alpha compiler fits */ - if (debug > 3) - printf("filegen_get(\"%s\") = %x\n", name, - (u_int)f->filegen); -#endif - return f->filegen; - } - f = f->next; - } -#ifdef DEBUG - if (debug > 3) - printf("filegen_get(\"%s\") = NULL\n", name); -#endif - return NULL; -} - -void -filegen_register( - const char *name, - FILEGEN *filegen - ) -{ - struct filegen_entry **f = &filegen_registry; - -#ifdef XXX /* this gives the Alpha compiler fits */ - if (debug > 3) - printf("filegen_register(\"%s\",%x)\n", name, (u_int)filegen); -#endif - while (*f) { - if ((*f)->name == name || strcmp(name, (*f)->name) == 0) { -#ifdef XXX /* this gives the Alpha compiler fits */ - if (debug > 4) { - printf("replacing filegen %x\n", (u_int)(*f)->filegen); - } -#endif - (*f)->filegen = filegen; - return; - } - f = &((*f)->next); - } - - *f = (struct filegen_entry *) emalloc(sizeof(struct filegen_entry)); - if (*f) { - (*f)->next = NULL; - (*f)->name = (char*)emalloc(strlen(name) + 1); - strcpy((*f)->name, name); - (*f)->filegen = filegen; -#ifdef DEBUG - if (debug > 5) { - printf("adding new filegen\n"); - } -#endif - } - - return; -} - -#ifdef UNUSED -static FILEGEN * -filegen_unregister( - char *name - ) -{ - struct filegen_entry **f = &filegen_registry; - -#ifdef DEBUG - if (debug > 3) - printf("filegen_unregister(\"%s\")\n", name); -#endif - - while (*f) { - if (strcmp((*f)->name,name) == 0) { - struct filegen_entry *ff = *f; - FILEGEN *fg; - - *f = (*f)->next; - fg = ff->filegen; - free(ff->name); - free(ff); - return fg; - } - f = &((*f)->next); - } - return NULL; -} -#endif /* UNUSED */ diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c deleted file mode 100644 index 7f27f21..0000000 --- a/contrib/ntp/ntpd/ntp_intres.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92 - * routine callable from ntpd, rather than separate program - * also, key info passed in via a global, so no key file needed. - */ - -/* - * ntpres - process configuration entries which require use of the resolver - * - * This is meant to be run by ntpd on the fly. It is not guaranteed - * to work properly if run by hand. This is actually a quick hack to - * stave off violence from people who hate using numbers in the - * configuration file (at least I hope the rest of the daemon is - * better than this). Also might provide some ideas about how one - * might go about autoconfiguring an NTP distribution network. - * - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include "ntp_machine.h" -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_request.h" -#include "ntp_stdlib.h" -#include "ntp_syslog.h" - -#include <stdio.h> -#include <ctype.h> -#include <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) - -/* - * Each item we are to resolve and configure gets one of these - * structures defined for it. - */ -struct conf_entry { - struct conf_entry *ce_next; - char *ce_name; /* name we are trying to resolve */ - struct conf_peer ce_config; /* configuration info for peer */ - struct sockaddr_storage peer_store; /* address info for both fams */ -}; -#define ce_peeraddr ce_config.peeraddr -#define ce_peeraddr6 ce_config.peeraddr6 -#define ce_hmode ce_config.hmode -#define ce_version ce_config.version -#define ce_minpoll ce_config.minpoll -#define ce_maxpoll ce_config.maxpoll -#define ce_flags ce_config.flags -#define ce_ttl ce_config.ttl -#define ce_keyid ce_config.keyid -#define ce_keystr ce_config.keystr - -/* - * confentries is a pointer to the list of configuration entries - * we have left to do. - */ -static struct conf_entry *confentries = NULL; - -/* - * We take an interrupt every thirty seconds, at which time we decrement - * config_timer and resolve_timer. The former is set to 2, so we retry - * unsucessful reconfigurations every minute. The latter is set to - * an exponentially increasing value which starts at 2 and increases to - * 32. When this expires we retry failed name resolutions. - * - * We sleep SLEEPTIME seconds before doing anything, to give the server - * time to arrange itself. - */ -#define MINRESOLVE 2 -#define MAXRESOLVE 32 -#define CONFIG_TIME 2 -#define ALARM_TIME 30 -#define SLEEPTIME 2 - -static volatile int config_timer = 0; -static volatile int resolve_timer = 0; - -static int resolve_value; /* next value of resolve timer */ - -/* - * Big hack attack - */ -#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */ -#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */ - -/* - * Select time out. Set to 2 seconds. The server is on the local machine, - * after all. - */ -#define TIMEOUT_SEC 2 -#define TIMEOUT_USEC 0 - - -/* - * Input processing. The data on each line in the configuration file - * is supposed to consist of entries in the following order - */ -#define TOK_HOSTNAME 0 -#define TOK_HMODE 1 -#define TOK_VERSION 2 -#define TOK_MINPOLL 3 -#define TOK_MAXPOLL 4 -#define TOK_FLAGS 5 -#define TOK_TTL 6 -#define TOK_KEYID 7 -#define TOK_KEYSTR 8 -#define NUMTOK 9 - -#define MAXLINESIZE 512 - - -/* - * File descriptor for ntp request code. - */ -static SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */ - -/* stuff to be filled in by caller */ - -keyid_t req_keyid; /* request keyid */ -char *req_file; /* name of the file with configuration info */ - -/* end stuff to be filled in */ - - -static 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, 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 *)); -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]; -}; - - -/* - * ntp_res_recv: Process an answer from the resolver - */ - -void -ntp_res_recv(void) -{ - /* - We have data ready on our descriptor. - It may be an EOF, meaning the resolver process went away. - Otherwise, it will be an "answer". - */ -} - - -/* - * ntp_intres needs; - * - * req_key(???), req_keyid, req_file valid - * syslog still open - */ - -void -ntp_intres(void) -{ - FILE *in; -#ifdef HAVE_SIGSUSPEND - sigset_t set; - - sigemptyset(&set); -#endif /* HAVE_SIGSUSPEND */ - -#ifdef DEBUG - if (debug > 1) { - msyslog(LOG_INFO, "NTP_INTRES running"); - } -#endif - - /* check out auth stuff */ - if (sys_authenticate) { - if (!authistrusted(req_keyid)) { - msyslog(LOG_ERR, "invalid request keyid %08x", - req_keyid ); - exit(1); - } - } - - /* - * Read the configuration info - * {this is bogus, since we are forked, but it is easier - * to keep this code - gdt} - */ - if ((in = fopen(req_file, "r")) == NULL) { - msyslog(LOG_ERR, "can't open configuration file %s: %m", - req_file); - exit(1); - } - readconf(in, req_file); - (void) fclose(in); - - if (!debug ) - (void) unlink(req_file); - - /* - * Sleep a little to make sure the server is completely up - */ - - sleep(SLEEPTIME); - - /* - * Make a first cut at resolving the bunch - */ - doconfigure(1); - if (confentries == NULL) { -#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 (confentries == NULL) - exit(0); - - checkparent(); - - if (resolve_timer == 0) { - if (resolve_value < MAXRESOLVE) - resolve_value <<= 1; - resolve_timer = resolve_value; -#ifdef DEBUG - if (debug > 2) - 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 - if (debug > 2) - 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 conf_entry *entry - ) -{ - register struct conf_entry *ce; - - ce = confentries; - if (ce == entry) { - confentries = ce->ce_next; - return; - } - - while (ce != NULL) { - if (ce->ce_next == entry) { - ce->ce_next = entry->ce_next; - return; - } - ce = ce->ce_next; - } -} - - -/* - * addentry - add an entry to the configuration list - */ -static void -addentry( - char *name, - int mode, - int version, - int minpoll, - int maxpoll, - u_int flags, - int ttl, - keyid_t keyid, - char *keystr - ) -{ - 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); - memmove(cp, name, len); - - ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); - ce->ce_name = cp; - ce->ce_peeraddr = 0; - ce->ce_peeraddr6 = in6addr_any; - ANYSOCK(&ce->peer_store); - ce->ce_hmode = (u_char)mode; - ce->ce_version = (u_char)version; - ce->ce_minpoll = (u_char)minpoll; - ce->ce_maxpoll = (u_char)maxpoll; - ce->ce_flags = (u_char)flags; - ce->ce_ttl = (u_char)ttl; - ce->ce_keyid = keyid; - strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME); - ce->ce_next = NULL; - - if (confentries == NULL) { - confentries = ce; - } else { - register struct conf_entry *cep; - - for (cep = confentries; cep->ce_next != NULL; - cep = cep->ce_next) - /* nothing */; - cep->ce_next = ce; - } -} - - -/* - * findhostaddr - resolve a host name into an address (Or vice-versa) - * - * Given one of {ce_peeraddr,ce_name}, find the other one. - * It returns 1 for "success" and 0 for an uncorrectable failure. - * Note that "success" includes try again errors. You can tell that you - * got a "try again" since {ce_peeraddr,ce_name} will still be zero. - */ -static int -findhostaddr( - struct conf_entry *entry - ) -{ - struct addrinfo *addr; - int error; - - checkparent(); /* make sure our guy is still running */ - - if (entry->ce_name != NULL && SOCKNUL(&entry->peer_store)) { - /* HMS: Squawk? */ - msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined..."); - return 1; - } - - if (entry->ce_name == NULL && !SOCKNUL(&entry->peer_store)) { - msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!"); - return 0; - } - - if (entry->ce_name) { -#ifdef DEBUG - if (debug > 2) - msyslog(LOG_INFO, "findhostaddr: Resolving <%s>", - entry->ce_name); -#endif /* DEBUG */ - error = getaddrinfo(entry->ce_name, NULL, NULL, &addr); - if (error == 0) { - entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr)); - if (entry->peer_store.ss_family == AF_INET) { - entry->ce_peeraddr = - GET_INADDR(entry->peer_store); - entry->ce_config.v6_flag = 0; - } else { - entry->ce_peeraddr6 = - GET_INADDR6(entry->peer_store); - entry->ce_config.v6_flag = 1; - } - } - } else { -#ifdef DEBUG - if (debug > 2) - msyslog(LOG_INFO, "findhostaddr: Resolving %s>", - stoa(&entry->peer_store)); -#endif - entry->ce_name = emalloc(MAXHOSTNAMELEN); - error = getnameinfo((const struct sockaddr *)&entry->peer_store, - SOCKLEN(&entry->peer_store), - (char *)&entry->ce_name, MAXHOSTNAMELEN, - NULL, 0, 0); - } - - if (error != 0) { - /* - * If the resolver is in use, see if the failure is - * temporary. If so, return success. - */ - if (h_errno == TRY_AGAIN) - return (1); - return (0); - } - - if (entry->ce_name) { -#ifdef DEBUG - if (debug > 2) - msyslog(LOG_INFO, "findhostaddr: name resolved."); -#endif - -#ifdef DEBUG - if (debug > 2) - msyslog(LOG_INFO, "findhostaddr: address resolved."); -#endif - } - - return (1); -} - - -/* - * openntp - open a socket to the ntp server - */ -static void -openntp(void) -{ - struct addrinfo hints; - struct addrinfo *addrResult; - - if (sockfd >= 0) - return; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - if (getaddrinfo(NULL, "ntp", &hints, &addrResult)!=0) { - msyslog(LOG_ERR, "getaddrinfo failed: %m"); - exit(1); - } - sockfd = socket(addrResult->ai_family, addrResult->ai_socktype, 0); - - if (sockfd == -1) { - msyslog(LOG_ERR, "socket() failed: %m"); - exit(1); - } - - /* - * 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, addrResult->ai_addr, addrResult->ai_addrlen) == -1) { - msyslog(LOG_ERR, "openntp: connect() failed: %m"); - exit(1); - } - freeaddrinfo(addrResult); -} - - -/* - * request - send a configuration request to the server, wait for a response - */ -static int -request( - struct conf_peer *conf - ) -{ - fd_set fdset; - struct timeval tvout; - struct req_pkt reqpkt; - l_fp ts; - int n; -#ifdef SYS_WINNT - HANDLE hReadWriteEvent = NULL; - BOOL ret; - DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait; - OVERLAPPED overlap; -#endif /* SYS_WINNT */ - - checkparent(); /* make sure our guy is still running */ - - if (sockfd < 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_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); - - 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) - { - if (errno != EINTR) - 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_CONFIG) { -#ifdef DEBUG - if (debug > 1) - msyslog(LOG_INFO, - "implementation (%d) or request (%d) incorrect", - reqpkt.implementation, reqpkt.request); -#endif - continue; - } - - if (INFO_NITEMS(reqpkt.err_nitems) != 0 || - INFO_MBZ(reqpkt.mbz_itemsize) != 0 || - INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) { -#ifdef DEBUG - if (debug > 1) - msyslog(LOG_INFO, - "nitems (%d) mbz (%d) or itemsize (%d) nonzero", - INFO_NITEMS(reqpkt.err_nitems), - INFO_MBZ(reqpkt.mbz_itemsize), - INFO_ITEMSIZE(reqpkt.mbz_itemsize)); -#endif - continue; - } - - n = INFO_ERR(reqpkt.err_nitems); - switch (n) { - case INFO_OKAY: - /* success */ - return 1; - - case INFO_ERR_IMPL: - msyslog(LOG_ERR, - "ntpd reports implementation mismatch!"); - return 0; - - case INFO_ERR_REQ: - msyslog(LOG_ERR, - "ntpd says configuration request is unknown!"); - return 0; - - case INFO_ERR_FMT: - msyslog(LOG_ERR, - "ntpd indicates a format error occurred!"); - return 0; - - case INFO_ERR_NODATA: - msyslog(LOG_ERR, - "ntpd indicates no data available!"); - return 0; - - case INFO_ERR_AUTH: - msyslog(LOG_ERR, - "ntpd returns a permission denied error!"); - return 0; - - default: - msyslog(LOG_ERR, - "ntpd returns unknown error code %d!", n); - return 0; - } - } -} - - -/* - * nexttoken - return the next token from a line - */ -static char * -nexttoken( - char **lptr - ) -{ - register char *cp; - register char *tstart; - - cp = *lptr; - - /* - * Skip leading white space - */ - while (*cp == ' ' || *cp == '\t') - cp++; - - /* - * If this is the end of the line, return nothing. - */ - if (*cp == '\n' || *cp == '\0') { - *lptr = cp; - return NULL; - } - - /* - * Must be the start of a token. Record the pointer and look - * for the end. - */ - tstart = cp++; - while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0') - cp++; - - /* - * Terminate the token with a \0. If this isn't the end of the - * line, space to the next character. - */ - if (*cp == '\n' || *cp == '\0') - *cp = '\0'; - else - *cp++ = '\0'; - - *lptr = cp; - return tstart; -} - - -/* - * readconf - read the configuration information out of the file we - * were passed. Note that since the file is supposed to be - * machine generated, we bail out at the first sign of trouble. - */ -static void -readconf( - FILE *fp, - char *name - ) -{ - register int i; - char *token[NUMTOK]; - u_long intval[NUMTOK]; - u_int flags; - char buf[MAXLINESIZE]; - char *bp; - - while (fgets(buf, MAXLINESIZE, fp) != NULL) { - - bp = buf; - for (i = 0; i < NUMTOK; i++) { - if ((token[i] = nexttoken(&bp)) == NULL) { - msyslog(LOG_ERR, - "tokenizing error in file `%s', quitting", - name); - exit(1); - } - } - - for (i = 1; i < NUMTOK - 1; i++) { - if (!atouint(token[i], &intval[i])) { - msyslog(LOG_ERR, - "format error for integer token `%s', file `%s', quitting", - token[i], name); - exit(1); - } - } - - if (intval[TOK_HMODE] != MODE_ACTIVE && - intval[TOK_HMODE] != MODE_CLIENT && - intval[TOK_HMODE] != MODE_BROADCAST) { - msyslog(LOG_ERR, "invalid mode (%ld) in file %s", - intval[TOK_HMODE], name); - exit(1); - } - - if (intval[TOK_VERSION] > NTP_VERSION || - intval[TOK_VERSION] < NTP_OLDVERSION) { - msyslog(LOG_ERR, "invalid version (%ld) in file %s", - intval[TOK_VERSION], name); - exit(1); - } - if (intval[TOK_MINPOLL] < NTP_MINPOLL || - intval[TOK_MINPOLL] > NTP_MAXPOLL) { - msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s", - intval[TOK_MINPOLL], name); - exit(1); - } - - if (intval[TOK_MAXPOLL] < NTP_MINPOLL || - intval[TOK_MAXPOLL] > NTP_MAXPOLL) { - msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s", - intval[TOK_MAXPOLL], name); - exit(1); - } - - if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER | - FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY)) - != 0) { - msyslog(LOG_ERR, "invalid flags (%ld) in file %s", - intval[TOK_FLAGS], name); - exit(1); - } - - flags = 0; - if (intval[TOK_FLAGS] & FLAG_AUTHENABLE) - flags |= CONF_FLAG_AUTHENABLE; - if (intval[TOK_FLAGS] & FLAG_PREFER) - flags |= CONF_FLAG_PREFER; - if (intval[TOK_FLAGS] & FLAG_NOSELECT) - flags |= CONF_FLAG_NOSELECT; - if (intval[TOK_FLAGS] & FLAG_BURST) - flags |= CONF_FLAG_BURST; - if (intval[TOK_FLAGS] & FLAG_IBURST) - flags |= CONF_FLAG_IBURST; - if (intval[TOK_FLAGS] & FLAG_SKEY) - flags |= CONF_FLAG_SKEY; - - /* - * This is as good as we can check it. Add it in. - */ - addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE], - (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL], - (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL], - intval[TOK_KEYID], token[TOK_KEYSTR]); - } -} - - -/* - * doconfigure - attempt to resolve names and configure the server - */ -static void -doconfigure( - int dores - ) -{ - register struct conf_entry *ce; - register struct conf_entry *ceremove; - - ce = confentries; - while (ce != NULL) { -#ifdef DEBUG - if (debug > 1) - msyslog(LOG_INFO, - "doconfigure: <%s> has peeraddr %s", - ce->ce_name, stoa(&ce->peer_store)); -#endif - if (dores && !SOCKNUL(&(ce->peer_store))) { - if (!findhostaddr(ce)) { - msyslog(LOG_ERR, - "couldn't resolve `%s', giving up on it", - ce->ce_name); - ceremove = ce; - ce = ceremove->ce_next; - removeentry(ceremove); - continue; - } - } - - if (!SOCKNUL(&ce->peer_store)) { - if (request(&ce->ce_config)) { - ceremove = ce; - ce = ceremove->ce_next; - removeentry(ceremove); - continue; - } -#ifdef DEBUG - if (debug > 1) { - msyslog(LOG_INFO, - "doconfigure: request() FAILED, maybe next time."); - } -#endif - } - ce = ce->ce_next; - } -} diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c deleted file mode 100644 index 9f2acea..0000000 --- a/contrib/ntp/ntpd/ntp_io.c +++ /dev/null @@ -1,2257 +0,0 @@ -/* - * ntp_io.c - input/output routines for ntpd. The socket-opening code - * was shamelessly stolen from ntpd. - */ - -#ifdef HAVE_CONFIG_H -# 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 "ntp.h" - -/* Don't include ISC's version of IPv6 variables and structures */ -#define ISC_IPV6_H 1 -#include <isc/interfaceiter.h> -#include <isc/list.h> -#include <isc/result.h> - -#ifdef SIM -#include "ntpsim.h" -#endif - -#include <stdio.h> -#include <signal.h> -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif /* HAVE_SYS_PARAM_H */ -#ifdef HAVE_NETINET_IN_H -# include <netinet/in.h> -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -# include <netinet/in_systm.h> -#else /* Some old linux systems at least have in_system.h instead. */ -# ifdef HAVE_NETINET_IN_SYSTEM_H -# include <netinet/in_system.h> -# endif -#endif /* HAVE_NETINET_IN_SYSTM_H */ -#ifdef HAVE_NETINET_IP_H -# include <netinet/ip.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */ -# include <sys/sockio.h> -#endif -#include <arpa/inet.h> - -extern int listen_to_virtual_ips; - -#if defined(SYS_WINNT) -#include <transmitbuff.h> -#include <isc/win32os.h> -/* - * Define this macro to control the behavior of connection - * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823 - * for details. - * NOTE: This requires that Windows 2000 systems install Service Pack 2 - * or later. - */ -#ifndef SIO_UDP_CONNRESET -#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) -#endif - -#endif - -/* - * We do asynchronous input using the SIGIO facility. A number of - * recvbuf buffers are preallocated for input. In the signal - * handler we poll to see which sockets are ready and read the - * packets from them into the recvbuf's along with a time stamp and - * an indication of the source host and the interface it was received - * through. This allows us to get as accurate receive time stamps - * as possible independent of other processing going on. - * - * We watch the number of recvbufs available to the signal handler - * and allocate more when this number drops below the low water - * mark. If the signal handler should run out of buffers in the - * interim it will drop incoming frames, the idea being that it is - * better to drop a packet than to be inaccurate. - */ - - -/* - * Other statistics of possible interest - */ -volatile u_long packets_dropped; /* total number of packets dropped on reception */ -volatile u_long packets_ignored; /* packets received on wild card interface */ -volatile u_long packets_received; /* total number of packets received */ -u_long packets_sent; /* total number of packets sent */ -u_long packets_notsent; /* total number of packets which couldn't be sent */ - -volatile u_long handler_calls; /* number of calls to interrupt handler */ -volatile u_long handler_pkts; /* number of pkts received by handler */ -u_long io_timereset; /* time counters were reset */ - -/* - * Interface stuff - */ -struct interface *any_interface; /* default ipv4 interface */ -struct interface *any6_interface; /* default ipv6 interface */ -struct interface *loopback_interface; /* loopback ipv4 interface */ -struct interface *loopback6_interface; /* loopback ipv6 interface */ -struct interface inter_list[MAXINTERFACES]; /* Interface list */ -int ninterfaces; /* Total number of interfaces */ -int nwilds; /* Total number of wildcard intefaces */ -int wildipv4 = -1; /* Index into inter_list for IPv4 wildcard */ -int wildipv6 = -1; /* Index into inter_list for IPv6 wildcard */ - -#ifdef REFCLOCK -/* - * Refclock stuff. We keep a chain of structures with data concerning - * the guys we are doing I/O for. - */ -static struct refclockio *refio; -#endif /* REFCLOCK */ - - -/* - * Define what the possible "soft" errors can be. These are non-fatal returns - * of various network related functions, like recv() and so on. - * - * For some reason, BSDI (and perhaps others) will sometimes return <0 - * from recv() but will have errno==0. This is broken, but we have to - * work around it here. - */ -#define SOFT_ERROR(e) ((e) == EAGAIN || \ - (e) == EWOULDBLOCK || \ - (e) == EINTR || \ - (e) == 0) - -/* - * File descriptor masks etc. for call to select - * Not needed for I/O Completion Ports - */ -fd_set activefds; -int maxactivefd; - -static int create_sockets P((u_short)); -static SOCKET open_socket P((struct sockaddr_storage *, int, int)); -static void close_socket P((SOCKET)); -#ifdef REFCLOCK -static void close_file P((SOCKET)); -#endif -static char * fdbits P((int, fd_set *)); -static void set_reuseaddr P((int)); - -typedef struct vsock vsock_t; - -struct vsock { - SOCKET fd; - ISC_LINK(vsock_t) link; -}; - -ISC_LIST(vsock_t) sockets_list; - -typedef struct remaddr remaddr_t; - -struct remaddr { - struct sockaddr_storage addr; - int if_index; - ISC_LINK(remaddr_t) link; -}; - -ISC_LIST(remaddr_t) remoteaddr_list; - -void add_socket_to_list P((SOCKET)); -void delete_socket_from_list P((SOCKET)); -void add_addr_to_list P((struct sockaddr_storage *, int)); -void delete_addr_from_list P((struct sockaddr_storage *)); -int find_addr_in_list P((struct sockaddr_storage *)); -int create_wildcards P((u_short)); -isc_boolean_t address_okay P((isc_interface_t *)); -void convert_isc_if P((isc_interface_t *, struct interface *, u_short)); - -#ifdef SYS_WINNT -/* - * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom - * to not work correctly, returning a WSACONNRESET error when a WSASendTo - * fails with an "ICMP port unreachable" response and preventing the - * socket from using the WSARecvFrom in subsequent operations. - * The function below fixes this, but requires that Windows 2000 - * Service Pack 2 or later be installed on the system. NT 4.0 - * systems are not affected by this and work correctly. - * See Microsoft Knowledge Base Article Q263823 for details of this. - */ -isc_result_t -connection_reset_fix(SOCKET fd) { - DWORD dwBytesReturned = 0; - BOOL bNewBehavior = FALSE; - DWORD status; - - if(isc_win32os_majorversion() < 5) - return (ISC_R_SUCCESS); /* NT 4.0 has no problem */ - - /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */ - status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior, - sizeof(bNewBehavior), NULL, 0, - &dwBytesReturned, NULL, NULL); - if (status != SOCKET_ERROR) - return (ISC_R_SUCCESS); - else - return (ISC_R_UNEXPECTED); -} -#endif -/* - * init_io - initialize I/O data structures and call socket creation routine - */ -void -init_io(void) -{ -#ifdef SYS_WINNT - init_transmitbuff(); -#endif /* SYS_WINNT */ - - /* - * Init buffer free list and stat counters - */ - init_recvbuff(RECV_INIT); - - packets_dropped = packets_received = 0; - packets_ignored = 0; - packets_sent = packets_notsent = 0; - handler_calls = handler_pkts = 0; - io_timereset = 0; - loopback_interface = NULL; - loopback6_interface = NULL; - -#ifdef REFCLOCK - refio = 0; -#endif - -#if defined(HAVE_SIGNALED_IO) - (void) set_signal(); -#endif - -#ifdef SYS_WINNT - if (!Win32InitSockets()) - { - netsyslog(LOG_ERR, "No useable winsock.dll: %m"); - exit(1); - } -#endif /* SYS_WINNT */ - - ISC_LIST_INIT(sockets_list); - - ISC_LIST_INIT(remoteaddr_list); - - /* - * Create the sockets - */ - BLOCKIO(); - (void) create_sockets(htons(NTP_PORT)); - UNBLOCKIO(); - -#ifdef DEBUG - if (debug) - printf("init_io: maxactivefd %d\n", maxactivefd); -#endif -} - -int -create_wildcards(u_short port) { - - int idx = 0; - /* - * create pseudo-interface with wildcard IPv4 address - */ - inter_list[idx].sin.ss_family = AF_INET; - ((struct sockaddr_in*)&inter_list[idx].sin)->sin_addr.s_addr = htonl(INADDR_ANY); - ((struct sockaddr_in*)&inter_list[idx].sin)->sin_port = port; - (void) strncpy(inter_list[idx].name, "wildcard", sizeof(inter_list[idx].name)); - inter_list[idx].mask.ss_family = AF_INET; - ((struct sockaddr_in*)&inter_list[idx].mask)->sin_addr.s_addr = htonl(~(u_int32)0); - inter_list[idx].bfd = INVALID_SOCKET; - inter_list[idx].num_mcast = 0; - inter_list[idx].received = 0; - inter_list[idx].sent = 0; - inter_list[idx].notsent = 0; - inter_list[idx].flags = INT_BROADCAST; - any_interface = &inter_list[idx]; -#if defined(MCAST) - /* - * enable possible multicast reception on the broadcast socket - */ - inter_list[idx].bcast.ss_family = AF_INET; - ((struct sockaddr_in*)&inter_list[idx].bcast)->sin_port = port; - ((struct sockaddr_in*)&inter_list[idx].bcast)->sin_addr.s_addr = htonl(INADDR_ANY); -#endif /* MCAST */ - wildipv4 = idx; - idx++; - -#ifdef HAVE_IPV6 - /* - * create pseudo-interface with wildcard IPv6 address - */ - if (isc_net_probeipv6() == ISC_R_SUCCESS) { - inter_list[idx].sin.ss_family = AF_INET6; - ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_addr = in6addr_any; - ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_port = port; - (void) strncpy(inter_list[idx].name, "wildcard", sizeof(inter_list[idx].name)); - inter_list[idx].mask.ss_family = AF_INET6; - memset(&((struct sockaddr_in6*)&inter_list[idx].mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr)); - inter_list[idx].bfd = INVALID_SOCKET; - inter_list[idx].num_mcast = 0; - inter_list[idx].received = 0; - inter_list[idx].sent = 0; - inter_list[idx].notsent = 0; - inter_list[idx].flags = 0; - any6_interface = &inter_list[idx]; - wildipv6 = idx; - idx++; - } -#endif - return (idx); -} - -isc_boolean_t -address_okay(isc_interface_t *isc_if) { - -#ifdef DEBUG - if (debug > 2) - printf("address_okay: listen Virtual: %d, IF name: %s, Up Flag: %d\n", - listen_to_virtual_ips, isc_if->name, (isc_if->flags & INTERFACE_F_UP)); -#endif - - if (listen_to_virtual_ips == 0 && (strchr(isc_if->name, (int)':') != NULL)) - return (ISC_FALSE); - - /* XXXPDM This should be fixed later, but since we may not have set - * the UP flag, we at least get to use the interface. - * The UP flag is not always set so we don't do this right now. - */ -/* if ((isc_if->flags & INTERFACE_F_UP) == 0) - return (ISC_FALSE); -*/ - return (ISC_TRUE); -} -void -convert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port) { - - if(isc_if->af == AF_INET) { - itf->sin.ss_family = (u_short) isc_if->af; - strcpy(itf->name, isc_if->name); - memcpy(&(((struct sockaddr_in*)&itf->sin)->sin_addr), - &(isc_if->address.type.in), - sizeof(struct in_addr)); - ((struct sockaddr_in*)&itf->sin)->sin_port = port; - - if((isc_if->flags & INTERFACE_F_BROADCAST) != 0) { - itf->flags |= INT_BROADCAST; - itf->bcast.ss_family = itf->sin.ss_family; - memcpy(&(((struct sockaddr_in*)&itf->bcast)->sin_addr), - &(isc_if->broadcast.type.in), - sizeof(struct in_addr)); - ((struct sockaddr_in*)&itf->bcast)->sin_port = port; - } - - itf->mask.ss_family = itf->sin.ss_family; - memcpy(&(((struct sockaddr_in*)&itf->mask)->sin_addr), - &(isc_if->netmask.type.in), - sizeof(struct in_addr)); - ((struct sockaddr_in*)&itf->mask)->sin_port = port; - - if (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback_interface == NULL)) - { - loopback_interface = itf; - } - } -#ifdef HAVE_IPV6 - else if (isc_if->af == AF_INET6) { - itf->sin.ss_family = (u_short) isc_if->af; - strcpy(itf->name, isc_if->name); - memcpy(&(((struct sockaddr_in6 *)&itf->sin)->sin6_addr), - &(isc_if->address.type.in6), - sizeof(struct in6_addr)); - ((struct sockaddr_in6 *)&itf->sin)->sin6_port = port; - - itf->mask.ss_family = itf->sin.ss_family; - memcpy(&(((struct sockaddr_in6 *)&itf->mask)->sin6_addr), - &(isc_if->netmask.type.in6), - sizeof(struct in6_addr)); - ((struct sockaddr_in6 *)&itf->mask)->sin6_port = port; - - if (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback6_interface == NULL)) - { - loopback6_interface = itf; - } - } -#endif /* HAVE_IPV6 */ - - /* Process the rest of the flags */ - - if((isc_if->flags & INTERFACE_F_UP) != 0) - itf->flags |= INT_UP; - if((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) - itf->flags |= INT_LOOPBACK; - if((isc_if->flags & INTERFACE_F_POINTTOPOINT) != 0) - itf->flags |= INT_PPP; -} -/* - * create_sockets - create a socket for each interface plus a default - * socket for when we don't know where to send - */ -static int -create_sockets( - u_short port - ) -{ - struct sockaddr_storage resmask; - int i; - isc_mem_t *mctx = NULL; - isc_interfaceiter_t *iter = NULL; - isc_boolean_t scan_ipv4 = ISC_FALSE; - isc_boolean_t scan_ipv6 = ISC_FALSE; - isc_result_t result; - int idx = 0; - -#ifdef DEBUG - if (debug) - printf("create_sockets(%d)\n", ntohs( (u_short) port)); -#endif - - if (isc_net_probeipv6() == ISC_R_SUCCESS) - scan_ipv6 = ISC_TRUE; -#ifdef HAVE_IPV6 - else - netsyslog(LOG_ERR, "no IPv6 interfaces found"); -#endif - - if (isc_net_probeipv4() == ISC_R_SUCCESS) - scan_ipv4 = ISC_TRUE; - else - netsyslog(LOG_ERR, "no IPv4 interfaces found"); - - nwilds = create_wildcards(port); - idx = nwilds; - - result = isc_interfaceiter_create(mctx, &iter); - if (result != ISC_R_SUCCESS) - return (result); - - for (result = isc_interfaceiter_first(iter); - result == ISC_R_SUCCESS; - result = isc_interfaceiter_next(iter)) - { - isc_interface_t isc_if; - unsigned int family; - - result = isc_interfaceiter_current(iter, &isc_if); - if (result != ISC_R_SUCCESS) - break; - - /* See if we have a valid family to use */ - family = isc_if.address.family; - if (family != AF_INET && family != AF_INET6) - continue; - if (scan_ipv4 == ISC_FALSE && family == AF_INET) - continue; - if (scan_ipv6 == ISC_FALSE && family == AF_INET6) - continue; - - /* Check to see if we are going to use the interface */ - if (address_okay(&isc_if) == ISC_TRUE) { - convert_isc_if(&isc_if, &inter_list[idx], port); - inter_list[idx].fd = INVALID_SOCKET; - inter_list[idx].bfd = INVALID_SOCKET; - inter_list[idx].num_mcast = 0; - inter_list[idx].received = 0; - inter_list[idx].sent = 0; - inter_list[idx].notsent = 0; - idx++; - } - } - isc_interfaceiter_destroy(&iter); - - ninterfaces = idx; - /* - * I/O Completion Ports don't care about the select and FD_SET - */ -#ifndef HAVE_IO_COMPLETION_PORT - maxactivefd = 0; - FD_ZERO(&activefds); -#endif - for (i = 0; i < ninterfaces; i++) { - inter_list[i].fd = open_socket(&inter_list[i].sin, - inter_list[i].flags & INT_BROADCAST, 0); - if (inter_list[i].bfd != INVALID_SOCKET) - msyslog(LOG_INFO, "Listening on interface %s, %s#%d", - inter_list[i].name, - stoa((&inter_list[i].sin)), - NTP_PORT); - if ((inter_list[i].flags & INT_BROADCAST) && - inter_list[i].bfd != INVALID_SOCKET) - msyslog(LOG_INFO, "Listening on broadcast address %s#%d", - stoa((&inter_list[i].bcast)), - NTP_PORT); -#if defined (HAVE_IO_COMPLETION_PORT) - if (inter_list[i].fd != INVALID_SOCKET) { - io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); - } -#endif - } - - /* - * Now that we have opened all the sockets, turn off the reuse - * flag for security. - */ - set_reuseaddr(0); - - /* - * Blacklist all bound interface addresses - * Wildcard interfaces are ignored. - */ - - for (i = nwilds; i < ninterfaces; i++) { - SET_HOSTMASK(&resmask, inter_list[i].sin.ss_family); - hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, - RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); - } - - /* - * Calculate the address hash for each interface address. - */ - for (i = 0; i < ninterfaces; i++) { - inter_list[i].addr_refid = addr2refid(&inter_list[i].sin); - } - - -#ifdef DEBUG - if (debug > 1) { - printf("create_sockets: ninterfaces=%d\n", ninterfaces); - for (i = 0; i < ninterfaces; i++) { - printf("interface %d: fd=%d, bfd=%d, name=%.8s, flags=0x%x\n", - i, - inter_list[i].fd, - inter_list[i].bfd, - inter_list[i].name, - inter_list[i].flags); - /* Leave these as three printf calls. */ - printf(" sin=%s", - stoa((&inter_list[i].sin))); - if (inter_list[i].flags & INT_BROADCAST) - printf(" bcast=%s,", - stoa((&inter_list[i].bcast))); - printf(" mask=%s\n", - stoa((&inter_list[i].mask))); - } - } -#endif - return ninterfaces; -} - -/* - * io_setbclient - open the broadcast client sockets - */ -void -io_setbclient(void) -{ - int i; - -#ifdef OPEN_BCAST_SOCKET - set_reuseaddr(1); -#endif - for (i = nwilds; i < ninterfaces; i++) { - /* Only IPv4 addresses are valid for broadcast */ - if (inter_list[i].bcast.ss_family != AF_INET) - continue; - - /* Is this a broadcast address? */ - if (!(inter_list[i].flags & INT_BROADCAST)) - continue; - - /* Do we already have the broadcast address open? */ - if (inter_list[i].flags & INT_BCASTOPEN) - continue; - -#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); - if (inter_list[i].bfd != INVALID_SOCKET) { - inter_list[i].flags |= INT_BCASTOPEN; -#if defined (HAVE_IO_COMPLETION_PORT) - io_completion_port_add_socket(inter_list[i].bfd, &inter_list[i]); -#endif - } -#ifdef DEBUG - if (debug) { - if (inter_list[i].bfd != INVALID_SOCKET) - printf("io_setbclient: Opened broadcast client on interface %d, socket: %d\n", - i, inter_list[i].bfd); - else - printf("io_setbclient: Unable to Open broadcast client on interface %d\n", - i); - } -#endif -#endif - } -#ifdef OPEN_BCAST_SOCKET - set_reuseaddr(0); -#endif -#ifdef DEBUG - if (debug) - printf("io_setbclient: Opened broadcast clients\n"); -#endif -} - -/* - * set_reuseaddr() - set/clear REUSEADDR on all sockets - * NB possible hole - should we be doing this on broadcast - * fd's also? - */ -static void -set_reuseaddr(int flag) { - int i; - - for (i=0; i < ninterfaces; i++) { - /* - * if inter_list[ n ].fd is -1, we might have a adapter - * configured but not present - */ - if (inter_list[i].fd != INVALID_SOCKET) { - if (setsockopt(inter_list[i].fd, SOL_SOCKET, - SO_REUSEADDR, (char *)&flag, - sizeof(flag))) { - netsyslog(LOG_ERR, "set_reuseaddr: setsockopt(SO_REUSEADDR, %s) failed: %m", flag ? "on" : "off"); - } - } - } -} - - -/* - * io_multicast_add() - add multicast group address - */ -void -io_multicast_add( - struct sockaddr_storage addr - ) -{ -#ifdef MCAST - struct ip_mreq mreq; - int i = ninterfaces; /* Use the next interface */ - u_int32 haddr = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); - struct in_addr iaddr; - SOCKET s; - struct sockaddr_in *sinp; - -#ifdef HAVE_IPV6 - struct ipv6_mreq mreq6; - struct in6_addr iaddr6; - struct sockaddr_in6 *sin6p; -#endif /* HAVE_IPV6 */ - - switch (addr.ss_family) - { - case AF_INET : - iaddr = (((struct sockaddr_in*)&addr)->sin_addr); - if (!IN_CLASSD(haddr)) { - netsyslog(LOG_ERR, - "multicast address %s not class D", - inet_ntoa(iaddr)); - return; - } - for (i = nwilds; i < ninterfaces; i++) { - /* Be sure it's the correct family */ - if (inter_list[i].sin.ss_family != AF_INET) - continue; - /* Already have this address */ - if (SOCKCMP(&inter_list[i].sin, &addr)) - return; - /* found a free slot */ - if (SOCKNUL(&inter_list[i].sin) && - inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && - inter_list[i].flags == 0) - break; - } - sinp = (struct sockaddr_in*)&(inter_list[i].sin); - memset((char *)&mreq, 0, sizeof(mreq)); - memset((char *)&inter_list[i], 0, sizeof(struct interface)); - sinp->sin_family = AF_INET; - sinp->sin_addr = iaddr; - sinp->sin_port = htons(NTP_PORT); - - /* - * Try opening a socket for the specified class D address. This - * works under SunOS 4.x, but not OSF1 .. :-( - */ - set_reuseaddr(1); - s = open_socket((struct sockaddr_storage*)sinp, 0, 1); - set_reuseaddr(0); - if (s == INVALID_SOCKET) { - memset((char *)&inter_list[i], 0, sizeof(struct interface)); - if (wildipv4 >= 0) { - i = wildipv4; - /* HACK ! -- stuff in an address */ - inter_list[i].bcast = addr; - netsyslog(LOG_ERR, - "...multicast address %s using wildcard socket", - inet_ntoa(iaddr)); - } else { - netsyslog(LOG_ERR, - "No wildcard socket available to use for address %s", - inet_ntoa(iaddr)); - return; - } - } else { - inter_list[i].fd = s; - inter_list[i].bfd = INVALID_SOCKET; - (void) strncpy(inter_list[i].name, "multicast", - sizeof(inter_list[i].name)); - ((struct sockaddr_in*)&inter_list[i].mask)->sin_addr.s_addr = htonl(~(u_int32)0); -#if defined (HAVE_IO_COMPLETION_PORT) - io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); -#endif - } - - /* - * enable reception of multicast packets - */ - mreq.imr_multiaddr = iaddr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) == -1) - netsyslog(LOG_ERR, - "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", - mreq.imr_multiaddr.s_addr, - mreq.imr_interface.s_addr, inet_ntoa(iaddr)); - inter_list[i].flags |= INT_MULTICAST; - inter_list[i].num_mcast++; - if (i >= ninterfaces) - ninterfaces = i+1; - - add_addr_to_list(&addr, i); - break; - -#ifdef HAVE_IPV6 - case AF_INET6 : - - iaddr6 = ((struct sockaddr_in6*)&addr)->sin6_addr; - if (!IN6_IS_ADDR_MULTICAST(&iaddr6)) { - netsyslog(LOG_ERR, - "address %s not IPv6 multicast address", - stoa(&addr)); - return; - } - for (i = nwilds; i < ninterfaces; i++) { - /* Be sure it's the correct family */ - if(inter_list[i].sin.ss_family != AF_INET6) - continue; - /* Already have this address */ - if (SOCKCMP(&inter_list[i].sin, &addr)) - return; - /* found a free slot */ - if (SOCKNUL(&inter_list[i].sin) && - inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && - inter_list[i].flags == 0) - break; - } - sin6p = (struct sockaddr_in6*)&inter_list[i].sin; - memset((char *)&mreq6, 0, sizeof(mreq6)); - memset((char *)&inter_list[i], 0, sizeof(struct interface)); - sin6p->sin6_family = AF_INET6; - sin6p->sin6_addr = iaddr6; - sin6p->sin6_port = htons(NTP_PORT); - - /* - * Try opening a socket for the specified class D address. This - * works under SunOS 4.x, but not OSF1 .. :-( - */ - set_reuseaddr(1); - s = open_socket((struct sockaddr_storage*)sin6p, 0, 1); - set_reuseaddr(0); - if(s == INVALID_SOCKET){ - memset((char *)&inter_list[i], 0, sizeof(struct interface)); - if (wildipv6 >= 0) { - i = wildipv6; - /* HACK ! -- stuff in an address */ - inter_list[i].bcast = addr; - netsyslog(LOG_ERR, - "...multicast address %s using wildcard socket", - stoa(&addr)); - } else { - netsyslog(LOG_ERR, - "No wildcard socket available to use for address %s", - stoa(&addr)); - return; - } - } else { - inter_list[i].fd = s; - inter_list[i].bfd = INVALID_SOCKET; - (void)strncpy(inter_list[i].name, "multicast", - sizeof(inter_list[i].name)); - memset(&(((struct sockaddr_in6*)&inter_list[i].mask)->sin6_addr), 1, sizeof(struct in6_addr)); -#if defined (HAVE_IO_COMPLETION_PORT) - io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); -#endif - } - - /* - * enable reception of multicast packets - */ - mreq6.ipv6mr_multiaddr = iaddr6; - mreq6.ipv6mr_interface = 0; - if(setsockopt(inter_list[i].fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, - (char *)&mreq6, sizeof(mreq6)) == -1) - netsyslog(LOG_ERR, - "setsockopt IPV6_JOIN_GROUP fails: %m on interface %d(%s)", - mreq6.ipv6mr_interface, stoa(&addr)); - inter_list[i].flags |= INT_MULTICAST; - inter_list[i].num_mcast++; - if(i >= ninterfaces) - ninterfaces = i+1; - - add_addr_to_list(&addr, i); - break; -#endif /* HAVE_IPV6 */ - } - -#ifdef DEBUG - if (debug) - printf("io_multicast_add %s\n", stoa(&addr)); -#endif -#else /* MCAST */ - netsyslog(LOG_ERR, - "cannot add multicast address %s as no MCAST support", - stoa(&addr)); -#endif /* MCAST */ -} - -/* - * io_unsetbclient - close the broadcast client sockets - */ -void -io_unsetbclient(void) -{ - int i; - - for (i = nwilds; i < ninterfaces; i++) - { - if (!(inter_list[i].flags & INT_BCASTOPEN)) - continue; - close_socket(inter_list[i].bfd); - inter_list[i].bfd = INVALID_SOCKET; - inter_list[i].flags &= ~INT_BCASTOPEN; - } -} - - -/* - * io_multicast_del() - delete multicast group address - */ -void -io_multicast_del( - struct sockaddr_storage addr - ) -{ -#ifdef MCAST - int i; - struct ip_mreq mreq; - u_int32 haddr; - -#ifdef HAVE_IPV6 - struct ipv6_mreq mreq6; - struct in6_addr haddr6; -#endif /* HAVE_IPV6 */ - - switch (addr.ss_family) - { - case AF_INET : - - haddr = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); - - if (!IN_CLASSD(haddr)) - { - netsyslog(LOG_ERR, - "invalid multicast address %s", stoa(&addr)); - return; - } - - /* - * Disable reception of multicast packets - */ - mreq.imr_multiaddr = ((struct sockaddr_in*)&addr)->sin_addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - for (i = 0; i < ninterfaces; i++) - { - /* Be sure it's the correct family */ - if (inter_list[i].sin.ss_family != AF_INET) - continue; - if (!(inter_list[i].flags & INT_MULTICAST)) - continue; - if (!(inter_list[i].fd < 0)) - continue; - if (!SOCKCMP(&addr, &inter_list[i].sin)) - continue; - if (i != wildipv4) - { - /* we have an explicit fd, so we can close it */ - close_socket(inter_list[i].fd); - memset((char *)&inter_list[i], 0, sizeof(struct interface)); - inter_list[i].fd = INVALID_SOCKET; - inter_list[i].bfd = INVALID_SOCKET; - } - else - { - /* We are sharing "any address" port :-( Don't close it! */ - if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) == -1) - netsyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails on address: %s %m", - stoa(&addr)); - inter_list[i].num_mcast--; - /* If there are none left negate the Multicast flag */ - if(inter_list[i].num_mcast == 0) - inter_list[i].flags &= ~INT_MULTICAST; - } - } - break; - -#ifdef HAVE_IPV6 - case AF_INET6 : - haddr6 = ((struct sockaddr_in6*)&addr)->sin6_addr; - - if (!IN6_IS_ADDR_MULTICAST(&haddr6)) - { - netsyslog(LOG_ERR, - "invalid multicast address %s", stoa(&addr)); - return; - } - - /* - * Disable reception of multicast packets - */ - mreq6.ipv6mr_multiaddr = ((struct sockaddr_in6*)&addr)->sin6_addr; - mreq6.ipv6mr_interface = 0; - for (i = 0; i < ninterfaces; i++) - { - /* Be sure it's the correct family */ - if (inter_list[i].sin.ss_family != AF_INET6) - continue; - if (!(inter_list[i].flags & INT_MULTICAST)) - continue; - if (!(inter_list[i].fd < 0)) - continue; - if (!SOCKCMP(&addr, &inter_list[i].sin)) - continue; - if (i != wildipv6) - { - /* we have an explicit fd, so we can close it */ - close_socket(inter_list[i].fd); - memset((char *)&inter_list[i], 0, sizeof(struct interface)); - inter_list[i].fd = INVALID_SOCKET; - inter_list[i].bfd = INVALID_SOCKET; - } - else - { - /* We are sharing "any address" port :-( Don't close it! */ - if (setsockopt(inter_list[i].fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - (char *)&mreq6, sizeof(mreq6)) == -1) - netsyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails on address %s: %m", - stoa(&addr)); - /* If there are none left negate the Multicast flag */ - if(inter_list[i].num_mcast == 0) - inter_list[i].flags &= ~INT_MULTICAST; - } - } - break; -#endif /* HAVE_IPV6 */ - }/* switch */ - delete_addr_from_list(&addr); - -#else /* not MCAST */ - netsyslog(LOG_ERR, "this function requires multicast kernel"); -#endif /* not MCAST */ -} - - -/* - * open_socket - open a socket, returning the file descriptor - */ - -static SOCKET -open_socket( - struct sockaddr_storage *addr, - int flags, - int turn_off_reuse - ) -{ - int errval; - SOCKET fd; - int on = 1, off = 0; -#if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS) - int tos; -#endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ - - if ((addr->ss_family == AF_INET6) && (isc_net_probeipv6() != ISC_R_SUCCESS)) - return (INVALID_SOCKET); - - /* create a datagram (UDP) socket */ -#ifndef SYS_WINNT - if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) < 0) { - errval = errno; - if(addr->ss_family == AF_INET) - netsyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed on address %s: %m", - stoa(addr)); - else if(addr->ss_family == AF_INET6) - netsyslog(LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed on address %s: %m", - stoa(addr)); - if (errval == EPROTONOSUPPORT || errval == EAFNOSUPPORT || - errval == EPFNOSUPPORT) - return (INVALID_SOCKET); - exit(1); - /*NOTREACHED*/ - } -#else - if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) == INVALID_SOCKET) { - errval = WSAGetLastError(); - if(addr->ss_family == AF_INET) - netsyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed on address %s: %m", - stoa(addr)); - else if(addr->ss_family == AF_INET6) - netsyslog(LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed on address %s: %m", - stoa(addr)); - if (errval == WSAEPROTONOSUPPORT || errval == WSAEAFNOSUPPORT || - errval == WSAEPFNOSUPPORT) - return (INVALID_SOCKET); - exit(1); - /*NOTREACHED*/ - } - if (connection_reset_fix(fd) != ISC_R_SUCCESS) { - netsyslog(LOG_ERR, "connection_reset_fix(fd) failed on address %s: %m", - stoa(addr)); - } - -#endif /* SYS_WINNT */ - - /* set SO_REUSEADDR since we will be binding the same port - number on each interface */ - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof(on))) - { - netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails on address %s: %m", - stoa(addr)); - } - -#if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS) - /* set IP_TOS to minimize packet delay */ - tos = IPTOS_LOWDELAY; - if (addr->ss_family == AF_INET) - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)) < 0) - { - netsyslog(LOG_ERR, "setsockopt IPTOS_LOWDELAY on fails on address %s: %m", - stoa(addr)); - } - -#if defined(IPV6_V6ONLY) - if (addr->ss_family == AF_INET6) - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, - (char*)&on, sizeof(on))) - { - netsyslog(LOG_ERR, "setsockopt IPV6_V6ONLY on fails on address %s: %m", - stoa(addr)); - } -#else /* IPV6_V6ONLY */ -#if defined(IPV6_BINDV6ONLY) - if (addr->ss_family == AF_INET6) - if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY, - (char*)&on, sizeof(on))) - { - netsyslog(LOG_ERR, - "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m", - stoa(addr)); - } -#endif /* IPV6_BINDV6ONLY */ -#endif /* IPV6_V6ONLY */ - -#endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ - - /* - * bind the local address. - */ - if (bind(fd, (struct sockaddr *)addr, SOCKLEN(addr)) < 0) { - char buff[160]; - - if(addr->ss_family == AF_INET) - sprintf(buff, - "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m", - fd, addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), - stoa(addr), - IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), flags); - else if(addr->ss_family == AF_INET6) - sprintf(buff, - "bind() fd %d, family %d, port %d, addr %s, in6_is_addr_multicast=%d flags=%d fails: %%m", - fd, addr->ss_family, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), - stoa(addr), - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), flags); - else return INVALID_SOCKET; - - netsyslog(LOG_ERR, buff); - closesocket(fd); - - /* - * soft fail if opening a multicast address - */ - if(addr->ss_family == AF_INET){ - if(IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr))) - return (INVALID_SOCKET); - } - else { - if(IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) - return (INVALID_SOCKET); - } -#if 0 - exit(1); -#else - return INVALID_SOCKET; -#endif - } -#ifdef DEBUG - if (debug) - printf("bind() fd %d, family %d, port %d, addr %s, flags=%d\n", - fd, - addr->ss_family, - (int)ntohs(((struct sockaddr_in*)addr)->sin_port), - stoa(addr), - flags); -#endif - - /* - * I/O Completion Ports don't care about the select and FD_SET - */ -#ifndef HAVE_IO_COMPLETION_PORT - if (fd > maxactivefd) - maxactivefd = fd; - FD_SET(fd, &activefds); -#endif - add_socket_to_list(fd); - /* - * set non-blocking, - */ - -#ifdef USE_FIONBIO - /* in vxWorks we use FIONBIO, but the others are defined for old systems, so - * all hell breaks loose if we leave them defined - */ -#undef O_NONBLOCK -#undef FNDELAY -#undef O_NDELAY -#endif - -#if defined(O_NONBLOCK) /* POSIX */ - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - { - netsyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails on address %s: %m", - stoa(addr)); - exit(1); - /*NOTREACHED*/ - } -#elif defined(FNDELAY) - if (fcntl(fd, F_SETFL, FNDELAY) < 0) - { - netsyslog(LOG_ERR, "fcntl(FNDELAY) fails on address %s: %m", - stoa(addr)); - exit(1); - /*NOTREACHED*/ - } -#elif defined(O_NDELAY) /* generally the same as FNDELAY */ - if (fcntl(fd, F_SETFL, O_NDELAY) < 0) - { - netsyslog(LOG_ERR, "fcntl(O_NDELAY) fails on address %s: %m", - stoa(addr)); - exit(1); - /*NOTREACHED*/ - } -#elif defined(FIONBIO) -# if defined(VMS) - if (ioctl(fd,FIONBIO,&on) < 0) -# elif defined(SYS_WINNT) - if (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) -# else - if (ioctl(fd,FIONBIO,&on) < 0) -# endif - { - netsyslog(LOG_ERR, "ioctl(FIONBIO) fails on address %s: %m", - stoa(addr)); - exit(1); - /*NOTREACHED*/ - } -#elif defined(FIOSNBIO) - if (ioctl(fd,FIOSNBIO,&on) < 0) - { - netsyslog(LOG_ERR, "ioctl(FIOSNBIO) fails on address %s: %m", - stoa(addr)); - exit(1); - /*NOTREACHED*/ - } -#else -# include "Bletch: Need non-blocking I/O!" -#endif - -#ifdef HAVE_SIGNALED_IO - init_socket_sig(fd); -#endif /* not HAVE_SIGNALED_IO */ - - /* - * Turn off the SO_REUSEADDR socket option. It apparently - * causes heartburn on systems with multicast IP installed. - * On normal systems it only gets looked at when the address - * is being bound anyway.. - */ - if (turn_off_reuse) - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&off, sizeof(off))) - { - netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails on address %s: %m", - stoa(addr)); - } - -#ifdef SO_BROADCAST - /* if this interface can support broadcast, set SO_BROADCAST */ - if (flags & INT_BROADCAST) - { - if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, - (char *)&on, sizeof(on))) - { - netsyslog(LOG_ERR, "setsockopt(SO_BROADCAST) on address %s: %m", - stoa(addr)); - } - } -#endif /* SO_BROADCAST */ - -#if !defined(SYS_WINNT) && !defined(VMS) -# ifdef DEBUG - if (debug > 1) - printf("flags for fd %d: 0%o\n", fd, - fcntl(fd, F_GETFL, 0)); -# endif -#endif /* SYS_WINNT || VMS */ - - return fd; -} - - -/* - * close_socket - close a socket and remove from the activefd list - */ -static void -close_socket( - SOCKET fd - ) -{ - SOCKET i, newmax; - - (void) closesocket(fd); - - /* - * I/O Completion Ports don't care about select and fd_set - */ -#ifndef HAVE_IO_COMPLETION_PORT - FD_CLR( (u_int) fd, &activefds); - - if (fd == maxactivefd) { - newmax = 0; - for (i = 0; i < maxactivefd; i++) - if (FD_ISSET(i, &activefds)) - newmax = i; - maxactivefd = newmax; - } -#endif - delete_socket_from_list(fd); - -} - - -/* - * close_file - close a file and remove from the activefd list - * added 1/31/1997 Greg Schueman for Windows NT portability - */ -#ifdef REFCLOCK -static void -close_file( - SOCKET fd - ) -{ - int i, newmax; - - (void) close(fd); - /* - * I/O Completion Ports don't care about select and fd_set - */ -#ifndef HAVE_IO_COMPLETION_PORT - FD_CLR( (u_int) fd, &activefds); - - if (fd == maxactivefd) { - newmax = 0; - for (i = 0; i < maxactivefd; i++) - if (FD_ISSET(i, &activefds)) - newmax = i; - maxactivefd = newmax; - } -#endif - delete_socket_from_list(fd); - -} -#endif - - -/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ -/* - * sendpkt - send a packet to the specified destination. Maintain a - * send error cache so that only the first consecutive error for a - * destination is logged. - */ -void -sendpkt( - struct sockaddr_storage *dest, - struct interface *inter, - int ttl, - struct pkt *pkt, - int len - ) -{ - int cc, slot; -#ifdef SYS_WINNT - DWORD err; -#endif /* SYS_WINNT */ - - /* - * Send error caches. Empty slots have port == 0 - * Set ERRORCACHESIZE to 0 to disable - */ - struct cache { - u_short port; - struct in_addr addr; - }; - -#ifdef HAVE_IPV6 - struct cache6 { - u_short port; - struct in6_addr addr; - }; -#endif /* HAVE_IPV6 */ - -#ifndef ERRORCACHESIZE -#define ERRORCACHESIZE 8 -#endif -#if ERRORCACHESIZE > 0 - static struct cache badaddrs[ERRORCACHESIZE]; -#ifdef HAVE_IPV6 - static struct cache6 badaddrs6[ERRORCACHESIZE]; -#endif /* HAVE_IPV6 */ -#else -#define badaddrs ((struct cache *)0) /* Only used in empty loops! */ -#ifdef HAVE_IPV6 -#define badaddrs6 ((struct cache6 *)0) /* Only used in empty loops! */ -#endif /* HAVE_IPV6 */ -#endif -#ifdef DEBUG - if (debug > 1) - printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n", - (ttl >= 0) ? "\tMCAST\t*****" : "", - inter->fd, stoa(dest), - stoa(&inter->sin), ttl, len); -#endif - -#ifdef MCAST - - switch (inter->sin.ss_family) { - - case AF_INET : - - /* - * for the moment we use the bcast option to set multicast ttl - */ - if (ttl > 0 && ttl != inter->last_ttl) { - - /* - * set the multicast ttl for outgoing packets - */ - if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, - (char *) &ttl, sizeof(ttl)) != 0) { - netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails on address %s: %m", - stoa(&inter->sin)); - } - else - inter->last_ttl = ttl; - } - break; - -#ifdef HAVE_IPV6 - case AF_INET6 : - - /* - * for the moment we use the bcast option to set - * multicast max hops - */ - if (ttl > 0 && ttl != inter->last_ttl) { - - /* - * set the multicast ttl for outgoing packets - */ - if (setsockopt(inter->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &ttl, sizeof(ttl)) == -1) - netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails on address %s: %m", - stoa(&inter->sin)); - else - inter->last_ttl = ttl; - } - break; -#endif /* HAVE_IPV6 */ - - default : - exit(1); - - } - - -#endif /* MCAST */ - - for (slot = ERRORCACHESIZE; --slot >= 0; ) - if(dest->ss_family == AF_INET) { - if (badaddrs[slot].port == ((struct sockaddr_in*)dest)->sin_port && - badaddrs[slot].addr.s_addr == ((struct sockaddr_in*)dest)->sin_addr.s_addr) - break; - } -#ifdef HAVE_IPV6 - else if (dest->ss_family == AF_INET6) { - if (badaddrs6[slot].port == ((struct sockaddr_in6*)dest)->sin6_port && - badaddrs6[slot].addr.s6_addr == ((struct sockaddr_in6*)dest)->sin6_addr.s6_addr) - break; - } -#endif /* HAVE_IPV6 */ - else exit(1); /* address family not supported yet */ - -#if defined(HAVE_IO_COMPLETION_PORT) - err = io_completion_port_sendto(inter, pkt, len, dest); - if (err != ERROR_SUCCESS) -#else -#ifdef SIM - cc = srvr_rply(&ntp_node, dest, inter, pkt); -#else /* SIM */ - cc = sendto(inter->fd, (char *)pkt, (unsigned int)len, 0, (struct sockaddr *)dest, - SOCKLEN(dest)); -#endif /* SIM */ - if (cc == -1) -#endif - { - inter->notsent++; - packets_notsent++; -#if defined(HAVE_IO_COMPLETION_PORT) - err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) -#else - if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) -#endif - { - /* - * Remember this, if there's an empty slot - */ - switch (dest->ss_family) { - - case AF_INET : - - for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs[slot].port == 0) - { - badaddrs[slot].port = SRCPORT(dest); - badaddrs[slot].addr = ((struct sockaddr_in*)dest)->sin_addr; - break; - } - break; - -#ifdef HAVE_IPV6 - case AF_INET6 : - - for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs6[slot].port == 0) - { - badaddrs6[slot].port = SRCPORT(dest); - badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr; - break; - } - break; -#endif /* HAVE_IPV6 */ - - default : - exit(1); - } - - netsyslog(LOG_ERR, "sendto(%s): %m", stoa(dest)); - } - } - else - { - inter->sent++; - packets_sent++; - /* - * He's not bad any more - */ - if (slot >= 0) - { - netsyslog(LOG_INFO, "Connection re-established to %s", stoa(dest)); - switch (dest->ss_family) { - case AF_INET : - badaddrs[slot].port = 0; - break; -#ifdef HAVE_IPV6 - case AF_INET6 : - badaddrs6[slot].port = 0; - break; -#endif /* HAVE_IPV6 */ - } - } - } -} - -#if !defined(HAVE_IO_COMPLETION_PORT) -/* - * fdbits - generate ascii representation of fd_set (FAU debug support) - * HFDF format - highest fd first. - */ -static char * -fdbits( - int count, - fd_set *set - ) -{ - static char buffer[256]; - char * buf = buffer; - - count = (count < 256) ? count : 255; - - while (count >= 0) - { - *buf++ = FD_ISSET(count, set) ? '#' : '-'; - count--; - } - *buf = '\0'; - - return buffer; -} - -/* - * input_handler - receive packets asynchronously - */ -void -input_handler( - l_fp *cts - ) -{ - register int i, n; - register struct recvbuf *rb; - register int doing; - register SOCKET fd; - struct timeval tvzero; - int fromlen; - l_fp ts; /* Timestamp at BOselect() gob */ - l_fp ts_e; /* Timestamp at EOselect() gob */ - fd_set fds; - int select_count = 0; - static int handler_count = 0; - - ++handler_count; - if (handler_count != 1) - msyslog(LOG_ERR, "input_handler: handler_count is %d!", handler_count); - handler_calls++; - ts = *cts; - - for (;;) - { - /* - * Do a poll to see who has data - */ - - fds = activefds; - tvzero.tv_sec = tvzero.tv_usec = 0; - - /* - * If we have something to do, freeze a timestamp. - * See below for the other cases (nothing (left) to do or error) - */ - while (0 < (n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero))) - { - ++select_count; - ++handler_pkts; - -#ifdef REFCLOCK - /* - * Check out the reference clocks first, if any - */ - if (refio != 0) - { - register struct refclockio *rp; - - for (rp = refio; rp != 0 && n > 0; rp = rp->next) - { - fd = rp->fd; - if (FD_ISSET(fd, &fds)) - { - n--; - if (free_recvbuffs() == 0) - { - char buf[RX_BUFF_SIZE]; - - (void) read(fd, buf, sizeof buf); - packets_dropped++; - goto select_again; - } - - rb = get_free_recv_buffer(); - - i = (rp->datalen == 0 - || rp->datalen > sizeof(rb->recv_space)) - ? sizeof(rb->recv_space) : rp->datalen; - rb->recv_length = - read(fd, (char *)&rb->recv_space, (unsigned)i); - - if (rb->recv_length == -1) - { - netsyslog(LOG_ERR, "clock read fd %d: %m", fd); - freerecvbuf(rb); - goto select_again; - } - - /* - * Got one. Mark how - * and when it got here, - * put it on the full - * list and do - * bookkeeping. - */ - rb->recv_srcclock = rp->srcclock; - rb->dstadr = 0; - rb->fd = fd; - rb->recv_time = ts; - rb->receiver = rp->clock_recv; - - if (rp->io_input) - { - /* - * have direct - * input routine - * for refclocks - */ - if (rp->io_input(rb) == 0) - { - /* - * data - * was - * consumed - * - - * nothing - * to - * pass - * up - * into - * block - * input - * machine - */ - freerecvbuf(rb); -#if 1 - goto select_again; -#else - continue; -#endif - } - } - - add_full_recv_buffer(rb); - - rp->recvcount++; - packets_received++; - } - } - } -#endif /* REFCLOCK */ - - /* - * Loop through the interfaces looking for data - * to read. - */ - for (i = ninterfaces - 1; (i >= 0) && (n > 0); i--) - { - for (doing = 0; (doing < 2) && (n > 0); doing++) - { - if (doing == 0) - { - fd = inter_list[i].fd; - } - else - { - if (!(inter_list[i].flags & INT_BCASTOPEN)) - break; - fd = inter_list[i].bfd; - } - if (fd < 0) continue; - if (FD_ISSET(fd, &fds)) - { - n--; - - /* - * Get a buffer and read - * the frame. If we - * haven't got a buffer, - * or this is received - * on the wild card - * socket, just dump the - * packet. - */ - if ( -#ifdef UDP_WILDCARD_DELIVERY - /* - * these guys manage to put properly addressed - * packets into the wildcard queue - */ - (free_recvbuffs() == 0) -#else - ((i == wildipv4) || (i == wildipv6)|| - (free_recvbuffs() == 0)) -#endif - ) - { - char buf[RX_BUFF_SIZE]; - struct sockaddr_storage from; - - fromlen = sizeof from; - (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen); -#ifdef DEBUG - if (debug) - printf("%s on %d(%lu) fd=%d from %s\n", - (i) ? "drop" : "ignore", - i, free_recvbuffs(), fd, - stoa(&from)); -#endif - if (i == wildipv4 || i == wildipv6) - packets_ignored++; - else - packets_dropped++; - goto select_again; - } - - rb = get_free_recv_buffer(); - - fromlen = sizeof(struct sockaddr_storage); - rb->recv_length = recvfrom(fd, - (char *)&rb->recv_space, - sizeof(rb->recv_space), 0, - (struct sockaddr *)&rb->recv_srcadr, - &fromlen); - if (rb->recv_length == 0 -#ifdef EWOULDBLOCK - || errno==EWOULDBLOCK -#endif -#ifdef EAGAIN - || errno==EAGAIN -#endif - ) { - freerecvbuf(rb); - continue; - } - else if (rb->recv_length < 0) - { - netsyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", - stoa(&rb->recv_srcadr), fd); -#ifdef DEBUG - if (debug) - printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); -#endif - freerecvbuf(rb); - continue; - } -#ifdef DEBUG - if (debug > 2) { - if(rb->recv_srcadr.ss_family == AF_INET) - printf("input_handler: if=%d fd=%d length %d from %08lx %s\n", - i, fd, rb->recv_length, - (u_long)ntohl(((struct sockaddr_in*)&rb->recv_srcadr)->sin_addr.s_addr) & - 0x00000000ffffffff, - stoa(&rb->recv_srcadr)); - else - printf("input_handler: if=%d fd=%d length %d from %s\n", - i, fd, rb->recv_length, - stoa(&rb->recv_srcadr)); - } -#endif - - /* - * Got one. Mark how and when it got here, - * put it on the full list and do bookkeeping. - */ - rb->dstadr = &inter_list[i]; - rb->fd = fd; - rb->recv_time = ts; - rb->receiver = receive; - - add_full_recv_buffer(rb); - - inter_list[i].received++; - packets_received++; - goto select_again; - } - /* Check more interfaces */ - } - } - select_again:; - /* - * Done everything from that select. Poll again. - */ - } - - /* - * If nothing more to do, try again. - * If nothing to do, just return. - * If an error occurred, complain and return. - */ - if (n == 0) - { - if (select_count == 0) /* We really had nothing to do */ - { - if (debug) - netsyslog(LOG_DEBUG, "input_handler: select() returned 0"); - --handler_count; - return; - } - /* We've done our work */ - get_systime(&ts_e); - /* - * (ts_e - ts) is the amount of time we spent - * processing this gob of file descriptors. Log - * it. - */ - L_SUB(&ts_e, &ts); - if (debug > 3) - netsyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); - - /* just bail. */ - --handler_count; - return; - } - else if (n == -1) - { - int err = errno; - - /* - * extended FAU debugging output - */ - if (err != EINTR) - netsyslog(LOG_ERR, - "select(%d, %s, 0L, 0L, &0.0) error: %m", - maxactivefd+1, - fdbits(maxactivefd, &activefds)); - if (err == EBADF) { - int j, b; - - fds = activefds; - for (j = 0; j <= maxactivefd; j++) - if ( - (FD_ISSET(j, &fds) && (read(j, &b, 0) == -1)) - ) - netsyslog(LOG_ERR, "Bad file descriptor %d", j); - } - --handler_count; - return; - } - } - msyslog(LOG_ERR, "input_handler: fell out of infinite for(;;) loop!"); - --handler_count; - return; -} - -#endif -/* - * findinterface - find interface corresponding to address - */ -struct interface * -findinterface( - struct sockaddr_storage *addr - ) -{ - SOCKET s; - int rtn, i; - struct sockaddr_storage saddr; - int saddrlen = SOCKLEN(addr); - /* - * This is considerably hoke. We open a socket, connect to it - * and slap a getsockname() on it. If anything breaks, as it - * probably will in some j-random knockoff, we just return the - * wildcard interface. - */ - memset(&saddr, 0, sizeof(saddr)); - saddr.ss_family = addr->ss_family; - if(addr->ss_family == AF_INET) - memcpy(&((struct sockaddr_in*)&saddr)->sin_addr, &((struct sockaddr_in*)addr)->sin_addr, sizeof(struct in_addr)); - else if(addr->ss_family == AF_INET6) - memcpy(&((struct sockaddr_in6*)&saddr)->sin6_addr, &((struct sockaddr_in6*)addr)->sin6_addr, sizeof(struct in6_addr)); - ((struct sockaddr_in*)&saddr)->sin_port = htons(2000); - s = socket(addr->ss_family, SOCK_DGRAM, 0); - if (s == INVALID_SOCKET) - return ANY_INTERFACE_CHOOSE(addr); - - rtn = connect(s, (struct sockaddr *)&saddr, SOCKLEN(&saddr)); -#ifndef SYS_WINNT - if (rtn < 0) -#else - if (rtn == SOCKET_ERROR) -#endif - { - closesocket(s); - return ANY_INTERFACE_CHOOSE(addr); - } - - rtn = getsockname(s, (struct sockaddr *)&saddr, &saddrlen); - closesocket(s); -#ifndef SYS_WINNT - if (rtn < 0) -#else - if (rtn == SOCKET_ERROR) -#endif - return ANY_INTERFACE_CHOOSE(addr); - - for (i = 0; i < ninterfaces; i++) { - /* - * First look if is the the correct family - */ - if(inter_list[i].sin.ss_family != saddr.ss_family) - continue; - /* - * We match the unicast address only. - */ - if (SOCKCMP(&inter_list[i].sin, &saddr)) - return (&inter_list[i]); - } - return ANY_INTERFACE_CHOOSE(addr); -} - -/* - * findbcastinter - find broadcast interface corresponding to address - */ -struct interface * -findbcastinter( - struct sockaddr_storage *addr - ) -{ -#if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT)) - register int i; - - i = find_addr_in_list(addr); - if(i >= 0) - return (&inter_list[i]); - - for (i = 0; i < ninterfaces; i++) { - /* - * First look if this is the correct family - */ - if(inter_list[i].sin.ss_family != addr->ss_family) - continue; - /* - * We match only those interfaces marked as - * broadcastable and either the explicit broadcast - * address or the network portion of the IP address. - * Sloppy. - */ - if (!(inter_list[i].flags & INT_BROADCAST)) - continue; - if(addr->ss_family == AF_INET) { - if (SOCKCMP(&inter_list[i].bcast, addr)) - return (&inter_list[i]); - if ((NSRCADR(&inter_list[i].sin) & - NSRCADR(&inter_list[i].mask)) == (NSRCADR(addr) & - NSRCADR(&inter_list[i].mask))) - return (&inter_list[i]); - } - else if(addr->ss_family == AF_INET6) { - if (SOCKCMP(&inter_list[i].bcast, addr)) - return (&inter_list[i]); - if (SOCKCMP(netof(&inter_list[i].sin), netof(addr))) - return (&inter_list[i]); - } - } -#endif /* SIOCGIFCONF */ - return ANY_INTERFACE_CHOOSE(addr); -} - - -/* - * io_clr_stats - clear I/O module statistics - */ -void -io_clr_stats(void) -{ - packets_dropped = 0; - packets_ignored = 0; - packets_received = 0; - packets_sent = 0; - packets_notsent = 0; - - handler_calls = 0; - handler_pkts = 0; - io_timereset = current_time; -} - - -#ifdef REFCLOCK -/* - * This is a hack so that I don't have to fool with these ioctls in the - * pps driver ... we are already non-blocking and turn on SIGIO thru - * another mechanisim - */ -int -io_addclock_simple( - struct refclockio *rio - ) -{ - BLOCKIO(); - /* - * Stuff the I/O structure in the list and mark the descriptor - * in use. There is a harmless (I hope) race condition here. - */ - rio->next = refio; - refio = rio; - - /* - * I/O Completion Ports don't care about select and fd_set - */ -#ifndef HAVE_IO_COMPLETION_PORT - if (rio->fd > maxactivefd) - maxactivefd = rio->fd; - FD_SET(rio->fd, &activefds); -#endif - UNBLOCKIO(); - return 1; -} - -/* - * io_addclock - add a reference clock to the list and arrange that we - * get SIGIO interrupts from it. - */ -int -io_addclock( - struct refclockio *rio - ) -{ - BLOCKIO(); - /* - * Stuff the I/O structure in the list and mark the descriptor - * in use. There is a harmless (I hope) race condition here. - */ - rio->next = refio; - refio = rio; - -# ifdef HAVE_SIGNALED_IO - if (init_clock_sig(rio)) - { - refio = rio->next; - UNBLOCKIO(); - return 0; - } -# elif defined(HAVE_IO_COMPLETION_PORT) - if (io_completion_port_add_clock_io(rio)) - { - add_socket_to_list(rio->fd); - refio = rio->next; - UNBLOCKIO(); - return 0; - } -# endif - - /* - * I/O Completion Ports don't care about select and fd_set - */ -#ifndef HAVE_IO_COMPLETION_PORT - if (rio->fd > maxactivefd) - maxactivefd = rio->fd; - FD_SET(rio->fd, &activefds); -#endif - UNBLOCKIO(); - return 1; -} - -/* - * io_closeclock - close the clock in the I/O structure given - */ -void -io_closeclock( - struct refclockio *rio - ) -{ - /* - * Remove structure from the list - */ - if (refio == rio) - { - refio = rio->next; - } - else - { - register struct refclockio *rp; - - for (rp = refio; rp != 0; rp = rp->next) - if (rp->next == rio) - { - rp->next = rio->next; - break; - } - - if (rp == 0) - { - /* - * Internal error. Report it. - */ - msyslog(LOG_ERR, - "internal error: refclockio structure not found"); - return; - } - } - - /* - * Close the descriptor. - */ - close_file(rio->fd); -} -#endif /* REFCLOCK */ - - /* - * I/O Completion Ports don't care about select and fd_set - */ -#ifndef HAVE_IO_COMPLETION_PORT -void -kill_asyncio( - int startfd - ) -{ - SOCKET i; - - BLOCKIO(); - for (i = startfd; i <= maxactivefd; i++) - (void)close_socket(i); -} -#else -/* - * On NT a SOCKET is an unsigned int so we cannot possibly keep it in - * an array. So we use one of the ISC_LIST functions to hold the - * socket value and use that when we want to enumerate it. - */ -void -kill_asyncio(int startfd) -{ - vsock_t *lsock; - vsock_t *next; - - BLOCKIO(); - - lsock = ISC_LIST_HEAD(sockets_list); - while (lsock != NULL) { - next = ISC_LIST_NEXT(lsock, link); - close_socket(lsock->fd); - lsock = next; - } - -} -#endif -/* - * Add and delete functions for the list of open sockets - */ -void -add_socket_to_list(SOCKET fd){ - vsock_t *lsock = malloc(sizeof(vsock_t)); - lsock->fd = fd; - - ISC_LIST_APPEND(sockets_list, lsock, link); -} -void -delete_socket_from_list(SOCKET fd) { - - vsock_t *next; - vsock_t *lsock = ISC_LIST_HEAD(sockets_list); - - while(lsock != NULL) { - next = ISC_LIST_NEXT(lsock, link); - if(lsock->fd == fd) { - ISC_LIST_DEQUEUE(sockets_list, lsock, link); - free(lsock); - break; - } - else - lsock = next; - } -} -void -add_addr_to_list(struct sockaddr_storage *addr, int if_index){ - remaddr_t *laddr = malloc(sizeof(remaddr_t)); - memcpy(&laddr->addr, addr, sizeof(addr)); - laddr->if_index = if_index; - - ISC_LIST_APPEND(remoteaddr_list, laddr, link); -#ifdef DEBUG - if (debug) - printf("Added addr %s to list of addresses\n", - stoa(addr)); -#endif - - -} -void -delete_addr_from_list(struct sockaddr_storage *addr) { - - remaddr_t *next; - remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list); - - while(laddr != NULL) { - next = ISC_LIST_NEXT(laddr, link); - if(SOCKCMP(&laddr->addr, addr)) { - ISC_LIST_DEQUEUE(remoteaddr_list, laddr, link); - free(laddr); - break; - } - else - laddr = next; - } -#ifdef DEBUG - if (debug) - printf("Deleted addr %s from list of addresses\n", - stoa(addr)); -#endif -} -int -find_addr_in_list(struct sockaddr_storage *addr) { - - remaddr_t *next; - remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list); -#ifdef DEBUG - if (debug) - printf("Finding addr %s in list of addresses\n", - stoa(addr)); -#endif - - while(laddr != NULL) { - next = ISC_LIST_NEXT(laddr, link); - if(SOCKCMP(&laddr->addr, addr)) { - return (laddr->if_index); - break; - } - else - laddr = next; - } - return (-1); /* Not found */ -} diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c deleted file mode 100644 index 99d1cc4..0000000 --- a/contrib/ntp/ntpd/ntp_loopfilter.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * ntp_loopfilter.c - implements the NTP loop filter algorithm - * - * ATTENTION: Get approval from Dave Mills on all changes to this file! - * - */ -#ifdef HAVE_CONFIG_H -# include <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 <signal.h> -#include <setjmp.h> - -#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ -#include "ntp_refclock.h" -#endif /* VMS */ - -#ifdef KERNEL_PLL -#include "ntp_syscall.h" -#endif /* KERNEL_PLL */ - -/* - * This is an implementation of the clock discipline algorithm described - * in UDel TR 97-4-3, as amended. It operates as an adaptive parameter, - * hybrid phase/frequency-lock loop. A number of sanity checks are - * included to protect against timewarps, timespikes and general mayhem. - * All units are in s and s/s, unless noted otherwise. - */ -#define CLOCK_MAX .128 /* default step threshold (s) */ -#define CLOCK_MINSTEP 900. /* default stepout threshold (s) */ -#define CLOCK_PANIC 1000. /* default panic threshold (s) */ -#define CLOCK_PHI 15e-6 /* max frequency error (s/s) */ -#define CLOCK_PLL 16. /* PLL loop gain */ -#define CLOCK_FLL 8. /* FLL loop gain */ -#define CLOCK_AVG 4. /* parameter averaging constant */ -#define CLOCK_ALLAN 1500. /* compromise Allan intercept (s) */ -#define CLOCK_DAY 86400. /* one day in seconds (s) */ -#define CLOCK_LIMIT 30 /* poll-adjust threshold */ -#define CLOCK_PGATE 4. /* poll-adjust gate */ -#define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */ - -/* - * Clock discipline state machine. This is used to control the - * synchronization behavior during initialization and following a - * 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 */ -#define S_TSET 2 /* time set */ -#define S_FREQ 3 /* frequency mode */ -#define S_SYNC 4 /* clock synchronized */ -#define S_SPIK 5 /* spike detected */ - -/* - * Kernel PLL/PPS state machine. This is used with the kernel PLL - * modifications described in the README.kernel file. - * - * If kernel support for the ntp_adjtime() system call is available, the - * ntp_control flag is set. The ntp_enable and kern_enable flags can be - * set at configuration time or run time using ntpdc. If ntp_enable is - * false, the discipline loop is unlocked and no correctios of any kind - * are made. If both ntp_control and kern_enable are set, the kernel - * 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_stratum if it survives the - * intersection algorithm and its time is within range. The PPS time - * discipline is enabled (STA_PPSTIME bit set in the status word) when - * pps_stratum is true and the PPS frequency discipline is enabled. If - * the PPS time discipline is enabled and the kernel reports a PPS - * signal is present, the pps_control variable is set to the current - * time. If the current time is later than pps_control by PPS_MAXAGE - * (120 s), this variable is set to zero. - * - * If an external clock is present, the clock driver sets STA_CLK in the - * status word. When the local clock driver sees this bit, it updates - * via this routine, which then calls ntp_adjtime() with the STA_PLL bit - * set to zero, in which case the system clock is not adjusted. This is - * also a signal for the external clock driver to discipline the system - * clock. - */ -/* - * Program variables that can be tinkered. - */ -double clock_max = CLOCK_MAX; /* step threshold (s) */ -double clock_minstep = CLOCK_MINSTEP; /* stepout threshold (s) */ -double clock_panic = CLOCK_PANIC; /* panic threshold (s) */ -double clock_phi = CLOCK_PHI; /* dispersion rate (s/s) */ -double allan_xpt = CLOCK_ALLAN; /* Allan intercept (s) */ - -/* - * Program variables - */ -static double clock_offset; /* clock offset adjustment (s) */ -double drift_comp; /* clock frequency (s/s) */ -double clock_stability; /* clock stability (s/s) */ -u_long pps_control; /* last pps sample time */ -static void rstclock P((int, u_long, double)); /* transition function */ - -#ifdef 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 */ - -/* - * Clock state machine control flags - */ -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_stratum; /* pps stratum */ -int allow_panic = FALSE; /* allow panic correction */ -int mode_ntpdate = FALSE; /* exit on first clock set */ - -/* - * Clock state machine variables - */ -u_char sys_poll = NTP_MINDPOLL; /* system poll interval (log2 s) */ -int state; /* clock discipline state */ -int tc_counter; /* hysteresis counter */ -u_long last_time; /* time of last clock update (s) */ -double last_offset; /* last clock offset (s) */ -double sys_jitter; /* system RMS jitter (s) */ - -/* - * 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) -#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() */ -#endif /* SIGSYS */ -#endif /* KERNEL_PLL */ - -/* - * init_loopfilter - initialize loop filter data - */ -void -init_loopfilter(void) -{ - /* - * Initialize state variables. Initially, we expect no drift - * file, so set the state to S_NSET. - */ - rstclock(S_NSET, current_time, 0); -} - -/* - * local_clock - the NTP logical clock loop filter. Returns 1 if the - * clock was stepped, 0 if it was slewed and -1 if it is hopeless. - * - * LOCKCLOCK: The only thing this routine does is set the - * sys_rootdispersion variable equal to the peer dispersion. - */ -int -local_clock( - struct peer *peer, /* synch source peer structure */ - double fp_offset, /* clock offset (s) */ - double epsil /* jittter (square s*s) */ - ) -{ - u_long mu; /* interval since last update (s) */ - double oerror; /* previous error estimate */ - double flladj; /* FLL frequency adjustment (ppm) */ - double plladj; /* PLL frequency adjustment (ppm) */ - double clock_frequency; /* clock frequency adjustment (ppm) */ - double dtemp, etemp; /* double temps */ - int retval; /* return value */ - - /* - * 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: assocID %d offset %.9f jitter %.9f state %d\n", - peer->associd, fp_offset, SQRT(epsil), state); -#endif -#ifdef LOCKCLOCK - sys_rootdispersion = peer->rootdispersion; - return (0); - -#else /* LOCKCLOCK */ - if (!ntp_enable) { - record_loop_stats(fp_offset, drift_comp, SQRT(epsil), - clock_stability, sys_poll); - return (0); - } - - /* - * 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. - */ - if (fabs(fp_offset) > clock_panic && clock_panic > 0 && - !allow_panic) { - msyslog(LOG_ERR, - "time correction of %.0f seconds exceeds sanity limit (%.0f); set clock manually to the correct UTC time.", - fp_offset, clock_panic); - return (-1); - } - - /* - * If simulating ntpdate, set the clock directly, rather than - * using the discipline. The clock_max defines the step - * threshold, above which the clock will be stepped instead of - * slewed. The value defaults to 128 ms, but can be set to even - * unreasonable values. If set to zero, the clock will never be - * stepped. - * - * Note that if ntpdate is active, the terminal does not detach, - * so the termination comments print directly to the console. - */ - if (mode_ntpdate) { - if (fabs(fp_offset) > clock_max && clock_max > 0) { - step_systime(fp_offset); - msyslog(LOG_NOTICE, "time reset %+.6f s", - fp_offset); - printf("ntpd: time set %+.6fs\n", fp_offset); - } else { - adj_systime(fp_offset); - 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 - * speed the inital convergence process. If lucky, after an hour - * the ntp.drift file is created and initialized and we don't - * get here again. - */ - if (state == S_NSET) { - if (fabs(fp_offset) > clock_max && clock_max > 0) { - step_systime(fp_offset); - msyslog(LOG_NOTICE, "time reset %+.6f s", - fp_offset); - reinit_timer(); - } - rstclock(S_FREQ, peer->epoch, 0); - return (1); - } - - /* - * Update the jitter estimate. - */ - 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 - * 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 = peer->epoch - last_time; - if (fabs(fp_offset) > clock_max && clock_max > 0) { - switch (state) { - - /* - * In S_TSET state the time has been set at the last - * valid update and the offset at that time set to zero. - * If following that we cruise outside the capture - * range, assume a really bad frequency error and switch - * to S_FREQ state. - */ - case S_TSET: - state = S_FREQ; - break; - - /* - * In S_SYNC state we ignore outlyers. At the first - * outlyer after the stepout threshold, switch to S_SPIK - * state. - */ - case S_SYNC: - if (mu < clock_minstep) - return (0); - state = S_SPIK; - return (0); - - /* - * In S_FREQ state we ignore outlyers. At the first - * outlyer after 900 s, compute the apparent phase and - * frequency correction. - */ - case S_FREQ: - if (mu < clock_minstep) - return (0); - /* fall through to S_SPIK */ - - /* - * In S_SPIK state a large correction is necessary. - * Since the outlyer may be due to a large frequency - * error, compute the apparent frequency correction. - */ - case S_SPIK: - clock_frequency = (fp_offset - clock_offset) / - mu; - /* fall through to default */ - - /* - * We get here directly in S_FSET state and indirectly - * from S_FREQ and S_SPIK states. The clock is either - * reset or shaken, but never stirred. - */ - default: - step_systime(fp_offset); - msyslog(LOG_NOTICE, "time reset %+.6f s", - fp_offset); - reinit_timer(); - rstclock(S_TSET, peer->epoch, 0); - retval = 1; - break; - } - } else { - switch (state) { - - /* - * 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, peer->epoch, fp_offset); - break; - - /* - * In S_FREQ state ignore updates until the stepout - * threshold. After that, correct the phase and - * frequency and switch to S_SYNC state. - */ - case S_FREQ: - if (mu < clock_minstep) - return (0); - clock_frequency = (fp_offset - clock_offset) / - mu; - rstclock(S_SYNC, peer->epoch, fp_offset); - break; - - /* - * Either the clock has just been set or the previous - * update was a spike and ignored. Since this update is - * not an outlyer, fold the tent and resume life. - */ - case S_TSET: - case S_SPIK: - state = S_SYNC; - /* fall through to default */ - - /* - * We come here in the normal case for linear phase and - * frequency adjustments. If the difference between the - * last offset and the current one exceeds the jitter by - * CLOCK_SGATE and the interval since the last update is - * less than twice the system poll interval, consider - * the update a popcorn spike and ignore it.. - */ - default: - allow_panic = FALSE; - dtemp = fabs(fp_offset - last_offset); -/* - if (dtemp > CLOCK_SGATE * oerror && mu < - (u_long) ULOGTOD(sys_poll + 1)) { -#ifdef DEBUG - if (debug) - printf( - "local_clock: popcorn %.6f %.6f\n", - dtemp, oerror); -#endif - last_offset = fp_offset; - return (0); - } -*/ - - /* - * The FLL and PLL frequency gain constants - * depend on the poll interval and Allan - * intercept. The PLL constant is calculated - * throughout the poll interval range, but the - * update interval is clamped so as not to - * exceed the poll interval. The FLL gain is - * zero below one-half the Allan intercept and - * unity at MAXPOLL. It decreases as 1 / - * (MAXPOLL + 1 - poll interval) in a feeble - * effort to match the loop stiffness to the - * Allan wobble. Particularly for the PLL, these - * measures allow oversampling, but not - * undersampling and insure stability even when - * the rules of fair engagement are broken. - */ - if (ULOGTOD(sys_poll) > allan_xpt / 2) { - dtemp = NTP_MAXPOLL + 1 - sys_poll; - flladj = (fp_offset - clock_offset) / - (max(mu, allan_xpt) * dtemp); - } - etemp = min(mu, (u_long)ULOGTOD(sys_poll)); - dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll); - plladj = fp_offset * etemp / (dtemp * dtemp); - last_time = peer->epoch; - last_offset = clock_offset = fp_offset; - break; - } - } - -#ifdef KERNEL_PLL - /* - * This code segment works when clock adjustments are made using - * precision time kernel support and the ntp_adjtime() system - * call. This support is available in Solaris 2.6 and later, - * Digital Unix 4.0 and later, FreeBSD, Linux and specially - * modified kernels for HP-UX 9 and Ultrix 4. In the case of the - * DECstation 5000/240 and Alpha AXP, additional kernel - * modifications provide a true microsecond clock and nanosecond - * clock, respectively. - */ - if (pll_control && kern_enable) { - - /* - * We initialize the structure for the ntp_adjtime() - * system call. We have to convert everything to - * microseconds or nanoseconds first. Do not update the - * system variables if the ext_enable flag is set. In - * this case, the external clock driver will update the - * variables, which will be read later by the local - * clock driver. Afterwards, remember the time and - * frequency offsets for jitter and stability values and - * to update the drift file. - */ - memset(&ntv, 0, sizeof(ntv)); - if (ext_enable) { - ntv.modes = MOD_STATUS; - } else { - ntv.modes = MOD_BITS; - if (clock_offset < 0) - dtemp = -.5; - else - dtemp = .5; - if (pll_nano) { - ntv.offset = (int32)(clock_offset * - 1e9 + dtemp); - 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); - } - ntv.esterror = (u_int32)(sys_jitter * 1e6); - ntv.maxerror = (u_int32)((sys_rootdelay / 2 + - sys_rootdispersion) * 1e6); - ntv.status = STA_PLL; - - /* - * Set the leap bits in the status word. - */ - if (sys_leap == LEAP_NOTINSYNC) { - ntv.status |= STA_UNSYNC; - } else if (calleapwhen(sys_reftime.l_ui) < - CLOCK_DAY) { - if (sys_leap & LEAP_ADDSECOND) - ntv.status |= STA_INS; - else if (sys_leap & LEAP_DELSECOND) - ntv.status |= STA_DEL; - } - - /* - * Switch to FLL mode if the poll interval is - * greater than MAXDPOLL, so that the kernel - * loop behaves as the daemon loop; viz., - * selects the FLL when necessary, etc. For - * legacy only. - */ - if (sys_poll > NTP_MAXDPOLL) - ntv.status |= STA_FLL; - - /* - * 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); - } - } - - /* - * 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) - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "kernel time sync disabled %04x", - ntv.status); - ntv.status &= ~(STA_PPSFREQ | STA_PPSTIME); - } else { - if (ntv.status != pll_status) - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "kernel time sync enabled %04x", - ntv.status); - } - pll_status = ntv.status; - if (pll_nano) - clock_offset = ntv.offset / 1e9; - else - clock_offset = ntv.offset / 1e6; - clock_frequency = ntv.freq / 65536e6 - drift_comp; - flladj = plladj = 0; - - /* - * If the kernel PPS is lit, monitor its performance. - */ - if (ntv.status & STA_PPSTIME) { - pps_control = current_time; - if (pll_nano) - sys_jitter = ntv.jitter / 1e9; - else - sys_jitter = ntv.jitter / 1e6; - } - } -#endif /* KERNEL_PLL */ - - /* - * Adjust the clock frequency and calculate the stability. If - * kernel support is available, we use the results of the kernel - * discipline instead of the PLL/FLL discipline. In this case, - * drift_comp is a sham and used only for updating the drift - * file and for billboard eye candy. - */ - dtemp = clock_frequency + flladj + plladj; - etemp = drift_comp + dtemp; - if (etemp > NTP_MAXFREQ) - drift_comp = NTP_MAXFREQ; - else if (etemp <= -NTP_MAXFREQ) - drift_comp = -NTP_MAXFREQ; - else - drift_comp = etemp; - if (fabs(etemp) > NTP_MAXFREQ) - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "frequency error %.0f PPM exceeds tolerance %.0f PPM", - etemp * 1e6, NTP_MAXFREQ * 1e6); - - etemp = SQUARE(clock_stability); - dtemp = SQUARE(dtemp); - clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG); - - /* - * In SYNC state, adjust the poll interval. The trick here is to - * 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 (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; - if (sys_poll < peer->maxpoll) { - tc_counter = 0; - sys_poll++; - } - } - } else { - tc_counter -= sys_poll << 1; - if (tc_counter < -CLOCK_LIMIT) { - tc_counter = -CLOCK_LIMIT; - if (sys_poll > peer->minpoll) { - tc_counter = 0; - sys_poll--; - } - } - } - } - - /* - * Update the system time variables. - */ - dtemp = peer->disp + (current_time - peer->epoch) * clock_phi + - sys_jitter + fabs(last_offset); - if (!(peer->flags & FLAG_REFCLOCK) && dtemp < MINDISPERSE) - dtemp = MINDISPERSE; - sys_rootdispersion = peer->rootdispersion + dtemp; - record_loop_stats(last_offset, drift_comp, sys_jitter, - clock_stability, sys_poll); - -#ifdef DEBUG - if (debug) - printf( - "local_clock: mu %lu rootjit %.6f stab %.3f poll %d count %d\n", - mu, dtemp, clock_stability * 1e6, sys_poll, - tc_counter); -#endif /* DEBUG */ - return (retval); -#endif /* LOCKCLOCK */ -} - - -/* - * adj_host_clock - Called once every second to update the local clock. - * - * LOCKCLOCK: The only thing this routine does is increment the - * sys_rootdispersion variable. - */ -void -adj_host_clock( - void - ) -{ - double adjustment; - - /* - * Update the dispersion since the last update. In contrast to - * NTPv3, NTPv4 does not declare unsynchronized after one day, - * since the dispersion check serves this function. Also, - * since the poll interval can exceed one day, the old test - * would be counterproductive. Note we do this even with - * external clocks, since the clock driver will recompute the - * maximum error and the local clock driver will pick it up and - * pass to the common refclock routines. Very elegant. - */ - sys_rootdispersion += clock_phi; - -#ifndef LOCKCLOCK - /* - * Declare PPS kernel unsync if the pps signal has not been - * heard for a few minutes. - */ - if (pps_control && current_time - pps_control > PPS_MAXAGE) { - if (pps_control) - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, "pps sync disabled"); - pps_control = 0; - } - - /* - * If NTP is disabled or ntpdate mode enabled or the kernel - * discipline enabled, we have no business going further. - */ - if (!ntp_enable || mode_ntpdate || (pll_control && kern_enable)) - return; - - /* - * Intricate wrinkle for legacy only. If the local clock driver - * is in use and selected for synchronization, somebody else may - * tinker the adjtime() syscall. If this is the case, the driver - * is marked prefer and we have to avoid calling adjtime(), - * since that may truncate the other guy's requests. - */ - if (sys_peer != 0) { - if (sys_peer->refclktype == REFCLK_LOCALCLOCK && - sys_peer->flags & FLAG_PREFER) - return; - } - - /* - * Implement the phase and frequency adjustments. Note the - * black art formerly practiced here has been whitewashed. - */ - adjustment = clock_offset / (CLOCK_PLL * ULOGTOD(sys_poll)); - clock_offset -= adjustment; - adj_systime(adjustment + drift_comp); -#endif /* LOCKCLOCK */ -} - - -/* - * Clock state machine. Enter new state and set state variables. - */ -static void -rstclock( - int trans, /* new state */ - u_long epoch, /* last time */ - double offset /* last offset */ - ) -{ - tc_counter = 0; - sys_poll = NTP_MINPOLL; - state = trans; - last_time = epoch; - last_offset = clock_offset = offset; -#ifdef DEBUG - if (debug) - printf("local_clock: at %lu state %d\n", last_time, - trans); -#endif -} - - -/* - * huff-n'-puff filter - */ -void -huffpuff() -{ - int i; - - 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]; - } -} - - -/* - * loop_config - configure the loop filter - * - * LOCKCLOCK: The LOOP_DRIFTINIT and LOOP_DRIFTCOMP cases are no-ops. - */ -void -loop_config( - int item, - double freq - ) -{ - int i; - - switch (item) { - - case LOOP_DRIFTINIT: - -#ifndef LOCKCLOCK -#ifdef KERNEL_PLL - /* - * 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. - * - * Call out the safety patrol. If ntpdate mode or if the - * step threshold has been changed by the -x option or - * tinker command, kernel discipline is unsafe, so don't - * do any of this stuff. - */ - if (mode_ntpdate || clock_max != CLOCK_MAX) - break; - - pll_control = 1; - memset(&ntv, 0, sizeof(ntv)); -#ifdef STA_NANO - 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; - } - if (sigsetjmp(env, 1) == 0) - ntp_adjtime(&ntv); - if ((sigaction(SIGSYS, &sigsys, - (struct sigaction *)NULL))) { - msyslog(LOG_ERR, - "sigaction() fails to restore SIGSYS trap: %m"); - pll_control = 0; - } -#else /* SIGSYS */ - ntp_adjtime(&ntv); -#endif /* SIGSYS */ - pll_status = ntv.status; - if (pll_control) { -#ifdef STA_NANO - if (pll_status & STA_NANO) - pll_nano = 1; - if (pll_status & STA_CLK) - ext_enable = 1; -#endif /* STA_NANO */ - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_INFO, - "kernel time sync status %04x", - pll_status); - } -#endif /* KERNEL_PLL */ -#endif /* LOCKCLOCK */ - break; - - case LOOP_DRIFTCOMP: - -#ifndef LOCKCLOCK - /* - * If the frequency value is reasonable, set the initial - * frequency to the given value and the state to S_FSET. - * Otherwise, the drift file may be missing or broken, - * so set the frequency to zero. This erases past - * history should somebody break something. - */ - if (freq <= NTP_MAXFREQ && freq >= -NTP_MAXFREQ) { - drift_comp = freq; - rstclock(S_FSET, current_time, 0); - } else { - drift_comp = 0; - } - -#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); - } - (void)ntp_adjtime(&ntv); - } -#endif /* KERNEL_PLL */ -#endif /* LOCKCLOCK */ - break; - - /* - * Special tinker variables for Ulrich Windl. Very dangerous. - */ - case LOOP_MAX: /* step threshold */ - clock_max = freq; - break; - - case LOOP_PANIC: /* panic 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_ALLAN: /* Allan intercept */ - 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; - - case LOOP_FREQ: /* initial frequency */ - drift_comp = freq / 1e6; - rstclock(S_FSET, current_time, 0); - break; - } -} - - -#if defined(KERNEL_PLL) && defined(SIGSYS) -/* - * _trap - trap processor for undefined syscalls - * - * This nugget is called by the kernel when the SYS_ntp_adjtime() - * syscall bombs because the silly thing has not been implemented in - * the kernel. In this case the phase-lock loop is emulated by - * the stock adjtime() syscall and a lot of indelicate abuse. - */ -static RETSIGTYPE -pll_trap( - int arg - ) -{ - pll_control = 0; - siglongjmp(env, 1); -} -#endif /* KERNEL_PLL && SIGSYS */ diff --git a/contrib/ntp/ntpd/ntp_monitor.c b/contrib/ntp/ntpd/ntp_monitor.c deleted file mode 100644 index 6b288fc..0000000 --- a/contrib/ntp/ntpd/ntp_monitor.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * ntp_monitor - monitor ntpd statistics - */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#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 - * overhead as I'd imagined. - * - * Anyway, we record statistics based on source address, mode and - * version (for now, anyway. Check the code). The receive procedure - * calls us with the incoming rbufp before it does anything else. - * - * Each entry is doubly linked into two lists, a hash table and a - * most-recently-used list. When a packet arrives it is looked up in - * the hash table. If found, the statistics are updated and the entry - * relinked at the head of the MRU list. If not found, a new entry is - * allocated, initialized and linked into both the hash table and at the - * head of the MRU list. - * - * Memory is usually allocated by grabbing a big chunk of new memory and - * cutting it up into littler pieces. The exception to this when we hit - * the memory limit. Then we free memory by grabbing entries off the - * tail for the MRU list, unlinking from the hash table, and - * reinitializing. - * - * trimmed back memory consumption ... jdg 8/94 - */ -/* - * Limits on the number of structures allocated. This limit is picked - * with the illicit knowlege that we can only return somewhat less - * than 8K bytes in a mode 7 response packet, and that each structure - * will require about 20 bytes of space in the response. - * - * ... I don't believe the above is true anymore ... jdg - */ -#ifndef MAXMONMEM -#define MAXMONMEM 600 /* we allocate up to 600 structures */ -#endif -#ifndef MONMEMINC -#define MONMEMINC 40 /* allocate them 40 at a time */ -#endif - -/* - * Hashing stuff - */ -#define MON_HASH_SIZE 128 -#define MON_HASH_MASK (MON_HASH_SIZE-1) -#define MON_HASH(addr) sock_hash(addr) - -/* - * Pointers to the hash table, the MRU list and the count table. Memory - * for the hash and count tables is only allocated if monitoring is - * turned on. - */ -static struct mon_data *mon_hash[MON_HASH_SIZE]; /* list ptrs */ -struct mon_data mon_mru_list; - -/* - * List of free structures structures, and counters of free and total - * structures. The free structures are linked with the hash_next field. - */ -static struct mon_data *mon_free; /* free list or null if none */ -static int mon_total_mem; /* total structures allocated */ -static int mon_mem_increments; /* times called malloc() */ - -/* - * Initialization state. We may be monitoring, we may not. If - * we aren't, we may not even have allocated any memory yet. - */ -int mon_enabled; /* enable switch */ -u_long mon_age = 3000; /* preemption limit */ -static int mon_have_memory; -static void mon_getmoremem P((void)); -static void remove_from_hash P((struct mon_data *)); - -/* - * init_mon - initialize monitoring global data - */ -void -init_mon(void) -{ - /* - * Don't do much of anything here. We don't allocate memory - * until someone explicitly starts us. - */ - mon_enabled = MON_OFF; - mon_have_memory = 0; - - mon_total_mem = 0; - mon_mem_increments = 0; - mon_free = NULL; - memset(&mon_hash[0], 0, sizeof mon_hash); - memset(&mon_mru_list, 0, sizeof mon_mru_list); -} - - -/* - * mon_start - start up the monitoring software - */ -void -mon_start( - int mode - ) -{ - - if (mon_enabled != MON_OFF) { - mon_enabled |= mode; - return; - } - if (mode == MON_OFF) - return; - - if (!mon_have_memory) { - mon_total_mem = 0; - mon_mem_increments = 0; - mon_free = NULL; - mon_getmoremem(); - mon_have_memory = 1; - } - - mon_mru_list.mru_next = &mon_mru_list; - mon_mru_list.mru_prev = &mon_mru_list; - mon_enabled = mode; -} - - -/* - * mon_stop - stop the monitoring software - */ -void -mon_stop( - int mode - ) -{ - register struct mon_data *md, *md_next; - register int i; - - if (mon_enabled == MON_OFF) - return; - if ((mon_enabled & mode) == 0 || mode == MON_OFF) - return; - - mon_enabled &= ~mode; - if (mon_enabled != MON_OFF) - return; - - /* - * Put everything back on the free list - */ - for (i = 0; i < MON_HASH_SIZE; i++) { - md = mon_hash[i]; /* get next list */ - mon_hash[i] = NULL; /* zero the list head */ - while (md != NULL) { - md_next = md->hash_next; - md->hash_next = mon_free; - mon_free = md; - md = md_next; - } - } - - mon_mru_list.mru_next = &mon_mru_list; - mon_mru_list.mru_prev = &mon_mru_list; -} - - -/* - * ntp_monitor - record stats about this packet - */ -void -ntp_monitor( - struct recvbuf *rbufp - ) -{ - register struct pkt *pkt; - register struct mon_data *md; - struct sockaddr_storage addr; - register int hash; - register int mode; - - if (mon_enabled == MON_OFF) - return; - - pkt = &rbufp->recv_pkt; - memset(&addr, 0, sizeof(addr)); - memcpy(&addr, &(rbufp->recv_srcadr), sizeof(addr)); - hash = MON_HASH(&addr); - mode = PKT_MODE(pkt->li_vn_mode); - md = mon_hash[hash]; - while (md != NULL) { - - /* - * Match address only to conserve MRU size. - */ - if (SOCKCMP(&md->rmtadr, &addr)) { - md->drop_count = current_time - md->lasttime; - md->lasttime = current_time; - md->count++; - md->rmtport = NSRCPORT(&rbufp->recv_srcadr); - md->mode = (u_char) mode; - md->version = PKT_VERSION(pkt->li_vn_mode); - - /* - * Shuffle to the head of the MRU list. - */ - md->mru_next->mru_prev = md->mru_prev; - md->mru_prev->mru_next = md->mru_next; - md->mru_next = mon_mru_list.mru_next; - md->mru_prev = &mon_mru_list; - mon_mru_list.mru_next->mru_prev = md; - mon_mru_list.mru_next = md; - return; - } - md = md->hash_next; - } - - /* - * If we got here, this is the first we've heard of this - * guy. Get him some memory, either from the free list - * or from the tail of the MRU list. - */ - if (mon_free == NULL && mon_total_mem >= MAXMONMEM) { - - /* - * Preempt from the MRU list if old enough. - */ - md = mon_mru_list.mru_prev; - if (((u_long)RANDOM & 0xffffffff) / FRAC > - (double)(current_time - md->lasttime) / mon_age) - return; - - md->mru_prev->mru_next = &mon_mru_list; - mon_mru_list.mru_prev = md->mru_prev; - remove_from_hash(md); - } else { - if (mon_free == NULL) - mon_getmoremem(); - md = mon_free; - mon_free = md->hash_next; - } - - /* - * Got one, initialize it - */ - md->avg_interval = 0; - md->lasttime = current_time; - md->count = 1; - md->drop_count = 0; - memset(&md->rmtadr, 0, sizeof(md->rmtadr)); - memcpy(&md->rmtadr, &addr, sizeof(addr)); - md->rmtport = NSRCPORT(&rbufp->recv_srcadr); - md->mode = (u_char) mode; - md->version = PKT_VERSION(pkt->li_vn_mode); - md->interface = rbufp->dstadr; - md->cast_flags = (u_char)(((rbufp->dstadr->flags & INT_MULTICAST) && - rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd == - md->interface->bfd ? MDF_BCAST : MDF_UCAST); - - /* - * Drop him into front of the hash table. Also put him on top of - * the MRU list. - */ - md->hash_next = mon_hash[hash]; - mon_hash[hash] = md; - md->mru_next = mon_mru_list.mru_next; - md->mru_prev = &mon_mru_list; - mon_mru_list.mru_next->mru_prev = md; - mon_mru_list.mru_next = md; -} - - -/* - * mon_getmoremem - get more memory and put it on the free list - */ -static void -mon_getmoremem(void) -{ - register struct mon_data *md; - register int i; - struct mon_data *freedata; /* 'old' free list (null) */ - - md = (struct mon_data *)emalloc(MONMEMINC * - sizeof(struct mon_data)); - freedata = mon_free; - mon_free = md; - for (i = 0; i < (MONMEMINC-1); i++) { - md->hash_next = (md + 1); - md++; - } - - /* - * md now points at the last. Link in the rest of the chain. - */ - md->hash_next = freedata; - mon_total_mem += MONMEMINC; - mon_mem_increments++; -} - -static void -remove_from_hash( - struct mon_data *md - ) -{ - register int hash; - register struct mon_data *md_prev; - - hash = MON_HASH(&md->rmtadr); - if (mon_hash[hash] == md) { - mon_hash[hash] = md->hash_next; - } else { - md_prev = mon_hash[hash]; - while (md_prev->hash_next != md) { - md_prev = md_prev->hash_next; - if (md_prev == NULL) { - /* logic error */ - return; - } - } - md_prev->hash_next = md->hash_next; - } -} diff --git a/contrib/ntp/ntpd/ntp_peer.c b/contrib/ntp/ntpd/ntp_peer.c deleted file mode 100644 index cf8a600..0000000 --- a/contrib/ntp/ntpd/ntp_peer.c +++ /dev/null @@ -1,880 +0,0 @@ -/* - * ntp_peer.c - management of data maintained for peer associations - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <sys/types.h> - -#include "ntpd.h" -#include "ntp_stdlib.h" -#ifdef OPENSSL -#include "openssl/rand.h" -#endif /* OPENSSL */ - -/* - * Table of valid association combinations - * --------------------------------------- - * - * packet->mode - * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST - * ---------- | --------------------------------------------- - * NO_PEER | e 1 e 1 1 1 - * ACTIVE | e 1 1 0 0 0 - * PASSIVE | e 1 e 0 0 0 - * CLIENT | e 0 0 0 1 1 - * SERVER | e 0 0 0 0 0 - * BCAST | e 0 0 0 0 0 - * CONTROL | e 0 0 0 0 0 - * PRIVATE | e 0 0 0 0 0 - * BCLIENT | e 0 0 0 e 1 - * - * 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] = { -/* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */ - -/*NONE*/{ AM_ERR, AM_NEWPASS, AM_ERR, AM_FXMIT, AM_MANYCAST, AM_NEWBCL}, - -/*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, - -/*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, - -/*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_POSSBCL}, - -/*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, - -/*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, - -/*CNTL*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, - -/*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}, -}; - -#define MATCH_ASSOC(x,y) AM[(x)][(y)] - -/* - * These routines manage the allocation of memory to peer structures - * and the maintenance of the peer hash table. The two main entry - * points are findpeer(), which looks for matching peer sturctures in - * the peer list, newpeer(), which allocates a new peer structure and - * adds it to the list, and unpeer(), which demobilizes the association - * and deallocates the structure. - */ -/* - * Peer hash tables - */ -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 */ - -/* - * Association ID. We initialize this value randomly, then assign a new - * value every time the peer structure is incremented. - */ -static associd_t current_association_ID; /* association ID */ - -/* - * Memory allocation watermarks. - */ -#define INIT_PEER_ALLOC 15 /* initialize for 15 peers */ -#define INC_PEER_ALLOC 5 /* when run out, add 5 more */ - -/* - * Miscellaneous statistic counters which may be queried. - */ -u_long peer_timereset; /* time stat counters zeroed */ -u_long findpeer_calls; /* calls to findpeer */ -u_long assocpeer_calls; /* calls to findpeerbyassoc */ -u_long peer_allocations; /* allocations from free list */ -u_long peer_demobilizations; /* structs freed to free list */ -int total_peer_structs; /* peer structs */ -int peer_associations; /* active associations */ -static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */ - -static void getmorepeermem P((void)); - -/* - * 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. - */ -void -init_peer(void) -{ - register int i; - - /* - * Clear hash table and counters. - */ - for (i = 0; i < HASH_SIZE; i++) { - peer_hash[i] = 0; - peer_hash_count[i] = 0; - assoc_hash[i] = 0; - assoc_hash_count[i] = 0; - } - - /* - * Clear stat counters - */ - findpeer_calls = peer_allocations = 0; - assocpeer_calls = peer_demobilizations = 0; - - /* - * Initialize peer memory. - */ - peer_free = 0; - for (i = 0; i < INIT_PEER_ALLOC; i++) { - init_peer_alloc[i].next = peer_free; - peer_free = &init_peer_alloc[i]; - } - total_peer_structs = INIT_PEER_ALLOC; - peer_free_count = INIT_PEER_ALLOC; - - /* - * Initialize our first association ID - */ - current_association_ID = (associd_t)ranp2(16); - if (current_association_ID == 0) - current_association_ID = 1; -} - - -/* - * getmorepeermem - add more peer structures to the free list - */ -static void -getmorepeermem(void) -{ - register int i; - register struct peer *peer; - - peer = (struct peer *)emalloc(INC_PEER_ALLOC * - sizeof(struct peer)); - for (i = 0; i < INC_PEER_ALLOC; i++) { - peer->next = peer_free; - peer_free = peer; - peer++; - } - - total_peer_structs += INC_PEER_ALLOC; - peer_free_count += INC_PEER_ALLOC; -} - - -/* - * findexistingpeer - return a pointer to a peer in the hash table - */ -struct peer * -findexistingpeer( - struct sockaddr_storage *addr, - struct peer *start_peer, - int mode - ) -{ - register struct peer *peer; - - /* - * start_peer is included so we can locate instances of the - * same peer through different interfaces in the hash table. - */ - if (start_peer == 0) - peer = peer_hash[HASH_ADDR(addr)]; - else - peer = start_peer->next; - - while (peer != 0) { - if (SOCKCMP(addr, &peer->srcadr) - && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) { - if (mode == -1) - return (peer); - else if (peer->hmode == mode) - break; - } - peer = peer->next; - } - return (peer); -} - - -/* - * findpeer - find and return a peer in the hash table. - */ -struct peer * -findpeer( - struct sockaddr_storage *srcadr, - struct interface *dstadr, - int fd, - int pkt_mode, - int *action - ) -{ - register struct peer *peer; - int hash; - - findpeer_calls++; - hash = HASH_ADDR(srcadr); - for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) { - if (SOCKCMP(srcadr, &peer->srcadr) - && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) { - - /* - * if the association matching rules determine - * that this is not a valid combination, then - * look for the next valid peer association. - */ - *action = MATCH_ASSOC(peer->hmode, pkt_mode); - - /* - * Sigh! Check if BCLIENT peer in client - * server mode, else return error. - */ - if ((*action == AM_POSSBCL) && !(peer->flags & - FLAG_MCAST)) - *action = AM_ERR; - - /* - * if an error was returned, exit back right - * here. - */ - if (*action == AM_ERR) - return ((struct peer *)0); - - /* - * if a match is found, we stop our search. - */ - if (*action != AM_NOMATCH) - break; - } - } - - /* - * If no matching association is found - */ - if (peer == 0) { - *action = MATCH_ASSOC(NO_PEER, pkt_mode); - return ((struct peer *)0); - } - peer->dstadr = dstadr; - return (peer); -} - -/* - * findpeerbyassocid - find and return a peer using his association ID - */ -struct peer * -findpeerbyassoc( - u_int assoc - ) -{ - register struct peer *peer; - int hash; - - assocpeer_calls++; - - hash = assoc & HASH_MASK; - for (peer = assoc_hash[hash]; peer != 0; peer = - peer->ass_next) { - if (assoc == peer->associd) - return (peer); - } - return (NULL); -} - - -/* - * clear_all - flush all time values for all associations - */ -void -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; - if (peer->flags & FLAG_CONFIG) { - if (!(peer->cast_flags & (MDF_ACAST | - MDF_MCAST | MDF_BCAST))) - peer_clear(peer, "STEP"); - } else { - unpeer(peer); - } - } - } -#ifdef DEBUG - if (debug) - printf("clear_all: at %lu\n", current_time); -#endif -} - - -/* - * unpeer - remove peer structure from hash table and free structure - */ -void -unpeer( - struct peer *peer_to_remove - ) -{ - int hash; -#ifdef OPENSSL - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ - - if (peer_to_remove->flags & FLAG_SKEY) { - sprintf(statstr, "unpeer %d flash %x reach %03o flags %04x", - peer_to_remove->associd, peer_to_remove->flash, - peer_to_remove->reach, peer_to_remove->flags); - record_crypto_stats(&peer_to_remove->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("peer: %s\n", statstr); -#endif - } -#endif /* OPENSSL */ -#ifdef DEBUG - if (debug) - printf("demobilize %u %d\n", peer_to_remove->associd, - peer_associations); -#endif - peer_clear(peer_to_remove, "NULL"); - hash = HASH_ADDR(&peer_to_remove->srcadr); - peer_hash_count[hash]--; - peer_demobilizations++; -#ifdef REFCLOCK - /* - * If this peer is actually a clock, shut it down first - */ - if (peer_to_remove->flags & FLAG_REFCLOCK) - refclock_unpeer(peer_to_remove); -#endif - peer_to_remove->action = 0; /* disable timeout actions */ - if (peer_hash[hash] == peer_to_remove) - peer_hash[hash] = peer_to_remove->next; - else { - register struct peer *peer; - - peer = peer_hash[hash]; - while (peer != 0 && peer->next != peer_to_remove) - peer = peer->next; - - if (peer == 0) { - peer_hash_count[hash]++; - msyslog(LOG_ERR, "peer struct for %s not in table!", - stoa(&peer->srcadr)); - } else { - peer->next = peer_to_remove->next; - } - } - - /* - * Remove him from the association hash as well. - */ - hash = peer_to_remove->associd & HASH_MASK; - assoc_hash_count[hash]--; - if (assoc_hash[hash] == peer_to_remove) - assoc_hash[hash] = peer_to_remove->ass_next; - else { - register struct peer *peer; - - peer = assoc_hash[hash]; - while (peer != 0 && peer->ass_next != peer_to_remove) - peer = peer->ass_next; - - if (peer == 0) { - assoc_hash_count[hash]++; - msyslog(LOG_ERR, - "peer struct for %s not in association table!", - stoa(&peer->srcadr)); - } else { - peer->ass_next = peer_to_remove->ass_next; - } - } - peer_to_remove->next = peer_free; - peer_free = peer_to_remove; - peer_free_count++; - peer_associations--; -} - - -/* - * peer_config - configure a new association - */ -struct peer * -peer_config( - struct sockaddr_storage *srcadr, - struct interface *dstadr, - int hmode, - int version, - int minpoll, - int maxpoll, - u_int flags, - int ttl, - keyid_t key, - u_char *keystr - ) -{ - register struct peer *peer; - u_char cast_flags; - - /* - * First search from the beginning for an association with given - * remote address and mode. If an interface is given, search - * from there to find the association which matches that - * destination. - */ - peer = findexistingpeer(srcadr, (struct peer *)0, hmode); - if (dstadr != 0) { - while (peer != 0) { - if (peer->dstadr == dstadr) - break; - peer = findexistingpeer(srcadr, peer, hmode); - } - } - - /* - * We do a dirty little jig to figure the cast flags. This is - * probably not the best place to do this, at least until the - * configure code is rebuilt. Note only one flag can be set. - */ - switch (hmode) { - - case MODE_BROADCAST: - if(srcadr->ss_family == AF_INET) { - if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr))) - cast_flags = MDF_MCAST; - else - cast_flags = MDF_BCAST; - break; - } - else { - if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr)) - cast_flags = MDF_MCAST; - else - cast_flags = MDF_BCAST; - break; - } - - case MODE_CLIENT: - if(srcadr->ss_family == AF_INET) { - if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr))) - cast_flags = MDF_ACAST; - else - cast_flags = MDF_UCAST; - break; - } - else { - if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr)) - cast_flags = MDF_ACAST; - else - cast_flags = MDF_UCAST; - break; - } - - default: - cast_flags = MDF_UCAST; - } - - /* - * If the peer is already configured, some dope has a duplicate - * configureation entry or another dope is wiggling from afar. - */ - if (peer != 0) { - peer->hmode = (u_char)hmode; - peer->version = (u_char) version; - peer->minpoll = (u_char) minpoll; - peer->maxpoll = (u_char) maxpoll; - peer->flags = flags | FLAG_CONFIG | - (peer->flags & FLAG_REFCLOCK); - peer->cast_flags = cast_flags; - peer->ttl = (u_char) ttl; - peer->keyid = key; - peer->precision = sys_precision; - peer_clear(peer, "RMOT"); - return (peer); - } - - /* - * Here no match has been found, so presumably this is a new - * persistent association. Mobilize the thing and initialize its - * variables. If emulating ntpdate, force iburst. - */ - if (mode_ntpdate) - flags |= FLAG_IBURST; - peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, - flags | FLAG_CONFIG, cast_flags, ttl, key); - return (peer); -} - - -/* - * newpeer - initialize a new peer association - */ -struct peer * -newpeer( - struct sockaddr_storage *srcadr, - struct interface *dstadr, - int hmode, - int version, - int minpoll, - int maxpoll, - u_int flags, - u_char cast_flags, - int ttl, - keyid_t key - ) -{ - register struct peer *peer; - register int i; -#ifdef OPENSSL - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ -#endif /* OPENSSL */ - - /* - * 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(); - peer = peer_free; - peer_free = peer->next; - peer_free_count--; - peer_associations++; - memset((char *)peer, 0, sizeof(struct peer)); - - /* - * Assign an association ID and increment the system variable. - */ - peer->associd = current_association_ID; - if (++current_association_ID == 0) - ++current_association_ID; - - /* - * Initialize the peer structure and dance the interface jig. - * Reference clocks step the loopback waltz, the others - * squaredance around the interface list looking for a buddy. If - * the dance peters out, there is always the wildcard interface. - * This might happen in some systems and would preclude proper - * operation with public key cryptography. - */ - if (ISREFCLOCKADR(srcadr)) - peer->dstadr = loopback_interface; - else if (cast_flags & (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) { - peer->dstadr = findbcastinter(srcadr); - /* - * If it was a multicast packet, findbcastinter() may not - * find it, so try a little harder. - */ - if (peer->dstadr == ANY_INTERFACE_CHOOSE(srcadr)) - peer->dstadr = findinterface(srcadr); - } else if (dstadr != NULL && dstadr != ANY_INTERFACE_CHOOSE(srcadr)) - peer->dstadr = dstadr; - else - peer->dstadr = findinterface(srcadr); - peer->srcadr = *srcadr; - peer->hmode = (u_char)hmode; - peer->version = (u_char)version; - peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll); - peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll); - peer->flags = flags; - if (key != 0) - peer->flags |= FLAG_AUTHENABLE; - if (key > NTP_MAXKEY) - peer->flags |= FLAG_SKEY; - peer->cast_flags = cast_flags; - peer->ttl = (u_char)ttl; - peer->keyid = key; - peer->precision = sys_precision; - if (cast_flags & MDF_ACAST) - peer_clear(peer, "ACST"); - else if (cast_flags & MDF_MCAST) - peer_clear(peer, "MCST"); - else if (cast_flags & MDF_BCAST) - peer_clear(peer, "BCST"); - else - peer_clear(peer, "INIT"); - if (mode_ntpdate) - peer_ntpdate++; - - /* - * Note time on statistics timers. - */ - peer->timereset = current_time; - peer->timereachable = current_time; - peer->timereceived = current_time; -#ifdef REFCLOCK - if (ISREFCLOCKADR(&peer->srcadr)) { - /* - * We let the reference clock support do clock - * dependent initialization. This includes setting - * the peer timer, since the clock may have requirements - * for this. - */ - if (!refclock_newpeer(peer)) { - /* - * Dump it, something screwed up - */ - peer->next = peer_free; - peer_free = peer; - peer_free_count++; - return (NULL); - } - } -#endif - - /* - * 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 OPENSSL - if (peer->flags & FLAG_SKEY) { - sprintf(statstr, "newpeer %d", peer->associd); - record_crypto_stats(&peer->srcadr, statstr); -#ifdef DEBUG - if (debug) - printf("peer: %s\n", statstr); -#endif - } -#endif /* OPENSSL */ -#ifdef DEBUG - if (debug) - printf( - "newpeer: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x\n", - peer->dstadr == NULL ? "null" : stoa(&peer->dstadr->sin), - stoa(&peer->srcadr), - peer->hmode, peer->version, peer->minpoll, - peer->maxpoll, peer->flags, peer->cast_flags, - peer->ttl, peer->keyid); -#endif - return (peer); -} - - -/* - * peer_unconfig - remove the configuration bit from a peer - */ -int -peer_unconfig( - struct sockaddr_storage *srcadr, - struct interface *dstadr, - int mode - ) -{ - register struct peer *peer; - int num_found; - - num_found = 0; - peer = findexistingpeer(srcadr, (struct peer *)0, mode); - while (peer != 0) { - if (peer->flags & FLAG_CONFIG - && (dstadr == 0 || peer->dstadr == dstadr)) { - num_found++; - - /* - * Tricky stuff here. If the peer is polling us - * in active mode, turn off the configuration - * bit and make the mode passive. This allows us - * to avoid dumping a lot of history for peers - * we might choose to keep track of in passive - * mode. The protocol will eventually terminate - * undesirables on its own. - */ - if (peer->hmode == MODE_ACTIVE - && peer->pmode == MODE_ACTIVE) { - peer->hmode = MODE_PASSIVE; - peer->flags &= ~FLAG_CONFIG; - } else { - unpeer(peer); - peer = 0; - } - } - peer = findexistingpeer(srcadr, peer, mode); - } - return (num_found); -} - -/* - * peer_clr_stats - clear peer module stat counters - */ -void -peer_clr_stats(void) -{ - findpeer_calls = 0; - assocpeer_calls = 0; - peer_allocations = 0; - peer_demobilizations = 0; - peer_timereset = current_time; -} - -/* - * peer_reset - reset stat counters in a peer structure - */ -void -peer_reset( - struct peer *peer - ) -{ - if (peer == 0) - return; - peer->sent = 0; - peer->received = 0; - peer->processed = 0; - peer->badauth = 0; - peer->bogusorg = 0; - peer->oldpkt = 0; - peer->seldisptoolarge = 0; - peer->selbroken = 0; - peer->rank = 0; - peer->timereset = current_time; -} - - -/* - * peer_all_reset - reset all peer stat counters - */ -void -peer_all_reset(void) -{ - struct peer *peer; - int hash; - - for (hash = 0; hash < HASH_SIZE; hash++) - for (peer = peer_hash[hash]; peer != 0; peer = peer->next) - peer_reset(peer); -} - - -#ifdef OPENSSL -/* - * expire_all - flush all crypto data and update timestamps. - */ -void -expire_all(void) -{ - struct peer *peer, *next_peer; - int n; - - /* - * This routine is called about once per day from the timer - * routine and when the client is first synchronized. Search the - * peer list for all associations and flush only the key list - * and cookie. If a manycast client association, flush - * everything. Then, recompute and sign the agreement public - * value, if present. - */ - if (!crypto_flags) - return; - for (n = 0; n < HASH_SIZE; n++) { - for (peer = peer_hash[n]; peer != 0; peer = next_peer) { - next_peer = peer->next; - if (!(peer->flags & FLAG_SKEY)) { - continue; - } else if (peer->cast_flags & MDF_ACAST) { - peer_clear(peer, "ACST"); - } else if (peer->hmode == MODE_ACTIVE || - peer->hmode == MODE_PASSIVE) { - key_expire(peer); - peer->crypto &= ~(CRYPTO_FLAG_AUTO | - CRYPTO_FLAG_AGREE); - } - - } - } - RAND_bytes((u_char *)&sys_private, 4); - crypto_update(); - resetmanycast(); -} -#endif /* OPENSSL */ - - -/* - * 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, 0); - } - } - } -} diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c deleted file mode 100644 index 451bc9a..0000000 --- a/contrib/ntp/ntpd/ntp_proto.c +++ /dev/null @@ -1,3208 +0,0 @@ -/* - * ntp_proto.c - NTP version 4 protocol machinery - * - * ATTENTION: Get approval from Dave Mills on all changes to this file! - * - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "ntpd.h" -#include "ntp_stdlib.h" -#include "ntp_unixtime.h" -#include "ntp_control.h" -#include "ntp_string.h" - -#include <stdio.h> - -#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ -#include "ntp_refclock.h" -#endif - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include <sys/sysctl.h> -#endif - -/* - * 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; /* roundtrip delay to primary source */ -double sys_rootdispersion; /* dispersion to primary source */ -u_int32 sys_refid; /* reference source for local clock */ -u_int32 sys_peer_refid; /* hashed refid of our current peer */ -static double sys_offset; /* current local clock offset */ -l_fp sys_reftime; /* time we were last updated */ -struct peer *sys_peer; /* our current peer */ -struct peer *sys_prefer; /* our cherished peer */ -int sys_kod; /* kod credit */ -int sys_kod_rate = 2; /* max kod packets per second */ -#ifdef OPENSSL -u_long sys_automax; /* maximum session key lifetime */ -#endif /* OPENSSL */ - -/* - * Nonspecified system state variables. - */ -int sys_bclient; /* broadcast client enable */ -double sys_bdelay; /* broadcast client default delay */ -int sys_calldelay; /* modem callup delay (s) */ -int sys_authenticate; /* requre authentication for config */ -l_fp sys_authdelay; /* authentication delay */ -static u_long sys_authdly[2]; /* authentication delay shift reg */ -static u_char leap_consensus; /* consensus of survivor leap bits */ -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 */ -int peer_ntpdate; /* active peers in ntpdate mode */ -int sys_survivors; /* truest of the truechimers */ -#ifdef OPENSSL -char *sys_hostname; /* gethostname() name */ -#endif /* OPENSSL */ - -/* - * TOS and multicast mapping stuff - */ -int sys_floor = 1; /* cluster stratum floor */ -int sys_ceiling = STRATUM_UNSPEC; /* cluster stratum ceiling*/ -int sys_minsane = 1; /* minimum candidates */ -int sys_minclock = NTP_MINCLOCK; /* minimum survivors */ -int sys_cohort = 0; /* cohort switch */ -int sys_ttlmax; /* max ttl mapping vector index */ -u_char sys_ttl[MAX_TTL]; /* ttl mapping vector */ - -/* - * Statistics counters - */ -u_long sys_stattime; /* time since reset */ -u_long sys_received; /* packets received */ -u_long sys_processed; /* packets processed */ -u_long sys_newversionpkt; /* current version */ -u_long sys_oldversionpkt; /* recent version */ -u_long sys_unknownversion; /* invalid version */ -u_long sys_restricted; /* access denied */ -u_long sys_badlength; /* bad length or format */ -u_long sys_badauth; /* bad authentication */ -u_long sys_limitrejected; /* rate exceeded */ - -static double root_distance P((struct peer *)); -static double clock_combine P((struct peer **, int)); -static void peer_xmit P((struct peer *)); -static void fast_xmit P((struct recvbuf *, int, keyid_t, int)); -static void clock_update P((void)); -int default_get_precision P((void)); -static int peer_unfit P((struct peer *)); - -/* - * transmit - Transmit Procedure. See Section 3.4.2 of the - * specification. - */ -void -transmit( - struct peer *peer /* peer structure pointer */ - ) -{ - int hpoll; - - - /* - * The polling state machine. There are two kinds of machines, - * those that never expect a reply (broadcast and manycast - * server modes) and those that do (all other modes). The dance - * is intricate... - */ - hpoll = peer->hpoll; - if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) { - - /* - * In broadcast mode the poll interval is fixed - * at minpoll. - */ - hpoll = peer->minpoll; - } else if (peer->cast_flags & MDF_ACAST) { - - /* - * In manycast mode we start with the minpoll interval - * and ttl. However, the actual poll interval is eight - * times the nominal poll interval shown here. If fewer - * than sys_minclock servers are found, the ttl is - * increased by one and we try again. If this continues - * to the max ttl, the poll interval is bumped by one - * and we try again. If at least sys_minclock servers - * are found, the poll interval increases with the - * system poll interval to the max and we continue - * indefinately. However, about once per day when the - * agreement parameters are refreshed, the manycast - * clients are reset and we start from the beginning. - * This is to catch and clamp the ttl to the lowest - * practical value and avoid knocking on spurious doors. - */ - if (sys_survivors < sys_minclock && peer->ttl < - sys_ttlmax) - peer->ttl++; - hpoll = sys_poll; - } else { - - /* - * For associations expecting a reply, the watchdog - * counter is bumped by one if the peer has not been - * heard since the previous poll. If the counter reaches - * the max, the poll interval is doubled and the peer is - * demobilized if not configured. - */ - peer->unreach++; - if (peer->unreach >= NTP_UNREACH) { - hpoll++; - if (peer->flags & FLAG_CONFIG) { - - /* - * If nothing is likely to change in - * future, flash the access denied bit - * so we won't bother the dude again. - */ - if (memcmp((char *)&peer->refid, - "DENY", 4) == 0 || - memcmp((char *)&peer->refid, - "CRYP", 4) == 0) - peer->flash |= TEST4; - } else { - unpeer(peer); - return; - } - } - if (peer->burst == 0) { - u_char oreach; - - oreach = peer->reach; - peer->reach <<= 1; - peer->hyst *= HYST_TC; - if (peer->reach == 0) { - - /* - * If this association has become - * unreachable, clear it and raise a - * trap. - */ - if (oreach != 0) { - report_event(EVNT_UNREACH, - peer); - peer->timereachable = - current_time; - if (peer->flags & FLAG_CONFIG) { - peer_clear(peer, - "INIT"); - } else { - unpeer(peer); - return; - } - } - if (peer->flags & FLAG_IBURST) - peer->burst = NTP_BURST; - } else { - /* - * Here the peer is reachable. If it has - * not been heard for three consecutive - * polls, stuff the clock filter. Next, - * determine the poll interval. If the - * peer is unfit for synchronization, - * increase it by one; otherwise, use - * the system poll interval. - */ - if (!(peer->reach & 0x07)) { - clock_filter(peer, 0., 0., - MAXDISPERSE); - clock_select(); - } - if (peer_unfit(peer)) - hpoll++; - else - hpoll = sys_poll; - if (peer->flags & FLAG_BURST) - peer->burst = NTP_BURST; - } - } else { - - /* - * Source rate control. If we are restrained, - * each burst consists of only one packet. - */ - if (memcmp((char *)&peer->refid, "RSTR", 4) == - 0) - peer->burst = 0; - else - peer->burst--; - if (peer->burst == 0) { - /* - * If a broadcast client at this point, - * the burst has concluded, so we switch - * to client mode and purge the keylist, - * since no further transmissions will - * be made. - */ - if (peer->cast_flags & MDF_BCLNT) { - peer->hmode = MODE_BCLIENT; -#ifdef OPENSSL - key_expire(peer); -#endif /* OPENSSL */ - } - poll_update(peer, hpoll); - clock_select(); - - /* - * If ntpdate mode and the clock has not - * been set and all peers have completed - * the burst, we declare a successful - * failure. - */ - if (mode_ntpdate) { - peer_ntpdate--; - if (peer_ntpdate > 0) { - poll_update( - peer, hpoll); - return; - } - msyslog(LOG_NOTICE, - "no reply; clock not set"); - exit (0); - } - poll_update(peer, hpoll); - return; - } - } - } - peer->outdate = current_time; - - /* - * Do not transmit if in broadcast cclient mode or access has - * been denied. - */ - if (peer->hmode == MODE_BCLIENT || peer->flash & TEST4) { - poll_update(peer, hpoll); - return; - - /* - * Do not transmit in broadcast mode unless we are synchronized. - */ - } else if (peer->hmode == MODE_BROADCAST && sys_peer == NULL) { - poll_update(peer, hpoll); - return; - } - peer_xmit(peer); - poll_update(peer, hpoll); -} - -/* - * receive - Receive Procedure. See section 3.4.3 in the specification. - */ -void -receive( - struct recvbuf *rbufp - ) -{ - register struct peer *peer; /* peer structure pointer */ - register struct pkt *pkt; /* receive packet pointer */ - int hismode; /* packet mode */ - int restrict_mask; /* restrict bits */ - int has_mac; /* length of MAC field */ - int authlen; /* offset of MAC field */ - int is_authentic; /* cryptosum ok */ - keyid_t skeyid = 0; /* key ID */ - struct sockaddr_storage *dstadr_sin; /* active runway */ - struct peer *peer2; /* aux peer structure pointer */ - l_fp p_org; /* originate timestamp */ - l_fp p_xmt; /* transmit timestamp */ -#ifdef OPENSSL - keyid_t tkeyid = 0; /* temporary key ID */ - keyid_t pkeyid = 0; /* previous key ID */ - struct autokey *ap; /* autokey structure pointer */ - int rval; /* cookie snatcher */ -#endif /* OPENSSL */ - int retcode = AM_NOMATCH; - - /* - * 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. - */ - /* - * Bogus port check is before anything, since it probably - * reveals a clogging attack. - */ - sys_received++; - if (SRCPORT(&rbufp->recv_srcadr) == 0) { - sys_badlength++; - return; /* bogus port */ - } - ntp_monitor(rbufp); - restrict_mask = restrictions(&rbufp->recv_srcadr); -#ifdef DEBUG - if (debug > 1) - printf("receive: at %ld %s<-%s restrict %03x\n", - current_time, stoa(&rbufp->dstadr->sin), - stoa(&rbufp->recv_srcadr), restrict_mask); -#endif - if (restrict_mask & RES_IGNORE) { - sys_restricted++; - return; /* no anything */ - } - pkt = &rbufp->recv_pkt; - hismode = (int)PKT_MODE(pkt->li_vn_mode); - if (hismode == MODE_PRIVATE) { - if (restrict_mask & RES_NOQUERY) { - sys_restricted++; - return; /* no query private */ - } - process_private(rbufp, ((restrict_mask & - RES_NOMODIFY) == 0)); - return; - } - if (hismode == MODE_CONTROL) { - if (restrict_mask & RES_NOQUERY) { - sys_restricted++; - return; /* no query control */ - } - process_control(rbufp, restrict_mask); - return; - } - if (restrict_mask & RES_DONTSERVE) { - sys_restricted++; - return; /* no time */ - } - if (rbufp->recv_length < LEN_PKT_NOMAC) { - sys_badlength++; - return; /* runt packet */ - } - - /* - * Version check must be after the query packets, since they - * intentionally use early version. - */ - if (PKT_VERSION(pkt->li_vn_mode) == NTP_VERSION) { - sys_newversionpkt++; /* new version */ - } else if (!(restrict_mask & RES_VERSION) && - PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) { - sys_oldversionpkt++; /* previous version */ - } else { - sys_unknownversion++; - return; /* old version */ - } - - /* - * Figure out his mode and validate the packet. This has some - * legacy raunch that probably should be removed. In very early - * NTP versions mode 0 was equivalent to what later versions - * would interpret as client mode. - */ - if (hismode == MODE_UNSPEC) { - if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION) { - hismode = MODE_CLIENT; - } else { - sys_badlength++; - return; /* invalid mode */ - } - } - - /* - * Discard broadcast if not enabled as broadcast client. If - * Autokey, the wildcard interface cannot be used, so dump - * packets gettiing off the bus at that stop as well. This means - * that some systems with broken interface code, specifically - * Linux, will not work with Autokey. - */ - if (hismode == MODE_BROADCAST) { - if (!sys_bclient || restrict_mask & RES_NOPEER) { - sys_restricted++; - return; /* no client */ - } -#ifdef OPENSSL - if (crypto_flags && rbufp->dstadr == any_interface) { - sys_restricted++; - return; /* no client */ - } -#endif /* OPENSSL */ - } - - /* - * Parse the extension field if present. We figure out whether - * 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. - */ - authlen = LEN_PKT_NOMAC; - has_mac = rbufp->recv_length - authlen; - while (has_mac > 0) { - int temp; - - if (has_mac % 4 != 0 || has_mac < 0) { - sys_badlength++; - return; /* bad MAC length */ - } - if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac == - MAX_MAC_LEN) { - skeyid = ntohl(((u_int32 *)pkt)[authlen / 4]); - break; - - } else if (has_mac > MAX_MAC_LEN) { - temp = ntohl(((u_int32 *)pkt)[authlen / 4]) & - 0xffff; - if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4 - != 0) { - sys_badlength++; - return; /* bad MAC length */ - } - authlen += temp; - has_mac -= temp; - } else { - sys_badlength++; - return; /* bad MAC length */ - } - } -#ifdef OPENSSL - pkeyid = tkeyid = 0; -#endif /* OPENSSL */ - - /* - * We have tossed out as many buggy packets as possible early in - * the game to reduce the exposure to a clogging attack. Now we - * have to burn some cycles to find the association and - * authenticate the packet if required. Note that we burn only - * MD5 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. - */ - 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 %s<-%s mode %d code %d\n", - current_time, stoa(&rbufp->dstadr->sin), - stoa(&rbufp->recv_srcadr), hismode, - retcode); -#endif - } else { -#ifdef OPENSSL - /* - * 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) { - - /* - * 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 (!SOCKNUL(&rbufp->dstadr->bcast)) - 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; - } - - /* - * 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( - &rbufp->recv_srcadr, dstadr_sin, - skeyid, pkeyid, 0); - } else { - tkeyid = session_key( - &rbufp->recv_srcadr, dstadr_sin, - skeyid, pkeyid, 2); - } - - } -#endif /* OPENSSL */ - - /* - * Compute the cryptosum. Note a clogging attack may - * succeed in bloating the key cache. If an autokey, - * purge it immediately, since we won't be needing it - * again. If the packet is authentic, it may mobilize an - * association. - */ - if (authdecrypt(skeyid, (u_int32 *)pkt, authlen, - has_mac)) { - is_authentic = 1; - restrict_mask &= ~RES_DONTTRUST; - } else { - sys_badauth++; - } -#ifdef OPENSSL - if (skeyid > NTP_MAXKEY) - authtrust(skeyid, 0); -#endif /* OPENSSL */ -#ifdef DEBUG - if (debug) - printf( - "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n", - current_time, stoa(dstadr_sin), - stoa(&rbufp->recv_srcadr), hismode, retcode, - skeyid, authlen, has_mac, - is_authentic); -#endif - } - - /* - * 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 manycast server packet mobilizes a manycast - * client association; a symmetric active packet mobilizes a - * symmetric passive association. And, the adventure - * continues... - */ - switch (retcode) { - case AM_FXMIT: - - /* - * 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_manycastserver && (rbufp->dstadr->flags & - INT_MULTICAST)) { - - /* - * There is no reason to respond to a request if - * our time is worse than the manycaster or it - * has already synchronized to us. - */ - if (sys_peer == NULL || - PKT_TO_STRATUM(pkt->stratum) < - sys_stratum || (sys_cohort && - PKT_TO_STRATUM(pkt->stratum) == - sys_stratum) || - rbufp->dstadr->addr_refid == pkt->refid) - return; /* manycast dropped */ - } - - /* - * Note that we don't require an authentication check - * here, since we can't set the system clock; but, we do - * send a crypto-NAK to tell the caller about this. - */ - if (has_mac && !is_authentic) - fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); - else - fast_xmit(rbufp, MODE_SERVER, skeyid, - restrict_mask); - return; - - case AM_MANYCAST: - - /* - * 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 and not - * restricted. If so and the manycast association is - * found, we mobilize a client association and copy - * pertinent variables from the manycast association to - * the new client association. - * - * There is an implosion hazard at the manycast client, - * since the manycast servers send the server packet - * immediately. If the guy is already here, don't fire - * up a duplicate. - */ - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - return; /* no trust */ - } - - if (sys_authenticate && !is_authentic) - return; /* bad auth */ - - if ((peer2 = findmanycastpeer(rbufp)) == NULL) - return; /* no assoc match */ - - if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_IBURST, MDF_UCAST | - MDF_ACLNT, 0, skeyid)) == NULL) - return; /* system error */ - - /* - * We don't need these, but it warms the billboards. - */ - peer->ttl = peer2->ttl; - break; - - case AM_NEWPASS: - - /* - * This is the first packet received from a symmetric - * active peer. First, make sure it is authentic and not - * restricted. If so, mobilize a passive association. - * If authentication fails send a crypto-NAK; otherwise, - * kiss the frog. - */ - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - return; /* no trust */ - } - if (sys_authenticate && !is_authentic) { - fast_xmit(rbufp, MODE_PASSIVE, 0, - restrict_mask); - return; /* bad auth */ - } - if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0, - skeyid)) == NULL) - return; /* system error */ - - break; - - case AM_NEWBCL: - - /* - * This is the first packet received from a broadcast - * server. First, make sure it is authentic and not - * restricted and that we are a broadcast client. If so, - * mobilize a broadcast client association. We don't - * kiss any frogs here. - */ - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - return; /* no trust */ - } - if (sys_authenticate && !is_authentic) - return; /* bad auth */ - - if (!sys_bclient) - return; /* not a client */ - - if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST | - FLAG_IBURST, MDF_BCLNT, 0, skeyid)) == NULL) - return; /* system error */ -#ifdef OPENSSL - /* - * Danger looms. If this is autokey, go process the - * extension fields. If something goes wrong, abandon - * ship and don't trust subsequent packets. - */ - if (crypto_flags) { - if ((rval = crypto_recv(peer, rbufp)) != - XEVNT_OK) { - struct sockaddr_storage mskadr_sin; - - unpeer(peer); - sys_restricted++; - SET_HOSTMASK(&mskadr_sin, - rbufp->recv_srcadr.ss_family); - hack_restrict(RESTRICT_FLAGS, - &rbufp->recv_srcadr, &mskadr_sin, - 0, RES_DONTTRUST | RES_TIMEOUT); -#ifdef DEBUG - if (debug) - printf( - "packet: bad exten %x\n", - rval); -#endif - } - } -#endif /* OPENSSL */ - return; - - case AM_POSSBCL: - - /* - * This is a broadcast packet received in client mode. - * It could happen if the initial client/server volley - * is not complete before the next broadcast packet is - * received. Be liberal in what we accept. - */ - case AM_PROCPKT: - - /* - * This is a symmetric mode packet received in symmetric - * mode, a server packet received in client mode or a - * broadcast packet received in broadcast client mode. - * If it is restricted, this is very strange because it - * is rude to send a packet to a restricted address. If - * anyway, flash a restrain kiss and skedaddle to - * Seattle. If not authentic, leave a light on and - * continue. - */ - peer->flash = 0; - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "RSTR"); - else - unpeer(peer); - return; /* no trust */ - } - if (has_mac && !is_authentic) - peer->flash |= TEST5; /* bad auth */ - break; - - default: - - /* - * Invalid mode combination. This happens when a passive - * mode packet arrives and matches another passive - * association or no association at all, or when a - * server mode packet arrives and matches a broadcast - * client association. This is usually the result of - * reconfiguring a client on-fly. If authenticated - * passive mode packet, send a crypto-NAK; otherwise, - * ignore it. - */ - if (has_mac && hismode == MODE_PASSIVE) - fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); -#ifdef DEBUG - if (debug) - printf("receive: bad protocol %d\n", retcode); -#endif - return; - } - - /* - * We do a little homework. Note we can get here with an - * authentication error. We Need to do this in order to validate - * a crypto-NAK later. Note the order of processing; it is very - * important to avoid livelocks, deadlocks and lockpicks. - */ - peer->timereceived = current_time; - peer->received++; - if (peer->flash & TEST5) - peer->flags &= ~FLAG_AUTHENTIC; - else - peer->flags |= FLAG_AUTHENTIC; - NTOHL_FP(&pkt->org, &p_org); - NTOHL_FP(&pkt->xmt, &p_xmt); - - /* - * If the packet is an old duplicate, we let it through so the - * extension fields will be processed. - */ - if (L_ISEQU(&peer->org, &p_xmt)) { /* test 1 */ - peer->flash |= TEST1; /* dupe */ - /* fall through */ - - /* - * For broadcast server mode, loopback checking is disabled. An - * authentication error probably means the server restarted or - * rolled a new private value. If so, dump the association - * and wait for the next message. - */ - } else if (hismode == MODE_BROADCAST) { - if (peer->flash & TEST5) { - unpeer(peer); - return; - } - /* fall through */ - - /* - * For server and symmetric modes, if the association transmit - * timestamp matches the packet originate timestamp, loopback is - * confirmed. Note in symmetric modes this also happens when the - * first packet from the active peer arrives at the newly - * mobilized passive peer. An authentication error probably - * means the server or peer restarted or rolled a new private - * value, but could be an intruder trying to stir up trouble. - * However, if this is a crypto-NAK, we know it is authentic, so - * dump the association and wait for the next message. - */ - } else if (L_ISEQU(&peer->xmt, &p_org)) { - if (peer->flash & TEST5) { - if (has_mac == 4 && pkt->exten[0] == 0) { - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "AUTH"); - else - unpeer(peer); - } - return; - } - /* fall through */ - - /* - * If the client or passive peer has never transmitted anything, - * this is either the first message from a symmetric peer or - * possibly a duplicate received before the transmit timeout. - * Pass it on. - */ - } else if (L_ISZERO(&peer->xmt)) { - /* fall through */ - - /* - * Now it gets interesting. We have transmitted at least one - * packet. If the packet originate timestamp is nonzero, it - * does not match the association transmit timestamp, which is a - * loopback error. This error might mean a manycast server has - * answered a manycast honk from us and we already have an - * association for him, in which case quietly drop the packet - * here. It might mean an old duplicate, dropped packet or - * intruder replay, in which case we drop it later after - * extension field processing, but never let it touch the time - * values. - */ - } else if (!L_ISZERO(&p_org)) { - if (peer->cast_flags & MDF_ACLNT) - return; /* not a client */ - - peer->flash |= TEST2; - /* fall through */ - - /* - * The packet originate timestamp is zero, meaning the other guy - * either didn't receive the first packet or died and restarted. - * If the association originate timestamp is zero, this is the - * first packet received, so we pass it on. - */ - } else if (L_ISZERO(&peer->org)) { - /* fall through */ - - /* - * The other guy has restarted and we are still on the wire. We - * should demobilize/clear and get out of Dodge. If this is - * symmetric mode, we should also send a crypto-NAK. - */ - } else { - if (hismode == MODE_ACTIVE) - fast_xmit(rbufp, MODE_PASSIVE, 0, - restrict_mask); - else if (hismode == MODE_PASSIVE) - fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); -#if DEBUG - if (debug) - printf("receive: dropped %03x\n", peer->flash); -#endif - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "DROP"); - else - unpeer(peer); - return; - } - if (peer->flash & ~TEST2) { - return; - } - -#ifdef OPENSSL - /* - * More autokey dance. The rules of the cha-cha are as follows: - * - * 1. If there is no key or the key is not auto, do nothing. - * - * 2. If this packet is in response to the one just previously - * sent or from a broadcast server, do the extension fields. - * Otherwise, assume bogosity and bail out. - * - * 3. If an extension field contains a verified signature, it is - * self-authenticated and we sit the dance. - * - * 4. If this is a server reply, check only to see that the - * transmitted key ID matches the received key ID. - * - * 5. Check to see that one or more hashes of the current key ID - * matches the previous key ID or ultimate original key ID - * obtained from the broadcaster or symmetric peer. If no - * match, sit the dance and wait for timeout. - */ - if (crypto_flags && (peer->flags & FLAG_SKEY)) { - peer->flash |= TEST10; - rval = crypto_recv(peer, rbufp); - if (rval != XEVNT_OK) { - /* fall through */ - - } else if (hismode == MODE_SERVER) { - if (skeyid == peer->keyid) - peer->flash &= ~TEST10; - } else if (!peer->flash & TEST10) { - peer->pkeyid = skeyid; - } else if ((ap = (struct autokey *)peer->recval.ptr) != - NULL) { - int i; - - for (i = 0; ; i++) { - if (tkeyid == peer->pkeyid || - tkeyid == ap->key) { - peer->flash &= ~TEST10; - peer->pkeyid = skeyid; - break; - } - if (i > ap->seq) - break; - tkeyid = session_key( - &rbufp->recv_srcadr, dstadr_sin, - tkeyid, pkeyid, 0); - } - } - if (!(peer->crypto & CRYPTO_FLAG_PROV)) /* test 11 */ - peer->flash |= TEST11; /* not proventic */ - - /* - * If the transmit queue is nonempty, clamp the host - * poll interval to the packet poll interval. - */ - if (peer->cmmd != 0) { - peer->ppoll = pkt->ppoll; - poll_update(peer, 0); - } - - /* - * If the return code from extension field processing is - * not okay, we scrub the association and start over. - */ - if (rval != XEVNT_OK) { - - /* - * If the return code is bad, the crypto machine - * may be jammed or an intruder may lurk. First, - * we demobilize the association, then see if - * the error is recoverable. - */ - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "CRYP"); - else - unpeer(peer); -#ifdef DEBUG - if (debug) - printf("packet: bad exten %x\n", rval); -#endif - return; - } - - /* - * If TEST10 is lit, the autokey sequence has broken, - * which probably means the server has refreshed its - * private value. We reset the poll interval to the - & minimum and scrub the association clean. - */ - if (peer->flash & TEST10 && peer->crypto & - CRYPTO_FLAG_AUTO) { - poll_update(peer, peer->minpoll); -#ifdef DEBUG - if (debug) - printf( - "packet: bad auto %03x\n", - peer->flash); -#endif - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "AUTO"); - else - unpeer(peer); - return; - } - } -#endif /* OPENSSL */ - - /* - * We have survived the gaunt. Forward to the packet routine. If - * a symmetric passive association has been mobilized and the - * association doesn't deserve to live, it will die in the - * transmit routine if not reachable after timeout. However, if - * either symmetric mode and the crypto code has something - * urgent to say, we expedite the response. - */ - process_packet(peer, pkt, &rbufp->recv_time); -} - - -/* - * process_packet - Packet Procedure, a la Section 3.4.4 of the - * specification. Or almost, at least. If we're in here we have a - * reasonable expectation that we will be having a long term - * relationship with this host. - */ -void -process_packet( - register struct peer *peer, - register struct pkt *pkt, - l_fp *recv_ts - ) -{ - l_fp t34, t21; - double p_offset, p_del, p_disp; - double dtemp; - l_fp p_rec, p_xmt, p_org, p_reftime; - l_fp ci; - u_char pmode, pleap, pstratum; - - /* - * Swap header fields and keep the books. The books amount to - * 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++; - p_del = FPTOD(NTOHS_FP(pkt->rootdelay)); - p_disp = FPTOD(NTOHS_FP(pkt->rootdispersion)); - NTOHL_FP(&pkt->reftime, &p_reftime); - NTOHL_FP(&pkt->rec, &p_rec); - NTOHL_FP(&pkt->xmt, &p_xmt); - pmode = PKT_MODE(pkt->li_vn_mode); - pleap = PKT_LEAP(pkt->li_vn_mode); - if (pmode != MODE_BROADCAST) - NTOHL_FP(&pkt->org, &p_org); - else - p_org = peer->rec; - pstratum = PKT_TO_STRATUM(pkt->stratum); - - /* - * Test for unsynchronized server. - */ - if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */ - peer->oldpkt++; - if (pmode != MODE_BROADCAST && (L_ISZERO(&p_rec) || - L_ISZERO(&p_org))) /* test 3 */ - peer->flash |= TEST3; /* unsynch */ - if (L_ISZERO(&p_xmt)) /* test 3 */ - peer->flash |= TEST3; /* unsynch */ - - /* - * If any tests fail, the packet is discarded leaving only the - * timestamps, which are enough to get the protocol started. The - * originate timestamp is copied from the packet transmit - * timestamp and the receive timestamp is copied from the - * packet receive timestamp. If okay so far, we save the leap, - * stratum and refid for billboards. - */ - peer->org = p_xmt; - peer->rec = *recv_ts; - if (peer->flash) { -#ifdef DEBUG - if (debug) - printf("packet: bad data %03x from address: %s\n", - peer->flash, stoa(&peer->srcadr)); -#endif - return; - } - peer->leap = pleap; - peer->stratum = pstratum; - peer->refid = pkt->refid; - - /* - * Test for valid peer data (tests 6-8) - */ - ci = p_xmt; - L_SUB(&ci, &p_reftime); - LFPTOD(&ci, dtemp); - if (pleap == LEAP_NOTINSYNC || /* test 6 */ - pstratum >= STRATUM_UNSPEC || dtemp < 0) - peer->flash |= TEST6; /* bad synch */ - if (!(peer->flags & FLAG_CONFIG) && sys_peer != NULL) { /* test 7 */ - if (pstratum > sys_stratum && pmode != MODE_ACTIVE) - peer->flash |= TEST7; /* bad stratum */ - } - if (p_del < 0 || p_disp < 0 || p_del / /* test 8 */ - 2 + p_disp >= MAXDISPERSE) - peer->flash |= TEST8; /* bad peer values */ - - /* - * If any tests fail at this point, the packet is discarded. - */ - if (peer->flash) { -#ifdef DEBUG - if (debug) - printf("packet: bad header %03x\n", - peer->flash); -#endif - return; - } - - /* - * 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->pmode = pmode; - peer->ppoll = pkt->ppoll; - peer->precision = pkt->precision; - peer->rootdelay = p_del; - peer->rootdispersion = p_disp; - peer->reftime = p_reftime; - if (!(peer->reach)) { - report_event(EVNT_REACH, peer); - peer->timereachable = current_time; - } - peer->reach |= 1; - peer->unreach = 0; - poll_update(peer, 0); - - /* - * If running in a client/server association, calculate the - * clock offset c, roundtrip delay d and dispersion e. We use - * the equations (reordered from those in the spec). Note that, - * in a broadcast association, org has been set to the time of - * last reception. Note the computation of dispersion includes - * the system precision plus that due to the frequency error - * since the originate time. - * - * Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec: - */ - t34 = p_xmt; /* t3 - t4 */ - L_SUB(&t34, &peer->rec); - t21 = p_rec; /* t2 - t1 */ - L_SUB(&t21, &p_org); - ci = peer->rec; /* t4 - t1 */ - L_SUB(&ci, &p_org); - LFPTOD(&ci, p_disp); - p_disp = clock_phi * max(p_disp, LOGTOD(sys_precision)); - - /* - * If running in a broadcast association, the clock offset is - * (t1 - t0) corrected by the one-way delay, but we can't - * measure that directly. Therefore, we start up in MODE_CLIENT - * mode, set FLAG_MCAST and exchange eight messages to determine - * the clock offset. When the last message is sent, we switch to - * MODE_BCLIENT mode. The next broadcast message after that - * computes the broadcast offset and clears FLAG_MCAST. - */ - ci = t34; - if (pmode == MODE_BROADCAST) { - if (peer->flags & FLAG_MCAST) { - LFPTOD(&ci, p_offset); - peer->estbdelay = peer->offset - p_offset; - if (peer->hmode == MODE_CLIENT) - return; - - peer->flags &= ~FLAG_MCAST; - } - DTOLFP(peer->estbdelay, &t34); - L_ADD(&ci, &t34); - p_del = peer->delay; - } else { - L_ADD(&ci, &t21); /* (t2 - t1) + (t3 - t4) */ - L_RSHIFT(&ci); - L_SUB(&t21, &t34); /* (t2 - t1) - (t3 - t4) */ - LFPTOD(&t21, p_del); - } - p_del = max(p_del, LOGTOD(sys_precision)); - LFPTOD(&ci, p_offset); - if ((peer->rootdelay + p_del) / 2. + peer->rootdispersion + - p_disp >= MAXDISPERSE) /* test 9 */ - peer->flash |= TEST9; /* bad root distance */ - - /* - * 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("packet: bad packet data %03x\n", - peer->flash); -#endif - return; - } - 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->jitter)); -} - - -/* - * clock_update - Called at system process update intervals. - */ -static void -clock_update(void) -{ - u_char oleap; - u_char ostratum; - - /* - * Reset/adjust the system clock. Do this only if there is a - * system peer and the peer epoch is not older than the last - * update. - */ - if (sys_peer == NULL) - return; - if (sys_peer->epoch <= last_time) - return; -#ifdef DEBUG - if (debug) - printf("clock_update: at %ld assoc %d \n", current_time, - peer_associations); -#endif - oleap = sys_leap; - ostratum = sys_stratum; - switch (local_clock(sys_peer, sys_offset, sys_syserr)) { - - /* - * Clock is too screwed up. Just exit for now. - */ - case -1: - report_event(EVNT_SYSFAULT, NULL); - exit (-1); - /*NOTREACHED*/ - - /* - * Clock was stepped. Flush all time values of all peers. - */ - case 1: - clear_all(); - sys_peer = NULL; - sys_stratum = STRATUM_UNSPEC; - memcpy(&sys_refid, "STEP", 4); - sys_poll = NTP_MINPOLL; - report_event(EVNT_CLOCKRESET, NULL); -#ifdef OPENSSL - if (oleap != LEAP_NOTINSYNC) - expire_all(); -#endif /* OPENSSL */ - break; - - /* - * 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 = (u_char) (sys_peer->stratum + 1); - if (sys_stratum == 1 || sys_stratum == STRATUM_UNSPEC) - sys_refid = sys_peer->refid; - else - sys_refid = sys_peer_refid; - sys_reftime = sys_peer->rec; - sys_rootdelay = sys_peer->rootdelay + sys_peer->delay; - sys_leap = leap_consensus; - if (oleap == LEAP_NOTINSYNC) { - report_event(EVNT_SYNCCHG, NULL); -#ifdef OPENSSL - expire_all(); -#endif /* OPENSSL */ - } - } - if (ostratum != sys_stratum) - report_event(EVNT_PEERSTCHG, NULL); -} - - -/* - * poll_update - update peer poll interval - */ -void -poll_update( - struct peer *peer, - int hpoll - ) -{ -#ifdef OPENSSL - int oldpoll; -#endif /* OPENSSL */ - - /* - * 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. - */ -#ifdef OPENSSL - oldpoll = peer->kpoll; -#endif /* OPENSSL */ - if (hpoll > 0) { - if (hpoll > peer->maxpoll) - peer->hpoll = peer->maxpoll; - else if (hpoll < peer->minpoll) - peer->hpoll = peer->minpoll; - else - peer->hpoll = (u_char)hpoll; - } - - /* - * Bit of adventure here. If during a burst and not a poll, just - * slink away. If a poll, figure what the next poll should be. - * If a burst is pending and a reference clock or a pending - * crypto response, delay for one second. If the first sent in a - * burst, delay ten seconds for the modem to come up. For others - * in the burst, delay two seconds. - * - * In case of manycast server, make the poll interval, which is - * axtually the manycast beacon interval, eight times the system - * poll interval. Normally when the host poll interval settles - * up to 1024 s, the beacon interval settles up to 2.3 hours. - */ -#ifdef OPENSSL - if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC || - peer->crypto)) { - peer->nextdate = current_time + RESP_DELAY; - } else if (peer->burst > 0) { -#else /* OPENSSL */ - if (peer->burst > 0) { -#endif /* OPENSSL */ - if (hpoll == 0 && peer->nextdate != current_time) - return; -#ifdef REFCLOCK - else if (peer->flags & FLAG_REFCLOCK) - peer->nextdate += RESP_DELAY; -#endif - else if (peer->flags & (FLAG_IBURST | FLAG_BURST) && - peer->burst == NTP_BURST) - peer->nextdate += sys_calldelay; - else - peer->nextdate += BURST_DELAY; - } else if (peer->cast_flags & MDF_ACAST) { - if (sys_survivors >= sys_minclock || peer->ttl >= - sys_ttlmax) - peer->kpoll = (u_char) (peer->hpoll + 3); - else - peer->kpoll = peer->hpoll; - peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); - } else { - peer->kpoll = (u_char) max(min(peer->ppoll, - peer->hpoll), peer->minpoll); - peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); - } - if (peer->nextdate < current_time) - peer->nextdate = current_time; -#ifdef OPENSSL - /* - * Bit of crass arrogance at this point. If the poll interval - * has changed and we have a keylist, the lifetimes in the - * keylist are probably bogus. In this case purge the keylist - * and regenerate it later. - */ - if (peer->kpoll != oldpoll) - key_expire(peer); -#endif /* OPENSSL */ -#ifdef DEBUG - if (debug > 1) - printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n", - current_time, ntoa(&peer->srcadr), peer->flags, - peer->kpoll, peer->burst, peer->outdate, - peer->nextdate); -#endif -} - - -/* - * clear - clear peer filter registers. See Section 3.4.8 of the spec. - */ -void -peer_clear( - struct peer *peer, /* peer structure */ - char *ident /* tally lights */ - ) -{ - u_char oreach, i; - - /* - * 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. - */ - oreach = peer->reach; -#ifdef OPENSSL - key_expire(peer); - if (peer->pkey != NULL) - EVP_PKEY_free(peer->pkey); - if (peer->ident_pkey != NULL) - EVP_PKEY_free(peer->ident_pkey); - if (peer->subject != NULL) - free(peer->subject); - if (peer->issuer != NULL) - free(peer->issuer); - if (peer->iffval != NULL) - BN_free(peer->iffval); - if (peer->grpkey != NULL) - BN_free(peer->grpkey); - if (peer->cmmd != NULL) - free(peer->cmmd); - value_free(&peer->cookval); - value_free(&peer->recval); - value_free(&peer->tai_leap); - value_free(&peer->encrypt); - value_free(&peer->sndval); -#endif /* OPENSSL */ - - /* - * Wipe the association clean and initialize the nonzero values. - */ - memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); - if (peer == sys_peer) - sys_peer = NULL; - peer->estbdelay = sys_bdelay; - peer->hpoll = peer->kpoll = peer->minpoll; - peer->ppoll = peer->maxpoll; - peer->jitter = MAXDISPERSE; - peer->epoch = current_time; -#ifdef REFCLOCK - if (!(peer->flags & FLAG_REFCLOCK)) { - peer->leap = LEAP_NOTINSYNC; - peer->stratum = STRATUM_UNSPEC; - memcpy(&peer->refid, ident, 4); - } -#else - peer->leap = LEAP_NOTINSYNC; - peer->stratum = STRATUM_UNSPEC; - memcpy(&peer->refid, ident, 4); -#endif - for (i = 0; i < NTP_SHIFT; i++) { - peer->filter_order[i] = i; - peer->filter_disp[i] = MAXDISPERSE; - peer->filter_epoch[i] = current_time; - } - - /* - * 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. - */ - if (peer->cast_flags & MDF_BCLNT) { - peer->flags |= FLAG_MCAST; - peer->hmode = MODE_CLIENT; - } - - /* - * Randomize the first poll to avoid bunching, but only if the - * rascal has never been heard. During initialization use the - * association count to spread out the polls at one-second - * intervals. - */ - peer->nextdate = peer->update = peer->outdate = current_time; - peer->burst = 0; - if (oreach) - poll_update(peer, 0); - else if (initializing) - peer->nextdate = current_time + peer_associations; - else - peer->nextdate = current_time + (u_int)RANDOM % - peer_associations; -#ifdef DEBUG - if (debug) - printf("peer_clear: at %ld assoc ID %d refid %s\n", - current_time, peer->associd, ident); -#endif -} - - -/* - * clock_filter - add incoming clock sample to filter register and run - * the filter procedure to find the best sample. - */ -void -clock_filter( - struct peer *peer, /* peer structure pointer */ - double sample_offset, /* clock offset */ - double sample_delay, /* roundtrip delay */ - double sample_disp /* dispersion */ - ) -{ - double dst[NTP_SHIFT]; /* distance vector */ - int ord[NTP_SHIFT]; /* index vector */ - int i, j, k, m; - double dsp, jit, dtemp, etemp; - - /* - * 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. - */ - dsp = min(LOGTOD(peer->precision) + LOGTOD(sys_precision) + - sample_disp, MAXDISPERSE); - j = peer->filter_nextpt; - peer->filter_offset[j] = sample_offset; - peer->filter_delay[j] = max(0, sample_delay); - peer->filter_disp[j] = dsp; - j++; j %= NTP_SHIFT; - peer->filter_nextpt = (u_short) j; - - /* - * 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. - */ - 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; - } - peer->filter_epoch[j] = current_time; - - /* - * Sort the samples in both lists by distance. - */ - for (i = 1; i < NTP_SHIFT; i++) { - for (j = 0; j < i; j++) { - if (dst[j] > dst[i]) { - k = ord[j]; - 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] = (u_char) ord[i]; - if (dst[i] >= MAXDISPERSE || (m >= 2 && dst[i] >= - MAXDISTANCE)) - continue; - m++; - } - - /* - * 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. - */ - jit = 0; - peer->disp = 0; - k = ord[0]; - for (i = NTP_SHIFT - 1; i >= 0; i--) { - - 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]); - } - - /* - * 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 = fabs(peer->offset - peer->filter_offset[k]); - dtemp = sqrt(peer->jitter); - peer->offset = peer->filter_offset[k]; - peer->delay = peer->filter_delay[k]; - if (m > 1) - 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, but only if the sucker has been synchronized. - */ - if (peer->filter_epoch[k] <= peer->epoch && sys_leap != - LEAP_NOTINSYNC) { -#ifdef DEBUG - if (debug) - printf("clock_filter: discard %lu\n", - peer->epoch - peer->filter_epoch[k]); -#endif - return; - } - - /* - * If the difference between the last offset and the current one - * exceeds the jitter by CLOCK_SGATE and the interval since the - * last update is less than twice the system poll interval, - * consider the update a popcorn spike and ignore it. - */ - if (m > 1 && etemp > CLOCK_SGATE * dtemp && - (long)(peer->filter_epoch[k] - peer->epoch) < (1 << (sys_poll + - 1))) { -#ifdef DEBUG - if (debug) - printf("clock_filter: popcorn %.6f %.6f\n", - etemp, dtemp); -#endif - return; - } - - /* - * The mitigated sample statistics are saved for later - * processing. - */ - peer->epoch = peer->filter_epoch[k]; -#ifdef DEBUG - if (debug) - printf( - "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 -} - - -/* - * clock_select - find the pick-of-the-litter clock - * - * LOCKCLOCK: If the local clock is the prefer peer, it will always be - * enabled, even if declared falseticker, (2) only the prefer peer can - * be selected as the system peer, (3) if the external source is down, - * the system leap bits are set to 11 and the stratum set to infinity. - */ -void -clock_select(void) -{ - struct peer *peer; - int i, j, k, n; - int nlist, nl3; - - double d, e, f; - int allow, sw, osurv; - double high, low; - double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; - struct peer *osys_peer; - struct peer *typeacts = NULL; - struct peer *typelocal = NULL; - struct peer *typepps = NULL; - struct peer *typesystem = NULL; - - static int list_alloc = 0; - static struct endpoint *endpoint = NULL; - static int *indx = NULL; - static struct peer **peer_list = NULL; - static u_int endpoint_size = 0; - static u_int indx_size = 0; - static u_int peer_list_size = 0; - - /* - * Initialize and create endpoint, index and peer lists big - * enough to handle all associations. - */ - osys_peer = sys_peer; - sys_peer = NULL; - osurv = sys_survivors; - sys_survivors = 0; - sys_prefer = NULL; -#ifdef LOCKCLOCK - sys_leap = LEAP_NOTINSYNC; - sys_stratum = STRATUM_UNSPEC; - memcpy(&sys_refid, "DOWN", 4); -#endif /* LOCKCLOCK */ - nlist = 0; - for (n = 0; n < HASH_SIZE; n++) - nlist += peer_hash_count[n]; - if (nlist > list_alloc) { - if (list_alloc > 0) { - free(endpoint); - free(indx); - free(peer_list); - } - while (list_alloc < nlist) { - list_alloc += 5; - endpoint_size += 5 * 3 * sizeof(*endpoint); - indx_size += 5 * 3 * sizeof(*indx); - peer_list_size += 5 * sizeof(*peer_list); - } - endpoint = emalloc(endpoint_size); - indx = emalloc(indx_size); - peer_list = emalloc(peer_list_size); - } - - /* - * 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 sys_minclock, the survivors split a million - * bucks and collectively crank the chimes. - */ - nlist = nl3 = 0; /* none yet */ - for (n = 0; n < HASH_SIZE; n++) { - for (peer = peer_hash[n]; peer != NULL; peer = - peer->next) { - peer->flags &= ~FLAG_SYSPEER; - peer->status = CTL_PST_SEL_REJECT; - - /* - * Leave the island immediately if the peer is - * unfit to synchronize. - */ - if (peer_unfit(peer)) - continue; - - /* - * Don't allow the local clock or modem drivers - * in the kitchen at this point, unless the - * prefer peer. Do that later, but only if - * nobody else is around. These guys are all - * configured, so we never throw them away. - */ - if (peer->refclktype == REFCLK_LOCALCLOCK -#if defined(VMS) && defined(VMS_LOCALUNIT) - /* wjm: VMS_LOCALUNIT taken seriously */ - && REFCLOCKUNIT(&peer->srcadr) != - VMS_LOCALUNIT -#endif /* VMS && VMS_LOCALUNIT */ - ) { - typelocal = peer; - if (!(peer->flags & FLAG_PREFER)) - continue; /* no local clock */ -#ifdef LOCKCLOCK - else - sys_prefer = peer; -#endif /* LOCKCLOCK */ - } - if (peer->sstclktype == CTL_SST_TS_TELEPHONE) { - typeacts = peer; - if (!(peer->flags & FLAG_PREFER)) - continue; /* no acts */ - } - - /* - * If we get this far, the peer can stay on the - * island, but does not yet have the immunity - * idol. - */ - peer->status = CTL_PST_SEL_SANE; - peer_list[nlist++] = peer; - - /* - * Insert each interval endpoint on the sorted - * list. - */ - e = peer->offset; /* Upper end */ - f = root_distance(peer); - e = e + f; - for (i = nl3 - 1; i >= 0; i--) { - if (e >= endpoint[indx[i]].val) - break; - indx[i + 3] = indx[i]; - } - indx[i + 3] = nl3; - endpoint[nl3].type = 1; - endpoint[nl3++].val = e; - - e = e - f; /* Center point */ - for (; i >= 0; i--) { - if (e >= endpoint[indx[i]].val) - break; - indx[i + 2] = indx[i]; - } - indx[i + 2] = nl3; - endpoint[nl3].type = 0; - endpoint[nl3++].val = e; - - e = e - f; /* Lower end */ - for (; i >= 0; i--) { - if (e >= endpoint[indx[i]].val) - break; - indx[i + 1] = indx[i]; - } - indx[i + 1] = nl3; - endpoint[nl3].type = -1; - endpoint[nl3++].val = e; - } - } -#ifdef DEBUG - if (debug > 2) - for (i = 0; i < nl3; i++) - printf("select: endpoint %2d %.6f\n", - endpoint[indx[i]].type, - endpoint[indx[i]].val); -#endif - /* - * This is the actual algorithm that cleaves the truechimers - * from the falsetickers. The original algorithm was described - * in Keith Marzullo's dissertation, but has been modified for - * better accuracy. - * - * Briefly put, we first assume there are no falsetickers, then - * scan the candidate list first from the low end upwards and - * then from the high end downwards. The scans stop when the - * number of intersections equals the number of candidates less - * the number of falsetickers. If this doesn't happen for a - * given number of falsetickers, we bump the number of - * falsetickers and try again. If the number of falsetickers - * becomes equal to or greater than half the number of - * candidates, the Albanians have won the Byzantine wars and - * correct synchronization is not possible. - * - * Here, nlist is the number of candidates and allow is the - * number of falsetickers. - */ - low = 1e9; - high = -1e9; - for (allow = 0; 2 * allow < nlist; allow++) { - int found; - - /* - * Bound the interval (low, high) as the largest - * interval containing points from presumed truechimers. - */ - found = 0; - n = 0; - for (i = 0; i < nl3; i++) { - low = endpoint[indx[i]].val; - n -= endpoint[indx[i]].type; - if (n >= nlist - allow) - break; - if (endpoint[indx[i]].type == 0) - found++; - } - n = 0; - for (j = nl3 - 1; j >= 0; j--) { - high = endpoint[indx[j]].val; - n += endpoint[indx[j]].type; - if (n >= nlist - allow) - break; - if (endpoint[indx[j]].type == 0) - found++; - } - - /* - * If the number of candidates found outside the - * interval is greater than the number of falsetickers, - * then at least one truechimer is outside the interval, - * so go around again. This is what makes this algorithm - * different than Marzullo's. - */ - if (found > allow) - continue; - - /* - * If an interval containing truechimers is found, stop. - * If not, increase the number of falsetickers and go - * around again. - */ - if (high > low) - break; - } - - /* - * If no survivors remain at this point, check if the local - * clock or modem drivers have been found. If so, nominate one - * of them as the only survivor. Otherwise, give up and leave - * the island to the rats. - */ - if (high <= low) { - if (typeacts != 0) { - typeacts->status = CTL_PST_SEL_SANE; - peer_list[0] = typeacts; - nlist = 1; - } else if (typelocal != 0) { - typelocal->status = CTL_PST_SEL_SANE; - peer_list[0] = typelocal; - nlist = 1; - } else { - if (osys_peer != NULL) { - sys_poll = NTP_MINPOLL; - NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, - "no servers reachable"); - report_event(EVNT_PEERSTCHG, NULL); - } - if (osurv > 0) - resetmanycast(); - return; - } - } - - /* - * We can only trust the survivors if the number of candidates - * sys_minsane is at least the number required to detect and - * cast out one falsticker. For the Byzantine agreement - * algorithm used here, that number is 4; however, the default - * sys_minsane is 1 to speed initial synchronization. Careful - * operators will tinker the value to 4 and use at least that - * number of synchronization sources. - */ - if (nlist < sys_minsane) - return; - - /* - * Clustering algorithm. Construct candidate list in order first - * by stratum then by root distance, but keep only the best - * NTP_MAXCLOCK of them. Scan the list to find falsetickers, who - * leave the island immediately. If a falseticker is not - * configured, his association raft is drowned as well, but only - * if at at least eight poll intervals have gone. We must leave - * at least one peer to collect the million bucks. - * - * Note the hysteresis gimmick that increases the effective - * distance for those rascals that have not made the final cut. - * This is to discourage clockhopping. Note also the prejudice - * against lower stratum peers if the floor is elevated. - */ - j = 0; - for (i = 0; i < nlist; i++) { - peer = peer_list[i]; - if (nlist > 1 && (peer->offset <= low || peer->offset >= - high)) { - if (!(peer->flags & FLAG_CONFIG)) - unpeer(peer); - continue; - } - peer->status = CTL_PST_SEL_DISTSYSPEER; - d = peer->stratum; - if (d < sys_floor) - d += sys_floor; - if (d > sys_ceiling) - d = STRATUM_UNSPEC; - d = root_distance(peer) + d * MAXDISTANCE; - d *= 1. - peer->hyst; - if (j >= NTP_MAXCLOCK) { - if (d >= synch[j - 1]) - continue; - else - j--; - } - for (k = j; k > 0; k--) { - if (d >= synch[k - 1]) - break; - 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; - if (nlist == 0) { -#ifdef DEBUG - if (debug) - printf("clock_select: empty intersection interval\n"); -#endif - return; - } - for (i = 0; i < nlist; i++) { - peer_list[i]->status = CTL_PST_SEL_SELCAND; - -#ifdef DEBUG - if (debug > 2) - printf("select: %s distance %.6f jitter %.6f\n", - ntoa(&peer_list[i]->srcadr), synch[i], - SQRT(error[i])); -#endif - } - - /* - * Now, vote outlyers off the island by select jitter weighted - * by root dispersion. Continue voting as long as there are more - * than sys_minclock survivors and the minimum select jitter - * squared is greater than the maximum peer jitter squared. Stop - * if we are about to discard a prefer peer, who of course has - * the immunity idol. - */ - while (1) { - 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 (f * synch[i] > e) { - sys_selerr = f; - e = f * synch[i]; - k = i; - } - } - f = max(sys_selerr, SQUARE(LOGTOD(sys_precision))); - if (nlist <= sys_minclock || f <= d || - peer_list[k]->flags & FLAG_PREFER) - break; -#ifdef DEBUG - if (debug > 2) - printf( - "select: drop %s select %.6f jitter %.6f\n", - ntoa(&peer_list[k]->srcadr), - SQRT(sys_selerr), SQRT(d)); -#endif - if (!(peer_list[k]->flags & FLAG_CONFIG) && - peer_list[k]->hmode == MODE_CLIENT) - unpeer(peer_list[k]); - for (j = k + 1; j < nlist; j++) { - peer_list[j - 1] = peer_list[j]; - error[j - 1] = error[j]; - } - nlist--; - } - - /* - * What remains is a list usually not greater than sys_minclock - * peers. We want only a peer at the lowest stratum to become - * the system peer, although all survivors are eligible for the - * combining algorithm. First record their order, diddle the - * flags and clamp the poll intervals. Then, consider each peer - * in turn and OR the leap bits on the assumption that, if some - * of them honk nonzero bits, they must know what they are - * doing. Check for prefer and pps peers at any stratum. Check - * if the old system peer is among the peers at the lowest - * stratum. Note that the head of the list is at the lowest - * stratum and that unsynchronized peers cannot survive this - * far. - * - * Fiddle for hysteresis. Pump it up for a peer only if the peer - * stratum is at least the floor and there are enough survivors. - * This minimizes the pain when tossing out rascals beneath the - * floorboard. Don't count peers with stratum above the ceiling. - * Manycast is sooo complicated. - */ - leap_consensus = 0; - for (i = nlist - 1; i >= 0; i--) { - peer = peer_list[i]; - leap_consensus |= peer->leap; - peer->status = CTL_PST_SEL_SYNCCAND; - peer->rank++; - peer->flags |= FLAG_SYSPEER; - if (peer->stratum >= sys_floor && osurv >= sys_minclock) - peer->hyst = HYST; - else - peer->hyst = 0; - if (peer->stratum <= sys_ceiling) - sys_survivors++; - if (peer->flags & FLAG_PREFER) - sys_prefer = peer; - if (peer->refclktype == REFCLK_ATOM_PPS && - peer->stratum < STRATUM_UNSPEC) - typepps = peer; - if (peer->stratum == peer_list[0]->stratum && peer == - osys_peer) - typesystem = peer; - } - - /* - * In manycast client mode we may have spooked a sizeable number - * of peers that we don't need. If there are at least - * sys_minclock of them, the manycast message will be turned - * off. By the time we get here we nay be ready to prune some of - * them back, but we want to make sure all the candicates have - * had a chance. If they didn't pass the sanity and intersection - * tests, they have already been voted off the island. - */ - if (sys_survivors < sys_minclock && osurv >= sys_minclock) - resetmanycast(); - - /* - * Mitigation rules of the game. There are several types of - * peers that make a difference here: (1) prefer local peers - * (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer modem - * peers (type REFCLK_NIST_ATOM etc with FLAG_PREFER), (2) pps - * peers (type REFCLK_ATOM_PPS), (3) remaining prefer peers - * (flag FLAG_PREFER), (4) the existing system peer, if any, (5) - * the head of the survivor list. Note that only one peer can be - * declared prefer. The order of preference is in the order - * stated. Note that all of these must be at the lowest stratum, - * i.e., the stratum of the head of the survivor list. - */ - 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_syserr = sys_peer->jitter; -#ifdef DEBUG - if (debug > 1) - printf("select: prefer offset %.6f\n", - sys_offset); -#endif - } -#ifndef LOCKCLOCK - else if (typepps) { - sys_peer = typepps; - sys_peer->status = CTL_PST_SEL_PPS; - sys_offset = sys_peer->offset; - sys_syserr = sys_peer->jitter; - if (!pps_control) - NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, "pps sync enabled"); - pps_control = current_time; -#ifdef DEBUG - if (debug > 1) - printf("select: pps offset %.6f\n", - sys_offset); -#endif - } else { - if (typesystem) - sys_peer = osys_peer; - else - sys_peer = peer_list[0]; - sys_peer->status = CTL_PST_SEL_SYSPEER; - sys_peer->rank++; - sys_offset = clock_combine(peer_list, nlist); - sys_syserr = sys_peer->jitter + sys_selerr; -#ifdef DEBUG - if (debug > 1) - printf("select: combine offset %.6f\n", - sys_offset); -#endif - } -#endif /* LOCKCLOCK */ - if (osys_peer != sys_peer) { - char *src; - - if (sys_peer == NULL) - sys_peer_refid = 0; - else - sys_peer_refid = addr2refid(&sys_peer->srcadr); - report_event(EVNT_PEERSTCHG, NULL); - -#ifdef REFCLOCK - if (ISREFCLOCKADR(&sys_peer->srcadr)) - src = refnumtoa(&sys_peer->srcadr); - else -#endif - src = ntoa(&sys_peer->srcadr); - NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, "synchronized to %s, stratum=%d", src, - sys_peer->stratum); - } - clock_update(); -} - -/* - * clock_combine - combine offsets from selected peers - */ -static double -clock_combine( - struct peer **peers, - int npeers - ) -{ - int i; - double x, y, z; - - y = z = 0; - for (i = 0; i < npeers; i++) { - x = root_distance(peers[i]); - y += 1. / x; - z += peers[i]->offset / x; - } - return (z / y); -} - -/* - * root_distance - compute synchronization distance from peer to root - */ -static double -root_distance( - struct peer *peer - ) -{ - /* - * 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)); -} - -/* - * peer_xmit - send packet for persistent association. - */ -static void -peer_xmit( - struct peer *peer /* peer structure pointer */ - ) -{ - struct pkt xpkt; /* transmit packet */ - int sendlen, authlen; - keyid_t xkeyid = 0; /* transmit key ID */ - l_fp xmt_tx; - - /* - * Initialize transmit packet header fields. - */ - 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)); - xpkt.refid = sys_refid; - HTONL_FP(&sys_reftime, &xpkt.reftime); - HTONL_FP(&peer->org, &xpkt.org); - HTONL_FP(&peer->rec, &xpkt.rec); - - /* - * 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)) { - get_systime(&peer->xmt); - HTONL_FP(&peer->xmt, &xpkt.xmt); - sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], - &xpkt, sendlen); - peer->sent++; -#ifdef DEBUG - if (debug) - printf("transmit: at %ld %s->%s mode %d\n", - current_time, stoa(&peer->dstadr->sin), - stoa(&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 OPENSSL - if (crypto_flags && (peer->flags & FLAG_SKEY)) { - struct exten *exten; /* extension field */ - u_int opcode; - - /* - * 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. - */ - while (1) { - - /* - * 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 (peer->keynumber == 0) - make_keylist(peer, peer->dstadr); - else - peer->keynumber--; - xkeyid = peer->keylist[peer->keynumber]; - if (authistrusted(xkeyid)) - break; - else - key_expire(peer); - } - peer->keyid = xkeyid; - switch (peer->hmode) { - - /* - * In broadcast server mode the autokey values are - * required by the broadcast clients. Push them when a - * new keylist is generated; otherwise, push the - * association message so the client can request them at - * other times. - */ - case MODE_BROADCAST: - if (peer->flags & FLAG_ASSOC) - exten = crypto_args(peer, CRYPTO_AUTO | - CRYPTO_RESP, NULL); - else - exten = crypto_args(peer, CRYPTO_ASSOC | - CRYPTO_RESP, NULL); - sendlen += crypto_xmit(&xpkt, &peer->srcadr, - sendlen, exten, 0); - free(exten); - break; - - /* - * In symmetric modes the digest, certificate, agreement - * parameters, cookie and autokey values are required. - * The leapsecond table is optional. But, a passive peer - * will not believe the active peer until the latter has - * synchronized, so the agreement must be postponed - * until then. In any case, if a new keylist is - * generated, the autokey values are pushed. - */ - case MODE_ACTIVE: - case MODE_PASSIVE: - if (peer->cmmd != NULL) { - peer->cmmd->associd = - htonl(peer->associd); - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, peer->cmmd, - 0); - free(peer->cmmd); - peer->cmmd = NULL; - } - exten = NULL; - if (!peer->crypto) - exten = crypto_args(peer, CRYPTO_ASSOC, - sys_hostname); - else if (!(peer->crypto & CRYPTO_FLAG_VALID)) - exten = crypto_args(peer, CRYPTO_CERT, - peer->issuer); - - /* - * Identity. Note we have to sign the - * certificate before the cookie to avoid a - * deadlock when the passive peer is walking the - * certificate trail. Awesome. - */ - else if ((opcode = crypto_ident(peer)) != 0) - exten = crypto_args(peer, opcode, NULL); - else if (sys_leap != LEAP_NOTINSYNC && - !(peer->crypto & CRYPTO_FLAG_SIGN)) - exten = crypto_args(peer, CRYPTO_SIGN, - sys_hostname); - - /* - * Autokey. We request the cookie only when the - * server and client are synchronized and - * signatures work both ways. On the other hand, - * the active peer needs the autokey values - * before then and when the passive peer is - * waiting for the active peer to synchronize. - * Any time we regenerate the key list, we offer - * the autokey values without being asked. - */ - else if (sys_leap != LEAP_NOTINSYNC && - peer->leap != LEAP_NOTINSYNC && - !(peer->crypto & CRYPTO_FLAG_AGREE)) - exten = crypto_args(peer, CRYPTO_COOK, - NULL); - else if (peer->flags & FLAG_ASSOC) - exten = crypto_args(peer, CRYPTO_AUTO | - CRYPTO_RESP, NULL); - else if (!(peer->crypto & CRYPTO_FLAG_AUTO)) - exten = crypto_args(peer, CRYPTO_AUTO, - NULL); - - /* - * Postamble. We trade leapseconds only when the - * server and client are synchronized. - */ - else if (sys_leap != LEAP_NOTINSYNC && - peer->leap != LEAP_NOTINSYNC && - peer->crypto & CRYPTO_FLAG_TAI && - !(peer->crypto & CRYPTO_FLAG_LEAP)) - exten = crypto_args(peer, CRYPTO_TAI, - NULL); - if (exten != NULL) { - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, exten, 0); - free(exten); - } - break; - - /* - * In client mode the digest, certificate, agreement - * parameters and cookie are required. The leapsecond - * table is optional. If broadcast client mode, the - * autokey values are required as well. In broadcast - * client mode, these values must be acquired during the - * client/server exchange to avoid having to wait until - * the next key list regeneration. Otherwise, the poor - * dude may die a lingering death until becoming - * unreachable and attempting rebirth. - * - * If neither the server or client have the agreement - * parameters, the protocol transmits the cookie in the - * clear. If the server has the parameters, the client - * requests them and the protocol blinds it using the - * agreed key. It is a protocol error if the client has - * the parameters but the server does not. - */ - case MODE_CLIENT: - if (peer->cmmd != NULL) { - peer->cmmd->associd = - htonl(peer->associd); - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, peer->cmmd, - 0); - free(peer->cmmd); - peer->cmmd = NULL; - } - exten = NULL; - if (!peer->crypto) - exten = crypto_args(peer, CRYPTO_ASSOC, - sys_hostname); - else if (!(peer->crypto & CRYPTO_FLAG_VALID)) - exten = crypto_args(peer, CRYPTO_CERT, - peer->issuer); - - /* - * Identity. - */ - else if ((opcode = crypto_ident(peer)) != 0) - exten = crypto_args(peer, opcode, NULL); - - /* - * Autokey - */ - else if (!(peer->crypto & CRYPTO_FLAG_AGREE)) - exten = crypto_args(peer, CRYPTO_COOK, - NULL); - else if (!(peer->crypto & CRYPTO_FLAG_AUTO) && - (peer->cast_flags & MDF_BCLNT)) - exten = crypto_args(peer, CRYPTO_AUTO, - NULL); - - /* - * Postamble. We can sign the certificate here, - * since there is no chance of deadlock. - */ - else if (sys_leap != LEAP_NOTINSYNC && - !(peer->crypto & CRYPTO_FLAG_SIGN)) - exten = crypto_args(peer, CRYPTO_SIGN, - sys_hostname); - else if (sys_leap != LEAP_NOTINSYNC && - peer->crypto & CRYPTO_FLAG_TAI && - !(peer->crypto & CRYPTO_FLAG_LEAP)) - exten = crypto_args(peer, CRYPTO_TAI, - NULL); - if (exten != NULL) { - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, exten, 0); - free(exten); - } - break; - } - - /* - * If extension fields are present, we must use a - * private value of zero and force min poll interval. - * Most intricate. - */ - if (sendlen > LEN_PKT_NOMAC) - session_key(&peer->dstadr->sin, &peer->srcadr, - xkeyid, 0, 2); - } -#endif /* OPENSSL */ - xkeyid = peer->keyid; - get_systime(&peer->xmt); - L_ADD(&peer->xmt, &sys_authdelay); - HTONL_FP(&peer->xmt, &xpkt.xmt); - authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); - if (authlen == 0) { - msyslog(LOG_INFO, - "transmit: encryption key %d not found", xkeyid); - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "NKEY"); - else - unpeer(peer); - return; - } - sendlen += authlen; -#ifdef OPENSSL - if (xkeyid > NTP_MAXKEY) - authtrust(xkeyid, 0); -#endif /* OPENSSL */ - get_systime(&xmt_tx); - if (sendlen > sizeof(xpkt)) { - msyslog(LOG_ERR, "buffer overflow %u", sendlen); - exit (-1); - } - sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[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 OPENSSL -#ifdef DEBUG - if (debug) - printf( - "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n", - current_time, ntoa(&peer->dstadr->sin), - ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - - authlen, 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, authlen); -#endif -#endif /* OPENSSL */ -} - - -/* - * 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 */ - keyid_t xkeyid, /* transmit key ID */ - int mask /* restrict mask */ - ) -{ - struct pkt xpkt; /* transmit packet structure */ - struct pkt *rpkt; /* receive packet structure */ - l_fp xmt_ts; /* timestamp */ - l_fp xmt_tx; /* timestamp after authent */ - int sendlen, authlen; -#ifdef OPENSSL - u_int32 temp32; -#endif - - /* - * Initialize transmit packet header fields from the receive - * 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; - if (rbufp->dstadr->flags & INT_MULTICAST) - rbufp->dstadr = findinterface(&rbufp->recv_srcadr); - - /* - * If the packet has picked up a restriction due to either - * access denied or rate exceeded, decide what to do with it. - */ - if (mask & (RES_DONTTRUST | RES_LIMITED)) { - char *code = "????"; - - if (mask & RES_LIMITED) { - sys_limitrejected++; - code = "RATE"; - } else if (mask & RES_DONTTRUST) { - sys_restricted++; - code = "DENY"; - } - - /* - * Here we light up a kiss-of-death packet. Note the - * rate limit on these packets. Once a second initialize - * a bucket counter. Every packet sent decrements the - * counter until reaching zero. If the counter is zero, - * drop the kod. - */ - if (sys_kod == 0 || !(mask & RES_DEMOBILIZE)) - return; - - sys_kod--; - memcpy(&xpkt.refid, code, 4); - xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, - PKT_VERSION(rpkt->li_vn_mode), xmode); - xpkt.stratum = STRATUM_UNSPEC; - } else { - xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, - PKT_VERSION(rpkt->li_vn_mode), xmode); - 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)); - HTONL_FP(&sys_reftime, &xpkt.reftime); - xpkt.org = rpkt->xmt; - HTONL_FP(&rbufp->recv_time, &xpkt.rec); - - /* - * 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); - HTONL_FP(&xmt_ts, &xpkt.xmt); - sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, - sendlen); -#ifdef DEBUG - if (debug) - printf("transmit: at %ld %s->%s mode %d\n", - current_time, stoa(&rbufp->dstadr->sin), - stoa(&rbufp->recv_srcadr), xmode); -#endif - 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 OPENSSL - if (xkeyid > NTP_MAXKEY) { - keyid_t cookie; - - /* - * 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. - */ - cookie = session_key(&rbufp->recv_srcadr, - &rbufp->dstadr->sin, 0, sys_private, 0); - if (rbufp->recv_length >= (int)(sendlen + MAX_MAC_LEN + 2 * - sizeof(u_int32))) { - session_key(&rbufp->dstadr->sin, - &rbufp->recv_srcadr, xkeyid, 0, 2); - temp32 = CRYPTO_RESP; - rpkt->exten[0] |= htonl(temp32); - sendlen += crypto_xmit(&xpkt, - &rbufp->recv_srcadr, sendlen, - (struct exten *)rpkt->exten, cookie); - } else { - session_key(&rbufp->dstadr->sin, - &rbufp->recv_srcadr, xkeyid, cookie, 2); - } - } -#endif /* OPENSSL */ - get_systime(&xmt_ts); - L_ADD(&xmt_ts, &sys_authdelay); - HTONL_FP(&xmt_ts, &xpkt.xmt); - authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); - sendlen += authlen; -#ifdef OPENSSL - if (xkeyid > NTP_MAXKEY) - authtrust(xkeyid, 0); -#endif /* OPENSSL */ - get_systime(&xmt_tx); - if (sendlen > sizeof(xpkt)) { - msyslog(LOG_ERR, "buffer overflow %u", sendlen); - exit (-1); - } - 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 %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, authlen); -#endif -} - - -#ifdef OPENSSL -/* - * key_expire - purge the key list - */ -void -key_expire( - struct peer *peer /* peer structure pointer */ - ) -{ - int i; - - if (peer->keylist != NULL) { - for (i = 0; i <= peer->keynumber; i++) - authtrust(peer->keylist[i], 0); - free(peer->keylist); - peer->keylist = NULL; - } - value_free(&peer->sndval); - peer->keynumber = 0; -#ifdef DEBUG - if (debug) - printf("key_expire: at %lu\n", current_time); -#endif -} -#endif /* OPENSSL */ - - -/* - * Determine if the peer is unfit for synchronization - * - * A peer is unfit for synchronization if - * > not reachable - * > a synchronization loop would form - * > never been synchronized - * > stratum undefined or too high - * > too long without synchronization - * > designated noselect - */ -static int /* 0 if no, 1 if yes */ -peer_unfit( - struct peer *peer /* peer structure pointer */ - ) -{ - return (!peer->reach || (peer->stratum > 1 && peer->refid == - peer->dstadr->addr_refid) || peer->leap == LEAP_NOTINSYNC || - peer->stratum >= STRATUM_UNSPEC || root_distance(peer) >= - MAXDISTANCE + 2. * clock_phi * ULOGTOD(sys_poll) || - peer->flags & FLAG_NOSELECT ); -} - - -/* - * Find the precision of this particular machine - */ -#define MINSTEP 100e-9 /* minimum clock increment (s) */ -#define MAXSTEP 20e-3 /* maximum clock increment (s) */ -#define MINLOOPS 5 /* minimum number of step samples */ - -/* - * This routine calculates the system precision, defined as the minimum - * of a sequency of differences between successive readings of the - * system clock. However, if the system clock can be read more than once - * during a tick interval, the difference can be zero or one LSB unit, - * where the LSB corresponds to one nanosecond or one microsecond. - * Conceivably, if some other process preempts this one and reads the - * clock, the difference can be more than one LSB unit. - * - * For hardware clock frequencies of 10 MHz or less, we assume the - * logical clock advances only at the hardware clock tick. For higher - * frequencies, we assume the logical clock can advance no more than 100 - * nanoseconds between ticks. - */ -int -default_get_precision(void) -{ - l_fp val; /* current seconds fraction */ - l_fp last; /* last seconds fraction */ - l_fp diff; /* difference */ - double tick; /* computed tick value */ - double dtemp; /* scratch */ - int i; /* log2 precision */ - - /* - * Loop to find tick value in nanoseconds. Toss out outlyer - * values less than the minimun tick value. In wacky cases, use - * the default maximum value. - */ - get_systime(&last); - tick = MAXSTEP; - for (i = 0; i < MINLOOPS;) { - get_systime(&val); - diff = val; - L_SUB(&diff, &last); - last = val; - LFPTOD(&diff, dtemp); - if (dtemp < MINSTEP) - continue; - i++; - if (dtemp < tick) - tick = dtemp; - } - - /* - * Find the nearest power of two. - */ - NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, "precision = %.3f usec", tick * 1e6); - for (i = 0; tick <= 1; i++) - tick *= 2; - if (tick - 1. > 1. - tick / 2) - i--; - return (-i); -} - - -/* - * kod_proto - called once per second to limit kiss-of-death packets - */ -void -kod_proto(void) -{ - sys_kod = sys_kod_rate; -} - - -/* - * init_proto - initialize the protocol module's data - */ -void -init_proto(void) -{ - l_fp dummy; - int i; - - /* - * Fill in the sys_* stuff. Default is don't listen to - * broadcasting, authenticate. - */ - sys_leap = LEAP_NOTINSYNC; - sys_stratum = STRATUM_UNSPEC; - memcpy(&sys_refid, "INIT", 4); - sys_precision = (s_char)default_get_precision(); - sys_jitter = LOGTOD(sys_precision); - sys_rootdelay = 0; - sys_rootdispersion = 0; - L_CLR(&sys_reftime); - sys_peer = NULL; - sys_survivors = 0; - get_systime(&dummy); - sys_manycastserver = 0; - sys_bclient = 0; - sys_bdelay = DEFBROADDELAY; - sys_calldelay = BURST_DELAY; - sys_authenticate = 1; - L_CLR(&sys_authdelay); - sys_authdly[0] = sys_authdly[1] = 0; - sys_stattime = 0; - proto_clr_stats(); - for (i = 0; i < MAX_TTL; i++) { - sys_ttl[i] = (u_char)((i * 256) / MAX_TTL); - sys_ttlmax = i; - } -#ifdef OPENSSL - sys_automax = 1 << NTP_AUTOMAX; -#endif /* OPENSSL */ - - /* - * Default these to enable - */ - ntp_enable = 1; -#ifndef KERNEL_FLL_BUG - kern_enable = 1; -#endif - pps_enable = 0; - stats_control = 1; -} - - -/* - * proto_config - configure the protocol module - */ -void -proto_config( - int item, - u_long value, - double dvalue, - struct sockaddr_storage* svalue - ) -{ - /* - * Figure out what he wants to change, then do it - */ - switch (item) { - - /* - * Turn on/off kernel discipline. - */ - case PROTO_KERNEL: - kern_enable = (int)value; - break; - - /* - * Turn on/off clock discipline. - */ - case PROTO_NTP: - ntp_enable = (int)value; - break; - - /* - * Turn on/off monitoring. - */ - case PROTO_MONITOR: - if (value) - mon_start(MON_ON); - else - mon_stop(MON_ON); - break; - - /* - * Turn on/off statistics. - */ - case PROTO_FILEGEN: - stats_control = (int)value; - break; - - /* - * Turn on/off facility to listen to broadcasts. - */ - case PROTO_BROADCLIENT: - sys_bclient = (int)value; - if (value) - io_setbclient(); - else - io_unsetbclient(); - break; - - /* - * Add muliticast group address. - */ - case PROTO_MULTICAST_ADD: - if (svalue) - io_multicast_add(*svalue); - break; - - /* - * Delete multicast group address. - */ - case PROTO_MULTICAST_DEL: - if (svalue) - io_multicast_del(*svalue); - break; - - /* - * Set default broadcast delay. - */ - case PROTO_BROADDELAY: - sys_bdelay = dvalue; - break; - - /* - * Set modem call delay. - */ - case PROTO_CALLDELAY: - sys_calldelay = (int)value; - break; - - /* - * Require authentication to mobilize ephemeral associations. - */ - case PROTO_AUTHENTICATE: - sys_authenticate = (int)value; - break; - - /* - * Turn on/off PPS discipline. - */ - case PROTO_PPS: - pps_enable = (int)value; - break; - - /* - * Set the minimum number of survivors. - */ - case PROTO_MINCLOCK: - sys_minclock = (int)dvalue; - break; - - /* - * Set the minimum number of candidates. - */ - case PROTO_MINSANE: - sys_minsane = (int)dvalue; - break; - - /* - * Set the stratum floor. - */ - case PROTO_FLOOR: - sys_floor = (int)dvalue; - break; - - /* - * Set the stratum ceiling. - */ - case PROTO_CEILING: - sys_ceiling = (int)dvalue; - break; - - /* - * Set the cohort switch. - */ - case PROTO_COHORT: - sys_cohort= (int)dvalue; - break; - /* - * Set the adjtime() resolution (s). - */ - case PROTO_ADJ: - sys_tick = dvalue; - break; - -#ifdef REFCLOCK - /* - * Turn on/off refclock calibrate - */ - case PROTO_CAL: - cal_enable = (int)value; - break; -#endif - default: - - /* - * Log this error. - */ - msyslog(LOG_INFO, - "proto_config: illegal item %d, value %ld", - item, value); - } -} - - -/* - * proto_clr_stats - clear protocol stat counters - */ -void -proto_clr_stats(void) -{ - sys_stattime = current_time; - sys_received = 0; - sys_processed = 0; - sys_newversionpkt = 0; - sys_oldversionpkt = 0; - sys_unknownversion = 0; - sys_restricted = 0; - sys_badlength = 0; - sys_badauth = 0; - sys_limitrejected = 0; -} diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c deleted file mode 100644 index 172fbda..0000000 --- a/contrib/ntp/ntpd/ntp_refclock.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* - * ntp_refclock - processing support for reference clocks - */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#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> -# endif -#endif /* TTYCLK */ - -#ifdef HAVE_PPSCLOCK_H -#include <sys/ppsclock.h> -#endif /* HAVE_PPSCLOCK_H */ - -#ifdef KERNEL_PLL -#include "ntp_syscall.h" -#endif /* KERNEL_PLL */ - -/* - * Reference clock support is provided here by maintaining the fiction - * that the clock is actually a peer. As no packets are exchanged with a - * reference clock, however, we replace the transmit, receive and packet - * procedures with separate code to simulate them. Routines - * refclock_transmit() and refclock_receive() maintain the peer - * variables in a state analogous to an actual peer and pass reference - * clock data on through the filters. Routines refclock_peer() and - * refclock_unpeer() are called to initialize and terminate reference - * clock associations. A set of utility routines is included to open - * serial devices, process sample data, edit input lines to extract - * embedded timestamps and to peform various debugging functions. - * - * The main interface used by these routines is the refclockproc - * structure, which contains for most drivers the decimal equivalants of - * the year, day, month, hour, second and millisecond/microsecond - * decoded from the ASCII timecode. Additional information includes the - * receive timestamp, exception report, statistics tallies, etc. In - * addition, there may be a driver-specific unit structure used for - * local control of the device. - * - * The support routines are passed a pointer to the peer structure, - * which is used for all peer-specific processing and contains a pointer - * to the refclockproc structure, which in turn containes a pointer to - * the unit structure, if used. The peer structure is identified by an - * interface address in the dotted quad form 127.127.t.u (for now only IPv4 - * addresses are used, so we need to be sure the address is it), where t is - * the clock type and u the unit. Some legacy drivers derive the - * refclockproc structure pointer from the table typeunit[type][unit]. - * This interface is strongly discouraged and may be abandoned in - * future. - */ -#define MAXUNIT 4 /* max units */ -#define FUDGEFAC .1 /* fudge correction factor */ - -int fdpps; /* pps file descriptor */ -int cal_enable; /* enable refclock calibrate */ - -/* - * Type/unit peer index. Used to find the peer structure for control and - * debugging. When all clock drivers have been converted to new style, - * this dissapears. - */ -static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT]; - -/* - * Forward declarations - */ -#ifdef QSORT_USES_VOID_P -static int refclock_cmpl_fp P((const void *, const void *)); -#else -static int refclock_cmpl_fp P((const double *, const double *)); -#endif /* QSORT_USES_VOID_P */ -static int refclock_sample P((struct refclockproc *)); - -/* - * refclock_report - note the occurance of an event - * - * This routine presently just remembers the report and logs it, but - * does nothing heroic for the trap handler. It tries to be a good - * citizen and bothers the system log only if things change. - */ -void -refclock_report( - struct peer *peer, - int code - ) -{ - struct refclockproc *pp; - - pp = peer->procptr; - if (pp == NULL) - return; - if (code == CEVNT_BADREPLY) - pp->badformat++; - if (code == CEVNT_BADTIME) - pp->baddata++; - if (code == CEVNT_TIMEOUT) - pp->noreply++; - if (pp->currentstatus != code) { - pp->currentstatus = (u_char)code; - pp->lastevent = (u_char)code; - if (code == CEVNT_FAULT) - msyslog(LOG_ERR, - "clock %s event '%s' (0x%02x)", - refnumtoa(&peer->srcadr), - ceventstr(code), code); - else { - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_INFO, - "clock %s event '%s' (0x%02x)", - refnumtoa(&peer->srcadr), - ceventstr(code), code); - } - } -#ifdef DEBUG - if (debug) - printf("clock %s event '%s' (0x%02x)\n", - refnumtoa(&peer->srcadr), - ceventstr(code), code); -#endif -} - - -/* - * init_refclock - initialize the reference clock drivers - * - * This routine calls each of the drivers in turn to initialize internal - * variables, if necessary. Most drivers have nothing to say at this - * point. - */ -void -init_refclock(void) -{ - int i, j; - - for (i = 0; i < (int)num_refclock_conf; i++) { - if (refclock_conf[i]->clock_init != noentry) - (refclock_conf[i]->clock_init)(); - for (j = 0; j < MAXUNIT; j++) - typeunit[i][j] = 0; - } -} - - -/* - * refclock_newpeer - initialize and start a reference clock - * - * This routine allocates and initializes the interface structure which - * supports a reference clock in the form of an ordinary NTP peer. A - * driver-specific support routine completes the initialization, if - * used. Default peer variables which identify the clock and establish - * its reference ID and stratum are set here. It returns one if success - * and zero if the clock address is invalid or already running, - * insufficient resources are available or the driver declares a bum - * rap. - */ -int -refclock_newpeer( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - u_char clktype; - int unit; - - /* - * Check for valid clock address. If already running, shut it - * down first. - */ - if (peer->srcadr.ss_family != AF_INET) { - msyslog(LOG_ERR, - "refclock_newpeer: clock address %s invalid, address family not implemented for refclock", - stoa(&peer->srcadr)); - return (0); - } - if (!ISREFCLOCKADR(&peer->srcadr)) { - msyslog(LOG_ERR, - "refclock_newpeer: clock address %s invalid", - stoa(&peer->srcadr)); - return (0); - } - clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); - unit = REFCLOCKUNIT(&peer->srcadr); - if (clktype >= num_refclock_conf || unit >= MAXUNIT || - refclock_conf[clktype]->clock_start == noentry) { - msyslog(LOG_ERR, - "refclock_newpeer: clock type %d invalid\n", - clktype); - return (0); - } - - /* - * Allocate and initialize interface structure - */ - pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)); - if (pp == NULL) - return (0); - memset((char *)pp, 0, sizeof(struct refclockproc)); - typeunit[clktype][unit] = peer; - peer->procptr = pp; - - /* - * Initialize structures - */ - peer->refclktype = clktype; - peer->refclkunit = (u_char)unit; - peer->flags |= FLAG_REFCLOCK; - peer->maxpoll = peer->minpoll; - peer->stratum = STRATUM_REFCLOCK; - pp->type = clktype; - pp->timestarted = current_time; - - /* - * Set peer.pmode based on the hmode. For appearances only. - */ - switch (peer->hmode) { - case MODE_ACTIVE: - peer->pmode = MODE_PASSIVE; - break; - - default: - peer->pmode = MODE_SERVER; - break; - } - - /* - * Do driver dependent initialization. The above defaults - * can be wiggled, then finish up for consistency. - */ - if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { - refclock_unpeer(peer); - return (0); - } - peer->hpoll = peer->minpoll; - peer->ppoll = peer->maxpoll; - peer->refid = pp->refid; - return (1); -} - - -/* - * refclock_unpeer - shut down a clock - */ -void -refclock_unpeer( - struct peer *peer /* peer structure pointer */ - ) -{ - u_char clktype; - int unit; - - /* - * Wiggle the driver to release its resources, then give back - * the interface structure. - */ - if (!peer->procptr) - return; - clktype = peer->refclktype; - unit = peer->refclkunit; - if (refclock_conf[clktype]->clock_shutdown != noentry) - (refclock_conf[clktype]->clock_shutdown)(unit, peer); - free(peer->procptr); - peer->procptr = 0; -} - - -/* - * refclock_transmit - simulate the transmit procedure - * - * This routine implements the NTP transmit procedure for a reference - * clock. This provides a mechanism to call the driver at the NTP poll - * interval, as well as provides a reachability mechanism to detect a - * broken radio or other madness. - */ -void -refclock_transmit( - struct peer *peer /* peer structure pointer */ - ) -{ - u_char clktype; - int unit; - u_long next; - - clktype = peer->refclktype; - unit = peer->refclkunit; - peer->sent++; - - /* - * This is a ripoff of the peer transmit routine, but - * specialized for reference clocks. We do a little less - * protocol here and call the driver-specific transmit routine. - */ - next = peer->outdate; - if (peer->burst == 0) { - u_char oreach; -#ifdef DEBUG - if (debug) - printf("refclock_transmit: at %ld %s\n", - current_time, stoa(&(peer->srcadr))); -#endif - - /* - * Update reachability and poll variables like the - * network code. - */ - oreach = peer->reach; - peer->reach <<= 1; - if (!peer->reach) { - if (oreach) { - report_event(EVNT_UNREACH, peer); - peer->timereachable = current_time; - peer_clear(peer, "NONE"); - } - } else { - if (!(oreach & 0x03)) { - clock_filter(peer, 0., 0., MAXDISPERSE); - clock_select(); - } - if (peer->flags & FLAG_BURST) - peer->burst = NSTAGE; - } - next = current_time; - } - get_systime(&peer->xmt); - if (refclock_conf[clktype]->clock_poll != noentry) - (refclock_conf[clktype]->clock_poll)(unit, peer); - peer->outdate = next; - if (peer->burst > 0) - peer->burst--; - poll_update(peer, 0); -} - - -/* - * Compare two doubles - used with qsort() - */ -#ifdef QSORT_USES_VOID_P -static int -refclock_cmpl_fp( - const void *p1, - const void *p2 - ) -{ - const double *dp1 = (const double *)p1; - const double *dp2 = (const double *)p2; - - if (*dp1 < *dp2) - return (-1); - if (*dp1 > *dp2) - return (1); - return (0); -} -#else -static int -refclock_cmpl_fp( - const double *dp1, - const double *dp2 - ) -{ - if (*dp1 < *dp2) - return (-1); - if (*dp1 > *dp2) - return (1); - return (0); -} -#endif /* QSORT_USES_VOID_P */ - - -/* - * 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. - */ -void -refclock_process_offset( - struct refclockproc *pp, /* refclock structure pointer */ - l_fp lasttim, /* last timecode timestamp */ - l_fp lastrec, /* last receive timestamp */ - double fudge - ) -{ - l_fp lftemp; - double doffset; - - pp->lastrec = lastrec; - lftemp = lasttim; - L_SUB(&lftemp, &lastrec); - LFPTOD(&lftemp, doffset); - SAMPLE(doffset + fudge); -} - -/* - * refclock_process - process a sample from the clock - * - * This routine converts the timecode in the form days, hours, minutes, - * seconds and milliseconds/microseconds to internal timestamp format, - * then constructs a new entry in the median filter circular buffer. - * Return success (1) if the data are correct and consistent with the - * converntional calendar. -*/ -int -refclock_process( - struct refclockproc *pp /* refclock structure pointer */ - ) -{ - l_fp offset, ltemp; - - /* - * Compute the timecode timestamp from the days, hours, minutes, - * seconds and milliseconds/microseconds of the timecode. Use - * clocktime() for the aggregate seconds and the msec/usec for - * the fraction, when present. Note that this code relies on the - * filesystem time for the years and does not use the years of - * the timecode. - */ - if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, - pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) - return (0); - offset.l_uf = 0; - DTOLFP(pp->nsec / 1e9, <emp); - L_ADD(&offset, <emp); - refclock_process_offset(pp, offset, pp->lastrec, - pp->fudgetime1); - return (1); -} - -/* - * refclock_sample - process a pile of samples from the clock - * - * 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 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 /* refclock structure pointer */ - ) -{ - int i, j, k, m, n; - double offset; - double off[MAXSTAGE]; - - /* - * Copy the raw offsets and sort into ascending order. Don't do - * anything if the buffer is empty. - */ - n = 0; - while (pp->codeproc != pp->coderecv) { - pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; - off[n] = pp->filter[pp->codeproc]; - n++; - } - if (n == 0) - return (0); - if (n > 1) - qsort((char *)off, (size_t)n, sizeof(double), refclock_cmpl_fp); - - /* - * Reject the furthest from the median of the samples until - * approximately 60 percent of the samples remain. - */ - i = 0; j = n; - 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 */ - else - j--; /* reject high end */ - } - - /* - * Determine the offset and jitter. - */ - 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 jitter %.6f\n", - n, pp->offset, pp->disp, SQRT(pp->jitter)); -#endif - return (n); -} - - -/* - * refclock_receive - simulate the receive and packet procedures - * - * This routine simulates the NTP receive and packet procedures for a - * reference clock. This provides a mechanism in which the ordinary NTP - * filter, selection and combining algorithms can be used to suppress - * misbehaving radios and to mitigate between them when more than one is - * available for backup. - */ -void -refclock_receive( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - -#ifdef DEBUG - if (debug) - printf("refclock_receive: at %lu %s\n", - current_time, stoa(&peer->srcadr)); -#endif - - /* - * Do a little sanity dance and update the peer structure. Groom - * the median filter samples and give the data to the clock - * filter. - */ - peer->received++; - pp = peer->procptr; - peer->processed++; - peer->timereceived = current_time; - peer->leap = pp->leap; - if (peer->leap == LEAP_NOTINSYNC) { - refclock_report(peer, CEVNT_FAULT); - return; - } - if (!peer->reach) - report_event(EVNT_REACH, peer); - peer->reach |= 1; - peer->reftime = pp->lastref; - peer->org = pp->lastrec; - peer->rootdispersion = pp->disp; - get_systime(&peer->rec); - if (!refclock_sample(pp)) - return; - 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->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; - } -} - -/* - * refclock_gtlin - groom next input line and extract timestamp - * - * This routine processes the timecode received from the clock and - * removes the parity bit and control characters. If a timestamp is - * present in the timecode, as produced by the tty_clk STREAMS module, - * it returns that as the timestamp; otherwise, it returns the buffer - * timestamp. The routine return code is the number of characters in - * the line. - */ -int -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 */ - ) -{ - char *dpt, *dpend, *dp; - int i; - l_fp trtmp, tstmp; - char c; - - /* - * Check for the presence of a timestamp left by the tty_clock - * module and, if present, use that instead of the buffer - * timestamp captured by the I/O routines. We recognize a - * timestamp by noting its value is earlier than the buffer - * timestamp, but not more than one second earlier. - */ - dpt = (char *)rbufp->recv_buffer; - dpend = dpt + rbufp->recv_length; - trtmp = rbufp->recv_time; - - if (dpend >= dpt + 8) { - if (buftvtots(dpend - 8, &tstmp)) { - L_SUB(&trtmp, &tstmp); - if (trtmp.l_ui == 0) { -#ifdef DEBUG - if (debug > 1) { - printf( - "refclock_gtlin: fd %d ldisc %s", - rbufp->fd, lfptoa(&trtmp, 6)); - get_systime(&trtmp); - L_SUB(&trtmp, &tstmp); - printf(" sigio %s\n", lfptoa(&trtmp, 6)); - } -#endif - dpend -= 8; - trtmp = tstmp; - } else - trtmp = rbufp->recv_time; - } - } - - /* - * Edit timecode to remove control chars. Don't monkey with the - * line buffer if the input buffer contains no ASCII printing - * characters. - */ - if (dpend - dpt > bmax - 1) - dpend = dpt + bmax - 1; - for (dp = lineptr; dpt < dpend; dpt++) { - c = (char) (*dpt & 0x7f); - if (c >= ' ') - *dp++ = c; - } - i = dp - lineptr; - if (i > 0) - *dp = '\0'; -#ifdef DEBUG - if (debug > 1) { - if (i > 0) - printf("refclock_gtlin: fd %d time %s timecode %d %s\n", - rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); - else - printf("refclock_gtlin: fd %d time %s\n", - rbufp->fd, ulfptoa(&trtmp, 6)); - } -#endif - *tsptr = trtmp; - return (i); -} - -/* - * The following code does not apply to WINNT & VMS ... - */ -#if !defined SYS_VXWORKS && !defined SYS_WINNT -#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) - -/* - * refclock_open - open serial port for reference clock - * - * This routine opens a serial port for I/O and sets default options. It - * returns the file descriptor if success and zero if failure. - */ -int -refclock_open( - char *dev, /* device name pointer */ - int speed, /* serial port speed (code) */ - int lflags /* line discipline flags */ - ) -{ - int fd, i; - int flags; - TTY ttyb, *ttyp; -#ifdef TIOCMGET - u_long ltemp; -#endif /* TIOCMGET */ - int omode; - - /* - * Open serial port and set default options - */ - flags = lflags; - - omode = O_RDWR; -#ifdef O_NONBLOCK - 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 - * and kill functions are normally disabled. There is a - * different section for each terminal interface, as selected at - * compile time. - */ - ttyp = &ttyb; - -#ifdef HAVE_TERMIOS - /* - * POSIX serial line parameters (termios interface) - */ - if (tcgetattr(fd, ttyp) < 0) { - msyslog(LOG_ERR, - "refclock_open: fd %d tcgetattr: %m", fd); - return (0); - } - - /* - * Set canonical mode and local connection; set specified speed, - * 8 bits and no parity; map CR to NL; ignore break. - */ - ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; - ttyp->c_oflag = 0; - ttyp->c_cflag = CS8 | CLOCAL | CREAD; - (void)cfsetispeed(&ttyb, (u_int)speed); - (void)cfsetospeed(&ttyb, (u_int)speed); - ttyp->c_lflag = ICANON; - for (i = 0; i < NCCS; ++i) - { - ttyp->c_cc[i] = '\0'; - } - - /* - * Some special cases - */ - if (flags & LDISC_RAW) { - ttyp->c_iflag = 0; - ttyp->c_lflag = 0; - ttyp->c_cc[VMIN] = 1; - } -#if defined(TIOCMGET) && !defined(SCO5_CLOCK) - /* - * If we have modem control, check to see if modem leads are - * active; if so, set remote connection. This is necessary for - * the kernel pps mods to work. - */ - ltemp = 0; - if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) - msyslog(LOG_ERR, - "refclock_open: fd %d TIOCMGET failed: %m", fd); -#ifdef DEBUG - if (debug) - printf("refclock_open: fd %d modem status 0x%lx\n", - fd, ltemp); -#endif - if (ltemp & TIOCM_DSR) - ttyp->c_cflag &= ~CLOCAL; -#endif /* TIOCMGET */ - if (tcsetattr(fd, TCSANOW, ttyp) < 0) { - msyslog(LOG_ERR, - "refclock_open: fd %d TCSANOW failed: %m", fd); - return (0); - } - if (tcflush(fd, TCIOFLUSH) < 0) { - msyslog(LOG_ERR, - "refclock_open: fd %d TCIOFLUSH failed: %m", fd); - return (0); - } -#endif /* HAVE_TERMIOS */ - -#ifdef HAVE_SYSV_TTYS - - /* - * System V serial line parameters (termio interface) - * - */ - if (ioctl(fd, TCGETA, ttyp) < 0) { - msyslog(LOG_ERR, - "refclock_open: fd %d TCGETA failed: %m", fd); - return (0); - } - - /* - * Set canonical mode and local connection; set specified speed, - * 8 bits and no parity; map CR to NL; ignore break. - */ - ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; - ttyp->c_oflag = 0; - ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; - ttyp->c_lflag = ICANON; - ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; - - /* - * Some special cases - */ - if (flags & LDISC_RAW) { - ttyp->c_iflag = 0; - ttyp->c_lflag = 0; - } -#ifdef TIOCMGET - /* - * If we have modem control, check to see if modem leads are - * active; if so, set remote connection. This is necessary for - * the kernel pps mods to work. - */ - ltemp = 0; - if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) - msyslog(LOG_ERR, - "refclock_open: fd %d TIOCMGET failed: %m", fd); -#ifdef DEBUG - if (debug) - printf("refclock_open: fd %d modem status %lx\n", - fd, ltemp); -#endif - if (ltemp & TIOCM_DSR) - ttyp->c_cflag &= ~CLOCAL; -#endif /* TIOCMGET */ - if (ioctl(fd, TCSETA, ttyp) < 0) { - msyslog(LOG_ERR, - "refclock_open: fd %d TCSETA failed: %m", fd); - return (0); - } -#endif /* HAVE_SYSV_TTYS */ - -#ifdef HAVE_BSD_TTYS - - /* - * 4.3bsd serial line parameters (sgttyb interface) - */ - if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { - msyslog(LOG_ERR, - "refclock_open: fd %d TIOCGETP %m", fd); - return (0); - } - ttyp->sg_ispeed = ttyp->sg_ospeed = speed; - ttyp->sg_flags = EVENP | ODDP | CRMOD; - if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { - msyslog(LOG_ERR, - "refclock_open: TIOCSETP failed: %m"); - return (0); - } -#endif /* HAVE_BSD_TTYS */ - if (!refclock_ioctl(fd, flags)) { - (void)close(fd); - msyslog(LOG_ERR, - "refclock_open: fd %d ioctl failed: %m", fd); - return (0); - } - return (fd); -} -#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ -#endif /* SYS_VXWORKS SYS_WINNT */ - -/* - * refclock_ioctl - set serial port control functions - * - * This routine attempts to hide the internal, system-specific details - * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD - * (sgtty) interfaces with varying degrees of success. The routine sets - * up optional features such as tty_clk. The routine returns 1 if - * success and 0 if failure. - */ -int -refclock_ioctl( - int fd, /* file descriptor */ - int flags /* line discipline flags */ - ) -{ - /* simply return 1 if no UNIX line discipline is supported */ -#if !defined SYS_VXWORKS && !defined SYS_WINNT -#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) - -#ifdef TTYCLK - TTY ttyb, *ttyp; -#endif /* TTYCLK */ - -#ifdef DEBUG - if (debug) - printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags); -#endif - if (flags == 0) - return (1); -#if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS)) - if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) { - msyslog(LOG_ERR, - "refclock_ioctl: unsupported terminal interface"); - return (0); - } -#endif /* HAVE_TERMIOS HAVE_BSD_TTYS */ -#ifdef TTYCLK - ttyp = &ttyb; -#endif /* TTYCLK */ - - /* - * The following features may or may not require System V - * STREAMS support, depending on the particular implementation. - */ -#if defined(TTYCLK) - /* - * The TTYCLK option provides timestamping at the driver level. - * It requires the tty_clk streams module and System V STREAMS - * support. If not available, don't complain. - */ - if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) { - int rval = 0; - - if (ioctl(fd, I_PUSH, "clk") < 0) { - msyslog(LOG_NOTICE, - "refclock_ioctl: I_PUSH clk failed: %m"); - } else { - char *str; - - if (flags & LDISC_CLKPPS) - str = "\377"; - else if (flags & LDISC_ACTS) - str = "*"; - else - str = "\n"; -#ifdef CLK_SETSTR - if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0) - msyslog(LOG_ERR, - "refclock_ioctl: CLK_SETSTR failed: %m"); - if (debug) - printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n", - fd, rval, str); -#endif - } - } -#endif /* TTYCLK */ -#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ -#endif /* SYS_VXWORKS SYS_WINNT */ - return (1); -} - -/* - * refclock_control - set and/or return clock values - * - * This routine is used mainly for debugging. It returns designated - * values from the interface structure that can be displayed using - * ntpdc and the clockstat command. It can also be used to initialize - * configuration variables, such as fudgetimes, fudgevalues, reference - * ID and stratum. - */ -void -refclock_control( - struct sockaddr_storage *srcadr, - struct refclockstat *in, - struct refclockstat *out - ) -{ - struct peer *peer; - struct refclockproc *pp; - u_char clktype; - int unit; - - /* - * Check for valid address and running peer - */ - if (srcadr->ss_family != AF_INET) - return; - if (!ISREFCLOCKADR(srcadr)) - return; - clktype = (u_char)REFCLOCKTYPE(srcadr); - unit = REFCLOCKUNIT(srcadr); - if (clktype >= num_refclock_conf || unit >= MAXUNIT) - return; - peer = typeunit[clktype][unit]; - if (peer == NULL) - return; - if (peer->procptr == NULL) - return; - pp = peer->procptr; - - /* - * Initialize requested data - */ - if (in != 0) { - if (in->haveflags & CLK_HAVETIME1) - pp->fudgetime1 = in->fudgetime1; - if (in->haveflags & CLK_HAVETIME2) - pp->fudgetime2 = in->fudgetime2; - if (in->haveflags & CLK_HAVEVAL1) - pp->stratum = (u_char) in->fudgeval1; - if (in->haveflags & CLK_HAVEVAL2) - pp->refid = in->fudgeval2; - peer->stratum = pp->stratum; - if (peer->stratum == STRATUM_REFCLOCK || peer->stratum == - STRATUM_UNSPEC) - peer->refid = pp->refid; - else - peer->refid = ((struct - sockaddr_in*)&peer->srcadr)->sin_addr.s_addr; - if (in->haveflags & CLK_HAVEFLAG1) { - pp->sloppyclockflag &= ~CLK_FLAG1; - pp->sloppyclockflag |= in->flags & CLK_FLAG1; - } - if (in->haveflags & CLK_HAVEFLAG2) { - pp->sloppyclockflag &= ~CLK_FLAG2; - pp->sloppyclockflag |= in->flags & CLK_FLAG2; - } - if (in->haveflags & CLK_HAVEFLAG3) { - pp->sloppyclockflag &= ~CLK_FLAG3; - pp->sloppyclockflag |= in->flags & CLK_FLAG3; - } - if (in->haveflags & CLK_HAVEFLAG4) { - pp->sloppyclockflag &= ~CLK_FLAG4; - pp->sloppyclockflag |= in->flags & CLK_FLAG4; - } - } - - /* - * Readback requested data - */ - if (out != 0) { - out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | - CLK_HAVEVAL2 | CLK_HAVEFLAG4; - out->fudgetime1 = pp->fudgetime1; - out->fudgetime2 = pp->fudgetime2; - out->fudgeval1 = pp->stratum; - out->fudgeval2 = pp->refid; - out->flags = (u_char) pp->sloppyclockflag; - - out->timereset = current_time - pp->timestarted; - out->polls = pp->polls; - out->noresponse = pp->noreply; - out->badformat = pp->badformat; - out->baddata = pp->baddata; - - out->lastevent = pp->lastevent; - out->currentstatus = pp->currentstatus; - out->type = pp->type; - out->clockdesc = pp->clockdesc; - out->lencode = pp->lencode; - out->p_lastcode = pp->a_lastcode; - } - - /* - * Give the stuff to the clock - */ - if (refclock_conf[clktype]->clock_control != noentry) - (refclock_conf[clktype]->clock_control)(unit, in, out, peer); -} - - -/* - * refclock_buginfo - return debugging info - * - * This routine is used mainly for debugging. It returns designated - * values from the interface structure that can be displayed using - * ntpdc and the clkbug command. - */ -void -refclock_buginfo( - struct sockaddr_storage *srcadr, /* clock address */ - struct refclockbug *bug /* output structure */ - ) -{ - struct peer *peer; - struct refclockproc *pp; - u_char clktype; - int unit; - int i; - - /* - * Check for valid address and peer structure - */ - if (srcadr->ss_family != AF_INET) - return; - if (!ISREFCLOCKADR(srcadr)) - return; - clktype = (u_char) REFCLOCKTYPE(srcadr); - unit = REFCLOCKUNIT(srcadr); - if (clktype >= num_refclock_conf || unit >= MAXUNIT) - return; - peer = typeunit[clktype][unit]; - if (peer == NULL) - return; - pp = peer->procptr; - - /* - * Copy structure values - */ - bug->nvalues = 8; - bug->svalues = 0x0000003f; - bug->values[0] = pp->year; - bug->values[1] = pp->day; - bug->values[2] = pp->hour; - bug->values[3] = pp->minute; - bug->values[4] = pp->second; - bug->values[5] = pp->nsec; - bug->values[6] = pp->yearstart; - bug->values[7] = pp->coderecv; - bug->stimes = 0xfffffffc; - bug->times[0] = pp->lastref; - bug->times[1] = pp->lastrec; - for (i = 2; i < (int)bug->ntimes; i++) - DTOLFP(pp->filter[i - 2], &bug->times[i]); - - /* - * Give the stuff to the clock - */ - if (refclock_conf[clktype]->clock_buginfo != noentry) - (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); -} - -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c deleted file mode 100644 index eacba28..0000000 --- a/contrib/ntp/ntpd/ntp_request.c +++ /dev/null @@ -1,2756 +0,0 @@ -/* - * ntp_request.c - respond to information requests - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_request.h" -#include "ntp_control.h" -#include "ntp_refclock.h" -#include "ntp_if.h" -#include "ntp_stdlib.h" - -#include <stdio.h> -#include <stddef.h> -#include <signal.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include "recvbuff.h" - -#ifdef KERNEL_PLL -#include "ntp_syscall.h" -#endif /* KERNEL_PLL */ - -/* - * Structure to hold request procedure information - */ -#define NOAUTH 0 -#define AUTH 1 - -#define NO_REQUEST (-1) -/* - * Because we now have v6 addresses in the messages, we need to compensate - * for the larger size. Therefore, we introduce the alternate size to - * keep us friendly with older implementations. A little ugly. - */ -static int client_v6_capable = 0; /* the client can handle longer messages */ - -#define v6sizeof(type) (client_v6_capable ? sizeof(type) : v4sizeof(type)) - -struct req_proc { - short request_code; /* defined request code */ - short needs_auth; /* true when authentication needed */ - short sizeofitem; /* size of request data item (older size)*/ - short v6_sizeofitem; /* size of request data item (new size)*/ - void (*handler) P((struct sockaddr_storage *, struct interface *, - struct req_pkt *)); /* routine to handle request */ -}; - -/* - * Universal request codes - */ -static struct req_proc univ_codes[] = { - { NO_REQUEST, NOAUTH, 0, 0 } -}; - -static void req_ack P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int)); -static char * prepare_pkt P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_int)); -static char * more_pkt P((void)); -static void flush_pkt P((void)); -static void peer_list P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void peer_list_sum P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void peer_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void peer_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void sys_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void sys_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void mem_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void io_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void timer_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void loop_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_conf P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_unconf P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void set_sys_flag P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void clr_sys_flag P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void setclr_flags P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long)); -static void list_restrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_resaddflags P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_ressubflags P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_unrestrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_restrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int)); -static void mon_getlist_0 P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void mon_getlist_1 P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void reset_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void reset_peer P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_key_reread P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void trust_key P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void untrust_key P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_trustkey P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long)); -static void get_auth_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void reset_auth_stats P((void)); -static void req_get_traps P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void req_set_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void req_clr_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void do_setclr_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int)); -static void set_request_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void set_control_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void get_ctl_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -#ifdef KERNEL_PLL -static void get_kernel_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -#endif /* KERNEL_PLL */ -#ifdef REFCLOCK -static void get_clock_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -static void set_clock_fudge P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -#endif /* REFCLOCK */ -#ifdef REFCLOCK -static void get_clkbug_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); -#endif /* REFCLOCK */ - -/* - * ntpd request codes - */ -static struct req_proc ntp_codes[] = { - { REQ_PEER_LIST, NOAUTH, 0, 0, peer_list }, - { REQ_PEER_LIST_SUM, NOAUTH, 0, 0, peer_list_sum }, - { REQ_PEER_INFO, NOAUTH, v4sizeof(struct info_peer_list), - sizeof(struct info_peer_list), peer_info}, - { REQ_PEER_STATS, NOAUTH, v4sizeof(struct info_peer_list), - sizeof(struct info_peer_list), peer_stats}, - { REQ_SYS_INFO, NOAUTH, 0, 0, sys_info }, - { REQ_SYS_STATS, NOAUTH, 0, 0, sys_stats }, - { REQ_IO_STATS, NOAUTH, 0, 0, io_stats }, - { REQ_MEM_STATS, NOAUTH, 0, 0, mem_stats }, - { REQ_LOOP_INFO, NOAUTH, 0, 0, loop_info }, - { REQ_TIMER_STATS, NOAUTH, 0, 0, timer_stats }, - { REQ_CONFIG, AUTH, v4sizeof(struct conf_peer), - sizeof(struct conf_peer), do_conf }, - { REQ_UNCONFIG, AUTH, v4sizeof(struct conf_unpeer), - sizeof(struct conf_unpeer), do_unconf }, - { REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), - sizeof(struct conf_sys_flags), set_sys_flag }, - { REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), - sizeof(struct conf_sys_flags), clr_sys_flag }, - { REQ_GET_RESTRICT, NOAUTH, 0, 0, list_restrict }, - { REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict), - sizeof(struct conf_restrict), do_resaddflags }, - { REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict), - sizeof(struct conf_restrict), do_ressubflags }, - { REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict), - sizeof(struct conf_restrict), do_unrestrict }, - { REQ_MON_GETLIST, NOAUTH, 0, 0, mon_getlist_0 }, - { REQ_MON_GETLIST_1, NOAUTH, 0, 0, mon_getlist_1 }, - { REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats }, - { REQ_RESET_PEER, AUTH, v4sizeof(struct conf_unpeer), - sizeof(struct conf_unpeer), reset_peer }, - { REQ_REREAD_KEYS, AUTH, 0, 0, do_key_reread }, - { REQ_TRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), trust_key }, - { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key }, - { REQ_AUTHINFO, NOAUTH, 0, 0, get_auth_info }, - { REQ_TRAPS, NOAUTH, 0, 0, req_get_traps }, - { REQ_ADD_TRAP, AUTH, v4sizeof(struct conf_trap), - sizeof(struct conf_trap), req_set_trap }, - { REQ_CLR_TRAP, AUTH, v4sizeof(struct conf_trap), - sizeof(struct conf_trap), req_clr_trap }, - { REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long), - set_request_keyid }, - { REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long), - set_control_keyid }, - { REQ_GET_CTLSTATS, NOAUTH, 0, 0, get_ctl_stats }, -#ifdef KERNEL_PLL - { REQ_GET_KERNEL, NOAUTH, 0, 0, get_kernel_info }, -#endif -#ifdef REFCLOCK - { REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), - get_clock_info }, - { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), - sizeof(struct conf_fudge), set_clock_fudge }, - { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), - get_clkbug_info }, -#endif - { NO_REQUEST, NOAUTH, 0, 0, 0 } -}; - - -/* - * Authentication keyid used to authenticate requests. Zero means we - * don't allow writing anything. - */ -keyid_t info_auth_keyid; - -/* - * Statistic counters to keep track of requests and responses. - */ -u_long numrequests; /* number of requests we've received */ -u_long numresppkts; /* number of resp packets sent with data */ - -u_long errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */ -/* by the error code */ - -/* - * A hack. To keep the authentication module clear of ntp-ism's, we - * include a time reset variable for its stats here. - */ -static u_long auth_timereset; - -/* - * 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 - * use the extra buffer and copy. - */ -static struct resp_pkt rpkt; -static int reqver; -static int seqno; -static int nitems; -static int itemsize; -static int databytes; -static char exbuf[RESP_DATA_SIZE]; -static int usingexbuf; -static struct sockaddr_storage *toaddr; -static struct interface *frominter; - -/* - * init_request - initialize request data - */ -void -init_request (void) -{ - int i; - - numrequests = 0; - numresppkts = 0; - auth_timereset = 0; - info_auth_keyid = 0; /* by default, can't do this */ - - for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++) - errorcounter[i] = 0; -} - - -/* - * req_ack - acknowledge request with no data - */ -static void -req_ack( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt, - int errcode - ) -{ - /* - * fill in the fields - */ - rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); - rpkt.auth_seq = AUTH_SEQ(0, 0); - rpkt.implementation = inpkt->implementation; - rpkt.request = inpkt->request; - rpkt.err_nitems = ERR_NITEMS(errcode, 0); - rpkt.mbz_itemsize = MBZ_ITEMSIZE(0); - - /* - * send packet and bump counters - */ - sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE); - errorcounter[errcode]++; -} - - -/* - * prepare_pkt - prepare response packet for transmission, return pointer - * to storage for data item. - */ -static char * -prepare_pkt( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *pkt, - u_int structsize - ) -{ -#ifdef DEBUG - if (debug > 3) - printf("request: preparing pkt\n"); -#endif - - /* - * Fill in the implementation, request and itemsize fields - * since these won't change. - */ - rpkt.implementation = pkt->implementation; - rpkt.request = pkt->request; - rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize); - - /* - * Compute the static data needed to carry on. - */ - toaddr = srcadr; - frominter = inter; - seqno = 0; - nitems = 0; - itemsize = structsize; - databytes = 0; - usingexbuf = 0; - - /* - * return the beginning of the packet buffer. - */ - return &rpkt.data[0]; -} - - -/* - * more_pkt - return a data pointer for a new item. - */ -static char * -more_pkt(void) -{ - /* - * If we were using the extra buffer, send the packet. - */ - if (usingexbuf) { -#ifdef DEBUG - if (debug > 2) - printf("request: sending pkt\n"); -#endif - rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver); - rpkt.auth_seq = AUTH_SEQ(0, seqno); - rpkt.err_nitems = htons((u_short)nitems); - sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, - RESP_HEADER_SIZE+databytes); - numresppkts++; - - /* - * Copy data out of exbuf into the packet. - */ - memmove(&rpkt.data[0], exbuf, (unsigned)itemsize); - seqno++; - databytes = 0; - nitems = 0; - usingexbuf = 0; - } - - databytes += itemsize; - nitems++; - if (databytes + itemsize <= RESP_DATA_SIZE) { -#ifdef DEBUG - if (debug > 3) - printf("request: giving him more data\n"); -#endif - /* - * More room in packet. Give him the - * next address. - */ - return &rpkt.data[databytes]; - } else { - /* - * No room in packet. Give him the extra - * buffer unless this was the last in the sequence. - */ -#ifdef DEBUG - if (debug > 3) - printf("request: into extra buffer\n"); -#endif - if (seqno == MAXSEQ) - return (char *)0; - else { - usingexbuf = 1; - return exbuf; - } - } -} - - -/* - * flush_pkt - we're done, return remaining information. - */ -static void -flush_pkt(void) -{ -#ifdef DEBUG - if (debug > 2) - printf("request: flushing packet, %d items\n", nitems); -#endif - /* - * Must send the last packet. If nothing in here and nothing - * has been sent, send an error saying no data to be found. - */ - if (seqno == 0 && nitems == 0) - req_ack(toaddr, frominter, (struct req_pkt *)&rpkt, - INFO_ERR_NODATA); - else { - rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); - rpkt.auth_seq = AUTH_SEQ(0, seqno); - rpkt.err_nitems = htons((u_short)nitems); - sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, - RESP_HEADER_SIZE+databytes); - numresppkts++; - } -} - - - -/* - * process_private - process private mode (7) packets - */ -void -process_private( - struct recvbuf *rbufp, - int mod_okay - ) -{ - struct req_pkt *inpkt; - struct req_pkt_tail *tailinpkt; - struct sockaddr_storage *srcadr; - struct interface *inter; - struct req_proc *proc; - int ec; - short temp_size; - - /* - * Initialize pointers, for convenience - */ - inpkt = (struct req_pkt *)&rbufp->recv_pkt; - srcadr = &rbufp->recv_srcadr; - inter = rbufp->dstadr; - -#ifdef DEBUG - if (debug > 2) - printf("process_private: impl %d req %d\n", - inpkt->implementation, inpkt->request); -#endif - - /* - * Do some sanity checks on the packet. Return a format - * error if it fails. - */ - 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_HDR) - ) { - msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test %d failed, pkt from %s", ec, stoa(srcadr)); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - reqver = INFO_VERSION(inpkt->rm_vn_mode); - - /* - * Get the appropriate procedure list to search. - */ - if (inpkt->implementation == IMPL_UNIV) - proc = univ_codes; - else if ((inpkt->implementation == IMPL_XNTPD) || - (inpkt->implementation == IMPL_XNTPD_OLD)) - proc = ntp_codes; - else { - req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL); - return; - } - - /* - * Search the list for the request codes. If it isn't one - * we know, return an error. - */ - while (proc->request_code != NO_REQUEST) { - if (proc->request_code == (short) inpkt->request) - break; - proc++; - } - if (proc->request_code == NO_REQUEST) { - req_ack(srcadr, inter, inpkt, INFO_ERR_REQ); - return; - } - -#ifdef DEBUG - if (debug > 3) - printf("found request in tables\n"); -#endif - - /* - * If we need data, check to see if we have some. If we - * don't, check to see that there is none (picky, picky). - */ - - /* This part is a bit tricky, we want to be sure that the size - * returned is either the old or the new size. We also can find - * out if the client can accept both types of messages this way. - * - * Handle the exception of REQ_CONFIG. It can have two data sizes. - */ - temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize); - if ((temp_size != proc->sizeofitem && - temp_size != proc->v6_sizeofitem) && - !(inpkt->implementation == IMPL_XNTPD && - inpkt->request == REQ_CONFIG && - temp_size == sizeof(struct old_conf_peer))) { - if (debug > 2) - printf("process_private: wrong item size, received %d, should be %d or %d\n", - temp_size, proc->sizeofitem, proc->v6_sizeofitem); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - if ((proc->sizeofitem != 0) && - ((temp_size * INFO_NITEMS(inpkt->err_nitems)) > - (rbufp->recv_length - REQ_LEN_HDR))) { - if (debug > 2) - printf("process_private: not enough data\n"); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - switch (inpkt->implementation) { - case IMPL_XNTPD: - client_v6_capable = 1; - break; - case IMPL_XNTPD_OLD: - client_v6_capable = 0; - break; - default: - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - /* - * If we need to authenticate, do so. Note that an - * authenticatable packet must include a mac field, must - * have used key info_auth_keyid and must have included - * a time stamp in the appropriate field. The time stamp - * must be within INFO_TS_MAXSKEW of the receive - * time stamp. - */ - if (proc->needs_auth && sys_authenticate) { - l_fp ftmp; - double dtemp; - - if (rbufp->recv_length < (int)((REQ_LEN_HDR + - (INFO_ITEMSIZE(inpkt->mbz_itemsize) * - INFO_NITEMS(inpkt->err_nitems)) - + sizeof(struct req_pkt_tail)))) { - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - } - tailinpkt = (struct req_pkt_tail *)((char *)&rbufp->recv_pkt + - rbufp->recv_length - sizeof(struct req_pkt_tail)); - - /* - * If this guy is restricted from doing this, don't let him - * If wrong key was used, or packet doesn't have mac, return. - */ - if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0 - || ntohl(tailinpkt->keyid) != info_auth_keyid) { -#ifdef DEBUG - if (debug > 4) - printf("failed auth %d info_auth_keyid %lu pkt keyid %lu\n", - INFO_IS_AUTH(inpkt->auth_seq), - (u_long)info_auth_keyid, - (u_long)ntohl(tailinpkt->keyid)); - msyslog(LOG_DEBUG, - "process_private: failed auth %d info_auth_keyid %lu pkt keyid %lu\n", - INFO_IS_AUTH(inpkt->auth_seq), - (u_long)info_auth_keyid, - (u_long)ntohl(tailinpkt->keyid)); -#endif - req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); - return; - } - if (rbufp->recv_length > REQ_LEN_MAC) { -#ifdef DEBUG - if (debug > 4) - printf("bad pkt length %d\n", - rbufp->recv_length); -#endif - msyslog(LOG_ERR, "process_private: bad pkt length %d", - rbufp->recv_length); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - if (!mod_okay || !authhavekey(info_auth_keyid)) { -#ifdef DEBUG - if (debug > 4) - printf("failed auth mod_okay %d\n", mod_okay); - msyslog(LOG_DEBUG, - "process_private: failed auth mod_okay %d\n", - mod_okay); -#endif - req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); - return; - } - - /* - * calculate absolute time difference between xmit time stamp - * and receive time stamp. If too large, too bad. - */ - NTOHL_FP(&tailinpkt->tstamp, &ftmp); - L_SUB(&ftmp, &rbufp->recv_time); - LFPTOD(&ftmp, dtemp); - if (fabs(dtemp) >= INFO_TS_MAXSKEW) { - /* - * He's a loser. Tell him. - */ -#ifdef DEBUG - if (debug > 4) - printf("xmit/rcv timestamp delta > INFO_TS_MAXSKEW\n"); -#endif - req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); - return; - } - - /* - * So far so good. See if decryption works out okay. - */ - if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt, - rbufp->recv_length - sizeof(struct req_pkt_tail) + - REQ_LEN_HDR, sizeof(struct req_pkt_tail) - REQ_LEN_HDR)) { -#ifdef DEBUG - if (debug > 4) - printf("authdecrypt failed\n"); -#endif - req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); - return; - } - } - -#ifdef DEBUG - if (debug > 3) - printf("process_private: all okay, into handler\n"); -#endif - - /* - * Packet is okay. Call the handler to send him data. - */ - (proc->handler)(srcadr, inter, inpkt); -} - - -/* - * peer_list - send a list of the peers - */ -static void -peer_list( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_peer_list *ip; - register struct peer *pp; - register int i; - register int skip = 0; - - ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_peer_list)); - for (i = 0; i < HASH_SIZE && ip != 0; i++) { - pp = peer_hash[i]; - while (pp != 0 && ip != 0) { - if (pp->srcadr.ss_family == AF_INET6) { - if (client_v6_capable) { - ip->addr6 = GET_INADDR6(pp->srcadr); - ip->v6_flag = 1; - skip = 0; - } else { - skip = 1; - break; - } - } else { - ip->addr = GET_INADDR(pp->srcadr); - if (client_v6_capable) - ip->v6_flag = 0; - skip = 0; - } - - if(!skip) { - ip->port = NSRCPORT(&pp->srcadr); - ip->hmode = pp->hmode; - ip->flags = 0; - if (pp->flags & FLAG_CONFIG) - ip->flags |= INFO_FLAG_CONFIG; - if (pp == sys_peer) - ip->flags |= INFO_FLAG_SYSPEER; - if (pp->status == CTL_PST_SEL_SYNCCAND) - ip->flags |= INFO_FLAG_SEL_CANDIDATE; - if (pp->status >= CTL_PST_SEL_SYSPEER) - ip->flags |= INFO_FLAG_SHORTLIST; - ip = (struct info_peer_list *)more_pkt(); - } - pp = pp->next; - } - } - flush_pkt(); -} - - -/* - * peer_list_sum - return extended peer list - */ -static void -peer_list_sum( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_peer_summary *ips; - register struct peer *pp; - register int i; - l_fp ltmp; - register int skip; - -#ifdef DEBUG - if (debug > 2) - printf("wants peer list summary\n"); -#endif - ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_peer_summary)); - for (i = 0; i < HASH_SIZE && ips != 0; i++) { - pp = peer_hash[i]; - while (pp != 0 && ips != 0) { -#ifdef DEBUG - if (debug > 3) - printf("sum: got one\n"); -#endif - /* - * Be careful here not to return v6 peers when we - * want only v4. - */ - if (pp->srcadr.ss_family == AF_INET6) { - if (client_v6_capable) { - ips->srcadr6 = GET_INADDR6(pp->srcadr); - ips->v6_flag = 1; - ips->dstadr6 = GET_INADDR6(pp->dstadr->sin); - skip = 0; - } else { - skip = 1; - break; - } - } else { - ips->srcadr = GET_INADDR(pp->srcadr); - if (client_v6_capable) - ips->v6_flag = 0; -/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */ - ips->dstadr = (pp->processed) ? - pp->cast_flags == MDF_BCAST ? - GET_INADDR(pp->dstadr->bcast): - pp->cast_flags ? - GET_INADDR(pp->dstadr->sin) ? - GET_INADDR(pp->dstadr->sin): - GET_INADDR(pp->dstadr->bcast): - 1 : GET_INADDR(pp->dstadr->sin); - - skip = 0; - } - if (!skip){ - ips->srcport = NSRCPORT(&pp->srcadr); - ips->stratum = pp->stratum; - ips->hpoll = pp->hpoll; - ips->ppoll = pp->ppoll; - ips->reach = pp->reach; - ips->flags = 0; - if (pp == sys_peer) - ips->flags |= INFO_FLAG_SYSPEER; - if (pp->flags & FLAG_CONFIG) - ips->flags |= INFO_FLAG_CONFIG; - if (pp->flags & FLAG_REFCLOCK) - ips->flags |= INFO_FLAG_REFCLOCK; - if (pp->flags & FLAG_AUTHENABLE) - ips->flags |= INFO_FLAG_AUTHENABLE; - if (pp->flags & FLAG_PREFER) - ips->flags |= INFO_FLAG_PREFER; - if (pp->flags & FLAG_BURST) - ips->flags |= INFO_FLAG_BURST; - if (pp->status == CTL_PST_SEL_SYNCCAND) - ips->flags |= INFO_FLAG_SEL_CANDIDATE; - if (pp->status >= CTL_PST_SEL_SYSPEER) - ips->flags |= INFO_FLAG_SHORTLIST; - ips->hmode = pp->hmode; - ips->delay = HTONS_FP(DTOFP(pp->delay)); - DTOLFP(pp->offset, <mp); - HTONL_FP(<mp, &ips->offset); - ips->dispersion = HTONS_FP(DTOUFP(pp->disp)); - } - pp = pp->next; - ips = (struct info_peer_summary *)more_pkt(); - } - } - flush_pkt(); -} - - -/* - * peer_info - send information for one or more peers - */ -static void -peer_info ( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_peer_list *ipl; - register struct peer *pp; - register struct info_peer *ip; - register int items; - register int i, j; - struct sockaddr_storage addr; - extern struct peer *sys_peer; - l_fp ltmp; - - memset((char *)&addr, 0, sizeof addr); - items = INFO_NITEMS(inpkt->err_nitems); - ipl = (struct info_peer_list *) inpkt->data; - - ip = (struct info_peer *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_peer)); - while (items-- > 0 && ip != 0) { - memset((char *)&addr, 0, sizeof(addr)); - NSRCPORT(&addr) = ipl->port; - if (client_v6_capable && ipl->v6_flag != 0) { - addr.ss_family = AF_INET6; - GET_INADDR6(addr) = ipl->addr6; - } else { - addr.ss_family = AF_INET; - GET_INADDR(addr) = ipl->addr; - } -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - addr.ss_len = SOCKLEN(&addr); -#endif - ipl++; - if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0) - continue; - if (pp->srcadr.ss_family == AF_INET6) { - ip->dstadr6 = pp->cast_flags == MDF_BCAST ? - GET_INADDR6(pp->dstadr->bcast) : - GET_INADDR6(pp->dstadr->sin); - ip->srcadr6 = GET_INADDR6(pp->srcadr); - ip->v6_flag = 1; - } else { -/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */ - ip->dstadr = (pp->processed) ? - pp->cast_flags == MDF_BCAST ? - GET_INADDR(pp->dstadr->bcast): - pp->cast_flags ? - GET_INADDR(pp->dstadr->sin) ? - GET_INADDR(pp->dstadr->sin): - GET_INADDR(pp->dstadr->bcast): - 2 : GET_INADDR(pp->dstadr->sin); - - ip->srcadr = GET_INADDR(pp->srcadr); - if (client_v6_capable) - ip->v6_flag = 0; - } - ip->srcport = NSRCPORT(&pp->srcadr); - ip->flags = 0; - if (pp == sys_peer) - ip->flags |= INFO_FLAG_SYSPEER; - if (pp->flags & FLAG_CONFIG) - ip->flags |= INFO_FLAG_CONFIG; - if (pp->flags & FLAG_REFCLOCK) - ip->flags |= INFO_FLAG_REFCLOCK; - if (pp->flags & FLAG_AUTHENABLE) - ip->flags |= INFO_FLAG_AUTHENABLE; - if (pp->flags & FLAG_PREFER) - ip->flags |= INFO_FLAG_PREFER; - if (pp->flags & FLAG_BURST) - ip->flags |= INFO_FLAG_BURST; - if (pp->status == CTL_PST_SEL_SYNCCAND) - ip->flags |= INFO_FLAG_SEL_CANDIDATE; - if (pp->status >= CTL_PST_SEL_SYSPEER) - ip->flags |= INFO_FLAG_SHORTLIST; - ip->leap = pp->leap; - ip->hmode = pp->hmode; - ip->keyid = pp->keyid; - ip->stratum = pp->stratum; - ip->ppoll = pp->ppoll; - ip->hpoll = pp->hpoll; - ip->precision = pp->precision; - ip->version = pp->version; - ip->reach = pp->reach; - ip->unreach = (u_char) pp->unreach; - ip->flash = (u_char)pp->flash; - ip->flash2 = (u_short) pp->flash; - ip->estbdelay = HTONS_FP(DTOFP(pp->estbdelay)); - ip->ttl = pp->ttl; - ip->associd = htons(pp->associd); - ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay)); - ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdispersion)); - ip->refid = pp->refid; - HTONL_FP(&pp->reftime, &ip->reftime); - HTONL_FP(&pp->org, &ip->org); - HTONL_FP(&pp->rec, &ip->rec); - HTONL_FP(&pp->xmt, &ip->xmt); - j = pp->filter_nextpt - 1; - for (i = 0; i < NTP_SHIFT; i++, j--) { - if (j < 0) - j = NTP_SHIFT-1; - ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j])); - DTOLFP(pp->filter_offset[j], <mp); - HTONL_FP(<mp, &ip->filtoffset[i]); - ip->order[i] = (u_char)((pp->filter_nextpt+NTP_SHIFT-1) - - pp->filter_order[i]); - if (ip->order[i] >= NTP_SHIFT) - ip->order[i] -= NTP_SHIFT; - } - DTOLFP(pp->offset, <mp); - 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->jitter))); - ip = (struct info_peer *)more_pkt(); - } - flush_pkt(); -} - - -/* - * peer_stats - send statistics for one or more peers - */ -static void -peer_stats ( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_peer_list *ipl; - register struct peer *pp; - register struct info_peer_stats *ip; - register int items; - struct sockaddr_storage addr; - extern struct peer *sys_peer; - - printf("peer_stats: called\n"); - items = INFO_NITEMS(inpkt->err_nitems); - ipl = (struct info_peer_list *) inpkt->data; - ip = (struct info_peer_stats *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_peer_stats)); - while (items-- > 0 && ip != 0) { - memset((char *)&addr, 0, sizeof(addr)); - NSRCPORT(&addr) = ipl->port; - if (client_v6_capable && ipl->v6_flag) { - addr.ss_family = AF_INET6; - GET_INADDR6(addr) = ipl->addr6; - } else { - addr.ss_family = AF_INET; - GET_INADDR(addr) = ipl->addr; - } -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - addr.ss_len = SOCKLEN(&addr); -#endif - printf("peer_stats: looking for %s, %d, %d\n", stoa(&addr), - ipl->port, ((struct sockaddr_in6 *)&addr)->sin6_port); - ipl = (struct info_peer_list *)((char *)ipl + - INFO_ITEMSIZE(inpkt->mbz_itemsize)); - - if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0) - continue; - printf("peer_stats: found %s\n", stoa(&addr)); - if (pp->srcadr.ss_family == AF_INET) { - ip->dstadr = (pp->processed) ? - pp->cast_flags == MDF_BCAST ? - GET_INADDR(pp->dstadr->bcast): - pp->cast_flags ? - GET_INADDR(pp->dstadr->sin) ? - GET_INADDR(pp->dstadr->sin): - GET_INADDR(pp->dstadr->bcast): - 3 : 7; - ip->srcadr = GET_INADDR(pp->srcadr); - if (client_v6_capable) - ip->v6_flag = 0; - } else { - ip->dstadr6 = pp->cast_flags == MDF_BCAST ? - GET_INADDR6(pp->dstadr->bcast): - GET_INADDR6(pp->dstadr->sin); - ip->srcadr6 = GET_INADDR6(pp->srcadr); - ip->v6_flag = 1; - } - ip->srcport = NSRCPORT(&pp->srcadr); - ip->flags = 0; - if (pp == sys_peer) - ip->flags |= INFO_FLAG_SYSPEER; - if (pp->flags & FLAG_CONFIG) - ip->flags |= INFO_FLAG_CONFIG; - if (pp->flags & FLAG_REFCLOCK) - ip->flags |= INFO_FLAG_REFCLOCK; - if (pp->flags & FLAG_AUTHENABLE) - ip->flags |= INFO_FLAG_AUTHENABLE; - if (pp->flags & FLAG_PREFER) - ip->flags |= INFO_FLAG_PREFER; - if (pp->flags & FLAG_BURST) - ip->flags |= INFO_FLAG_BURST; - if (pp->status == CTL_PST_SEL_SYNCCAND) - ip->flags |= INFO_FLAG_SEL_CANDIDATE; - if (pp->status >= CTL_PST_SEL_SYSPEER) - ip->flags |= INFO_FLAG_SHORTLIST; - ip->timereceived = htonl((u_int32)(current_time - pp->timereceived)); - ip->timetosend = htonl(pp->nextdate - current_time); - ip->timereachable = htonl((u_int32)(current_time - pp->timereachable)); - ip->sent = htonl((u_int32)(pp->sent)); - ip->processed = htonl((u_int32)(pp->processed)); - ip->badauth = htonl((u_int32)(pp->badauth)); - ip->bogusorg = htonl((u_int32)(pp->bogusorg)); - ip->oldpkt = htonl((u_int32)(pp->oldpkt)); - ip->seldisp = htonl((u_int32)(pp->seldisptoolarge)); - ip->selbroken = htonl((u_int32)(pp->selbroken)); - ip->candidate = pp->status; - ip = (struct info_peer_stats *)more_pkt(); - } - flush_pkt(); -} - - -/* - * sys_info - return system info - */ -static void -sys_info( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_sys *is; - - /* - * Importations from the protocol module - */ - extern u_char sys_leap; - extern u_char sys_stratum; - extern s_char sys_precision; - extern double sys_rootdelay; - extern double sys_rootdispersion; - extern u_int32 sys_refid; - extern l_fp sys_reftime; - extern u_char sys_poll; - extern struct peer *sys_peer; - extern int sys_bclient; - extern double sys_bdelay; - extern l_fp sys_authdelay; - extern double clock_stability; - extern double sys_jitter; - - is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_sys)); - - if (sys_peer != 0) { - if (sys_peer->srcadr.ss_family == AF_INET) { - is->peer = GET_INADDR(sys_peer->srcadr); - if (client_v6_capable) - is->v6_flag = 0; - } else if (client_v6_capable) { - is->peer6 = GET_INADDR6(sys_peer->srcadr); - is->v6_flag = 1; - } - is->peer_mode = sys_peer->hmode; - } else { - is->peer = 0; - if (client_v6_capable) { - is->v6_flag = 0; - } - is->peer_mode = 0; - } - - is->leap = sys_leap; - is->stratum = sys_stratum; - is->precision = sys_precision; - is->rootdelay = htonl(DTOFP(sys_rootdelay)); - is->rootdispersion = htonl(DTOUFP(sys_rootdispersion)); - is->frequency = htonl(DTOFP(sys_jitter)); - is->stability = htonl(DTOUFP(clock_stability * 1e6)); - is->refid = sys_refid; - HTONL_FP(&sys_reftime, &is->reftime); - - is->poll = sys_poll; - - is->flags = 0; - if (sys_authenticate) - is->flags |= INFO_FLAG_AUTHENTICATE; - if (sys_bclient) - is->flags |= INFO_FLAG_BCLIENT; -#ifdef REFCLOCK - if (cal_enable) - is->flags |= INFO_FLAG_CAL; -#endif /* REFCLOCK */ - if (kern_enable) - is->flags |= INFO_FLAG_KERNEL; - if (mon_enabled != MON_OFF) - is->flags |= INFO_FLAG_MONITOR; - if (ntp_enable) - is->flags |= INFO_FLAG_NTP; - if (pps_enable) - is->flags |= INFO_FLAG_PPS_SYNC; - if (stats_control) - is->flags |= INFO_FLAG_FILEGEN; - is->bdelay = HTONS_FP(DTOFP(sys_bdelay)); - HTONL_UF(sys_authdelay.l_f, &is->authdelay); - - (void) more_pkt(); - flush_pkt(); -} - - -/* - * sys_stats - return system statistics - */ -static void -sys_stats( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_sys_stats *ss; - - /* - * Importations from the protocol module - */ - ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_sys_stats)); - ss->timeup = htonl((u_int32)current_time); - ss->timereset = htonl((u_int32)(current_time - sys_stattime)); - ss->denied = htonl((u_int32)sys_restricted); - ss->oldversionpkt = htonl((u_int32)sys_oldversionpkt); - ss->newversionpkt = htonl((u_int32)sys_newversionpkt); - ss->unknownversion = htonl((u_int32)sys_unknownversion); - ss->badlength = htonl((u_int32)sys_badlength); - ss->processed = htonl((u_int32)sys_processed); - ss->badauth = htonl((u_int32)sys_badauth); - ss->limitrejected = htonl((u_int32)sys_limitrejected); - ss->received = htonl((u_int32)sys_received); - (void) more_pkt(); - flush_pkt(); -} - - -/* - * mem_stats - return memory statistics - */ -static void -mem_stats( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_mem_stats *ms; - register int i; - - /* - * Importations from the peer module - */ - extern int peer_hash_count[HASH_SIZE]; - extern int peer_free_count; - extern u_long peer_timereset; - extern u_long findpeer_calls; - extern u_long peer_allocations; - extern u_long peer_demobilizations; - extern int total_peer_structs; - - ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_mem_stats)); - - ms->timereset = htonl((u_int32)(current_time - peer_timereset)); - ms->totalpeermem = htons((u_short)total_peer_structs); - ms->freepeermem = htons((u_short)peer_free_count); - ms->findpeer_calls = htonl((u_int32)findpeer_calls); - ms->allocations = htonl((u_int32)peer_allocations); - ms->demobilizations = htonl((u_int32)peer_demobilizations); - - for (i = 0; i < HASH_SIZE; i++) { - if (peer_hash_count[i] > 255) - ms->hashcount[i] = 255; - else - ms->hashcount[i] = (u_char)peer_hash_count[i]; - } - - (void) more_pkt(); - flush_pkt(); -} - - -/* - * io_stats - return io statistics - */ -static void -io_stats( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_io_stats *io; - - /* - * Importations from the io module - */ - extern u_long io_timereset; - - io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_io_stats)); - - io->timereset = htonl((u_int32)(current_time - io_timereset)); - io->totalrecvbufs = htons((u_short) total_recvbuffs()); - io->freerecvbufs = htons((u_short) free_recvbuffs()); - io->fullrecvbufs = htons((u_short) full_recvbuffs()); - io->lowwater = htons((u_short) lowater_additions()); - io->dropped = htonl((u_int32)packets_dropped); - io->ignored = htonl((u_int32)packets_ignored); - io->received = htonl((u_int32)packets_received); - io->sent = htonl((u_int32)packets_sent); - io->notsent = htonl((u_int32)packets_notsent); - io->interrupts = htonl((u_int32)handler_calls); - io->int_received = htonl((u_int32)handler_pkts); - - (void) more_pkt(); - flush_pkt(); -} - - -/* - * timer_stats - return timer statistics - */ -static void -timer_stats( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_timer_stats *ts; - - /* - * Importations from the timer module - */ - extern u_long timer_timereset; - extern u_long timer_overflows; - extern u_long timer_xmtcalls; - - ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_timer_stats)); - - ts->timereset = htonl((u_int32)(current_time - timer_timereset)); - ts->alarms = htonl((u_int32)alarm_overflow); - ts->overflows = htonl((u_int32)timer_overflows); - ts->xmtcalls = htonl((u_int32)timer_xmtcalls); - - (void) more_pkt(); - flush_pkt(); -} - - -/* - * loop_info - return the current state of the loop filter - */ -static void -loop_info( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_loop *li; - l_fp ltmp; - - /* - * Importations from the loop filter module - */ - extern double last_offset; - extern double drift_comp; - extern int tc_counter; - extern u_long last_time; - - li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_loop)); - - DTOLFP(last_offset, <mp); - HTONL_FP(<mp, &li->last_offset); - DTOLFP(drift_comp * 1e6, <mp); - HTONL_FP(<mp, &li->drift_comp); - li->compliance = htonl((u_int32)(tc_counter)); - li->watchdog_timer = htonl((u_int32)(current_time - last_time)); - - (void) more_pkt(); - flush_pkt(); -} - - -/* - * do_conf - add a peer to the configuration list - */ -static void -do_conf( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - int items; - u_int fl; - struct conf_peer *cp; - struct conf_peer temp_cp; - struct sockaddr_storage peeraddr; - struct sockaddr_in tmp_clock; - - /* - * Do a check of everything to see that it looks - * okay. If not, complain about it. Note we are - * very picky here. - */ - items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_peer *)inpkt->data; - memset(&temp_cp, 0, sizeof(struct conf_peer)); - memcpy(&temp_cp, (char *)cp, INFO_ITEMSIZE(inpkt->mbz_itemsize)); - fl = 0; - while (items-- > 0 && !fl) { - if (((temp_cp.version) > NTP_VERSION) - || ((temp_cp.version) < NTP_OLDVERSION)) - fl = 1; - if (temp_cp.hmode != MODE_ACTIVE - && temp_cp.hmode != MODE_CLIENT - && temp_cp.hmode != MODE_BROADCAST) - fl = 1; - if (temp_cp.flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER - | CONF_FLAG_BURST | CONF_FLAG_SKEY)) - fl = 1; - cp = (struct conf_peer *) - ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - if (fl) { - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - /* - * Looks okay, try it out - */ - items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_peer *)inpkt->data; - - while (items-- > 0) { - memset(&temp_cp, 0, sizeof(struct conf_peer)); - memcpy(&temp_cp, (char *)cp, INFO_ITEMSIZE(inpkt->mbz_itemsize)); - memset((char *)&peeraddr, 0, sizeof(struct sockaddr_storage)); - - fl = 0; - if (temp_cp.flags & CONF_FLAG_AUTHENABLE) - fl |= FLAG_AUTHENABLE; - if (temp_cp.flags & CONF_FLAG_PREFER) - fl |= FLAG_PREFER; - if (temp_cp.flags & CONF_FLAG_BURST) - fl |= FLAG_BURST; - if (temp_cp.flags & CONF_FLAG_SKEY) - fl |= FLAG_SKEY; - if (client_v6_capable && temp_cp.v6_flag != 0) { - peeraddr.ss_family = AF_INET6; - GET_INADDR6(peeraddr) = temp_cp.peeraddr6; - } else { - peeraddr.ss_family = AF_INET; - GET_INADDR(peeraddr) = temp_cp.peeraddr; - /* - * Make sure the address is valid - */ - tmp_clock = *CAST_V4(peeraddr); - if ( -#ifdef REFCLOCK - !ISREFCLOCKADR(&tmp_clock) && -#endif - ISBADADR(&tmp_clock)) { - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - } - NSRCPORT(&peeraddr) = htons(NTP_PORT); -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - peeraddr.ss_len = SOCKLEN(&peeraddr); -#endif - - /* XXX W2DO? minpoll/maxpoll arguments ??? */ - if (peer_config(&peeraddr, (struct interface *)0, - temp_cp.hmode, temp_cp.version, temp_cp.minpoll, - temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid, - NULL) == 0) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - cp = (struct conf_peer *) - ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - -#if 0 -/* XXX */ -/* - * dns_a - Snarf DNS info for an association ID - */ -static void -dns_a( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_dns_assoc *dp; - register int items; - struct sockaddr_in peeraddr; - - /* - * Do a check of everything to see that it looks - * okay. If not, complain about it. Note we are - * very picky here. - */ - items = INFO_NITEMS(inpkt->err_nitems); - dp = (struct info_dns_assoc *)inpkt->data; - - /* - * Looks okay, try it out - */ - items = INFO_NITEMS(inpkt->err_nitems); - dp = (struct info_dns_assoc *)inpkt->data; - memset((char *)&peeraddr, 0, sizeof(struct sockaddr_in)); - peeraddr.sin_family = AF_INET; - peeraddr.sin_port = htons(NTP_PORT); - - /* - * Make sure the address is valid - */ - if ( -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - ISBADADR(&peeraddr)) { -#ifdef REFCLOCK - msyslog(LOG_ERR, "dns_a: !ISREFCLOCK && ISBADADR"); -#else - msyslog(LOG_ERR, "dns_a: ISBADADR"); -#endif - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - while (items-- > 0) { - associd_t associd; - size_t hnl; - struct peer *peer; - int bogon = 0; - - associd = dp->associd; - peer = findpeerbyassoc(associd); - if (peer == 0 || peer->flags & FLAG_REFCLOCK) { - msyslog(LOG_ERR, "dns_a: %s", - (peer == 0) - ? "peer == 0" - : "peer->flags & FLAG_REFCLOCK"); - ++bogon; - } - peeraddr.sin_addr.s_addr = dp->peeraddr; - for (hnl = 0; dp->hostname[hnl] && hnl < sizeof dp->hostname; ++hnl) ; - if (hnl >= sizeof dp->hostname) { - msyslog(LOG_ERR, "dns_a: hnl (%ld) >= %ld", - (long)hnl, (long)sizeof dp->hostname); - ++bogon; - } - - msyslog(LOG_INFO, "dns_a: <%s> for %s, AssocID %d, bogon %d", - dp->hostname, - stoa((struct sockaddr_storage *)&peeraddr), associd, - bogon); - - if (bogon) { - /* If it didn't work */ - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } else { -#if 0 -#ifdef PUBKEY - crypto_public(peer, dp->hostname); -#endif /* PUBKEY */ -#endif - } - - dp++; - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} -#endif /* 0 */ - -/* - * do_unconf - remove a peer from the configuration list - */ -static void -do_unconf( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct conf_unpeer *cp; - struct conf_unpeer temp_cp; - register int items; - register struct peer *peer; - struct sockaddr_storage peeraddr; - int bad, found; - - /* - * This is a bit unstructured, but I like to be careful. - * We check to see that every peer exists and is actually - * configured. If so, we remove them. If not, we return - * an error. - */ - items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_unpeer *)inpkt->data; - - bad = 0; - while (items-- > 0 && !bad) { - memset(&temp_cp, 0, sizeof(temp_cp)); - memset(&peeraddr, 0, sizeof(peeraddr)); - memcpy(&temp_cp, cp, INFO_ITEMSIZE(inpkt->mbz_itemsize)); - if (client_v6_capable && temp_cp.v6_flag != 0) { - peeraddr.ss_family = AF_INET6; - GET_INADDR6(peeraddr) = temp_cp.peeraddr6; - } else { - peeraddr.ss_family = AF_INET; - GET_INADDR(peeraddr) = temp_cp.peeraddr; - } - NSRCPORT(&peeraddr) = htons(NTP_PORT); -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - peeraddr.ss_len = SOCKLEN(&peeraddr); -#endif - found = 0; - peer = (struct peer *)0; - printf("searching for %s\n", stoa(&peeraddr)); - while (!found) { - peer = findexistingpeer(&peeraddr, peer, -1); - if (peer == (struct peer *)0) - break; - if (peer->flags & FLAG_CONFIG) - found = 1; - } - if (!found) - bad = 1; - cp = (struct conf_unpeer *) - ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - if (bad) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - /* - * Now do it in earnest. - */ - - items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_unpeer *)inpkt->data; - while (items-- > 0) { - memset(&temp_cp, 0, sizeof(temp_cp)); - memset(&peeraddr, 0, sizeof(peeraddr)); - memcpy(&temp_cp, cp, INFO_ITEMSIZE(inpkt->mbz_itemsize)); - if (client_v6_capable && temp_cp.v6_flag != 0) { - peeraddr.ss_family = AF_INET6; - GET_INADDR6(peeraddr) = temp_cp.peeraddr6; - } else { - peeraddr.ss_family = AF_INET; - GET_INADDR(peeraddr) = temp_cp.peeraddr; - } - NSRCPORT(&peeraddr) = htons(NTP_PORT); -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - peeraddr.ss_len = SOCKLEN(&peeraddr); -#endif - peer_unconfig(&peeraddr, (struct interface *)0, -1); - cp = (struct conf_unpeer *) - ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * set_sys_flag - set system flags - */ -static void -set_sys_flag( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - setclr_flags(srcadr, inter, inpkt, 1); -} - - -/* - * clr_sys_flag - clear system flags - */ -static void -clr_sys_flag( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - setclr_flags(srcadr, inter, inpkt, 0); -} - - -/* - * setclr_flags - do the grunge work of flag setting/clearing - */ -static void -setclr_flags( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt, - u_long set - ) -{ - 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_PPS | - SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR | - SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) { - msyslog(LOG_ERR, "setclr_flags: extra flags: %#x", - flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | - SYS_FLAG_NTP | SYS_FLAG_KERNEL | - SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN | - SYS_FLAG_AUTH | SYS_FLAG_CAL)); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - if (flags & SYS_FLAG_BCLIENT) - proto_config(PROTO_BROADCLIENT, set, 0., NULL); - if (flags & SYS_FLAG_PPS) - proto_config(PROTO_PPS, set, 0., NULL); - if (flags & SYS_FLAG_NTP) - proto_config(PROTO_NTP, set, 0., NULL); - if (flags & SYS_FLAG_KERNEL) - proto_config(PROTO_KERNEL, set, 0., NULL); - if (flags & SYS_FLAG_MONITOR) - proto_config(PROTO_MONITOR, set, 0., NULL); - if (flags & SYS_FLAG_FILEGEN) - proto_config(PROTO_FILEGEN, set, 0., NULL); - if (flags & SYS_FLAG_AUTH) - proto_config(PROTO_AUTHENTICATE, set, 0., NULL); - if (flags & SYS_FLAG_CAL) - proto_config(PROTO_CAL, set, 0., NULL); - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * list_restrict - return the restrict list - */ -static void -list_restrict( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_restrict *ir; - register struct restrictlist *rl; - register struct restrictlist6 *rl6; - -#ifdef DEBUG - if (debug > 2) - printf("wants restrict list summary\n"); -#endif - - ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_restrict)); - - for (rl = restrictlist; rl != 0 && ir != 0; rl = rl->next) { - ir->addr = htonl(rl->addr); - if (client_v6_capable) - ir->v6_flag = 0; - ir->mask = htonl(rl->mask); - ir->count = htonl((u_int32)rl->count); - ir->flags = htons(rl->flags); - ir->mflags = htons(rl->mflags); - ir = (struct info_restrict *)more_pkt(); - } - if (client_v6_capable) - for (rl6 = restrictlist6; rl6 != 0 && ir != 0; rl6 = rl6->next) { - ir->addr6 = rl6->addr6; - ir->mask6 = rl6->mask6; - ir->v6_flag = 1; - ir->count = htonl((u_int32)rl6->count); - ir->flags = htons(rl6->flags); - ir->mflags = htons(rl6->mflags); - ir = (struct info_restrict *)more_pkt(); - } - flush_pkt(); -} - - - -/* - * do_resaddflags - add flags to a restrict entry (or create one) - */ -static void -do_resaddflags( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_restrict(srcadr, inter, inpkt, RESTRICT_FLAGS); -} - - - -/* - * do_ressubflags - remove flags from a restrict entry - */ -static void -do_ressubflags( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_restrict(srcadr, inter, inpkt, RESTRICT_UNFLAG); -} - - -/* - * do_unrestrict - remove a restrict entry from the list - */ -static void -do_unrestrict( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_restrict(srcadr, inter, inpkt, RESTRICT_REMOVE); -} - - - - - -/* - * do_restrict - do the dirty stuff of dealing with restrictions - */ -static void -do_restrict( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt, - int op - ) -{ - register struct conf_restrict *cr; - register int items; - struct sockaddr_storage matchaddr; - struct sockaddr_storage matchmask; - int bad; - - /* - * Do a check of the flags to make sure that only - * the NTPPORT flag is set, if any. If not, complain - * about it. Note we are very picky here. - */ - items = INFO_NITEMS(inpkt->err_nitems); - cr = (struct conf_restrict *)inpkt->data; - - bad = 0; - while (items-- > 0 && !bad) { - if (cr->mflags & ~(RESM_NTPONLY)) - bad |= 1; - if (cr->flags & ~(RES_ALLFLAGS)) - bad |= 2; - if (cr->mask != htonl(INADDR_ANY)) { - if (client_v6_capable && cr->v6_flag != 0) { - if (IN6_IS_ADDR_UNSPECIFIED(&cr->addr6)) - bad |= 4; - } else - if (cr->addr == htonl(INADDR_ANY)) - bad |= 8; - } - cr = (struct conf_restrict *)((char *)cr + - INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - if (bad) { - msyslog(LOG_ERR, "do_restrict: bad = %#x", bad); - req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); - return; - } - - /* - * Looks okay, try it out - */ - items = INFO_NITEMS(inpkt->err_nitems); - cr = (struct conf_restrict *)inpkt->data; - memset((char *)&matchaddr, 0, sizeof(struct sockaddr_storage)); - memset((char *)&matchmask, 0, sizeof(struct sockaddr_storage)); - - while (items-- > 0) { - if (client_v6_capable && cr->v6_flag != 0) { - GET_INADDR6(matchaddr) = cr->addr6; - GET_INADDR6(matchmask) = cr->mask6; - matchaddr.ss_family = AF_INET6; - matchmask.ss_family = AF_INET6; - } else { - GET_INADDR(matchaddr) = cr->addr; - GET_INADDR(matchmask) = cr->mask; - matchaddr.ss_family = AF_INET; - matchmask.ss_family = AF_INET; - } - hack_restrict(op, &matchaddr, &matchmask, cr->mflags, - cr->flags); - cr++; - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * mon_getlist - return monitor data - */ -static void -mon_getlist_0( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_monitor *im; - register struct mon_data *md; - extern struct mon_data mon_mru_list; - extern int mon_enabled; - -#ifdef DEBUG - if (debug > 2) - printf("wants monitor 0 list\n"); -#endif - if (!mon_enabled) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_monitor)); - for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0; - md = md->mru_next) { - im->lasttime = htonl((u_int32)md->avg_interval); - im->firsttime = htonl((u_int32)(current_time - md->lasttime)); - im->lastdrop = htonl((u_int32)md->drop_count); - im->count = htonl((u_int32)(md->count)); - if (md->rmtadr.ss_family == AF_INET6) { - if (!client_v6_capable) - continue; - im->addr6 = GET_INADDR6(md->rmtadr); - im->v6_flag = 1; - } else { - im->addr = GET_INADDR(md->rmtadr); - if (client_v6_capable) - im->v6_flag = 0; - } - im->port = md->rmtport; - im->mode = md->mode; - im->version = md->version; - im = (struct info_monitor *)more_pkt(); - } - flush_pkt(); -} - -/* - * mon_getlist - return monitor data - */ -static void -mon_getlist_1( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_monitor_1 *im; - register struct mon_data *md; - extern struct mon_data mon_mru_list; - extern int mon_enabled; - - if (!mon_enabled) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_monitor_1)); - for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0; - md = md->mru_next) { - im->lasttime = htonl((u_int32)md->avg_interval); - im->firsttime = htonl((u_int32)(current_time - md->lasttime)); - im->lastdrop = htonl((u_int32)md->drop_count); - im->count = htonl((u_int32)md->count); - if (md->rmtadr.ss_family == AF_INET6) { - if (!client_v6_capable) - continue; - im->addr6 = GET_INADDR6(md->rmtadr); - im->v6_flag = 1; - im->daddr6 = GET_INADDR6(md->interface->sin); - } else { - im->addr = GET_INADDR(md->rmtadr); - if (client_v6_capable) - im->v6_flag = 0; - im->daddr = (md->cast_flags == MDF_BCAST) - ? GET_INADDR(md->interface->bcast) - : (md->cast_flags - ? (GET_INADDR(md->interface->sin) - ? GET_INADDR(md->interface->sin) - : GET_INADDR(md->interface->bcast)) - : 4); - } - im->flags = md->cast_flags; - im->port = md->rmtport; - im->mode = md->mode; - im->version = md->version; - im = (struct info_monitor_1 *)more_pkt(); - } - flush_pkt(); -} - -/* - * Module entry points and the flags they correspond with - */ -struct reset_entry { - int flag; /* flag this corresponds to */ - void (*handler) P((void)); /* routine to handle request */ -}; - -struct reset_entry reset_entries[] = { - { RESET_FLAG_ALLPEERS, peer_all_reset }, - { RESET_FLAG_IO, io_clr_stats }, - { RESET_FLAG_SYS, proto_clr_stats }, - { RESET_FLAG_MEM, peer_clr_stats }, - { RESET_FLAG_TIMER, timer_clr_stats }, - { RESET_FLAG_AUTH, reset_auth_stats }, - { RESET_FLAG_CTL, ctl_clr_stats }, - { 0, 0 } -}; - -/* - * reset_stats - reset statistic counters here and there - */ -static void -reset_stats( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - u_long flags; - 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; - } - - 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; - } - - for (rent = reset_entries; rent->flag != 0; rent++) { - if (flags & rent->flag) - (rent->handler)(); - } - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * reset_peer - clear a peer's statistics - */ -static void -reset_peer( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct conf_unpeer *cp; - register int items; - register struct peer *peer; - struct sockaddr_storage peeraddr; - int bad; - - /* - * We check first to see that every peer exists. If not, - * we return an error. - */ - - items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_unpeer *)inpkt->data; - - bad = 0; - while (items-- > 0 && !bad) { - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - if (client_v6_capable && cp->v6_flag != 0) { - GET_INADDR6(peeraddr) = cp->peeraddr6; - peeraddr.ss_family = AF_INET6; - } else { - GET_INADDR(peeraddr) = cp->peeraddr; - peeraddr.ss_family = AF_INET; - } - NSRCPORT(&peeraddr) = htons(NTP_PORT); -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - peeraddr.ss_len = SOCKLEN(&peeraddr); -#endif - peer = findexistingpeer(&peeraddr, (struct peer *)0, -1); - if (peer == (struct peer *)0) - bad++; - cp = (struct conf_unpeer *)((char *)cp + - INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - if (bad) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - /* - * Now do it in earnest. - */ - - items = INFO_NITEMS(inpkt->err_nitems); - cp = (struct conf_unpeer *)inpkt->data; - while (items-- > 0) { - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - if (client_v6_capable && cp->v6_flag != 0) { - GET_INADDR6(peeraddr) = cp->peeraddr6; - peeraddr.ss_family = AF_INET6; - } else { - GET_INADDR(peeraddr) = cp->peeraddr; - peeraddr.ss_family = AF_INET; - } -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - peeraddr.ss_len = SOCKLEN(&peeraddr); -#endif - peer = findexistingpeer(&peeraddr, (struct peer *)0, -1); - while (peer != 0) { - peer_reset(peer); - peer = findexistingpeer(&peeraddr, (struct peer *)peer, -1); - } - cp = (struct conf_unpeer *)((char *)cp + - INFO_ITEMSIZE(inpkt->mbz_itemsize)); - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * do_key_reread - reread the encryption key file - */ -static void -do_key_reread( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - rereadkeys(); - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * trust_key - make one or more keys trusted - */ -static void -trust_key( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_trustkey(srcadr, inter, inpkt, 1); -} - - -/* - * untrust_key - make one or more keys untrusted - */ -static void -untrust_key( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_trustkey(srcadr, inter, inpkt, 0); -} - - -/* - * do_trustkey - make keys either trustable or untrustable - */ -static void -do_trustkey( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt, - u_long trust - ) -{ - register u_long *kp; - register int items; - - items = INFO_NITEMS(inpkt->err_nitems); - kp = (u_long *)inpkt->data; - while (items-- > 0) { - authtrust(*kp, trust); - kp++; - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - -/* - * get_auth_info - return some stats concerning the authentication module - */ -static void -get_auth_info( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_auth *ia; - - /* - * Importations from the authentication module - */ - extern u_long authnumkeys; - extern int authnumfreekeys; - extern u_long authkeylookups; - extern u_long authkeynotfound; - extern u_long authencryptions; - extern u_long authdecryptions; - extern u_long authkeyuncached; - extern u_long authkeyexpired; - - ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_auth)); - - ia->numkeys = htonl((u_int32)authnumkeys); - ia->numfreekeys = htonl((u_int32)authnumfreekeys); - ia->keylookups = htonl((u_int32)authkeylookups); - ia->keynotfound = htonl((u_int32)authkeynotfound); - ia->encryptions = htonl((u_int32)authencryptions); - ia->decryptions = htonl((u_int32)authdecryptions); - ia->keyuncached = htonl((u_int32)authkeyuncached); - ia->expired = htonl((u_int32)authkeyexpired); - ia->timereset = htonl((u_int32)(current_time - auth_timereset)); - - (void) more_pkt(); - flush_pkt(); -} - - - -/* - * reset_auth_stats - reset the authentication stat counters. Done here - * to keep ntp-isms out of the authentication module - */ -static void -reset_auth_stats(void) -{ - /* - * Importations from the authentication module - */ - extern u_long authkeylookups; - extern u_long authkeynotfound; - extern u_long authencryptions; - extern u_long authdecryptions; - extern u_long authkeyuncached; - - authkeylookups = 0; - authkeynotfound = 0; - authencryptions = 0; - authdecryptions = 0; - authkeyuncached = 0; - auth_timereset = current_time; -} - - -/* - * req_get_traps - return information about current trap holders - */ -static void -req_get_traps( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_trap *it; - register struct ctl_trap *tr; - register int i; - - /* - * Imported from the control module - */ - extern struct ctl_trap ctl_trap[]; - extern int num_ctl_traps; - - if (num_ctl_traps == 0) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt, - v6sizeof(struct info_trap)); - - for (i = 0, tr = ctl_trap; i < CTL_MAXTRAPS; i++, tr++) { - if (tr->tr_flags & TRAP_INUSE) { - if (tr->tr_addr.ss_family == AF_INET) { - if (tr->tr_localaddr == any_interface) - it->local_address = 0; - else - it->local_address - = GET_INADDR(tr->tr_localaddr->sin); - it->trap_address = GET_INADDR(tr->tr_addr); - if (client_v6_capable) - it->v6_flag = 0; - } else { - if (!client_v6_capable) - continue; - it->local_address6 - = GET_INADDR6(tr->tr_localaddr->sin); - it->trap_address6 = GET_INADDR6(tr->tr_addr); - it->v6_flag = 1; - } - it->trap_port = NSRCPORT(&tr->tr_addr); - it->sequence = htons(tr->tr_sequence); - it->settime = htonl((u_int32)(current_time - tr->tr_settime)); - it->origtime = htonl((u_int32)(current_time - tr->tr_origtime)); - it->resets = htonl((u_int32)tr->tr_resets); - it->flags = htonl((u_int32)tr->tr_flags); - it = (struct info_trap *)more_pkt(); - } - } - flush_pkt(); -} - - -/* - * req_set_trap - configure a trap - */ -static void -req_set_trap( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_setclr_trap(srcadr, inter, inpkt, 1); -} - - - -/* - * req_clr_trap - unconfigure a trap - */ -static void -req_clr_trap( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - do_setclr_trap(srcadr, inter, inpkt, 0); -} - - - -/* - * do_setclr_trap - do the grunge work of (un)configuring a trap - */ -static void -do_setclr_trap( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt, - int set - ) -{ - register struct conf_trap *ct; - register struct interface *linter; - int res; - struct sockaddr_storage laddr; - - /* - * Prepare sockaddr_storage structure - */ - memset((char *)&laddr, 0, sizeof laddr); - laddr.ss_family = srcadr->ss_family; - NSRCPORT(&laddr) = ntohs(NTP_PORT); - - /* - * Restrict ourselves to one item only. This eliminates - * 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; - } - ct = (struct conf_trap *)inpkt->data; - - /* - * Look for the local interface. If none, use the default. - */ - if (ct->local_address == 0) { - linter = any_interface; - } else { - if (laddr.ss_family == AF_INET) - GET_INADDR(laddr) = ct->local_address; - else - GET_INADDR6(laddr) = ct->local_address6; - linter = findinterface(&laddr); - if (linter == NULL) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - } - - if (laddr.ss_family == AF_INET) - GET_INADDR(laddr) = ct->trap_address; - else - GET_INADDR6(laddr) = ct->trap_address6; - if (ct->trap_port != 0) - NSRCPORT(&laddr) = ct->trap_port; - else - NSRCPORT(&laddr) = htons(TRAPPORT); - - if (set) { - res = ctlsettrap(&laddr, linter, 0, - INFO_VERSION(inpkt->rm_vn_mode)); - } else { - res = ctlclrtrap(&laddr, linter, 0); - } - - if (!res) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - } else { - req_ack(srcadr, inter, inpkt, INFO_OKAY); - } - return; -} - - - -/* - * set_request_keyid - set the keyid used to authenticate requests - */ -static void -set_request_keyid( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - 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; - } - - keyid = ntohl(*((u_int32 *)(inpkt->data))); - info_auth_keyid = keyid; - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - - -/* - * set_control_keyid - set the keyid used to authenticate requests - */ -static void -set_control_keyid( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - 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; - } - - keyid = ntohl(*((u_int32 *)(inpkt->data))); - ctl_auth_keyid = keyid; - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} - - - -/* - * get_ctl_stats - return some stats concerning the control message module - */ -static void -get_ctl_stats( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_control *ic; - - /* - * Importations from the control module - */ - extern u_long ctltimereset; - extern u_long numctlreq; - extern u_long numctlbadpkts; - extern u_long numctlresponses; - extern u_long numctlfrags; - extern u_long numctlerrors; - extern u_long numctltooshort; - extern u_long numctlinputresp; - extern u_long numctlinputfrag; - extern u_long numctlinputerr; - extern u_long numctlbadoffset; - extern u_long numctlbadversion; - extern u_long numctldatatooshort; - extern u_long numctlbadop; - extern u_long numasyncmsgs; - - ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_control)); - - ic->ctltimereset = htonl((u_int32)(current_time - ctltimereset)); - ic->numctlreq = htonl((u_int32)numctlreq); - ic->numctlbadpkts = htonl((u_int32)numctlbadpkts); - ic->numctlresponses = htonl((u_int32)numctlresponses); - ic->numctlfrags = htonl((u_int32)numctlfrags); - ic->numctlerrors = htonl((u_int32)numctlerrors); - ic->numctltooshort = htonl((u_int32)numctltooshort); - ic->numctlinputresp = htonl((u_int32)numctlinputresp); - ic->numctlinputfrag = htonl((u_int32)numctlinputfrag); - ic->numctlinputerr = htonl((u_int32)numctlinputerr); - ic->numctlbadoffset = htonl((u_int32)numctlbadoffset); - ic->numctlbadversion = htonl((u_int32)numctlbadversion); - ic->numctldatatooshort = htonl((u_int32)numctldatatooshort); - ic->numctlbadop = htonl((u_int32)numctlbadop); - ic->numasyncmsgs = htonl((u_int32)numasyncmsgs); - - (void) more_pkt(); - flush_pkt(); -} - - -#ifdef KERNEL_PLL -/* - * get_kernel_info - get kernel pll/pps information - */ -static void -get_kernel_info( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_kernel *ik; - struct timex ntx; - - if (!pll_control) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - memset((char *)&ntx, 0, sizeof(ntx)); - if (ntp_adjtime(&ntx) < 0) - msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m"); - ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_kernel)); - - /* - * pll variables - */ - ik->offset = htonl((u_int32)ntx.offset); - ik->freq = htonl((u_int32)ntx.freq); - ik->maxerror = htonl((u_int32)ntx.maxerror); - ik->esterror = htonl((u_int32)ntx.esterror); - ik->status = htons(ntx.status); - ik->constant = htonl((u_int32)ntx.constant); - ik->precision = htonl((u_int32)ntx.precision); - ik->tolerance = htonl((u_int32)ntx.tolerance); - - /* - * pps variables - */ - ik->ppsfreq = htonl((u_int32)ntx.ppsfreq); - ik->jitter = htonl((u_int32)ntx.jitter); - ik->shift = htons(ntx.shift); - ik->stabil = htonl((u_int32)ntx.stabil); - ik->jitcnt = htonl((u_int32)ntx.jitcnt); - ik->calcnt = htonl((u_int32)ntx.calcnt); - ik->errcnt = htonl((u_int32)ntx.errcnt); - ik->stbcnt = htonl((u_int32)ntx.stbcnt); - - (void) more_pkt(); - flush_pkt(); -} -#endif /* KERNEL_PLL */ - - -#ifdef REFCLOCK -/* - * get_clock_info - get info about a clock - */ -static void -get_clock_info( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct info_clock *ic; - register u_int32 *clkaddr; - register int items; - struct refclockstat clock_stat; - struct sockaddr_storage addr; - struct sockaddr_in tmp_clock; - l_fp ltmp; - - memset((char *)&addr, 0, sizeof addr); - addr.ss_family = AF_INET; -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - addr.ss_len = SOCKLEN(&addr); -#endif - NSRCPORT(&addr) = htons(NTP_PORT); - items = INFO_NITEMS(inpkt->err_nitems); - clkaddr = (u_int32 *) inpkt->data; - - ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_clock)); - - while (items-- > 0) { - tmp_clock.sin_addr.s_addr = *clkaddr++; - CAST_V4(addr)->sin_addr = tmp_clock.sin_addr; - if (!ISREFCLOCKADR(&tmp_clock) || - findexistingpeer(&addr, (struct peer *)0, -1) == 0) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - clock_stat.kv_list = (struct ctl_var *)0; - - refclock_control(&addr, (struct refclockstat *)0, &clock_stat); - - ic->clockadr = tmp_clock.sin_addr.s_addr; - ic->type = clock_stat.type; - ic->flags = clock_stat.flags; - ic->lastevent = clock_stat.lastevent; - ic->currentstatus = clock_stat.currentstatus; - ic->polls = htonl((u_int32)clock_stat.polls); - ic->noresponse = htonl((u_int32)clock_stat.noresponse); - ic->badformat = htonl((u_int32)clock_stat.badformat); - ic->baddata = htonl((u_int32)clock_stat.baddata); - ic->timestarted = htonl((u_int32)clock_stat.timereset); - DTOLFP(clock_stat.fudgetime1, <mp); - HTONL_FP(<mp, &ic->fudgetime1); - DTOLFP(clock_stat.fudgetime2, <mp); - HTONL_FP(<mp, &ic->fudgetime2); - ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1); - ic->fudgeval2 = htonl((u_int32)clock_stat.fudgeval2); - - free_varlist(clock_stat.kv_list); - - ic = (struct info_clock *)more_pkt(); - } - flush_pkt(); -} - - - -/* - * set_clock_fudge - get a clock's fudge factors - */ -static void -set_clock_fudge( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register struct conf_fudge *cf; - register int items; - struct refclockstat clock_stat; - struct sockaddr_storage addr; - struct sockaddr_in tmp_clock; - l_fp ltmp; - - memset((char *)&addr, 0, sizeof addr); - memset((char *)&clock_stat, 0, sizeof clock_stat); - items = INFO_NITEMS(inpkt->err_nitems); - cf = (struct conf_fudge *) inpkt->data; - - while (items-- > 0) { - tmp_clock.sin_addr.s_addr = cf->clockadr; - *CAST_V4(addr) = tmp_clock; - addr.ss_family = AF_INET; -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - addr.ss_len = SOCKLEN(&addr); -#endif - NSRCPORT(&addr) = htons(NTP_PORT); - if (!ISREFCLOCKADR(&tmp_clock) || - findexistingpeer(&addr, (struct peer *)0, -1) == 0) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - switch(ntohl(cf->which)) { - case FUDGE_TIME1: - NTOHL_FP(&cf->fudgetime, <mp); - LFPTOD(<mp, clock_stat.fudgetime1); - clock_stat.haveflags = CLK_HAVETIME1; - break; - case FUDGE_TIME2: - NTOHL_FP(&cf->fudgetime, <mp); - LFPTOD(<mp, clock_stat.fudgetime2); - clock_stat.haveflags = CLK_HAVETIME2; - break; - case FUDGE_VAL1: - clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags); - clock_stat.haveflags = CLK_HAVEVAL1; - break; - case FUDGE_VAL2: - clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags); - clock_stat.haveflags = CLK_HAVEVAL2; - break; - case FUDGE_FLAGS: - clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf); - clock_stat.haveflags = - (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; - } - - refclock_control(&addr, &clock_stat, (struct refclockstat *)0); - } - - req_ack(srcadr, inter, inpkt, INFO_OKAY); -} -#endif - -#ifdef REFCLOCK -/* - * get_clkbug_info - get debugging info about a clock - */ -static void -get_clkbug_info( - struct sockaddr_storage *srcadr, - struct interface *inter, - struct req_pkt *inpkt - ) -{ - register int i; - register struct info_clkbug *ic; - register u_int32 *clkaddr; - register int items; - struct refclockbug bug; - struct sockaddr_storage addr; - struct sockaddr_in tmp_clock; - - memset((char *)&addr, 0, sizeof addr); - addr.ss_family = AF_INET; -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - addr.ss_len = SOCKLEN(&addr); -#endif - NSRCPORT(&addr) = htons(NTP_PORT); - items = INFO_NITEMS(inpkt->err_nitems); - clkaddr = (u_int32 *) inpkt->data; - - ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt, - sizeof(struct info_clkbug)); - - while (items-- > 0) { - tmp_clock.sin_addr.s_addr = *clkaddr++; - GET_INADDR(addr) = tmp_clock.sin_addr.s_addr; - if (!ISREFCLOCKADR(&tmp_clock) || - findexistingpeer(&addr, (struct peer *)0, -1) == 0) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - memset((char *)&bug, 0, sizeof bug); - refclock_buginfo(&addr, &bug); - if (bug.nvalues == 0 && bug.ntimes == 0) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); - return; - } - - ic->clockadr = tmp_clock.sin_addr.s_addr; - i = bug.nvalues; - if (i > NUMCBUGVALUES) - i = NUMCBUGVALUES; - ic->nvalues = (u_char)i; - ic->svalues = htons((u_short) (bug.svalues & ((1<<i)-1))); - while (--i >= 0) - ic->values[i] = htonl(bug.values[i]); - - i = bug.ntimes; - if (i > NUMCBUGTIMES) - i = NUMCBUGTIMES; - ic->ntimes = (u_char)i; - ic->stimes = htonl(bug.stimes); - while (--i >= 0) { - HTONL_FP(&bug.times[i], &ic->times[i]); - } - - ic = (struct info_clkbug *)more_pkt(); - } - flush_pkt(); -} -#endif diff --git a/contrib/ntp/ntpd/ntp_restrict.c b/contrib/ntp/ntpd/ntp_restrict.c deleted file mode 100644 index ede4225..0000000 --- a/contrib/ntp/ntpd/ntp_restrict.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * ntp_restrict.c - determine host restrictions - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <sys/types.h> - -#include "ntpd.h" -#include "ntp_if.h" -#include "ntp_stdlib.h" - -/* - * This code keeps a simple address-and-mask list of hosts we want - * to place restrictions on (or remove them from). The restrictions - * are implemented as a set of flags which tell you what the host - * can't do. There is a subroutine entry to return the flags. The - * list is kept sorted to reduce the average number of comparisons - * and make sure you get the set of restrictions most specific to - * the address. - * - * The algorithm is that, when looking up a host, it is first assumed - * that the default set of restrictions will apply. It then searches - * down through the list. Whenever it finds a match it adopts the - * match's flags instead. When you hit the point where the sorted - * address is greater than the target, you return with the last set of - * flags you found. Because of the ordering of the list, the most - * specific match will provide the final set of flags. - * - * This was originally intended to restrict you from sync'ing to your - * own broadcasts when you are doing that, by restricting yourself from - * your own interfaces. It was also thought it would sometimes be useful - * to keep a misbehaving host or two from abusing your primary clock. It - * has been expanded, however, to suit the needs of those with more - * restrictive access policies. - */ -/* - * We will use two lists, one for IPv4 addresses and one for IPv6 - * addresses. This is not protocol-independant but for now I can't - * find a way to respect this. We'll check this later... JFB 07/2001 - */ -#define SET_IPV6_ADDR_MASK(dst, src, msk) \ - do { \ - int idx; \ - for (idx = 0; idx < 16; idx++) { \ - (dst)->s6_addr[idx] = \ - (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \ - } \ - } while (0) - -/* - * Memory allocation parameters. We allocate INITRESLIST entries - * initially, and add INCRESLIST entries to the free list whenever - * we run out. - */ -#define INITRESLIST 10 -#define INCRESLIST 5 - -#define RES_AVG 8. /* interpacket averaging factor */ - -/* - * The restriction list - */ -struct restrictlist *restrictlist; -struct restrictlist6 *restrictlist6; -static int restrictcount; /* count of entries in the res list */ -static int restrictcount6; /* count of entries in the res list 2*/ - -/* - * The free list and associated counters. Also some uninteresting - * stat counters. - */ -static struct restrictlist *resfree; -static struct restrictlist6 *resfree6; -static int numresfree; /* number of structures on free list */ -static int numresfree6; /* number of structures on free list 2 */ - -static u_long res_calls; -static u_long res_found; -static u_long res_not_found; - -/* - * Parameters of the RES_LIMITED restriction option. - */ -u_long res_avg_interval = 5; /* min average interpacket interval */ -u_long res_min_interval = 1; /* min interpacket interval */ - -/* - * Count number of restriction entries referring to RES_LIMITED controls - * activation/deactivation of monitoring (with respect to RES_LIMITED - * control) - */ -static u_long res_limited_refcnt; -static u_long res_limited_refcnt6; - -/* - * Our initial allocation of lists entries. - */ -static struct restrictlist resinit[INITRESLIST]; -static struct restrictlist6 resinit6[INITRESLIST]; - -/* - * init_restrict - initialize the restriction data structures - */ -void -init_restrict(void) -{ - register int i; - - /* - * Zero the list and put all but one on the free list - */ - resfree = 0; - memset((char *)resinit, 0, sizeof resinit); - resfree6 = 0; - memset((char *)resinit6, 0, sizeof resinit6); - for (i = 1; i < INITRESLIST; i++) { - resinit[i].next = resfree; - resinit6[i].next = resfree6; - resfree = &resinit[i]; - resfree6 = &resinit6[i]; - } - numresfree = INITRESLIST-1; - numresfree6 = INITRESLIST-1; - - /* - * Put the remaining item at the head of the list as our default - * entry. Everything in here should be zero for now. - */ - resinit[0].addr = htonl(INADDR_ANY); - resinit[0].mask = 0; - memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr)); - memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr)); - restrictlist = &resinit[0]; - restrictlist6 = &resinit6[0]; - restrictcount = 1; - restrictcount = 2; - - /* - * fix up stat counters - */ - res_calls = 0; - res_found = 0; - res_not_found = 0; - - /* - * set default values for RES_LIMIT functionality - */ - res_limited_refcnt = 0; - res_limited_refcnt6 = 0; -} - - -/* - * restrictions - return restrictions for this host - */ -int -restrictions( - struct sockaddr_storage *srcadr - ) -{ - struct restrictlist *rl; - struct restrictlist *match = NULL; - struct restrictlist6 *rl6; - struct restrictlist6 *match6 = NULL; - struct in6_addr hostaddr6; - struct in6_addr hostservaddr6; - u_int32 hostaddr; - int flags = 0; - int isntpport; - - res_calls++; - if (srcadr->ss_family == AF_INET) { - /* - * We need the host address in host order. Also need to - * know whether this is from the ntp port or not. - */ - hostaddr = SRCADR(srcadr); - isntpport = (SRCPORT(srcadr) == NTP_PORT); - - /* - * Ignore any packets with a multicast source address - * (this should be done early in the receive process, - * later!) - */ - if (IN_CLASSD(SRCADR(srcadr))) - return (int)RES_IGNORE; - - /* - * Set match to first entry, which is default entry. - * Work our way down from there. - */ - match = restrictlist; - for (rl = match->next; rl != 0 && rl->addr <= hostaddr; - rl = rl->next) - if ((hostaddr & rl->mask) == rl->addr) { - if ((rl->mflags & RESM_NTPONLY) && - !isntpport) - continue; - match = rl; - } - match->count++; - if (match == restrictlist) - res_not_found++; - else - res_found++; - flags = match->flags; - } - - /* IPv6 source address */ - if (srcadr->ss_family == AF_INET6) { - /* - * Need to know whether this is from the ntp port or - * not. - */ - hostaddr6 = GET_INADDR6(*srcadr); - isntpport = (ntohs(( - (struct sockaddr_in6 *)srcadr)->sin6_port) == - NTP_PORT); - - /* - * Ignore any packets with a multicast source address - * (this should be done early in the receive process, - * later!) - */ - if (IN6_IS_ADDR_MULTICAST(&hostaddr6)) - return (int)RES_IGNORE; - - /* - * Set match to first entry, which is default entry. - * Work our way down from there. - */ - match6 = restrictlist6; - for (rl6 = match6->next; rl6 != 0 && - (memcmp(&(rl6->addr6), &hostaddr6, - sizeof(hostaddr6)) <= 0); rl6 = rl6->next) { - SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6, - &rl6->mask6); - if (memcmp(&hostservaddr6, &(rl6->addr6), - sizeof(hostservaddr6)) == 0) { - if ((rl6->mflags & RESM_NTPONLY) && - !isntpport) - continue; - match6 = rl6; - } - } - match6->count++; - if (match6 == restrictlist6) - res_not_found++; - else - res_found++; - flags = match6->flags; - } - - /* - * The following implements a generalized call gap facility. - * Douse the RES_LIMITED bit only if the interval since the last - * packet is greater than res_min_interval and the average is - * greater thatn res_avg_interval. - */ - if (mon_enabled == MON_OFF) { - flags &= ~RES_LIMITED; - } else { - struct mon_data *md; - - /* - * At this poin the most recent arrival is first in the - * MRU list. Let the first 10 packets in for free until - * the average stabilizes. - */ - md = mon_mru_list.mru_next; - if (md->avg_interval == 0) - md->avg_interval = md->drop_count; - else - md->avg_interval += (md->drop_count - - md->avg_interval) / RES_AVG; - if (md->count < 10 || (md->drop_count > - res_min_interval && md->avg_interval > - res_avg_interval)) - flags &= ~RES_LIMITED; - md->drop_count = flags; - } - return (flags); -} - - -/* - * hack_restrict - add/subtract/manipulate entries on the restrict list - */ -void -hack_restrict( - int op, - struct sockaddr_storage *resaddr, - struct sockaddr_storage *resmask, - int mflags, - int flags - ) -{ - register u_int32 addr = 0; - register u_int32 mask = 0; - struct in6_addr addr6; - struct in6_addr mask6; - register struct restrictlist *rl = NULL; - register struct restrictlist *rlprev = NULL; - register struct restrictlist6 *rl6 = NULL; - register struct restrictlist6 *rlprev6 = NULL; - int i, addr_cmp, mask_cmp; - memset(&addr6, 0, sizeof(struct in6_addr)); - memset(&mask6, 0, sizeof(struct in6_addr)); - - if (resaddr->ss_family == AF_INET) { - /* - * Get address and mask in host byte order - */ - addr = SRCADR(resaddr); - mask = SRCADR(resmask); - addr &= mask; /* make sure low bits zero */ - - /* - * If this is the default address, point at first on - * list. Else go searching for it. - */ - if (addr == 0) { - rlprev = 0; - rl = restrictlist; - } else { - rlprev = restrictlist; - rl = rlprev->next; - while (rl != 0) { - if (rl->addr > addr) { - rl = 0; - break; - } else if (rl->addr == addr) { - if (rl->mask == mask) { - if ((mflags & - RESM_NTPONLY) == - (rl->mflags & - RESM_NTPONLY)) - break; - - if (!(mflags & - RESM_NTPONLY)) { - rl = 0; - break; - } - } else if (rl->mask > mask) { - rl = 0; - break; - } - } - rlprev = rl; - rl = rl->next; - } - } - } - - if (resaddr->ss_family == AF_INET6) { - mask6 = GET_INADDR6(*resmask); - SET_IPV6_ADDR_MASK(&addr6, - &GET_INADDR6(*resaddr), &mask6); - if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) { - rlprev6 = 0; - rl6 = restrictlist6; - } else { - rlprev6 = restrictlist6; - rl6 = rlprev6->next; - while (rl6 != 0) { - addr_cmp = memcmp(&rl6->addr6, &addr6, - sizeof(addr6)); - if (addr_cmp > 0) { - rl6 = 0; - break; - } else if (addr_cmp == 0) { - mask_cmp = memcmp(&rl6->mask6, - &mask6, sizeof(mask6)); - if (mask_cmp == 0) { - if ((mflags & - RESM_NTPONLY) == - (rl6->mflags & - RESM_NTPONLY)) - break; - - if (!(mflags & - RESM_NTPONLY)) { - rl6 = 0; - break; - } - } else if (mask_cmp > 0) { - rl6 = 0; - break; - } - } - rlprev6 = rl6; - rl6 = rl6->next; - } - } - } - - /* - * In case the above wasn't clear :-), either rl now points - * at the entry this call refers to, or rl is zero and rlprev - * points to the entry prior to where this one should go in - * the sort. - */ - - /* - * Switch based on operation - */ - if (resaddr->ss_family == AF_INET) { - switch (op) { - case RESTRICT_FLAGS: - /* - * Here we add bits to the flags. If this is a - * new restriction add it. - */ - if (rl == 0) { - if (numresfree == 0) { - rl = (struct restrictlist *) - emalloc(INCRESLIST * - sizeof(struct - restrictlist)); - memset((char *)rl, 0, - INCRESLIST * sizeof(struct - restrictlist)); - for (i = 0; i < INCRESLIST; i++) { - rl->next = resfree; - resfree = rl; - rl++; - } - numresfree = INCRESLIST; - } - - rl = resfree; - resfree = rl->next; - numresfree--; - - rl->addr = addr; - rl->mask = mask; - rl->mflags = (u_short)mflags; - - rl->next = rlprev->next; - rlprev->next = rl; - restrictcount++; - } - if ((rl->flags ^ (u_short)flags) & - RES_LIMITED) { - res_limited_refcnt++; - mon_start(MON_RES); - } - rl->flags |= (u_short)flags; - break; - - case RESTRICT_UNFLAG: - /* - * Remove some bits from the flags. If we didn't - * find this one, just return. - */ - if (rl != 0) { - if ((rl->flags ^ (u_short)flags) & - RES_LIMITED) { - res_limited_refcnt--; - if (res_limited_refcnt == 0) - mon_stop(MON_RES); - } - rl->flags &= (u_short)~flags; - } - break; - - case RESTRICT_REMOVE: - /* - * Remove an entry from the table entirely if we - * found one. Don't remove the default entry and - * don't remove an interface entry. - */ - if (rl != 0 - && rl->addr != htonl(INADDR_ANY) - && !(rl->mflags & RESM_INTERFACE)) { - rlprev->next = rl->next; - restrictcount--; - if (rl->flags & RES_LIMITED) { - res_limited_refcnt--; - if (res_limited_refcnt == 0) - mon_stop(MON_RES); - } - memset((char *)rl, 0, - sizeof(struct restrictlist)); - - rl->next = resfree; - resfree = rl; - numresfree++; - } - break; - - default: - break; - } - } else if (resaddr->ss_family == AF_INET6) { - switch (op) { - case RESTRICT_FLAGS: - /* - * Here we add bits to the flags. If this is a - * new restriction add it. - */ - if (rl6 == 0) { - if (numresfree6 == 0) { - rl6 = (struct - restrictlist6 *)emalloc( - INCRESLIST * sizeof(struct - restrictlist6)); - memset((char *)rl6, 0, - INCRESLIST * sizeof(struct - restrictlist6)); - - for (i = 0; i < INCRESLIST; - i++) { - rl6->next = resfree6; - resfree6 = rl6; - rl6++; - } - numresfree6 = INCRESLIST; - } - rl6 = resfree6; - resfree6 = rl6->next; - numresfree6--; - rl6->addr6 = addr6; - rl6->mask6 = mask6; - rl6->mflags = (u_short)mflags; - rl6->next = rlprev6->next; - rlprev6->next = rl6; - restrictcount6++; - } - if ((rl6->flags ^ (u_short)flags) & - RES_LIMITED) { - res_limited_refcnt6++; - mon_start(MON_RES); - } - rl6->flags |= (u_short)flags; - break; - - case RESTRICT_UNFLAG: - /* - * Remove some bits from the flags. If we didn't - * find this one, just return. - */ - if (rl6 != 0) { - if ((rl6->flags ^ (u_short)flags) & - RES_LIMITED) { - res_limited_refcnt6--; - if (res_limited_refcnt6 == 0) - mon_stop(MON_RES); - } - rl6->flags &= (u_short)~flags; - } - break; - - case RESTRICT_REMOVE: - /* - * Remove an entry from the table entirely if we - * found one. Don't remove the default entry and - * don't remove an interface entry. - */ - if (rl6 != 0 && - !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6) - && !(rl6->mflags & RESM_INTERFACE)) { - rlprev6->next = rl6->next; - restrictcount6--; - if (rl6->flags & RES_LIMITED) { - res_limited_refcnt6--; - if (res_limited_refcnt6 == 0) - mon_stop(MON_RES); - } - memset((char *)rl6, 0, - sizeof(struct restrictlist6)); - rl6->next = resfree6; - resfree6 = rl6; - numresfree6++; - } - break; - - default: - break; - } - } -} diff --git a/contrib/ntp/ntpd/ntp_timer.c b/contrib/ntp/ntpd/ntp_timer.c deleted file mode 100644 index 6f0f18b..0000000 --- a/contrib/ntp/ntpd/ntp_timer.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * ntp_timer.c - event timer support routines - */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include "ntp_machine.h" -#include "ntpd.h" -#include "ntp_stdlib.h" - -#include <stdio.h> -#include <signal.h> -#ifdef HAVE_SYS_SIGNAL_H -# include <sys/signal.h> -#endif -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#if defined(HAVE_IO_COMPLETION_PORT) -# include "ntp_iocompletionport.h" -# include "ntp_timer.h" -#endif - -/* - * These routines provide support for the event timer. The timer is - * implemented by an interrupt routine which sets a flag once every - * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which - * is called when the mainline code gets around to seeing the flag. - * The timer routine dispatches the clock adjustment code if its time - * has come, then searches the timer queue for expiries which are - * dispatched to the transmit procedure. Finally, we call the hourly - * procedure to do cleanup and print a message. - */ - -/* - * Alarm flag. The mainline code imports this. - */ -volatile int alarm_flag; - -/* - * The counters - */ -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 OPENSSL -static u_long revoke_timer; /* keys revoke timer */ -u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ -#endif /* OPENSSL */ - -/* - * Statistics counter for the interested. - */ -volatile u_long alarm_overflow; - -#define MINUTE 60 -#define HOUR (60*60) - -u_long current_time; - -/* - * Stats. Number of overflows and number of calls to transmit(). - */ -u_long timer_timereset; -u_long timer_overflows; -u_long timer_xmtcalls; - -#if defined(VMS) -static int vmstimer[2]; /* time for next timer AST */ -static int vmsinc[2]; /* timer increment */ -#endif /* VMS */ - -#if defined SYS_WINNT -static HANDLE WaitableTimerHandle = NULL; -#else -static RETSIGTYPE alarming P((int)); -#endif /* SYS_WINNT */ - -#if !defined(VMS) -# if !defined SYS_WINNT || defined(SYS_CYGWIN32) -# ifndef HAVE_TIMER_SETTIME - struct itimerval itimer; -# else - static timer_t ntpd_timerid; - struct itimerspec itimer; -# endif /* HAVE_TIMER_SETTIME */ -# endif /* SYS_WINNT */ -#endif /* VMS */ - -/* - * reinit_timer - reinitialize interval timer. - */ -void -reinit_timer(void) -{ -#if !defined(SYS_WINNT) && !defined(VMS) -# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) - timer_gettime(ntpd_timerid, &itimer); - if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) { - itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); - } - if (itimer.it_value.tv_nsec < 0 ) { - itimer.it_value.tv_nsec = 0; - } - if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) { - itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); - itimer.it_value.tv_nsec = 0; - } - itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT); - itimer.it_interval.tv_nsec = 0; - timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL); -# else - getitimer(ITIMER_REAL, &itimer); - if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) { - itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); - } - if (itimer.it_value.tv_usec < 0 ) { - itimer.it_value.tv_usec = 0; - } - if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) { - itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); - itimer.it_value.tv_usec = 0; - } - itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT); - itimer.it_interval.tv_usec = 0; - setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); -# endif -# endif /* VMS */ -} - -/* - * init_timer - initialize the timer data structures - */ -void -init_timer(void) -{ -# if defined SYS_WINNT & !defined(SYS_CYGWIN32) - HANDLE hToken; - TOKEN_PRIVILEGES tkp; -# endif /* SYS_WINNT */ - - /* - * Initialize... - */ - alarm_flag = 0; - alarm_overflow = 0; - adjust_timer = 1; - hourly_timer = HOUR; - huffpuff_timer = 0; - current_time = 0; - timer_overflows = 0; - timer_xmtcalls = 0; - timer_timereset = 0; - -#if !defined(SYS_WINNT) - /* - * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT - * seconds from now and they continue on every 2**EVENT_TIMEOUT - * seconds. - */ -# if !defined(VMS) -# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) - if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) == -# ifdef SYS_VXWORKS - ERROR -# else - -1 -# endif - ) - { - fprintf (stderr, "timer create FAILED\n"); - exit (0); - } - (void) signal_no_reset(SIGALRM, alarming); - itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); - itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0; - timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL); -# else - (void) signal_no_reset(SIGALRM, alarming); - itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); - itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); -# endif -# else /* VMS */ - vmsinc[0] = 10000000; /* 1 sec */ - vmsinc[1] = 0; - lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); - - sys$gettim(&vmstimer); /* that's "now" as abstime */ - - lib$addx(&vmsinc, &vmstimer, &vmstimer); - sys$setimr(0, &vmstimer, alarming, alarming, 0); -# endif /* VMS */ -#else /* SYS_WINNT */ - _tzset(); - - /* - * Get privileges needed for fiddling with the clock - */ - - /* get the current process token handle */ - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { - msyslog(LOG_ERR, "OpenProcessToken failed: %m"); - exit(1); - } - /* get the LUID for system-time privilege. */ - LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); - tkp.PrivilegeCount = 1; /* one privilege to set */ - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - /* get set-time privilege for this process. */ - AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); - /* cannot test return value of AdjustTokenPrivileges. */ - if (GetLastError() != ERROR_SUCCESS) { - msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); - } - - /* - * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds - * Under Windows/NT, - */ - - WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); - if (WaitableTimerHandle == NULL) { - msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); - exit(1); - } - else { - DWORD Period = (1<<EVENT_TIMEOUT) * 1000; - LARGE_INTEGER DueTime; - DueTime.QuadPart = Period * 10000i64; - if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) { - msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); - exit(1); - } - } - -#endif /* SYS_WINNT */ -} - -#if defined(SYS_WINNT) -extern HANDLE -get_timer_handle(void) -{ - return WaitableTimerHandle; -} -#endif - -/* - * timer - dispatch anyone who needs to be - */ -void -timer(void) -{ - register struct peer *peer, *next_peer; -#ifdef OPENSSL - char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ -#endif /* OPENSSL */ - u_int n; - - current_time += (1<<EVENT_TIMEOUT); - - /* - * Adjustment timeout first. - */ - if (adjust_timer <= current_time) { - adjust_timer += 1; - adj_host_clock(); - kod_proto(); - } - - /* - * Now dispatch any peers whose event timer has expired. Be careful - * here, since the peer structure might go away as the result of - * the call. - */ - for (n = 0; n < HASH_SIZE; n++) { - for (peer = peer_hash[n]; peer != 0; peer = next_peer) { - next_peer = peer->next; - if (peer->action && peer->nextaction <= current_time) - peer->action(peer); - if (peer->nextdate <= current_time) { -#ifdef REFCLOCK - if (peer->flags & FLAG_REFCLOCK) - refclock_transmit(peer); - else - transmit(peer); -#else /* REFCLOCK */ - transmit(peer); -#endif /* REFCLOCK */ - } - } - } - - /* - * Garbage collect expired keys. - */ - if (keys_timer <= current_time) { - keys_timer += MINUTE; - auth_agekeys(); - } - - /* - * Huff-n'-puff filter - */ - if (huffpuff_timer <= current_time) { - huffpuff_timer += HUFFPUFF; - huffpuff(); - } - -#ifdef OPENSSL - /* - * Garbage collect old keys and generate new private value - */ - if (revoke_timer <= current_time) { - revoke_timer += RANDPOLL(sys_revoke); - expire_all(); - sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp)); - record_crypto_stats(NULL, statstr); -#ifdef DEBUG - if (debug) - printf("timer: %s\n", statstr); -#endif - } -#endif /* OPENSSL */ - - /* - * Finally, call the hourly routine. - */ - if (hourly_timer <= current_time) { - hourly_timer += HOUR; - hourly_stats(); - } -} - - -#ifndef SYS_WINNT -/* - * alarming - tell the world we've been alarmed - */ -static RETSIGTYPE -alarming( - int sig - ) -{ -#if !defined(VMS) - if (initializing) - return; - if (alarm_flag) - alarm_overflow++; - else - alarm_flag++; -#else /* VMS AST routine */ - if (!initializing) { - if (alarm_flag) alarm_overflow++; - else alarm_flag = 1; /* increment is no good */ - } - lib$addx(&vmsinc,&vmstimer,&vmstimer); - sys$setimr(0,&vmstimer,alarming,alarming,0); -#endif /* VMS */ -} -#endif /* SYS_WINNT */ - - -/* - * timer_clr_stats - clear timer module stat counters - */ -void -timer_clr_stats(void) -{ - timer_overflows = 0; - timer_xmtcalls = 0; - timer_timereset = current_time; -} - diff --git a/contrib/ntp/ntpd/ntp_util.c b/contrib/ntp/ntpd/ntp_util.c deleted file mode 100644 index 135f9b3..0000000 --- a/contrib/ntp/ntpd/ntp_util.c +++ /dev/null @@ -1,797 +0,0 @@ -/* - * ntp_util.c - stuff I didn't have any other place for - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_filegen.h" -#include "ntp_if.h" -#include "ntp_stdlib.h" - -#include <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> -#endif /* VMS */ -#endif - -#if defined(VMS) -#include <descrip.h> -#endif /* VMS */ - -/* - * This contains odds and ends. Right now the only thing you'll find - * in here is the hourly stats printer and some code to support - * rereading the keys file, but I may eventually put other things in - * here such as code to do something with the leap bits. - */ -/* - * Name of the keys file - */ -static char *key_file_name; - -/* - * The name of the drift_comp file and the temporary. - */ -static char *stats_drift_file; -static char *stats_temp_file; - -/* - * Statistics file stuff - */ -#ifndef NTP_VAR -#ifndef SYS_WINNT -#define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ -#else -#define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ -#endif /* SYS_WINNT */ -#endif - -#ifndef MAXPATHLEN -#define MAXPATHLEN 256 -#endif - -static char statsdir[MAXPATHLEN] = NTP_VAR; - -static FILEGEN peerstats; -static FILEGEN loopstats; -static FILEGEN clockstats; -static FILEGEN rawstats; -static FILEGEN sysstats; -#ifdef OPENSSL -static FILEGEN cryptostats; -#endif /* OPENSSL */ - -/* - * This controls whether stats are written to the fileset. Provided - * so that ntpdc can turn off stats when the file system fills up. - */ -int stats_control; - -/* - * init_util - initialize the utilities - */ -void -init_util(void) -{ - stats_drift_file = 0; - stats_temp_file = 0; - key_file_name = 0; - -#define PEERNAME "peerstats" -#define LOOPNAME "loopstats" -#define CLOCKNAME "clockstats" -#define RAWNAME "rawstats" -#define STANAME "systats" -#ifdef OPENSSL -#define CRYPTONAME "cryptostats" -#endif /* OPENSSL */ - - peerstats.fp = NULL; - peerstats.prefix = &statsdir[0]; - peerstats.basename = (char*)emalloc(strlen(PEERNAME)+1); - strcpy(peerstats.basename, PEERNAME); - peerstats.id = 0; - peerstats.type = FILEGEN_DAY; - peerstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ - filegen_register("peerstats", &peerstats); - - loopstats.fp = NULL; - loopstats.prefix = &statsdir[0]; - loopstats.basename = (char*)emalloc(strlen(LOOPNAME)+1); - strcpy(loopstats.basename, LOOPNAME); - loopstats.id = 0; - loopstats.type = FILEGEN_DAY; - loopstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ - filegen_register("loopstats", &loopstats); - - clockstats.fp = NULL; - clockstats.prefix = &statsdir[0]; - clockstats.basename = (char*)emalloc(strlen(CLOCKNAME)+1); - strcpy(clockstats.basename, CLOCKNAME); - clockstats.id = 0; - clockstats.type = FILEGEN_DAY; - clockstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ - filegen_register("clockstats", &clockstats); - - rawstats.fp = NULL; - rawstats.prefix = &statsdir[0]; - rawstats.basename = (char*)emalloc(strlen(RAWNAME)+1); - strcpy(rawstats.basename, RAWNAME); - rawstats.id = 0; - rawstats.type = FILEGEN_DAY; - rawstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ - filegen_register("rawstats", &rawstats); - - sysstats.fp = NULL; - sysstats.prefix = &statsdir[0]; - sysstats.basename = (char*)emalloc(strlen(STANAME)+1); - strcpy(sysstats.basename, STANAME); - sysstats.id = 0; - sysstats.type = FILEGEN_DAY; - sysstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ - filegen_register("sysstats", &sysstats); - -#ifdef OPENSSL - cryptostats.fp = NULL; - cryptostats.prefix = &statsdir[0]; - cryptostats.basename = (char*)emalloc(strlen(CRYPTONAME)+1); - strcpy(cryptostats.basename, CRYPTONAME); - cryptostats.id = 0; - cryptostats.type = FILEGEN_DAY; - cryptostats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ - filegen_register("cryptostats", &cryptostats); -#endif /* OPENSSL */ - -#undef PEERNAME -#undef LOOPNAME -#undef CLOCKNAME -#undef RAWNAME -#undef STANAME -#ifdef OPENSSL -#undef CRYPTONAME -#endif /* OPENSSL */ -} - - -/* - * hourly_stats - print some interesting stats - */ -void -hourly_stats(void) -{ - FILE *fp; - -#ifdef DOSYNCTODR - struct timeval tv; -#if !defined(VMS) - int prio_set; -#endif -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif - int o_prio; - - /* - * Sometimes having a Sun can be a drag. - * - * The kernel variable dosynctodr controls whether the system's - * soft clock is kept in sync with the battery clock. If it - * is zero, then the soft clock is not synced, and the battery - * clock is simply left to rot. That means that when the system - * reboots, the battery clock (which has probably gone wacky) - * sets the soft clock. That means ntpd starts off with a very - * confused idea of what time it is. It then takes a large - * amount of time to figure out just how wacky the battery clock - * has made things drift, etc, etc. The solution is to make the - * battery clock sync up to system time. The way to do THAT is - * to simply set the time of day to the current time of day, but - * as quickly as possible. This may, or may not be a sensible - * thing to do. - * - * CAVEAT: settimeofday() steps the sun clock by about 800 us, - * so setting DOSYNCTODR seems a bad idea in the - * case of us resolution - */ - -#if !defined(VMS) - /* (prr) getpriority returns -1 on error, but -1 is also a valid - * return value (!), so instead we have to zero errno before the - * call and check it for non-zero afterwards. - */ - errno = 0; - prio_set = 0; - o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ - - /* - * (prr) if getpriority succeeded, call setpriority to raise - * scheduling priority as high as possible. If that succeeds - * as well, set the prio_set flag so we remember to reset - * priority to its previous value below. Note that on Solaris - * 2.6 (and beyond?), both getpriority and setpriority will fail - * with ESRCH, because sched_setscheduler (called from main) put - * us in the real-time scheduling class which setpriority - * doesn't know about. Being in the real-time class is better - * than anything setpriority can do, anyhow, so this error is - * silently ignored. - */ - if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) - prio_set = 1; /* overdrive */ -#endif /* VMS */ -#ifdef HAVE_GETCLOCK - (void) getclock(TIMEOFDAY, &ts); - tv.tv_sec = ts.tv_sec; - tv.tv_usec = ts.tv_nsec / 1000; -#else /* not HAVE_GETCLOCK */ - GETTIMEOFDAY(&tv,(struct timezone *)NULL); -#endif /* not HAVE_GETCLOCK */ - if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) { - msyslog(LOG_ERR, "can't sync battery time: %m"); - } -#if !defined(VMS) - if (prio_set) - setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ -#endif /* VMS */ -#endif /* DOSYNCTODR */ - - NLOG(NLOG_SYSSTATIST) - msyslog(LOG_INFO, - "offset %.6f sec freq %.3f ppm error %.6f poll %d", - last_offset, drift_comp * 1e6, sys_jitter, - sys_poll); - - - record_sys_stats(); - if (stats_drift_file != 0) { - if ((fp = fopen(stats_temp_file, "w")) == NULL) { - msyslog(LOG_ERR, "can't open %s: %m", - stats_temp_file); - return; - } - fprintf(fp, "%.3f\n", drift_comp * 1e6); - (void)fclose(fp); - /* atomic */ -#ifdef SYS_WINNT - (void) _unlink(stats_drift_file); /* rename semantics differ under NT */ -#endif /* SYS_WINNT */ - -#ifndef NO_RENAME - (void) rename(stats_temp_file, stats_drift_file); -#else - /* we have no rename NFS of ftp in use*/ - if ((fp = fopen(stats_drift_file, "w")) == NULL) { - msyslog(LOG_ERR, "can't open %s: %m", - stats_drift_file); - return; - } - -#endif - -#if defined(VMS) - /* PURGE */ - { - $DESCRIPTOR(oldvers,";-1"); - struct dsc$descriptor driftdsc = { - strlen(stats_drift_file),0,0,stats_drift_file }; - - while(lib$delete_file(&oldvers,&driftdsc) & 1) ; - } -#endif - } -} - - -/* - * stats_config - configure the stats operation - */ -void -stats_config( - int item, - char *invalue /* only one type so far */ - ) -{ - FILE *fp; - char *value; - double old_drift; - int len; - - /* - * Expand environment strings under Windows NT, since the - * command interpreter doesn't do this, the program must. - */ -#ifdef SYS_WINNT - char newvalue[MAX_PATH], parameter[MAX_PATH]; - - if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { - switch(item) { - case STATS_FREQ_FILE: - strcpy(parameter,"STATS_FREQ_FILE"); - break; - case STATS_STATSDIR: - strcpy(parameter,"STATS_STATSDIR"); - break; - case STATS_PID_FILE: - strcpy(parameter,"STATS_PID_FILE"); - break; - default: - strcpy(parameter,"UNKNOWN"); - break; - } - value = invalue; - - msyslog(LOG_ERR, - "ExpandEnvironmentStrings(%s) failed: %m\n", parameter); - } else { - value = newvalue; - } -#else - value = invalue; -#endif /* SYS_WINNT */ - - switch(item) { - case STATS_FREQ_FILE: - if (stats_drift_file != 0) { - (void) free(stats_drift_file); - (void) free(stats_temp_file); - stats_drift_file = 0; - stats_temp_file = 0; - } - - if (value == 0 || (len = strlen(value)) == 0) - break; - - stats_drift_file = (char*)emalloc((u_int)(len + 1)); -#if !defined(VMS) - stats_temp_file = (char*)emalloc((u_int)(len + - sizeof(".TEMP"))); -#else - stats_temp_file = (char*)emalloc((u_int)(len + - sizeof("-TEMP"))); -#endif /* VMS */ - memmove(stats_drift_file, value, (unsigned)(len+1)); - memmove(stats_temp_file, value, (unsigned)len); -#if !defined(VMS) - memmove(stats_temp_file + len, ".TEMP", - sizeof(".TEMP")); -#else - memmove(stats_temp_file + len, "-TEMP", - sizeof("-TEMP")); -#endif /* VMS */ - - /* - * Open drift file and read frequency. If the file is - * missing or contains errors, tell the loop to reset. - */ - if ((fp = fopen(stats_drift_file, "r")) == NULL) { - loop_config(LOOP_DRIFTCOMP, 1e9); - break; - } - if (fscanf(fp, "%lf", &old_drift) != 1) { - msyslog(LOG_ERR, "Frequency format error in %s", - stats_drift_file); - loop_config(LOOP_DRIFTCOMP, 1e9); - fclose(fp); - break; - } - fclose(fp); - msyslog(LOG_INFO, - "frequency initialized %.3f PPM from %s", - old_drift, stats_drift_file); - loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); - break; - - case STATS_STATSDIR: - if (strlen(value) >= sizeof(statsdir)) { - msyslog(LOG_ERR, - "value for statsdir too long (>%d, sigh)", - (int)sizeof(statsdir)-1); - } else { - l_fp now; - - get_systime(&now); - strcpy(statsdir,value); - if(peerstats.prefix == &statsdir[0] && - peerstats.fp != NULL) { - fclose(peerstats.fp); - peerstats.fp = NULL; - filegen_setup(&peerstats, now.l_ui); - } - if(loopstats.prefix == &statsdir[0] && - loopstats.fp != NULL) { - fclose(loopstats.fp); - loopstats.fp = NULL; - filegen_setup(&loopstats, now.l_ui); - } - if(clockstats.prefix == &statsdir[0] && - clockstats.fp != NULL) { - fclose(clockstats.fp); - clockstats.fp = NULL; - filegen_setup(&clockstats, now.l_ui); - } - if(rawstats.prefix == &statsdir[0] && - rawstats.fp != NULL) { - fclose(rawstats.fp); - rawstats.fp = NULL; - filegen_setup(&rawstats, now.l_ui); - } - if(sysstats.prefix == &statsdir[0] && - sysstats.fp != NULL) { - fclose(sysstats.fp); - sysstats.fp = NULL; - filegen_setup(&sysstats, now.l_ui); - } -#ifdef OPENSSL - if(cryptostats.prefix == &statsdir[0] && - cryptostats.fp != NULL) { - fclose(cryptostats.fp); - cryptostats.fp = NULL; - filegen_setup(&cryptostats, now.l_ui); - } -#endif /* OPENSSL */ - } - break; - - case STATS_PID_FILE: - if ((fp = fopen(value, "w")) == NULL) { - msyslog(LOG_ERR, "Can't open %s: %m", value); - break; - } - fprintf(fp, "%d", (int) getpid()); - fclose(fp);; - break; - - default: - /* oh well */ - break; - } -} - -/* - * record_peer_stats - write peer statistics to file - * - * file format: - * day (mjd) - * time (s past UTC midnight) - * peer (ip address) - * peer status word (hex) - * peer offset (s) - * peer delay (s) - * peer error bound (s) - * peer error (s) -*/ -void -record_peer_stats( - struct sockaddr_storage *addr, - int status, - double offset, - double delay, - double dispersion, - double skew - ) -{ - l_fp now; - u_long day; - - if (!stats_control) - return; - - get_systime(&now); - filegen_setup(&peerstats, now.l_ui); - day = now.l_ui / 86400 + MJD_1900; - now.l_ui %= 86400; - if (peerstats.fp != NULL) { - fprintf(peerstats.fp, - "%lu %s %s %x %.9f %.9f %.9f %.9f\n", - day, ulfptoa(&now, 3), stoa(addr), status, offset, - delay, dispersion, skew); - fflush(peerstats.fp); - } -} -/* - * record_loop_stats - write loop filter statistics to file - * - * file format: - * day (mjd) - * time (s past midnight) - * offset (s) - * frequency (approx ppm) - * time constant (log base 2) - */ -void -record_loop_stats( - double offset, - double freq, - double jitter, - double stability, - int spoll - ) -{ - l_fp now; - u_long day; - - if (!stats_control) - return; - - get_systime(&now); - filegen_setup(&loopstats, now.l_ui); - day = now.l_ui / 86400 + MJD_1900; - now.l_ui %= 86400; - if (loopstats.fp != NULL) { - fprintf(loopstats.fp, "%lu %s %.9f %.6f %.9f %.6f %d\n", - day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, - stability * 1e6, spoll); - fflush(loopstats.fp); - } -} - -/* - * record_clock_stats - write clock statistics to file - * - * file format: - * day (mjd) - * time (s past midnight) - * peer (ip address) - * text message - */ -void -record_clock_stats( - struct sockaddr_storage *addr, - const char *text - ) -{ - l_fp now; - u_long day; - - if (!stats_control) - return; - - get_systime(&now); - filegen_setup(&clockstats, now.l_ui); - day = now.l_ui / 86400 + MJD_1900; - now.l_ui %= 86400; - if (clockstats.fp != NULL) { - fprintf(clockstats.fp, "%lu %s %s %s\n", - day, ulfptoa(&now, 3), stoa(addr), text); - fflush(clockstats.fp); - } -} - -/* - * record_raw_stats - write raw timestamps to file - * - * - * file format - * time (s past midnight) - * peer ip address - * local ip address - * t1 t2 t3 t4 timestamps - */ -void -record_raw_stats( - struct sockaddr_storage *srcadr, - struct sockaddr_storage *dstadr, - l_fp *t1, - l_fp *t2, - l_fp *t3, - l_fp *t4 - ) -{ - l_fp now; - u_long day; - - if (!stats_control) - return; - - get_systime(&now); - filegen_setup(&rawstats, now.l_ui); - day = now.l_ui / 86400 + MJD_1900; - now.l_ui %= 86400; - if (rawstats.fp != NULL) { - fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", - day, ulfptoa(&now, 3), stoa(srcadr), stoa(dstadr), - ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9), - ulfptoa(t4, 9)); - fflush(rawstats.fp); - } -} - - -/* - * record_sys_stats - write system statistics to file - * - * file format - * time (s past midnight) - * time since startup (hr) - * packets recieved - * packets processed - * current version - * previous version - * bad version - * access denied - * bad length or format - * bad authentication - * rate exceeded - */ -void -record_sys_stats(void) -{ - l_fp now; - u_long day; - - if (!stats_control) - return; - - get_systime(&now); - filegen_setup(&sysstats, now.l_ui); - day = now.l_ui / 86400 + MJD_1900; - now.l_ui %= 86400; - if (sysstats.fp != NULL) { - fprintf(sysstats.fp, - "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - day, ulfptoa(&now, 3), sys_stattime / 3600, - sys_received, sys_processed, sys_newversionpkt, - sys_oldversionpkt, sys_unknownversion, - sys_restricted, sys_badlength, sys_badauth, - sys_limitrejected); - fflush(sysstats.fp); - proto_clr_stats(); - } -} - - -#ifdef OPENSSL -/* - * record_crypto_stats - write crypto statistics to file - * - * file format: - * day (mjd) - * time (s past midnight) - * peer (ip address) - * text message - */ -void -record_crypto_stats( - struct sockaddr_storage *addr, - const char *text - ) -{ - l_fp now; - u_long day; - - if (!stats_control) - return; - - get_systime(&now); - filegen_setup(&cryptostats, now.l_ui); - day = now.l_ui / 86400 + MJD_1900; - now.l_ui %= 86400; - if (cryptostats.fp != NULL) { - if (addr == NULL) - fprintf(cryptostats.fp, "%lu %s %s\n", - day, ulfptoa(&now, 3), text); - else - fprintf(cryptostats.fp, "%lu %s %s %s\n", - day, ulfptoa(&now, 3), stoa(addr), text); - fflush(cryptostats.fp); - } -} -#endif /* OPENSSL */ - - -/* - * getauthkeys - read the authentication keys from the specified file - */ -void -getauthkeys( - char *keyfile - ) -{ - int len; - - len = strlen(keyfile); - if (len == 0) - return; - - if (key_file_name != 0) { - if (len > (int)strlen(key_file_name)) { - (void) free(key_file_name); - key_file_name = 0; - } - } - - if (key_file_name == 0) { -#ifndef SYS_WINNT - key_file_name = (char*)emalloc((u_int) (len + 1)); -#else - key_file_name = (char*)emalloc((u_int) (MAXPATHLEN)); -#endif - } -#ifndef SYS_WINNT - memmove(key_file_name, keyfile, (unsigned)(len+1)); -#else - if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN)) - { - msyslog(LOG_ERR, - "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n"); - } -#endif /* SYS_WINNT */ - - authreadkeys(key_file_name); -} - - -/* - * rereadkeys - read the authentication key file over again. - */ -void -rereadkeys(void) -{ - if (key_file_name != 0) - authreadkeys(key_file_name); -} - -/* - * sock_hash - hash an sockaddr_storage structure - */ -int -sock_hash( - struct sockaddr_storage *addr - ) -{ - int hashVal; - int i; - int len; - char *ch; - - hashVal = 0; - len = 0; - /* - * We can't just hash the whole thing because there are hidden - * fields in sockaddr_in6 that might be filled in by recvfrom(), - * so just use the family, port and address. - */ - ch = (char *)&addr->ss_family; - hashVal = 37 * hashVal + (int)*ch; - if (sizeof(addr->ss_family) > 1) { - ch++; - hashVal = 37 * hashVal + (int)*ch; - } - switch(addr->ss_family) { - case AF_INET: - ch = (char *)&((struct sockaddr_in *)addr)->sin_addr; - len = sizeof(struct in_addr); - break; - case AF_INET6: - ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr; - len = sizeof(struct in6_addr); - break; - } - - for (i = 0; i < len ; i++) - hashVal = 37 * hashVal + (int)*(ch + i); - - hashVal = hashVal % 128; /* % MON_HASH_SIZE hardcoded */ - - if (hashVal < 0) - hashVal += 128; - - return hashVal; -} diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c deleted file mode 100644 index 0b05253..0000000 --- a/contrib/ntp/ntpd/ntpd.c +++ /dev/null @@ -1,1274 +0,0 @@ -/* - * ntpd.c - main program for the fixed point NTP daemon - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include "ntp_machine.h" -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_stdlib.h" - -#ifdef SIM -#include "ntpsim.h" -#endif - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#ifdef HAVE_SYS_STAT_H -# include <sys/stat.h> -#endif -#include <stdio.h> -#ifndef SYS_WINNT -# if !defined(VMS) /*wjm*/ -# ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -# endif -# endif /* VMS */ -# ifdef HAVE_SYS_SIGNAL_H -# include <sys/signal.h> -# else -# include <signal.h> -# endif -# ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -# endif /* HAVE_SYS_IOCTL_H */ -# ifdef HAVE_SYS_RESOURCE_H -# include <sys/resource.h> -# endif /* HAVE_SYS_RESOURCE_H */ -#else -# include <signal.h> -# include <process.h> -# include <io.h> -# include "../libntp/log.h" -# include <clockstuff.h> -# include <crtdbg.h> -#endif /* SYS_WINNT */ -#if defined(HAVE_RTPRIO) -# ifdef HAVE_SYS_RESOURCE_H -# include <sys/resource.h> -# endif -# ifdef HAVE_SYS_LOCK_H -# include <sys/lock.h> -# endif -# include <sys/rtprio.h> -#else -# ifdef HAVE_PLOCK -# ifdef HAVE_SYS_LOCK_H -# include <sys/lock.h> -# endif -# endif -#endif -#if defined(HAVE_SCHED_SETSCHEDULER) -# ifdef HAVE_SCHED_H -# include <sched.h> -# else -# ifdef HAVE_SYS_SCHED_H -# include <sys/sched.h> -# endif -# endif -#endif -#if defined(HAVE_SYS_MMAN_H) -# include <sys/mman.h> -#endif - -#ifdef HAVE_TERMIOS_H -# include <termios.h> -#endif - -#ifdef SYS_DOMAINOS -# include <apollo/base.h> -#endif /* SYS_DOMAINOS */ - -#include "recvbuff.h" -#include "ntp_cmdargs.h" - -#if 0 /* HMS: I don't think we need this. 961223 */ -#ifdef LOCK_PROCESS -# ifdef SYS_SOLARIS -# include <sys/mman.h> -# else -# include <sys/lock.h> -# endif -#endif -#endif - -#ifdef _AIX -# include <ulimit.h> -#endif /* _AIX */ - -#ifdef SCO5_CLOCK -# include <sys/ci/ciioctl.h> -#endif - -#ifdef HAVE_CLOCKCTL -# include <ctype.h> -# include <grp.h> -# include <pwd.h> -#endif - -/* - * Signals we catch for debugging. If not debugging we ignore them. - */ -#define MOREDEBUGSIG SIGUSR1 -#define LESSDEBUGSIG SIGUSR2 - -/* - * Signals which terminate us gracefully. - */ -#ifndef SYS_WINNT -# define SIGDIE1 SIGHUP -# define SIGDIE3 SIGQUIT -# define SIGDIE2 SIGINT -# define SIGDIE4 SIGTERM -#endif /* SYS_WINNT */ - -#if defined SYS_WINNT -/* handles for various threads, process, and objects */ -HANDLE ResolverThreadHandle = NULL; -/* variables used to inform the Service Control Manager of our current state */ -BOOL NoWinService = FALSE; -SERVICE_STATUS ssStatus; -SERVICE_STATUS_HANDLE sshStatusHandle; -HANDLE WaitHandles[3] = { NULL, NULL, NULL }; -char szMsgPath[255]; -static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType); -BOOL init_randfile(); -#endif /* SYS_WINNT */ - -/* - * Scheduling priority we run at - */ -#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 - */ -volatile int debug; - -/* - * Set the processing not to be in the forground - */ -int forground_process = FALSE; - -/* - * No-fork flag. If set, we do not become a background daemon. - */ -int nofork; - -#ifdef HAVE_CLOCKCTL -char *user = NULL; /* User to switch to */ -char *group = NULL; /* group to switch to */ -char *chrootdir = NULL; /* directory to chroot to */ -int sw_uid; -int sw_gid; -char *endp; -struct group *gr; -struct passwd *pw; -#endif /* HAVE_CLOCKCTL */ - -/* - * Initializing flag. All async routines watch this and only do their - * thing when it is clear. - */ -int initializing; - -/* - * Version declaration - */ -extern const char *Version; - -int was_alarmed; - -#ifdef DECL_SYSCALL -/* - * We put this here, since the argument profile is syscall-specific - */ -extern int syscall P((int, ...)); -#endif /* DECL_SYSCALL */ - - -#ifdef SIGDIE2 -static RETSIGTYPE finish P((int)); -#endif /* SIGDIE2 */ - -#ifdef DEBUG -#ifndef SYS_WINNT -static RETSIGTYPE moredebug P((int)); -static RETSIGTYPE lessdebug P((int)); -#endif -#else /* not DEBUG */ -static RETSIGTYPE no_debug P((int)); -#endif /* not DEBUG */ - -int ntpdmain P((int, char **)); -static void set_process_priority P((void)); - -#ifdef SIM -int -main( - int argc, - char *argv[] - ) -{ - return ntpsim(argc, argv); -} -#else /* SIM */ -#ifdef NO_MAIN_ALLOWED -CALL(ntpd,"ntpd",ntpdmain); -#else -int -main( - int argc, - char *argv[] - ) -{ - return ntpdmain(argc, argv); -} -#endif -#endif /* SIM */ - -#ifdef _AIX -/* - * OK. AIX is different than solaris in how it implements plock(). - * If you do NOT adjust the stack limit, you will get the MAXIMUM - * stack size allocated and PINNED with you program. To check the - * value, use ulimit -a. - * - * To fix this, we create an automatic variable and set our stack limit - * to that PLUS 32KB of extra space (we need some headroom). - * - * This subroutine gets the stack address. - * - * Grover Davidson and Matt Ladendorf - * - */ -static char * -get_aix_stack(void) -{ - char ch; - return (&ch); -} - -/* - * Signal handler for SIGDANGER. - */ -static void -catch_danger(int signo) -{ - msyslog(LOG_INFO, "ntpd: setpgid(): %m"); - /* Make the system believe we'll free something, but don't do it! */ - return; -} -#endif /* _AIX */ - -/* - * Set the process priority - */ -static void -set_process_priority(void) -{ - -#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 */ - -#ifdef SYS_WINNT - priority_done += NT_set_process_priority(); -#endif - -#if defined(HAVE_SCHED_SETSCHEDULER) - if (!priority_done) { - extern int config_priority_override, config_priority; - int pmax, pmin; - struct sched_param sched; - - pmax = sched_get_priority_max(SCHED_FIFO); - sched.sched_priority = pmax; - if ( config_priority_override ) { - pmin = sched_get_priority_min(SCHED_FIFO); - if ( config_priority > pmax ) - sched.sched_priority = pmax; - else if ( config_priority < pmin ) - sched.sched_priority = pmin; - else - sched.sched_priority = config_priority; - } - if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) - msyslog(LOG_ERR, "sched_setscheduler(): %m"); - else - ++priority_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 */ - srtp.prio = 0; /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */ - - if (rtprio(RTP_SET, getpid(), &srtp) < 0) - msyslog(LOG_ERR, "rtprio() error: %m"); - else - ++priority_done; - } -# else /* not RTP_SET */ - if (!priority_done) { - if (rtprio(0, 120) < 0) - msyslog(LOG_ERR, "rtprio() error: %m"); - else - ++priority_done; - } -# endif /* not RTP_SET */ -#endif /* HAVE_RTPRIO */ -#if defined(NTPD_PRIO) && NTPD_PRIO != 0 -# ifdef HAVE_ATT_NICE - if (!priority_done) { - errno = 0; - if (-1 == nice (NTPD_PRIO) && errno != 0) - msyslog(LOG_ERR, "nice() error: %m"); - else - ++priority_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 - ++priority_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"); -} - - -/* - * Main program. Initialize us, disconnect us from the tty if necessary, - * and loop waiting for I/O and/or timer expiries. - */ -int -ntpdmain( - int argc, - char *argv[] - ) -{ - l_fp now; - char *cp; - struct recvbuf *rbuflist; - struct recvbuf *rbuf; -#ifdef _AIX /* HMS: ifdef SIGDANGER? */ - struct sigaction sa; -#endif - - initializing = 1; /* mark that we are initializing */ - debug = 0; /* no debugging by default */ - nofork = 0; /* will fork by default */ - -#ifdef HAVE_UMASK - { - mode_t uv; - - uv = umask(0); - if(uv) - (void) umask(uv); - else - (void) umask(022); - } -#endif - -#if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */ - { - uid_t uid; - - uid = getuid(); - if (uid) - { - msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid); - exit(1); - } - } -#endif - -#ifdef SYS_WINNT - /* Set the Event-ID message-file name. */ - if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) { - msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n"); - exit(1); - } - addSourceToRegistry("NTP", szMsgPath); -#endif - getstartup(argc, argv); /* startup configuration, may set debug */ - - if (debug) - printf("%s\n", Version); - - /* - * Initialize random generator and public key pair - */ -#ifdef SYS_WINNT - /* Initialize random file before OpenSSL checks */ - if(!init_randfile()) - msyslog(LOG_ERR, "Unable to initialize .rnd file\n"); -#endif - get_systime(&now); - SRANDOM((int)(now.l_i * now.l_uf)); - -#if !defined(VMS) -# ifndef NODETACH - /* - * Detach us from the terminal. May need an #ifndef GIZMO. - */ -# ifdef DEBUG - if (!debug && !nofork) -# else /* DEBUG */ - if (!nofork) -# endif /* DEBUG */ - { -# ifndef SYS_WINNT -# ifdef HAVE_DAEMON - daemon(0, 0); -# else /* not HAVE_DAEMON */ - if (fork()) /* HMS: What about a -1? */ - exit(0); - - { -#if !defined(F_CLOSEM) - u_long s; - int max_fd; -#endif /* not F_CLOSEM */ - -#if defined(F_CLOSEM) - /* - * From 'Writing Reliable AIX Daemons,' SG24-4946-00, - * by Eric Agar (saves us from doing 32767 system - * calls) - */ - if (fcntl(0, F_CLOSEM, 0) == -1) - msyslog(LOG_ERR, "ntpd: failed to close open files(): %m"); -#else /* not F_CLOSEM */ - -# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) - max_fd = sysconf(_SC_OPEN_MAX); -# else /* HAVE_SYSCONF && _SC_OPEN_MAX */ - max_fd = getdtablesize(); -# endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ - for (s = 0; s < max_fd; s++) - (void) close((int)s); -#endif /* not F_CLOSEM */ - (void) open("/", 0); - (void) dup2(0, 1); - (void) dup2(0, 2); -#ifdef SYS_DOMAINOS - { - uid_$t puid; - status_$t st; - - proc2_$who_am_i(&puid); - proc2_$make_server(&puid, &st); - } -#endif /* SYS_DOMAINOS */ -#if defined(HAVE_SETPGID) || defined(HAVE_SETSID) -# ifdef HAVE_SETSID - if (setsid() == (pid_t)-1) - msyslog(LOG_ERR, "ntpd: setsid(): %m"); -# else - if (setpgid(0, 0) == -1) - msyslog(LOG_ERR, "ntpd: setpgid(): %m"); -# endif -#else /* HAVE_SETPGID || HAVE_SETSID */ - { -# if defined(TIOCNOTTY) - int fid; - - fid = open("/dev/tty", 2); - if (fid >= 0) - { - (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); - (void) close(fid); - } -# endif /* defined(TIOCNOTTY) */ -# ifdef HAVE_SETPGRP_0 - (void) setpgrp(); -# else /* HAVE_SETPGRP_0 */ - (void) setpgrp(0, getpid()); -# endif /* HAVE_SETPGRP_0 */ - } -#endif /* HAVE_SETPGID || HAVE_SETSID */ -#ifdef _AIX - /* Don't get killed by low-on-memory signal. */ - sa.sa_handler = catch_danger; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - - (void) sigaction(SIGDANGER, &sa, NULL); -#endif /* _AIX */ - } -# endif /* not HAVE_DAEMON */ -# else /* SYS_WINNT */ - - { - if (NoWinService == FALSE) { - SERVICE_TABLE_ENTRY dispatchTable[] = { - { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main }, - { NULL, NULL } - }; - - /* daemonize */ - if (!StartServiceCtrlDispatcher(dispatchTable)) - { - msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m"); - ExitProcess(2); - } - } - else { - service_main(argc, argv); - return 0; - } - } -# endif /* SYS_WINNT */ - } -# endif /* NODETACH */ -# if defined(SYS_WINNT) && !defined(NODETACH) - else - service_main(argc, argv); - return 0; /* must return a value */ -} /* end main */ - -/* - * If this runs as a service under NT, the main thread will block at - * StartServiceCtrlDispatcher() and another thread will be started by the - * Service Control Dispatcher which will begin execution at the routine - * specified in that call (viz. service_main) - */ -void -service_main( - DWORD argc, - LPTSTR *argv - ) -{ - char *cp; - struct recvbuf *rbuflist; - struct recvbuf *rbuf; - - if(!debug && NoWinService == FALSE) - { - /* register our service control handler */ - sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"), - (LPHANDLER_FUNCTION)service_ctrl); - if(sshStatusHandle == 0) - { - msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m"); - return; - } - - /* report pending status to Service Control Manager */ - ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ssStatus.dwCurrentState = SERVICE_START_PENDING; - ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - ssStatus.dwWin32ExitCode = NO_ERROR; - ssStatus.dwServiceSpecificExitCode = 0; - ssStatus.dwCheckPoint = 1; - ssStatus.dwWaitHint = 5000; - if (!SetServiceStatus(sshStatusHandle, &ssStatus)) - { - msyslog(LOG_ERR, "SetServiceStatus: %m"); - ssStatus.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(sshStatusHandle, &ssStatus); - return; - } - - } /* debug */ -# endif /* defined(SYS_WINNT) && !defined(NODETACH) */ -#endif /* VMS */ - - /* - * Logging. This may actually work on the gizmo board. Find a name - * to log with by using the basename of argv[0] - */ - cp = strrchr(argv[0], '/'); - if (cp == 0) - cp = argv[0]; - else - cp++; - - debug = 0; /* will be immediately re-initialized 8-( */ - getstartup(argc, argv); /* startup configuration, catch logfile this time */ - -#if !defined(VMS) - -# ifndef LOG_DAEMON - openlog(cp, LOG_PID); -# else /* LOG_DAEMON */ - -# ifndef LOG_NTP -# define LOG_NTP LOG_DAEMON -# endif - openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP); -# ifdef DEBUG - if (debug) - setlogmask(LOG_UPTO(LOG_DEBUG)); - else -# endif /* DEBUG */ - setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ -# endif /* LOG_DAEMON */ -#endif /* !SYS_WINNT && !VMS */ - - NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "%s", Version); - -#ifdef SYS_WINNT - /* GMS 1/18/1997 - * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions - * - process_handle = GetCurrentProcess(); - if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) { - if (VirtualLock(0 , 4194304) == FALSE) - msyslog(LOG_ERR, "VirtualLock() failed: %m"); - } else { - msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m"); - } - */ -#endif /* SYS_WINNT */ - -#ifdef SCO5_CLOCK - /* - * SCO OpenServer's system clock offers much more precise timekeeping - * on the base CPU than the other CPUs (for multiprocessor systems), - * so we must lock to the base CPU. - */ - { - int fd = open("/dev/at1", O_RDONLY); - if (fd >= 0) { - int zero = 0; - if (ioctl(fd, ACPU_LOCK, &zero) < 0) - msyslog(LOG_ERR, "cannot lock to base CPU: %m\n"); - close( fd ); - } /* else ... - * If we can't open the device, this probably just isn't - * a multiprocessor system, so we're A-OK. - */ - } -#endif - -#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE) -# ifdef HAVE_SETRLIMIT - /* - * Set the stack limit to something smaller, so that we don't lock a lot - * of unused stack memory. - */ - { - struct rlimit rl; - - if (getrlimit(RLIMIT_STACK, &rl) != -1 - && (rl.rlim_cur = 20 * 4096) < rl.rlim_max) - { - if (setrlimit(RLIMIT_STACK, &rl) == -1) - { - msyslog(LOG_ERR, - "Cannot adjust stack limit for mlockall: %m"); - } - } - } -# endif /* HAVE_SETRLIMIT */ - /* - * lock the process into memory - */ - if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) - msyslog(LOG_ERR, "mlockall(): %m"); -#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ -# ifdef HAVE_PLOCK -# ifdef PROCLOCK -# ifdef _AIX - /* - * set the stack limit for AIX for plock(). - * see get_aix_stack for more info. - */ - if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0) - { - msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m"); - } -# endif /* _AIX */ - /* - * lock the process into memory - */ - if (plock(PROCLOCK) < 0) - msyslog(LOG_ERR, "plock(PROCLOCK): %m"); -# else /* not PROCLOCK */ -# ifdef TXTLOCK - /* - * Lock text into ram - */ - if (plock(TXTLOCK) < 0) - msyslog(LOG_ERR, "plock(TXTLOCK) error: %m"); -# else /* not TXTLOCK */ - msyslog(LOG_ERR, "plock() - don't know what to lock!"); -# endif /* not TXTLOCK */ -# endif /* not PROCLOCK */ -# endif /* HAVE_PLOCK */ -#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ - - /* - * Set up signals we pay attention to locally. - */ -#ifdef SIGDIE1 - (void) signal_no_reset(SIGDIE1, finish); -#endif /* SIGDIE1 */ -#ifdef SIGDIE2 - (void) signal_no_reset(SIGDIE2, finish); -#endif /* SIGDIE2 */ -#ifdef SIGDIE3 - (void) signal_no_reset(SIGDIE3, finish); -#endif /* SIGDIE3 */ -#ifdef SIGDIE4 - (void) signal_no_reset(SIGDIE4, finish); -#endif /* SIGDIE4 */ - -#ifdef SIGBUS - (void) signal_no_reset(SIGBUS, finish); -#endif /* SIGBUS */ - -#if !defined(SYS_WINNT) && !defined(VMS) -# ifdef DEBUG - (void) signal_no_reset(MOREDEBUGSIG, moredebug); - (void) signal_no_reset(LESSDEBUGSIG, lessdebug); -# else - (void) signal_no_reset(MOREDEBUGSIG, no_debug); - (void) signal_no_reset(LESSDEBUGSIG, no_debug); -# endif /* DEBUG */ -#endif /* !SYS_WINNT && !VMS */ - - /* - * Set up signals we should never pay attention to. - */ -#if defined SIGPIPE - (void) signal_no_reset(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#if defined SYS_WINNT - if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) { - msyslog(LOG_ERR, "Can't set console control handler: %m"); - } -#endif - - /* - * Call the init_ routines to initialize the data structures. - */ -#if defined (HAVE_IO_COMPLETION_PORT) - init_io_completion_port(); - init_winnt_time(); -#endif - init_auth(); - init_util(); - init_restrict(); - init_mon(); - init_timer(); - init_lib(); - init_random(); - init_request(); - init_control(); - init_peer(); -#ifdef REFCLOCK - init_refclock(); -#endif - set_process_priority(); - init_proto(); /* Call at high priority */ - init_io(); - init_loopfilter(); - 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. 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 OPENSSL - crypto_setup(); -#endif /* OPENSSL */ - initializing = 0; - -#if defined(SYS_WINNT) && !defined(NODETACH) -# if defined(DEBUG) - if(!debug) - { -# endif - if (NoWinService == FALSE) { - /* report to the service control manager that the service is running */ - ssStatus.dwCurrentState = SERVICE_RUNNING; - ssStatus.dwWin32ExitCode = NO_ERROR; - if (!SetServiceStatus(sshStatusHandle, &ssStatus)) - { - msyslog(LOG_ERR, "SetServiceStatus: %m"); - if (ResolverThreadHandle != NULL) - CloseHandle(ResolverThreadHandle); - ssStatus.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(sshStatusHandle, &ssStatus); - return; - } - } -# if defined(DEBUG) - } -# endif -#endif - -#ifdef HAVE_CLOCKCTL - /* - * Drop super-user privileges and chroot now if the OS supports - * non root clock control (only NetBSD for now). - */ - if (user != NULL) { - if (isdigit((unsigned char)*user)) { - sw_uid = (uid_t)strtoul(user, &endp, 0); - if (*endp != '\0') - goto getuser; - } else { -getuser: - if ((pw = getpwnam(user)) != NULL) { - sw_uid = pw->pw_uid; - } else { - errno = 0; - msyslog(LOG_ERR, "Cannot find user `%s'", user); - exit (-1); - } - } - } - if (group != NULL) { - if (isdigit((unsigned char)*group)) { - sw_gid = (gid_t)strtoul(group, &endp, 0); - if (*endp != '\0') - goto getgroup; - } else { -getgroup: - if ((gr = getgrnam(group)) != NULL) { - sw_gid = pw->pw_gid; - } else { - errno = 0; - msyslog(LOG_ERR, "Cannot find group `%s'", group); - exit (-1); - } - } - } - if (chrootdir && chroot(chrootdir)) { - msyslog(LOG_ERR, "Cannot chroot to `%s': %m", chrootdir); - exit (-1); - } - if (group && setgid(sw_gid)) { - msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group); - exit (-1); - } - if (group && setegid(sw_gid)) { - msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group); - exit (-1); - } - if (user && setuid(sw_uid)) { - msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user); - exit (-1); - } - if (user && seteuid(sw_uid)) { - msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user); - exit (-1); - } -#endif - /* - * Report that we're up to any trappers - */ - report_event(EVNT_SYSRESTART, (struct peer *)0); - - /* - * Use select() on all on all input fd's for unlimited - * time. select() will terminate on SIGALARM or on the - * reception of input. Using select() means we can't do - * robust signal handling and we get a potential race - * between checking for alarms and doing the select(). - * Mostly harmless, I think. - */ - /* On VMS, I suspect that select() can't be interrupted - * by a "signal" either, so I take the easy way out and - * have select() time out after one second. - * System clock updates really aren't time-critical, - * and - lacking a hardware reference clock - I have - * yet to learn about anything else that is. - */ -#if defined(HAVE_IO_COMPLETION_PORT) - WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */ - WaitHandles[1] = get_timer_handle(); - WaitHandles[2] = get_io_event(); - - for (;;) { - DWORD Index = WaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, FALSE, 1000, TRUE); - switch (Index) { - case WAIT_OBJECT_0 + 0 : /* exit request */ - exit(0); - break; - - case WAIT_OBJECT_0 + 1 : /* timer */ - timer(); - break; - - case WAIT_OBJECT_0 + 2 : /* Io event */ -# ifdef DEBUG - if ( debug > 3 ) - { - printf( "IoEvent occurred\n" ); - } -# endif - break; - - case WAIT_IO_COMPLETION : /* loop */ - case WAIT_TIMEOUT : - break; - case WAIT_FAILED: - msyslog(LOG_ERR, "ntpdc: WaitForMultipleObjectsEx Failed: Error: %m"); - break; - - /* For now do nothing if not expected */ - default: - break; - - } /* switch */ - rbuflist = getrecvbufs(); /* get received buffers */ - -#else /* normal I/O */ - - was_alarmed = 0; - rbuflist = (struct recvbuf *)0; - for (;;) - { -# if !defined(HAVE_SIGNALED_IO) - extern fd_set activefds; - extern int maxactivefd; - - fd_set rdfdes; - int nfound; -# elif defined(HAVE_SIGNALED_IO) - block_io_and_alarm(); -# endif - - rbuflist = getrecvbufs(); /* get received buffers */ - if (alarm_flag) /* alarmed? */ - { - was_alarmed = 1; - alarm_flag = 0; - } - - if (!was_alarmed && rbuflist == (struct recvbuf *)0) - { - /* - * Nothing to do. Wait for something. - */ -# ifndef HAVE_SIGNALED_IO - rdfdes = activefds; -# if defined(VMS) || defined(SYS_VXWORKS) - /* make select() wake up after one second */ - { - struct timeval t1; - - t1.tv_sec = 1; t1.tv_usec = 0; - nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, - (fd_set *)0, &t1); - } -# else - nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, - (fd_set *)0, (struct timeval *)0); -# endif /* VMS */ - if (nfound > 0) - { - l_fp ts; - - get_systime(&ts); - - (void)input_handler(&ts); - } - else if (nfound == -1 && errno != EINTR) - msyslog(LOG_ERR, "select() error: %m"); -# ifdef DEBUG - else if (debug > 2) - msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); -# endif /* DEBUG */ -# else /* HAVE_SIGNALED_IO */ - - wait_for_signal(); -# endif /* HAVE_SIGNALED_IO */ - if (alarm_flag) /* alarmed? */ - { - was_alarmed = 1; - alarm_flag = 0; - } - rbuflist = getrecvbufs(); /* get received buffers */ - } -# ifdef HAVE_SIGNALED_IO - unblock_io_and_alarm(); -# endif /* HAVE_SIGNALED_IO */ - - /* - * Out here, signals are unblocked. Call timer routine - * to process expiry. - */ - if (was_alarmed) - { - timer(); - was_alarmed = 0; - } - -#endif /* HAVE_IO_COMPLETION_PORT */ - /* - * Call the data procedure to handle each received - * packet. - */ - while (rbuflist != (struct recvbuf *)0) - { - rbuf = rbuflist; - rbuflist = rbuf->next; - (rbuf->receiver)(rbuf); - freerecvbuf(rbuf); - } -#if defined DEBUG && defined SYS_WINNT - if (debug > 4) - printf("getrecvbufs: %ld handler interrupts, %ld frames\n", - handler_calls, handler_pkts); -#endif - - /* - * Go around again - */ - } -#ifndef SYS_WINNT - exit(1); /* unreachable */ -#endif -#ifndef SYS_WINNT - return 1; /* DEC OSF cc braindamage */ -#endif -} - - -#ifdef SIGDIE2 -/* - * finish - exit gracefully - */ -static RETSIGTYPE -finish( - int sig - ) -{ - - msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig); - - switch (sig) - { -# ifdef SIGBUS - case SIGBUS: - printf("\nfinish(SIGBUS)\n"); - exit(0); -# endif - case 0: /* Should never happen... */ - return; - default: - exit(0); - } -} -#endif /* SIGDIE2 */ - - -#ifdef DEBUG -#ifndef SYS_WINNT -/* - * moredebug - increase debugging verbosity - */ -static RETSIGTYPE -moredebug( - int sig - ) -{ - int saved_errno = errno; - - if (debug < 255) - { - debug++; - msyslog(LOG_DEBUG, "debug raised to %d", debug); - } - errno = saved_errno; -} - -/* - * lessdebug - decrease debugging verbosity - */ -static RETSIGTYPE -lessdebug( - int sig - ) -{ - int saved_errno = errno; - - if (debug > 0) - { - debug--; - msyslog(LOG_DEBUG, "debug lowered to %d", debug); - } - errno = saved_errno; -} -#endif -#else /* not DEBUG */ -#ifndef SYS_WINNT/* - * no_debug - We don't do the debug here. - */ -static RETSIGTYPE -no_debug( - int sig - ) -{ - int saved_errno = errno; - - msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig); - errno = saved_errno; -} -#endif /* not SYS_WINNT */ -#endif /* not DEBUG */ - -#ifdef SYS_WINNT -/* service_ctrl - control handler for NTP service - * signals the service_main routine of start/stop requests - * from the control panel or other applications making - * win32API calls - */ -void -service_ctrl( - DWORD dwCtrlCode - ) -{ - DWORD dwState = SERVICE_RUNNING; - - /* Handle the requested control code */ - switch(dwCtrlCode) - { - case SERVICE_CONTROL_PAUSE: - /* see no reason to support this */ - break; - - case SERVICE_CONTROL_CONTINUE: - /* see no reason to support this */ - break; - - case SERVICE_CONTROL_STOP: - dwState = SERVICE_STOP_PENDING; - /* - * Report the status, specifying the checkpoint and waithint, - * before setting the termination event. - */ - ssStatus.dwCurrentState = dwState; - ssStatus.dwWin32ExitCode = NO_ERROR; - ssStatus.dwWaitHint = 3000; - if (!SetServiceStatus(sshStatusHandle, &ssStatus)) - { - msyslog(LOG_ERR, "SetServiceStatus: %m"); - } - if (WaitHandles[0] != NULL) { - SetEvent(WaitHandles[0]); - } - return; - - case SERVICE_CONTROL_INTERROGATE: - /* Update the service status */ - break; - - default: - /* invalid control code */ - break; - - } - - ssStatus.dwCurrentState = dwState; - ssStatus.dwWin32ExitCode = NO_ERROR; - if (!SetServiceStatus(sshStatusHandle, &ssStatus)) - { - msyslog(LOG_ERR, "SetServiceStatus: %m"); - } -} - -static BOOL WINAPI -OnConsoleEvent( - DWORD dwCtrlType - ) -{ - switch (dwCtrlType) { - case CTRL_BREAK_EVENT : - if (debug > 0) { - debug <<= 1; - } - else { - debug = 1; - } - if (debug > 8) { - debug = 0; - } - printf("debug level %d\n", debug); - break ; - - case CTRL_C_EVENT : - case CTRL_CLOSE_EVENT : - case CTRL_SHUTDOWN_EVENT : - if (WaitHandles[0] != NULL) { - SetEvent(WaitHandles[0]); - } - break; - - default : - return FALSE; - - - } - return TRUE;; -} - - -/* - * NT version of exit() - all calls to exit() should be routed to - * this function. - */ -void -service_exit( - int status - ) -{ - if (!debug) { /* did not become a service, simply exit */ - /* service mode, need to have the service_main routine - * register with the service control manager that the - * service has stopped running, before exiting - */ - ssStatus.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(sshStatusHandle, &ssStatus); - - } - uninit_io_completion_port(); - reset_winnt_time(); - -# if defined _MSC_VER - _CrtDumpMemoryLeaks(); -# endif -#undef exit - exit(status); -} - -#endif /* SYS_WINNT */ diff --git a/contrib/ntp/ntpd/ntpsim.c b/contrib/ntp/ntpd/ntpsim.c deleted file mode 100644 index 3fbae17..0000000 --- a/contrib/ntp/ntpd/ntpsim.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * NTP simulator engine - Harish Nair - * University of Delaware, 2001 - */ -#include "ntpd.h" -#include "ntpsim.h" - -/* - * Defines... - */ -#define SIM_TIME 86400 /* end simulation time */ -#define NET_DLY .001 /* network delay */ -#define PROC_DLY .001 /* processing delay */ -#define BEEP_DLY 3600 /* beep interval (s) */ -#define SLEW 500e-6 /* correction rate (PPM) */ - -/* - * Function pointers - */ -void (*funcPtr[]) (Node *, Event) = { - &ndbeep, &ndeclk, &ntptmr, &netpkt -}; - - -/* - * ntpsim - initialize global variables and event queue and start - */ -int -ntpsim( - int argc, - char *argv[] - ) -{ - Event e; - double maxtime; - struct timeval seed; - - /* - * Initialize the global node - */ - ntp_node.time = 0; /* simulation time */ - ntp_node.sim_time = SIM_TIME; /* end simulation time (-S) */ - ntp_node.ntp_time = 0; /* client disciplined time */ - ntp_node.adj = 0; /* remaining time correction */ - ntp_node.slew = SLEW; /* correction rate (-H) */ - - ntp_node.clk_time = 0; /* server time (-O) */ - ntp_node.ferr = 0; /* frequency error (-T) */ - ntp_node.fnse = 0; /* random walk noise (-W) */ - ntp_node.ndly = NET_DLY; /* network delay (-Y) */ - ntp_node.snse = 0; /* phase noise (-C) */ - ntp_node.pdly = PROC_DLY; /* processing delay (-Z) */ - ntp_node.bdly = BEEP_DLY; /* beep interval (-B) */ - - ntp_node.events = NULL; - ntp_node.rbuflist = NULL; - - /* - * Initialize ntp variables - */ - initializing = 1; - init_auth(); - init_util(); - init_restrict(); - init_mon(); - init_timer(); - init_lib(); - init_random(); - init_request(); - init_control(); - init_peer(); - init_proto(); - init_io(); - init_loopfilter(); - mon_start(MON_OFF); - getconfig(argc, argv); - initializing = 0; - - /* - * Watch out here, we want the real time, not the silly stuff. - */ - gettimeofday(&seed, NULL); - srand48(seed.tv_usec); - - /* - * Push a beep and timer interrupt on the queue - */ - push(event(0, BEEP), &ntp_node.events); - push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events); - - /* - * Pop the queue until nothing is left or time is exceeded - */ - maxtime = ntp_node.time + ntp_node.sim_time; - while (ntp_node.time <= maxtime && ntp_node.events != NULL ) { - e = pop(&ntp_node.events); - ndeclk(&ntp_node, e); - funcPtr[e.function](&ntp_node, e); - } - return (0); -} - - -/* - * Return an event - */ -Event -event( - double t, - funcTkn f - ) -{ - Event e; - - e.time = t; - e.function = f; - return (e); -} - -/* - * Create an event queue - */ -Queue -queue( - Event e, - Queue q - ) -{ - Queue ret; - - if ((ret = (Queue)malloc(sizeof(struct List))) == NULL) - abortsim("queue-malloc"); - ret->event = e; - ret->next = q; - return (ret); -} - - -/* - * Push an event into the event queue - */ -void push( - Event e, - Queue *qp - ) -{ - Queue *tmp = qp; - - while (*tmp != NULL && ((*tmp)->event.time < e.time)) - tmp = &((*tmp)->next); - *tmp = queue(e, (*tmp)); -} - - -/* - * Pop the first event from the event queue - */ -Event -pop( - Queue *qp - ) -{ - Event ret; - Queue tmp; - - tmp = *qp; - if (tmp == NULL) - abortsim("pop - empty queue"); - ret = tmp->event; - *qp = tmp->next; - free(tmp); - return (ret); -} - - -/* - * Update clocks - */ -void -ndeclk( - Node *n, - Event e - ) -{ - node_clock(n, e.time); -} - - -/* - * Timer interrupt. Eventually, this results in calling the - * srvr_rplyi() routine below. - */ -void -ntptmr( - Node *n, - Event e - ) -{ - struct recvbuf *rbuf; - - timer(); - - /* - * Process buffers received. They had better be in order by - * receive timestamp. - */ - while (n->rbuflist != NULL) { - rbuf = n->rbuflist; - n->rbuflist = rbuf->next; - (rbuf->receiver)(rbuf); - free(rbuf); - } - - /* - * Arm the next timer interrupt. - */ - push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events); -} - - -/* - * srvr_rply() - send packet - */ -int srvr_rply( - Node *n, - struct sockaddr_storage *dest, - struct interface *inter, struct pkt *rpkt - ) -{ - struct pkt xpkt; - struct recvbuf rbuf; - Event xvnt; - double dtemp, etemp; - - /* - * Insert packet header values. We make this look like a - * stratum-1 server with a GPS clock, but nobody will ever - * notice that. - */ - xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, - MODE_SERVER); - xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); - memcpy(&xpkt.refid, "GPS", 4); - xpkt.ppoll = rpkt->ppoll; - xpkt.precision = rpkt->precision; - xpkt.rootdelay = 0; - xpkt.rootdispersion = 0; - - /* - * Insert the timestamps. - */ - xpkt.org = rpkt->xmt; - dtemp = poisson(n->ndly, n->snse); /* client->server delay */ - DTOLFP(dtemp + n->clk_time, &xpkt.rec); - dtemp += poisson(n->pdly, 0); /* server delay */ - DTOLFP(dtemp + n->clk_time, &xpkt.xmt); - xpkt.reftime = xpkt.xmt; - dtemp += poisson(n->ndly, n->snse); /* server->client delay */ - - /* - * Insert the I/O stuff. - */ - rbuf.receiver = receive; - get_systime(&rbuf.recv_time); - rbuf.recv_length = LEN_PKT_NOMAC; - rbuf.recv_pkt = xpkt; - memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage)); - memcpy(&rbuf.recv_srcadr, dest, - sizeof(struct sockaddr_storage)); - if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL) - abortsim("server-malloc"); - memcpy(rbuf.dstadr, inter, sizeof(struct interface)); - rbuf.next = NULL; - - /* - * Very carefully predict the time of arrival for the received - * packet. - */ - LFPTOD(&xpkt.org, etemp); - etemp += dtemp; - xvnt = event(etemp, PACKET); - xvnt.rcv_buf = rbuf; - push(xvnt, &n->events); - return (0); -} - - -/* - * netpkt() - receive packet - */ -void -netpkt( - Node *n, - Event e - ) -{ - struct recvbuf *rbuf; - struct recvbuf *obuf; - - /* - * Insert the packet on the receive queue and record the arrival - * time. - */ - if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL) - abortsim("ntprcv-malloc"); - memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf)); - rbuf->receiver = receive; - DTOLFP(n->ntp_time, &rbuf->recv_time); - rbuf->next = NULL; - obuf = n->rbuflist; - - /* - * In the present incarnation, no more than one buffer can be on - * the queue; however, we sniff the queue anyway as a hint for - * further development. - */ - if (obuf == NULL) { - n->rbuflist = rbuf; - } else { - while (obuf->next != NULL) - obuf = obuf->next; - obuf->next = rbuf; - } -} - - -/* - * ndbeep() - progress indicator - */ -void -ndbeep( - Node *n, - Event e - ) -{ - static int first_time = 1; - char *dash = "-----------------"; - - if(n->bdly > 0) { - if (first_time) { - printf( - "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' '); - printf("\t%s\t%s\t%s\n", dash, dash, dash); - first_time = 0; - push(event(n->bdly, BEEP), &n->events); - push(event(n->sim_time, BEEP), &n->events); - printf("\t%16.6f\t%16.6f\t%16.6f\n", - n->time, n->clk_time, n->ntp_time); - return; - } - printf("\t%16.6f\t%16.6f\t%16.6f\n", - n->time, n->clk_time, n->ntp_time); - push(event(e.time + n->bdly, BEEP), &n->events); - } -} - - -/* - * Abort simulation - */ -void -abortsim( - char *errmsg - ) -{ - perror(errmsg); - exit(1); -} diff --git a/contrib/ntp/ntpd/refclock_acts.c b/contrib/ntp/ntpd/refclock_acts.c deleted file mode 100644 index d26ceed..0000000 --- a/contrib/ntp/ntpd/refclock_acts.c +++ /dev/null @@ -1,984 +0,0 @@ -/* - * refclock_acts - clock driver for the NIST/PTB Automated Computer Time - * Service aka Amalgamated Containerized Trash Service (ACTS) - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS)) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_refclock.h" -#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) -# if defined(KEEPPTBACTS) -# undef CLOCK_ACTS -# else /* not KEEPPTBACTS */ -# undef CLOCK_PTBACTS -# endif /* not KEEPPTBACTS */ -#endif /* CLOCK_ACTS && CLOCK_PTBACTS */ - -/* - * This driver supports the NIST Automated Computer Time Service (ACTS). - * It periodically dials a prespecified telephone number, receives the - * NIST timecode data and calculates the local clock correction. It is - * designed primarily for use as a backup when neither a radio clock nor - * connectivity to Internet time servers is available. For the best - * accuracy, the individual telephone line/modem delay needs to be - * calibrated using outside sources. - * - * The ACTS is located at NIST Boulder, CO, telephone 303 494 4774. A - * toll call from a residence telephone in Newark, DE, costs between 14 - * and 27 cents, depending on time of day, and from a campus telephone - * between 3 and 4 cents, although it is not clear what carrier and time - * of day discounts apply in this case. The modem dial string will - * differ depending on local telephone configuration, etc., and is - * specified by the phone command in the configuration file. The - * argument to this command is an AT command for a Hayes compatible - * modem. - * - * The accuracy produced by this driver should be in the range of a - * millisecond or two, but may need correction due to the delay - * characteristics of the individual modem involved. For undetermined - * reasons, some modems work with the ACTS echo-delay measurement scheme - * and some don't. This driver tries to do the best it can with what it - * gets. Initial experiments with a Practical Peripherals 9600SA modem - * here in Delaware suggest an accuracy of a millisecond or two can be - * achieved without the scheme by using a fudge time1 value of 65.0 ms. - * In either case, the dispersion for a single call involving ten - * samples is about 1.3 ms. - * - * The driver can operate in either of three modes, as determined by - * the mode parameter in the server configuration command. In mode 0 - * (automatic) the driver operates continuously at intervals depending - * on the prediction error, as measured by the driver, usually in the - * order of several hours. In mode 1 (backup) the driver is enabled in - * automatic mode only when no other source of synchronization is - * available and when more than MAXOUTAGE (3600 s) have elapsed since - * last synchronized by other sources. In mode 2 (manual) the driver - * operates only when enabled using a fudge flags switch, as described - * below. - * - * For reliable call management, this driver requires a 1200-bps modem - * with a Hayes-compatible command set and control over the modem data - * terminal ready (DTR) control line. Present restrictions require the - * use of a POSIX-compatible programming interface, although other - * interfaces may work as well. The modem setup string is hard-coded in - * the driver and may require changes for nonstandard modems or special - * circumstances. - * - * Further information can be found in the README.refclock file in the - * ntp - Version 3 distribution. - * - * Fudge Factors - * - * Ordinarily, the propagation time correction is computed automatically - * by ACTS and the driver. When this is not possible or erratic due to - * individual modem characteristics, the fudge flag2 switch should be - * set to disable the ACTS echo-delay scheme. In any case, the fudge - * time1 parameter can be used to adjust the propagation delay as - * required. - * - * The ACTS call interval is determined in one of three ways. In manual - * mode a call is initiated by setting fudge flag1 using ntpdc, either - * manually or via a cron job. In AUTO mode this flag is set by the peer - * timer, which is controlled by the sys_poll variable in response to - * measured errors. In backup mode the driver is ordinarily asleep, but - * awakes (in auto mode) if all other synchronization sources are lost. - * In either auto or backup modes, the call interval increases as long - * as the measured errors do not exceed the value of the fudge time2 - * parameter. - * - * When the fudge flag1 is set, the ACTS calling program is activated. - * This program dials each number listed in the phones command of the - * configuration file in turn. If a call attempt fails, the next number - * in the list is dialed. The fudge flag1 and counter are reset and the - * calling program terminated if (a) a valid clock update has been - * determined, (b) no more numbers remain in the list, (c) a device - * fault or timeout occurs or (d) fudge flag1 is reset manually using - * ntpdc. - * - * In automatic and backup modes, the driver determines the call - * interval using a procedure depending on the measured prediction - * error and the fudge time2 parameter. If the error exceeds time2 for a - * number of times depending on the current interval, the interval is - * decreased, but not less than about 1000 s. If the error is less than - * time2 for some number of times, the interval is increased, but not - * more than about 18 h. With the default value of zero for fudge time2, - * the interval will increase from 1000 s to the 4000-8000-s range, in - * which the expected accuracy should be in the 1-2-ms range. Setting - * fudge time2 to a large value, like 0.1 s, may result in errors of - * that order, but increase the call interval to the maximum. The exact - * value for each configuration will depend on the modem and operating - * system involved, so some experimentation may be necessary. - */ - -/* - * DESCRIPTION OF THE AUTOMATED COMPUTER TELEPHONE SERVICE (ACTS) - * (reformatted from ACTS on-line computer help information) - * - * The following is transmitted (at 1200 baud) following completion of - * the telephone connection. - * - * National Institute of Standards and Technology - * Telephone Time Service, Generator 3B - * Enter question mark "?" for HELP - * D L D - * MJD YR MO DA H M S ST S UT1 msADV <OTM> - * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) * - * 47999 90-04-18 21:39:16 50 0 +.1 045.0 UTC(NIST) * - * 47999 90-04-18 21:39:17 50 0 +.1 045.0 UTC(NIST) * - * 47999 90-04-18 21:39:18 50 0 +.1 045.0 UTC(NIST) * - * 47999 90-04-18 21:39:19 50 0 +.1 037.6 UTC(NIST) # - * 47999 90-04-18 21:39:20 50 0 +.1 037.6 UTC(NIST) # - * etc..etc...etc....... - * - * UTC = Universal Time Coordinated, the official world time referred to - * the zero meridian. - * - * DST Daylight savings time characters, valid for the continental - * U.S., are set as follows: - * - * 00 We are on standard time (ST). - * 01-49 Now on DST, go to ST when your local time is 2:00 am and - * the count is 01. The count is decremented daily at 00 - * (UTC). - * 50 We are on DST. - * 51-99 Now on ST, go to DST when your local time is 2:00 am and - * the count is 51. The count is decremented daily at 00 - * (UTC). - * - * The two DST characters provide up to 48 days advance notice of a - * change in time. The count remains at 00 or 50 at other times. - * - * LS Leap second flag is set to "1" to indicate that a leap second is - * to be added as 23:59:60 (UTC) on the last day of the current UTC - * month. The LS flag will be reset to "0" starting with 23:59:60 - * (UTC). The flag will remain on for the entire month before the - * second is added. Leap seconds are added as needed at the end of - * any month. Usually June and/or December are chosen. - * - * The leap second flag will be set to a "2" to indicate that a - * leap second is to be deleted at 23:59:58--00:00:00 on the last - * day of the current month. (This latter provision is included per - * international recommendation, however it is not likely to be - * required in the near future.) - * - * DUT1 Approximate difference between earth rotation time (UT1) and - * UTC, in steps of 0.1 second: DUT1 = UT1 - UTC. - * - * MJD Modified Julian Date, often used to tag certain scientific data. - * - * The full time format is sent at 1200 baud, 8 bit, 1 stop, no parity. - * The format at 300 Baud is also 8 bit, 1 stop, no parity. At 300 Baud - * the MJD and DUT1 values are deleted and the time is transmitted only - * on even seconds. - * - * Maximum on line time will be 56 seconds. If all lines are busy at any - * time, the oldest call will be terminated if it has been on line more - * than 28 seconds, otherwise, the call that first reaches 28 seconds - * will be terminated. - * - * Current time is valid at the "on-time" marker (OTM), either "*" or - * "#". The nominal on-time marker (*) will be transmitted 45 ms early - * to account for the 8 ms required to send 1 character at 1200 Baud, - * plus an additional 7 ms for delay from NIST to the user, and - * approximately 30 ms "scrambler" delay inherent in 1200 Baud modems. - * If the caller echoes all characters, NIST will measure the round trip - * delay and advance the on-time marker so that the midpoint of the stop - * bit arrives at the user on time. The amount of msADV will reflect the - * actual required advance in milliseconds and the OTM will be a "#". - * - * (The NIST system requires 4 or 5 consecutive delay measurements which - * are consistent before switching from "*" to "#". If the user has a - * 1200 Baud modem with the same internal delay as that used by NIST, - * then the "#" OTM should arrive at the user within +-2 ms of the - * correct time. - * - * However, NIST has studied different brands of 1200 Baud modems and - * found internal delays from 24 ms to 40 ms and offsets of the "#" OTM - * of +-10 ms. For many computer users, +-10 ms accuracy should be more - * than adequate since many computer internal clocks can only be set - * with granularity of 20 to 50 ms. In any case, the repeatability of - * the offset for the "#" OTM should be within +-2 ms, if the dial-up - * path is reciprocal and the user doesn't change the brand or model of - * modem used. - * - * This should be true even if the dial-up path on one day is a land- - * line of less than 40 ms (one way) and on the next day is a satellite - * link of 260 to 300 ms. In the rare event that the path is one way by - * satellite and the other way by land line with a round trip - * measurement in the range of 90 to 260 ms, the OTM will remain a "*" - * indicating 45 ms advance. - * - * For user comments write: - * NIST-ACTS - * Time and Frequency Division - * Mail Stop 847 - * 325 Broadway - * Boulder, CO 80303 - * - * Software for setting (PC)DOS compatable machines is available on a - * 360-kbyte diskette for $35.00 from: NIST Office of Standard Reference - * Materials B311-Chemistry Bldg, NIST, Gaithersburg, MD, 20899, (301) - * 975-6776 - * - * PTB timecode service (+49 531 512038) - * The Physikalisch-Technische Bundesanstalt (Germany) - * also supports a modem time service - * as the data formats are very similar this driver can also be compiled for - * utilizing the PTB time code service. - * - * Data format - * 0000000000111111111122222222223333333333444444444455555555556666666666777777777 7 - * 0123456789012345678901234567890123456789012345678901234567890123456789012345678 9 - * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500 * - * A B C D EF G H IJ K L M N O P Q R S T U V W XY Z<CR><LF> - * - * A year - * B month - * C day - * D hour - * E : normally - * A for DST to ST switch first hour - * B for DST to ST switch second hour if not marked in H - * F minute - * G second - * H timezone - * I day of week - * J week of year - * K day of year - * L month for next ST/DST changes - * M day - * N hour - * O UTC year - * P UTC month - * Q UTC day - * R UTC hour - * S UTC minute - * T modified julian day (MJD) - * U DUT1 - * V direction and month if leap second - * W signal delay (assumed/measured) - * X sequence number for additional text line in Y - * Y additional text - * Z on time marker (* - assumed delay / # measured delay) - * <CR>!<LF> ! is second change ! - * - * This format is also used by the National Physical Laboratory (NPL)'s - * TRUETIME service in the UK. In this case the timezone field is - * UTC+0 or UTC+1 for standard and daylight saving time. The phone - * number for this service (a premium rate number) is 0891 516 333. - * It is not clear whether the echo check is implemented. - * - * For more detail, see http://www.npl.co.uk/npl/cetm/taf/truetime.html. - */ - -/* - * Interface definitions - */ -#define SPEED232 B1200 /* uart speed (1200 cowardly baud) */ -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#ifdef CLOCK_ACTS -# define REFID "ACTS" /* reference ID */ -# define DESCRIPTION "NIST Automated Computer Time Service" /* WRU */ -# define LENCODE 50 /* length of valid timecode string */ -# define DEVICE "/dev/acts%d" /* device name and unit */ -# define REF_ENTRY refclock_acts -#else /* not CLOCK_ACTS */ -# define REFID "TPTB" /* reference ID */ -# define DESCRIPTION "PTB Automated Computer Time Service" -# define LENCODE 78 /* length of valid timecode string */ -# define DEVICE "/dev/ptb%d" /* device name and unit */ -# define REF_ENTRY refclock_ptb -#endif /* not CLOCK_ACTS */ -#define MODE_AUTO 0 /* automatic mode */ -#define MODE_BACKUP 1 /* backup mode */ -#define MODE_MANUAL 2 /* manual mode */ - -#define MSGCNT 10 /* we need this many ACTS messages */ -#define SMAX 80 /* max token string length */ -#define ACTS_MINPOLL 10 /* log2 min poll interval (1024 s) */ -#define ACTS_MAXPOLL 18 /* log2 max poll interval (16384 s) */ -#define MAXOUTAGE 3600 /* max before ACTS kicks in (s) */ - -/* - * Modem control strings. These may have to be changed for some modems. - * - * AT command prefix - * B1 initiate call negotiation using Bell 212A - * &C1 enable carrier detect - * &D2 hang up and return to command mode on DTR transition - * E0 modem command echo disabled - * l1 set modem speaker volume to low level - * M1 speaker enabled untill carrier detect - * Q0 return result codes - * V1 return result codes as English words - */ -#define MODEM_SETUP "ATB1&C1&D2E0L1M1Q0V1" /* modem setup */ -#define MODEM_HANGUP "ATH" /* modem disconnect */ - -/* - * Timeouts - */ -#define IDLE 60 /* idle timeout (s) */ -#define WAIT 2 /* wait timeout (s) */ -#define ANSWER 30 /* answer timeout (s) */ -#define CONNECT 10 /* connect timeout (s) */ -#define TIMECODE 15 /* timecode timeout (s) */ - -/* - * Tables to compute the ddd of year form icky dd/mm timecode. Viva la - * leap. - */ -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}; - -/* - * Unit control structure - */ -struct actsunit { - int pollcnt; /* poll message counter */ - int state; /* the first one was Delaware */ - int run; /* call program run switch */ - int msgcnt; /* count of ACTS messages received */ - long redial; /* interval to next automatic call */ - double msADV; /* millisecond advance of last message */ -}; - -/* - * Function prototypes - */ -static int acts_start P((int, struct peer *)); -static void acts_shutdown P((int, struct peer *)); -static void acts_receive P((struct recvbuf *)); -static void acts_poll P((int, struct peer *)); -static void acts_timeout P((struct peer *)); -static void acts_disc P((struct peer *)); -static int acts_write P((struct peer *, const char *)); - -/* - * Transfer vector (conditional structure name) - */ -struct refclock REF_ENTRY = { - acts_start, /* start up driver */ - acts_shutdown, /* shut down driver */ - acts_poll, /* transmit poll message */ - noentry, /* not used (old acts_control) */ - noentry, /* not used (old acts_init) */ - noentry, /* not used (old acts_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * acts_start - open the devices and initialize data for processing - */ - -static int -acts_start ( - int unit, - struct peer *peer - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - int dtr = TIOCM_DTR; - - /* - * Open serial port. Use ACTS line discipline, if available. It - * pumps a timestamp into the data stream at every on-time - * character '*' found. Note: the port must have modem control - * or deep pockets for the phone bill. HP-UX 9.03 users should - * have very deep pockets. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS))) - return (0); - if (ioctl(fd, TIOCMBIS, (char *)&dtr) < 0) { - msyslog(LOG_ERR, "clock %s ACTS no modem control", - ntoa(&peer->srcadr)); - return (0); - } - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct actsunit *) - emalloc(sizeof(struct actsunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct actsunit)); - pp = peer->procptr; - pp->io.clock_recv = acts_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - peer->minpoll = ACTS_MINPOLL; - peer->maxpoll = ACTS_MAXPOLL; - peer->sstclktype = CTL_SST_TS_TELEPHONE; - - /* - * Initialize modem and kill DTR. We skedaddle if this comes - * bum. - */ - if (!acts_write(peer, MODEM_SETUP)) { - (void) close(fd); - free(up); - return (0); - } - - /* - * Set up the driver timeout - */ - peer->nextdate = current_time + WAIT; - return (1); -} - - -/* - * acts_shutdown - shut down the clock - */ -static void -acts_shutdown ( - int unit, - struct peer *peer - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * acts_receive - receive data from the serial interface - */ -static void -acts_receive ( - struct recvbuf *rbufp - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - struct peer *peer; - char str[SMAX]; - int i; - char hangup = '%'; /* ACTS hangup */ - int day; /* day of the month */ - int month; /* month of the year */ - u_long mjd; /* Modified Julian Day */ - double dut1; /* DUT adjustment */ - double msADV; /* ACTS transmit advance (ms) */ - char flag; /* calibration flag */ -#ifndef CLOCK_PTBACTS - char utc[10]; /* this is NIST and you're not */ - u_int dst; /* daylight/standard time indicator */ - u_int leap; /* leap-second indicator */ -#else - char leapdir; /* leap direction */ - u_int leapmonth; /* month of leap */ -#endif - /* - * Initialize pointers and read the timecode and timestamp. If - * the OK modem status code, leave it where folks can find it. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, - &pp->lastrec); - if (pp->lencode == 0) { - if (strcmp(pp->a_lastcode, "OK") == 0) - pp->lencode = 2; - return; - } -#ifdef DEBUG - if (debug) - printf("acts: state %d timecode %d %*s\n", up->state, - pp->lencode, pp->lencode, pp->a_lastcode); -#endif - - switch (up->state) { - - case 0: - - /* - * State 0. We are not expecting anything. Probably - * modem disconnect noise. Go back to sleep. - */ - return; - - case 1: - - /* - * State 1. We are waiting for the call to be answered. - * All we care about here is CONNECT as the first token - * in the string. If the modem signals BUSY, ERROR, NO - * ANSWER, NO CARRIER or NO DIALTONE, we immediately - * hang up the phone. If CONNECT doesn't happen after - * ANSWER seconds, hang up the phone. If everything is - * okay, start the connect timeout and slide into state - * 2. - */ - if( strcmp(pp->a_lastcode, " ") == 0) { - acts_disc(peer); - return; - } - if( strcmp(sys_phone[0],"DIRECT") != 0 ) { - (void)strncpy(str, strtok(pp->a_lastcode, " "), SMAX); - if (strcmp(str, "BUSY") == 0 || strcmp(str, "ERROR") == - 0 || strcmp(str, "NO") == 0) { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s ACTS modem status %s", - ntoa(&peer->srcadr), pp->a_lastcode); - acts_disc(peer); - } else if (strcmp(str, "CONNECT") == 0) { - peer->nextdate = current_time + CONNECT; - up->msgcnt = 0; - up->state++; - } - } else { - (void) strncpy(str,"CONNECT",7); - peer->nextdate = current_time + CONNECT; - up->msgcnt = 0; - up->state++; - } - return; - - case 2: - - /* - * State 2. The call has been answered and we are - * waiting for the first ACTS message. If this doesn't - * happen within the timecode timeout, hang up the - * phone. We probably got a wrong number or ACTS is - * down. - */ - peer->nextdate = current_time + TIMECODE; - up->state++; - } - - /* - * Real yucky things here. Ignore everything except timecode - * messages, as determined by the message length. We told the - * terminal routines to end the line with '*' and the line - * discipline to strike a timestamp on that character. However, - * when the ACTS echo-delay scheme works, the '*' eventually - * becomes a '#'. In this case the message is ended by the <CR> - * that comes about 200 ms after the '#' and the '#' cannot be - * echoed at the proper time. But, this may not be a lose, since - * we already have good data from prior messages and only need - * the millisecond advance calculated by ACTS. So, if the - * message is long enough and has an on-time character at the - * right place, we consider the message (but not neccesarily the - * timestmap) to be valid. - */ - if (pp->lencode != LENCODE) - return; - -#ifndef CLOCK_PTBACTS - /* - * We apparently have a valid timecode message, so dismember it - * with sscan(). This routine does a good job in spotting syntax - * errors without becoming overly pedantic. - * - * D L D - * MJD YR MO DA H M S ST S UT1 msADV OTM - * 47222 88-03-02 21:39:15 83 0 +.3 045.0 UTC(NBS) * - */ - if (sscanf(pp->a_lastcode, - "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %s %c", - &mjd, &pp->year, &month, &day, &pp->hour, &pp->minute, - &pp->second, &dst, &leap, &dut1, &msADV, utc, &flag) != 13) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } -#else - /* - * Data format - * 0000000000111111111122222222223333333333444444444455555555556666666666777777777 7 - * 0123456789012345678901234567890123456789012345678901234567890123456789012345678 9 - * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500 * - */ - if (sscanf(pp->a_lastcode, - "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c", - &pp->second, &pp->year, &month, &day, &pp->hour, &pp->minute, &mjd, &dut1, &leapdir, &leapmonth, &msADV, &flag) != 12) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } -#endif - /* - * Some modems can't be trusted (the Practical Peripherals - * 9600SA comes to mind) and, even if they manage to unstick - * ACTS, the millisecond advance is wrong, so we use CLK_FLAG2 - * to disable echoes, if neccessary. - */ - if ((flag == '*' || flag == '#') && !(pp->sloppyclockflag & - CLK_FLAG2)) - (void)write(pp->io.fd, &flag, 1); - - /* - * 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; - } - - /* - * 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; - } - for (i = 0; i < month - 1; i++) - day += day1tab[i]; - } else { - if (day > day2tab[month - 1]) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - for (i = 0; i < month - 1; i++) - day += day2tab[i]; - } - pp->day = day; - -#ifndef CLOCK_PTBACTS - if (leap == 1) - pp->leap = LEAP_ADDSECOND; - else if (pp->leap == 2) - pp->leap = LEAP_DELSECOND; -#else - if (leapmonth == month) { - if (leapdir == '+') - pp->leap = LEAP_ADDSECOND; - else if (leapdir == '-') - pp->leap = LEAP_DELSECOND; - } -#endif - - /* - * Colossal hack here. We process each sample in a trimmed-mean - * filter and determine the reference clock offset and - * dispersion. The fudge time1 value is added to each sample as - * received. If we collect MSGCNT samples before the '#' on-time - * character, we use the results of the filter as is. If the '#' - * is found before that, the adjusted msADV is used to correct - * the propagation delay. - */ - up->msgcnt++; - if (flag == '#') { - pp->offset += (msADV - up->msADV) * 1000 * 1e-6; - } else { - up->msADV = msADV; - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } else if (up->msgcnt < MSGCNT) - return; - } - - /* - * We have a filtered sample offset ready for peer processing. - * We use lastrec as both the reference time and receive time in - * order to avoid being cute, like setting the reference time - * later than the receive time, which may cause a paranoid - * protocol module to chuck out the data. Finaly, we unhook the - * timeout, arm for the next call, fold the tent and go home. - * The little dance with the '%' character is an undocumented - * ACTS feature that hangs up the phone real quick without - * waiting for carrier loss or long-space disconnect, but we do - * these clumsy things anyway. - */ - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); - pp->sloppyclockflag &= ~CLK_FLAG1; - up->pollcnt = 0; - (void)write(pp->io.fd, &hangup, 1); - up->state = 0; - acts_disc(peer); -} - - -/* - * acts_poll - called by the transmit routine - */ -static void -acts_poll ( - int unit, - struct peer *peer - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - - /* - * If the driver is running, we set the enable flag (fudge - * flag1), which causes the driver timeout routine to initiate a - * call to ACTS. If not, the enable flag can be set using - * ntpdc. If this is the sustem peer, then follow the system - * poll interval. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - - if (up->run) { - pp->sloppyclockflag |= CLK_FLAG1; - if (peer == sys_peer) - peer->hpoll = sys_poll; - else - peer->hpoll = peer->minpoll; - } - acts_timeout (peer); - return; -} - - -/* - * acts_timeout - called by the timer interrupt - */ -static void -acts_timeout ( - struct peer *peer - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - int dtr = TIOCM_DTR; - - /* - * If a timeout occurs in other than state 0, the call has - * failed. If in state 0, we just see if there is other work to - * do. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - if (up->state) { - acts_disc(peer); - return; - } - switch (peer->ttl) { - - /* - * In manual mode the ACTS calling program is activated - * by the ntpdc program using the enable flag (fudge - * flag1), either manually or by a cron job. - */ - case MODE_MANUAL: - up->run = 0; - break; - - /* - * In automatic mode the ACTS calling program runs - * continuously at intervals determined by the sys_poll - * variable. - */ - case MODE_AUTO: - if (!up->run) - pp->sloppyclockflag |= CLK_FLAG1; - up->run = 1; - break; - - /* - * In backup mode the ACTS calling program is disabled, - * unless no system peer has been selected for MAXOUTAGE - * (3600 s). Once enabled, it runs until some other NTP - * peer shows up. - */ - case MODE_BACKUP: - if (!up->run && sys_peer == 0) { - if (current_time - last_time > MAXOUTAGE) { - up->run = 1; - peer->hpoll = peer->minpoll; - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s ACTS backup started ", - ntoa(&peer->srcadr)); - } - } else if (up->run && sys_peer->sstclktype != CTL_SST_TS_TELEPHONE) { - peer->hpoll = peer->minpoll; - up->run = 0; - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s ACTS backup stopped", - ntoa(&peer->srcadr)); - } - break; - - default: - msyslog(LOG_ERR, - "clock %s ACTS invalid mode", ntoa(&peer->srcadr)); - } - - /* - * The fudge flag1 is used as an enable/disable; if set either - * by the code or via ntpdc, the ACTS calling program is - * started; if reset, the phones stop ringing. - */ - if (!(pp->sloppyclockflag & CLK_FLAG1)) { - up->pollcnt = 0; - peer->nextdate = current_time + IDLE; - return; - } - - /* - * Initiate a call to the ACTS service. If we wind up here in - * other than state 0, a successful call could not be completed - * within minpoll seconds. We advance to the next modem dial - * string. If none are left, we log a notice and clear the - * enable flag. For future enhancement: call the site RP and - * leave an obscene message in his voicemail. - */ - if (sys_phone[up->pollcnt][0] == '\0') { - refclock_report(peer, CEVNT_TIMEOUT); - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s ACTS calling program terminated", - ntoa(&peer->srcadr)); - pp->sloppyclockflag &= ~CLK_FLAG1; -#ifdef DEBUG - if (debug) - printf("acts: calling program terminated\n"); -#endif - up->pollcnt = 0; - peer->nextdate = current_time + IDLE; - return; - } - - /* - * Raise DTR, call ACTS and start the answer timeout. We think - * it strange if the OK status has not been received from the - * modem, but plow ahead anyway. - */ - if (strcmp(pp->a_lastcode, "OK") != 0) - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "clock %s ACTS no modem status", - ntoa(&peer->srcadr)); - (void)ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr); - (void)acts_write(peer, sys_phone[up->pollcnt]); - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "clock %s ACTS calling %s\n", - ntoa(&peer->srcadr), sys_phone[up->pollcnt]); - up->state = 1; - up->pollcnt++; - pp->polls++; - peer->nextdate = current_time + ANSWER; - return; -} - - -/* - * acts_disc - disconnect the call and wait for the ruckus to cool - */ -static void -acts_disc ( - struct peer *peer - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - int dtr = TIOCM_DTR; - - /* - * We should never get here other than in state 0, unless a call - * has timed out. We drop DTR, which will reliably get the modem - * off the air, even while ACTS is hammering away full tilt. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - (void)ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr); - if (up->state > 0) { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "clock %s ACTS call failed %d", - ntoa(&peer->srcadr), up->state); -#ifdef DEBUG - if (debug) - printf("acts: call failed %d\n", up->state); -#endif - up->state = 0; - } - peer->nextdate = current_time + WAIT; -} - - -/* - * acts_write - write a message to the serial port - */ -static int -acts_write ( - struct peer *peer, - const char *str - ) -{ - register struct actsunit *up; - struct refclockproc *pp; - int len; - int code; - char cr = '\r'; - - /* - * Not much to do here, other than send the message, handle - * debug and report faults. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - len = strlen(str); -#ifdef DEBUG - if (debug) - printf("acts: state %d send %d %s\n", up->state, len, - str); -#endif - code = write(pp->io.fd, str, (unsigned)len) == len; - code &= write(pp->io.fd, &cr, 1) == 1; - if (!code) - refclock_report(peer, CEVNT_FAULT); - return (code); -} - -#else -int refclock_acts_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_arbiter.c b/contrib/ntp/ntpd/refclock_arbiter.c deleted file mode 100644 index cf5f92f..0000000 --- a/contrib/ntp/ntpd/refclock_arbiter.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite - * Controlled Clock - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_ARBITER) - -#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 - * output when receiving four or more satellites. - * - * The receiver should be configured before starting the NTP daemon, in - * order to establish reliable position and operating conditions. It - * does not initiate surveying or hold mode. For use with NTP, the - * daylight savings time feature should be disables (D0 command) and the - * broadcast mode set to operate in UTC (BU command). - * - * The timecode format supported by this driver is selected by the poll - * sequence "B5", which initiates a line in the following format to be - * repeated once per second until turned off by the "B0" poll sequence. - * - * Format B5 (24 ASCII printing characters): - * - * <cr><lf>i yy ddd hh:mm:ss.000bbb - * - * on-time = <cr> - * i = synchronization flag (' ' = locked, '?' = unlocked) - * yy = year of century - * ddd = day of year - * hh:mm:ss = hours, minutes, seconds - * .000 = fraction of second (not used) - * bbb = tailing spaces for fill - * - * The alarm condition is indicated by a '?' at i, which indicates the - * receiver is not synchronized. In normal operation, a line consisting - * of the timecode followed by the time quality character (TQ) followed - * by the receiver status string (SR) is written to the clockstats file. - * The time quality character is encoded in IEEE P1344 standard: - * - * Format TQ (IEEE P1344 estimated worst-case time quality) - * - * 0 clock locked, maximum accuracy - * F clock failure, time not reliable - * 4 clock unlocked, accuracy < 1 us - * 5 clock unlocked, accuracy < 10 us - * 6 clock unlocked, accuracy < 100 us - * 7 clock unlocked, accuracy < 1 ms - * 8 clock unlocked, accuracy < 10 ms - * 9 clock unlocked, accuracy < 100 ms - * A clock unlocked, accuracy < 1 s - * B clock unlocked, accuracy < 10 s - * - * The status string is encoded as follows: - * - * Format SR (25 ASCII printing characters) - * - * V=vv S=ss T=t P=pdop E=ee - * - * vv = satellites visible - * ss = relative signal strength - * t = satellites tracked - * pdop = position dilution of precision (meters) - * ee = hardware errors - * - * If flag4 is set, an additional line consisting of the receiver - * latitude (LA), longitude (LO) and elevation (LH) (meters) is written - * to this file. If channel B is enabled for deviation mode and connected - * to a 1-PPS signal, the last two numbers on the line are the deviation - * and standard deviation averaged over the last 15 seconds. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/gps%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS " /* reference ID */ -#define DESCRIPTION "Arbiter 1088A/B GPS Receiver" /* WRU */ - -#define LENARB 24 /* format B5 timecode length */ -#define MAXSTA 30 /* max length of status string */ -#define MAXPOS 70 /* max length of position string */ - -/* - * ARB unit control structure - */ -struct arbunit { - l_fp laststamp; /* last receive timestamp */ - int tcswitch; /* timecode switch/counter */ - char qualchar; /* IEEE P1344 quality (TQ command) */ - char status[MAXSTA]; /* receiver status (SR command) */ - char latlon[MAXPOS]; /* receiver position (lat/lon/alt) */ -}; - -/* - * Function prototypes - */ -static int arb_start P((int, struct peer *)); -static void arb_shutdown P((int, struct peer *)); -static void arb_receive P((struct recvbuf *)); -static void arb_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_arbiter = { - arb_start, /* start up driver */ - arb_shutdown, /* shut down driver */ - arb_poll, /* transmit poll message */ - noentry, /* not used (old arb_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old arb_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * arb_start - open the devices and initialize data for processing - */ -static int -arb_start( - int unit, - struct peer *peer - ) -{ - register struct arbunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct arbunit *)emalloc(sizeof(struct arbunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct arbunit)); - pp = peer->procptr; - pp->io.clock_recv = arb_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - write(pp->io.fd, "B0", 2); - return (1); -} - - -/* - * arb_shutdown - shut down the clock - */ -static void -arb_shutdown( - int unit, - struct peer *peer - ) -{ - register struct arbunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct arbunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * arb_receive - receive data from the serial interface - */ -static void -arb_receive( - struct recvbuf *rbufp - ) -{ - register struct arbunit *up; - struct refclockproc *pp; - struct peer *peer; - l_fp trtmp; - int temp; - u_char syncchar; /* synchronization indicator */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct arbunit *)pp->unitptr; - temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); - - /* - * Note we get a buffer and timestamp for both a <cr> and <lf>, - * but only the <cr> timestamp is retained. The program first - * sends a TQ and expects the echo followed by the time quality - * character. It then sends a B5 starting the timecode broadcast - * and expects the echo followed some time later by the on-time - * character <cr> and then the <lf> beginning the timecode - * itself. Finally, at the <cr> beginning the next timecode at - * the next second, the program sends a B0 shutting down the - * timecode broadcast. - * - * If flag4 is set, the program snatches the latitude, longitude - * and elevation and writes it to the clockstats file. - */ - if (temp == 0) - return; - pp->lastrec = up->laststamp; - up->laststamp = trtmp; - if (temp < 3) - return; - if (up->tcswitch == 0) { - - /* - * Collect statistics. If nothing is recogized, just - * ignore; sometimes the clock doesn't stop spewing - * timecodes for awhile after the B0 commant. - */ - if (!strncmp(pp->a_lastcode, "TQ", 2)) { - up->qualchar = pp->a_lastcode[2]; - write(pp->io.fd, "SR", 2); - } else if (!strncmp(pp->a_lastcode, "SR", 2)) { - strcpy(up->status, pp->a_lastcode + 2); - if (pp->sloppyclockflag & CLK_FLAG4) - write(pp->io.fd, "LA", 2); - else { - write(pp->io.fd, "B5", 2); - up->tcswitch++; - } - } else if (!strncmp(pp->a_lastcode, "LA", 2)) { - strcpy(up->latlon, pp->a_lastcode + 2); - write(pp->io.fd, "LO", 2); - } else if (!strncmp(pp->a_lastcode, "LO", 2)) { - strcat(up->latlon, " "); - strcat(up->latlon, pp->a_lastcode + 2); - write(pp->io.fd, "LH", 2); - } else if (!strncmp(pp->a_lastcode, "LH", 2)) { - strcat(up->latlon, " "); - strcat(up->latlon, pp->a_lastcode + 2); - write(pp->io.fd, "DB", 2); - } else if (!strncmp(pp->a_lastcode, "DB", 2)) { - strcat(up->latlon, " "); - strcat(up->latlon, pp->a_lastcode + 2); - record_clock_stats(&peer->srcadr, up->latlon); - write(pp->io.fd, "B5", 2); - up->tcswitch++; - } - return; - } - pp->lencode = temp; - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has valid length, but not in - * proper format, we declare bad format and exit. If the - * timecode has invalid length, which sometimes occurs when the - * B0 amputates the broadcast, we just quietly steal away. Note - * that the time quality character and receiver status string is - * tacked on the end for clockstats display. - */ - if (pp->lencode == LENARB) { - /* - * Timecode format B5: "i yy ddd hh:mm:ss.000 " - */ - pp->a_lastcode[LENARB - 2] = up->qualchar; - strcat(pp->a_lastcode, up->status); - syncchar = ' '; - if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d", - &syncchar, &pp->year, &pp->day, &pp->hour, - &pp->minute, &pp->second) != 6) { - refclock_report(peer, CEVNT_BADREPLY); - write(pp->io.fd, "B0", 2); - return; - } - } else { - write(pp->io.fd, "B0", 2); - return; - } - up->tcswitch++; - - /* - * We decode the clock dispersion from the time quality - * character. - */ - switch (up->qualchar) { - - case '0': /* locked, max accuracy */ - pp->disp = 1e-7; - break; - - case '4': /* unlock accuracy < 1 us */ - pp->disp = 1e-6; - break; - - case '5': /* unlock accuracy < 10 us */ - pp->disp = 1e-5; - break; - - case '6': /* unlock accuracy < 100 us */ - pp->disp = 1e-4; - break; - - case '7': /* unlock accuracy < 1 ms */ - pp->disp = .001; - break; - - case '8': /* unlock accuracy < 10 ms */ - pp->disp = .01; - break; - - case '9': /* unlock accuracy < 100 ms */ - pp->disp = .1; - break; - - case 'A': /* unlock accuracy < 1 s */ - pp->disp = 1; - break; - - case 'B': /* unlock accuracy < 10 s */ - pp->disp = 10; - break; - - case 'F': /* clock failure */ - pp->disp = MAXDISPERSE; - refclock_report(peer, CEVNT_FAULT); - write(pp->io.fd, "B0", 2); - return; - - default: - pp->disp = MAXDISPERSE; - refclock_report(peer, CEVNT_BADREPLY); - write(pp->io.fd, "B0", 2); - return; - } - if (syncchar != ' ') - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; -#ifdef DEBUG - if (debug) - printf("arbiter: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - if (up->tcswitch >= NSTAGE) - write(pp->io.fd, "B0", 2); - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if (!refclock_process(pp)) - refclock_report(peer, CEVNT_BADTIME); -} - - -/* - * arb_poll - called by the transmit procedure - */ -static void -arb_poll( - int unit, - struct peer *peer - ) -{ - register struct arbunit *up; - struct refclockproc *pp; - - /* - * Time to poll the clock. The Arbiter clock responds to a "B5" - * by returning a timecode in the format specified above. - * Transmission occurs once per second, unless turned off by a - * "B0". Note there is no checking on state, since this may not - * be the only customer reading the clock. Only one customer - * need poll the clock; all others just listen in. If nothing is - * heard from the clock for two polls, declare a timeout and - * keep going. - */ - pp = peer->procptr; - up = (struct arbunit *)pp->unitptr; - up->tcswitch = 0; - if (write(pp->io.fd, "TQ", 2) != 2) { - refclock_report(peer, CEVNT_FAULT); - } else - pp->polls++; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -} - -#else -int refclock_arbiter_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_arc.c b/contrib/ntp/ntpd/refclock_arc.c deleted file mode 100644 index f556da6..0000000 --- a/contrib/ntp/ntpd/refclock_arc.c +++ /dev/null @@ -1,1529 +0,0 @@ -/* - * refclock_arc - clock driver for ARCRON MSF/DCF/WWVB receivers - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF) -static const char arc_version[] = { "V1.3 2003/02/21" }; - -/* define PRE_NTP420 for compatibility to previous versions of NTP (at least - to 4.1.0 */ -#undef PRE_NTP420 - -#ifndef ARCRON_NOT_KEEN -#define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */ -#endif - -#ifndef ARCRON_NOT_MULTIPLE_SAMPLES -#define ARCRON_MULTIPLE_SAMPLES 1 /* Use all timestamp bytes as samples. */ -#endif - -#ifndef ARCRON_NOT_LEAPSECOND_KEEN -#ifndef ARCRON_LEAPSECOND_KEEN -#undef ARCRON_LEAPSECOND_KEEN /* Respond quickly to leap seconds: doesn't work yet. */ -#endif -#endif - -/* -Code by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997. -Modifications by Damon Hart-Davis, <d@hd.org>, 1997. -Modifications by Paul Alfille, <palfille@partners.org>, 2003. -Modifications by Christopher Price, <cprice@cs-home.com>, 2003. - - -THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND. USE AT -YOUR OWN RISK. - -Orginally developed and used with ntp3-5.85 by Derek Mulcahy. - -Built against ntp3-5.90 on Solaris 2.5 using gcc 2.7.2. - -This code may be freely copied and used and incorporated in other -systems providing the disclaimer and notice of authorship are -reproduced. - -------------------------------------------------------------------------------- - -Christopher's notes: - -MAJOR CHANGES SINCE V1.2 -======================== - 1) Applied patch by Andrey Bray <abuse@madhouse.demon.co.uk> - 2001-02-17 comp.protocols.time.ntp - - 2) Added WWVB support via clock mode command, localtime/UTC time configured - via flag1=(0=UTC, 1=localtime) - - 3) Added ignore resync request via flag2=(0=resync, 1=ignore resync) - - 4) Added simplified conversion from localtime to UTC with dst/bst translation - - 5) Added average signal quality poll - - 6) Fixed a badformat error when no code is available due to stripping - \n & \r's - - 7) Fixed a badformat error when clearing lencode & memset a_lastcode in poll - routine - - 8) Lots of code cleanup, including standardized DEBUG macros and removal - of unused code - -------------------------------------------------------------------------------- - -Author's original note: - -I enclose my ntp driver for the Galleon Systems Arc MSF receiver. - -It works (after a fashion) on both Solaris-1 and Solaris-2. - -I am currently using ntp3-5.85. I have been running the code for -about 7 months without any problems. Even coped with the change to BST! - -I had to do some funky things to read from the clock because it uses the -power from the receive lines to drive the transmit lines. This makes the -code look a bit stupid but it works. I also had to put in some delays to -allow for the turnaround time from receive to transmit. These delays -are between characters when requesting a time stamp so that shouldn't affect -the results too drastically. - -... - -The bottom line is that it works but could easily be improved. You are -free to do what you will with the code. I haven't been able to determine -how good the clock is. I think that this requires a known good clock -to compare it against. - -------------------------------------------------------------------------------- - -Damon's notes for adjustments: - -MAJOR CHANGES SINCE V1.0 -======================== - 1) Removal of pollcnt variable that made the clock go permanently - off-line once two time polls failed to gain responses. - - 2) Avoiding (at least on Solaris-2) terminal becoming the controlling - terminal of the process when we do a low-level open(). - - 3) Additional logic (conditional on ARCRON_LEAPSECOND_KEEN being - defined) to try to resync quickly after a potential leap-second - insertion or deletion. - - 4) Code significantly slimmer at run-time than V1.0. - - -GENERAL -======= - - 1) The C preprocessor symbol to have the clock built has been changed - from ARC to ARCRON_MSF to CLOCK_ARCRON_MSF to minimise the - possiblity of clashes with other symbols in the future. - - 2) PRECISION should be -4/-5 (63ms/31ms) for the following reasons: - - a) The ARC documentation claims the internal clock is (only) - accurate to about 20ms relative to Rugby (plus there must be - noticable drift and delay in the ms range due to transmission - delays and changing atmospheric effects). This clock is not - designed for ms accuracy as NTP has spoilt us all to expect. - - b) The clock oscillator looks like a simple uncompensated quartz - crystal of the sort used in digital watches (ie 32768Hz) which - can have large temperature coefficients and drifts; it is not - clear if this oscillator is properly disciplined to the MSF - transmission, but as the default is to resync only once per - *day*, we can imagine that it is not, and is free-running. We - can minimise drift by resyncing more often (at the cost of - reduced battery life), but drift/wander may still be - significant. - - c) Note that the bit time of 3.3ms adds to the potential error in - the the clock timestamp, since the bit clock of the serial link - may effectively be free-running with respect to the host clock - and the MSF clock. Actually, the error is probably 1/16th of - the above, since the input data is probably sampled at at least - 16x the bit rate. - - By keeping the clock marked as not very precise, it will have a - fairly large dispersion, and thus will tend to be used as a - `backup' time source and sanity checker, which this clock is - probably ideal for. For an isolated network without other time - sources, this clock can probably be expected to provide *much* - better than 1s accuracy, which will be fine. - - By default, PRECISION is set to -4, but experience, especially at a - particular geographic location with a particular clock, may allow - this to be altered to -5. (Note that skews of +/- 10ms are to be - expected from the clock from time-to-time.) This improvement of - reported precision can be instigated by setting flag3 to 1, though - the PRECISION will revert to the normal value while the clock - signal quality is unknown whatever the flag3 setting. - - IN ANY CASE, BE SURE TO SET AN APPROPRIATE FUDGE FACTOR TO REMOVE - ANY RESIDUAL SKEW, eg: - - server 127.127.27.0 # ARCRON MSF radio clock unit 0. - # Fudge timestamps by about 20ms. - fudge 127.127.27.0 time1 0.020 - - You will need to observe your system's behaviour, assuming you have - some other NTP source to compare it with, to work out what the - fudge factor should be. For my Sun SS1 running SunOS 4.1.3_U1 with - my MSF clock with my distance from the MSF transmitter, +20ms - seemed about right, after some observation. - - 3) REFID has been made "MSFa" to reflect the MSF time source and the - ARCRON receiver. - - 4) DEFAULT_RESYNC_TIME is the time in seconds (by default) before - forcing a resync since the last attempt. This is picked to give a - little less than an hour between resyncs and to try to avoid - clashing with any regular event at a regular time-past-the-hour - which might cause systematic errors. - - The INITIAL_RESYNC_DELAY is to avoid bothering the clock and - running down its batteries unnecesarily if ntpd is going to crash - or be killed or reconfigured quickly. If ARCRON_KEEN is defined - then this period is long enough for (with normal polling rates) - enough time samples to have been taken to allow ntpd to sync to - the clock before the interruption for the clock to resync to MSF. - This avoids ntpd syncing to another peer first and then - almost immediately hopping to the MSF clock. - - The RETRY_RESYNC_TIME is used before rescheduling a resync after a - resync failed to reveal a statisfatory signal quality (too low or - unknown). - - 5) The clock seems quite jittery, so I have increased the - median-filter size from the typical (previous) value of 3. I - discard up to half the results in the filter. It looks like maybe - 1 sample in 10 or so (maybe less) is a spike, so allow the median - filter to discard at least 10% of its entries or 1 entry, whichever - is greater. - - 6) Sleeping *before* each character sent to the unit to allow required - inter-character time but without introducting jitter and delay in - handling the response if possible. - - 7) If the flag ARCRON_KEEN is defined, take time samples whenever - possible, even while resyncing, etc. We rely, in this case, on the - clock always giving us a reasonable time or else telling us in the - status byte at the end of the timestamp that it failed to sync to - MSF---thus we should never end up syncing to completely the wrong - time. - - 8) If the flag ARCRON_OWN_FILTER is defined, use own versions of - refclock median-filter routines to get round small bug in 3-5.90 - code which does not return the median offset. XXX Removed this - bit due NTP Version 4 upgrade - dlm. - - 9) We would appear to have a year-2000 problem with this clock since - it returns only the two least-significant digits of the year. But - ntpd ignores the year and uses the local-system year instead, so - this is in fact not a problem. Nevertheless, we attempt to do a - sensible thing with the dates, wrapping them into a 100-year - window. - - 10)Logs stats information that can be used by Derek's Tcl/Tk utility - to show the status of the clock. - - 11)The clock documentation insists that the number of bits per - character to be sent to the clock, and sent by it, is 11, including - one start bit and two stop bits. The data format is either 7+even - or 8+none. - - -TO-DO LIST -========== - - * Eliminate use of scanf(), and maybe sprintf(). - - * Allow user setting of resync interval to trade battery life for - accuracy; maybe could be done via fudge factor or unit number. - - * Possibly note the time since the last resync of the MSF clock to - MSF as the age of the last reference timestamp, ie trust the - clock's oscillator not very much... - - * Add very slow auto-adjustment up to a value of +/- time2 to correct - for long-term errors in the clock value (time2 defaults to 0 so the - correction would be disabled by default). - - * Consider trying to use the tty_clk/ppsclock support. - - * Possibly use average or maximum signal quality reported during - resync, rather than just the last one, which may be atypical. - -*/ - - -/* Notes for HKW Elektronik GmBH Radio clock driver */ -/* Author Lyndon David, Sentinet Ltd, Feb 1997 */ -/* These notes seem also to apply usefully to the ARCRON clock. */ - -/* The HKW clock module is a radio receiver tuned into the Rugby */ -/* MSF time signal tranmitted on 60 kHz. The clock module connects */ -/* to the computer via a serial line and transmits the time encoded */ -/* in 15 bytes at 300 baud 7 bits two stop bits even parity */ - -/* Clock communications, from the datasheet */ -/* All characters sent to the clock are echoed back to the controlling */ -/* device. */ -/* Transmit time/date information */ -/* syntax ASCII o<cr> */ -/* Character o may be replaced if neccesary by a character whose code */ -/* contains the lowest four bits f(hex) eg */ -/* syntax binary: xxxx1111 00001101 */ - -/* DHD note: -You have to wait for character echo + 10ms before sending next character. -*/ - -/* The clock replies to this command with a sequence of 15 characters */ -/* which contain the complete time and a final <cr> making 16 characters */ -/* in total. */ -/* The RC computer clock will not reply immediately to this command because */ -/* the start bit edge of the first reply character marks the beginning of */ -/* the second. So the RC Computer Clock will reply to this command at the */ -/* start of the next second */ -/* The characters have the following meaning */ -/* 1. hours tens */ -/* 2. hours units */ -/* 3. minutes tens */ -/* 4. minutes units */ -/* 5. seconds tens */ -/* 6. seconds units */ -/* 7. day of week 1-monday 7-sunday */ -/* 8. day of month tens */ -/* 9. day of month units */ -/* 10. month tens */ -/* 11. month units */ -/* 12. year tens */ -/* 13. year units */ -/* 14. BST/UTC status */ -/* bit 7 parity */ -/* bit 6 always 0 */ -/* bit 5 always 1 */ -/* bit 4 always 1 */ -/* bit 3 always 0 */ -/* bit 2 =1 if UTC is in effect, complementary to the BST bit */ -/* bit 1 =1 if BST is in effect, according to the BST bit */ -/* bit 0 BST/UTC change impending bit=1 in case of change impending */ -/* 15. status */ -/* bit 7 parity */ -/* bit 6 always 0 */ -/* bit 5 always 1 */ -/* bit 4 always 1 */ -/* bit 3 =1 if low battery is detected */ -/* bit 2 =1 if the very last reception attempt failed and a valid */ -/* time information already exists (bit0=1) */ -/* =0 if the last reception attempt was successful */ -/* bit 1 =1 if at least one reception since 2:30 am was successful */ -/* =0 if no reception attempt since 2:30 am was successful */ -/* bit 0 =1 if the RC Computer Clock contains valid time information */ -/* This bit is zero after reset and one after the first */ -/* successful reception attempt */ - -/* DHD note: -Also note g<cr> command which confirms that a resync is in progress, and -if so what signal quality (0--5) is available. -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_calendar.h" -#include "ntp_stdlib.h" - -#include <stdio.h> -#include <ctype.h> - -#if defined(HAVE_BSD_TTYS) -#include <sgtty.h> -#endif /* HAVE_BSD_TTYS */ - -#if defined(HAVE_SYSV_TTYS) -#include <termio.h> -#endif /* HAVE_SYSV_TTYS */ - -#if defined(HAVE_TERMIOS) -#include <termios.h> -#endif - -/* - * This driver supports the ARCRON MSF/DCF/WWVB Radio Controlled Clock - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/arc%d" /* Device name and unit. */ -#define SPEED B300 /* UART speed (300 baud) */ -#define PRECISION (-4) /* Precision (~63 ms). */ -#define HIGHPRECISION (-5) /* If things are going well... */ -#define REFID "MSFa" /* Reference ID. */ -#define REFID_MSF "MSF" /* Reference ID. */ -#define REFID_DCF77 "DCF" /* Reference ID. */ -#define REFID_WWVB "WWVB" /* Reference ID. */ -#define DESCRIPTION "ARCRON MSF/DCF/WWVB Receiver" - -#ifdef PRE_NTP420 -#define MODE ttlmax -#else -#define MODE ttl -#endif - -#define LENARC 16 /* Format `o' timecode length. */ - -#define BITSPERCHAR 11 /* Bits per character. */ -#define BITTIME 0x0DA740E /* Time for 1 bit at 300bps. */ -#define CHARTIME10 0x8888888 /* Time for 10-bit char at 300bps. */ -#define CHARTIME11 0x962FC96 /* Time for 11-bit char at 300bps. */ -#define CHARTIME /* Time for char at 300bps. */ \ -( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \ - (BITSPERCHAR * BITTIME) ) ) - - /* Allow for UART to accept char half-way through final stop bit. */ -#define INITIALOFFSET (u_int32)(-BITTIME/2) - - /* - charoffsets[x] is the time after the start of the second that byte - x (with the first byte being byte 1) is received by the UART, - assuming that the initial edge of the start bit of the first byte - is on-time. The values are represented as the fractional part of - an l_fp. - - We store enough values to have the offset of each byte including - the trailing \r, on the assumption that the bytes follow one - another without gaps. - */ - static const u_int32 charoffsets[LENARC+1] = { -#if BITSPERCHAR == 11 /* Usual case. */ - /* Offsets computed as accurately as possible... */ - 0, - INITIALOFFSET + 0x0962fc96, /* 1 chars, 11 bits */ - INITIALOFFSET + 0x12c5f92c, /* 2 chars, 22 bits */ - INITIALOFFSET + 0x1c28f5c3, /* 3 chars, 33 bits */ - INITIALOFFSET + 0x258bf259, /* 4 chars, 44 bits */ - INITIALOFFSET + 0x2eeeeeef, /* 5 chars, 55 bits */ - INITIALOFFSET + 0x3851eb85, /* 6 chars, 66 bits */ - INITIALOFFSET + 0x41b4e81b, /* 7 chars, 77 bits */ - INITIALOFFSET + 0x4b17e4b1, /* 8 chars, 88 bits */ - INITIALOFFSET + 0x547ae148, /* 9 chars, 99 bits */ - INITIALOFFSET + 0x5dddddde, /* 10 chars, 110 bits */ - INITIALOFFSET + 0x6740da74, /* 11 chars, 121 bits */ - INITIALOFFSET + 0x70a3d70a, /* 12 chars, 132 bits */ - INITIALOFFSET + 0x7a06d3a0, /* 13 chars, 143 bits */ - INITIALOFFSET + 0x8369d037, /* 14 chars, 154 bits */ - INITIALOFFSET + 0x8ccccccd, /* 15 chars, 165 bits */ - INITIALOFFSET + 0x962fc963 /* 16 chars, 176 bits */ -#else - /* Offsets computed with a small rounding error... */ - 0, - INITIALOFFSET + 1 * CHARTIME, - INITIALOFFSET + 2 * CHARTIME, - INITIALOFFSET + 3 * CHARTIME, - INITIALOFFSET + 4 * CHARTIME, - INITIALOFFSET + 5 * CHARTIME, - INITIALOFFSET + 6 * CHARTIME, - INITIALOFFSET + 7 * CHARTIME, - INITIALOFFSET + 8 * CHARTIME, - INITIALOFFSET + 9 * CHARTIME, - INITIALOFFSET + 10 * CHARTIME, - INITIALOFFSET + 11 * CHARTIME, - INITIALOFFSET + 12 * CHARTIME, - INITIALOFFSET + 13 * CHARTIME, - INITIALOFFSET + 14 * CHARTIME, - INITIALOFFSET + 15 * CHARTIME, - INITIALOFFSET + 16 * CHARTIME -#endif - }; - -#define DEFAULT_RESYNC_TIME (57*60) /* Gap between resync attempts (s). */ -#define RETRY_RESYNC_TIME (27*60) /* Gap to emergency resync attempt. */ -#ifdef ARCRON_KEEN -#define INITIAL_RESYNC_DELAY 500 /* Delay before first resync. */ -#else -#define INITIAL_RESYNC_DELAY 50 /* Delay before first resync. */ -#endif - - static const int moff[12] = -{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; -/* Flags for a raw open() of the clock serial device. */ -#ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */ -#define OPEN_FLAGS (O_RDWR | O_NOCTTY) -#else /* Oh well, it may not matter... */ -#define OPEN_FLAGS (O_RDWR) -#endif - - -/* Length of queue of command bytes to be sent. */ -#define CMDQUEUELEN 4 /* Enough for two cmds + each \r. */ -/* Queue tick time; interval in seconds between chars taken off queue. */ -/* Must be >= 2 to allow o\r response to come back uninterrupted. */ -#define QUEUETICK 2 /* Allow o\r reply to finish. */ - -/* - * ARC unit control structure - */ -struct arcunit { - l_fp lastrec; /* Time tag for the receive time (system). */ - int status; /* Clock status. */ - - int quality; /* Quality of reception 0--5 for unit. */ - /* We may also use the values -1 or 6 internally. */ - u_long quality_stamp; /* Next time to reset quality average. */ - - u_long next_resync; /* Next resync time (s) compared to current_time. */ - int resyncing; /* Resync in progress if true. */ - - /* In the outgoing queue, cmdqueue[0] is next to be sent. */ - char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */ - - u_long saved_flags; /* Saved fudge flags. */ -}; - -#ifdef ARCRON_LEAPSECOND_KEEN -/* The flag `possible_leap' is set non-zero when any MSF unit - thinks a leap-second may have happened. - - Set whenever we receive a valid time sample in the first hour of - the first day of the first/seventh months. - - Outside the special hour this value is unconditionally set - to zero by the receive routine. - - On finding itself in this timeslot, as long as the value is - non-negative, the receive routine sets it to a positive value to - indicate a resync to MSF should be performed. - - In the poll routine, if this value is positive and we are not - already resyncing (eg from a sync that started just before - midnight), start resyncing and set this value negative to - indicate that a leap-triggered resync has been started. Having - set this negative prevents the receive routine setting it - positive and thus prevents multiple resyncs during the witching - hour. - */ -static int possible_leap = 0; /* No resync required by default. */ -#endif - -#if 0 -static void dummy_event_handler P((struct peer *)); -static void arc_event_handler P((struct peer *)); -#endif /* 0 */ - -#define QUALITY_UNKNOWN -1 /* Indicates unknown clock quality. */ -#define MIN_CLOCK_QUALITY 0 /* Min quality clock will return. */ -#define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */ -#define MAX_CLOCK_QUALITY 5 /* Max quality clock will return. */ - -/* - * Function prototypes - */ -static int arc_start P((int, struct peer *)); -static void arc_shutdown P((int, struct peer *)); -static void arc_receive P((struct recvbuf *)); -static void arc_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_arc = { - arc_start, /* start up driver */ - arc_shutdown, /* shut down driver */ - arc_poll, /* transmit poll message */ - noentry, /* not used (old arc_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old arc_buginfo) */ - NOFLAGS /* not used */ -}; - -/* Queue us up for the next tick. */ -#define ENQUEUE(up) \ - do { \ - peer->nextaction = current_time + QUEUETICK; \ - } while(0) - -/* Placeholder event handler---does nothing safely---soaks up loose tick. */ -static void -dummy_event_handler( - struct peer *peer - ) -{ -#ifdef DEBUG - if(debug) { printf("arc: dummy_event_handler() called.\n"); } -#endif -} - -/* -Normal event handler. - -Take first character off queue and send to clock if not a null. - -Shift characters down and put a null on the end. - -We assume that there is no parallelism so no race condition, but even -if there is nothing bad will happen except that we might send some bad -data to the clock once in a while. -*/ -static void -arc_event_handler( - struct peer *peer - ) -{ - struct refclockproc *pp = peer->procptr; - register struct arcunit *up = (struct arcunit *)pp->unitptr; - int i; - char c; -#ifdef DEBUG - if(debug > 2) { printf("arc: arc_event_handler() called.\n"); } -#endif - - c = up->cmdqueue[0]; /* Next char to be sent. */ - /* Shift down characters, shifting trailing \0 in at end. */ - for(i = 0; i < CMDQUEUELEN; ++i) - { up->cmdqueue[i] = up->cmdqueue[i+1]; } - - /* Don't send '\0' characters. */ - if(c != '\0') { - if(write(pp->io.fd, &c, 1) != 1) { - msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd); - } -#ifdef DEBUG - else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); } -#endif - } - - ENQUEUE(up); -} - -/* - * arc_start - open the devices and initialize data for processing - */ -static int -arc_start( - int unit, - struct peer *peer - ) -{ - register struct arcunit *up; - struct refclockproc *pp; - int fd; - char device[20]; -#ifdef HAVE_TERMIOS - struct termios arg; -#endif - - msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit); -#ifdef DEBUG - if(debug) { - printf("arc: %s: attempt to open unit %d.\n", arc_version, unit); - } -#endif - - /* Prevent a ridiculous device number causing overflow of device[]. */ - if((unit < 0) || (unit > 255)) { return(0); } - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) - return(0); -#ifdef DEBUG - if(debug) { printf("arc: unit %d using open().\n", unit); } -#endif - fd = open(device, OPEN_FLAGS); - if(fd < 0) { -#ifdef DEBUG - if(debug) { printf("arc: failed [open()] to open %s.\n", device); } -#endif - return(0); - } - - fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */ -#ifdef DEBUG - if(debug) - { printf("arc: opened RS232 port with file descriptor %d.\n", fd); } -#endif - -#ifdef HAVE_TERMIOS - - arg.c_iflag = IGNBRK | ISTRIP; - arg.c_oflag = 0; - arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB; - arg.c_lflag = 0; - arg.c_cc[VMIN] = 1; - arg.c_cc[VTIME] = 0; - - tcsetattr(fd, TCSANOW, &arg); - -#else - - msyslog(LOG_ERR, "ARCRON: termios not supported in this driver"); - (void)close(fd); - - return 0; - -#endif - - up = (struct arcunit *) emalloc(sizeof(struct arcunit)); - if(!up) { (void) close(fd); return(0); } - /* Set structure to all zeros... */ - memset((char *)up, 0, sizeof(struct arcunit)); - pp = peer->procptr; - pp->io.clock_recv = arc_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if(!io_addclock(&pp->io)) { (void) close(fd); free(up); return(0); } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - peer->stratum = 2; /* Default to stratum 2 not 0. */ - pp->clockdesc = DESCRIPTION; - if (peer->MODE > 3) { - msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); - return 0; - } -#ifdef DEBUG - if(debug) { printf("arc: mode = %d.\n", peer->MODE); } -#endif - switch (peer->MODE) { - case 1: - memcpy((char *)&pp->refid, REFID_MSF, 4); - break; - case 2: - memcpy((char *)&pp->refid, REFID_DCF77, 4); - break; - case 3: - memcpy((char *)&pp->refid, REFID_WWVB, 4); - break; - default: - memcpy((char *)&pp->refid, REFID, 4); - break; - } - /* Spread out resyncs so that they should remain separated. */ - up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009; - -#if 0 /* Not needed because of zeroing of arcunit structure... */ - up->resyncing = 0; /* Not resyncing yet. */ - up->saved_flags = 0; /* Default is all flags off. */ - /* Clear send buffer out... */ - { - int i; - for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; } - } -#endif - -#ifdef ARCRON_KEEN - up->quality = QUALITY_UNKNOWN; /* Trust the clock immediately. */ -#else - up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */ -#endif - - peer->action = arc_event_handler; - - ENQUEUE(up); - - return(1); -} - - -/* - * arc_shutdown - shut down the clock - */ -static void -arc_shutdown( - int unit, - struct peer *peer - ) -{ - register struct arcunit *up; - struct refclockproc *pp; - - peer->action = dummy_event_handler; - - pp = peer->procptr; - up = (struct arcunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - -/* -Compute space left in output buffer. -*/ -static int -space_left( - register struct arcunit *up - ) -{ - int spaceleft; - - /* Compute space left in buffer after any pending output. */ - for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft) - { if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } } - return(spaceleft); -} - -/* -Send command by copying into command buffer as far forward as possible, -after any pending output. - -Indicate an error by returning 0 if there is not space for the command. -*/ -static int -send_slow( - register struct arcunit *up, - int fd, - const char *s - ) -{ - int sl = strlen(s); - int spaceleft = space_left(up); - -#ifdef DEBUG - if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); } -#endif - if(spaceleft < sl) { /* Should not normally happen... */ -#ifdef DEBUG - msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)", - sl, spaceleft); -#endif - return(0); /* FAILED! */ - } - - /* Copy in the command to be sent. */ - while(*s) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; } - - return(1); -} - - -/* Macro indicating action we will take for different quality values. */ -#define quality_action(q) \ -(((q) == QUALITY_UNKNOWN) ? "UNKNOWN, will use clock anyway" : \ - (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \ - "OK, will use clock")) - - /* - * arc_receive - receive data from the serial interface - */ - static void -arc_receive( - struct recvbuf *rbufp - ) -{ - register struct arcunit *up; - struct refclockproc *pp; - struct peer *peer; - char c; - int i, n, wday, month, flags, status; - int arc_last_offset; - static int quality_average = 0; - static int quality_sum = 0; - static int quality_polls = 0; - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct arcunit *)pp->unitptr; - - - /* - If the command buffer is empty, and we are resyncing, insert a - g\r quality request into it to poll for signal quality again. - */ - if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) { -#ifdef DEBUG - if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); } -#endif - send_slow(up, pp->io.fd, "g\r"); - } - - /* - The `arc_last_offset' is the offset in lastcode[] of the last byte - received, and which we assume actually received the input - timestamp. - - (When we get round to using tty_clk and it is available, we - assume that we will receive the whole timecode with the - trailing \r, and that that \r will be timestamped. But this - assumption also works if receive the characters one-by-one.) - */ - arc_last_offset = pp->lencode+rbufp->recv_length - 1; - - /* - We catch a timestamp iff: - - * The command code is `o' for a timestamp. - - * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have - exactly char in the buffer (the command code) so that we - only sample the first character of the timecode as our - `on-time' character. - - * The first character in the buffer is not the echoed `\r' - from the `o` command (so if we are to timestamp an `\r' it - must not be first in the receive buffer with lencode==1. - (Even if we had other characters following it, we probably - would have a premature timestamp on the '\r'.) - - * We have received at least one character (I cannot imagine - how it could be otherwise, but anyway...). - */ - c = rbufp->recv_buffer[0]; - if((pp->a_lastcode[0] == 'o') && -#ifndef ARCRON_MULTIPLE_SAMPLES - (pp->lencode == 1) && -#endif - ((pp->lencode != 1) || (c != '\r')) && - (arc_last_offset >= 1)) { - /* Note that the timestamp should be corrected if >1 char rcvd. */ - l_fp timestamp; - timestamp = rbufp->recv_time; -#ifdef DEBUG - if(debug) { /* Show \r as `R', other non-printing char as `?'. */ - printf("arc: stamp -->%c<-- (%d chars rcvd)\n", - ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')), - rbufp->recv_length); - } -#endif - - /* - Now correct timestamp by offset of last byte received---we - subtract from the receive time the delay implied by the - extra characters received. - - Reject the input if the resulting code is too long, but - allow for the trailing \r, normally not used but a good - handle for tty_clk or somesuch kernel timestamper. - */ - if(arc_last_offset > LENARC) { -#ifdef DEBUG - if(debug) { - printf("arc: input code too long (%d cf %d); rejected.\n", - arc_last_offset, LENARC); - } -#endif - pp->lencode = 0; - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - L_SUBUF(×tamp, charoffsets[arc_last_offset]); -#ifdef DEBUG - if(debug > 1) { - printf( - "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", - ((rbufp->recv_length > 1) ? "*** " : ""), - rbufp->recv_length, - arc_last_offset, - mfptoms((unsigned long)0, - charoffsets[arc_last_offset], - 1)); - } -#endif - -#ifdef ARCRON_MULTIPLE_SAMPLES - /* - If taking multiple samples, capture the current adjusted - sample iff: - - * No timestamp has yet been captured (it is zero), OR - - * This adjusted timestamp is earlier than the one already - captured, on the grounds that this one suffered less - delay in being delivered to us and is more accurate. - - */ - if(L_ISZERO(&(up->lastrec)) || - L_ISGEQ(&(up->lastrec), ×tamp)) -#endif - { -#ifdef DEBUG - if(debug > 1) { - printf("arc: system timestamp captured.\n"); -#ifdef ARCRON_MULTIPLE_SAMPLES - if(!L_ISZERO(&(up->lastrec))) { - l_fp diff; - diff = up->lastrec; - L_SUB(&diff, ×tamp); - printf("arc: adjusted timestamp by -%sms.\n", - mfptoms(diff.l_i, diff.l_f, 3)); - } -#endif - } -#endif - up->lastrec = timestamp; - } - - } - - /* Just in case we still have lots of rubbish in the buffer... */ - /* ...and to avoid the same timestamp being reused by mistake, */ - /* eg on receipt of the \r coming in on its own after the */ - /* timecode. */ - if(pp->lencode >= LENARC) { -#ifdef DEBUG - if(debug && (rbufp->recv_buffer[0] != '\r')) - { printf("arc: rubbish in pp->a_lastcode[].\n"); } -#endif - pp->lencode = 0; - return; - } - - /* Append input to code buffer, avoiding overflow. */ - for(i = 0; i < rbufp->recv_length; i++) { - if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */ - c = rbufp->recv_buffer[i]; - - /* Drop trailing '\r's and drop `h' command echo totally. */ - if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; } - - /* - If we've just put an `o' in the lastcode[0], clear the - timestamp in anticipation of a timecode arriving soon. - - We would expect to get to process this before any of the - timecode arrives. - */ - if((c == 'o') && (pp->lencode == 1)) { - L_CLR(&(up->lastrec)); -#ifdef DEBUG - if(debug > 1) { printf("arc: clearing timestamp.\n"); } -#endif - } - } - if (pp->lencode == 0) return; - - /* Handle a quality message. */ - if(pp->a_lastcode[0] == 'g') { - int r, q; - - if(pp->lencode < 3) { return; } /* Need more data... */ - r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */ - q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */ - if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || - ((r & 0x70) != 0x30)) { - /* Badly formatted response. */ -#ifdef DEBUG - if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); } -#endif - return; - } - if(r == '3') { /* Only use quality value whilst sync in progress. */ - if (up->quality_stamp < current_time) { - struct calendar cal; - l_fp new_stamp; - - get_systime (&new_stamp); - caljulian (new_stamp.l_ui, &cal); - up->quality_stamp = - current_time + 60 - cal.second + 5; - quality_sum = 0; - quality_polls = 0; - } - quality_sum += (q & 0xf); - quality_polls++; - quality_average = (quality_sum / quality_polls); -#ifdef DEBUG - if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); } -#endif - } else if( /* (r == '2') && */ up->resyncing) { - up->quality = quality_average; -#ifdef DEBUG - if(debug) - { - printf("arc: sync finished, signal quality %d: %s\n", - up->quality, - quality_action(up->quality)); - } -#endif - msyslog(LOG_NOTICE, - "ARCRON: sync finished, signal quality %d: %s", - up->quality, - quality_action(up->quality)); - up->resyncing = 0; /* Resync is over. */ - quality_average = 0; - quality_sum = 0; - quality_polls = 0; - -#ifdef ARCRON_KEEN - /* Clock quality dubious; resync earlier than usual. */ - if((up->quality == QUALITY_UNKNOWN) || - (up->quality < MIN_CLOCK_QUALITY_OK)) - { up->next_resync = current_time + RETRY_RESYNC_TIME; } -#endif - } - pp->lencode = 0; - return; - } - - /* Stop now if this is not a timecode message. */ - if(pp->a_lastcode[0] != 'o') { - pp->lencode = 0; - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* If we don't have enough data, wait for more... */ - if(pp->lencode < LENARC) { return; } - - - /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */ -#ifdef DEBUG - if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); } -#endif - - /* But check that we actually captured a system timestamp on it. */ - if(L_ISZERO(&(up->lastrec))) { -#ifdef DEBUG - if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); } -#endif - pp->lencode = 0; - refclock_report(peer, CEVNT_BADREPLY); - return; - } - /* - Append a mark of the clock's received signal quality for the - benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown' - quality value to `6' for his s/w) and terminate the string for - sure. This should not go off the buffer end. - */ - pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ? - '6' : ('0' + up->quality)); - pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */ - -#ifdef PRE_NTP420 - /* We don't use the micro-/milli- second part... */ - pp->usec = 0; - pp->msec = 0; -#else - /* We don't use the nano-second part... */ - pp->nsec = 0; -#endif - n = sscanf(pp->a_lastcode, "o%2d%2d%2d%1d%2d%2d%2d%1d%1d", - &pp->hour, &pp->minute, &pp->second, - &wday, &pp->day, &month, &pp->year, &flags, &status); - - /* Validate format and numbers. */ - if(n != 9) { -#ifdef DEBUG - /* Would expect to have caught major problems already... */ - if(debug) { printf("arc: badly formatted data.\n"); } -#endif - pp->lencode = 0; - refclock_report(peer, CEVNT_BADREPLY); - return; - } - /* - 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.*/ || - (wday < 1) || (wday > 7) || - (pp->day < 1) || (pp->day > 31) || - (month < 1) || (month > 12) || - (pp->year < 0) || (pp->year > 99)) { - /* Data out of range. */ - pp->lencode = 0; - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - - if(peer->MODE == 0) { /* compatiblity to original version */ - int bst = flags; - /* Check that BST/UTC bits are the complement of one another. */ - if(!(bst & 2) == !(bst & 4)) { - pp->lencode = 0; - refclock_report(peer, CEVNT_BADREPLY); - return; - } - } - if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); } - - /* Year-2000 alert! */ - /* Attempt to wrap 2-digit date into sensible window. */ - if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* Y2KFixes */ - pp->year += 1900; /* use full four-digit year */ /* Y2KFixes */ - /* - Attempt to do the right thing by screaming that the code will - soon break when we get to the end of its useful life. What a - hero I am... PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X! - */ - if(pp->year >= YEAR_PIVOT+2000-2 ) { /* Y2KFixes */ - /*This should get attention B^> */ - msyslog(LOG_NOTICE, - "ARCRON: fix me! EITHER YOUR DATE IS BADLY WRONG or else I will break soon!"); - } -#ifdef DEBUG - if(debug) { - printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n", - n, - pp->hour, pp->minute, pp->second, - pp->day, month, pp->year, flags, status); - } -#endif - - /* - The status value tested for is not strictly supported by the - clock spec since the value of bit 2 (0x4) is claimed to be - undefined for MSF, yet does seem to indicate if the last resync - was successful or not. - */ - pp->leap = LEAP_NOWARNING; - status &= 0x7; - if(status == 0x3) { - if(status != up->status) - { msyslog(LOG_NOTICE, "ARCRON: signal acquired"); } - } else { - if(status != up->status) { - msyslog(LOG_NOTICE, "ARCRON: signal lost"); - pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */ - up->status = status; - pp->lencode = 0; - refclock_report(peer, CEVNT_FAULT); - return; - } - } - up->status = status; - - if (peer->MODE == 0) { /* compatiblity to original version */ - int bst = flags; - - pp->day += moff[month - 1]; - - if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */ - - /* Convert to UTC if required */ - if(bst & 2) { - pp->hour--; - if (pp->hour < 0) { - pp->hour = 23; - pp->day--; - /* If we try to wrap round the year - * (BST on 1st Jan), reject.*/ - if(pp->day < 0) { - pp->lencode = 0; - refclock_report(peer, CEVNT_BADTIME); - return; - } - } - } - } - - if(peer->MODE > 0) { - if(pp->sloppyclockflag & CLK_FLAG1) { - struct tm local; - struct tm *gmtp; - time_t unixtime; - - /* - * Convert to GMT for sites that distribute localtime. - * This means we have to do Y2K conversion on the - * 2-digit year; otherwise, we get the time wrong. - */ - - local.tm_year = pp->year-1900; - local.tm_mon = month-1; - local.tm_mday = pp->day; - local.tm_hour = pp->hour; - local.tm_min = pp->minute; - local.tm_sec = pp->second; - switch (peer->MODE) { - case 1: - local.tm_isdst = (flags & 2); - break; - case 2: - local.tm_isdst = (flags & 2); - break; - case 3: - switch (flags & 3) { - case 0: /* It is unclear exactly when the - Arcron changes from DST->ST and - ST->DST. Testing has shown this - to be irregular. For the time - being, let the OS decide. */ - local.tm_isdst = 0; -#ifdef DEBUG - if (debug) - printf ("arc: DST = 00 (0)\n"); -#endif - break; - case 1: /* dst->st time */ - local.tm_isdst = -1; -#ifdef DEBUG - if (debug) - printf ("arc: DST = 01 (1)\n"); -#endif - break; - case 2: /* st->dst time */ - local.tm_isdst = -1; -#ifdef DEBUG - if (debug) - printf ("arc: DST = 10 (2)\n"); -#endif - break; - case 3: /* dst time */ - local.tm_isdst = 1; -#ifdef DEBUG - if (debug) - printf ("arc: DST = 11 (3)\n"); -#endif - break; - } - break; - default: - msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", - peer->MODE); - return; - break; - } - unixtime = mktime (&local); - if ((gmtp = gmtime (&unixtime)) == NULL) - { - pp->lencode = 0; - refclock_report (peer, CEVNT_FAULT); - return; - } - pp->year = gmtp->tm_year+1900; - month = gmtp->tm_mon+1; - pp->day = ymd2yd(pp->year,month,gmtp->tm_mday); - /* pp->day = gmtp->tm_yday; */ - pp->hour = gmtp->tm_hour; - pp->minute = gmtp->tm_min; - pp->second = gmtp->tm_sec; -#ifdef DEBUG - if (debug) - { - printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", - pp->year,month,gmtp->tm_mday,pp->hour,pp->minute, - pp->second); - } -#endif - } else - { - /* - * For more rational sites distributing UTC - */ - pp->day = ymd2yd(pp->year,month,pp->day); - } - } - - if (peer->MODE == 0) { /* compatiblity to original version */ - /* If clock signal quality is - * unknown, revert to default PRECISION...*/ - if(up->quality == QUALITY_UNKNOWN) { - peer->precision = PRECISION; - } else { /* ...else improve precision if flag3 is set... */ - peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? - HIGHPRECISION : PRECISION); - } - } else { - if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) { - peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? - HIGHPRECISION : PRECISION); - } else if (up->quality == QUALITY_UNKNOWN) { - peer->precision = PRECISION; - } else { - peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? - HIGHPRECISION : PRECISION); - } - } - - /* Notice and log any change (eg from initial defaults) for flags. */ - if(up->saved_flags != pp->sloppyclockflag) { -#ifdef DEBUG - msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s", - ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."), - ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."), - ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."), - ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : ".")); - /* Note effects of flags changing... */ - if(debug) { - printf("arc: PRECISION = %d.\n", peer->precision); - } -#endif - up->saved_flags = pp->sloppyclockflag; - } - - /* Note time of last believable timestamp. */ - pp->lastrec = up->lastrec; - -#ifdef ARCRON_LEAPSECOND_KEEN - /* Find out if a leap-second might just have happened... - (ie is this the first hour of the first day of Jan or Jul?) - */ - if((pp->hour == 0) && - (pp->day == 1) && - ((month == 1) || (month == 7))) { - if(possible_leap >= 0) { - /* A leap may have happened, and no resync has started yet...*/ - possible_leap = 1; - } - } else { - /* Definitely not leap-second territory... */ - possible_leap = 0; - } -#endif - - if (!refclock_process(pp)) { - pp->lencode = 0; - refclock_report(peer, CEVNT_BADTIME); - return; - } - record_clock_stats(&peer->srcadr, pp->a_lastcode); - refclock_receive(peer); -} - - -/* request_time() sends a time request to the clock with given peer. */ -/* This automatically reports a fault if necessary. */ -/* No data should be sent after this until arc_poll() returns. */ -static void request_time P((int, struct peer *)); -static void -request_time( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp = peer->procptr; - register struct arcunit *up = (struct arcunit *)pp->unitptr; -#ifdef DEBUG - if(debug) { printf("arc: unit %d: requesting time.\n", unit); } -#endif - if (!send_slow(up, pp->io.fd, "o\r")) { -#ifdef DEBUG - if (debug) { - printf("arc: unit %d: problem sending", unit); - } -#endif - pp->lencode = 0; - refclock_report(peer, CEVNT_FAULT); - return; - } - pp->polls++; -} - -/* - * arc_poll - called by the transmit procedure - */ -static void -arc_poll( - int unit, - struct peer *peer - ) -{ - register struct arcunit *up; - struct refclockproc *pp; - int resync_needed; /* Should we start a resync? */ - - pp = peer->procptr; - up = (struct arcunit *)pp->unitptr; -#if 0 - pp->lencode = 0; - memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode)); -#endif - -#if 0 - /* Flush input. */ - tcflush(pp->io.fd, TCIFLUSH); -#endif - - /* Resync if our next scheduled resync time is here or has passed. */ - resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) && - (up->next_resync <= current_time) ); - -#ifdef ARCRON_LEAPSECOND_KEEN - /* - Try to catch a potential leap-second insertion or deletion quickly. - - In addition to the normal NTP fun of clocks that don't report - leap-seconds spooking their hosts, this clock does not even - sample the radio sugnal the whole time, so may miss a - leap-second insertion or deletion for up to a whole sample - time. - - To try to minimise this effect, if in the first few minutes of - the day immediately following a leap-second-insertion point - (ie in the first hour of the first day of the first and sixth - months), and if the last resync was in the previous day, and a - resync is not already in progress, resync the clock - immediately. - - */ - if((possible_leap > 0) && /* Must be 00:XX 01/0{1,7}/XXXX. */ - (!up->resyncing)) { /* No resync in progress yet. */ - resync_needed = 1; - possible_leap = -1; /* Prevent multiple resyncs. */ - msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit); - } -#endif - - /* Do a resync if required... */ - if(resync_needed) { - /* First, reset quality value to `unknown' so we can detect */ - /* when a quality message has been responded to by this */ - /* being set to some other value. */ - up->quality = QUALITY_UNKNOWN; - - /* Note that we are resyncing... */ - up->resyncing = 1; - - /* Now actually send the resync command and an immediate poll. */ -#ifdef DEBUG - if(debug) { printf("arc: sending resync command (h\\r).\n"); } -#endif - msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit); - send_slow(up, pp->io.fd, "h\r"); - - /* Schedule our next resync... */ - up->next_resync = current_time + DEFAULT_RESYNC_TIME; - - /* Drop through to request time if appropriate. */ - } - - /* If clock quality is too poor to trust, indicate a fault. */ - /* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/ - /* we'll cross our fingers and just hope that the thing */ - /* synced so quickly we did not catch it---we'll */ - /* double-check the clock is OK elsewhere. */ - if( -#ifdef ARCRON_KEEN - (up->quality != QUALITY_UNKNOWN) && -#else - (up->quality == QUALITY_UNKNOWN) || -#endif - (up->quality < MIN_CLOCK_QUALITY_OK)) { -#ifdef DEBUG - if(debug) { - printf("arc: clock quality %d too poor.\n", up->quality); - } -#endif - pp->lencode = 0; - refclock_report(peer, CEVNT_FAULT); - return; - } - /* This is the normal case: request a timestamp. */ - request_time(unit, peer); -} - -#else -int refclock_arc_bs; -#endif diff --git a/contrib/ntp/ntpd/refclock_as2201.c b/contrib/ntp/ntpd/refclock_as2201.c deleted file mode 100644 index f04d417b..0000000 --- a/contrib/ntp/ntpd/refclock_as2201.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * refclock_as2201 - clock driver for the Austron 2201A GPS - * Timing Receiver - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_AS2201) - -#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 - * receivers will not work reliably with this driver, since the older - * design cannot accept input commands at any reasonable data rate. - * - * The program sends a "*toc\r" to the radio and expects a response of - * the form "yy:ddd:hh:mm:ss.mmm\r" where yy = year of century, ddd = - * day of year, hh:mm:ss = second of day and mmm = millisecond of - * second. Then, it sends statistics commands to the radio and expects - * a multi-line reply showing the corresponding statistics or other - * selected data. Statistics commands are sent in order as determined by - * a vector of commands; these might have to be changed with different - * radio options. If flag4 of the fudge configuration command is set to - * 1, the statistics data are written to the clockstats file for later - * processing. - * - * In order for this code to work, the radio must be placed in non- - * interactive mode using the "off" command and with a single <cr> - * response using the "term cr" command. The setting of the "echo" - * and "df" commands does not matter. The radio should select UTC - * timescale using the "ts utc" command. - * - * There are two modes of operation for this driver. The first with - * default configuration is used with stock kernels and serial-line - * drivers and works with almost any machine. In this mode the driver - * assumes the radio captures a timestamp upon receipt of the "*" that - * begins the driver query. Accuracies in this mode are in the order of - * a millisecond or two and the receiver can be connected to only one - * host. - * - * The second mode of operation can be used for SunOS kernels that have - * been modified with the ppsclock streams module included in this - * distribution. The mode is enabled if flag3 of the fudge configuration - * command has been set to 1. In this mode a precise timestamp is - * available using a gadget box and 1-pps signal from the receiver. This - * improves the accuracy to the order of a few tens of microseconds. In - * addition, the serial output and 1-pps signal can be bussed to more - * than one hosts, but only one of them should be connected to the - * radio input data line. - */ - -/* - * GPS Definitions - */ -#define SMAX 200 /* statistics buffer length */ -#define DEVICE "/dev/gps%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS\0" /* reference ID */ -#define DESCRIPTION "Austron 2201A GPS Receiver" /* WRU */ - -#define LENTOC 19 /* yy:ddd:hh:mm:ss.mmm timecode lngth */ - -/* - * AS2201 unit control structure. - */ -struct as2201unit { - char *lastptr; /* statistics buffer pointer */ - char stats[SMAX]; /* statistics buffer */ - int linect; /* count of lines remaining */ - int index; /* current statistics command */ -}; - -/* - * Radio commands to extract statitistics - * - * A command consists of an ASCII string terminated by a <cr> (\r). The - * command list consist of a sequence of commands terminated by a null - * string ("\0"). One command from the list is sent immediately - * following each received timecode (*toc\r command) and the ASCII - * strings received from the radio are saved along with the timecode in - * the clockstats file. Subsequent commands are sent at each timecode, - * with the last one in the list followed by the first one. The data - * received from the radio consist of ASCII strings, each terminated by - * a <cr> (\r) character. The number of strings for each command is - * specified as the first line of output as an ASCII-encode number. Note - * that the ETF command requires the Input Buffer Module and the LORAN - * commands require the LORAN Assist Module. However, if these modules - * are not installed, the radio and this driver will continue to operate - * successfuly, but no data will be captured for these commands. - */ -static char stat_command[][30] = { - "ITF\r", /* internal time/frequency */ - "ETF\r", /* external time/frequency */ - "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ - "LORAN TDATA\r", /* LORAN signal data */ - "ID;OPT;VER\r", /* model; options; software version */ - - "ITF\r", /* internal time/frequency */ - "ETF\r", /* external time/frequency */ - "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ - "TRSTAT\r", /* satellite tracking status */ - "POS;PPS;PPSOFF\r", /* position, pps source, offsets */ - - "ITF\r", /* internal time/frequency */ - "ETF\r", /* external time/frequency */ - "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ - "LORAN TDATA\r", /* LORAN signal data */ - "UTC\r", /* UTC leap info */ - - "ITF\r", /* internal time/frequency */ - "ETF\r", /* external time/frequency */ - "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ - "TRSTAT\r", /* satellite tracking status */ - "OSC;ET;TEMP\r", /* osc type; tune volts; oven temp */ - "\0" /* end of table */ -}; - -/* - * Function prototypes - */ -static int as2201_start P((int, struct peer *)); -static void as2201_shutdown P((int, struct peer *)); -static void as2201_receive P((struct recvbuf *)); -static void as2201_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_as2201 = { - as2201_start, /* start up driver */ - as2201_shutdown, /* shut down driver */ - as2201_poll, /* transmit poll message */ - noentry, /* not used (old as2201_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old as2201_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * as2201_start - open the devices and initialize data for processing - */ -static int -as2201_start( - int unit, - struct peer *peer - ) -{ - register struct as2201unit *up; - struct refclockproc *pp; - int fd; - char gpsdev[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(gpsdev, DEVICE, unit); - if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct as2201unit *) - emalloc(sizeof(struct as2201unit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct as2201unit)); - pp = peer->procptr; - pp->io.clock_recv = as2201_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - peer->burst = NSTAGE; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->lastptr = up->stats; - up->index = 0; - return (1); -} - - -/* - * as2201_shutdown - shut down the clock - */ -static void -as2201_shutdown( - int unit, - struct peer *peer - ) -{ - register struct as2201unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct as2201unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * as2201__receive - receive data from the serial interface - */ -static void -as2201_receive( - struct recvbuf *rbufp - ) -{ - register struct as2201unit *up; - struct refclockproc *pp; - struct peer *peer; - l_fp trtmp; - - /* - * Initialize pointers and read the timecode and timestamp. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct as2201unit *)pp->unitptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); -#ifdef DEBUG - if (debug) - printf("gps: timecode %d %d %s\n", - up->linect, pp->lencode, pp->a_lastcode); -#endif - if (pp->lencode == 0) - return; - - /* - * If linect is greater than zero, we must be in the middle of a - * statistics operation, so simply tack the received data at the - * end of the statistics string. If not, we could either have - * just received the timecode itself or a decimal number - * indicating the number of following lines of the statistics - * reply. In the former case, write the accumulated statistics - * data to the clockstats file and continue onward to process - * the timecode; in the later case, save the number of lines and - * quietly return. - */ - if (pp->sloppyclockflag & CLK_FLAG2) - pp->lastrec = trtmp; - if (up->linect > 0) { - up->linect--; - if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2) - return; - *up->lastptr++ = ' '; - (void)strcpy(up->lastptr, pp->a_lastcode); - up->lastptr += pp->lencode; - return; - } else { - if (pp->lencode == 1) { - up->linect = atoi(pp->a_lastcode); - return; - } else { - record_clock_stats(&peer->srcadr, up->stats); -#ifdef DEBUG - if (debug) - printf("gps: stat %s\n", up->stats); -#endif - } - } - up->lastptr = up->stats; - *up->lastptr = '\0'; - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. - */ - if (pp->lencode < LENTOC) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Timecode format: "yy:ddd:hh:mm:ss.mmm" - */ - if (sscanf(pp->a_lastcode, "%2d:%3d:%2d:%2d:%2d.%3ld", &pp->year, - &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec) - != 6) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - pp->nsec *= 1000000; - - /* - * Test for synchronization (this is a temporary crock). - */ - if (pp->a_lastcode[2] != ':') - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - /* - * If CLK_FLAG4 is set, initialize the statistics buffer and - * send the next command. If not, simply write the timecode to - * the clockstats file. - */ - (void)strcpy(up->lastptr, pp->a_lastcode); - up->lastptr += pp->lencode; - if (pp->sloppyclockflag & CLK_FLAG4) { - *up->lastptr++ = ' '; - (void)strcpy(up->lastptr, stat_command[up->index]); - up->lastptr += strlen(stat_command[up->index]); - up->lastptr--; - *up->lastptr = '\0'; - (void)write(pp->io.fd, stat_command[up->index], - strlen(stat_command[up->index])); - up->index++; - if (*stat_command[up->index] == '\0') - up->index = 0; - } -} - - -/* - * as2201_poll - called by the transmit procedure - * - * We go to great pains to avoid changing state here, since there may be - * more than one eavesdropper receiving the same timecode. - */ -static void -as2201_poll( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - - /* - * Send a "\r*toc\r" to get things going. We go to great pains - * to avoid changing state, since there may be more than one - * eavesdropper watching the radio. - */ - pp = peer->procptr; - if (write(pp->io.fd, "\r*toc\r", 6) != 6) { - refclock_report(peer, CEVNT_FAULT); - } else { - pp->polls++; - if (!(pp->sloppyclockflag & CLK_FLAG2)) - get_systime(&pp->lastrec); - } - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - refclock_receive(peer); - peer->burst = NSTAGE; -} - -#else -int refclock_as2201_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c deleted file mode 100644 index 51153ae..0000000 --- a/contrib/ntp/ntpd/refclock_atom.c +++ /dev/null @@ -1,504 +0,0 @@ - -/* - * refclock_atom - clock driver for 1-pps signals - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <ctype.h> - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" - -#if defined(REFCLOCK) && defined(CLOCK_ATOM) - -#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 furnishes an interface for pulse-per-second (PPS) signals - * produced by a cesium clock, timing receiver or related equipment. It - * can be used to remove accumulated jitter and retime a secondary - * server when synchronized to a primary server over a congested, wide- - * area network and before redistributing the time to local clients. - * - * 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. 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. - * - * 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. - * - * In many configurations a single port is used for the radio timecode - * and PPS signal. In order to provide for this configuration and others - * involving dedicated multiple serial/parallel ports, the driver first - * attempts to open the device /dev/pps%d, where %d is the unit number. - * If this fails, the driver attempts to open the device specified by - * the pps configuration command. If a port is to be shared, the pps - * command must be placed before the radio device(s) and the radio - * device(s) must be placed before the PPS driver(s) in the - * configuration file. - * - * This driver normally uses the PLL/FLL clock discipline implemented in - * the ntpd code. 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 device - * driver and OS delays. - */ -/* - * Interface definitions - */ -#ifdef HAVE_PPSAPI -#define DEVICE "/dev/pps%d" /* device name and unit */ -#endif /* HAVE_PPSAPI */ - -#define PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "PPS\0" /* reference ID */ -#define DESCRIPTION "PPS Clock Discipline" /* WRU */ -#define NANOSECOND 1000000000 /* one second (ns) */ -#define RANGEGATE 500000 /* range gate (ns) */ -#define ASTAGE 8 /* filter stages */ - -static struct peer *pps_peer; /* atom driver for PPS sources */ - -#ifdef HAVE_PPSAPI -/* - * PPS unit control structure - */ -struct ppsunit { - struct timespec ts; /* last timestamp */ - int fddev; /* pps device descriptor */ - pps_params_t pps_params; /* pps parameters */ - pps_info_t pps_info; /* last pps data */ - pps_handle_t handle; /* pps handlebars */ -}; -#endif /* HAVE_PPSAPI */ - -/* - * Function prototypes - */ -static int atom_start P((int, struct peer *)); -static void atom_poll P((int, struct peer *)); -#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 *)); -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 */ -#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 */ -}; - - -/* - * atom_start - initialize data for processing - */ -static int -atom_start( - int unit, /* unit number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; -#ifdef HAVE_PPSAPI - register struct ppsunit *up; - char device[80]; -#endif /* HAVE_PPSAPI */ - - /* - * Allocate and initialize unit structure - */ - pps_peer = peer; - pp = peer->procptr; - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - pp->stratum = STRATUM_UNSPEC; - memcpy((char *)&pp->refid, REFID, 4); - peer->burst = ASTAGE; -#ifdef HAVE_PPSAPI - up = emalloc(sizeof(struct ppsunit)); - memset(up, 0, sizeof(struct ppsunit)); - pp->unitptr = (caddr_t)up; - - /* - * Open PPS device. If this fails and some driver has already - * opened the associated radio device, fdpps has the file - * descriptor for it. - */ - 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); - } - - /* - * 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 (time_pps_create(up->fddev, &up->handle) < 0) { - msyslog(LOG_ERR, - "refclock_atom: time_pps_create failed: %m"); - return (0); - } - return (atom_ppsapi(peer, 0, 0)); -#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; - 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", - 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_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; - } -#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); -} - - -/* - * atom_shutdown - shut down the clock - */ -static void -atom_shutdown( - int unit, /* unit number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - register struct ppsunit *up; - - pp = peer->procptr; - 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); -} - - -/* - * 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 /* peer structure pointer */ - ) -{ - register struct ppsunit *up; - struct refclockproc *pp; - pps_info_t pps_info; - struct timespec timeout, ts; - double dtemp; - - /* - * Convert the timespec nanoseconds field to signed double and - * save in the median filter. for billboards. No harm is done if - * previous data are overwritten. If the discipline comes bum or - * the data grow stale, just forget it. A range gate rejects new - * samples if less than a jiggle time from the next second. - */ - pp = peer->procptr; - up = (struct ppsunit *)pp->unitptr; - if (up->handle == 0) - return (-1); - 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 (-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 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; - } else { - return (-1); - } - 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 /* HAVE_PPSAPI */ - - -/* - * pps_sample - receive PPS data from some other clock driver - * - * This routine is called once per second when the external clock driver - * processes PPS information. It processes the PPS timestamp and saves - * the sign-extended fraction in a circular buffer for processing at the - * next poll event. This works only for a single PPS device. - */ -int -pps_sample( - l_fp *offset /* PPS offset */ - ) -{ - register struct peer *peer; - struct refclockproc *pp; - l_fp lftmp; - double doffset; - - peer = pps_peer; - if (peer == 0) /* nobody home */ - return (1); - pp = peer->procptr; - - /* - * Convert the timeval to l_fp and save for billboards. Sign- - * extend the fraction and stash in the buffer. No harm is done - * if previous data are overwritten. If the discipline comes bum - * or the data grow stale, just forget it. - */ - pp->lastrec = *offset; - L_CLR(&lftmp); - L_ADDF(&lftmp, pp->lastrec.l_f); - LFPTOD(&lftmp, doffset); - SAMPLE(-doffset + pp->fudgetime1); - return (0); -} - -/* - * 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, /* unit number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; -#ifdef HAVE_PPSAPI - int err; -#endif /* HAVE_PPSAPI */ - - /* - * 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; - pp->polls++; -#ifdef HAVE_PPSAPI - err = atom_pps(peer); - if (err < 0) { - refclock_report(peer, CEVNT_FAULT); - return; - } -#endif /* HAVE_PPSAPI */ - - /* - * 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, unless overriden by a fudge command. - */ - if (peer->burst > 0) - return; - peer->leap = LEAP_NOTINSYNC; - if (pp->codeproc == pp->coderecv) { - refclock_report(peer, CEVNT_TIMEOUT); - peer->burst = ASTAGE; - return; - - } else if (sys_prefer == NULL) { - 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->leap = LEAP_NOWARNING; - if (pp->stratum >= STRATUM_UNSPEC) - peer->stratum = sys_prefer->stratum; - else - peer->stratum = pp->stratum; - if (peer->stratum == STRATUM_REFCLOCK || peer->stratum == - STRATUM_UNSPEC) - peer->refid = pp->refid; - else - peer->refid = addr2refid(&sys_prefer->srcadr); - pp->lastref = pp->lastrec; - refclock_receive(peer); - 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 deleted file mode 100644 index a63be44..0000000 --- a/contrib/ntp/ntpd/refclock_bancomm.c +++ /dev/null @@ -1,433 +0,0 @@ -/* refclock_bancomm.c - clock driver for the Datum/Bancomm bc635VME - * Time and Frequency Processor. It requires the BANCOMM bc635VME/ - * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x - * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc - * IIi-cEngine running Solaris 2.6. - * - * Author(s): Ganesh Ramasivan & Gary Cliff, Computing Devices Canada, - * Ottawa, Canada - * - * Date: July 1999 - * - * Note(s): The refclock type has been defined as 16. - * - * This program has been modelled after the Bancomm driver - * originally written by R. Schmidt of Time Service, U.S. - * Naval Observatory for a HP-UX machine. Since the original - * authors no longer plan to maintain this code, all - * references to the HP-UX vme2 driver subsystem bave been - * removed. Functions vme_report_event(), vme_receive(), - * vme_control() and vme_buginfo() have been deleted because - * they are no longer being used. - * - * The time on the bc635 TFP must be set to GMT due to the - * fact that NTP makes use of GMT for all its calculations. - * - * Installation of the Datum/Bancomm driver creates the - * device file /dev/btfp0 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_BANC) - -#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> - -/* STUFF BY RES */ -struct btfp_time /* Structure for reading 5 time words */ - /* in one ioctl(2) operation. */ -{ - unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/ -}; - -/* SunOS5 ioctl commands definitions.*/ -#define BTFPIOC ( 'b'<< 8 ) -#define IOCIO( l, n ) ( BTFPIOC | n ) -#define IOCIOR( l, n, s ) ( BTFPIOC | n ) -#define IOCIORN( l, n, s ) ( BTFPIOC | n ) -#define IOCIOWN( l, n, s ) ( BTFPIOC | n ) - -/***** Simple ioctl commands *****/ -#define RUNLOCK IOCIOR(b, 19, int ) /* Release Capture Lockout */ -#define RCR0 IOCIOR(b, 22, int ) /* Read control register zero.*/ -#define WCR0 IOCIOWN(b, 23, int) /* Write control register zero*/ - -/***** Compound ioctl commands *****/ - -/* Read all 5 time words in one call. */ -#define READTIME IOCIORN(b, 32, sizeof( struct btfp_time )) -#define VMEFD "/dev/btfp0" - -struct vmedate { /* structure returned by get_vmetime.c */ - unsigned short year; - unsigned short day; - unsigned short hr; - unsigned short mn; - unsigned short sec; - unsigned long frac; - unsigned short status; -}; - -/* END OF STUFF FROM RES */ - -/* - * VME interface parameters. - */ -#define VMEPRECISION (-21) /* precision assumed (1 us) */ -#define USNOREFID "BTFP" /* or whatever */ -#define VMEREFID "BTFP" /* reference id */ -#define VMEDESCRIPTION "Bancomm bc635 TFP" /* who we are */ -#define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */ -/* clock type 16 is used here */ -#define GMT 0 /* hour offset from Greenwich */ - -/* - * Imported from ntp_timer module - */ -extern u_long current_time; /* current time(s) */ - -/* - * Imported from ntpd module - */ -extern int debug; /* global debug flag */ - -/* - * VME unit control structure. - * Changes made to vmeunit structure. Most members are now available in the - * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan - */ -struct vmeunit { - struct vmedate vmedata; /* data returned from vme read */ - u_long lasttime; /* last time clock heard from */ -}; - -/* - * Function prototypes - */ -static void vme_init (void); -static int vme_start (int, struct peer *); -static void vme_shutdown (int, struct peer *); -static void vme_receive (struct recvbuf *); -static void vme_poll (int unit, struct peer *); -struct vmedate *get_datumtime(struct vmedate *); - -/* - * Transfer vector - */ -struct refclock refclock_bancomm = { - 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_start - open the VME device and initialize data for processing - */ -static int -vme_start( - int unit, - struct peer *peer - ) -{ - register struct vmeunit *vme; - struct refclockproc *pp; - int dummy; - char vmedev[20]; - - /* - * Open VME device - */ -#ifdef DEBUG - - printf("Opening DATUM VME DEVICE \n"); -#endif - if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) { - msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev); - return (0); - } - else { /* Release capture lockout in case it was set from before. */ - if( ioctl( fd_vme, RUNLOCK, &dummy ) ) - msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m"); - - regvalue = 0; /* More esoteric stuff to do... */ - if( ioctl( fd_vme, WCR0, ®value ) ) - msyslog(LOG_ERR, "vme_start: WCR0 failed %m"); - } - - /* - * Allocate unit structure - */ - vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit)); - bzero((char *)vme, sizeof(struct vmeunit)); - - - /* - * Set up the structures - */ - pp = peer->procptr; - pp->unitptr = (caddr_t) vme; - pp->timestarted = current_time; - - pp->io.clock_recv = vme_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd_vme; - - /* - * All done. Initialize a few random peer variables, then - * return success. Note that root delay and root dispersion are - * always zero for this clock. - */ - peer->precision = VMEPRECISION; - memcpy(&pp->refid, USNOREFID,4); - return (1); -} - - -/* - * vme_shutdown - shut down a VME clock - */ -static void -vme_shutdown( - int unit, - struct peer *peer - ) -{ - register struct vmeunit *vme; - struct refclockproc *pp; - - /* - * 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; - free(vme); -} - - -/* - * vme_receive - receive data from the VME device. - * - * Note: This interface would be interrupt-driven. We don't use that - * now, but include a dummy routine for possible future adventures. - */ -static void -vme_receive( - struct recvbuf *rbufp - ) -{ -} - - -/* - * vme_poll - called by the transmit procedure - */ -static void -vme_poll( - int unit, - struct peer *peer - ) -{ - struct vmedate *tptr; - struct vmeunit *vme; - struct refclockproc *pp; - time_t tloc; - struct tm *tadr; - - pp = peer->procptr; - vme = (struct vmeunit *)pp->unitptr; /* Here is the structure */ - - tptr = &vme->vmedata; - if ((tptr = get_datumtime(tptr)) == NULL ) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - get_systime(&pp->lastrec); - pp->polls++; - vme->lasttime = current_time; - - /* - * Get VME time and convert to timestamp format. - * The year must come from the system clock. - */ - - time(&tloc); - tadr = gmtime(&tloc); - tptr->year = (unsigned short)(tadr->tm_year + 1900); - - - sprintf(pp->a_lastcode, - "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d", - tptr->day, - tptr->hr, - tptr->mn, - tptr->sec, - tptr->frac, - tptr->status); - - pp->lencode = (u_short) strlen(pp->a_lastcode); - - pp->day = tptr->day; - pp->hour = tptr->hr; - pp->minute = tptr->mn; - pp->second = tptr->sec; - pp->usec = tptr->frac; - -#ifdef DEBUG - if (debug) - printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n", - pp->day, pp->hour, pp->minute, pp->second, - pp->usec, tptr->status); -#endif - if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Now, compute the reference time value. Use the heavy - * machinery for the seconds and the millisecond field for the - * fraction when present. If an error in conversion to internal - * format is found, the program declares bad data and exits. - * Note that this code does not yet know how to do the years and - * relies on the clock-calendar chip for sanity. - */ - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -} - -struct vmedate * -get_datumtime(struct vmedate *time_vme) -{ - unsigned short status; - char cbuf[7]; - struct btfp_time vts; - - if ( time_vme == (struct vmedate *)NULL) { - time_vme = (struct vmedate *)malloc(sizeof(struct vmedate )); - } - - if( ioctl(fd_vme, READTIME, &vts)) - msyslog(LOG_ERR, "get_datumtime error: %m"); - - /* if you want to actually check the validity of these registers, do a - define of CHECK above this. I didn't find it necessary. - RES - */ - -#ifdef CHECK - - /* Get day */ - sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + - ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); - - if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) ) - time_vme->day = (unsigned short)atoi(cbuf); - else - time_vme->day = (unsigned short) 0; - - /* Get hour */ - sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff); - - if (isdigit(cbuf[0]) && isdigit(cbuf[1])) - time_vme->hr = (unsigned short)atoi(cbuf); - else - time_vme->hr = (unsigned short) 0; - - /* Get minutes */ - sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8); - if (isdigit(cbuf[0]) && isdigit(cbuf[1])) - time_vme->mn = (unsigned short)atoi(cbuf); - else - time_vme->mn = (unsigned short) 0; - - /* Get seconds */ - sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff); - - if (isdigit(cbuf[0]) && isdigit(cbuf[1])) - time_vme->sec = (unsigned short)atoi(cbuf); - else - time_vme->sec = (unsigned short) 0; - - /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can - use the TVTOTSF function later on...*/ - - sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ], - vts.btfp_time[ 4 ]>>8); - - if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) - && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5])) - time_vme->frac = (u_long) atoi(cbuf); - else - time_vme->frac = (u_long) 0; -#else - - /* DONT CHECK just trust the card */ - - /* Get day */ - sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + - ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); - time_vme->day = (unsigned short)atoi(cbuf); - - /* Get hour */ - sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff); - - time_vme->hr = (unsigned short)atoi(cbuf); - - /* Get minutes */ - sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8); - time_vme->mn = (unsigned short)atoi(cbuf); - - /* Get seconds */ - sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff); - time_vme->sec = (unsigned short)atoi(cbuf); - - /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can - use the TVTOTSF function later on...*/ - - sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ], - vts.btfp_time[ 4 ]>>8); - - time_vme->frac = (u_long) atoi(cbuf); - -#endif /* CHECK */ - - /* Get status bit */ - status = (vts.btfp_time[0] & 0x0010) >>4; - time_vme->status = status; /* Status=0 if locked to ref. */ - /* Status=1 if flywheeling */ - if (status) { /* lost lock ? */ - return ((void *)NULL); - } - else - return (time_vme); -} - -#else -int refclock_bancomm_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_chronolog.c b/contrib/ntp/ntpd/refclock_chronolog.c deleted file mode 100644 index a1d131e..0000000 --- a/contrib/ntp/ntpd/refclock_chronolog.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * refclock_chronolog - clock driver for Chronolog K-series WWVB receiver. - */ - -/* - * Must interpolate back to local time. Very annoying. - */ -#define GET_LOCALTIME - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_CHRONOLOG) - -#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. - * - * Input format: - * - * Y YY/MM/DD<cr><lf> - * Z hh:mm:ss<cr><lf> - * - * YY/MM/DD -- what you'd expect. This arrives a few seconds before the - * timestamp. - * hh:mm:ss -- what you'd expect. We take time on the <cr>. - * - * Our Chronolog writes time out at 2400 bps 8/N/1, but it can be configured - * otherwise. The clock seems to appear every 60 seconds, which doesn't make - * for good statistics collection. - * - * The original source of this module was the WWVB module. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/chronolog%d" /* device name and unit */ -#define SPEED232 B2400 /* uart speed (2400 baud) */ -#define PRECISION (-13) /* precision assumed (about 100 us) */ -#define REFID "chronolog" /* reference ID */ -#define DESCRIPTION "Chrono-log K" /* WRU */ - -#define MONLIN 15 /* number of monitoring lines */ - -/* - * Chrono-log unit control structure - */ -struct chronolog_unit { - u_char tcswitch; /* timecode switch */ - l_fp laststamp; /* last receive timestamp */ - u_char lasthour; /* last hour (for monitor) */ - int year; /* Y2K-adjusted year */ - int day; /* day-of-month */ - int month; /* month-of-year */ -}; - -/* - * Function prototypes - */ -static int chronolog_start P((int, struct peer *)); -static void chronolog_shutdown P((int, struct peer *)); -static void chronolog_receive P((struct recvbuf *)); -static void chronolog_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_chronolog = { - chronolog_start, /* start up driver */ - chronolog_shutdown, /* shut down driver */ - chronolog_poll, /* poll the driver -- a nice fabrication */ - noentry, /* not used */ - noentry, /* not used */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - - -/* - * chronolog_start - open the devices and initialize data for processing - */ -static int -chronolog_start( - int unit, - struct peer *peer - ) -{ - register struct chronolog_unit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Don't bother with CLK line discipline, since - * it's not available. - */ - (void)sprintf(device, DEVICE, unit); -#ifdef DEBUG - if (debug) - printf ("starting Chronolog with device %s\n",device); -#endif - if (!(fd = refclock_open(device, SPEED232, 0))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct chronolog_unit *) - emalloc(sizeof(struct chronolog_unit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct chronolog_unit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = chronolog_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - return (1); -} - - -/* - * chronolog_shutdown - shut down the clock - */ -static void -chronolog_shutdown( - int unit, - struct peer *peer - ) -{ - register struct chronolog_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct chronolog_unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * chronolog_receive - receive data from the serial interface - */ -static void -chronolog_receive( - struct recvbuf *rbufp - ) -{ - struct chronolog_unit *up; - struct refclockproc *pp; - struct peer *peer; - - l_fp trtmp; /* arrival timestamp */ - int hours; /* hour-of-day */ - int minutes; /* minutes-past-the-hour */ - int seconds; /* seconds */ - int temp; /* int temp */ - int got_good; /* got a good time flag */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct chronolog_unit *)pp->unitptr; - temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); - - if (temp == 0) { - if (up->tcswitch == 0) { - up->tcswitch = 1; - up->laststamp = trtmp; - } else - up->tcswitch = 0; - return; - } - pp->lencode = temp; - pp->lastrec = up->laststamp; - up->laststamp = trtmp; - up->tcswitch = 1; - -#ifdef DEBUG - if (debug) - printf("chronolog: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - - /* - * We get down to business. Check the timecode format and decode - * its contents. This code uses the first character to see whether - * we're looking at a date or a time. We store data data across - * calls since it is transmitted a few seconds ahead of the - * timestamp. - */ - got_good=0; - if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day)) - { - /* - * Y2K convert the 2-digit year - */ - up->year = up->year >= 69 ? up->year : up->year + 100; - return; - } - if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d", - &hours,&minutes,&seconds) == 3) - { -#ifdef GET_LOCALTIME - struct tm local; - struct tm *gmtp; - time_t unixtime; - int adjyear; - int adjmon; - - /* - * Convert to GMT for sites that distribute localtime. This - * means we have to do Y2K conversion on the 2-digit year; - * otherwise, we get the time wrong. - */ - - local.tm_year = up->year; - local.tm_mon = up->month-1; - local.tm_mday = up->day; - local.tm_hour = hours; - local.tm_min = minutes; - local.tm_sec = seconds; - local.tm_isdst = -1; - - unixtime = mktime (&local); - if ((gmtp = gmtime (&unixtime)) == NULL) - { - refclock_report (peer, CEVNT_FAULT); - return; - } - adjyear = gmtp->tm_year+1900; - adjmon = gmtp->tm_mon+1; - pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday); - pp->hour = gmtp->tm_hour; - pp->minute = gmtp->tm_min; - pp->second = gmtp->tm_sec; -#ifdef DEBUG - if (debug) - printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", - adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute, - pp->second); -#endif - -#else - /* - * For more rational sites distributing UTC - */ - pp->day = ymd2yd(year+1900,month,day); - pp->hour = hours; - pp->minute = minutes; - pp->second = seconds; - -#endif - got_good=1; - } - - if (!got_good) - return; - - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); - up->lasthour = pp->hour; -} - - -/* - * chronolog_poll - called by the transmit procedure - */ -static void -chronolog_poll( - int unit, - struct peer *peer - ) -{ - /* - * Time to poll the clock. The Chrono-log clock is supposed to - * respond to a 'T' by returning a timecode in the format(s) - * specified above. Ours does (can?) not, but this seems to be - * an installation-specific problem. This code is dyked out, - * but may be re-enabled if anyone ever finds a Chrono-log that - * actually listens to this command. - */ -#if 0 - register struct chronolog_unit *up; - struct refclockproc *pp; - char pollchar; - - pp = peer->procptr; - up = (struct chronolog_unit *)pp->unitptr; - if (peer->burst == 0 && peer->reach == 0) - refclock_report(peer, CEVNT_TIMEOUT); - if (up->linect > 0) - pollchar = 'R'; - else - pollchar = 'T'; - if (write(pp->io.fd, &pollchar, 1) != 1) - refclock_report(peer, CEVNT_FAULT); - else - pp->polls++; -#endif -} - -#else -int refclock_chronolog_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_chu.c b/contrib/ntp/ntpd/refclock_chu.c deleted file mode 100644 index e0c79e2..0000000 --- a/contrib/ntp/ntpd/refclock_chu.c +++ /dev/null @@ -1,1687 +0,0 @@ -/* - * refclock_chu - clock driver for Canadian CHU time/frequency station - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_CHU) - -#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 <math.h> - -#ifdef HAVE_AUDIO -#include "audio.h" -#endif /* HAVE_AUDIO */ - -#define ICOM 1 /* undefine to suppress ICOM code */ - -#ifdef ICOM -#include "icom.h" -#endif /* ICOM */ - -/* - * Audio CHU demodulator/decoder - * - * This driver synchronizes the computer time using data encoded in - * radio transmissions from Canadian time/frequency station CHU in - * Ottawa, Ontario. Transmissions are made continuously on 3330 kHz, - * 7335 kHz and 14670 kHz in upper sideband, compatible AM mode. An - * ordinary shortwave receiver can be tuned manually to one of these - * frequencies or, in the case of ICOM receivers, the receiver can be - * tuned automatically using this program as propagation conditions - * change throughout the day and night. - * - * The driver receives, demodulates and decodes the radio signals when - * connected to the audio codec of a suported workstation hardware and - * operating system. These include Solaris, SunOS, FreeBSD, NetBSD and - * Linux. In this implementation, only one audio driver and codec can be - * supported on a single machine. - * - * The driver can be compiled to use a Bell 103 compatible modem or - * modem chip to receive the radio signal and demodulate the data. - * Alternatively, the driver can be compiled to use the audio codec of - * the Sun workstation or another with compatible audio drivers. In the - * latter case, the driver implements the modem using DSP routines, so - * the radio can be connected directly to either the microphone on line - * input port. In either case, the driver decodes the data using a - * maximum likelihood technique which exploits the considerable degree - * of redundancy available to maximize accuracy and minimize errors. - * - * The CHU time broadcast includes an audio signal compatible with the - * Bell 103 modem standard (mark = 2225 Hz, space = 2025 Hz). It consist - * of nine, ten-character bursts transmitted at 300 bps and beginning - * each second from second 31 to second 39 of the minute. Each character - * consists of eight data bits plus one start bit and two stop bits to - * encode two hex digits. The burst data consist of five characters (ten - * hex digits) followed by a repeat of these characters. In format A, - * the characters are repeated in the same polarity; in format B, the - * characters are repeated in the opposite polarity. - * - * Format A bursts are sent at seconds 32 through 39 of the minute in - * hex digits - * - * 6dddhhmmss6dddhhmmss - * - * The first ten digits encode a frame marker (6) followed by the day - * (ddd), hour (hh in UTC), minute (mm) and the second (ss). Since - * format A bursts are sent during the third decade of seconds the tens - * digit of ss is always 3. The driver uses this to determine correct - * burst synchronization. These digits are then repeated with the same - * polarity. - * - * Format B bursts are sent at second 31 of the minute in hex digits - * - * xdyyyyttaaxdyyyyttaa - * - * The first ten digits encode a code (x described below) followed by - * the DUT1 (d in deciseconds), Gregorian year (yyyy), difference TAI - - * UTC (tt) and daylight time indicator (aa) peculiar to Canada. These - * digits are then repeated with inverted polarity. - * - * The x is coded - * - * 1 Sign of DUT (0 = +) - * 2 Leap second warning. One second will be added. - * 4 Leap second warning. One second will be subtracted. - * 8 Even parity bit for this nibble. - * - * By design, the last stop bit of the last character in the burst - * coincides with 0.5 second. Since characters have 11 bits and are - * transmitted at 300 bps, the last stop bit of the first character - * coincides with 0.5 - 10 * 11/300 = 0.133 second. Depending on the - * UART, character interrupts can vary somewhere between the beginning - * of bit 9 and end of bit 11. These eccentricities can be corrected - * along with the radio propagation delay using fudge time 1. - * - * Debugging aids - * - * The timecode format used for debugging and data recording includes - * data helpful in diagnosing problems with the radio signal and serial - * connections. With debugging enabled (-d on the ntpd command line), - * the driver produces one line for each burst in two formats - * corresponding to format A and B. Following is format A: - * - * n b f s m code - * - * where n is the number of characters in the burst (0-11), b the burst - * distance (0-40), f the field alignment (-1, 0, 1), s the - * synchronization distance (0-16), m the burst number (2-9) and code - * the burst characters as received. Note that the hex digits in each - * character are reversed, so the burst - * - * 10 38 0 16 9 06851292930685129293 - * - * is interpreted as containing 11 characters with burst distance 38, - * field alignment 0, synchronization distance 16 and burst number 9. - * The nibble-swapped timecode shows day 58, hour 21, minute 29 and - * second 39. - * - * When the audio driver is compiled, format A is preceded by - * the current gain (0-255) and relative signal level (0-9999). The - * receiver folume control should be set so that the gain is somewhere - * near the middle of the range 0-255, which results in a signal level - * near 1000. - * - * Following is format B: - * - * n b s code - * - * where n is the number of characters in the burst (0-11), b the burst - * distance (0-40), s the synchronization distance (0-40) and code the - * burst characters as received. Note that the hex digits in each - * character are reversed and the last ten digits inverted, so the burst - * - * 11 40 1091891300ef6e76ecff - * - * is interpreted as containing 11 characters with burst distance 40. - * The nibble-swapped timecode shows DUT1 +0.1 second, year 1998 and TAI - * - UTC 31 seconds. - * - * In addition to the above, the reference timecode is updated and - * written to the clockstats file and debug score after the last burst - * received in the minute. The format is - * - * qq yyyy ddd hh:mm:ss nn dd tt - * - * where qq are the error flags, as described below, yyyy is the year, - * ddd the day, hh:mm:ss the time of day, nn the number of format A - * bursts received during the previous minute, dd the decoding distance - * and tt the number of timestamps. The error flags are cleared after - * every update. - * - * Fudge factors - * - * For accuracies better than the low millisceconds, fudge time1 can be - * set to the radio propagation delay from CHU to the receiver. This can - * be done conviently using the minimuf program. - * - * Fudge flag4 causes the dubugging output described above to be - * recorded in the clockstats file. When the audio driver is compiled, - * fudge flag2 selects the audio input port, where 0 is the mike port - * (default) and 1 is the line-in port. It does not seem useful to - * select the compact disc player port. Fudge flag3 enables audio - * monitoring of the input signal. For this purpose, the monitor gain is - * set to a default value. - * - * The audio codec code is normally compiled in the driver if the - * architecture supports it (HAVE_AUDIO defined), but is used only if - * the link /dev/chu_audio is defined and valid. The serial port code is - * always compiled in the driver, but is used only if the autdio codec - * is not available and the link /dev/chu%d is defined and valid. - * - * The ICOM code is normally compiled in the driver if selected (ICOM - * defined), but is used only if the link /dev/icom%d is defined and - * valid and the mode keyword on the server configuration command - * 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 - */ -#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 TUNE .001 /* offset for narrow filter (kHz) */ -#define DWELL 5 /* minutes in a probe cycle */ -#define NCHAN 3 /* number of channels */ -#define ISTAGE 3 /* number of integrator stages */ -#endif /* ICOM */ - -#ifdef HAVE_AUDIO -/* - * Audio demodulator definitions - */ -#define SECOND 8000 /* nominal sample rate (Hz) */ -#define BAUD 300 /* modulation rate (bps) */ -#define OFFSET 128 /* companded sample offset */ -#define SIZE 256 /* decompanding table size */ -#define MAXSIG 6000. /* maximum signal level */ -#define MAXCLP 100 /* max clips above reference per s */ -#define LIMIT 1000. /* soft limiter threshold */ -#define AGAIN 6. /* baseband gain */ -#define LAG 10 /* discriminator lag */ -#define DEVICE_AUDIO "/dev/chu_audio" /* device name */ -#define DESCRIPTION "CHU Audio/Modem Receiver" /* WRU */ -#define AUDIO_BUFSIZ 240 /* audio buffer size (30 ms) */ -#else -#define DESCRIPTION "CHU Modem Receiver" /* WRU */ -#endif /* HAVE_AUDIO */ - -/* - * Decoder definitions - */ -#define CHAR (11. / 300.) /* character time (s) */ -#define FUDGE .185 /* offset to first stop bit (s) */ -#define BURST 11 /* max characters per burst */ -#define MINCHAR 9 /* min characters per burst */ -#define MINDIST 28 /* min burst distance (of 40) */ -#define MINBURST 4 /* min bursts in minute */ -#define MINSYNC 8 /* min sync distance (of 16) */ -#define MINSTAMP 20 /* min timestamps (of 60) */ -#define METRIC 50. /* min channel metric */ -#define PANIC 1440 /* panic timeout (m) */ -#define HOLD 30 /* reach hold (m) */ - -/* - * Hex extension codes (>= 16) - */ -#define HEX_MISS 16 /* miss _ */ -#define HEX_SOFT 17 /* soft error * */ -#define HEX_HARD 18 /* hard error = */ - -/* - * Status bits (status) - */ -#define RUNT 0x0001 /* runt burst */ -#define NOISE 0x0002 /* noise burst */ -#define BFRAME 0x0004 /* invalid format B frame sync */ -#define BFORMAT 0x0008 /* invalid format B data */ -#define AFRAME 0x0010 /* invalid format A frame sync */ -#define AFORMAT 0x0020 /* invalid format A data */ -#define DECODE 0x0040 /* invalid data decode */ -#define STAMP 0x0080 /* too few timestamps */ -#define AVALID 0x0100 /* valid A frame */ -#define BVALID 0x0200 /* valid B frame */ -#define INSYNC 0x0400 /* clock synchronized */ - -/* - * Alarm status bits (alarm) - * - * These alarms are set at the end of a minute in which at least one - * burst was received. SYNERR is raised if the AFRAME or BFRAME status - * bits are set during the minute, FMTERR is raised if the AFORMAT or - * BFORMAT status bits are set, DECERR is raised if the DECODE status - * bit is set and TSPERR is raised if the STAMP status bit is set. - */ -#define SYNERR 0x01 /* frame sync error */ -#define FMTERR 0x02 /* data format error */ -#define DECERR 0x04 /* data decoding error */ -#define TSPERR 0x08 /* insufficient data */ - -#ifdef HAVE_AUDIO -/* - * Maximum likelihood UART structure. There are eight of these - * corresponding to the number of phases. - */ -struct surv { - double shift[12]; /* mark register */ - double es_max, es_min; /* max/min envelope signals */ - double dist; /* sample distance */ - int uart; /* decoded character */ -}; -#endif /* HAVE_AUDIO */ - -#ifdef ICOM -/* - * CHU station structure. There are three of these corresponding to the - * three frequencies. - */ -struct xmtr { - double integ[ISTAGE]; /* circular integrator */ - double metric; /* integrator sum */ - int iptr; /* integrator pointer */ - int probe; /* dwells since last probe */ -}; -#endif /* ICOM */ - -/* - * CHU unit control structure - */ -struct chuunit { - u_char decode[20][16]; /* maximum likelihood decoding matrix */ - l_fp cstamp[BURST]; /* character timestamps */ - l_fp tstamp[MAXSTAGE]; /* timestamp samples */ - l_fp timestamp; /* current buffer timestamp */ - l_fp laststamp; /* last buffer timestamp */ - l_fp charstamp; /* character time as a l_fp */ - int errflg; /* error flags */ - int status; /* status bits */ - char ident[5]; /* station ID and channel */ -#ifdef ICOM - int fd_icom; /* ICOM file descriptor */ - int chan; /* data channel */ - int achan; /* active channel */ - int dwell; /* dwell cycle */ - struct xmtr xmtr[NCHAN]; /* station metric */ -#endif /* ICOM */ - - /* - * Character burst variables - */ - int cbuf[BURST]; /* character buffer */ - int ntstamp; /* number of timestamp samples */ - int ndx; /* buffer start index */ - int prevsec; /* previous burst second */ - int burdist; /* burst distance */ - int syndist; /* sync distance */ - int burstcnt; /* format A bursts this minute */ - - /* - * Format particulars - */ - int leap; /* leap/dut code */ - int dut; /* UTC1 correction */ - int tai; /* TAI - UTC correction */ - int dst; /* Canadian DST code */ - -#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 */ - int mongain; /* codec monitor gain */ - int clipcnt; /* sample clip count */ - int seccnt; /* second interval counter */ - - /* - * Modem variables - */ - l_fp tick; /* audio sample increment */ - double bpf[9]; /* IIR bandpass filter */ - double disc[LAG]; /* discriminator shift register */ - double lpf[27]; /* FIR lowpass filter */ - double monitor; /* audio monitor */ - double maxsignal; /* signal level */ - int discptr; /* discriminator pointer */ - - /* - * Maximum likelihood UART variables - */ - double baud; /* baud interval */ - struct surv surv[8]; /* UART survivor structures */ - int decptr; /* decode pointer */ - int dbrk; /* holdoff counter */ -#endif /* HAVE_AUDIO */ -}; - -/* - * Function prototypes - */ -static int chu_start P((int, struct peer *)); -static void chu_shutdown P((int, struct peer *)); -static void chu_receive P((struct recvbuf *)); -static void chu_poll P((int, struct peer *)); - -/* - * More function prototypes - */ -static void chu_decode P((struct peer *, int)); -static void chu_burst P((struct peer *)); -static void chu_clear P((struct peer *)); -static void chu_a P((struct peer *, int)); -static void chu_b P((struct peer *, int)); -static int chu_dist P((int, int)); -static double chu_major P((struct peer *)); -#ifdef HAVE_AUDIO -static void chu_uart P((struct surv *, double)); -static void chu_rf P((struct peer *, double)); -static void chu_gain P((struct peer *)); -static void chu_audio_receive P((struct recvbuf *rbufp)); -#endif /* HAVE_AUDIO */ -#ifdef ICOM -static int chu_newchan P((struct peer *, double)); -#endif /* ICOM */ -static void chu_serial_receive P((struct recvbuf *rbufp)); - -/* - * Global variables - */ -static char hexchar[] = "0123456789abcdef_*="; - -#ifdef ICOM -/* - * Note the tuned frequencies are 1 kHz higher than the carrier. CHU - * transmits on USB with carrier so we can use AM and the narrow SSB - * filter. - */ -static double qsy[NCHAN] = {3.330, 7.335, 14.670}; /* freq (MHz) */ -#endif /* ICOM */ - -/* - * Transfer vector - */ -struct refclock refclock_chu = { - chu_start, /* start up driver */ - chu_shutdown, /* shut down driver */ - chu_poll, /* transmit poll message */ - noentry, /* not used (old chu_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old chu_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * chu_start - open the devices and initialize data for processing - */ -static int -chu_start( - int unit, /* instance number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct chuunit *up; - struct refclockproc *pp; - char device[20]; /* device name */ - int fd; /* file descriptor */ -#ifdef ICOM - int temp; -#endif /* ICOM */ -#ifdef HAVE_AUDIO - int fd_audio; /* audio port file descriptor */ - int i; /* index */ - double step; /* codec adjustment */ - - /* - * Open audio device. - */ - fd_audio = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); -#ifdef DEBUG - if (fd_audio > 0 && debug) - audio_show(); -#endif - - /* - * Open serial port in raw mode. - */ - if (fd_audio > 0) { - fd = fd_audio; - } else { - sprintf(device, DEVICE, unit); - fd = refclock_open(device, SPEED232, LDISC_RAW); - } -#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)))) { - close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct chuunit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = chu_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - strcpy(up->ident, "CHU"); - memcpy(&peer->refid, up->ident, 4); - DTOLFP(CHAR, &up->charstamp); -#ifdef HAVE_AUDIO - - /* - * The companded samples are encoded sign-magnitude. The table - * 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.; - step = 2.; - for (i = 3; i < OFFSET; i++) { - up->comp[i] = up->comp[i - 1] + step; - up->comp[OFFSET + i] = -up->comp[i]; - if (i % 16 == 0) - step *= 2.; - } - DTOLFP(1. / SECOND, &up->tick); -#endif /* HAVE_AUDIO */ -#ifdef ICOM - temp = 0; -#ifdef DEBUG - if (debug > 1) - temp = P_TRACE; -#endif - if (peer->ttl > 0) { - if (peer->ttl & 0x80) - up->fd_icom = icom_init("/dev/icom", B1200, - temp); - else - up->fd_icom = icom_init("/dev/icom", B9600, - temp); - } - if (up->fd_icom > 0) { - if (chu_newchan(peer, 0) != 0) { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: radio not found"); - up->errflg = CEVNT_FAULT; - close(up->fd_icom); - up->fd_icom = 0; - } else { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: autotune enabled"); - } - } -#endif /* ICOM */ - return (1); -} - - -/* - * chu_shutdown - shut down the clock - */ -static void -chu_shutdown( - int unit, /* instance number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct chuunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - if (up == NULL) - return; - - io_closeclock(&pp->io); -#ifdef ICOM - if (up->fd_icom > 0) - close(up->fd_icom); -#endif /* ICOM */ - free(up); -} - - -/* - * chu_receive - receive data from the audio or serial device - */ -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; - - double sample; /* codec sample */ - u_char *dpt; /* buffer pointer */ - int bufcnt; /* buffer counter */ - l_fp ltemp; /* l_fp temp */ - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Main loop - read until there ain't no more. Note codec - * samples are bit-inverted. - */ - DTOLFP((double)rbufp->recv_length / SECOND, <emp); - L_SUB(&rbufp->recv_time, <emp); - up->timestamp = rbufp->recv_time; - dpt = rbufp->recv_buffer; - for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { - sample = up->comp[~*dpt++ & 0xff]; - - /* - * Clip noise spikes greater than MAXSIG. If no clips, - * increase the gain a tad; if the clips are too high, - * decrease a tad. - */ - if (sample > MAXSIG) { - sample = MAXSIG; - up->clipcnt++; - } else if (sample < -MAXSIG) { - sample = -MAXSIG; - up->clipcnt++; - } - chu_rf(peer, sample); - L_ADD(&up->timestamp, &up->tick); - - /* - * Once each second ride gain. - */ - up->seccnt = (up->seccnt + 1) % SECOND; - if (up->seccnt == 0) { - pp->second = (pp->second + 1) % 60; - chu_gain(peer); - } - } - - /* - * Set the input port and monitor gain for the next buffer. - */ - if (pp->sloppyclockflag & CLK_FLAG2) - up->port = 2; - else - up->port = 1; - if (pp->sloppyclockflag & CLK_FLAG3) - up->mongain = MONGAIN; - else - up->mongain = 0; -} - - -/* - * chu_rf - filter and demodulate the FSK signal - * - * This routine implements a 300-baud Bell 103 modem with mark 2225 Hz - * and space 2025 Hz. It uses a bandpass filter followed by a soft - * limiter, FM discriminator and lowpass filter. A maximum likelihood - * decoder samples the baseband signal at eight times the baud rate and - * detects the start bit of each character. - * - * The filters are built for speed, which explains the rather clumsy - * code. Hopefully, the compiler will efficiently implement the move- - * and-muiltiply-and-add operations. - */ -static void -chu_rf( - struct peer *peer, /* peer structure pointer */ - double sample /* analog sample */ - ) -{ - struct refclockproc *pp; - struct chuunit *up; - struct surv *sp; - - /* - * Local variables - */ - double signal; /* bandpass signal */ - double limit; /* limiter signal */ - double disc; /* discriminator signal */ - double lpf; /* lowpass signal */ - double span; /* UART signal span */ - double dist; /* UART signal distance */ - int i, j; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Bandpass filter. 4th-order elliptic, 500-Hz bandpass centered - * at 2125 Hz. Passband ripple 0.3 dB, stopband ripple 50 dB. - */ - signal = (up->bpf[8] = up->bpf[7]) * 5.844676e-01; - signal += (up->bpf[7] = up->bpf[6]) * 4.884860e-01; - signal += (up->bpf[6] = up->bpf[5]) * 2.704384e+00; - signal += (up->bpf[5] = up->bpf[4]) * 1.645032e+00; - signal += (up->bpf[4] = up->bpf[3]) * 4.644557e+00; - signal += (up->bpf[3] = up->bpf[2]) * 1.879165e+00; - signal += (up->bpf[2] = up->bpf[1]) * 3.522634e+00; - signal += (up->bpf[1] = up->bpf[0]) * 7.315738e-01; - up->bpf[0] = sample - signal; - signal = up->bpf[0] * 6.176213e-03 - + up->bpf[1] * 3.156599e-03 - + up->bpf[2] * 7.567487e-03 - + up->bpf[3] * 4.344580e-03 - + up->bpf[4] * 1.190128e-02 - + up->bpf[5] * 4.344580e-03 - + up->bpf[6] * 7.567487e-03 - + up->bpf[7] * 3.156599e-03 - + up->bpf[8] * 6.176213e-03; - - up->monitor = signal / 4.; /* note monitor after filter */ - - /* - * Soft limiter/discriminator. The 11-sample discriminator lag - * interval corresponds to three cycles of 2125 Hz, which - * requires the sample frequency to be 2125 * 11 / 3 = 7791.7 - * Hz. The discriminator output varies +-0.5 interval for input - * frequency 2025-2225 Hz. However, we don't get to sample at - * this frequency, so the discriminator output is biased. Life - * at 8000 Hz sucks. - */ - limit = signal; - if (limit > LIMIT) - limit = LIMIT; - else if (limit < -LIMIT) - limit = -LIMIT; - disc = up->disc[up->discptr] * -limit; - up->disc[up->discptr] = limit; - up->discptr = (up->discptr + 1 ) % LAG; - if (disc >= 0) - disc = SQRT(disc); - else - disc = -SQRT(-disc); - - /* - * Lowpass filter. Raised cosine, Ts = 1 / 300, beta = 0.1. - */ - lpf = (up->lpf[26] = up->lpf[25]) * 2.538771e-02; - lpf += (up->lpf[25] = up->lpf[24]) * 1.084671e-01; - lpf += (up->lpf[24] = up->lpf[23]) * 2.003159e-01; - lpf += (up->lpf[23] = up->lpf[22]) * 2.985303e-01; - lpf += (up->lpf[22] = up->lpf[21]) * 4.003697e-01; - lpf += (up->lpf[21] = up->lpf[20]) * 5.028552e-01; - lpf += (up->lpf[20] = up->lpf[19]) * 6.028795e-01; - lpf += (up->lpf[19] = up->lpf[18]) * 6.973249e-01; - lpf += (up->lpf[18] = up->lpf[17]) * 7.831828e-01; - lpf += (up->lpf[17] = up->lpf[16]) * 8.576717e-01; - lpf += (up->lpf[16] = up->lpf[15]) * 9.183463e-01; - lpf += (up->lpf[15] = up->lpf[14]) * 9.631951e-01; - lpf += (up->lpf[14] = up->lpf[13]) * 9.907208e-01; - lpf += (up->lpf[13] = up->lpf[12]) * 1.000000e+00; - lpf += (up->lpf[12] = up->lpf[11]) * 9.907208e-01; - lpf += (up->lpf[11] = up->lpf[10]) * 9.631951e-01; - lpf += (up->lpf[10] = up->lpf[9]) * 9.183463e-01; - lpf += (up->lpf[9] = up->lpf[8]) * 8.576717e-01; - lpf += (up->lpf[8] = up->lpf[7]) * 7.831828e-01; - lpf += (up->lpf[7] = up->lpf[6]) * 6.973249e-01; - lpf += (up->lpf[6] = up->lpf[5]) * 6.028795e-01; - lpf += (up->lpf[5] = up->lpf[4]) * 5.028552e-01; - lpf += (up->lpf[4] = up->lpf[3]) * 4.003697e-01; - lpf += (up->lpf[3] = up->lpf[2]) * 2.985303e-01; - lpf += (up->lpf[2] = up->lpf[1]) * 2.003159e-01; - lpf += (up->lpf[1] = up->lpf[0]) * 1.084671e-01; - lpf += up->lpf[0] = disc * 2.538771e-02; - - /* - * Maximum likelihood decoder. The UART updates each of the - * eight survivors and determines the span, slice level and - * tentative decoded character. Valid 11-bit characters are - * framed so that bit 1 and bit 11 (stop bits) are mark and bit - * 2 (start bit) is space. When a valid character is found, the - * survivor with maximum distance determines the final decoded - * character. - */ - up->baud += 1. / SECOND; - if (up->baud > 1. / (BAUD * 8.)) { - up->baud -= 1. / (BAUD * 8.); - sp = &up->surv[up->decptr]; - span = sp->es_max - sp->es_min; - up->maxsignal += (span - up->maxsignal) / 80.; - if (up->dbrk > 0) { - up->dbrk--; - } else if ((sp->uart & 0x403) == 0x401 && span > 1000.) - { - dist = 0; - j = 0; - for (i = 0; i < 8; i++) { - if (up->surv[i].dist > dist) { - dist = up->surv[i].dist; - j = i; - } - } - chu_decode(peer, (up->surv[j].uart >> 2) & - 0xff); - up->dbrk = 80; - } - up->decptr = (up->decptr + 1) % 8; - chu_uart(sp, -lpf * AGAIN); - } -} - - -/* - * chu_uart - maximum likelihood UART - * - * This routine updates a shift register holding the last 11 envelope - * samples. It then computes the slice level and span over these samples - * and determines the tentative data bits and distance. The calling - * program selects over the last eight survivors the one with maximum - * distance to determine the decoded character. - */ -static void -chu_uart( - struct surv *sp, /* survivor structure pointer */ - double sample /* baseband signal */ - ) -{ - double es_max, es_min; /* max/min envelope */ - double slice; /* slice level */ - double dist; /* distance */ - double dtemp; - int i; - - /* - * Save the sample and shift right. At the same time, measure - * the maximum and minimum over all eleven samples. - */ - es_max = -1e6; - es_min = 1e6; - sp->shift[0] = sample; - for (i = 11; i > 0; i--) { - sp->shift[i] = sp->shift[i - 1]; - if (sp->shift[i] > es_max) - es_max = sp->shift[i]; - if (sp->shift[i] < es_min) - es_min = sp->shift[i]; - } - - /* - * Determine the slice level midway beteen the maximum and - * minimum and the span as the maximum less the minimum. Compute - * the distance on the assumption the first and last bits must - * be mark, the second space and the rest either mark or space. - */ - slice = (es_max + es_min) / 2.; - dist = 0; - sp->uart = 0; - for (i = 1; i < 12; i++) { - sp->uart <<= 1; - dtemp = sp->shift[i]; - if (dtemp > slice) - sp->uart |= 0x1; - if (i == 1 || i == 11) { - dist += dtemp - es_min; - } else if (i == 10) { - dist += es_max - dtemp; - } else { - if (dtemp > slice) - dist += dtemp - es_min; - else - dist += es_max - dtemp; - } - } - sp->es_max = es_max; - sp->es_min = es_min; - sp->dist = dist / (11 * (es_max - es_min)); -} -#endif /* HAVE_AUDIO */ - - -/* - * chu_serial_receive - receive data from the serial device - */ -static void -chu_serial_receive( - struct recvbuf *rbufp /* receive buffer structure pointer */ - ) -{ - struct chuunit *up; - struct refclockproc *pp; - struct peer *peer; - - u_char *dpt; /* receive buffer pointer */ - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Initialize pointers and read the timecode and timestamp. - */ - up->timestamp = rbufp->recv_time; - dpt = (u_char *)&rbufp->recv_space; - chu_decode(peer, *dpt); -} - - -/* - * chu_decode - decode the character data - */ -static void -chu_decode( - struct peer *peer, /* peer structure pointer */ - int hexhex /* data character */ - ) -{ - struct refclockproc *pp; - struct chuunit *up; - - l_fp tstmp; /* timestamp temp */ - double dtemp; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * If the interval since the last character is greater than the - * longest burst, process the last burst and start a new one. If - * the interval is less than this but greater than two - * characters, consider this a noise burst and reject it. - */ - tstmp = up->timestamp; - if (L_ISZERO(&up->laststamp)) - up->laststamp = up->timestamp; - L_SUB(&tstmp, &up->laststamp); - up->laststamp = up->timestamp; - LFPTOD(&tstmp, dtemp); - if (dtemp > BURST * CHAR) { - chu_burst(peer); - up->ndx = 0; - } else if (dtemp > 2.5 * CHAR) { - up->ndx = 0; - } - - /* - * Append the character to the current burst and append the - * timestamp to the timestamp list. - */ - if (up->ndx < BURST) { - up->cbuf[up->ndx] = hexhex & 0xff; - up->cstamp[up->ndx] = up->timestamp; - up->ndx++; - - } -} - - -/* - * chu_burst - search for valid burst format - */ -static void -chu_burst( - struct peer *peer - ) -{ - struct chuunit *up; - struct refclockproc *pp; - - int i; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Correlate a block of five characters with the next block of - * five characters. The burst distance is defined as the number - * of bits that match in the two blocks for format A and that - * match the inverse for format B. - */ - if (up->ndx < MINCHAR) { - up->status |= RUNT; - return; - } - up->burdist = 0; - for (i = 0; i < 5 && i < up->ndx - 5; i++) - up->burdist += chu_dist(up->cbuf[i], up->cbuf[i + 5]); - - /* - * If the burst distance is at least MINDIST, this must be a - * format A burst; if the value is not greater than -MINDIST, it - * must be a format B burst. If the B burst is perfect, we - * believe it; otherwise, it is a noise burst and of no use to - * anybody. - */ - if (up->burdist >= MINDIST) { - chu_a(peer, up->ndx); - } else if (up->burdist <= -MINDIST) { - chu_b(peer, up->ndx); - } else { - up->status |= NOISE; - return; - } - - /* - * If this is a valid burst, wait a guard time of ten seconds to - * allow for more bursts, then arm the poll update routine to - * process the minute. Don't do this if this is called from the - * timer interrupt routine. - */ - if (peer->outdate != current_time) - peer->nextdate = current_time + 10; -} - - -/* - * chu_b - decode format B burst - */ -static void -chu_b( - struct peer *peer, - int nchar - ) -{ - struct refclockproc *pp; - struct chuunit *up; - - u_char code[11]; /* decoded timecode */ - char tbuf[80]; /* trace buffer */ - l_fp offset; /* timestamp offset */ - int i; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * In a format B burst, a character is considered valid only if - * the first occurrence matches the last occurrence. The burst - * is considered valid only if all characters are valid; that - * is, only if the distance is 40. Note that once a valid frame - * has been found errors are ignored. - */ - sprintf(tbuf, "chuB %04x %2d %2d ", up->status, nchar, - -up->burdist); - for (i = 0; i < nchar; i++) - sprintf(&tbuf[strlen(tbuf)], "%02x", up->cbuf[i]); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif - if (up->burdist > -40) { - up->status |= BFRAME; - return; - } - up->status |= BVALID; - - /* - * Convert the burst data to internal format. If this succeeds, - * save the timestamps for later. - */ - for (i = 0; i < 5; i++) { - code[2 * i] = hexchar[up->cbuf[i] & 0xf]; - code[2 * i + 1] = hexchar[(up->cbuf[i] >> - 4) & 0xf]; - } - if (sscanf((char *)code, "%1x%1d%4d%2d%2x", &up->leap, &up->dut, - &pp->year, &up->tai, &up->dst) != 5) { - up->status |= BFORMAT; - return; - } - if (up->leap & 0x8) - up->dut = -up->dut; - offset.l_ui = 31; - offset.l_f = 0; - for (i = 0; i < nchar && i < 10; i++) { - up->tstamp[up->ntstamp] = up->cstamp[i]; - L_SUB(&up->tstamp[up->ntstamp], &offset); - L_ADD(&offset, &up->charstamp); - if (up->ntstamp < MAXSTAGE) - up->ntstamp++; - } -} - - -/* - * chu_a - decode format A burst - */ -static void -chu_a( - struct peer *peer, - int nchar - ) -{ - struct refclockproc *pp; - struct chuunit *up; - - char tbuf[80]; /* trace buffer */ - l_fp offset; /* timestamp offset */ - int val; /* distance */ - int temp; - int i, j, k; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Determine correct burst phase. There are three cases - * corresponding to in-phase, one character early or one - * character late. These cases are distinguished by the position - * of the framing digits x6 at positions 0 and 5 and x3 at - * positions 4 and 9. The correct phase is when the distance - * relative to the framing digits is maximum. The burst is valid - * only if the maximum distance is at least MINSYNC. - */ - up->syndist = k = 0; - val = -16; - for (i = -1; i < 2; i++) { - temp = up->cbuf[i + 4] & 0xf; - if (i >= 0) - temp |= (up->cbuf[i] & 0xf) << 4; - val = chu_dist(temp, 0x63); - temp = (up->cbuf[i + 5] & 0xf) << 4; - if (i + 9 < nchar) - temp |= up->cbuf[i + 9] & 0xf; - val += chu_dist(temp, 0x63); - if (val > up->syndist) { - up->syndist = val; - k = i; - } - } - temp = (up->cbuf[k + 4] >> 4) & 0xf; - if (temp > 9 || k + 9 >= nchar || temp != ((up->cbuf[k + 9] >> - 4) & 0xf)) - temp = 0; -#ifdef HAVE_AUDIO - if (up->fd_audio) - sprintf(tbuf, "chuA %04x %4.0f %2d %2d %2d %2d %1d ", - up->status, up->maxsignal, nchar, up->burdist, k, - up->syndist, temp); - else - sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", - up->status, nchar, up->burdist, k, up->syndist, - temp); - -#else - sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", up->status, - nchar, up->burdist, k, up->syndist, temp); -#endif /* HAVE_AUDIO */ - for (i = 0; i < nchar; i++) - sprintf(&tbuf[strlen(tbuf)], "%02x", - up->cbuf[i]); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif - if (up->syndist < MINSYNC) { - up->status |= AFRAME; - return; - } - - /* - * A valid burst requires the first seconds number to match the - * last seconds number. If so, the burst timestamps are - * corrected to the current minute and saved for later - * processing. In addition, the seconds decode is advanced from - * the previous burst to the current one. - */ - if (temp != 0) { - pp->second = 30 + temp; - offset.l_ui = 30 + temp; - offset.l_f = 0; - i = 0; - if (k < 0) - offset = up->charstamp; - else if (k > 0) - i = 1; - for (; i < nchar && i < k + 10; i++) { - up->tstamp[up->ntstamp] = up->cstamp[i]; - L_SUB(&up->tstamp[up->ntstamp], &offset); - L_ADD(&offset, &up->charstamp); - if (up->ntstamp < MAXSTAGE) - up->ntstamp++; - } - while (temp > up->prevsec) { - for (j = 15; j > 0; j--) { - up->decode[9][j] = up->decode[9][j - 1]; - up->decode[19][j] = - up->decode[19][j - 1]; - } - up->decode[9][j] = up->decode[19][j] = 0; - up->prevsec++; - } - } - i = -(2 * k); - for (j = 0; j < nchar; j++) { - if (i < 0 || i > 19) { - i += 2; - continue; - } - up->decode[i][up->cbuf[j] & 0xf]++; - i++; - up->decode[i][(up->cbuf[j] >> 4) & 0xf]++; - i++; - } - up->status |= AVALID; - up->burstcnt++; -} - - -/* - * chu_poll - called by the transmit procedure - */ -static void -chu_poll( - int unit, - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct chuunit *up; - l_fp offset; - char synchar, qual, leapchar; - int minset, i; - double dtemp; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - if (pp->coderecv == pp->codeproc) - up->errflg = CEVNT_TIMEOUT; - else - pp->polls++; - - /* - * If once in sync and the radio has not been heard for awhile - * (30 m), it is no longer reachable. If not heard in a long - * while (one day), turn out the lights and start from scratch. - */ - minset = ((current_time - peer->update) + 30) / 60; - if (up->status & INSYNC) { - if (minset > PANIC) - up->status = 0; - else if (minset <= HOLD) - peer->reach |= 1; - } - - /* - * Process the last burst, if still in the burst buffer. - * Don't mess with anything if nothing has been heard. If the - * minute contains a valid A frame and valid B frame, assume - * synchronized; however, believe the time only if within metric - * threshold. Note the quality indicator is only for - * diagnostics; the data are used only if in sync and above - * metric threshold. - */ - chu_burst(peer); - if (up->burstcnt == 0) { -#ifdef ICOM - chu_newchan(peer, 0); -#endif /* ICOM */ - return; - } - dtemp = chu_major(peer); - qual = 0; - if (up->status & (BFRAME | AFRAME)) - qual |= SYNERR; - if (up->status & (BFORMAT | AFORMAT)) - qual |= FMTERR; - if (up->status & DECODE) - qual |= DECERR; - if (up->status & STAMP) - qual |= TSPERR; - if (up->status & AVALID && up->status & BVALID) - up->status |= INSYNC; - synchar = leapchar = ' '; - if (!(up->status & INSYNC)) { - pp->leap = LEAP_NOTINSYNC; - synchar = '?'; - } else if (up->leap & 0x2) { - pp->leap = LEAP_ADDSECOND; - leapchar = 'L'; - } else if (up->leap & 0x4) { - pp->leap = LEAP_DELSECOND; - leapchar = 'l'; - } else { - pp->leap = LEAP_NOWARNING; - } -#ifdef HAVE_AUDIO - if (up->fd_audio) - sprintf(pp->a_lastcode, - "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %d %s %.0f %d", - synchar, qual, pp->year, pp->day, pp->hour, - pp->minute, pp->second, leapchar, up->dst, up->dut, - minset, up->gain, up->ident, dtemp, up->ntstamp); - else - sprintf(pp->a_lastcode, - "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %s %.0f %d", - synchar, qual, pp->year, pp->day, pp->hour, - pp->minute, pp->second, leapchar, up->dst, up->dut, - minset, up->ident, dtemp, up->ntstamp); -#else - sprintf(pp->a_lastcode, - "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %s %.0f %d", - synchar, qual, pp->year, pp->day, pp->hour, pp->minute, - pp->second, leapchar, up->dst, up->dut, minset, up->ident, - dtemp, up->ntstamp); -#endif /* HAVE_AUDIO */ - pp->lencode = strlen(pp->a_lastcode); - - /* - * If in sync and the signal metric is above threshold, the - * timecode is ipso fatso valid and can be selected to - * discipline the clock. Be sure not to leave stray timestamps - * around if signals are too weak or the clock time is invalid. - */ - if (up->status & INSYNC && dtemp > METRIC) { - if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT, - up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) { - up->errflg = CEVNT_BADTIME; - } else { - offset.l_uf = 0; - for (i = 0; i < up->ntstamp; i++) - refclock_process_offset(pp, offset, - up->tstamp[i], FUDGE + - pp->fudgetime1); - pp->lastref = up->timestamp; - refclock_receive(peer); - } - record_clock_stats(&peer->srcadr, pp->a_lastcode); - } else if (pp->sloppyclockflag & CLK_FLAG4) { - record_clock_stats(&peer->srcadr, pp->a_lastcode); - } -#ifdef DEBUG - if (debug) - printf("chu: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif -#ifdef ICOM - chu_newchan(peer, dtemp); -#endif /* ICOM */ - chu_clear(peer); - if (up->errflg) - refclock_report(peer, up->errflg); - up->errflg = 0; -} - - -/* - * chu_major - majority decoder - */ -static double -chu_major( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct chuunit *up; - - u_char code[11]; /* decoded timecode */ - int mindist; /* minimum distance */ - int val1, val2; /* maximum distance */ - int synchar; /* stray cat */ - int temp; - int i, j, k; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Majority decoder. Each burst encodes two replications at each - * digit position in the timecode. Each row of the decoding - * matrix encodes the number of occurrences of each digit found - * at the corresponding position. The maximum over all - * occurrences at each position is the distance for this - * position and the corresponding digit is the maximum - * likelihood candidate. If the distance is zero, assume a miss - * '_'; if the distance is not more than half the total number - * of occurrences, assume a soft error '*'; if two different - * digits with the same distance are found, assume a hard error - * '='. These will later cause a format error when the timecode - * is interpreted. The decoding distance is defined as the - * minimum distance over the first nine digits. The tenth digit - * varies over the seconds, so we don't count it. - */ - mindist = 16; - for (i = 0; i < 9; i++) { - val1 = val2 = 0; - k = 0; - for (j = 0; j < 16; j++) { - temp = up->decode[i][j] + up->decode[i + 10][j]; - if (temp > val1) { - val2 = val1; - val1 = temp; - k = j; - } - } - if (val1 == 0) - code[i] = HEX_MISS; - else if (val1 == val2) - code[i] = HEX_HARD; - else if (val1 <= up->burstcnt) - code[i] = HEX_SOFT; - else - code[i] = k; - if (val1 < mindist) - mindist = val1; - code[i] = hexchar[code[i]]; - } - code[i] = 0; - - /* - * A valid timecode requires a minimum distance at least half - * the total number of occurrences. A valid timecode also - * requires at least 20 valid timestamps. - */ - if (up->burstcnt < MINBURST || mindist < up->burstcnt) - up->status |= DECODE; - if (up->ntstamp < MINSTAMP) - up->status |= STAMP; - - /* - * Compute the timecode timestamp from the days, hours and - * minutes of the timecode. Use clocktime() for the aggregate - * minutes and the minute offset computed from the burst - * seconds. Note that this code relies on the filesystem time - * for the years and does not use the years of the timecode. - */ - if (sscanf((char *)code, "%1x%3d%2d%2d", &synchar, &pp->day, - &pp->hour, &pp->minute) != 4) { - up->status |= AFORMAT; - return (0); - } - if (up->status & (DECODE | STAMP)) { - up->errflg = CEVNT_BADREPLY; - return (0); - } - return (mindist * 100. / (2. * up->burstcnt)); -} - - -/* - * chu_clear - clear decoding matrix - */ -static void -chu_clear( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct chuunit *up; - int i, j; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Clear stuff for the minute. - */ - up->ndx = up->prevsec = 0; - up->burstcnt = up->ntstamp = 0; - up->status &= INSYNC; - for (i = 0; i < 20; i++) { - for (j = 0; j < 16; j++) - up->decode[i][j] = 0; - } -} - -#ifdef ICOM -/* - * chu_newchan - called once per minute to find the best channel; - * returns zero on success, nonzero if ICOM error. - */ -static int -chu_newchan( - struct peer *peer, - double met - ) -{ - struct chuunit *up; - struct refclockproc *pp; - struct xmtr *sp; - char tbuf[80]; /* trace buffer */ - int rval; - double metric; - int i, j; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * The radio can be tuned to three channels: 0 (3330 kHz), 1 - * (7335 kHz) and 2 (14670 kHz). There are five one-minute - * dwells in each cycle. During the first dwell the radio is - * tuned to one of three probe channels; during the remaining - * four dwells the radio is tuned to the data channel. The probe - * channel is selects as the least recently used. At the end of - * each dwell the channel metrics are measured and the highest - * one is selected as the data channel. - */ - if (up->fd_icom <= 0) - return (0); - - sp = &up->xmtr[up->achan]; - sp->metric -= sp->integ[sp->iptr]; - sp->integ[sp->iptr] = met; - sp->metric += sp->integ[sp->iptr]; - sp->iptr = (sp->iptr + 1) % ISTAGE; - metric = 0; - j = 0; - for (i = 0; i < NCHAN; i++) { - up->xmtr[i].probe++; - if (i == up->achan) - up->xmtr[i].probe = 0; - if (up->xmtr[i].metric < metric) - continue; - metric = up->xmtr[i].metric; - j = i; - } - if (j != up->chan && metric > 0) { - up->chan = j; - sprintf(tbuf, "chu: QSY to %.3f MHz metric %.0f", - qsy[up->chan], metric); - if (pp->sloppyclockflag & CLK_FLAG4) - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif - } - - /* - * Start the next dwell. We speed up the initial sync a little. - * If not in sync and no bursts were heard the previous dwell, - * restart the probe. - */ - rval = 0; - if (up->burstcnt == 0 && !(up->status & INSYNC)) - up->dwell = 0; -#ifdef DEBUG - if (debug) - printf( - "chu: at %ld dwell %d achan %d metric %.0f chan %d\n", - current_time, up->dwell, up->achan, sp->metric, - up->chan); -#endif - if (up->dwell == 0) { - rval = 0; - for (i = 0; i < NCHAN; i++) { - if (up->xmtr[i].probe < rval) - continue; - rval = up->xmtr[i].probe; - up->achan = i; - } - rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, - qsy[up->achan] + TUNE); -#ifdef DEBUG - if (debug) - printf("chu: at %ld probe channel %d\n", - current_time, up->achan); -#endif - } else { - if (up->achan != up->chan) { - rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, - qsy[up->chan] + TUNE); - up->achan = up->chan; - } - } - sprintf(up->ident, "CHU%d", up->achan); - memcpy(&peer->refid, up->ident, 4); - up->dwell = (up->dwell + 1) % DWELL; - return (rval); -} -#endif /* ICOM */ - -/* - * chu_dist - determine the distance of two octet arguments - */ -static int -chu_dist( - int x, /* an octet of bits */ - int y /* another octet of bits */ - ) -{ - int val; /* bit count */ - int temp; - int i; - - /* - * The distance is determined as the weight of the exclusive OR - * of the two arguments. The weight is determined by the number - * of one bits in the result. Each one bit increases the weight, - * while each zero bit decreases it. - */ - temp = x ^ y; - val = 0; - for (i = 0; i < 8; i++) { - if ((temp & 0x1) == 0) - val++; - else - val--; - temp >>= 1; - } - return (val); -} - - -#ifdef HAVE_AUDIO -/* - * chu_gain - adjust codec gain - * - * This routine is called once each second. If the signal envelope - * amplitude is too low, the codec gain is bumped up by four units; if - * too high, it is bumped down. The decoder is relatively insensitive to - * amplitude, so this crudity works just fine. The input port is set and - * the error flag is cleared, mostly to be ornery. - */ -static void -chu_gain( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct chuunit *up; - - pp = peer->procptr; - up = (struct chuunit *)pp->unitptr; - - /* - * Apparently, the codec uses only the high order bits of the - * gain control field. Thus, it may take awhile for changes to - * wiggle the hardware bits. - */ - if (up->clipcnt == 0) { - up->gain += 4; - if (up->gain > MAXGAIN) - up->gain = MAXGAIN; - } else if (up->clipcnt > MAXCLP) { - up->gain -= 4; - if (up->gain < 0) - up->gain = 0; - } - audio_gain(up->gain, up->mongain, up->port); - up->clipcnt = 0; -} -#endif /* HAVE_AUDIO */ - - -#else -int refclock_chu_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_conf.c b/contrib/ntp/ntpd/refclock_conf.c deleted file mode 100644 index 8a424f0..0000000 --- a/contrib/ntp/ntpd/refclock_conf.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * refclock_conf.c - reference clock configuration - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <sys/types.h> - -#include "ntpd.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" - -#ifdef REFCLOCK - -static struct refclock refclock_none = { - noentry, noentry, noentry, noentry, noentry, noentry, NOFLAGS -}; - -#ifdef CLOCK_LOCAL -extern struct refclock refclock_local; -#else -#define refclock_local refclock_none -#endif - -#if defined(CLOCK_TRAK) && defined(PPS) -extern struct refclock refclock_trak; -#else -#define refclock_trak refclock_none -#endif - -#ifdef CLOCK_PST -extern struct refclock refclock_pst; -#else -#define refclock_pst refclock_none -#endif - -#ifdef CLOCK_CHU -extern struct refclock refclock_chu; -#else -#define refclock_chu refclock_none -#endif - -#ifdef CLOCK_WWV -extern struct refclock refclock_wwv; -#else -#define refclock_wwv refclock_none -#endif - -#ifdef CLOCK_SPECTRACOM -extern struct refclock refclock_wwvb; -#else -#define refclock_wwvb refclock_none -#endif - -#ifdef CLOCK_PARSE -extern struct refclock refclock_parse; -#else -#define refclock_parse refclock_none -#endif - -#if defined(CLOCK_MX4200) && defined(HAVE_PPSAPI) -extern struct refclock refclock_mx4200; -#else -#define refclock_mx4200 refclock_none -#endif - -#ifdef CLOCK_AS2201 -extern struct refclock refclock_as2201; -#else -#define refclock_as2201 refclock_none -#endif - -#ifdef CLOCK_ARBITER -extern struct refclock refclock_arbiter; -#else -#define refclock_arbiter refclock_none -#endif - -#ifdef CLOCK_TPRO -extern struct refclock refclock_tpro; -#else -#define refclock_tpro refclock_none -#endif - -#ifdef CLOCK_LEITCH -extern struct refclock refclock_leitch; -#else -#define refclock_leitch refclock_none -#endif - -#ifdef CLOCK_IRIG -extern struct refclock refclock_irig; -#else -#define refclock_irig refclock_none -#endif - -#if defined(CLOCK_MSFEES) && defined(PPS) -extern struct refclock refclock_msfees; -#else -#define refclock_msfees refclock_none -#endif - -#ifdef CLOCK_BANC -extern struct refclock refclock_bancomm; -#else -#define refclock_bancomm refclock_none -#endif - -#ifdef CLOCK_TRUETIME -extern struct refclock refclock_true; -#else -#define refclock_true refclock_none -#endif - -#ifdef CLOCK_DATUM -extern struct refclock refclock_datum; -#else -#define refclock_datum refclock_none -#endif - -#ifdef CLOCK_ACTS -extern struct refclock refclock_acts; -#else -#define refclock_acts refclock_none -#endif - -#ifdef CLOCK_HEATH -extern struct refclock refclock_heath; -#else -#define refclock_heath refclock_none -#endif - -#ifdef CLOCK_NMEA -extern struct refclock refclock_nmea; -#else -#define refclock_nmea refclock_none -#endif - -#ifdef CLOCK_ATOM -extern struct refclock refclock_atom; -#else -#define refclock_atom refclock_none -#endif - -#ifdef CLOCK_PTBACTS -extern struct refclock refclock_ptb; -#else -#define refclock_ptb refclock_none -#endif - -#ifdef CLOCK_USNO -extern struct refclock refclock_usno; -#else -#define refclock_usno refclock_none -#endif - -#ifdef CLOCK_HPGPS -extern struct refclock refclock_hpgps; -#else -#define refclock_hpgps refclock_none -#endif - -#ifdef CLOCK_GPSVME -extern struct refclock refclock_gpsvme; -#else -#define refclock_gpsvme refclock_none -#endif - -#ifdef CLOCK_ARCRON_MSF -extern struct refclock refclock_arc; -#else -#define refclock_arc refclock_none -#endif - -#ifdef CLOCK_SHM -extern struct refclock refclock_shm; -#else -#define refclock_shm refclock_none -#endif - -#ifdef CLOCK_PALISADE -extern struct refclock refclock_palisade; -#else -#define refclock_palisade refclock_none -#endif - -#if defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI) -extern struct refclock refclock_oncore; -#else -#define refclock_oncore refclock_none -#endif - -#if defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) -extern struct refclock refclock_jupiter; -#else -#define refclock_jupiter refclock_none -#endif - -#if defined(CLOCK_CHRONOLOG) -extern struct refclock refclock_chronolog; -#else -#define refclock_chronolog refclock_none -#endif - -#if defined(CLOCK_DUMBCLOCK) -extern struct refclock refclock_dumbclock; -#else -#define refclock_dumbclock refclock_none -#endif - -#ifdef CLOCK_ULINK -extern struct refclock refclock_ulink; -#else -#define refclock_ulink refclock_none -#endif - -#ifdef CLOCK_PCF -extern struct refclock refclock_pcf; -#else -#define refclock_pcf refclock_none -#endif - -#ifdef CLOCK_FG -extern struct refclock refclock_fg; -#else -#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 - -#ifdef CLOCK_JJY -extern struct refclock refclock_jjy; -#else -#define refclock_jjy refclock_none -#endif - -#ifdef CLOCK_TT560 -extern struct refclock refclock_tt560; -#else -#define refclock_tt560 refclock_none -#endif - -#ifdef CLOCK_ZYFER -extern struct refclock refclock_zyfer; -#else -#define refclock_zyfer refclock_none -#endif - -#ifdef CLOCK_RIPENCC -extern struct refclock refclock_ripencc; -#else -#define refclock_ripencc refclock_none -#endif - -#ifdef CLOCK_NEOCLOCK4X -extern struct refclock refclock_neoclock4x; -#else -#define refclock_neoclock4x refclock_none -#endif - -/* - * Order is clock_start(), clock_shutdown(), clock_poll(), - * clock_control(), clock_init(), clock_buginfo, clock_flags; - * - * Types are defined in ntp.h. The index must match this. - */ -struct refclock *refclock_conf[] = { - &refclock_none, /* 0 REFCLK_NONE */ - &refclock_local, /* 1 REFCLK_LOCAL */ - &refclock_trak, /* 2 REFCLK_GPS_TRAK */ - &refclock_pst, /* 3 REFCLK_WWV_PST */ - &refclock_wwvb, /* 4 REFCLK_SPECTRACOM */ - &refclock_true, /* 5 REFCLK_TRUETIME */ - &refclock_irig, /* 6 REFCLK_IRIG_AUDIO */ - &refclock_chu, /* 7 REFCLK_CHU_AUDIO */ - &refclock_parse, /* 8 REFCLK_PARSE */ - &refclock_mx4200, /* 9 REFCLK_GPS_MX4200 */ - &refclock_as2201, /* 10 REFCLK_GPS_AS2201 */ - &refclock_arbiter, /* 11 REFCLK_GPS_ARBITER */ - &refclock_tpro, /* 12 REFCLK_IRIG_TPRO */ - &refclock_leitch, /* 13 REFCLK_ATOM_LEITCH */ - &refclock_msfees, /* 14 REFCLK_MSF_EES */ - &refclock_true, /* 15 alias for REFCLK_TRUETIME */ - &refclock_bancomm, /* 16 REFCLK_IRIG_BANCOMM */ - &refclock_datum, /* 17 REFCLK_GPS_DATUM */ - &refclock_acts, /* 18 REFCLK_NIST_ACTS */ - &refclock_heath, /* 19 REFCLK_WWV_HEATH */ - &refclock_nmea, /* 20 REFCLK_GPS_NMEA */ - &refclock_gpsvme, /* 21 REFCLK_GPS_VME */ - &refclock_atom, /* 22 REFCLK_ATOM_PPS */ - &refclock_ptb, /* 23 REFCLK_PTB_ACTS */ - &refclock_usno, /* 24 REFCLK_USNO */ - &refclock_true, /* 25 alias for REFCLK_TRUETIME */ - &refclock_hpgps, /* 26 REFCLK_GPS_HP */ - &refclock_arc, /* 27 REFCLK_ARCRON_MSF */ - &refclock_shm, /* 28 REFCLK_SHM */ - &refclock_palisade, /* 29 REFCLK_PALISADE */ - &refclock_oncore, /* 30 REFCLK_ONCORE */ - &refclock_jupiter, /* 31 REFCLK_GPS_JUPITER */ - &refclock_chronolog, /* 32 REFCLK_CHRONOLOG */ - &refclock_dumbclock, /* 33 REFCLK_DUMBCLOCK */ - &refclock_ulink, /* 34 REFCLOCK_ULINK */ - &refclock_pcf, /* 35 REFCLOCK_PCF */ - &refclock_wwv, /* 36 REFCLOCK_WWV_AUDIO */ - &refclock_fg, /* 37 REFCLOCK_FG */ - &refclock_hopfser, /* 38 REFCLK_HOPF_SERIAL */ - &refclock_hopfpci, /* 39 REFCLK_HOPF_PCI */ - &refclock_jjy, /* 40 REFCLK_JJY */ - &refclock_tt560, /* 41 REFCLK_TT560 */ - &refclock_zyfer, /* 42 REFCLK_ZYFER */ - &refclock_ripencc, /* 43 REFCLK_RIPENCC */ - &refclock_neoclock4x /* 44 REFCLK_NEOCLOCK4X */ -}; - -u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *); - -#else -int refclock_conf_bs; -#endif diff --git a/contrib/ntp/ntpd/refclock_datum.c b/contrib/ntp/ntpd/refclock_datum.c deleted file mode 100644 index 82b7369..0000000 --- a/contrib/ntp/ntpd/refclock_datum.c +++ /dev/null @@ -1,869 +0,0 @@ -/* -** refclock_datum - clock driver for the Datum Programmable Time Server -** -** Important note: This driver assumes that you have termios. If you have -** a system that does not have termios, you will have to modify this driver. -** -** Sorry, I have only tested this driver on SUN and HP platforms. -*/ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_DATUM) - -/* -** Include Files -*/ - -#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 */ - -#if defined(HAVE_SYSV_TTYS) -#include <termio.h> -#endif /* HAVE_SYSV_TTYS */ - -#if defined(HAVE_TERMIOS) -#include <termios.h> -#endif -#if defined(STREAM) -#include <stropts.h> -#if defined(WWVBCLK) -#include <sys/clkdefs.h> -#endif /* WWVBCLK */ -#endif /* STREAM */ - -#include "ntp_stdlib.h" - -/* -** This driver supports the Datum Programmable Time System (PTS) clock. -** The clock works in very straight forward manner. When it receives a -** time code request (e.g., the ascii string "//k/mn"), it responds with -** a seven byte BCD time code. This clock only responds with a -** time code after it first receives the "//k/mn" message. It does not -** periodically send time codes back at some rate once it is started. -** the returned time code can be broken down into the following fields. -** -** _______________________________ -** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | -** =============================== -** byte 0: | - - - - | H D | -** =============================== -** byte 1: | T D | U D | -** =============================== -** byte 2: | - - | T H | U H | -** =============================== -** byte 3: | - | T M | U M | -** =============================== -** byte 4: | - | T S | U S | -** =============================== -** byte 5: | t S | h S | -** =============================== -** byte 6: | m S | - - - - | -** =============================== -** -** In the table above: -** -** "-" means don't care -** "H D", "T D", and "U D" means Hundreds, Tens, and Units of Days -** "T H", and "UH" means Tens and Units of Hours -** "T M", and "U M" means Tens and Units of Minutes -** "T S", and "U S" means Tens and Units of Seconds -** "t S", "h S", and "m S" means tenths, hundredths, and thousandths -** of seconds -** -** The Datum PTS communicates throught the RS232 port on your machine. -** Right now, it assumes that you have termios. This driver has been tested -** on SUN and HP workstations. The Datum PTS supports various IRIG and -** NASA input codes. This driver assumes that the name of the device is -** /dev/datum. You will need to make a soft link to your RS232 device or -** create a new driver to use this refclock. -*/ - -/* -** Datum PTS defines -*/ - -/* -** Note that if GMT is defined, then the Datum PTS must use Greenwich -** time. Otherwise, this driver allows the Datum PTS to use the current -** wall clock for its time. It determines the time zone offset by minimizing -** the error after trying several time zone offsets. If the Datum PTS -** time is Greenwich time and GMT is not defined, everything should still -** work since the time zone will be found to be 0. What this really means -** is that your system time (at least to start with) must be within the -** correct time by less than +- 30 minutes. The default is for GMT to not -** defined. If you really want to force GMT without the funny +- 30 minute -** stuff then you must define (uncomment) GMT below. -*/ - -/* -#define GMT -#define DEBUG_DATUM_PTC -#define LOG_TIME_ERRORS -*/ - - -#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 */ - -#define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR) - -/* -** The Datum PTS structure -*/ - -/* -** I don't use a fixed array of MAXUNITS like everyone else just because -** I don't like to program that way. Sorry if this bothers anyone. I assume -** that you can use any id for your unit and I will search for it in a -** dynamic array of units until I find it. I was worried that users might -** enter a bad id in their configuration file (larger than MAXUNITS) and -** besides, it is just cleaner not to have to assume that you have a fixed -** number of anything in a program. -*/ - -struct datum_pts_unit { - struct peer *peer; /* peer used by ntp */ - struct refclockio io; /* io structure used by ntp */ - int PTS_fd; /* file descriptor for PTS */ - u_int unit; /* id for unit */ - u_long timestarted; /* time started */ - l_fp lastrec; /* time tag for the receive time (system) */ - l_fp lastref; /* reference time (Datum time) */ - u_long yearstart; /* the year that this clock started */ - int coderecv; /* number of time codes received */ - int day; /* day */ - int hour; /* hour */ - int minute; /* minutes */ - int second; /* seconds */ - int msec; /* miliseconds */ - int usec; /* miliseconds */ - u_char leap; /* funny leap character code */ - char retbuf[8]; /* returned time from the datum pts */ - char nbytes; /* number of bytes received from datum pts */ - double sigma2; /* average squared error (roughly) */ - int tzoff; /* time zone offest from GMT */ -}; - -/* -** PTS static constant variables for internal use -*/ - -static char TIME_REQUEST[6]; /* request message sent to datum for time */ -static int nunits; /* number of active units */ -static struct datum_pts_unit -**datum_pts_unit; /* dynamic array of datum PTS structures */ - -/* -** Callback function prototypes that ntpd needs to know about. -*/ - -static int datum_pts_start P((int, struct peer *)); -static void datum_pts_shutdown P((int, struct peer *)); -static void datum_pts_poll P((int, struct peer *)); -static void datum_pts_control P((int, struct refclockstat *, - struct refclockstat *, struct peer *)); -static void datum_pts_init P((void)); -static void datum_pts_buginfo P((int, struct refclockbug *, struct peer *)); - -/* -** This is the call back function structure that ntpd actually uses for -** this refclock. -*/ - -struct refclock refclock_datum = { - datum_pts_start, /* start up a new Datum refclock */ - datum_pts_shutdown, /* shutdown a Datum refclock */ - datum_pts_poll, /* sends out the time request */ - datum_pts_control, /* not used */ - datum_pts_init, /* initialization (called first) */ - datum_pts_buginfo, /* not used */ - NOFLAGS /* we are not setting any special flags */ -}; - -/* -** The datum_pts_receive callback function is handled differently from the -** rest. It is passed to the ntpd io data structure. Basically, every -** 64 seconds, the datum_pts_poll() routine is called. It sends out the time -** request message to the Datum Programmable Time System. Then, ntpd -** waits on a select() call to receive data back. The datum_pts_receive() -** function is called as data comes back. We expect a seven byte time -** code to be returned but the datum_pts_receive() function may only get -** a few bytes passed to it at a time. In other words, this routine may -** get called by the io stuff in ntpd a few times before we get all seven -** bytes. Once the last byte is received, we process it and then pass the -** new time measurement to ntpd for updating the system time. For now, -** there is no 3 state filtering done on the time measurements. The -** jitter may be a little high but at least for its current use, it is not -** a problem. We have tried to keep things as simple as possible. This -** clock should not jitter more than 1 or 2 mseconds at the most once -** things settle down. It is important to get the right drift calibrated -** in the ntpd.drift file as well as getting the right tick set up right -** using tickadj for SUNs. Tickadj is not used for the HP but you need to -** remember to bring up the adjtime daemon because HP does not support -** the adjtime() call. -*/ - -static void datum_pts_receive P((struct recvbuf *)); - -/*......................................................................*/ -/* datum_pts_start - start up the datum PTS. This means open the */ -/* RS232 device and set up the data structure for my unit. */ -/*......................................................................*/ - -static int -datum_pts_start( - int unit, - struct peer *peer - ) -{ - struct datum_pts_unit **temp_datum_pts_unit; - struct datum_pts_unit *datum_pts; -#ifdef HAVE_TERMIOS - struct termios arg; -#endif - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Starting Datum PTS unit %d\n", unit); -#endif - - /* - ** Create the memory for the new unit - */ - - temp_datum_pts_unit = (struct datum_pts_unit **) - malloc((nunits+1)*sizeof(struct datum_pts_unit *)); - if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit, - nunits*sizeof(struct datum_pts_unit *)); - free(datum_pts_unit); - datum_pts_unit = temp_datum_pts_unit; - datum_pts_unit[nunits] = (struct datum_pts_unit *) - malloc(sizeof(struct datum_pts_unit)); - datum_pts = datum_pts_unit[nunits]; - - datum_pts->unit = unit; /* set my unit id */ - datum_pts->yearstart = 0; /* initialize the yearstart to 0 */ - datum_pts->sigma2 = 0.0; /* initialize the sigma2 to 0 */ - - /* - ** Open the Datum PTS device - */ - - datum_pts->PTS_fd = open("/dev/datum",O_RDWR); - - fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */ - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Opening RS232 port with file descriptor %d\n", - datum_pts->PTS_fd); -#endif - - /* - ** Set up the RS232 terminal device information. Note that we assume that - ** we have termios. This code has only been tested on SUNs and HPs. If your - ** machine does not have termios this driver cannot be initialized. You can change this - ** if you want by editing this source. Please give the changes back to the - ** ntp folks so that it can become part of their regular distribution. - */ - -#ifdef HAVE_TERMIOS - - arg.c_iflag = IGNBRK; - arg.c_oflag = 0; - arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL; - arg.c_lflag = 0; - arg.c_cc[VMIN] = 0; /* start timeout timer right away (not used) */ - arg.c_cc[VTIME] = 30; /* 3 second timout on reads (not used) */ - - tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg); - -#else - - msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver"); - (void)close(datum_pts->PTS_fd); - - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - - return 0; - -#endif - - /* - ** Initialize the ntpd IO structure - */ - - datum_pts->peer = peer; - datum_pts->io.clock_recv = datum_pts_receive; - datum_pts->io.srcclock = (caddr_t)datum_pts; - datum_pts->io.datalen = 0; - datum_pts->io.fd = datum_pts->PTS_fd; - - if (!io_addclock(&(datum_pts->io))) { - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Problem adding clock\n"); -#endif - - msyslog(LOG_ERR, "Datum_PTS: Problem adding clock"); - (void)close(datum_pts->PTS_fd); - - return 0; - } - - /* - ** Now add one to the number of units and return a successful code - */ - - nunits++; - return 1; - -} - - -/*......................................................................*/ -/* datum_pts_shutdown - this routine shuts doen the device and */ -/* removes the memory for the unit. */ -/*......................................................................*/ - -static void -datum_pts_shutdown( - int unit, - struct peer *peer - ) -{ - int i,j; - struct datum_pts_unit **temp_datum_pts_unit; - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Shutdown Datum PTS\n"); -#endif - - msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS"); - - /* - ** First we have to find the right unit (i.e., the one with the same id). - ** We do this by looping through the dynamic array of units intil we find - ** it. Note, that I don't simply use an array with a maximimum number of - ** Datum PTS units. Everything is completely dynamic. - */ - - for (i=0; i<nunits; i++) { - if (datum_pts_unit[i]->unit == unit) { - - /* - ** We found the unit so close the file descriptor and free up the memory used - ** by the structure. - */ - - io_closeclock(&datum_pts_unit[i]->io); - close(datum_pts_unit[i]->PTS_fd); - free(datum_pts_unit[i]); - - /* - ** Now clean up the datum_pts_unit dynamic array so that there are no holes. - ** This may mean moving pointers around, etc., to keep things compact. - */ - - if (nunits > 1) { - - temp_datum_pts_unit = (struct datum_pts_unit **) - malloc((nunits-1)*sizeof(struct datum_pts_unit *)); - if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit, - i*sizeof(struct datum_pts_unit *)); - - for (j=i+1; j<nunits; j++) { - temp_datum_pts_unit[j-1] = datum_pts_unit[j]; - } - - free(datum_pts_unit); - datum_pts_unit = temp_datum_pts_unit; - - }else{ - - free(datum_pts_unit); - datum_pts_unit = NULL; - - } - - return; - - } - } - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Error, could not shut down unit %d\n",unit); -#endif - - msyslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit); - -} - -/*......................................................................*/ -/* datum_pts_poll - this routine sends out the time request to the */ -/* Datum PTS device. The time will be passed back in the */ -/* datum_pts_receive() routine. */ -/*......................................................................*/ - -static void -datum_pts_poll( - int unit, - struct peer *peer - ) -{ - int i; - int unit_index; - int error_code; - struct datum_pts_unit *datum_pts; - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Poll Datum PTS\n"); -#endif - - /* - ** Find the right unit and send out a time request once it is found. - */ - - unit_index = -1; - for (i=0; i<nunits; i++) { - if (datum_pts_unit[i]->unit == unit) { - unit_index = i; - datum_pts = datum_pts_unit[i]; - error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6); - if (error_code != 6) perror("TIME_REQUEST"); - datum_pts->nbytes = 0; - break; - } - } - - /* - ** Print out an error message if we could not find the right unit. - */ - - if (unit_index == -1) { - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Error, could not poll unit %d\n",unit); -#endif - - msyslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit); - return; - - } - -} - - -/*......................................................................*/ -/* datum_pts_control - not used */ -/*......................................................................*/ - -static void -datum_pts_control( - int unit, - struct refclockstat *in, - struct refclockstat *out, - struct peer *peer - ) -{ - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Control Datum PTS\n"); -#endif - -} - - -/*......................................................................*/ -/* datum_pts_init - initializes things for all possible Datum */ -/* time code generators that might be used. In practice, this is */ -/* only called once at the beginning before anything else is */ -/* called. */ -/*......................................................................*/ - -static void -datum_pts_init(void) -{ - - /* */ - /*...... open up the log file if we are debugging ......................*/ - /* */ - - /* - ** Open up the log file if we are debugging. For now, send data out to the - ** screen (stdout). - */ - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Init Datum PTS\n"); -#endif - - /* - ** Initialize the time request command string. This is the only message - ** that we ever have to send to the Datum PTS (although others are defined). - */ - - memcpy(TIME_REQUEST, "//k/mn",6); - - /* - ** Initialize the number of units to 0 and set the dynamic array of units to - ** NULL since there are no units defined yet. - */ - - datum_pts_unit = NULL; - nunits = 0; - -} - - -/*......................................................................*/ -/* datum_pts_buginfo - not used */ -/*......................................................................*/ - -static void -datum_pts_buginfo( - int unit, - register struct refclockbug *bug, - register struct peer *peer - ) -{ - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Buginfo Datum PTS\n"); -#endif - -} - - -/*......................................................................*/ -/* datum_pts_receive - receive the time buffer that was read in */ -/* by the ntpd io handling routines. When 7 bytes have been */ -/* received (it may take several tries before all 7 bytes are */ -/* received), then the time code must be unpacked and sent to */ -/* the ntpd clock_receive() routine which causes the systems */ -/* clock to be updated (several layers down). */ -/*......................................................................*/ - -static void -datum_pts_receive( - struct recvbuf *rbufp - ) -{ - int i; - l_fp tstmp; - struct datum_pts_unit *datum_pts; - char *dpt; - int dpend; - int tzoff; - int timerr; - double ftimerr, abserr; -#ifdef DEBUG_DATUM_PTC - double dispersion; -#endif - int goodtime; - /*double doffset;*/ - - /* - ** Get the time code (maybe partial) message out of the rbufp buffer. - */ - - datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock; - dpt = (char *)&rbufp->recv_space; - dpend = rbufp->recv_length; - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Receive Datum PTS: %d bytes\n", dpend); -#endif - - /* */ - /*...... save the ntp system time when the first byte is received ......*/ - /* */ - - /* - ** Save the ntp system time when the first byte is received. Note that - ** because it may take several calls to this routine before all seven - ** bytes of our return message are finally received by the io handlers in - ** ntpd, we really do want to use the time tag when the first byte is - ** received to reduce the jitter. - */ - - if (datum_pts->nbytes == 0) { - datum_pts->lastrec = rbufp->recv_time; - } - - /* - ** Increment our count to the number of bytes received so far. Return if we - ** haven't gotten all seven bytes yet. - */ - - for (i=0; i<dpend; i++) { - datum_pts->retbuf[datum_pts->nbytes+i] = dpt[i]; - } - - datum_pts->nbytes += dpend; - - if (datum_pts->nbytes != 7) { - return; - } - - /* - ** Convert the seven bytes received in our time buffer to day, hour, minute, - ** second, and msecond values. The usec value is not used for anything - ** currently. It is just the fractional part of the time stored in units - ** of microseconds. - */ - - datum_pts->day = 100*(datum_pts->retbuf[0] & 0x0f) + - 10*((datum_pts->retbuf[1] & 0xf0)>>4) + - (datum_pts->retbuf[1] & 0x0f); - - datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) + - (datum_pts->retbuf[2] & 0x0f); - - datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) + - (datum_pts->retbuf[3] & 0x0f); - - datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) + - (datum_pts->retbuf[4] & 0x0f); - - datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) + - 10*(datum_pts->retbuf[5] & 0x0f) + - ((datum_pts->retbuf[6] & 0xf0)>>4); - - datum_pts->usec = 1000*datum_pts->msec; - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("day %d, hour %d, minute %d, second %d, msec %d\n", - datum_pts->day, - datum_pts->hour, - datum_pts->minute, - datum_pts->second, - datum_pts->msec); -#endif - - /* - ** Get the GMT time zone offset. Note that GMT should be zero if the Datum - ** reference time is using GMT as its time base. Otherwise we have to - ** determine the offset if the Datum PTS is using time of day as its time - ** base. - */ - - goodtime = 0; /* We are not sure about the time and offset yet */ - -#ifdef GMT - - /* - ** This is the case where the Datum PTS is using GMT so there is no time - ** zone offset. - */ - - tzoff = 0; /* set time zone offset to 0 */ - -#else - - /* - ** This is the case where the Datum PTS is using regular time of day for its - ** time so we must compute the time zone offset. The way we do it is kind of - ** funny but it works. We loop through different time zones (0 to 24) and - ** pick the one that gives the smallest error (+- one half hour). The time - ** zone offset is stored in the datum_pts structure for future use. Normally, - ** the clocktime() routine is only called once (unless the time zone offset - ** changes due to daylight savings) since the goodtime flag is set when a - ** good time is found (with a good offset). Note that even if the Datum - ** PTS is using GMT, this mechanism will still work since it should come up - ** with a value for tzoff = 0 (assuming that your system clock is within - ** a half hour of the Datum time (even with time zone differences). - */ - - for (tzoff=0; tzoff<24; tzoff++) { - if (clocktime( datum_pts->day, - datum_pts->hour, - datum_pts->minute, - datum_pts->second, - (tzoff + datum_pts->tzoff) % 24, - datum_pts->lastrec.l_ui, - &datum_pts->yearstart, - &datum_pts->lastref.l_ui) ) { - - datum_pts->lastref.l_uf = 0; - error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui; - -#ifdef DEBUG_DATUM_PTC - printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error); -#endif - - if ((error < 1799) && (error > -1799)) { - tzoff = (tzoff + datum_pts->tzoff) % 24; - datum_pts->tzoff = tzoff; - goodtime = 1; - -#ifdef DEBUG_DATUM_PTC - printf("Time Zone found (clocktime method) = %d\n",tzoff); -#endif - - break; - } - - } - } - -#endif - - /* - ** Make sure that we have a good time from the Datum PTS. Clocktime() also - ** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e., - ** the fraction of a second) stuff later. - */ - - if (!goodtime) { - - if (!clocktime( datum_pts->day, - datum_pts->hour, - datum_pts->minute, - datum_pts->second, - tzoff, - datum_pts->lastrec.l_ui, - &datum_pts->yearstart, - &datum_pts->lastref.l_ui) ) { - -#ifdef DEBUG_DATUM_PTC - if (debug) - { - printf("Error: bad clocktime\n"); - printf("GMT %d, lastrec %d, yearstart %d, lastref %d\n", - tzoff, - datum_pts->lastrec.l_ui, - datum_pts->yearstart, - datum_pts->lastref.l_ui); - } -#endif - - msyslog(LOG_ERR, "Datum_PTS: Bad clocktime"); - - return; - - }else{ - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Good clocktime\n"); -#endif - - } - - } - - /* - ** We have datum_pts->lastref.l_ui set (which is the integer part of the - ** time. Now set the microseconds field. - */ - - TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf); - - /* - ** Compute the time correction as the difference between the reference - ** time (i.e., the Datum time) minus the receive time (system time). - */ - - tstmp = datum_pts->lastref; /* tstmp is the datum ntp time */ - L_SUB(&tstmp, &datum_pts->lastrec); /* tstmp is now the correction */ - datum_pts->coderecv++; /* increment a counter */ - -#ifdef DEBUG_DATUM_PTC - dispersion = DATUM_DISPERSION; /* set the dispersion to 0 */ - ftimerr = dispersion; - ftimerr /= (1024.0 * 64.0); - if (debug) - printf("dispersion = %d, %f\n", dispersion, ftimerr); -#endif - - /* - ** Pass the new time to ntpd through the refclock_receive function. Note - ** that we are not trying to make any corrections due to the time it takes - ** for the Datum PTS to send the message back. I am (erroneously) assuming - ** that the time for the Datum PTS to send the time back to us is negligable. - ** I suspect that this time delay may be as much as 15 ms or so (but probably - ** less). For our needs at JPL, this kind of error is ok so it is not - ** necessary to use fudge factors in the ntp.conf file. Maybe later we will. - */ - /*LFPTOD(&tstmp, doffset);*/ - datum_pts->lastref = datum_pts->lastrec; - refclock_receive(datum_pts->peer); - - /* - ** Compute sigma squared (not used currently). Maybe later, this could be - ** used for the dispersion estimate. The problem is that ntpd does not link - ** in the math library so sqrt() is not available. Anyway, this is useful - ** for debugging. Maybe later I will just use absolute values for the time - ** error to come up with my dispersion estimate. Anyway, for now my dispersion - ** is set to 0. - */ - - timerr = tstmp.l_ui<<20; - timerr |= (tstmp.l_uf>>12) & 0x000fffff; - ftimerr = timerr; - ftimerr /= 1024*1024; - abserr = ftimerr; - if (ftimerr < 0.0) abserr = -ftimerr; - - if (datum_pts->sigma2 == 0.0) { - if (abserr < DATUM_MAX_ERROR) { - datum_pts->sigma2 = abserr*abserr; - }else{ - datum_pts->sigma2 = DATUM_MAX_ERROR2; - } - }else{ - if (abserr < DATUM_MAX_ERROR) { - datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr; - }else{ - datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2; - } - } - -#ifdef DEBUG_DATUM_PTC - if (debug) - printf("Time error = %f seconds\n", ftimerr); -#endif - -#if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS) - if (debug) - printf("PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n", - datum_pts->day, - datum_pts->hour, - datum_pts->minute, - datum_pts->second, - datum_pts->msec, - ftimerr); -#endif - -} -#else -int refclock_datum_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_dumbclock.c b/contrib/ntp/ntpd/refclock_dumbclock.c deleted file mode 100644 index 2788649..0000000 --- a/contrib/ntp/ntpd/refclock_dumbclock.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * refclock_dumbclock - clock driver for a unknown time distribution system - * that only provides hh:mm:ss (in local time, yet!). - */ - -/* - * Must interpolate back to local time. Very annoying. - */ -#define GET_LOCALTIME - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - -#if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) - -#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. - * - * Input format: - * - * hh:mm:ss <cr> - * - * hh:mm:ss -- what you'd expect, with a 24 hour clock. (Heck, that's the only - * way it could get stupider.) We take time on the <cr>. - * - * The original source of this module was the WWVB module. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/dumbclock%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-13) /* precision assumed (about 100 us) */ -#define REFID "dumbclock" /* reference ID */ -#define DESCRIPTION "Dumb clock" /* WRU */ - - -/* - * Insanity check. Since the time is local, we need to make sure that during midnight - * transitions, we can convert back to Unix time. If the conversion results in some number - * worse than this number of seconds away, assume the next day and retry. - */ -#define INSANE_SECONDS 3600 - -/* - * Dumb clock control structure - */ -struct dumbclock_unit { - u_char tcswitch; /* timecode switch */ - l_fp laststamp; /* last receive timestamp */ - u_char lasthour; /* last hour (for monitor) */ - u_char linect; /* count ignored lines (for monitor */ - struct tm ymd; /* struct tm for y/m/d only */ -}; - -/* - * Function prototypes - */ -static int dumbclock_start P((int, struct peer *)); -static void dumbclock_shutdown P((int, struct peer *)); -static void dumbclock_receive P((struct recvbuf *)); -#if 0 -static void dumbclock_poll P((int, struct peer *)); -#endif - -/* - * Transfer vector - */ -struct refclock refclock_dumbclock = { - dumbclock_start, /* start up driver */ - dumbclock_shutdown, /* shut down driver */ - noentry, /* poll the driver -- a nice fabrication */ - noentry, /* not used */ - noentry, /* not used */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - - -/* - * dumbclock_start - open the devices and initialize data for processing - */ -static int -dumbclock_start( - int unit, - struct peer *peer - ) -{ - register struct dumbclock_unit *up; - struct refclockproc *pp; - int fd; - char device[20]; - struct tm *tm_time_p; - time_t now; - - /* - * Open serial port. Don't bother with CLK line discipline, since - * it's not available. - */ - (void)sprintf(device, DEVICE, unit); -#ifdef DEBUG - if (debug) - printf ("starting Dumbclock with device %s\n",device); -#endif - fd = refclock_open(device, SPEED232, 0); - if (fd < 0) - return (0); - - /* - * Allocate and initialize unit structure - */ - up = (struct dumbclock_unit *)emalloc(sizeof(struct dumbclock_unit)); - if (up == NULL) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct dumbclock_unit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = dumbclock_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - - - time(&now); -#ifdef GET_LOCALTIME - tm_time_p = localtime(&now); -#else - tm_time_p = gmtime(&now); -#endif - if (tm_time_p) - { - up->ymd = *tm_time_p; - } - else - { - return 0; - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - return (1); -} - - -/* - * dumbclock_shutdown - shut down the clock - */ -static void -dumbclock_shutdown( - int unit, - struct peer *peer - ) -{ - register struct dumbclock_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct dumbclock_unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * dumbclock_receive - receive data from the serial interface - */ -static void -dumbclock_receive( - struct recvbuf *rbufp - ) -{ - struct dumbclock_unit *up; - struct refclockproc *pp; - struct peer *peer; - - l_fp trtmp; /* arrival timestamp */ - int hours; /* hour-of-day */ - int minutes; /* minutes-past-the-hour */ - int seconds; /* seconds */ - int temp; /* int temp */ - int got_good; /* got a good time flag */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct dumbclock_unit *)pp->unitptr; - temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); - - if (temp == 0) { - if (up->tcswitch == 0) { - up->tcswitch = 1; - up->laststamp = trtmp; - } else - up->tcswitch = 0; - return; - } - pp->lencode = (u_short)temp; - pp->lastrec = up->laststamp; - up->laststamp = trtmp; - up->tcswitch = 1; - -#ifdef DEBUG - if (debug) - printf("dumbclock: timecode %d %s\n", - pp->lencode, pp->a_lastcode); -#endif - - /* - * We get down to business. Check the timecode format... - */ - got_good=0; - if (sscanf(pp->a_lastcode,"%02d:%02d:%02d", - &hours,&minutes,&seconds) == 3) - { - struct tm *gmtp; - struct tm *lt_p; - time_t asserted_time; /* the SPM time based on the composite time+date */ - struct tm asserted_tm; /* the struct tm of the same */ - int adjyear; - int adjmon; - int reality_delta; - time_t now; - - - /* - * Convert to GMT for sites that distribute localtime. This - * means we have to figure out what day it is. Easier said - * than done... - */ - - asserted_tm.tm_year = up->ymd.tm_year; - asserted_tm.tm_mon = up->ymd.tm_mon; - asserted_tm.tm_mday = up->ymd.tm_mday; - asserted_tm.tm_hour = hours; - asserted_tm.tm_min = minutes; - asserted_tm.tm_sec = seconds; - asserted_tm.tm_isdst = -1; - -#ifdef GET_LOCALTIME - asserted_time = mktime (&asserted_tm); - time(&now); -#else -#include "GMT unsupported for dumbclock!" -#endif - reality_delta = asserted_time - now; - - /* - * We assume that if the time is grossly wrong, it's because we got the - * year/month/day wrong. - */ - if (reality_delta > INSANE_SECONDS) - { - asserted_time -= SECSPERDAY; /* local clock behind real time */ - } - else if (-reality_delta > INSANE_SECONDS) - { - asserted_time += SECSPERDAY; /* local clock ahead of real time */ - } - lt_p = localtime(&asserted_time); - if (lt_p) - { - up->ymd = *lt_p; - } - else - { - refclock_report (peer, CEVNT_FAULT); - return; - } - - if ((gmtp = gmtime (&asserted_time)) == NULL) - { - refclock_report (peer, CEVNT_FAULT); - return; - } - adjyear = gmtp->tm_year+1900; - adjmon = gmtp->tm_mon+1; - pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday); - pp->hour = gmtp->tm_hour; - pp->minute = gmtp->tm_min; - pp->second = gmtp->tm_sec; -#ifdef DEBUG - if (debug) - printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", - adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute, - pp->second); -#endif - - got_good=1; - } - - if (!got_good) - { - if (up->linect > 0) - up->linect--; - else - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); - up->lasthour = (u_char)pp->hour; -} - -#if 0 -/* - * dumbclock_poll - called by the transmit procedure - */ -static void -dumbclock_poll( - int unit, - struct peer *peer - ) -{ - register struct dumbclock_unit *up; - struct refclockproc *pp; - char pollchar; - - /* - * Time to poll the clock. The Chrono-log clock is supposed to - * respond to a 'T' by returning a timecode in the format(s) - * specified above. Ours does (can?) not, but this seems to be - * an installation-specific problem. This code is dyked out, - * but may be re-enabled if anyone ever finds a Chrono-log that - * actually listens to this command. - */ -#if 0 - pp = peer->procptr; - up = (struct dumbclock_unit *)pp->unitptr; - if (peer->reach == 0) - refclock_report(peer, CEVNT_TIMEOUT); - if (up->linect > 0) - pollchar = 'R'; - else - pollchar = 'T'; - if (write(pp->io.fd, &pollchar, 1) != 1) - refclock_report(peer, CEVNT_FAULT); - else - pp->polls++; -#endif -} -#endif - -#else -int refclock_dumbclock_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_fg.c b/contrib/ntp/ntpd/refclock_fg.c deleted file mode 100644 index ebcf1b5..0000000 --- a/contrib/ntp/ntpd/refclock_fg.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * refclock_fg - clock driver for the Forum Graphic GPS datating station - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_FG) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_calendar.h" -#include "ntp_stdlib.h" - -/* - * This driver supports the Forum Graphic GPS dating station. - * More information about FG GPS is available on http://www.forumgraphic.com - * Contact das@amt.ru for any question about this driver. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/fgclock%d" -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define REFID "GPS" -#define DESCRIPTION "Forum Graphic GPS dating station" -#define LENFG 26 /* timecode length */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ - -/* - * Function prototypes - */ -static int fg_init P((int)); -static int fg_start P((int, struct peer *)); -static void fg_shutdown P((int, struct peer *)); -static void fg_poll P((int, struct peer *)); -static void fg_receive P((struct recvbuf *)); - -/* - * Forum Graphic unit control structure - */ - -struct fgunit { - int pollnum; /* Use peer.poll instead? */ - int status; /* Hug to check status information on GPS */ - int y2kwarn; /* Y2K bug */ -}; - -/* - * Queries definition - */ -static char fginit[] = { 0x10, 0x48, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -/* - * Transfer vector - */ -struct refclock refclock_fg = { - fg_start, /* start up driver */ - fg_shutdown, /* shut down driver */ - fg_poll, /* transmit poll message */ - noentry, /* not used */ - noentry, /* initialize driver (not used) */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - -/* - * fg_init - Initialization of FG GPS. - */ - -static int -fg_init( - int fd - ) -{ - if (write(fd, fginit, LENFG) != LENFG) - return 0; - - return (1); - -} - -/* - * fg_start - open the device and initialize data for processing - */ -static int -fg_start( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - struct fgunit *up; - int fd; - char device[20]; - - - /* - * Open device file for reading. - */ - (void)sprintf(device, DEVICE, unit); - -#ifdef DEBUG - if (debug) - printf ("starting FG with device %s\n",device); -#endif - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - - if (!(up = (struct fgunit *) - emalloc(sizeof(struct fgunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct fgunit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = fg_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - return (0); - } - - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 3); - up->pollnum = 0; - - /* - * Setup dating station to use GPS receiver. - * GPS receiver should work before this operation. - */ - if(!fg_init(pp->io.fd)) - refclock_report(peer, CEVNT_FAULT); - - return (1); -} - - -/* - * fg_shutdown - shut down the clock - */ -static void -fg_shutdown( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - struct fgunit *up; - - pp = peer->procptr; - up = (struct fgunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * fg_poll - called by the transmit procedure - */ -static void -fg_poll( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - - pp = peer->procptr; - - /* - * Time to poll the clock. The FG clock responds to a - * "<DLE>D<DLE><CR>" by returning a timecode in the format specified - * above. If nothing is heard from the clock for two polls, - * declare a timeout and keep going. - */ - - if (write(pp->io.fd, fgdate, LENFG) != LENFG) - refclock_report(peer, CEVNT_FAULT); - else - pp->polls++; - - if (peer->burst > 0) - return; - /* - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - */ - peer->burst = NSTAGE; - - record_clock_stats(&peer->srcadr, pp->a_lastcode); - - - return; - -} - -/* - * fg_receive - receive data from the serial interface - */ -static void -fg_receive( - struct recvbuf *rbufp - ) -{ - struct refclockproc *pp; - struct fgunit *up; - struct peer *peer; - char *bpt; - - /* - * Initialize pointers and read the timecode and timestamp - * We can't use gtlin function because we need bynary data in buf */ - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct fgunit *)pp->unitptr; - - /* - * Below hug to implement receiving of status information - */ - if(!up->pollnum) - { - up->pollnum++; - return; - } - - - if (rbufp->recv_length < (LENFG-2)) - { - refclock_report(peer, CEVNT_BADREPLY); - return; /* The reply is invalid discard it. */ - } - - /* Below I trying to find a correct reply in buffer. - * Sometime GPS reply located in the beginnig of buffer, - * sometime you can find it with some offset. - */ - - bpt = (char *)rbufp->recv_space.X_recv_buffer; - while(*bpt != '') - bpt++; - -#define BP2(x) ( bpt[x] & 15 ) -#define BP1(x) (( bpt[x] & 240 ) >> 4) - - pp->year = BP1(2)*10 + BP2(2); - - if(pp->year == 94) - { - refclock_report(peer, CEVNT_BADREPLY); - if(!fg_init(pp->io.fd)) - refclock_report(peer, CEVNT_FAULT); - return; - /* GPS is just powered up. The date is invalid - - discarding it. Initilize GPS one more time */ - /* Sorry - this driver will broken in 2094 ;) */ - } - - if (pp->year < 99) - pp->year += 100; - - pp->year += 1900; - pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4); - -/* - After Jan, 10 2000 Forum Graphic GPS receiver had a very strange - benahour. It doubles day number for an hours in replys after 10:10:10 UTC - and doubles min every hour at HH:10:ss for a minute. - Hope it is a problem of my unit only and not a Y2K problem of FG GPS. - Below small code to avoid such situation. -*/ - if(up->y2kwarn > 10) - pp->hour = BP1(6)*10 + BP2(6); - else - pp->hour = BP1(5)*10 + BP2(5); - - if((up->y2kwarn > 10) && (pp->hour == 10)) - { - pp->minute = BP1(7)*10 + BP2(7); - pp->second = BP1(8)*10 + BP2(8); - pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000; - pp->nsec += BP1(10) * 1000; - } else { - pp->hour = BP1(5)*10 + BP2(5); - pp->minute = BP1(6)*10 + BP2(6); - pp->second = BP1(7)*10 + BP2(7); - pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000; - pp->nsec += BP1(9) * 1000; - } - - if((pp->hour == 10) && (pp->minute == 10)) - { - up->y2kwarn++; - } - - sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second); - pp->lencode = strlen(pp->a_lastcode); - /*get_systime(&pp->lastrec);*/ - -#ifdef DEBUG - if (debug) - printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n", - pp->year, pp->day, pp->hour, pp->minute, pp->second); -#endif - - if (peer->stratum <= 1) - peer->refid = pp->refid; - pp->disp = (10e-6); - pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */ - /* pp->leap = LEAP_NOWARNING; */ - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - - if (!refclock_process(pp)) - refclock_report(peer, CEVNT_BADTIME); - pp->lastref = pp->lastrec; - refclock_receive(peer); - return; -} - - -#else -int refclock_fg_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_gpsvme.c b/contrib/ntp/ntpd/refclock_gpsvme.c deleted file mode 100644 index a7fcf5f..0000000 --- a/contrib/ntp/ntpd/refclock_gpsvme.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * refclock_gpsvme.c NTP clock driver for the TrueTime GPS-VME - * R. Schmidt, Time Service, US Naval Obs. res@tuttle.usno.navy.mil - * - * The refclock type has been defined as 16 (until new id assigned). - * These DEFS are included in the Makefile: - * DEFS= -DHAVE_TERMIOS -DSYS_HPUX=9 - * DEFS_LOCAL= -DREFCLOCK - * CLOCKDEFS= -DGPSVME - * The file map_vme.c does the VME memory mapping, and includes vme_init(). - * map_vme.c is HP-UX specific, because HPUX cannot mmap() device files! Boo! - * The file gps.h provides TrueTime register info. - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_GPSVME) - -#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 */ - -#include <time.h> - -#define PRIO 120 /* set the realtime priority */ -#define NREGS 7 /* number of registers we will use */ - -extern int init_vme(); /* This is just a call to map_vme() */ - /* It doesn't have to be extern */ - /* the map_vme() call */ -extern unsigned short *greg[NREGS]; /* made extern to avoid being in both map_vme.c and this file */ -extern void *gps_base; /* mjb lmco 12/20/99 */ - -extern caddr_t map_vme (); -extern void unmap_vme(); /* Unmaps the VME space */ - -struct vmedate { /* structure needed by ntp */ - unsigned short year; /* *tptr is a pointer to this */ - unsigned short doy; - unsigned short hr; - unsigned short mn; - unsigned short sec; - unsigned long frac; - unsigned short status; -}; - -struct vmedate *get_gpsvme_time(); -struct vmedate * time_vme; /* added to emulate LM refclock_gpsvme - (Made global per RES suggestion to fix mem leak DW lmco) mjb lmco 12/15/99 */ - -/* END OF STUFF FROM RES */ - -/* - * Definitions - */ -#define MAXUNITS 2 /* max number of VME units */ -#define BMAX 50 /* timecode buffer length */ - -/* - * VME interface parameters. - */ -#define VMEPRECISION (-21) /* precision assumed (1 us) */ -#define USNOREFID "USNO\0" /* Or whatever? */ -#define VMEREFID "GPS" /* reference id */ -#define VMEDESCRIPTION "GPS" /* who we are */ -#define VMEHSREFID 0x7f7f1001 /* 127.127.16.01 refid hi strata */ - -/* I'm using clock type 16 until one is assigned */ -/* This is set also in vme_control, below */ - - -#define GMT 0 /* hour offset from Greenwich */ - -/* - * VME unit control structure. - */ -struct vmeunit { - struct peer *peer; /* associated peer structure */ - struct refclockio io; /* given to the I/O handler */ - struct vmedate vmedata; /* data returned from vme read */ - l_fp lastrec; /* last local time */ - l_fp lastref; /* last timecode time */ - char lastcode[BMAX]; /* last timecode received */ - u_short lencode; /* length of last timecode */ - u_long lasttime; /* last time clock heard from */ - u_short unit; /* unit number for this guy */ - u_short status; /* clock status */ - u_short lastevent; /* last clock event */ - u_short year; /* year of eternity */ - u_short day; /* day of year */ - u_short hour; /* hour of day */ - u_short minute; /* minute of hour */ - u_short second; /* seconds of minute */ - u_long usec; /* microsecond of second */ - u_long yearstart; /* start of current year */ - u_short leap; /* leap indicators */ - /* - * Status tallies - */ - u_long polls; /* polls sent */ - u_long noreply; /* no replies to polls */ - u_long coderecv; /* timecodes received */ - u_long badformat; /* bad format */ - u_long baddata; /* bad data */ - u_long timestarted; /* time we started this */ -}; - -/* - * Data space for the unit structures. Note that we allocate these on - * the fly, but never give them back. - */ -static struct vmeunit *vmeunits[MAXUNITS]; -static u_char unitinuse[MAXUNITS]; - -/* - * Keep the fudge factors separately so they can be set even - * when no clock is configured. - */ -static l_fp fudgefactor[MAXUNITS]; -static u_char stratumtouse[MAXUNITS]; -static u_char sloppyclockflag[MAXUNITS]; - -/* - * Function prototypes - */ -static void vme_init (void); -static int vme_start (int, struct peer *); -static void vme_shutdown (int, struct peer *); -static void vme_report_event (struct vmeunit *, int); -static void vme_receive (struct recvbuf *); -static void vme_poll (int unit, struct peer *); -static void vme_control (int, struct refclockstat *, struct refclockstat *, struct peer *); -static void vme_buginfo (int, struct refclockbug *, struct peer *); - -/* - * Transfer vector - */ -struct refclock refclock_gpsvme = { - vme_start, vme_shutdown, vme_poll, - vme_control, vme_init, vme_buginfo, NOFLAGS -}; - -int fd_vme; /* file descriptor for ioctls */ -int regvalue; - -/* - * vme_init - initialize internal vme driver data - */ -static void -vme_init(void) -{ - register int i; - /* - * Just zero the data arrays - */ - /* - bzero((char *)vmeunits, sizeof vmeunits); - bzero((char *)unitinuse, sizeof unitinuse); - */ - - /* - * Initialize fudge factors to default. - */ - for (i = 0; i < MAXUNITS; i++) { - fudgefactor[i].l_ui = 0; - fudgefactor[i].l_uf = 0; - stratumtouse[i] = 0; - sloppyclockflag[i] = 0; - } -} - -/* - * vme_start - open the VME device and initialize data for processing - */ -static int -vme_start( - u_int unit, - struct peer *peer - ) -{ - register struct vmeunit *vme; - register int i; - int dummy; - char vmedev[20]; - - /* - * Check configuration info. - */ - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_start: unit %d invalid", unit); - return (0); - } - if (unitinuse[unit]) { - msyslog(LOG_ERR, "vme_start: unit %d in use", unit); - return (0); - } - - /* - * Open VME device - */ -#ifdef DEBUG - - printf("Opening VME DEVICE \n"); -#endif - init_vme(); /* This is in the map_vme.c external file */ - - /* - * Allocate unit structure - */ - if (vmeunits[unit] != 0) { - vme = vmeunits[unit]; /* The one we want is okay */ - } else { - for (i = 0; i < MAXUNITS; i++) { - if (!unitinuse[i] && vmeunits[i] != 0) - break; - } - if (i < MAXUNITS) { - /* - * Reclaim this one - */ - vme = vmeunits[i]; - vmeunits[i] = 0; - } else { - vme = (struct vmeunit *) - emalloc(sizeof(struct vmeunit)); - time_vme = (struct vmedate *)malloc(sizeof(struct vmedate)); /* Added to emulate LM's refclock_gpsvme - (added to fix mem lead DW lmco) mjb lmco 12/22/99 */ - } - } - bzero((char *)vme, sizeof(struct vmeunit)); - vmeunits[unit] = vme; - - /* - * Set up the structures - */ - vme->peer = peer; - vme->unit = (u_short)unit; - vme->timestarted = current_time; - - vme->io.clock_recv = vme_receive; - vme->io.srcclock = (caddr_t)vme; - vme->io.datalen = 0; - vme->io.fd = fd_vme; - - /* - * All done. Initialize a few random peer variables, then - * return success. - */ - peer->precision = VMEPRECISION; - peer->stratum = stratumtouse[unit]; - memcpy( (char *)&peer->refid, USNOREFID,4); - - /* peer->refid = htonl(VMEHSREFID); */ - - unitinuse[unit] = 1; - return (1); -} - - -/* - * vme_shutdown - shut down a VME clock - */ -static void -vme_shutdown( - int unit - ) -{ - register struct vmeunit *vme; - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit); - return; - } - if (!unitinuse[unit]) { - msyslog(LOG_ERR, "vme_shutdown: unit %d not in use", unit); - return; - } - - /* - * Tell the I/O module to turn us off. We're history. - */ - unmap_vme(); - vme = vmeunits[unit]; - io_closeclock(&vme->io); - unitinuse[unit] = 0; -} - -/* - * vme_report_event - note the occurance of an event - * - * This routine presently just remembers the report and logs it, but - * does nothing heroic for the trap handler. - */ -static void -vme_report_event( - struct vmeunit *vme, - int code - ) -{ - struct peer *peer; - - peer = vme->peer; - if (vme->status != (u_short)code) { - vme->status = (u_short)code; - if (code != CEVNT_NOMINAL) - vme->lastevent = (u_short)code; - msyslog(LOG_INFO, - "clock %s event %x", ntoa(&peer->srcadr), code); - } -} - - -/* - * vme_receive - receive data from the VME device. - * - * Note: This interface would be interrupt-driven. We don't use that - * now, but include a dummy routine for possible future adventures. - */ -static void -vme_receive( - struct recvbuf *rbufp - ) -{ -} - -/* - * vme_poll - called by the transmit procedure - */ -static void -vme_poll( - int unit, - struct peer *peer - ) -{ - struct vmedate *tptr; - struct vmeunit *vme; - l_fp tstmp; - time_t tloc; - struct tm *tadr; - long ltemp; - - - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_poll: unit %d invalid", unit); - return; - } - if (!unitinuse[unit]) { - msyslog(LOG_ERR, "vme_poll: unit %d not in use", unit); - return; - } - vme = vmeunits[unit]; /* Here is the structure */ - vme->polls++; - - tptr = &vme->vmedata; - - if ((tptr = get_gpsvme_time()) == NULL ) { - vme_report_event(vme, CEVNT_BADREPLY); - return; - } - - get_systime(&vme->lastrec); - vme->lasttime = current_time; - - /* - * Get VME time and convert to timestamp format. - * The year must come from the system clock. - */ - /* - time(&tloc); - tadr = gmtime(&tloc); - tptr->year = (unsigned short)(tadr->tm_year + 1900); - */ - - sprintf(vme->lastcode, - "%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0", - tptr->doy, tptr->hr, tptr->mn, - tptr->sec, tptr->frac, tptr->status); - - record_clock_stats(&(vme->peer->srcadr), vme->lastcode); - vme->lencode = (u_short) strlen(vme->lastcode); - - vme->day = tptr->doy; - vme->hour = tptr->hr; - vme->minute = tptr->mn; - vme->second = tptr->sec; - vme->nsec = tptr->frac * 1000; - -#ifdef DEBUG - if (debug) - printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n", - vme->day, vme->hour, vme->minute, vme->second, - vme->nsec, tptr->status); -#endif - if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ - vme_report_event(vme, CEVNT_BADREPLY); - return; - } - - /* - * Now, compute the reference time value. Use the heavy - * machinery for the seconds and the millisecond field for the - * fraction when present. If an error in conversion to internal - * format is found, the program declares bad data and exits. - * Note that this code does not yet know how to do the years and - * relies on the clock-calendar chip for sanity. - */ - if (!clocktime(vme->day, vme->hour, vme->minute, - vme->second, GMT, vme->lastrec.l_ui, - &vme->yearstart, &vme->lastref.l_ui)) { - vme->baddata++; - vme_report_event(vme, CEVNT_BADTIME); - msyslog(LOG_ERR, "refclock_gpsvme: bad data!!"); - return; - } - vme->lastref.l_uf = 0; - DTOLFP(vme->nsec / 1e9, <emp); - L_ADD(&vme->lastrec, <emp); - tstmp = vme->lastref; - - L_SUB(&tstmp, &vme->lastrec); - vme->coderecv++; - - L_ADD(&tstmp, &(fudgefactor[vme->unit])); - vme->lastref = vme->lastrec; - refclock_receive(vme->peer); -} - -/* - * vme_control - set fudge factors, return statistics2 - */ -static void -vme_control( - u_int unit, - struct refclockstat *in, - struct refclockstat *out, - struct peer * peer - ) -{ - register struct vmeunit *vme; - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_control: unit %d invalid)", unit); - return; - } - - if (in != 0) { - if (in->haveflags & CLK_HAVETIME1) - DTOLFP(in->fudgetime1, &fudgefactor[unit]); /* added mjb lmco 12/20/99 */ - - if (in->haveflags & CLK_HAVEVAL1) { - stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf); - if (unitinuse[unit]) { - struct peer *peer; - - /* - * Should actually reselect clock, but - * will wait for the next timecode - */ - vme = vmeunits[unit]; - peer = vme->peer; - peer->stratum = stratumtouse[unit]; - if (stratumtouse[unit] <= 1) - memcpy( (char *)&peer->refid, USNOREFID,4); - else - peer->refid = htonl(VMEHSREFID); - } - } - if (in->haveflags & CLK_HAVEFLAG1) { - sloppyclockflag[unit] = in->flags & CLK_FLAG1; - } - } - - if (out != 0) { - out->type = 16; /*set by RES SHOULD BE CHANGED */ - out->haveflags - = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1; - out->clockdesc = VMEDESCRIPTION; - LFPTOD(&fudgefactor[unit], out->fudgetime1); /* added mjb lmco 12/20/99 */ - - out ->fudgetime2 = 0; /* should do what above was supposed to do mjb lmco 12/20/99 */ - - out->fudgeval1 = (long)stratumtouse[unit]; /*changed from above LONG was not - defined mjb lmco 12/15/99 */ - - out->fudgeval2 = 0; - out->flags = sloppyclockflag[unit]; - if (unitinuse[unit]) { - vme = vmeunits[unit]; - out->lencode = vme->lencode; - out->p_lastcode = vme->lastcode; - out->timereset = current_time - vme->timestarted; - out->polls = vme->polls; - out->noresponse = vme->noreply; - out->badformat = vme->badformat; - out->baddata = vme->baddata; - out->lastevent = vme->lastevent; - out->currentstatus = vme->status; - } else { - out->lencode = 0; - out->p_lastcode = ""; - out->polls = out->noresponse = 0; - out->badformat = out->baddata = 0; - out->timereset = 0; - out->currentstatus = out->lastevent = CEVNT_NOMINAL; - } - } -} - -/* - * vme_buginfo - return clock dependent debugging info - */ -static void -vme_buginfo( - int unit, - register struct refclockbug *bug, - struct peer * peer - ) -{ - register struct vmeunit *vme; - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "vme_buginfo: unit %d invalid)", unit); - return; - } - - if (!unitinuse[unit]) - return; - vme = vmeunits[unit]; - - bug->nvalues = 11; - bug->ntimes = 5; - if (vme->lasttime != 0) - bug->values[0] = current_time - vme->lasttime; - else - bug->values[0] = 0; - bug->values[2] = (u_long)vme->year; - bug->values[3] = (u_long)vme->day; - bug->values[4] = (u_long)vme->hour; - bug->values[5] = (u_long)vme->minute; - bug->values[6] = (u_long)vme->second; - bug->values[7] = (u_long)vme->nsec; - bug->values[9] = vme->yearstart; - bug->stimes = 0x1c; - bug->times[0] = vme->lastref; - bug->times[1] = vme->lastrec; -} -/* -------------------------------------------------------*/ -/* get_gpsvme_time() */ -/* R. Schmidt, USNO, 1995 */ -/* It's ugly, but hey, it works and its free */ - -#include "gps.h" /* defines for TrueTime GPS-VME */ - -#define PBIAS 193 /* 193 microsecs to read the GPS experimentally found */ - -struct vmedate * -get_gpsvme_time(void) -{ - extern struct vmedate *time_vme; - unsigned short set, hr, min, sec, ums, hms, status; - int ret; - char ti[3]; - - long tloc ; - time_t mktime(),time(); - struct tm *gmtime(), *gmt; - char *gpsmicro; - gpsmicro = (char *) malloc(7); - - *greg = (unsigned short *)malloc(sizeof(short) * NREGS); - - - /* reference the freeze command address general register 1 */ - set = *greg[0]; - /* read the registers : */ - /* get year */ - time_vme->year = (unsigned short) *greg[6]; - /* Get doy */ - time_vme->doy = (unsigned short) (*greg[5] & MASKDAY); - /* Get hour */ - time_vme->hr = (unsigned short) ((*greg[4] & MASKHI) >>8); - /* Get minutes */ - time_vme->mn = (unsigned short) (*greg[4] & MASKLO); - /* Get seconds */ - time_vme->sec = (unsigned short) (*greg[3] & MASKHI) >>8; - /* get microseconds in 2 parts and put together */ - ums = *greg[2]; - hms = *greg[3] & MASKLO; - - time_vme->status = (unsigned short) *greg[5] >>13; - - /* reference the unfreeze command address general register 1 */ - set = *greg[1]; - - sprintf(gpsmicro,"%2.2x%4.4x\0", hms, ums); - time_vme->frac = (u_long) gpsmicro; - - /* unmap_vme(); */ - - if (!status) { - return (NULL); /* fixed mjb lmco 12/20/99 */ - } - else - return (time_vme); -} - -#else -int refclock_gpsvme_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_heath.c b/contrib/ntp/ntpd/refclock_heath.c deleted file mode 100644 index c16cef3..0000000 --- a/contrib/ntp/ntpd/refclock_heath.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * refclock_heath - clock driver for Heath GC-1000 and and GC-1000 II - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#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 HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif /* not HAVE_SYS_IOCTL_H */ - -/* - * This driver supports the Heath GC-1000 Most Accurate Clock, with - * RS232C Output Accessory. This is a WWV/WWVH receiver somewhat less - * robust than other supported receivers. Its claimed accuracy is 100 ms - * when actually synchronized to the broadcast signal, but this doesn't - * happen even most of the time, due to propagation conditions, ambient - * noise sources, etc. When not synchronized, the accuracy is at the - * whim of the internal clock oscillator, which can wander into the - * sunset without warning. Since the indicated precision is 100 ms, - * expect a host synchronized only to this thing to wander to and fro, - * occasionally being rudely stepped when the offset exceeds the default - * clock_max of 128 ms. - * - * 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 - * is necessary that the operating system implement the TIOCMBIC and - * TIOCMBIS ioctl system calls and TIOCM_RTS control bit. Present - * restrictions require the use of a POSIX-compatible programming - * interface, although other interfaces may work as well. - * - * A simple hardware modification to the clock can be made which - * prevents the clock hearing the request to send (RTS) if the HI SPEC - * lamp is out. Route the HISPEC signal to the tone decoder board pin - * 19, from the display, pin 19. Isolate pin 19 of the decoder board - * first, but maintain connection with pin 10. Also isolate pin 38 of - * the CPU on the tone board, and use half an added 7400 to gate the - * original signal to pin 38 with that from pin 19. - * - * The clock message consists of 23 ASCII printing characters in the - * following format: - * - * hh:mm:ss.f AM dd/mm/yr<cr> - * - * hh:mm:ss.f = hours, minutes, seconds - * f = deciseconds ('?' when out of spec) - * AM/PM/bb = blank in 24-hour mode - * dd/mm/yr = day, month, year - * - * The alarm condition is indicated by '?', rather than a digit, at f. - * Note that 0?:??:??.? is displayed before synchronization is first - * 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 - * residuals. The fudge time2 parameter is the local time offset east of - * Greenwich, which depends on DST. Sorry about that, but the clock - * gives no hint on what the DIPswitches say. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/heath%d" /* device name and unit */ -#define PRECISION (-4) /* precision assumed (about 100 ms) */ -#define REFID "WWV\0" /* reference ID */ -#define DESCRIPTION "Heath GC-1000 Most Accurate Clock" /* WRU */ - -#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 - * leap. - */ -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}; - -/* - * Function prototypes - */ -static int heath_start P((int, struct peer *)); -static void heath_shutdown P((int, struct peer *)); -static void heath_receive P((struct recvbuf *)); -static void heath_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_heath = { - heath_start, /* start up driver */ - heath_shutdown, /* shut down driver */ - heath_poll, /* transmit poll message */ - noentry, /* not used (old heath_control) */ - noentry, /* initialize driver */ - noentry, /* not used (old heath_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * heath_start - open the devices and initialize data for processing - */ -static int -heath_start( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, speed[peer->ttl & 0x3], 0))) - return (0); - pp = peer->procptr; - pp->io.clock_recv = heath_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - peer->burst = NSTAGE; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - return (1); -} - - -/* - * heath_shutdown - shut down the clock - */ -static void -heath_shutdown( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - - pp = peer->procptr; - io_closeclock(&pp->io); -} - - -/* - * heath_receive - receive data from the serial interface - */ -static void -heath_receive( - struct recvbuf *rbufp - ) -{ - struct refclockproc *pp; - struct peer *peer; - l_fp trtmp; - int month, day; - int i; - char dsec, a[5]; - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, - &trtmp); - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. - */ - switch (pp->lencode) { - - /* - * GC-1000 timecode format: "hh:mm:ss.f AM mm/dd/yy" - * GC-1000 II timecode format: "hh:mm:ss.f " - */ - 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; - - /* - * GC-1000 II timecode format: "hh:mm:ss.f " - */ - 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; - } - break; - - default: - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * We determine the day of the year from the DIPswitches. This - * should be fixed, since somebody might forget to set them. - * Someday this hazard will be fixed by a fiendish scheme that - * looks at the timecode and year the radio shows, then computes - * the residue of the seconds mod the seconds in a leap cycle. - * If in the third year of that cycle and the third and later - * months of that year, add one to the day. Then, correct the - * 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. - */ - if (month < 1 || month > 12 || day < 1) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - if (pp->year % 4) { - if (day > day1tab[month - 1]) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - for (i = 0; i < month - 1; i++) - day += day1tab[i]; - } else { - if (day > day2tab[month - 1]) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - for (i = 0; i < month - 1; i++) - day += day2tab[i]; - } - pp->day = day; - - /* - * Determine synchronization and last update - */ - if (!isdigit((int)dsec)) - pp->leap = LEAP_NOTINSYNC; - else { - pp->nsec = (dsec - '0') * 100000000; - pp->leap = LEAP_NOWARNING; - } - if (!refclock_process(pp)) - refclock_report(peer, CEVNT_BADTIME); -} - - -/* - * heath_poll - called by the transmit procedure - */ -static void -heath_poll( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - int bits = TIOCM_RTS; - - /* - * At each poll we check for timeout and toggle the RTS modem - * control line, then take a timestamp. Presumably, this is the - * event the radio captures to generate the timecode. - * Apparently, the radio takes about a second to make up its - * mind to send a timecode, so the receive timestamp is - * worthless. - */ - pp = peer->procptr; - - /* - * 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(&pp->lastrec); - if (write(pp->io.fd, "T", 1) != 1) - refclock_report(peer, CEVNT_FAULT); - ioctl(pp->io.fd, TIOCMBIS, (char *)&bits); - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("heath: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - peer->burst = MAXSTAGE; - pp->polls++; -} - -#else -int refclock_heath_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_hopfpci.c b/contrib/ntp/ntpd/refclock_hopfpci.c deleted file mode 100644 index 1b02319..0000000 --- a/contrib/ntp/ntpd/refclock_hopfpci.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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 <sys/ioctl.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 = INVALID_SOCKET; - 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->nsec = m_time.wMilliseconds * 1000000; - if (m_time.wStatus & LEWAPWAR) - pp->leap = LEAP_ADDSECOND; - else - pp->leap = LEAP_NOWARNING; - - sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d", - m_time.wStatus, pp->hour, pp->minute, pp->second, - pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear); - pp->lencode = (u_short)strlen(pp->a_lastcode); - - get_systime(&pp->lastrec); - - /* - * 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; - } - pp->lastref = pp->lastrec; - 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 deleted file mode 100644 index 1d27333..0000000 --- a/contrib/ntp/ntpd/refclock_hopfser.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * - * 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(SYS_WINNT) -#undef close -#define close closesocket -#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 synch; /* synchhronization 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 = (u_short)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 - &synch, - &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", - synch, - DoW, - day, - month, - pp->year, - pp->hour, - pp->minute, - pp->second); - - pp->lencode = strlen(pp->a_lastcode); - if ((synch && 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 ((synch & 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 ((synch & 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; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - -#if 0 - msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,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 deleted file mode 100644 index 7c801bb..0000000 --- a/contrib/ntp/ntpd/refclock_hpgps.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * refclock_hpgps - clock driver for HP 58503A GPS receiver - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_HPGPS) - -#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 - * clear status if prompt indicates error; - * can use either local time or UTC from receiver; - * can get receiver status screen via flag4 - * - * WARNING!: This driver is UNDER CONSTRUCTION - * Everything in here should be treated with suspicion. - * If it looks wrong, it probably is. - * - * Comments and/or questions to: Dave Vitanye - * Hewlett Packard Company - * dave@scd.hp.com - * (408) 553-2856 - * - * Thanks to the author of the PST driver, which was the starting point for - * this one. - * - * This driver supports the HP 58503A Time and Frequency Reference Receiver. - * This receiver uses HP SmartClock (TM) to implement an Enhanced GPS receiver. - * The receiver accuracy when locked to GPS in normal operation is better - * than 1 usec. The accuracy when operating in holdover is typically better - * than 10 usec. per day. - * - * The receiver should be operated with factory default settings. - * Initial driver operation: expects the receiver to be already locked - * to GPS, configured and able to output timecode format 2 messages. - * - * The driver uses the poll sequence :PTIME:TCODE? to get a response from - * the receiver. The receiver responds with a timecode string of ASCII - * printing characters, followed by a <cr><lf>, followed by a prompt string - * issued by the receiver, in the following format: - * T#yyyymmddhhmmssMFLRVcc<cr><lf>scpi > - * - * The driver processes the response at the <cr> and <lf>, so what the - * driver sees is the prompt from the previous poll, followed by this - * timecode. The prompt from the current poll is (usually) left unread until - * the next poll. So (except on the very first poll) the driver sees this: - * - * scpi > T#yyyymmddhhmmssMFLRVcc<cr><lf> - * - * The T is the on-time character, at 980 msec. before the next 1PPS edge. - * The # is the timecode format type. We look for format 2. - * Without any of the CLK or PPS stuff, then, the receiver buffer timestamp - * at the <cr> is 24 characters later, which is about 25 msec. at 9600 bps, - * so the first approximation for fudge time1 is nominally -0.955 seconds. - * This number probably needs adjusting for each machine / OS type, so far: - * -0.955000 on an HP 9000 Model 712/80 HP-UX 9.05 - * -0.953175 on an HP 9000 Model 370 HP-UX 9.10 - * - * This receiver also provides a 1PPS signal, but I haven't figured out - * how to deal with any of the CLK or PPS stuff yet. Stay tuned. - * - */ - -/* - * Fudge Factors - * - * Fudge time1 is used to accomodate the timecode serial interface adjustment. - * Fudge flag4 can be set to request a receiver status screen summary, which - * is recorded in the clockstats file. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/hpgps%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define REFID "GPS\0" /* reference ID */ -#define DESCRIPTION "HP 58503A GPS Time and Frequency Reference Receiver" - -#define SMAX 23*80+1 /* for :SYSTEM:PRINT? status screen response */ - -#define MTZONE 2 /* number of fields in timezone reply */ -#define MTCODET2 12 /* number of fields in timecode format T2 */ -#define NTCODET2 21 /* number of chars to checksum in format T2 */ - -/* - * Tables to compute the day of year from yyyymmdd timecode. - * Viva la leap. - */ -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}; - -/* - * Unit control structure - */ -struct hpgpsunit { - int pollcnt; /* poll message counter */ - int tzhour; /* timezone offset, hours */ - int tzminute; /* timezone offset, minutes */ - int linecnt; /* set for expected multiple line responses */ - char *lastptr; /* pointer to receiver response data */ - char statscrn[SMAX]; /* receiver status screen buffer */ -}; - -/* - * Function prototypes - */ -static int hpgps_start P((int, struct peer *)); -static void hpgps_shutdown P((int, struct peer *)); -static void hpgps_receive P((struct recvbuf *)); -static void hpgps_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_hpgps = { - hpgps_start, /* start up driver */ - hpgps_shutdown, /* shut down driver */ - hpgps_poll, /* transmit poll message */ - noentry, /* not used (old hpgps_control) */ - noentry, /* initialize driver */ - noentry, /* not used (old hpgps_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * hpgps_start - open the devices and initialize data for processing - */ -static int -hpgps_start( - int unit, - struct peer *peer - ) -{ - register struct hpgpsunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct hpgpsunit *) - emalloc(sizeof(struct hpgpsunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct hpgpsunit)); - pp = peer->procptr; - pp->io.clock_recv = hpgps_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->tzhour = 0; - up->tzminute = 0; - - *up->statscrn = '\0'; - up->lastptr = up->statscrn; - up->pollcnt = 2; - - /* - * Get the identifier string, which is logged but otherwise ignored, - * and get the local timezone information - */ - up->linecnt = 1; - if (write(pp->io.fd, "*IDN?\r:PTIME:TZONE?\r", 20) != 20) - refclock_report(peer, CEVNT_FAULT); - - return (1); -} - - -/* - * hpgps_shutdown - shut down the clock - */ -static void -hpgps_shutdown( - int unit, - struct peer *peer - ) -{ - register struct hpgpsunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct hpgpsunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * hpgps_receive - receive data from the serial interface - */ -static void -hpgps_receive( - struct recvbuf *rbufp - ) -{ - register struct hpgpsunit *up; - struct refclockproc *pp; - struct peer *peer; - l_fp trtmp; - char tcodechar1; /* identifies timecode format */ - char tcodechar2; /* identifies timecode format */ - char timequal; /* time figure of merit: 0-9 */ - char freqqual; /* frequency figure of merit: 0-3 */ - char leapchar; /* leapsecond: + or 0 or - */ - char servchar; /* request for service: 0 = no, 1 = yes */ - char syncchar; /* time info is invalid: 0 = no, 1 = yes */ - short expectedsm; /* expected timecode byte checksum */ - short tcodechksm; /* computed timecode byte checksum */ - int i,m,n; - int month, day, lastday; - char *tcp; /* timecode pointer (skips over the prompt) */ - char prompt[BMAX]; /* prompt in response from receiver */ - - /* - * Initialize pointers and read the receiver response - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct hpgpsunit *)pp->unitptr; - *pp->a_lastcode = '\0'; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); - -#ifdef DEBUG - if (debug) - printf("hpgps: lencode: %d timecode:%s\n", - pp->lencode, pp->a_lastcode); -#endif - - /* - * If there's no characters in the reply, we can quit now - */ - if (pp->lencode == 0) - return; - - /* - * If linecnt is greater than zero, we are getting information only, - * such as the receiver identification string or the receiver status - * screen, so put the receiver response at the end of the status - * screen buffer. When we have the last line, write the buffer to - * the clockstats file and return without further processing. - * - * If linecnt is zero, we are expecting either the timezone - * or a timecode. At this point, also write the response - * to the clockstats file, and go on to process the prompt (if any), - * timezone, or timecode and timestamp. - */ - - - if (up->linecnt-- > 0) { - if ((int)(pp->lencode + 2) <= (SMAX - (up->lastptr - up->statscrn))) { - *up->lastptr++ = '\n'; - (void)strcpy(up->lastptr, pp->a_lastcode); - up->lastptr += pp->lencode; - } - if (up->linecnt == 0) - record_clock_stats(&peer->srcadr, up->statscrn); - - return; - } - - record_clock_stats(&peer->srcadr, pp->a_lastcode); - pp->lastrec = trtmp; - - up->lastptr = up->statscrn; - *up->lastptr = '\0'; - up->pollcnt = 2; - - /* - * We get down to business: get a prompt if one is there, issue - * a clear status command if it contains an error indication. - * Next, check for either the timezone reply or the timecode reply - * and decode it. If we don't recognize the reply, or don't get the - * proper number of decoded fields, or get an out of range timezone, - * or if the timecode checksum is bad, then we declare bad format - * and exit. - * - * Timezone format (including nominal prompt): - * scpi > -H,-M<cr><lf> - * - * Timecode format (including nominal prompt): - * scpi > T2yyyymmddhhmmssMFLRVcc<cr><lf> - * - */ - - (void)strcpy(prompt,pp->a_lastcode); - tcp = strrchr(pp->a_lastcode,'>'); - if (tcp == NULL) - tcp = pp->a_lastcode; - else - tcp++; - prompt[tcp - pp->a_lastcode] = '\0'; - while ((*tcp == ' ') || (*tcp == '\t')) tcp++; - - /* - * deal with an error indication in the prompt here - */ - if (strrchr(prompt,'E') > strrchr(prompt,'s')){ -#ifdef DEBUG - if (debug) - printf("hpgps: error indicated in prompt: %s\n", prompt); -#endif - if (write(pp->io.fd, "*CLS\r\r", 6) != 6) - refclock_report(peer, CEVNT_FAULT); - } - - /* - * make sure we got a timezone or timecode format and - * then process accordingly - */ - m = sscanf(tcp,"%c%c", &tcodechar1, &tcodechar2); - - if (m != 2){ -#ifdef DEBUG - if (debug) - printf("hpgps: no format indicator\n"); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - switch (tcodechar1) { - - case '+': - case '-': - m = sscanf(tcp,"%d,%d", &up->tzhour, &up->tzminute); - if (m != MTZONE) { -#ifdef DEBUG - if (debug) - printf("hpgps: only %d fields recognized in timezone\n", m); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } - if ((up->tzhour < -12) || (up->tzhour > 13) || - (up->tzminute < -59) || (up->tzminute > 59)){ -#ifdef DEBUG - if (debug) - printf("hpgps: timezone %d, %d out of range\n", - up->tzhour, up->tzminute); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } - return; - - case 'T': - break; - - default: -#ifdef DEBUG - if (debug) - printf("hpgps: unrecognized reply format %c%c\n", - tcodechar1, tcodechar2); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } /* end of tcodechar1 switch */ - - - switch (tcodechar2) { - - case '2': - m = sscanf(tcp,"%*c%*c%4d%2d%2d%2d%2d%2d%c%c%c%c%c%2hx", - &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, - &timequal, &freqqual, &leapchar, &servchar, &syncchar, - &expectedsm); - n = NTCODET2; - - if (m != MTCODET2){ -#ifdef DEBUG - if (debug) - printf("hpgps: only %d fields recognized in timecode\n", m); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } - break; - - default: -#ifdef DEBUG - if (debug) - printf("hpgps: unrecognized timecode format %c%c\n", - tcodechar1, tcodechar2); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } /* end of tcodechar2 format switch */ - - /* - * Compute and verify the checksum. - * Characters are summed starting at tcodechar1, ending at just - * before the expected checksum. Bail out if incorrect. - */ - tcodechksm = 0; - while (n-- > 0) tcodechksm += *tcp++; - tcodechksm &= 0x00ff; - - if (tcodechksm != expectedsm) { -#ifdef DEBUG - if (debug) - printf("hpgps: checksum %2hX doesn't match %2hX expected\n", - tcodechksm, expectedsm); -#endif - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Compute the day of year from the yyyymmdd format. - */ - if (month < 1 || month > 12 || day < 1) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - if ( ! isleap_4(pp->year) ) { /* Y2KFixes */ - /* not a leap year */ - if (day > day1tab[month - 1]) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - for (i = 0; i < month - 1; i++) day += day1tab[i]; - lastday = 365; - } else { - /* a leap year */ - if (day > day2tab[month - 1]) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - for (i = 0; i < month - 1; i++) day += day2tab[i]; - lastday = 366; - } - - /* - * Deal with the timezone offset here. The receiver timecode is in - * local time = UTC + :PTIME:TZONE, so SUBTRACT the timezone values. - * For example, Pacific Standard Time is -8 hours , 0 minutes. - * Deal with the underflows and overflows. - */ - pp->minute -= up->tzminute; - pp->hour -= up->tzhour; - - if (pp->minute < 0) { - pp->minute += 60; - pp->hour--; - } - if (pp->minute > 59) { - pp->minute -= 60; - pp->hour++; - } - if (pp->hour < 0) { - pp->hour += 24; - day--; - if (day < 1) { - pp->year--; - if ( isleap_4(pp->year) ) /* Y2KFixes */ - day = 366; - else - day = 365; - } - } - - if (pp->hour > 23) { - pp->hour -= 24; - day++; - if (day > lastday) { - pp->year++; - day = 1; - } - } - - pp->day = day; - - /* - * Decode the MFLRV indicators. - * NEED TO FIGURE OUT how to deal with the request for service, - * time quality, and frequency quality indicators some day. - */ - if (syncchar != '0') { - pp->leap = LEAP_NOTINSYNC; - } - else { - switch (leapchar) { - - case '+': - pp->leap = LEAP_ADDSECOND; - break; - - case '0': - pp->leap = LEAP_NOWARNING; - break; - - case '-': - pp->leap = LEAP_DELSECOND; - break; - - default: -#ifdef DEBUG - if (debug) - printf("hpgps: unrecognized leap indicator: %c\n", - leapchar); -#endif - refclock_report(peer, CEVNT_BADTIME); - return; - } /* end of leapchar switch */ - } - - /* - * Process the new sample in the median filter and determine the - * reference clock offset and dispersion. We use lastrec as both - * the reference time and receive time in order to avoid being - * cute, like setting the reference time later than the receive - * time, which may cause a paranoid protocol module to chuck out - * the data. - */ - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - - /* - * If CLK_FLAG4 is set, ask for the status screen response. - */ - if (pp->sloppyclockflag & CLK_FLAG4){ - up->linecnt = 22; - if (write(pp->io.fd, ":SYSTEM:PRINT?\r", 15) != 15) - refclock_report(peer, CEVNT_FAULT); - } -} - - -/* - * hpgps_poll - called by the transmit procedure - */ -static void -hpgps_poll( - int unit, - struct peer *peer - ) -{ - register struct hpgpsunit *up; - struct refclockproc *pp; - - /* - * Time to poll the clock. The HP 58503A responds to a - * ":PTIME:TCODE?" by returning a timecode in the format specified - * above. If nothing is heard from the clock for two polls, - * declare a timeout and keep going. - */ - pp = peer->procptr; - up = (struct hpgpsunit *)pp->unitptr; - if (up->pollcnt == 0) - refclock_report(peer, CEVNT_TIMEOUT); - else - up->pollcnt--; - if (write(pp->io.fd, ":PTIME:TCODE?\r", 14) != 14) { - refclock_report(peer, CEVNT_FAULT); - } - else - pp->polls++; -} - -#else -int refclock_hpgps_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_irig.c b/contrib/ntp/ntpd/refclock_irig.c deleted file mode 100644 index 0b35368..0000000 --- a/contrib/ntp/ntpd/refclock_irig.c +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * refclock_irig - audio IRIG-B/E demodulator/decoder - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#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 <math.h> -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif /* HAVE_SYS_IOCTL_H */ - -#include "audio.h" - -/* - * Audio IRIG-B/E demodulator/decoder - * - * This driver receives, demodulates and decodes IRIG-B/E signals when - * connected to the audio codec /dev/audio. The IRIG signal format is an - * amplitude-modulated carrier with pulse-width modulated data bits. For - * IRIG-B, the carrier frequency is 1000 Hz and bit rate 100 b/s; for - * IRIG-E, the carrier frequenchy is 100 Hz and bit rate 10 b/s. The - * driver automatically recognizes which format is in use. - * - * The program processes 8000-Hz mu-law companded samples using separate - * signal filters for IRIG-B and IRIG-E, a comb filter, envelope - * detector and automatic threshold corrector. Cycle crossings relative - * to the corrected slice level determine the width of each pulse and - * its value - zero, one or position identifier. The data encode 20 BCD - * digits which determine the second, minute, hour and day of the year - * and sometimes the year and synchronization condition. The comb filter - * exponentially averages the corresponding samples of successive baud - * intervals in order to reliably identify the reference carrier cycle. - * A type-II phase-lock loop (PLL) performs additional integration and - * interpolation to accurately determine the zero crossing of that - * cycle, which determines the reference timestamp. A pulse-width - * discriminator demodulates the data pulses, which are then encoded as - * the BCD digits of the timecode. - * - * The timecode and reference timestamp are updated once each second - * with IRIG-B (ten seconds with IRIG-E) and local clock offset samples - * saved for later processing. At poll intervals of 64 s, the saved - * samples are processed by a trimmed-mean filter and used to update the - * system clock. - * - * An automatic gain control feature provides protection against - * overdriven or underdriven input signal amplitudes. It is designed to - * maintain adequate demodulator signal amplitude while avoiding - * occasional noise spikes. In order to assure reliable capture, the - * decompanded input signal amplitude must be greater than 100 units and - * the codec sample frequency error less than 250 PPM (.025 percent). - * - * The program performs a number of error checks to protect against - * overdriven or underdriven input signal levels, incorrect signal - * format or improper hardware configuration. Specifically, if any of - * the following errors occur for a time measurement, the data are - * rejected. - * - * o The peak carrier amplitude is less than DRPOUT (100). This usually - * means dead IRIG signal source, broken cable or wrong input port. - * - * o The frequency error is greater than MAXFREQ +-250 PPM (.025%). This - * usually means broken codec hardware or wrong codec configuration. - * - * o The modulation index is less than MODMIN (0.5). This usually means - * overdriven IRIG signal or wrong IRIG format. - * - * o A frame synchronization error has occurred. This usually means - * wrong IRIG signal format or the IRIG signal source has lost - * synchronization (signature control). - * - * o A data decoding error has occurred. This usually means wrong IRIG - * signal format. - * - * o The current second of the day is not exactly one greater than the - * previous one. This usually means a very noisy IRIG signal or - * insufficient CPU resources. - * - * o An audio codec error (overrun) occurred. This usually means - * insufficient CPU resources, as sometimes happens with Sun SPARC - * IPCs when doing something useful. - * - * Note that additional checks are done elsewhere in the reference clock - * interface routines. - * - * Debugging aids - * - * The timecode format used for debugging and data recording includes - * data helpful in diagnosing problems with the IRIG signal and codec - * connections. With debugging enabled (-d on the ntpd command line), - * the driver produces one line for each timecode in the following - * format: - * - * 00 1 98 23 19:26:52 721 143 0.694 20 0.1 66.5 3094572411.00027 - * - * The most recent line is also written to the clockstats file at 64-s - * intervals. - * - * The first field contains the error flags in hex, where the hex bits - * are interpreted as below. This is followed by the IRIG status - * indicator, year of century, day of year and time of day. The status - * indicator and year are not produced by some IRIG devices. Following - * these fields are the signal amplitude (0-8100), codec gain (0-255), - * modulation index (0-1), time constant (2-20), carrier phase error - * (us) and carrier frequency error (PPM). The last field is the on-time - * timestamp in NTP format. - * - * The fraction part of the on-time timestamp is a good indicator of how - * well the driver is doing. With an UltrSPARC 30 and Solaris 2.7, this - * thing can keep the clock within a few tens of microseconds relative - * to the IRIG-B signal. Accuracy with IRIG-E is about ten times worse. - * Unfortunately, Sun broke the 2.7 audio driver in 2.8, which has a - * 10-ms sawtooth modulation. The driver attempts to remove the - * modulation by some clever estimation techniques which mostly work. - * Your experience may vary. - * - * Unlike other drivers, which can have multiple instantiations, this - * one supports only one. It does not seem likely that more than one - * audio codec would be useful in a single machine. More than one would - * probably chew up too much CPU time anyway. - * - * Fudge factors - * - * Fudge flag4 causes the dubugging output described above to be - * recorded in the clockstats file. When the audio driver is compiled, - * fudge flag2 selects the audio input port, where 0 is the mike port - * (default) and 1 is the line-in port. It does not seem useful to - * select the compact disc player port. Fudge flag3 enables audio - * monitoring of the input signal. For this purpose, the monitor gain is - * set to a default value. Fudgetime2 is used as a frequency vernier for - * broken codec sample frequency. - */ -/* - * 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 */ -#define AUDIO_BUFSIZ 320 /* audio buffer size (40 ms) */ -#define SECOND 8000 /* nominal sample rate (Hz) */ -#define BAUD 80 /* samples per baud interval */ -#define OFFSET 128 /* companded sample offset */ -#define SIZE 256 /* decompanding table size */ -#define CYCLE 8 /* samples per carrier cycle */ -#define SUBFLD 10 /* bits per subfield */ -#define FIELD 10 /* subfields per field */ -#define MINTC 2 /* min PLL time constant */ -#define MAXTC 20 /* max PLL time constant max */ -#define MAXSIG 6000. /* maximum signal level */ -#define MAXCLP 100 /* max clips above reference per s */ -#define DRPOUT 100. /* dropout signal level */ -#define MODMIN 0.5 /* minimum modulation index */ -#define MAXFREQ (250e-6 * SECOND) /* freq tolerance (.025%) */ -#define PI 3.1415926535 /* the real thing */ -#ifdef IRIG_SUCKS -#define WIGGLE 11 /* wiggle filter length */ -#endif /* IRIG_SUCKS */ - -/* - * Experimentally determined filter delays - */ -#define IRIG_B .0019 /* IRIG-B filter delay */ -#define IRIG_E .0019 /* IRIG-E filter delay */ - -/* - * Data bit definitions - */ -#define BIT0 0 /* zero */ -#define BIT1 1 /* one */ -#define BITP 2 /* position identifier */ - -/* - * Error flags (up->errflg) - */ -#define IRIG_ERR_AMP 0x01 /* low carrier amplitude */ -#define IRIG_ERR_FREQ 0x02 /* frequency tolerance exceeded */ -#define IRIG_ERR_MOD 0x04 /* low modulation index */ -#define IRIG_ERR_SYNCH 0x08 /* frame synch error */ -#define IRIG_ERR_DECODE 0x10 /* frame decoding error */ -#define IRIG_ERR_CHECK 0x20 /* second numbering discrepancy */ -#define IRIG_ERR_ERROR 0x40 /* codec error (overrun) */ -#define IRIG_ERR_SIGERR 0x80 /* IRIG status error (Spectracom) */ - -/* - * IRIG unit control structure - */ -struct irigunit { - u_char timecode[21]; /* timecode string */ - l_fp timestamp; /* audio sample timestamp */ - l_fp tick; /* audio sample increment */ - double integ[BAUD]; /* baud integrator */ - double phase, freq; /* logical clock phase and frequency */ - double zxing; /* phase detector integrator */ - double yxing; /* cycle phase */ - double exing; /* envelope phase */ - double modndx; /* modulation index */ - double irig_b; /* IRIG-B signal amplitude */ - double irig_e; /* IRIG-E signal amplitude */ - int errflg; /* error flags */ - /* - * Audio codec variables - */ - double comp[SIZE]; /* decompanding table */ - int port; /* codec port */ - int gain; /* codec gain */ - int mongain; /* codec monitor gain */ - int clipcnt; /* sample clipped count */ - int seccnt; /* second interval counter */ - - /* - * RF variables - */ - double hpf[5]; /* IRIG-B filter shift register */ - double lpf[5]; /* IRIG-E filter shift register */ - double intmin, intmax; /* integrated envelope min and max */ - double envmax; /* peak amplitude */ - double envmin; /* noise amplitude */ - double maxsignal; /* integrated peak amplitude */ - double noise; /* integrated noise amplitude */ - double lastenv[CYCLE]; /* last cycle amplitudes */ - double lastint[CYCLE]; /* last integrated cycle amplitudes */ - double lastsig; /* last carrier sample */ - double fdelay; /* filter delay */ - int decim; /* sample decimation factor */ - int envphase; /* envelope phase */ - int envptr; /* envelope phase pointer */ - int carphase; /* carrier phase */ - int envsw; /* envelope state */ - int envxing; /* envelope slice crossing */ - int tc; /* time constant */ - int tcount; /* time constant counter */ - int badcnt; /* decimation interval counter */ - - /* - * Decoder variables - */ - int pulse; /* cycle counter */ - int cycles; /* carrier cycles */ - int dcycles; /* data cycles */ - int xptr; /* translate table pointer */ - int lastbit; /* last code element length */ - int second; /* previous second */ - int fieldcnt; /* subfield count in field */ - int bits; /* demodulated bits */ - int bitcnt; /* bit count in subfield */ -#ifdef IRIG_SUCKS - l_fp wigwag; /* wiggle accumulator */ - int wp; /* wiggle filter pointer */ - l_fp wiggle[WIGGLE]; /* wiggle filter */ - l_fp wigbot[WIGGLE]; /* wiggle bottom fisher*/ -#endif /* IRIG_SUCKS */ - l_fp wuggle; -}; - -/* - * Function prototypes - */ -static int irig_start P((int, struct peer *)); -static void irig_shutdown P((int, struct peer *)); -static void irig_receive P((struct recvbuf *)); -static void irig_poll P((int, struct peer *)); - -/* - * More function prototypes - */ -static void irig_base P((struct peer *, double)); -static void irig_rf P((struct peer *, double)); -static void irig_decode P((struct peer *, int)); -static void irig_gain P((struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_irig = { - irig_start, /* start up driver */ - irig_shutdown, /* shut down driver */ - irig_poll, /* transmit poll message */ - noentry, /* not used (old irig_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old irig_buginfo) */ - NOFLAGS /* not used */ -}; - -/* - * Global variables - */ -static char hexchar[] = { /* really quick decoding table */ - '0', '8', '4', 'c', /* 0000 0001 0010 0011 */ - '2', 'a', '6', 'e', /* 0100 0101 0110 0111 */ - '1', '9', '5', 'd', /* 1000 1001 1010 1011 */ - '3', 'b', '7', 'f' /* 1100 1101 1110 1111 */ -}; - - -/* - * irig_start - open the devices and initialize data for processing - */ -static int -irig_start( - int unit, /* instance number (used for PCM) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; - - /* - * Local variables - */ - int fd; /* file descriptor */ - int i; /* index */ - double step; /* codec adjustment */ - - /* - * Open audio device - */ - fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); - if (fd < 0) - return (0); -#ifdef DEBUG - if (debug) - audio_show(); -#endif - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct irigunit *) - emalloc(sizeof(struct irigunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct irigunit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = irig_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void)close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->tc = MINTC; - up->decim = 1; - up->fdelay = IRIG_B; - up->gain = 127; - - /* - * The companded samples are encoded sign-magnitude. The table - * contains all the 256 values in the interest of speed. - */ - 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.; - step = 2.; - for (i = 3; i < OFFSET; i++) { - up->comp[i] = up->comp[i - 1] + step; - up->comp[OFFSET + i] = -up->comp[i]; - if (i % 16 == 0) - step *= 2.; - } - DTOLFP(1. / SECOND, &up->tick); - return (1); -} - - -/* - * irig_shutdown - shut down the clock - */ -static void -irig_shutdown( - int unit, /* instance number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; - - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * irig_receive - receive data from the audio device - * - * This routine reads input samples and adjusts the logical clock to - * track the irig clock by dropping or duplicating codec samples. - */ -static void -irig_receive( - struct recvbuf *rbufp /* receive buffer structure pointer */ - ) -{ - struct peer *peer; - struct refclockproc *pp; - struct irigunit *up; - - /* - * Local variables - */ - double sample; /* codec sample */ - u_char *dpt; /* buffer pointer */ - int bufcnt; /* buffer counter */ - l_fp ltemp; /* l_fp temp */ - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - - /* - * Main loop - read until there ain't no more. Note codec - * samples are bit-inverted. - */ - DTOLFP((double)rbufp->recv_length / SECOND, <emp); - L_SUB(&rbufp->recv_time, <emp); - up->timestamp = rbufp->recv_time; - dpt = rbufp->recv_buffer; - for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { - sample = up->comp[~*dpt++ & 0xff]; - - /* - * Clip noise spikes greater than MAXSIG. If no clips, - * increase the gain a tad; if the clips are too high, - * decrease a tad. - */ - if (sample > MAXSIG) { - sample = MAXSIG; - up->clipcnt++; - } else if (sample < -MAXSIG) { - sample = -MAXSIG; - up->clipcnt++; - } - - /* - * Variable frequency oscillator. The codec oscillator - * runs at the nominal rate of 8000 samples per second, - * or 125 us per sample. A frequency change of one unit - * results in either duplicating or deleting one sample - * per second, which results in a frequency change of - * 125 PPM. - */ - up->phase += up->freq / SECOND; - up->phase += pp->fudgetime2 / 1e6; - if (up->phase >= .5) { - up->phase -= 1.; - } else if (up->phase < -.5) { - up->phase += 1.; - irig_rf(peer, sample); - irig_rf(peer, sample); - } else { - irig_rf(peer, sample); - } - L_ADD(&up->timestamp, &up->tick); - - /* - * Once each second, determine the IRIG format and gain. - */ - up->seccnt = (up->seccnt + 1) % SECOND; - if (up->seccnt == 0) { - if (up->irig_b > up->irig_e) { - up->decim = 1; - up->fdelay = IRIG_B; - } else { - up->decim = 10; - up->fdelay = IRIG_E; - } - irig_gain(peer); - up->irig_b = up->irig_e = 0; - } - } - - /* - * Set the input port and monitor gain for the next buffer. - */ - if (pp->sloppyclockflag & CLK_FLAG2) - up->port = 2; - else - up->port = 1; - if (pp->sloppyclockflag & CLK_FLAG3) - up->mongain = MONGAIN; - else - up->mongain = 0; -} - -/* - * irig_rf - RF processing - * - * This routine filters the RF signal using a highpass filter for IRIG-B - * and a lowpass filter for IRIG-E. In case of IRIG-E, the samples are - * decimated by a factor of ten. The lowpass filter functions also as a - * decimation filter in this case. Note that the codec filters function - * as roofing filters to attenuate both the high and low ends of the - * passband. IIR filter coefficients were determined using Matlab Signal - * Processing Toolkit. - */ -static void -irig_rf( - struct peer *peer, /* peer structure pointer */ - double sample /* current signal sample */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; - - /* - * Local variables - */ - double irig_b, irig_e; /* irig filter outputs */ - - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - - /* - * IRIG-B filter. 4th-order elliptic, 800-Hz highpass, 0.3 dB - * passband ripple, -50 dB stopband ripple, phase delay .0022 - * s) - */ - irig_b = (up->hpf[4] = up->hpf[3]) * 2.322484e-01; - irig_b += (up->hpf[3] = up->hpf[2]) * -1.103929e+00; - irig_b += (up->hpf[2] = up->hpf[1]) * 2.351081e+00; - irig_b += (up->hpf[1] = up->hpf[0]) * -2.335036e+00; - up->hpf[0] = sample - irig_b; - irig_b = up->hpf[0] * 4.335855e-01 - + up->hpf[1] * -1.695859e+00 - + up->hpf[2] * 2.525004e+00 - + up->hpf[3] * -1.695859e+00 - + up->hpf[4] * 4.335855e-01; - up->irig_b += irig_b * irig_b; - - /* - * IRIG-E filter. 4th-order elliptic, 130-Hz lowpass, 0.3 dB - * passband ripple, -50 dB stopband ripple, phase delay .0219 s. - */ - irig_e = (up->lpf[4] = up->lpf[3]) * 8.694604e-01; - irig_e += (up->lpf[3] = up->lpf[2]) * -3.589893e+00; - irig_e += (up->lpf[2] = up->lpf[1]) * 5.570154e+00; - irig_e += (up->lpf[1] = up->lpf[0]) * -3.849667e+00; - up->lpf[0] = sample - irig_e; - irig_e = up->lpf[0] * 3.215696e-03 - + up->lpf[1] * -1.174951e-02 - + up->lpf[2] * 1.712074e-02 - + up->lpf[3] * -1.174951e-02 - + up->lpf[4] * 3.215696e-03; - up->irig_e += irig_e * irig_e; - - /* - * Decimate by a factor of either 1 (IRIG-B) or 10 (IRIG-E). - */ - up->badcnt = (up->badcnt + 1) % up->decim; - if (up->badcnt == 0) { - if (up->decim == 1) - irig_base(peer, irig_b); - else - irig_base(peer, irig_e); - } -} - -/* - * irig_base - baseband processing - * - * This routine processes the baseband signal and demodulates the AM - * carrier using a synchronous detector. It then synchronizes to the - * data frame at the baud rate and decodes the data pulses. - */ -static void -irig_base( - struct peer *peer, /* peer structure pointer */ - double sample /* current signal sample */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; - - /* - * Local variables - */ - double xxing; /* phase detector interpolated output */ - double lope; /* integrator output */ - double env; /* envelope detector output */ - double dtemp; /* double temp */ - - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - - /* - * Synchronous baud integrator. Corresponding samples of current - * and past baud intervals are integrated to refine the envelope - * amplitude and phase estimate. We keep one cycle of both the - * raw and integrated data for later use. - */ - up->envphase = (up->envphase + 1) % BAUD; - up->carphase = (up->carphase + 1) % CYCLE; - up->integ[up->envphase] += (sample - up->integ[up->envphase]) / - (5 * up->tc); - lope = up->integ[up->envphase]; - up->lastenv[up->carphase] = sample; - up->lastint[up->carphase] = lope; - - /* - * Phase detector. Sample amplitudes are integrated over the - * baud interval. Cycle phase is determined from these - * amplitudes using an eight-sample cyclic buffer. A phase - * change of 360 degrees produces an output change of one unit. - */ - if (up->lastsig > 0 && lope <= 0) { - xxing = lope / (up->lastsig - lope); - up->zxing += (up->carphase - 4 + xxing) / CYCLE; - } - up->lastsig = lope; - - /* - * Update signal/noise estimates and PLL phase/frequency. - */ - if (up->envphase == 0) { - - /* - * Update envelope signal and noise estimates and mess - * with error bits. - */ - up->maxsignal = up->intmax; - up->noise = up->intmin; - if (up->maxsignal < DRPOUT) - up->errflg |= IRIG_ERR_AMP; - if (up->maxsignal > 0) - up->modndx = (up->intmax - up->intmin) / - up->intmax; - else - up->modndx = 0; - if (up->modndx < MODMIN) - up->errflg |= IRIG_ERR_MOD; - up->intmin = 1e6; up->intmax = 0; - if (up->errflg & (IRIG_ERR_AMP | IRIG_ERR_FREQ | - IRIG_ERR_MOD | IRIG_ERR_SYNCH)) { - up->tc = MINTC; - up->tcount = 0; - } - - /* - * Update PLL phase and frequency. The PLL time constant - * is set initially to stabilize the frequency within a - * minute or two, then increases to the maximum. The - * frequency is clamped so that the PLL capture range - * cannot be exceeded. - */ - dtemp = up->zxing * up->decim / BAUD; - up->yxing = dtemp; - up->zxing = 0.; - up->phase += dtemp / up->tc; - up->freq += dtemp / (4. * up->tc * up->tc); - if (up->freq > MAXFREQ) { - up->freq = MAXFREQ; - up->errflg |= IRIG_ERR_FREQ; - } else if (up->freq < -MAXFREQ) { - up->freq = -MAXFREQ; - up->errflg |= IRIG_ERR_FREQ; - } - } - - /* - * Synchronous demodulator. There are eight samples in the cycle - * and ten cycles in the baud interval. The amplitude of each - * cycle is determined at the last sample in the cycle. The - * beginning of the data pulse is determined from the integrated - * samples, while the end of the pulse is determined from the - * raw samples. The raw data bits are demodulated relative to - * the slice level and left-shifted in the decoding register. - */ - if (up->carphase != 7) - return; - env = (up->lastenv[2] - up->lastenv[6]) / 2.; - lope = (up->lastint[2] - up->lastint[6]) / 2.; - if (lope > up->intmax) - up->intmax = lope; - if (lope < up->intmin) - up->intmin = lope; - - /* - * Pulse code demodulator and reference timestamp. The decoder - * looks for a sequence of ten bits; the first two bits must be - * one, the last two bits must be zero. Frame synch is asserted - * when three correct frames have been found. - */ - up->pulse = (up->pulse + 1) % 10; - if (up->pulse == 1) - up->envmax = env; - else if (up->pulse == 9) - up->envmin = env; - up->dcycles <<= 1; - if (env >= (up->envmax + up->envmin) / 2.) - up->dcycles |= 1; - up->cycles <<= 1; - if (lope >= (up->maxsignal + up->noise) / 2.) - up->cycles |= 1; - if ((up->cycles & 0x303c0f03) == 0x300c0300) { - l_fp ltemp; - int bitz; - - /* - * The PLL time constant starts out small, in order to - * sustain a frequency tolerance of 250 PPM. It - * gradually increases as the loop settles down. Note - * that small wiggles are not believed, unless they - * persist for lots of samples. - */ - if (up->pulse != 9) - up->errflg |= IRIG_ERR_SYNCH; - up->pulse = 9; - up->exing = -up->yxing; - if (fabs(up->envxing - up->envphase) <= 1) { - up->tcount++; - if (up->tcount > 50 * up->tc) { - up->tc++; - if (up->tc > MAXTC) - up->tc = MAXTC; - up->tcount = 0; - up->envxing = up->envphase; - } else { - up->exing -= up->envxing - up->envphase; - } - } else { - up->tcount = 0; - up->envxing = up->envphase; - } - - /* - * Determine a reference timestamp, accounting for the - * codec delay and filter delay. Note the timestamp is - * for the previous frame, so we have to backtrack for - * this plus the delay since the last carrier positive - * zero crossing. - */ - dtemp = up->decim * ((up->exing + BAUD) / SECOND + 1.) + - up->fdelay; - DTOLFP(dtemp, <emp); - pp->lastrec = up->timestamp; - L_SUB(&pp->lastrec, <emp); - - /* - * The data bits are collected in ten-bit frames. The - * first two and last two bits are determined by frame - * sync and ignored here; the resulting patterns - * represent zero (0-1 bits), one (2-4 bits) and - * position identifier (5-6 bits). The remaining - * patterns represent errors and are treated as zeros. - */ - bitz = up->dcycles & 0xfc; - switch(bitz) { - - case 0x00: - case 0x80: - irig_decode(peer, BIT0); - break; - - case 0xc0: - case 0xe0: - case 0xf0: - irig_decode(peer, BIT1); - break; - - case 0xf8: - case 0xfc: - irig_decode(peer, BITP); - break; - - default: - irig_decode(peer, 0); - up->errflg |= IRIG_ERR_DECODE; - } - } -} - - -/* - * irig_decode - decode the data - * - * This routine assembles bits into digits, digits into subfields and - * subfields into the timecode field. Bits can have values of zero, one - * or position identifier. There are four bits per digit, two digits per - * subfield and ten subfields per field. The last bit in every subfield - * and the first bit in the first subfield are position identifiers. - */ -static void -irig_decode( - struct peer *peer, /* peer structure pointer */ - int bit /* data bit (0, 1 or 2) */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; -#ifdef IRIG_SUCKS - int i; -#endif /* IRIG_SUCKS */ - - /* - * Local variables - */ - char syncchar; /* sync character (Spectracom) */ - char sbs[6]; /* binary seconds since 0h */ - char spare[2]; /* mulligan digits */ - - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - - /* - * Assemble subfield bits. - */ - up->bits <<= 1; - if (bit == BIT1) { - up->bits |= 1; - } else if (bit == BITP && up->lastbit == BITP) { - - /* - * Frame sync - two adjacent position identifiers. - * Monitor the reference timestamp and wiggle the - * clock, but only if no errors have occurred. - */ - up->bitcnt = 1; - up->fieldcnt = 0; - up->lastbit = 0; - if (up->errflg == 0) { -#ifdef IRIG_SUCKS - l_fp ltemp; - - /* - * You really don't wanna know what comes down - * here. Leave it to say Solaris 2.8 broke the - * nice clean audio stream, apparently affected - * by a 5-ms sawtooth jitter. Sundown on - * Solaris. This leaves a little twilight. - * - * The scheme involves differentiation, forward - * learning and integration. The sawtooth has a - * period of 11 seconds. The timestamp - * differences are integrated and subtracted - * from the signal. - */ - ltemp = pp->lastrec; - L_SUB(<emp, &pp->lastref); - if (ltemp.l_f < 0) - ltemp.l_i = -1; - else - ltemp.l_i = 0; - pp->lastref = pp->lastrec; - if (!L_ISNEG(<emp)) - L_CLR(&up->wigwag); - else - L_ADD(&up->wigwag, <emp); - L_SUB(&pp->lastrec, &up->wigwag); - up->wiggle[up->wp] = ltemp; - - /* - * Bottom fisher. To understand this, you have - * to know about velocity microphones and AM - * transmitters. No further explanation is - * offered, as this is truly a black art. - */ - up->wigbot[up->wp] = pp->lastrec; - for (i = 0; i < WIGGLE; i++) { - if (i != up->wp) - up->wigbot[i].l_ui++; - L_SUB(&pp->lastrec, &up->wigbot[i]); - if (L_ISNEG(&pp->lastrec)) - L_ADD(&pp->lastrec, - &up->wigbot[i]); - else - pp->lastrec = up->wigbot[i]; - } - up->wp++; - up->wp %= WIGGLE; - up->wuggle = pp->lastrec; - refclock_process(pp); -#else /* IRIG_SUCKS */ - pp->lastref = pp->lastrec; - up->wuggle = pp->lastrec; - refclock_process(pp); -#endif /* IRIG_SUCKS */ - } - up->errflg = 0; - } - up->bitcnt = (up->bitcnt + 1) % SUBFLD; - if (up->bitcnt == 0) { - - /* - * End of subfield. Encode two hexadecimal digits in - * little-endian timecode field. - */ - if (up->fieldcnt == 0) - up->bits <<= 1; - if (up->xptr < 2) - up->xptr = 2 * FIELD; - up->timecode[--up->xptr] = hexchar[(up->bits >> 5) & - 0xf]; - up->timecode[--up->xptr] = hexchar[up->bits & 0xf]; - up->fieldcnt = (up->fieldcnt + 1) % FIELD; - if (up->fieldcnt == 0) { - - /* - * End of field. Decode the timecode and wind - * the clock. Not all IRIG generators have the - * year; if so, it is nonzero after year 2000. - * Not all have the hardware status bit; if so, - * it is lit when the source is okay and dim - * when bad. We watch this only if the year is - * nonzero. Not all are configured for signature - * control. If so, all BCD digits are set to - * zero if the source is bad. In this case the - * refclock_process() will reject the timecode - * as invalid. - */ - up->xptr = 2 * FIELD; - if (sscanf((char *)up->timecode, - "%6s%2d%c%2s%3d%2d%2d%2d", sbs, &pp->year, - &syncchar, spare, &pp->day, &pp->hour, - &pp->minute, &pp->second) != 8) - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; - up->second = (up->second + up->decim) % 60; - if (pp->year > 0) { - pp->year += 2000; - if (syncchar == '0') - up->errflg |= IRIG_ERR_CHECK; - } - if (pp->second != up->second) - up->errflg |= IRIG_ERR_CHECK; - up->second = pp->second; - sprintf(pp->a_lastcode, - "%02x %c %2d %3d %02d:%02d:%02d %4.0f %3d %6.3f %2d %6.1f %6.1f %s", - up->errflg, syncchar, pp->year, pp->day, - pp->hour, pp->minute, pp->second, - up->maxsignal, up->gain, up->modndx, - up->tc, up->exing * 1e6 / SECOND, up->freq * - 1e6 / SECOND, ulfptoa(&up->wuggle, 6)); - pp->lencode = strlen(pp->a_lastcode); - if (pp->sloppyclockflag & CLK_FLAG4) { - record_clock_stats(&peer->srcadr, - pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("irig: %s\n", - pp->a_lastcode); -#endif /* DEBUG */ - } - } - } - up->lastbit = bit; -} - - -/* - * irig_poll - called by the transmit procedure - * - * This routine sweeps up the timecode updates since the last poll. For - * IRIG-B there should be at least 60 updates; for IRIG-E there should - * be at least 6. If nothing is heard, a timeout event is declared and - * any orphaned timecode updates are sent to foster care. - */ -static void -irig_poll( - int unit, /* instance number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; - - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } else { - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("irig: %s\n", pp->a_lastcode); -#endif /* DEBUG */ - } - pp->polls++; - -} - - -/* - * irig_gain - adjust codec gain - * - * This routine is called once each second. If the signal envelope - * amplitude is too low, the codec gain is bumped up by four units; if - * too high, it is bumped down. The decoder is relatively insensitive to - * amplitude, so this crudity works just fine. The input port is set and - * the error flag is cleared, mostly to be ornery. - */ -static void -irig_gain( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct irigunit *up; - - pp = peer->procptr; - up = (struct irigunit *)pp->unitptr; - - /* - * Apparently, the codec uses only the high order bits of the - * gain control field. Thus, it may take awhile for changes to - * wiggle the hardware bits. - */ - if (up->clipcnt == 0) { - up->gain += 4; - if (up->gain > MAXGAIN) - up->gain = MAXGAIN; - } else if (up->clipcnt > MAXCLP) { - up->gain -= 4; - if (up->gain < 0) - up->gain = 0; - } - audio_gain(up->gain, up->mongain, up->port); - up->clipcnt = 0; -} - -#else -int refclock_irig_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_jjy.c b/contrib/ntp/ntpd/refclock_jjy.c deleted file mode 100644 index 2aa9d6a..0000000 --- a/contrib/ntp/ntpd/refclock_jjy.c +++ /dev/null @@ -1,710 +0,0 @@ -/* - * refclock_jjy - clock driver for JJY receivers - */ - -/**********************************************************************/ -/* */ -/* Copyright (C) 2001, Takao Abe. All rights reserved. */ -/* */ -/* Permission to use, copy, modify, and distribute this software */ -/* and its documentation for any purpose is hereby granted */ -/* without fee, provided that the following conditions are met: */ -/* */ -/* One retains the entire copyright notice properly, and both the */ -/* copyright notice and this license. in the documentation and/or */ -/* other materials provided with the distribution. */ -/* */ -/* This software and the name of the author must not be used to */ -/* endorse or promote products derived from this software without */ -/* prior written permission. */ -/* */ -/* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */ -/* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */ -/* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */ -/* PARTICULAR PURPOSE. */ -/* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */ -/* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ -/* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ -/* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */ -/* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ -/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */ -/* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */ -/* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* */ -/* This driver is developed in my private time, and is opened as */ -/* voluntary contributions for the NTP. */ -/* The manufacturer of the JJY receiver has not participated in */ -/* a development of this driver. */ -/* The manufacturer does not warrant anything about this driver, */ -/* and is not liable for anything about this driver. */ -/* */ -/**********************************************************************/ -/* */ -/* Author Takao Abe */ -/* Email abetakao@bea.hi-ho.ne.jp */ -/* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */ -/* */ -/**********************************************************************/ -/* */ -/* History */ -/* */ -/* 2001/07/15 */ -/* [New] Support the Tristate Ltd. JJY receiver */ -/* */ -/* 2001/08/04 */ -/* [Change] Log to clockstats even if bad reply */ -/* [Fix] PRECISION = (-3) (about 100 ms) */ -/* [Add] Support the C-DEX Co.Ltd. JJY receiver */ -/* 2001/12/04 */ -/* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */ -/* */ -/**********************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_JJY) - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <sys/time.h> -#include <time.h> - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_tty.h" -#include "ntp_refclock.h" -#include "ntp_calendar.h" -#include "ntp_stdlib.h" - -/**********************************************************************/ -/* */ -/* The Tristate Ltd. JJY receiver JJY01 */ -/* */ -/* Command Response Remarks */ -/* ------------ ---------------------- --------------------- */ -/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */ -/* time<CR><LF> HH:MM:SS<CR><LF> */ -/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */ -/* */ -/* During synchronization after a receiver is turned on, */ -/* It replies the past time from 2000/01/01 00:00:00. */ -/* The function "refclock_process" checks the time and tells */ -/* as an insanity time. */ -/* */ -/**********************************************************************/ -/* */ -/* The C-DEX Co. Ltd. JJY receiver JST2000 */ -/* */ -/* Command Response Remarks */ -/* ------------ ---------------------- --------------------- */ -/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */ -/* */ -/**********************************************************************/ - -/* - * Interface definitions - */ -#define DEVICE "/dev/jjy%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define REFID "JJY" /* reference ID */ -#define DESCRIPTION "JJY Receiver" -#define PRECISION (-3) /* precision assumed (about 100 ms) */ - -/* - * JJY unit control structure - */ -struct jjyunit { - char unittype ; /* UNITTYPE_XXXXXXXXXX */ - short version ; - short linediscipline ; /* LDISC_CLK or LDISC_RAW */ - int linecount ; - int lineerror ; - int year, month, day, hour, minute, second, msecond ; -/* LDISC_RAW only */ -#define MAX_LINECOUNT 8 -#define MAX_RAWBUF 64 - int lineexpect ; - int charexpect [ MAX_LINECOUNT ] ; - int charcount ; - char rawbuf [ MAX_RAWBUF ] ; -}; - -#define UNITTYPE_TRISTATE_JJY01 1 -#define UNITTYPE_CDEX_JST2000 2 - -/* - * Function prototypes - */ -static int jjy_start P((int, struct peer *)); -static void jjy_shutdown P((int, struct peer *)); -static void jjy_poll P((int, struct peer *)); -static void jjy_poll_tristate_jjy01 P((int, struct peer *)); -static void jjy_poll_cdex_jst2000 P((int, struct peer *)); -static void jjy_receive P((struct recvbuf *)); -static int jjy_receive_tristate_jjy01 P((struct recvbuf *)); -static int jjy_receive_cdex_jst2000 P((struct recvbuf *)); - -/* - * Transfer vector - */ -struct refclock refclock_jjy = { - jjy_start, /* start up driver */ - jjy_shutdown, /* shutdown driver */ - jjy_poll, /* transmit poll message */ - noentry, /* not used */ - noentry, /* not used */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - -/* - * Start up driver return code - */ -#define RC_START_SUCCESS 1 -#define RC_START_ERROR 0 - -/* - * Local constants definition - */ - -#define MAX_LOGTEXT 64 - - -/**************************************************************************************************/ -/* jjy_start - open the devices and initialize data for processing */ -/**************************************************************************************************/ -static int -jjy_start ( int unit, struct peer *peer ) -{ - - struct jjyunit *up ; - struct refclockproc *pp ; - int fd ; - char *pDeviceName ; - short iDiscipline ; - -#ifdef DEBUG - if ( debug ) { - printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ; - printf ( DEVICE, unit ) ; - printf ( "\n" ) ; - } -#endif - /* - * Open serial port - */ - if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) { - return RC_START_ERROR ; - } - sprintf ( pDeviceName, DEVICE, unit ) ; - - /* - * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf - */ - switch ( peer->ttl ) { - case 0 : - case 1 : iDiscipline = LDISC_CLK ; break ; - case 2 : iDiscipline = LDISC_RAW ; break ; - default : - msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", - ntoa(&peer->srcadr), peer->ttl ) ; - free ( (void*) pDeviceName ) ; - return RC_START_ERROR ; - } - - if ( ! ( fd = refclock_open ( pDeviceName, SPEED232, iDiscipline ) ) ) { - free ( (void*) pDeviceName ) ; - return RC_START_ERROR ; - } - free ( (void*) pDeviceName ) ; - - /* - * Allocate and initialize unit structure - */ - if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) { - close ( fd ) ; - return RC_START_ERROR ; - } - - memset ( (char*)up, 0, sizeof(struct jjyunit) ) ; - up->linediscipline = iDiscipline ; - - /* - * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf - */ - switch ( peer->ttl ) { - case 0 : - /* - * The mode 0 is a default clock type at this time. - * But this will be change to auto-detect mode in the future. - */ - case 1 : - up->unittype = UNITTYPE_TRISTATE_JJY01 ; - up->version = 100 ; - up->lineexpect = 2 ; - up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */ - up->charexpect[1] = 8 ; /* HH:MM:SS<CR><LF> */ - break ; - case 2 : - up->unittype = UNITTYPE_CDEX_JST2000 ; - up->lineexpect = 1 ; - up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */ - break ; - default : - msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", - ntoa(&peer->srcadr), peer->ttl ) ; - close ( fd ) ; - free ( (void*) up ) ; - return RC_START_ERROR ; - } - - pp = peer->procptr ; - pp->unitptr = (caddr_t) up ; - pp->io.clock_recv = jjy_receive ; - pp->io.srcclock = (caddr_t) peer ; - pp->io.datalen = 0 ; - pp->io.fd = fd ; - if ( ! io_addclock(&pp->io) ) { - close ( fd ) ; - free ( (void*) up ) ; - return RC_START_ERROR ; - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION ; - peer->burst = 1 ; - pp->clockdesc = DESCRIPTION ; - memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ; - - return RC_START_SUCCESS ; - -} - - -/**************************************************************************************************/ -/* jjy_shutdown - shutdown the clock */ -/**************************************************************************************************/ -static void -jjy_shutdown ( int unit, struct peer *peer ) -{ - - struct jjyunit *up; - struct refclockproc *pp; - - pp = peer->procptr ; - up = (struct jjyunit *) pp->unitptr ; - io_closeclock ( &pp->io ) ; - free ( (void*) up ) ; - -} - - -/**************************************************************************************************/ -/* jjy_receive - receive data from the serial interface */ -/**************************************************************************************************/ -static void -jjy_receive ( struct recvbuf *rbufp ) -{ - - struct jjyunit *up ; - struct refclockproc *pp ; - struct peer *peer; - - l_fp tRecvTimestamp; /* arrival timestamp */ - int rc ; - char sLogText [ MAX_LOGTEXT ] ; - int i, bCntrlChar ; - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *) rbufp->recv_srcclock ; - pp = peer->procptr ; - up = (struct jjyunit *) pp->unitptr ; - - /* - * Get next input line - */ - pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ; - - if ( up->linediscipline == LDISC_RAW ) { - /* - * The reply with <STX> and <ETX> may give a blank line - */ - if ( pp->lencode == 0 && up->charcount == 0 ) return ; - /* - * Copy received charaters to temporary buffer - */ - for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) { - up->rawbuf[up->charcount] = pp->a_lastcode[i] ; - } - while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) { - for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ; - up->charcount -- ; - } - bCntrlChar = 0 ; - for ( i = 0 ; i < up->charcount ; i ++ ) { - if ( up->rawbuf[i] < ' ' ) { - bCntrlChar = 1 ; - break ; - } - } - if ( pp->lencode > 0 && up->linecount < up->lineexpect ) { - if ( bCntrlChar == 0 && up->charcount < up->charexpect[up->linecount] ) return ; - } - up->rawbuf[up->charcount] = 0 ; - } else { - /* - * The reply with <CR><LF> gives a blank line - */ - if ( pp->lencode == 0 ) return ; - } - /* - * We get down to business - */ - - pp->lastrec = tRecvTimestamp ; - - up->linecount ++ ; - - if ( up->lineerror != 0 ) return ; - - switch ( up->unittype ) { - - case UNITTYPE_TRISTATE_JJY01 : - rc = jjy_receive_tristate_jjy01 ( rbufp ) ; - break ; - - case UNITTYPE_CDEX_JST2000 : - rc = jjy_receive_cdex_jst2000 ( rbufp ) ; - break ; - - default : - rc = 0 ; - break ; - - } - - if ( up->linediscipline == LDISC_RAW ) { - if ( up->linecount <= up->lineexpect && up->charcount > up->charexpect[up->linecount-1] ) { - for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) { - up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ; - } - up->charcount -= up->charexpect[up->linecount-1] ; - } else { - up->charcount = 0 ; - } - } - - if ( rc == 0 ) return ; - - if ( up->lineerror != 0 ) { - refclock_report ( peer, CEVNT_BADREPLY ) ; - strcpy ( sLogText, "BAD REPLY [" ) ; - if ( up->linediscipline == LDISC_RAW ) { - strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ; - } else { - strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ; - } - sLogText[MAX_LOGTEXT-1] = 0 ; - if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ; - record_clock_stats ( &peer->srcadr, sLogText ) ; - return ; - } - - pp->year = up->year ; - pp->day = ymd2yd ( up->year, up->month, up->day ) ; - pp->hour = up->hour ; - pp->minute = up->minute ; - pp->second = up->second ; - pp->nsec = up->msecond * 1000000; - - /* - * JST to UTC - */ - pp->hour -= 9 ; - if ( pp->hour < 0 ) { - pp->hour += 24 ; - pp->day -- ; - if ( pp->day < 1 ) { - pp->year -- ; - pp->day = ymd2yd ( pp->year, 12, 31 ) ; - } - } -#ifdef DEBUG - if ( debug ) { - printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d JST ", - up->year, up->month, up->day, up->hour, up->minute, up->second ) ; - printf ( "( %04d/%03d %02d:%02d:%02d UTC )\n", - pp->year, pp->day, pp->hour, pp->minute, pp->second ) ; - } -#endif - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if ( ! refclock_process ( pp ) ) { - refclock_report(peer, CEVNT_BADTIME); - sprintf ( sLogText, "BAD TIME %04d/%02d/%02d %02d:%02d:%02d JST", - up->year, up->month, up->day, up->hour, up->minute, up->second ) ; - record_clock_stats ( &peer->srcadr, sLogText ) ; - return ; - } - - sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d JST", - up->year, up->month, up->day, up->hour, up->minute, up->second ) ; - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats ( &peer->srcadr, sLogText ) ; -} - -/**************************************************************************************************/ - -static int -jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp ) -{ - - struct jjyunit *up ; - struct refclockproc *pp ; - struct peer *peer; - - char *pBuf ; - int iLen ; - int rc ; - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *) rbufp->recv_srcclock ; - pp = peer->procptr ; - up = (struct jjyunit *) pp->unitptr ; - - if ( up->linediscipline == LDISC_RAW ) { - pBuf = up->rawbuf ; - iLen = up->charcount ; - } else { - pBuf = pp->a_lastcode ; - iLen = pp->lencode ; - } - - switch ( up->linecount ) { - - case 1 : /* YYYY/MM/DD */ - - if ( iLen < 10 ) { - up->lineerror = 1 ; - break ; - } - rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ; - if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) { - up->lineerror = 1 ; - break ; - } - return 0 ; - - case 2 : /* HH:MM:SS */ - - if ( iLen < 8 ) { - up->lineerror = 1 ; - break ; - } - rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ; - if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { - up->lineerror = 1 ; - break ; - } - up->msecond = 0 ; - if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) { - /* - * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously. - * But the JJY receiver replies a date and time separately. - * Just after midnight transtions, we ignore this time. - */ - return 0 ; - } - break ; - - default : /* Unexpected reply */ - - up->lineerror = 1 ; - break ; - - } - - return 1 ; - -} - -/**************************************************************************************************/ - -static int -jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp ) -{ - - struct jjyunit *up ; - struct refclockproc *pp ; - struct peer *peer; - - char *pBuf ; - int iLen ; - int rc ; - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *) rbufp->recv_srcclock ; - pp = peer->procptr ; - up = (struct jjyunit *) pp->unitptr ; - - if ( up->linediscipline == LDISC_RAW ) { - pBuf = up->rawbuf ; - iLen = up->charcount ; - } else { - pBuf = pp->a_lastcode ; - iLen = pp->lencode ; - } - - switch ( up->linecount ) { - - case 1 : /* JYYMMDD HHMMSSS */ - - if ( iLen < 15 ) { - up->lineerror = 1 ; - break ; - } - rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d", - &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ; - if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 - || up->hour > 23 || up->minute > 59 || up->second > 60 ) { - up->lineerror = 1 ; - break ; - } - up->year += 2000 ; - up->msecond *= 100 ; - break ; - - default : /* Unexpected reply */ - - up->lineerror = 1 ; - break ; - - } - - return 1 ; - -} - -/**************************************************************************************************/ -/* jjy_poll - called by the transmit procedure */ -/**************************************************************************************************/ -static void -jjy_poll ( int unit, struct peer *peer ) -{ - - struct jjyunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct jjyunit *) pp->unitptr ; - - if ( pp->polls > 0 && up->linecount == 0 ) { - /* - * No reply for last command - */ - refclock_report ( peer, CEVNT_TIMEOUT ) ; - } - -#ifdef DEBUG - if ( debug ) { - printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ; - } -#endif - - pp->polls ++ ; - - up->linecount = 0 ; - up->lineerror = 0 ; - up->charcount = 0 ; - - switch ( up->unittype ) { - - case UNITTYPE_TRISTATE_JJY01 : - jjy_poll_tristate_jjy01 ( unit, peer ) ; - break ; - - case UNITTYPE_CDEX_JST2000 : - jjy_poll_cdex_jst2000 ( unit, peer ) ; - break ; - - default : - break ; - - } - -} - -/**************************************************************************************************/ - -static void -jjy_poll_tristate_jjy01 ( int unit, struct peer *peer ) -{ - - struct jjyunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct jjyunit *) pp->unitptr ; - - /* - * Send "date<CR><LF>" command - */ - - if ( write ( pp->io.fd, "date\r\n",6 ) != 6 ) { - refclock_report ( peer, CEVNT_FAULT ) ; - } - - /* - * Send "stim<CR><LF>" or "time<CR><LF>" command - */ - - if ( up->version >= 100 ) { - if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) { - refclock_report ( peer, CEVNT_FAULT ) ; - } - } else { - if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) { - refclock_report ( peer, CEVNT_FAULT ) ; - } - } - -} - -/**************************************************************************************************/ - -static void -jjy_poll_cdex_jst2000 ( int unit, struct peer *peer ) -{ - - struct refclockproc *pp; - - pp = peer->procptr; - - /* - * Send "<ENQ>1J<ETX>" command - */ - - if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) { - refclock_report ( peer, CEVNT_FAULT ) ; - } - -} - -#else -int refclock_jjy_bs ; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_jupiter.c b/contrib/ntp/ntpd/refclock_jupiter.c deleted file mode 100644 index eff088b..0000000 --- a/contrib/ntp/ntpd/refclock_jupiter.c +++ /dev/null @@ -1,1140 +0,0 @@ -/* - * Copyright (c) 1997, 1998, 2003 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory. - * 4. The name of the University may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_unixtime.h" -#include "ntp_stdlib.h" - -#include <stdio.h> -#include <ctype.h> - -#include "jupiter.h" - -#ifdef HAVE_PPSAPI -# ifdef HAVE_TIMEPPS_H -# include <timepps.h> -# else -# ifdef HAVE_SYS_TIMEPPS_H -# include <sys/timepps.h> -# endif -# endif -#endif - -#ifdef XNTP_BIG_ENDIAN -#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) -#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) -#else -#define getshort(s) (s) -#define putshort(s) (s) -#endif - -/* XXX */ -#ifdef sun -char *strerror(int); -#endif - -/* - * This driver supports the Rockwell Jupiter GPS Receiver board - * adapted to precision timing applications. It requires the - * ppsclock line discipline or streams module described in the - * Line Disciplines and Streams Drivers page. It also requires a - * gadget box and 1-PPS level converter, such as described in the - * Pulse-per-second (PPS) Signal Interfacing page. - * - * It may work (with minor modifications) with other Rockwell GPS - * receivers such as the CityTracker. - */ - -/* - * GPS Definitions - */ -#define DEVICE "/dev/gps%d" /* device name and unit */ -#define SPEED232 B9600 /* baud */ - -/* - * Radio interface parameters - */ -#define PRECISION (-18) /* precision assumed (about 4 us) */ -#define REFID "GPS\0" /* reference id */ -#define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ -#define DEFFUDGETIME 0 /* default fudge time (ms) */ - -/* Unix timestamp for the GPS epoch: January 6, 1980 */ -#define GPS_EPOCH 315964800 - -/* Double short to unsigned int */ -#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) - -/* Double short to signed int */ -#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) - -/* One week's worth of seconds */ -#define WEEKSECS (7 * 24 * 60 * 60) - -/* - * Jupiter unit control structure. - */ -struct instance { - struct peer *peer; /* peer */ - u_int pollcnt; /* poll message counter */ - u_int polled; /* Hand in a time sample? */ -#ifdef HAVE_PPSAPI - pps_params_t pps_params; /* pps parameters */ - pps_info_t pps_info; /* last pps data */ - pps_handle_t pps_handle; /* pps handle */ - u_int assert; /* pps edge to use */ - struct timespec ts; /* last timestamp */ -#endif - l_fp limit; - u_int gpos_gweek; /* Current GPOS GPS week number */ - u_int gpos_sweek; /* Current GPOS GPS seconds into week */ - u_int gweek; /* current GPS week number */ - u_int32 lastsweek; /* last seconds into GPS week */ - time_t timecode; /* current ntp timecode */ - u_int32 stime; /* used to detect firmware bug */ - int wantid; /* don't reconfig on channel id msg */ - u_int moving; /* mobile platform? */ - u_char sloppyclockflag; /* fudge flags */ - u_short sbuf[512]; /* local input buffer */ - int ssize; /* space used in sbuf */ -}; - -/* - * Function prototypes - */ -static void jupiter_canmsg P((struct instance *, u_int)); -static u_short jupiter_cksum P((u_short *, u_int)); -static int jupiter_config P((struct instance *)); -static void jupiter_debug P((struct peer *, char *, char *, ...)) - __attribute__ ((format (printf, 3, 4))); -static char * jupiter_parse_t P((struct instance *, u_short *)); -static char * jupiter_parse_gpos P((struct instance *, u_short *)); -static void jupiter_platform P((struct instance *, u_int)); -static void jupiter_poll P((int, struct peer *)); -static void jupiter_control P((int, struct refclockstat *, struct - refclockstat *, struct peer *)); -#ifdef HAVE_PPSAPI -static int jupiter_ppsapi P((struct instance *, int, int)); -static int jupiter_pps P((struct instance *)); -#endif /* HAVE_PPSAPI */ -static int jupiter_recv P((struct instance *)); -static void jupiter_receive P((struct recvbuf *rbufp)); -static void jupiter_reqmsg P((struct instance *, u_int, u_int)); -static void jupiter_reqonemsg P((struct instance *, u_int)); -static char * jupiter_send P((struct instance *, struct jheader *)); -static void jupiter_shutdown P((int, struct peer *)); -static int jupiter_start P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_jupiter = { - jupiter_start, /* start up driver */ - jupiter_shutdown, /* shut down driver */ - jupiter_poll, /* transmit poll message */ - jupiter_control, /* (clock control) */ - noentry, /* (clock init) */ - noentry, /* (clock buginfo) */ - NOFLAGS /* not used */ -}; - -/* - * jupiter_start - open the devices and initialize data for processing - */ -static int -jupiter_start( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - struct instance *instance; - int fd = -1; - char gpsdev[20]; - - /* - * Open serial port - */ - (void)sprintf(gpsdev, DEVICE, unit); - fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); - if (fd == 0) { - jupiter_debug(peer, "jupiter_start", "open %s: %s", - gpsdev, strerror(errno)); - return (0); - } - - /* Allocate unit structure */ - if ((instance = (struct instance *) - emalloc(sizeof(struct instance))) == NULL) { - (void) close(fd); - return (0); - } - memset((char *)instance, 0, sizeof(struct instance)); - instance->peer = peer; - pp = peer->procptr; - pp->io.clock_recv = jupiter_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(instance); - return (0); - } - pp->unitptr = (caddr_t)instance; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - -#ifdef HAVE_PPSAPI - /* - * Start the PPSAPI interface if it is there. Default to use - * the assert edge and do not enable the kernel hardpps. - */ - if (time_pps_create(fd, &instance->pps_handle) < 0) { - instance->pps_handle = 0; - msyslog(LOG_ERR, - "refclock_jupiter: time_pps_create failed: %m"); - } - else if (!jupiter_ppsapi(instance, 0, 0)) - goto clean_up; -#endif /* HAVE_PPSAPI */ - - /* Ensure the receiver is properly configured */ - if (!jupiter_config(instance)) - goto clean_up; - - return (1); - -clean_up: - jupiter_shutdown(unit, peer); - pp->unitptr = 0; - return (0); -} - -/* - * jupiter_shutdown - shut down the clock - */ -static void -jupiter_shutdown(int unit, struct peer *peer) -{ - struct instance *instance; - struct refclockproc *pp; - - pp = peer->procptr; - instance = (struct instance *)pp->unitptr; - if(!instance) - return; - -#ifdef HAVE_PPSAPI - if (instance->pps_handle) { - time_pps_destroy(instance->pps_handle); - instance->pps_handle = 0; - } -#endif /* HAVE_PPSAPI */ - - io_closeclock(&pp->io); - free(instance); -} - -/* - * jupiter_config - Configure the receiver - */ -static int -jupiter_config(struct instance *instance) -{ - jupiter_debug(instance->peer, "jupiter_config", "init receiver"); - - /* - * Initialize the unit variables - */ - instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; - instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); - if (instance->moving) - jupiter_debug(instance->peer, "jupiter_config", - "mobile platform"); - - instance->pollcnt = 2; - instance->polled = 0; - instance->gpos_gweek = 0; - instance->gpos_sweek = 0; - instance->gweek = 0; - instance->lastsweek = 2 * WEEKSECS; - instance->timecode = 0; - instance->stime = 0; - instance->ssize = 0; - - /* Stop outputting all messages */ - jupiter_canmsg(instance, JUPITER_ALL); - - /* Request the receiver id so we can syslog the firmware version */ - jupiter_reqonemsg(instance, JUPITER_O_ID); - - /* Flag that this the id was requested (so we don't get called again) */ - instance->wantid = 1; - - /* Request perodic time mark pulse messages */ - jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); - - /* Request perodic geodetic position status */ - jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); - - /* Set application platform type */ - if (instance->moving) - jupiter_platform(instance, JUPITER_I_PLAT_MED); - else - jupiter_platform(instance, JUPITER_I_PLAT_LOW); - - return (1); -} - -#ifdef HAVE_PPSAPI -/* - * Initialize PPSAPI - */ -int -jupiter_ppsapi( - struct instance *instance, /* unit structure pointer */ - int enb_clear, /* clear enable */ - int enb_hardpps /* hardpps enable */ - ) -{ - int capability; - - if (time_pps_getcap(instance->pps_handle, &capability) < 0) { - msyslog(LOG_ERR, - "refclock_jupiter: time_pps_getcap failed: %m"); - return (0); - } - memset(&instance->pps_params, 0, sizeof(pps_params_t)); - if (enb_clear) - instance->pps_params.mode = capability & PPS_CAPTURECLEAR; - else - instance->pps_params.mode = capability & PPS_CAPTUREASSERT; - if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { - msyslog(LOG_ERR, - "refclock_jupiter: invalid capture edge %d", - !enb_clear); - return (0); - } - instance->pps_params.mode |= PPS_TSFMT_TSPEC; - if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { - msyslog(LOG_ERR, - "refclock_jupiter: time_pps_setparams failed: %m"); - return (0); - } - if (enb_hardpps) { - if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, - instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR), - PPS_TSFMT_TSPEC) < 0) { - msyslog(LOG_ERR, - "refclock_jupiter: time_pps_kcbind failed: %m"); - return (0); - } - pps_enable = 1; - } -/* instance->peer->precision = PPS_PRECISION; */ - -#if DEBUG - if (debug) { - time_pps_getparams(instance->pps_handle, &instance->pps_params); - jupiter_debug(instance->peer, "refclock_jupiter", - "pps capability 0x%x version %d mode 0x%x kern %d", - capability, instance->pps_params.api_version, - instance->pps_params.mode, enb_hardpps); - } -#endif - - return (1); -} - -/* - * Get PPSAPI timestamps. - * - * Return 0 on failure and 1 on success. - */ -static int -jupiter_pps(struct instance *instance) -{ - pps_info_t pps_info; - struct timespec timeout, ts; - double dtemp; - l_fp tstmp; - - /* - * Convert the timespec nanoseconds field to ntp l_fp units. - */ - if (instance->pps_handle == 0) - return 1; - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); - if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, - &timeout) < 0) - return 1; - if (instance->pps_params.mode & PPS_CAPTUREASSERT) { - if (pps_info.assert_sequence == - instance->pps_info.assert_sequence) - return 1; - ts = instance->pps_info.assert_timestamp; - } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { - if (pps_info.clear_sequence == - instance->pps_info.clear_sequence) - return 1; - ts = instance->pps_info.clear_timestamp; - } else { - return 1; - } - if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) - return 1; - instance->ts = ts; - - tstmp.l_ui = ts.tv_sec + JAN_1970; - dtemp = ts.tv_nsec * FRAC / 1e9; - tstmp.l_uf = (u_int32)dtemp; - instance->peer->procptr->lastrec = tstmp; - return 0; -} -#endif /* HAVE_PPSAPI */ - -/* - * jupiter_poll - jupiter watchdog routine - */ -static void -jupiter_poll(int unit, struct peer *peer) -{ - struct instance *instance; - struct refclockproc *pp; - - pp = peer->procptr; - instance = (struct instance *)pp->unitptr; - - /* - * You don't need to poll this clock. It puts out timecodes - * once per second. If asked for a timestamp, take note. - * The next time a timecode comes in, it will be fed back. - */ - - /* - * If we haven't had a response in a while, reset the receiver. - */ - if (instance->pollcnt > 0) { - instance->pollcnt--; - } else { - refclock_report(peer, CEVNT_TIMEOUT); - - /* Request the receiver id to trigger a reconfig */ - jupiter_reqonemsg(instance, JUPITER_O_ID); - instance->wantid = 0; - } - - /* - * polled every 64 seconds. Ask jupiter_receive to hand in - * a timestamp. - */ - instance->polled = 1; - pp->polls++; -} - -/* - * jupiter_control - fudge control - */ -static void -jupiter_control( - int unit, /* unit (not used) */ - struct refclockstat *in, /* input parameters (not used) */ - struct refclockstat *out, /* output parameters (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct instance *instance; - u_char sloppyclockflag; - - pp = peer->procptr; - instance = (struct instance *)pp->unitptr; - - DTOLFP(pp->fudgetime2, &instance->limit); - /* Force positive value. */ - if (L_ISNEG(&instance->limit)) - L_NEG(&instance->limit); - -#ifdef HAVE_PPSAPI - instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); - jupiter_ppsapi(instance, !instance->assert, 0); -#endif /* HAVE_PPSAPI */ - - sloppyclockflag = instance->sloppyclockflag; - instance->sloppyclockflag = pp->sloppyclockflag; - if ((instance->sloppyclockflag & CLK_FLAG2) != - (sloppyclockflag & CLK_FLAG2)) { - jupiter_debug(peer, - "jupiter_control", - "mode switch: reset receiver"); - jupiter_config(instance); - return; - } -} - -/* - * jupiter_receive - receive gps data - * Gag me! - */ -static void -jupiter_receive(struct recvbuf *rbufp) -{ - int bpcnt, cc, size, ppsret; - time_t last_timecode; - u_int32 laststime; - char *cp; - u_char *bp; - u_short *sp; - struct jid *ip; - struct jheader *hp; - struct peer *peer; - struct refclockproc *pp; - struct instance *instance; - l_fp tstamp; - - /* Initialize pointers and read the timecode and timestamp */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - instance = (struct instance *)pp->unitptr; - - bp = (u_char *)rbufp->recv_buffer; - bpcnt = rbufp->recv_length; - - /* This shouldn't happen */ - if (bpcnt > sizeof(instance->sbuf) - instance->ssize) - bpcnt = sizeof(instance->sbuf) - instance->ssize; - - /* Append to input buffer */ - memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); - instance->ssize += bpcnt; - - /* While there's at least a header and we parse an intact message */ - while (instance->ssize > sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) { - instance->pollcnt = 2; - - tstamp = rbufp->recv_time; - hp = (struct jheader *)instance->sbuf; - sp = (u_short *)(hp + 1); - size = cc - sizeof(*hp); - switch (getshort(hp->id)) { - - case JUPITER_O_PULSE: - if (size != sizeof(struct jpulse)) { - jupiter_debug(peer, - "jupiter_receive", "pulse: len %d != %u", - size, (int)sizeof(struct jpulse)); - refclock_report(peer, CEVNT_BADREPLY); - break; - } - - /* - * There appears to be a firmware bug related - * to the pulse message; in addition to the one - * per second messages, we get an extra pulse - * message once an hour (on the anniversary of - * the cold start). It seems to come 200 ms - * after the one requested. So if we've seen a - * pulse message in the last 210 ms, we skip - * this one. - */ - laststime = instance->stime; - instance->stime = DS2UI(((struct jpulse *)sp)->stime); - if (laststime != 0 && instance->stime - laststime <= 21) { - jupiter_debug(peer, "jupiter_receive", - "avoided firmware bug (stime %.2f, laststime %.2f)", - (double)instance->stime * 0.01, (double)laststime * 0.01); - break; - } - - /* Retrieve pps timestamp */ - ppsret = jupiter_pps(instance); - - /* - * Add one second if msg received early - * (i.e. before limit, a.k.a. fudgetime2) in - * the second. - */ - L_SUB(&tstamp, &pp->lastrec); - if (!L_ISGEQ(&tstamp, &instance->limit)) - ++pp->lastrec.l_ui; - - /* Parse timecode (even when there's no pps) */ - last_timecode = instance->timecode; - if ((cp = jupiter_parse_t(instance, sp)) != NULL) { - jupiter_debug(peer, - "jupiter_receive", "pulse: %s", cp); - break; - } - - /* Bail if we didn't get a pps timestamp */ - if (ppsret) - break; - - /* Bail if we don't have the last timecode yet */ - if (last_timecode == 0) - break; - - /* Add the new sample to a median filter */ - tstamp.l_ui = JAN_1970 + last_timecode; - tstamp.l_uf = 0; - - refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1); - - /* - * The clock will blurt a timecode every second - * but we only want one when polled. If we - * havn't been polled, bail out. - */ - if (!instance->polled) - break; - instance->polled = 0; - - /* - * It's a live one! Remember this time. - */ - - pp->lastref = pp->lastrec; - refclock_receive(peer); - - /* - * If we get here - what we got from the clock is - * OK, so say so - */ - refclock_report(peer, CEVNT_NOMINAL); - - /* - * We have succeeded in answering the poll. - * Turn off the flag and return - */ - instance->polled = 0; - break; - - case JUPITER_O_GPOS: - if (size != sizeof(struct jgpos)) { - jupiter_debug(peer, - "jupiter_receive", "gpos: len %d != %u", - size, (int)sizeof(struct jgpos)); - refclock_report(peer, CEVNT_BADREPLY); - break; - } - - if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) { - jupiter_debug(peer, - "jupiter_receive", "gpos: %s", cp); - break; - } - break; - - case JUPITER_O_ID: - if (size != sizeof(struct jid)) { - jupiter_debug(peer, - "jupiter_receive", "id: len %d != %u", - size, (int)sizeof(struct jid)); - refclock_report(peer, CEVNT_BADREPLY); - break; - } - /* - * If we got this message because the Jupiter - * just powered instance, it needs to be reconfigured. - */ - ip = (struct jid *)sp; - jupiter_debug(peer, - "jupiter_receive", "%s chan ver %s, %s (%s)", - ip->chans, ip->vers, ip->date, ip->opts); - msyslog(LOG_DEBUG, - "jupiter_receive: %s chan ver %s, %s (%s)\n", - ip->chans, ip->vers, ip->date, ip->opts); - if (instance->wantid) - instance->wantid = 0; - else { - jupiter_debug(peer, - "jupiter_receive", "reset receiver"); - jupiter_config(instance); - /* - * Restore since jupiter_config() just - * zeroed it - */ - instance->ssize = cc; - } - break; - - default: - jupiter_debug(peer, - "jupiter_receive", "unknown message id %d", - getshort(hp->id)); - break; - } - instance->ssize -= cc; - if (instance->ssize < 0) { - fprintf(stderr, "jupiter_recv: negative ssize!\n"); - abort(); - } else if (instance->ssize > 0) - memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize); - } -} - -static char * -jupiter_parse_t(struct instance *instance, u_short *sp) -{ - struct tm *tm; - char *cp; - struct jpulse *jp; - u_int32 sweek; - time_t last_timecode; - u_short flags; - - jp = (struct jpulse *)sp; - - /* The timecode is presented as seconds into the current GPS week */ - sweek = DS2UI(jp->sweek) % WEEKSECS; - - /* - * If we don't know the current GPS week, calculate it from the - * current time. (It's too bad they didn't include this - * important value in the pulse message). We'd like to pick it - * up from one of the other messages like gpos or chan but they - * don't appear to be synchronous with time keeping and changes - * too soon (something like 10 seconds before the new GPS - * week). - * - * If we already know the current GPS week, increment it when - * we wrap into a new week. - */ - if (instance->gweek == 0) { - if (!instance->gpos_gweek) { - return ("jupiter_parse_t: Unknown gweek"); - } - - instance->gweek = instance->gpos_gweek; - - /* - * Fix warps. GPOS has GPS time and PULSE has UTC. - * Plus, GPOS need not be completely in synch with - * the PPS signal. - */ - if (instance->gpos_sweek >= sweek) { - if ((instance->gpos_sweek - sweek) > WEEKSECS / 2) - ++instance->gweek; - } - else { - if ((sweek - instance->gpos_sweek) > WEEKSECS / 2) - --instance->gweek; - } - } - else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) { - ++instance->gweek; - jupiter_debug(instance->peer, - "jupiter_parse_t", "NEW gps week %u", instance->gweek); - } - - /* - * See if the sweek stayed the same (this happens when there is - * no pps pulse). - * - * Otherwise, look for time warps: - * - * - we have stored at least one lastsweek and - * - the sweek didn't increase by one and - * - we didn't wrap to a new GPS week - * - * Then we warped. - */ - if (instance->lastsweek == sweek) - jupiter_debug(instance->peer, - "jupiter_parse_t", "gps sweek not incrementing (%d)", - sweek); - else if (instance->lastsweek != 2 * WEEKSECS && - instance->lastsweek + 1 != sweek && - !(sweek == 0 && instance->lastsweek == WEEKSECS - 1)) - jupiter_debug(instance->peer, - "jupiter_parse_t", "gps sweek jumped (was %d, now %d)", - instance->lastsweek, sweek); - instance->lastsweek = sweek; - - /* This timecode describes next pulse */ - last_timecode = instance->timecode; - instance->timecode = - GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek; - - if (last_timecode == 0) - /* XXX debugging */ - jupiter_debug(instance->peer, - "jupiter_parse_t", "UTC <none> (gweek/sweek %u/%u)", - instance->gweek, sweek); - else { - /* XXX debugging */ - tm = gmtime(&last_timecode); - cp = asctime(tm); - - jupiter_debug(instance->peer, - "jupiter_parse_t", "UTC %.24s (gweek/sweek %u/%u)", - cp, instance->gweek, sweek); - - /* Billboard last_timecode (which is now the current time) */ - instance->peer->procptr->year = tm->tm_year + 1900; - instance->peer->procptr->day = tm->tm_yday + 1; - instance->peer->procptr->hour = tm->tm_hour; - instance->peer->procptr->minute = tm->tm_min; - instance->peer->procptr->second = tm->tm_sec; - } - - flags = getshort(jp->flags); - - /* Toss if not designated "valid" by the gps */ - if ((flags & JUPITER_O_PULSE_VALID) == 0) { - refclock_report(instance->peer, CEVNT_BADTIME); - return ("time mark not valid"); - } - - /* We better be sync'ed to UTC... */ - if ((flags & JUPITER_O_PULSE_UTC) == 0) { - refclock_report(instance->peer, CEVNT_BADTIME); - return ("time mark not sync'ed to UTC"); - } - - return (NULL); -} - -static char * -jupiter_parse_gpos(struct instance *instance, u_short *sp) -{ - struct jgpos *jg; - time_t t; - struct tm *tm; - char *cp; - - jg = (struct jgpos *)sp; - - if (jg->navval != 0) { - /* - * Solution not valid. Use caution and refuse - * to determine GPS week from this message. - */ - instance->gpos_gweek = 0; - instance->gpos_sweek = 0; - return ("Navigation solution not valid"); - } - - instance->gpos_gweek = jg->gweek; - instance->gpos_sweek = DS2UI(jg->sweek); - while(instance->gpos_sweek >= WEEKSECS) { - instance->gpos_sweek -= WEEKSECS; - ++instance->gpos_gweek; - } - instance->gweek = 0; - - t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek; - tm = gmtime(&t); - cp = asctime(tm); - - jupiter_debug(instance->peer, - "jupiter_parse_g", "GPS %.24s (gweek/sweek %u/%u)", - cp, instance->gpos_gweek, instance->gpos_sweek); - return (NULL); -} - -/* - * jupiter_debug - print debug messages - */ -#if defined(__STDC__) || defined(SYS_WINNT) -static void -jupiter_debug(struct peer *peer, char *function, char *fmt, ...) -#else -static void -jupiter_debug(peer, function, fmt, va_alist) - struct peer *peer; - char *function; - char *fmt; -#endif /* __STDC__ */ -{ - char buffer[200]; - va_list ap; - -#if defined(__STDC__) || defined(SYS_WINNT) - va_start(ap, fmt); -#else - va_start(ap); -#endif /* __STDC__ */ - /* - * Print debug message to stdout - * In the future, we may want to get get more creative... - */ - vsnprintf(buffer, sizeof(buffer), fmt, ap); - record_clock_stats(&(peer->srcadr), buffer); - if (debug) { - fprintf(stdout, "%s: ", function); - fprintf(stdout, buffer); - fprintf(stdout, "\n"); - fflush(stdout); - } - - va_end(ap); -} - -/* Checksum and transmit a message to the Jupiter */ -static char * -jupiter_send(struct instance *instance, struct jheader *hp) -{ - u_int len, size; - int cc; - u_short *sp; - static char errstr[132]; - - size = sizeof(*hp); - hp->hsum = putshort(jupiter_cksum((u_short *)hp, - (size / sizeof(u_short)) - 1)); - len = getshort(hp->len); - if (len > 0) { - sp = (u_short *)(hp + 1); - sp[len] = putshort(jupiter_cksum(sp, len)); - size += (len + 1) * sizeof(u_short); - } - - if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { - (void)sprintf(errstr, "write: %s", strerror(errno)); - return (errstr); - } else if (cc != size) { - (void)sprintf(errstr, "short write (%d != %d)", cc, size); - return (errstr); - } - return (NULL); -} - -/* Request periodic message output */ -static struct { - struct jheader jheader; - struct jrequest jrequest; -} reqmsg = { - { putshort(JUPITER_SYNC), 0, - putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), - 0, (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | - JUPITER_FLAG_CONN | JUPITER_FLAG_LOG), 0 }, - { 0, 0, 0, 0 } -}; - -/* An interval of zero means to output on trigger */ -static void -jupiter_reqmsg(struct instance *instance, u_int id, - u_int interval) -{ - struct jheader *hp; - struct jrequest *rp; - char *cp; - - hp = &reqmsg.jheader; - hp->id = putshort(id); - rp = &reqmsg.jrequest; - rp->trigger = putshort(interval == 0); - rp->interval = putshort(interval); - if ((cp = jupiter_send(instance, hp)) != NULL) - jupiter_debug(instance->peer, "jupiter_reqmsg", "%u: %s", id, cp); -} - -/* Cancel periodic message output */ -static struct jheader canmsg = { - putshort(JUPITER_SYNC), 0, 0, 0, - (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC), - 0 -}; - -static void -jupiter_canmsg(struct instance *instance, u_int id) -{ - struct jheader *hp; - char *cp; - - hp = &canmsg; - hp->id = putshort(id); - if ((cp = jupiter_send(instance, hp)) != NULL) - jupiter_debug(instance->peer, "jupiter_canmsg", "%u: %s", id, cp); -} - -/* Request a single message output */ -static struct jheader reqonemsg = { - putshort(JUPITER_SYNC), 0, 0, 0, - (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY), - 0 -}; - -static void -jupiter_reqonemsg(struct instance *instance, u_int id) -{ - struct jheader *hp; - char *cp; - - hp = &reqonemsg; - hp->id = putshort(id); - if ((cp = jupiter_send(instance, hp)) != NULL) - jupiter_debug(instance->peer, "jupiter_reqonemsg", "%u: %s", id, cp); -} - -/* Set the platform dynamics */ -static struct { - struct jheader jheader; - struct jplat jplat; -} platmsg = { - { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), - putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, - (u_char)putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 }, - { 0, 0, 0 } -}; - -static void -jupiter_platform(struct instance *instance, u_int platform) -{ - struct jheader *hp; - struct jplat *pp; - char *cp; - - hp = &platmsg.jheader; - pp = &platmsg.jplat; - pp->platform = putshort(platform); - if ((cp = jupiter_send(instance, hp)) != NULL) - jupiter_debug(instance->peer, "jupiter_platform", "%u: %s", platform, cp); -} - -/* Checksum "len" shorts */ -static u_short -jupiter_cksum(u_short *sp, u_int len) -{ - u_short sum, x; - - sum = 0; - while (len-- > 0) { - x = *sp++; - sum += getshort(x); - } - return (~sum + 1); -} - -/* Return the size of the next message (or zero if we don't have it all yet) */ -static int -jupiter_recv(struct instance *instance) -{ - int n, len, size, cc; - struct jheader *hp; - u_char *bp; - u_short *sp; - - /* Must have at least a header's worth */ - cc = sizeof(*hp); - size = instance->ssize; - if (size < cc) - return (0); - - /* Search for the sync short if missing */ - sp = instance->sbuf; - hp = (struct jheader *)sp; - if (getshort(hp->sync) != JUPITER_SYNC) { - /* Wasn't at the front, sync up */ - jupiter_debug(instance->peer, "jupiter_recv", "syncing"); - bp = (u_char *)sp; - n = size; - while (n >= 2) { - if (bp[0] != (JUPITER_SYNC & 0xff)) { - /* - jupiter_debug(instance->peer, "{0x%x}", bp[0]); - */ - ++bp; - --n; - continue; - } - if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) - break; - /* - jupiter_debug(instance->peer, "{0x%x 0x%x}", bp[0], bp[1]); - */ - bp += 2; - n -= 2; - } - /* - jupiter_debug(instance->peer, "\n"); - */ - /* Shuffle data to front of input buffer */ - if (n > 0) - memcpy(sp, bp, n); - size = n; - instance->ssize = size; - if (size < cc || hp->sync != JUPITER_SYNC) - return (0); - } - - if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != - getshort(hp->hsum)) { - jupiter_debug(instance->peer, "jupiter_recv", "bad header checksum!"); - /* This is drastic but checksum errors should be rare */ - instance->ssize = 0; - return (0); - } - - /* Check for a payload */ - len = getshort(hp->len); - if (len > 0) { - n = (len + 1) * sizeof(u_short); - /* Not enough data yet */ - if (size < cc + n) - return (0); - - /* Check payload checksum */ - sp = (u_short *)(hp + 1); - if (jupiter_cksum(sp, len) != getshort(sp[len])) { - jupiter_debug(instance->peer, - "jupiter_recv", "bad payload checksum!"); - /* This is drastic but checksum errors should be rare */ - instance->ssize = 0; - return (0); - } - cc += n; - } - return (cc); -} - -#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ -int refclock_jupiter_bs; -#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ diff --git a/contrib/ntp/ntpd/refclock_leitch.c b/contrib/ntp/ntpd/refclock_leitch.c deleted file mode 100644 index d7cd9bb..0000000 --- a/contrib/ntp/ntpd/refclock_leitch.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_LEITCH) - -#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) -#include <sys/clkdefs.h> -#endif /* LEITCHCLK */ -#endif /* STREAM */ - -#include "ntp_stdlib.h" - - -/* - * Driver for Leitch CSD-5300 Master Clock System - * - * COMMANDS: - * DATE: D <CR> - * TIME: T <CR> - * STATUS: S <CR> - * LOOP: L <CR> - * - * FORMAT: - * DATE: YYMMDD<CR> - * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/ - * second bondaried on the stop bit of the <CR> - * second boundaries at '/' above. - * STATUS: G (good), D (diag fail), T (time not provided) or - * P (last phone update failed) - */ -#define MAXUNITS 1 /* max number of LEITCH units */ -#define LEITCHREFID "ATOM" /* reference id */ -#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver" -#define LEITCH232 "/dev/leitch%d" /* name of radio device */ -#define SPEED232 B300 /* uart speed (300 baud) */ -#define leitch_send(A,M) \ -if (debug) fprintf(stderr,"write leitch %s\n",M); \ -if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\ - if (debug) \ - fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \ - else \ - msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);} - -#define STATE_IDLE 0 -#define STATE_DATE 1 -#define STATE_TIME1 2 -#define STATE_TIME2 3 -#define STATE_TIME3 4 - -/* - * LEITCH unit control structure - */ -struct leitchunit { - struct peer *peer; - struct refclockio leitchio; - u_char unit; - short year; - short yearday; - short month; - short day; - short hour; - short second; - short minute; - short state; - u_short fudge1; - l_fp reftime1; - l_fp reftime2; - l_fp reftime3; - l_fp codetime1; - l_fp codetime2; - l_fp codetime3; - u_long yearstart; -}; - -/* - * Function prototypes - */ -static void leitch_init P((void)); -static int leitch_start P((int, struct peer *)); -static void leitch_shutdown P((int, struct peer *)); -static void leitch_poll P((int, struct peer *)); -static void leitch_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); -#define leitch_buginfo noentry -static void leitch_receive P((struct recvbuf *)); -static void leitch_process P((struct leitchunit *)); -#if 0 -static void leitch_timeout P((struct peer *)); -#endif -static int leitch_get_date P((struct recvbuf *, struct leitchunit *)); -static int leitch_get_time P((struct recvbuf *, struct leitchunit *, int)); -static int days_per_year P((int)); - -static struct leitchunit leitchunits[MAXUNITS]; -static u_char unitinuse[MAXUNITS]; -static u_char stratumtouse[MAXUNITS]; -static u_int32 refid[MAXUNITS]; - -static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -/* - * Transfer vector - */ -struct refclock refclock_leitch = { - leitch_start, leitch_shutdown, leitch_poll, - leitch_control, leitch_init, leitch_buginfo, NOFLAGS -}; - -/* - * leitch_init - initialize internal leitch driver data - */ -static void -leitch_init(void) -{ - int i; - - memset((char*)leitchunits, 0, sizeof(leitchunits)); - memset((char*)unitinuse, 0, sizeof(unitinuse)); - for (i = 0; i < MAXUNITS; i++) - memcpy((char *)&refid[i], LEITCHREFID, 4); -} - -/* - * leitch_shutdown - shut down a LEITCH clock - */ -static void -leitch_shutdown( - int unit, - struct peer *peer - ) -{ -#ifdef DEBUG - if (debug) - fprintf(stderr, "leitch_shutdown()\n"); -#endif -} - -/* - * leitch_poll - called by the transmit procedure - */ -static void -leitch_poll( - int unit, - struct peer *peer - ) -{ - struct leitchunit *leitch; - - /* start the state machine rolling */ - -#ifdef DEBUG - if (debug) - fprintf(stderr, "leitch_poll()\n"); -#endif - if (unit > MAXUNITS) { - /* XXXX syslog it */ - return; - } - - leitch = &leitchunits[unit]; - - if (leitch->state != STATE_IDLE) { - /* reset and wait for next poll */ - /* XXXX syslog it */ - leitch->state = STATE_IDLE; - } else { - leitch_send(leitch,"D\r"); - leitch->state = STATE_DATE; - } -} - -static void -leitch_control( - int unit, - struct refclockstat *in, - struct refclockstat *out, - struct peer *passed_peer - ) -{ - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, - "leitch_control: unit %d invalid", unit); - return; - } - - if (in) { - if (in->haveflags & CLK_HAVEVAL1) - stratumtouse[unit] = (u_char)(in->fudgeval1); - if (in->haveflags & CLK_HAVEVAL2) - refid[unit] = in->fudgeval2; - if (unitinuse[unit]) { - struct peer *peer; - - peer = (&leitchunits[unit])->peer; - peer->stratum = stratumtouse[unit]; - peer->refid = refid[unit]; - } - } - - if (out) { - memset((char *)out, 0, sizeof (struct refclockstat)); - out->type = REFCLK_ATOM_LEITCH; - out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; - out->fudgeval1 = (int32)stratumtouse[unit]; - out->fudgeval2 = refid[unit]; - out->p_lastcode = ""; - out->clockdesc = LEITCH_DESCRIPTION; - } -} - -/* - * leitch_start - open the LEITCH devices and initialize data for processing - */ -static int -leitch_start( - int unit, - struct peer *peer - ) -{ - struct leitchunit *leitch; - int fd232; - char leitchdev[20]; - - /* - * Check configuration info. - */ - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit); - return (0); - } - - if (unitinuse[unit]) { - msyslog(LOG_ERR, "leitch_start: unit %d in use", unit); - return (0); - } - - /* - * Open serial port. - */ - (void) sprintf(leitchdev, LEITCH232, unit); - fd232 = open(leitchdev, O_RDWR, 0777); - if (fd232 == -1) { - msyslog(LOG_ERR, - "leitch_start: open of %s: %m", leitchdev); - return (0); - } - - leitch = &leitchunits[unit]; - memset((char*)leitch, 0, sizeof(*leitch)); - -#if defined(HAVE_SYSV_TTYS) - /* - * System V serial line parameters (termio interface) - * - */ - { struct termio ttyb; - if (ioctl(fd232, TCGETA, &ttyb) < 0) { - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, TCGETA): %m", leitchdev); - goto screwed; - } - ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL; - ttyb.c_oflag = 0; - ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD; - ttyb.c_lflag = ICANON; - ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0'; - if (ioctl(fd232, TCSETA, &ttyb) < 0) { - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, TCSETA): %m", leitchdev); - goto screwed; - } - } -#endif /* HAVE_SYSV_TTYS */ -#if defined(HAVE_TERMIOS) - /* - * POSIX serial line parameters (termios interface) - * - * The LEITCHCLK option provides timestamping at the driver level. - * It requires the tty_clk streams module. - */ - { struct termios ttyb, *ttyp; - - ttyp = &ttyb; - if (tcgetattr(fd232, ttyp) < 0) { - msyslog(LOG_ERR, - "leitch_start: tcgetattr(%s): %m", leitchdev); - goto screwed; - } - ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; - ttyp->c_oflag = 0; - ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; - ttyp->c_lflag = ICANON; - ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; - if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { - msyslog(LOG_ERR, - "leitch_start: tcsetattr(%s): %m", leitchdev); - goto screwed; - } - if (tcflush(fd232, TCIOFLUSH) < 0) { - msyslog(LOG_ERR, - "leitch_start: tcflush(%s): %m", leitchdev); - goto screwed; - } - } -#endif /* HAVE_TERMIOS */ -#ifdef STREAM -#if defined(LEITCHCLK) - if (ioctl(fd232, I_PUSH, "clk") < 0) - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev); - if (ioctl(fd232, CLK_SETSTR, "\n") < 0) - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev); -#endif /* LEITCHCLK */ -#endif /* STREAM */ -#if defined(HAVE_BSD_TTYS) - /* - * 4.3bsd serial line parameters (sgttyb interface) - * - * The LEITCHCLK option provides timestamping at the driver level. - * It requires the tty_clk line discipline and 4.3bsd or later. - */ - { struct sgttyb ttyb; -#if defined(LEITCHCLK) - int ldisc = CLKLDISC; -#endif /* LEITCHCLK */ - - if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev); - goto screwed; - } - ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; -#if defined(LEITCHCLK) - ttyb.sg_erase = ttyb.sg_kill = '\r'; - ttyb.sg_flags = RAW; -#else - ttyb.sg_erase = ttyb.sg_kill = '\0'; - ttyb.sg_flags = EVENP|ODDP|CRMOD; -#endif /* LEITCHCLK */ - if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev); - goto screwed; - } -#if defined(LEITCHCLK) - if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { - msyslog(LOG_ERR, - "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev); - goto screwed; - } -#endif /* LEITCHCLK */ - } -#endif /* HAVE_BSD_TTYS */ - - /* - * Set up the structures - */ - leitch->peer = peer; - leitch->unit = unit; - leitch->state = STATE_IDLE; - leitch->fudge1 = 15; /* 15ms */ - - leitch->leitchio.clock_recv = leitch_receive; - leitch->leitchio.srcclock = (caddr_t) leitch; - leitch->leitchio.datalen = 0; - leitch->leitchio.fd = fd232; - if (!io_addclock(&leitch->leitchio)) { - goto screwed; - } - - /* - * All done. Initialize a few random peer variables, then - * return success. - */ - peer->precision = 0; - peer->stratum = stratumtouse[unit]; - peer->refid = refid[unit]; - unitinuse[unit] = 1; - return(1); - - /* - * Something broke; abandon ship. - */ - screwed: - close(fd232); - return(0); -} - -/* - * leitch_receive - receive data from the serial interface on a leitch - * clock - */ -static void -leitch_receive( - struct recvbuf *rbufp - ) -{ - struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock; - -#ifdef DEBUG - if (debug) - fprintf(stderr, "leitch_recieve(%*.*s)\n", - rbufp->recv_length, rbufp->recv_length, - rbufp->recv_buffer); -#endif - if (rbufp->recv_length != 7) - return; /* The date is return with a trailing newline, - discard it. */ - - switch (leitch->state) { - case STATE_IDLE: /* unexpected, discard and resync */ - return; - case STATE_DATE: - if (!leitch_get_date(rbufp,leitch)) { - leitch->state = STATE_IDLE; - break; - } - leitch_send(leitch,"T\r"); -#ifdef DEBUG - if (debug) - fprintf(stderr, "%u\n",leitch->yearday); -#endif - leitch->state = STATE_TIME1; - break; - case STATE_TIME1: - if (!leitch_get_time(rbufp,leitch,1)) { - } - if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, - leitch->second, 1, rbufp->recv_time.l_ui, - &leitch->yearstart, &leitch->reftime1.l_ui)) { - leitch->state = STATE_IDLE; - break; - } - leitch->reftime1.l_uf = 0; -#ifdef DEBUG - if (debug) - fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui); -#endif - MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf); - leitch->codetime1 = rbufp->recv_time; - leitch->state = STATE_TIME2; - break; - case STATE_TIME2: - if (!leitch_get_time(rbufp,leitch,2)) { - } - if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, - leitch->second, 1, rbufp->recv_time.l_ui, - &leitch->yearstart, &leitch->reftime2.l_ui)) { - leitch->state = STATE_IDLE; - break; - } -#ifdef DEBUG - if (debug) - fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui); -#endif - MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf); - leitch->codetime2 = rbufp->recv_time; - leitch->state = STATE_TIME3; - break; - case STATE_TIME3: - if (!leitch_get_time(rbufp,leitch,3)) { - } - if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, - leitch->second, GMT, rbufp->recv_time.l_ui, - &leitch->yearstart, &leitch->reftime3.l_ui)) { - leitch->state = STATE_IDLE; - break; - } -#ifdef DEBUG - if (debug) - fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui); -#endif - MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf); - leitch->codetime3 = rbufp->recv_time; - leitch_process(leitch); - leitch->state = STATE_IDLE; - break; - default: - msyslog(LOG_ERR, - "leitech_receive: invalid state %d unit %d", - leitch->state, leitch->unit); - } -} - -/* - * leitch_process - process a pile of samples from the clock - * - * This routine uses a three-stage median filter to calculate offset and - * dispersion. reduce jitter. The dispersion is calculated as the span - * of the filter (max - min), unless the quality character (format 2) is - * non-blank, in which case the dispersion is calculated on the basis of - * the inherent tolerance of the internal radio oscillator, which is - * +-2e-5 according to the radio specifications. - */ -static void -leitch_process( - struct leitchunit *leitch - ) -{ - l_fp off; - l_fp tmp_fp; - /*double doffset;*/ - - off = leitch->reftime1; - L_SUB(&off,&leitch->codetime1); - tmp_fp = leitch->reftime2; - L_SUB(&tmp_fp,&leitch->codetime2); - if (L_ISGEQ(&off,&tmp_fp)) - off = tmp_fp; - tmp_fp = leitch->reftime3; - L_SUB(&tmp_fp,&leitch->codetime3); - - if (L_ISGEQ(&off,&tmp_fp)) - off = tmp_fp; - /*LFPTOD(&off, doffset);*/ - refclock_receive(leitch->peer); -} - -/* - * days_per_year - */ -static int -days_per_year( - int year - ) -{ - if (year%4) { /* not a potential leap year */ - return (365); - } else { - if (year % 100) { /* is a leap year */ - return (366); - } else { - if (year % 400) { - return (365); - } else { - return (366); - } - } - } -} - -static int -leitch_get_date( - struct recvbuf *rbufp, - struct leitchunit *leitch - ) -{ - int i; - - if (rbufp->recv_length < 6) - return(0); -#undef BAD /* confict: defined as (-1) in AIX sys/param.h */ -#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9') - if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) - return(0); -#define ATOB(A) ((rbufp->recv_buffer[A])-'0') - leitch->year = ATOB(0)*10 + ATOB(1); - leitch->month = ATOB(2)*10 + ATOB(3); - leitch->day = ATOB(4)*10 + ATOB(5); - - /* sanity checks */ - if (leitch->month > 12) - return(0); - if (leitch->day > days_in_month[leitch->month-1]) - return(0); - - /* calculate yearday */ - i = 0; - leitch->yearday = leitch->day; - - while ( i < (leitch->month-1) ) - leitch->yearday += days_in_month[i++]; - - if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) && - leitch->month > 2) - leitch->yearday--; - - return(1); -} - -/* - * leitch_get_time - */ -static int -leitch_get_time( - struct recvbuf *rbufp, - struct leitchunit *leitch, - int which - ) -{ - if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) - return(0); - leitch->hour = ATOB(0)*10 +ATOB(1); - leitch->minute = ATOB(2)*10 +ATOB(3); - leitch->second = ATOB(4)*10 +ATOB(5); - - if ((leitch->hour > 23) || (leitch->minute > 60) || - (leitch->second > 60)) - return(0); - return(1); -} - -#else -int refclock_leitch_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_local.c b/contrib/ntp/ntpd/refclock_local.c deleted file mode 100644 index 3478f43..0000000 --- a/contrib/ntp/ntpd/refclock_local.c +++ /dev/null @@ -1,264 +0,0 @@ - -/* - * refclock_local - local pseudo-clock driver - * - * wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef REFCLOCK - -#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 - -/* - * This is a hack to allow a machine to use its own system clock as a - * reference clock, i.e., to free-run using no outside clock discipline - * source. This is useful if you want to use NTP in an isolated - * environment with no radio clock or NIST modem available. Pick a - * machine that you figure has a good clock oscillator and configure it - * with this driver. Set the clock using the best means available, like - * eyeball-and-wristwatch. Then, point all the other machines at this - * one or use broadcast (not multicast) mode to distribute time. - * - * Another application for this driver is if you want to use a - * particular server's clock as the clock of last resort when all other - * normal synchronization sources have gone away. This is especially - * useful if that server has an ovenized oscillator. For this you would - * configure this driver at a higher stratum (say 5) to prevent the - * server's stratum from falling below that. - * - * A third application for this driver is when an external discipline - * source is available, such as the NIST "lockclock" program, which - * synchronizes the local clock via a telephone modem and the NIST - * Automated Computer Time Service (ACTS), or the Digital Time - * Synchronization Service (DTSS), which runs on DCE machines. In this - * case the stratum should be set at zero, indicating a bona fide - * stratum-1 source. Exercise some caution with this, since there is no - * easy way to telegraph via NTP that something might be wrong in the - * discipline source itself. In the case of DTSS, the local clock can - * have a rather large jitter, depending on the interval between - * corrections and the intrinsic frequency error of the clock - * oscillator. In extreme cases, this can cause clients to exceed the - * 128-ms slew window and drop off the NTP subnet. - * - * THis driver includes provisions to telegraph synchronization state - * and related variables by means of kernel variables with specially - * modified kernels. This is done using the ntp_adjtime() syscall. - * In the cases where another protocol or device synchronizes the local - * host, the data given to the kernel can be slurped up by this driver - * and distributed to clients by ordinary NTP messaging. - * - * In the default mode the behavior of the clock selection algorithm is - * modified when this driver is in use. The algorithm is designed so - * that this driver will never be selected unless no other discipline - * source is available. This can be overriden with the prefer keyword of - * the server configuration command, in which case only this driver will - * be selected for synchronization and all other discipline sources will - * be ignored. This behavior is intended for use when an external - * discipline source controls the system clock. - * - * Fudge Factors - * - * The stratum for this driver set at 5 by default, but it can be - * changed by the fudge command and/or the ntpdc utility. The reference - * ID is "LCL" by default, but can be changed using the same mechanism. - * *NEVER* configure this driver to operate at a stratum which might - * possibly disrupt a client with access to a bona fide primary server, - * unless the local clock oscillator is reliably disciplined by another - * source. *NEVER NEVER* configure a server which might devolve to an - * undisciplined local clock to use multicast mode. Always remember that - * an improperly configured local clock driver let loose in the Internet - * can cause very serious disruption. This is why most of us who care - * about good time use cryptographic authentication. - * - * This driver provides a mechanism to trim the local clock in both time - * and frequency, as well as a way to manipulate the leap bits. The - * fudge time1 parameter adjusts the time, in seconds, and the fudge - * time2 parameter adjusts the frequency, in ppm. The fudge time1 - * parameter is additive; that is, it adds an increment to the current - * time. The fudge time2 parameter directly sets the frequency. - */ -/* - * Local interface definitions - */ -#define PRECISION (-7) /* about 10 ms precision */ -#if defined(VMS) && defined(VMS_LOCALUNIT) -#define REFID "LCLv" /* reference ID */ -#else /* VMS VMS_LOCALUNIT */ -#define REFID "LCL\0" /* reference ID */ -#endif /* VMS VMS_LOCALUNIT */ -#define DESCRIPTION "Undisciplined local clock" /* WRU */ - -#define STRATUM 5 /* default stratum */ -#define DISPERSION .01 /* default dispersion (10 ms) */ - -/* - * Imported from the timer module - */ -extern u_long current_time; - -/* - * Imported from ntp_proto - */ -extern s_char sys_precision; - -#ifdef KERNEL_PLL -/* - * Imported from ntp_loopfilter - */ -extern int pll_control; /* kernel pll control */ -extern int kern_enable; /* kernel pll enabled */ -extern int ext_enable; /* external clock enable */ -#endif /* KERNEL_PLL */ - -/* - * Function prototypes - */ -static int local_start P((int, struct peer *)); -static void local_poll P((int, struct peer *)); - -/* - * Local variables - */ -static u_long poll_time; /* last time polled */ - -/* - * Transfer vector - */ -struct refclock refclock_local = { - local_start, /* start up driver */ - noentry, /* shut down driver (not used) */ - local_poll, /* transmit poll message */ - noentry, /* not used (old lcl_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old lcl_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * local_start - start up the clock - */ -static int -local_start( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - - pp = peer->procptr; - - /* - * Initialize miscellaneous variables - */ - peer->precision = sys_precision; - pp->leap = LEAP_NOTINSYNC; - peer->stratum = STRATUM; - pp->stratum = STRATUM; - pp->clockdesc = DESCRIPTION; - memcpy(&pp->refid, "INIT", 4); - poll_time = current_time; - return (1); -} - - -/* - * local_poll - called by the transmit procedure - * - * LOCKCLOCK: If the kernel supports the nanokernel or microkernel - * system calls, the leap bits are extracted from the kernel. If there - * is a kernel error or the kernel leap bits are set to 11, the NTP leap - * bits are set to 11 and the stratum is set to infinity. Otherwise, the - * NTP leap bits are set to the kernel leap bits and the stratum is set - * as fudged. This behavior does not faithfully follow the - * specification, but is probably more appropriate in a multiple-server - * national laboratory network. - */ -static void -local_poll( - int unit, - struct peer *peer - ) -{ -#if defined(KERNEL_PLL) && defined(LOCKCLOCK) - struct timex ntv; -#endif /* KERNEL_PLL LOCKCLOCK */ - struct refclockproc *pp; - -#if defined(VMS) && defined(VMS_LOCALUNIT) - if (unit == VMS_LOCALUNIT) { - extern void vms_local_poll(struct peer *); - - vms_local_poll(peer); - return; - } -#endif /* VMS && VMS_LOCALUNIT */ - pp = peer->procptr; - pp->polls++; - - /* - * Ramble through the usual filtering and grooming code, which - * is essentially a no-op and included mostly for pretty - * billboards. We allow a one-time time adjustment using fudge - * time1 (s) and a continuous frequency adjustment using fudge - * time 2 (ppm). - */ - get_systime(&pp->lastrec); - pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time - - poll_time); - poll_time = current_time; - refclock_process_offset(pp, pp->lastrec, pp->lastrec, - pp->fudgetime1); - - /* - * If another process is disciplining the system clock, we set - * the leap bits and quality indicators from the kernel. - */ -#if defined(KERNEL_PLL) && defined(LOCKCLOCK) - memset(&ntv, 0, sizeof ntv); - switch (ntp_adjtime(&ntv)) { - case TIME_OK: - pp->leap = LEAP_NOWARNING; - peer->stratum = pp->stratum; - break; - - case TIME_INS: - pp->leap = LEAP_ADDSECOND; - peer->stratum = pp->stratum; - break; - - case TIME_DEL: - pp->leap = LEAP_DELSECOND; - peer->stratum = pp->stratum; - break; - - default: - pp->leap = LEAP_NOTINSYNC; - peer->stratum = STRATUM_UNSPEC; - } - pp->disp = 0; - pp->jitter = 0; -#else /* KERNEL_PLL LOCKCLOCK */ - pp->leap = LEAP_NOWARNING; - pp->disp = DISPERSION; - pp->jitter = 0; -#endif /* KERNEL_PLL LOCKCLOCK */ - pp->lastref = pp->lastrec; - refclock_receive(peer); - pp->fudgetime1 = 0; -} -#else -int refclock_local_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_msfees.c b/contrib/ntp/ntpd/refclock_msfees.c deleted file mode 100644 index ebfb983..0000000 --- a/contrib/ntp/ntpd/refclock_msfees.c +++ /dev/null @@ -1,1455 +0,0 @@ -/* refclock_ees - clock driver for the EES M201 receiver */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS) - -/* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes - * were removed as the code was overly hairy, they weren't in use - * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk - */ - -#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 */ -#if defined(HAVE_SYSV_TTYS) -#include <termio.h> -#endif /* HAVE_SYSV_TTYS */ -#if defined(HAVE_TERMIOS) -#include <termios.h> -#endif -#if defined(STREAM) -#include <stropts.h> -#endif - -#ifdef HAVE_SYS_TERMIOS_H -# include <sys/termios.h> -#endif -#ifdef HAVE_SYS_PPSCLOCK_H -# include <sys/ppsclock.h> -#endif - -#include "ntp_stdlib.h" - -/* - fudgefactor = fudgetime1; - os_delay = fudgetime2; - offset_fudge = os_delay + fudgefactor + inherent_delay; - stratumtouse = fudgeval1 & 0xf - debug = fudgeval2; - sloppyclockflag = flags & CLK_FLAG1; - 1 log smoothing summary when processing sample - 4 dump the buffer from the clock - 8 EIOGETKD the last n uS time stamps - if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0; - ees->dump_vals = flags & CLK_FLAG3; - ees->usealldata = flags & CLK_FLAG4; - - - bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0; - bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0; - bug->values[2] = (u_long)ees->status; - bug->values[3] = (u_long)ees->lastevent; - bug->values[4] = (u_long)ees->reason; - bug->values[5] = (u_long)ees->nsamples; - bug->values[6] = (u_long)ees->codestate; - bug->values[7] = (u_long)ees->day; - bug->values[8] = (u_long)ees->hour; - bug->values[9] = (u_long)ees->minute; - bug->values[10] = (u_long)ees->second; - bug->values[11] = (u_long)ees->tz; - bug->values[12] = ees->yearstart; - bug->values[13] = (ees->leaphold > current_time) ? - ees->leaphold - current_time : 0; - bug->values[14] = inherent_delay[unit].l_uf; - bug->values[15] = offset_fudge[unit].l_uf; - - bug->times[0] = ees->reftime; - bug->times[1] = ees->arrvtime; - bug->times[2] = ees->lastsampletime; - bug->times[3] = ees->offset; - bug->times[4] = ees->lowoffset; - bug->times[5] = ees->highoffset; - bug->times[6] = inherent_delay[unit]; - bug->times[8] = os_delay[unit]; - bug->times[7] = fudgefactor[unit]; - bug->times[9] = offset_fudge[unit]; - bug->times[10]= ees->yearstart, 0; - */ - -/* This should support the use of an EES M201 receiver with RS232 - * output (modified to transmit time once per second). - * - * For the format of the message sent by the clock, see the EESM_ - * definitions below. - * - * It appears to run free for an integral number of minutes, until the error - * reaches 4mS, at which point it steps at second = 01. - * It appears that sometimes it steps 4mS (say at 7 min interval), - * then the next minute it decides that it was an error, so steps back. - * On the next minute it steps forward again :-( - * This is typically 16.5uS/S then 3975uS at the 4min re-sync, - * or 9.5uS/S then 3990.5uS at a 7min re-sync, - * at which point it may lose the "00" second time stamp. - * I assume that the most accurate time is just AFTER the re-sync. - * Hence remember the last cycle interval, - * - * Can run in any one of: - * - * PPSCD PPS signal sets CD which interupts, and grabs the current TOD - * (sun) *in the interupt code*, so as to avoid problems with - * the STREAMS scheduling. - * - * It appears that it goes 16.5 uS slow each second, then every 4 mins it - * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7) - */ - -/* Definitions */ -#ifndef MAXUNITS -#define MAXUNITS 4 /* maximum number of EES units permitted */ -#endif - -#ifndef EES232 -#define EES232 "/dev/ees%d" /* Device to open to read the data */ -#endif - -/* Other constant stuff */ -#ifndef EESPRECISION -#define EESPRECISION (-10) /* what the heck - 2**-10 = 1ms */ -#endif -#ifndef EESREFID -#define EESREFID "MSF\0" /* String to identify the clock */ -#endif -#ifndef EESHSREFID -#define EESHSREFID (0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */ -#endif - -/* Description of clock */ -#define EESDESCRIPTION "EES M201 MSF Receiver" - -/* Speed we run the clock port at. If this is changed the UARTDELAY - * value should be recomputed to suit. - */ -#ifndef SPEED232 -#define SPEED232 B9600 /* 9600 baud */ -#endif - -/* What is the inherent delay for this mode of working, i.e. when is the - * data time stamped. - */ -#define SAFETY_SHIFT 10 /* Split the shift to avoid overflow */ -#define BITS_TO_L_FP(bits, baud) \ -(((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT) -#define INH_DELAY_CBREAK BITS_TO_L_FP(119, 9600) -#define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600) - -#ifndef STREAM_PP1 -#define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->" -#endif -#ifndef STREAM_PP2 -#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->" -#endif - - /* Offsets of the bytes of the serial line code. The clock gives - * local time with a GMT/BST indication. The EESM_ definitions - * give offsets into ees->lastcode. - */ -#define EESM_CSEC 0 /* centiseconds - always zero in our clock */ -#define EESM_SEC 1 /* seconds in BCD */ -#define EESM_MIN 2 /* minutes in BCD */ -#define EESM_HOUR 3 /* hours in BCD */ -#define EESM_DAYWK 4 /* day of week (Sun = 0 etc) */ -#define EESM_DAY 5 /* day of month in BCD */ -#define EESM_MON 6 /* month in BCD */ -#define EESM_YEAR 7 /* year MOD 100 in BCD */ -#define EESM_LEAP 8 /* 0x0f if leap year, otherwise zero */ -#define EESM_BST 9 /* 0x03 if BST, 0x00 if GMT */ -#define EESM_MSFOK 10 /* 0x3f if radio good, otherwise zero */ - /* followed by a frame alignment byte (0xff) / - / which is not put into the lastcode buffer*/ - -/* Length of the serial time code, in characters. The first length - * is less the frame alignment byte. - */ -#define LENEESPRT (EESM_MSFOK+1) -#define LENEESCODE (LENEESPRT+1) - - /* Code state. */ -#define EESCS_WAIT 0 /* waiting for start of timecode */ -#define EESCS_GOTSOME 1 /* have an incomplete time code buffered */ - - /* Default fudge factor and character to receive */ -#define DEFFUDGETIME 0 /* Default user supplied fudge factor */ -#ifndef DEFOSTIME -#define DEFOSTIME 0 /* Default OS delay -- passed by Make ? */ -#endif -#define DEFINHTIME INH_DELAY_PPS /* inherent delay due to sample point*/ - - /* Limits on things. Reduce the number of samples to SAMPLEREDUCE by median - * elimination. If we're running with an accurate clock, chose the BESTSAMPLE - * as the estimated offset, otherwise average the remainder. - */ -#define FULLSHIFT 6 /* NCODES root 2 */ -#define NCODES (1<< FULLSHIFT) /* 64 */ -#define REDUCESHIFT (FULLSHIFT -1) /* SAMPLEREDUCE root 2 */ - - /* Towards the high ( Why ?) end of half */ -#define BESTSAMPLE ((samplereduce * 3) /4) /* 24 */ - - /* Leap hold time. After a leap second the clock will no longer be - * reliable until it resynchronizes. Hope 40 minutes is enough. */ -#define EESLEAPHOLD (40 * 60) - -#define EES_STEP_F (1 << 24) /* the receiver steps in units of about 4ms */ -#define EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/ -#define EES_STEP_NOTE (1 << 21)/* Log any unexpected jumps, say .5 ms .... */ -#define EES_STEP_NOTES 50 /* Only do a limited number */ -#define MAX_STEP 16 /* Max number of steps to remember */ - - /* debug is a bit mask of debugging that is wanted */ -#define DB_SYSLOG_SMPLI 0x0001 -#define DB_SYSLOG_SMPLE 0x0002 -#define DB_SYSLOG_SMTHI 0x0004 -#define DB_SYSLOG_NSMTHE 0x0008 -#define DB_SYSLOG_NSMTHI 0x0010 -#define DB_SYSLOG_SMTHE 0x0020 -#define DB_PRINT_EV 0x0040 -#define DB_PRINT_CDT 0x0080 -#define DB_PRINT_CDTC 0x0100 -#define DB_SYSLOG_KEEPD 0x0800 -#define DB_SYSLOG_KEEPE 0x1000 -#define DB_LOG_DELTAS 0x2000 -#define DB_PRINT_DELTAS 0x4000 -#define DB_LOG_AWAITMORE 0x8000 -#define DB_LOG_SAMPLES 0x10000 -#define DB_NO_PPS 0x20000 -#define DB_INC_PPS 0x40000 -#define DB_DUMP_DELTAS 0x80000 - - struct eesunit { /* EES unit control structure. */ - struct peer *peer; /* associated peer structure */ - struct refclockio io; /* given to the I/O handler */ - l_fp reftime; /* reference time */ - l_fp lastsampletime; /* time as in txt from last EES msg */ - l_fp arrvtime; /* Time at which pkt arrived */ - l_fp codeoffsets[NCODES]; /* the time of arrival of 232 codes */ - l_fp offset; /* chosen offset (for clkbug) */ - l_fp lowoffset; /* lowest sample offset (for clkbug) */ - l_fp highoffset; /* highest " " (for clkbug) */ - char lastcode[LENEESCODE+6]; /* last time code we received */ - u_long lasttime; /* last time clock heard from */ - u_long clocklastgood; /* last time good radio seen */ - u_char lencode; /* length of code in buffer */ - u_char nsamples; /* number of samples we've collected */ - u_char codestate; /* state of 232 code reception */ - u_char unit; /* unit number for this guy */ - u_char status; /* clock status */ - u_char lastevent; /* last clock event */ - u_char reason; /* reason for last abort */ - u_char hour; /* hour of day */ - u_char minute; /* minute of hour */ - u_char second; /* seconds of minute */ - char tz; /* timezone from clock */ - u_char ttytype; /* method used */ - u_char dump_vals; /* Should clock values be dumped */ - u_char usealldata; /* Use ALL samples */ - u_short day; /* day of year from last code */ - u_long yearstart; /* start of current year */ - u_long leaphold; /* time of leap hold expiry */ - u_long badformat; /* number of bad format codes */ - u_long baddata; /* number of invalid time codes */ - u_long timestarted; /* time we started this */ - long last_pps_no; /* The serial # of the last PPS */ - char fix_pending; /* Is a "sync to time" pending ? */ - /* Fine tuning - compensate for 4 mS ramping .... */ - l_fp last_l; /* last time stamp */ - u_char last_steps[MAX_STEP]; /* Most recent n steps */ - int best_av_step; /* Best guess at average step */ - char best_av_step_count; /* # of steps over used above */ - char this_step; /* Current pos in buffer */ - int last_step_late; /* How late the last step was (0-59) */ - long jump_fsecs; /* # of fractions of a sec last jump */ - u_long last_step; /* time of last step */ - int last_step_secs; /* Number of seconds in last step */ - int using_ramp; /* 1 -> noemal, -1 -> over stepped */ - }; -#define last_sec last_l.l_ui -#define last_sfsec last_l.l_f -#define this_uisec ((ees->arrvtime).l_ui) -#define this_sfsec ((ees->arrvtime).l_f) -#define msec(x) ((x) / (1<<22)) -#define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0]) -#define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5))) - -/* Bitmask for what methods to try to use -- currently only PPS enabled */ -#define T_CBREAK 1 -#define T_PPS 8 -/* macros to test above */ -#define is_cbreak(x) ((x)->ttytype & T_CBREAK) -#define is_pps(x) ((x)->ttytype & T_PPS) -#define is_any(x) ((x)->ttytype) - -#define CODEREASON 20 /* reason codes */ - -/* Data space for the unit structures. Note that we allocate these on - * the fly, but never give them back. */ -static struct eesunit *eesunits[MAXUNITS]; -static u_char unitinuse[MAXUNITS]; - -/* Keep the fudge factors separately so they can be set even - * when no clock is configured. */ -static l_fp inherent_delay[MAXUNITS]; /* when time stamp is taken */ -static l_fp fudgefactor[MAXUNITS]; /* fudgetime1 */ -static l_fp os_delay[MAXUNITS]; /* fudgetime2 */ -static l_fp offset_fudge[MAXUNITS]; /* Sum of above */ -static u_char stratumtouse[MAXUNITS]; -static u_char sloppyclockflag[MAXUNITS]; - -static int deltas[60]; - -static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */ -static l_fp onesec; /* = { 1, 0 }; */ - -#ifndef DUMP_BUF_SIZE /* Size of buffer to be used by dump_buf */ -#define DUMP_BUF_SIZE 10112 -#endif - -/* ees_reset - reset the count back to zero */ -#define ees_reset(ees) (ees)->nsamples = 0; \ -(ees)->codestate = EESCS_WAIT - -/* ees_event - record and report an event */ -#define ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \ -ees_report_event((ees), (evcode)) - - /* Find the precision of the system clock by reading it */ -#define USECS 1000000 -#define MINSTEP 5 /* some systems increment uS on each call */ -#define MAXLOOPS (USECS/9) - -/* - * Function prototypes - */ - -static int msfees_start P((int unit, struct peer *peer)); -static void msfees_shutdown P((int unit, struct peer *peer)); -static void msfees_poll P((int unit, struct peer *peer)); -static void msfees_init P((void)); -static void dump_buf P((l_fp *coffs, int from, int to, char *text)); -static void ees_report_event P((struct eesunit *ees, int code)); -static void ees_receive P((struct recvbuf *rbufp)); -static void ees_process P((struct eesunit *ees)); -#ifdef QSORT_USES_VOID_P -static int offcompare P((const void *va, const void *vb)); -#else -static int offcompare P((const l_fp *a, const l_fp *b)); -#endif /* QSORT_USES_VOID_P */ - - -/* - * Transfer vector - */ -struct refclock refclock_msfees = { - msfees_start, /* start up driver */ - msfees_shutdown, /* shut down driver */ - msfees_poll, /* transmit poll message */ - noentry, /* not used */ - msfees_init, /* initialize driver */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - - -static void -dump_buf( - l_fp *coffs, - int from, - int to, - char *text - ) -{ - char buff[DUMP_BUF_SIZE + 80]; - int i; - register char *ptr = buff; - - sprintf(ptr, text); - for (i=from; i<to; i++) - { while (*ptr) ptr++; - if ((ptr-buff) > DUMP_BUF_SIZE) msyslog(LOG_DEBUG, "D: %s", ptr=buff); - sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295); - } - msyslog(LOG_DEBUG, "D: %s", buff); -} - -/* msfees_init - initialize internal ees driver data */ -static void -msfees_init(void) -{ - register int i; - /* Just zero the data arrays */ - memset((char *)eesunits, 0, sizeof eesunits); - memset((char *)unitinuse, 0, sizeof unitinuse); - - acceptable_slop.l_ui = 0; - acceptable_slop.l_uf = 1 << (FRACTION_PREC -2); - - onesec.l_ui = 1; - onesec.l_uf = 0; - - /* Initialize fudge factors to default. */ - for (i = 0; i < MAXUNITS; i++) { - fudgefactor[i].l_ui = 0; - fudgefactor[i].l_uf = DEFFUDGETIME; - os_delay[i].l_ui = 0; - os_delay[i].l_uf = DEFOSTIME; - inherent_delay[i].l_ui = 0; - inherent_delay[i].l_uf = DEFINHTIME; - offset_fudge[i] = os_delay[i]; - L_ADD(&offset_fudge[i], &fudgefactor[i]); - L_ADD(&offset_fudge[i], &inherent_delay[i]); - stratumtouse[i] = 0; - sloppyclockflag[i] = 0; - } -} - - -/* msfees_start - open the EES devices and initialize data for processing */ -static int -msfees_start( - int unit, - struct peer *peer - ) -{ - register struct eesunit *ees; - register int i; - int fd232 = -1; - char eesdev[20]; - struct termios ttyb, *ttyp; - struct refclockproc *pp; - pp = peer->procptr; - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)", - unit, MAXUNITS-1); - return 0; - } - if (unitinuse[unit]) { - msyslog(LOG_ERR, "ees clock: unit number %d in use", unit); - return 0; - } - - /* Unit okay, attempt to open the devices. We do them both at - * once to make sure we can */ - (void) sprintf(eesdev, EES232, unit); - - fd232 = open(eesdev, O_RDWR, 0777); - if (fd232 == -1) { - msyslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev); - return 0; - } - -#ifdef TIOCEXCL - /* Set for exclusive use */ - if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) { - msyslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev); - goto screwed; - } -#endif - - /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */ - - /* Set port characteristics. If we don't have a STREAMS module or - * a clock line discipline, cooked mode is just usable, even though it - * strips the top bit. The only EES byte which uses the top - * bit is the year, and we don't use that anyway. If we do - * have the line discipline, we choose raw mode, and the - * line discipline code will block up the messages. - */ - - /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */ - - ttyp = &ttyb; - if (tcgetattr(fd232, ttyp) < 0) { - msyslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev); - goto screwed; - } - - ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; - ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; - ttyp->c_oflag = 0; - ttyp->c_lflag = ICANON; - ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; - if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { - msyslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev); - goto screwed; - } - - if (tcflush(fd232, TCIOFLUSH) < 0) { - msyslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev); - goto screwed; - } - - inherent_delay[unit].l_uf = INH_DELAY_PPS; - - /* offset fudge (how *late* the timestamp is) = fudge + os delays */ - offset_fudge[unit] = os_delay[unit]; - L_ADD(&offset_fudge[unit], &fudgefactor[unit]); - L_ADD(&offset_fudge[unit], &inherent_delay[unit]); - - /* Looks like this might succeed. Find memory for the structure. - * Look to see if there are any unused ones, if not we malloc() one. - */ - if (eesunits[unit] != 0) /* The one we want is okay */ - ees = eesunits[unit]; - else { - /* Look for an unused, but allocated struct */ - for (i = 0; i < MAXUNITS; i++) { - if (!unitinuse[i] && eesunits[i] != 0) - break; - } - - if (i < MAXUNITS) { /* Reclaim this one */ - ees = eesunits[i]; - eesunits[i] = 0; - } /* no spare -- make a new one */ - else ees = (struct eesunit *) emalloc(sizeof(struct eesunit)); - } - memset((char *)ees, 0, sizeof(struct eesunit)); - eesunits[unit] = ees; - - /* Set up the structures */ - ees->peer = peer; - ees->unit = (u_char)unit; - ees->timestarted= current_time; - ees->ttytype = 0; - ees->io.clock_recv= ees_receive; - ees->io.srcclock= (caddr_t)ees; - ees->io.datalen = 0; - ees->io.fd = fd232; - - /* Okay. Push one of the two (linked into the kernel, or dynamically - * loaded) STREAMS module, and give it to the I/O code to start - * receiving stuff. - */ - -#ifdef STREAM - { - int rc1; - /* Pop any existing onews first ... */ - while (ioctl(fd232, I_POP, 0 ) >= 0) ; - - /* Now try pushing either of the possible modules */ - if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 && - ioctl(fd232, I_PUSH, STREAM_PP2) < 0) { - msyslog(LOG_ERR, - "ees clock: Push of `%s' and `%s' to %s failed %m", - STREAM_PP1, STREAM_PP2, eesdev); - goto screwed; - } - else { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, "I: ees clock: PUSHed %s on %s", - (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev); - ees->ttytype |= T_PPS; - } - } -#endif /* STREAM */ - - /* Add the clock */ - if (!io_addclock(&ees->io)) { - /* Oh shit. Just close and return. */ - msyslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev); - goto screwed; - } - - - /* All done. Initialize a few random peer variables, then - * return success. */ - peer->precision = sys_precision; - peer->stratum = stratumtouse[unit]; - if (stratumtouse[unit] <= 1) { - memcpy((char *)&pp->refid, EESREFID, 4); - if (unit > 0 && unit < 10) - ((char *)&pp->refid)[3] = '0' + unit; - } else { - peer->refid = htonl(EESHSREFID); - } - unitinuse[unit] = 1; - pp->unitptr = (caddr_t) &eesunits[unit]; - pp->clockdesc = EESDESCRIPTION; - msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit); - return (1); - - screwed: - if (fd232 != -1) - (void) close(fd232); - return (0); -} - - -/* msfees_shutdown - shut down a EES clock */ -static void -msfees_shutdown( - int unit, - struct peer *peer - ) -{ - register struct eesunit *ees; - - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, - "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)", - unit, MAXUNITS); - return; - } - if (!unitinuse[unit]) { - msyslog(LOG_ERR, - "ees clock: INTERNAL ERROR, unit number %d not in use", unit); - return; - } - - /* Tell the I/O module to turn us off. We're history. */ - ees = eesunits[unit]; - io_closeclock(&ees->io); - unitinuse[unit] = 0; -} - - -/* ees_report_event - note the occurance of an event */ -static void -ees_report_event( - struct eesunit *ees, - int code - ) -{ - if (ees->status != (u_char)code) { - ees->status = (u_char)code; - if (code != CEVNT_NOMINAL) - ees->lastevent = (u_char)code; - /* Should report event to trap handler in here. - * Soon... - */ - } -} - - -/* ees_receive - receive data from the serial interface on an EES clock */ -static void -ees_receive( - struct recvbuf *rbufp - ) -{ - register int n_sample; - register int day; - register struct eesunit *ees; - register u_char *dpt; /* Data PoinTeR: move along ... */ - register u_char *dpend; /* Points just *after* last data char */ - register char *cp; - l_fp tmp; - int call_pps_sample = 0; - l_fp pps_arrvstamp; - int sincelast; - int pps_step = 0; - int suspect_4ms_step = 0; - struct ppsclockev ppsclockev; - long *ptr = (long *) &ppsclockev; - int rc; - int request; -#ifdef HAVE_CIOGETEV - request = CIOGETEV; -#endif -#ifdef HAVE_TIOCGPPSEV - request = TIOCGPPSEV; -#endif - - /* Get the clock this applies to and a pointer to the data */ - ees = (struct eesunit *)rbufp->recv_srcclock; - dpt = (u_char *)&rbufp->recv_space; - dpend = dpt + rbufp->recv_length; - if ((debug & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE)) - printf("[%d] ", rbufp->recv_length); - - /* Check out our state and process appropriately */ - switch (ees->codestate) { - case EESCS_WAIT: - /* Set an initial guess at the timestamp as the recv time. - * If just running in CBREAK mode, we can't improve this. - * If we have the CLOCK Line Discipline, PPSCD, or sime such, - * then we will do better later .... - */ - ees->arrvtime = rbufp->recv_time; - ees->codestate = EESCS_GOTSOME; - ees->lencode = 0; - /*FALLSTHROUGH*/ - - case EESCS_GOTSOME: - cp = &(ees->lastcode[ees->lencode]); - - /* Gobble the bytes until the final (possibly stripped) 0xff */ - while (dpt < dpend && (*dpt & 0x7f) != 0x7f) { - *cp++ = (char)*dpt++; - ees->lencode++; - /* Oh dear -- too many bytes .. */ - if (ees->lencode > LENEESPRT) { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, - "I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]", - ees->lencode, dpend - dpt, LENEESPRT, -#define D(x) (ees->lastcode[x]) - D(0), D(1), D(2), D(3), D(4), D(5), D(6), - D(7), D(8), D(9), D(10), D(11), D(12)); -#undef D - ees->badformat++; - ees->reason = CODEREASON + 1; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - } - /* Gave up because it was end of the buffer, rather than ff */ - if (dpt == dpend) { - /* Incomplete. Wait for more. */ - if (debug & DB_LOG_AWAITMORE) - msyslog(LOG_INFO, - "I: ees clock %d: %p == %p: await more", - ees->unit, dpt, dpend); - return; - } - - /* This shouldn't happen ... ! */ - if ((*dpt & 0x7f) != 0x7f) { - msyslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt); - ees->badformat++; - ees->reason = CODEREASON + 2; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - - /* Skip the 0xff */ - dpt++; - - /* Finally, got a complete buffer. Mainline code will - * continue on. */ - cp = ees->lastcode; - break; - - default: - msyslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d", - ees->unit, ees->codestate); - ees->reason = CODEREASON + 5; - ees_event(ees, CEVNT_FAULT); - ees_reset(ees); - return; - } - - /* Boy! After all that crap, the lastcode buffer now contains - * something we hope will be a valid time code. Do length - * checks and sanity checks on constant data. - */ - ees->codestate = EESCS_WAIT; - ees->lasttime = current_time; - if (ees->lencode != LENEESPRT) { - ees->badformat++; - ees->reason = CODEREASON + 6; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - - cp = ees->lastcode; - - /* Check that centisecond is zero */ - if (cp[EESM_CSEC] != 0) { - ees->baddata++; - ees->reason = CODEREASON + 7; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - - /* Check flag formats */ - if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) { - ees->badformat++; - ees->reason = CODEREASON + 8; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - - if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) { - ees->badformat++; - ees->reason = CODEREASON + 9; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - - if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) { - ees->badformat++; - ees->reason = CODEREASON + 10; - ees_event(ees, CEVNT_BADREPLY); - ees_reset(ees); - return; - } - - /* So far, so good. Compute day, hours, minutes, seconds, - * time zone. Do range checks on these. - */ - -#define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) ) -#define istrue(x) ((x)?1:0) - - ees->second = bcdunpack(cp[EESM_SEC]); /* second */ - ees->minute = bcdunpack(cp[EESM_MIN]); /* minute */ - ees->hour = bcdunpack(cp[EESM_HOUR]); /* hour */ - - day = bcdunpack(cp[EESM_DAY]); /* day of month */ - - switch (bcdunpack(cp[EESM_MON])) { /* month */ - - /* Add in lengths of all previous months. Add one more - if it is a leap year and after February. - */ - case 12: day += NOV; /*FALLSTHROUGH*/ - case 11: day += OCT; /*FALLSTHROUGH*/ - case 10: day += SEP; /*FALLSTHROUGH*/ - case 9: day += AUG; /*FALLSTHROUGH*/ - case 8: day += JUL; /*FALLSTHROUGH*/ - case 7: day += JUN; /*FALLSTHROUGH*/ - case 6: day += MAY; /*FALLSTHROUGH*/ - case 5: day += APR; /*FALLSTHROUGH*/ - case 4: day += MAR; /*FALLSTHROUGH*/ - case 3: day += FEB; - if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/ - case 2: day += JAN; /*FALLSTHROUGH*/ - case 1: break; - default: ees->baddata++; - ees->reason = CODEREASON + 11; - ees_event(ees, CEVNT_BADDATE); - ees_reset(ees); - return; - } - - ees->day = day; - - /* Get timezone. The clocktime routine wants the number - * of hours to add to the delivered time to get UT. - * Currently -1 if BST flag set, 0 otherwise. This - * is the place to tweak things if double summer time - * ever happens. - */ - ees->tz = istrue(cp[EESM_BST]) ? -1 : 0; - - if (ees->day > 366 || ees->day < 1 || - ees->hour > 23 || ees->minute > 59 || ees->second > 59) { - ees->baddata++; - ees->reason = CODEREASON + 12; - ees_event(ees, CEVNT_BADDATE); - ees_reset(ees); - return; - } - - n_sample = ees->nsamples; - - /* Now, compute the reference time value: text -> tmp.l_ui */ - if (!clocktime(ees->day, ees->hour, ees->minute, ees->second, - ees->tz, rbufp->recv_time.l_ui, &ees->yearstart, - &tmp.l_ui)) { - ees->baddata++; - ees->reason = CODEREASON + 13; - ees_event(ees, CEVNT_BADDATE); - ees_reset(ees); - return; - } - tmp.l_uf = 0; - - /* DON'T use ees->arrvtime -- it may be < reftime */ - ees->lastsampletime = tmp; - - /* If we are synchronised to the radio, update the reference time. - * Also keep a note of when clock was last good. - */ - if (istrue(cp[EESM_MSFOK])) { - ees->reftime = tmp; - ees->clocklastgood = current_time; - } - - - /* Compute the offset. For the fractional part of the - * offset we use the expected delay for the message. - */ - ees->codeoffsets[n_sample].l_ui = tmp.l_ui; - ees->codeoffsets[n_sample].l_uf = 0; - - /* Number of seconds since the last step */ - sincelast = this_uisec - ees->last_step; - - memset((char *) &ppsclockev, 0, sizeof ppsclockev); - - rc = ioctl(ees->io.fd, request, (char *) &ppsclockev); - if (debug & DB_PRINT_EV) fprintf(stderr, - "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08lx %08lx %ld\n", - DB_PRINT_EV, ees->unit, ees->io.fd, request, is_pps(ees), - rc, errno, ptr[0], ptr[1], ptr[2]); - - /* If we managed to get the time of arrival, process the info */ - if (rc >= 0) { - int conv = -1; - pps_step = ppsclockev.serial - ees->last_pps_no; - - /* Possible that PPS triggered, but text message didn't */ - if (pps_step == 2) msyslog(LOG_ERR, "pps step = 2 @ %02d", ees->second); - if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1; - if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4; - - /* allow for single loss of PPS only */ - if (pps_step != 1 && pps_step != 2) - fprintf(stderr, "PPS step: %d too far off %ld (%d)\n", - ppsclockev.serial, ees->last_pps_no, pps_step); - else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp)) - fprintf(stderr, "buftvtots failed\n"); - else { /* if ((ABS(time difference) - 0.25) < 0) - * then believe it ... - */ - l_fp diff; - diff = pps_arrvstamp; - conv = 0; - L_SUB(&diff, &ees->arrvtime); - if (debug & DB_PRINT_CDT) - printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s", - DB_PRINT_CDT, (long)ees->arrvtime.l_ui, (long)ees->arrvtime.l_uf, - (long)pps_arrvstamp.l_ui, (long)pps_arrvstamp.l_uf, - (long)diff.l_ui, (long)diff.l_uf, - ctime(&(ppsclockev.tv.tv_sec))); - if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf); - L_SUB(&diff, &acceptable_slop); - if (L_ISNEG(&diff)) { /* AOK -- pps_sample */ - ees->arrvtime = pps_arrvstamp; - conv++; - call_pps_sample++; - } - /* Some loss of some signals around sec = 1 */ - else if (ees->second == 1) { - diff = pps_arrvstamp; - L_ADD(&diff, &onesec); - L_SUB(&diff, &ees->arrvtime); - if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf); - L_SUB(&diff, &acceptable_slop); - msyslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s", - pps_arrvstamp.l_ui - ees->arrvtime.l_ui, - pps_arrvstamp.l_uf, - ees->arrvtime.l_uf, - diff.l_ui, diff.l_uf, - (int)ppsclockev.tv.tv_usec, - ctime(&(ppsclockev.tv.tv_sec))); - if (L_ISNEG(&diff)) { /* AOK -- pps_sample */ - suspect_4ms_step |= 2; - ees->arrvtime = pps_arrvstamp; - L_ADD(&ees->arrvtime, &onesec); - conv++; - call_pps_sample++; - } - } - } - ees->last_pps_no = ppsclockev.serial; - if (debug & DB_PRINT_CDTC) - printf( - "[%x] %08lx %08lx %d u%d (%d %d)\n", - DB_PRINT_CDTC, (long)pps_arrvstamp.l_ui, - (long)pps_arrvstamp.l_uf, conv, ees->unit, - call_pps_sample, pps_step); - } - - /* See if there has been a 4ms jump at a minute boundry */ - { l_fp delta; -#define delta_isec delta.l_ui -#define delta_ssec delta.l_i -#define delta_sfsec delta.l_f - long delta_f_abs; - - delta.l_i = ees->arrvtime.l_i; - delta.l_f = ees->arrvtime.l_f; - - L_SUB(&delta, &ees->last_l); - delta_f_abs = delta_sfsec; - if (delta_f_abs < 0) delta_f_abs = -delta_f_abs; - - /* Dump the deltas each minute */ - if (debug & DB_DUMP_DELTAS) - { if (/*0 <= ees->second && */ - ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec; - /* Dump on second 1, as second 0 sometimes missed */ - if (ees->second == 1) { - char text[16 * ((sizeof deltas) / (sizeof deltas[0]))]; - char *cptr=text; - int i; - for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) { - sprintf(cptr, " %d.%04d", - msec(deltas[i]), subms(deltas[i])); - while (*cptr) cptr++; - } - msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s", - msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE), - msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE), - text+1); - for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0; - } - } - - /* Lets see if we have a 4 mS step at a minute boundaary */ - if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) && - (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) && - (ees->second == 0 || ees->second == 1 || ees->second == 2) && - (sincelast < 0 || sincelast > 122) - ) { /* 4ms jump at min boundry */ - int old_sincelast; - int count=0; - int sum = 0; - /* Yes -- so compute the ramp time */ - if (ees->last_step == 0) sincelast = 0; - old_sincelast = sincelast; - - /* First time in, just set "ees->last_step" */ - if(ees->last_step) { - int other_step = 0; - int third_step = 0; - int this_step = (sincelast + (60 /2)) / 60; - int p_step = ees->this_step; - int p; - ees->last_steps[p_step] = this_step; - p= p_step; - p_step++; - if (p_step >= LAST_STEPS) p_step = 0; - ees->this_step = p_step; - /* Find the "average" interval */ - while (p != p_step) { - int this = ees->last_steps[p]; - if (this == 0) break; - if (this != this_step) { - if (other_step == 0 && ( - this== (this_step +2) || - this== (this_step -2) || - this== (this_step +1) || - this== (this_step -1))) - other_step = this; - if (other_step != this) { - int idelta = (this_step - other_step); - if (idelta < 0) idelta = - idelta; - if (third_step == 0 && ( - (idelta == 1) ? ( - this == (other_step +1) || - this == (other_step -1) || - this == (this_step +1) || - this == (this_step -1)) - : - ( - this == (this_step + other_step)/2 - ) - )) third_step = this; - if (third_step != this) break; - } - } - sum += this; - p--; - if (p < 0) p += LAST_STEPS; - count++; - } - msyslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step); - if (count != 0) sum = ((sum * 60) + (count /2)) / count; -#define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS]) - msyslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", - ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6), - SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15)); - printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", - ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6), - SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15)); -#undef SV - ees->jump_fsecs = delta_sfsec; - ees->using_ramp = 1; - if (sincelast > 170) - ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs); - else ees->last_step_late = 30; - if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30; - if (ees->last_step_late < 0) ees->last_step_late = 0; - if (ees->last_step_late >= 60) ees->last_step_late = 59; - sincelast = 0; - } - else { /* First time in -- just save info */ - ees->last_step_late = 30; - ees->jump_fsecs = delta_sfsec; - ees->using_ramp = 1; - sum = 4 * 60; - } - ees->last_step = this_uisec; - printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n", - ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec), - ees->second, old_sincelast, ees->last_step_late, count, sum, - ees->last_step_secs); - msyslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d", - ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, - old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs); - if (sum) ees->last_step_secs = sum; - } - /* OK, so not a 4ms step at a minute boundry */ - else { - if (suspect_4ms_step) msyslog(LOG_ERR, - "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]", - ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec), - msec(EES_STEP_F - EES_STEP_F_GRACE), - subms(EES_STEP_F - EES_STEP_F_GRACE), - (int)msec(delta_f_abs), - (int)subms(delta_f_abs), - msec(EES_STEP_F + EES_STEP_F_GRACE), - subms(EES_STEP_F + EES_STEP_F_GRACE), - ees->second, - sincelast); - if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) { - static int ees_step_notes = EES_STEP_NOTES; - if (ees_step_notes > 0) { - ees_step_notes--; - printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n", - ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec), - ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !"); - msyslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s", - ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !"); - } - } - } - } - ees->last_l = ees->arrvtime; - - /* IF we have found that it's ramping - * && it's within twice the expected ramp period - * && there is a non zero step size (avoid /0 !) - * THEN we twiddle things - */ - if (ees->using_ramp && - sincelast < (ees->last_step_secs)*2 && - ees->last_step_secs) - { long sec_of_ramp = sincelast + ees->last_step_late; - long fsecs; - l_fp inc; - - /* Ramp time may vary, so may ramp for longer than last time */ - if (sec_of_ramp > (ees->last_step_secs + 120)) - sec_of_ramp = ees->last_step_secs; - - /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */ - fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs); - - if (debug & DB_LOG_DELTAS) msyslog(LOG_ERR, - "[%x] MSF%d: %3ld/%03d -> d=%11ld (%d|%ld)", - DB_LOG_DELTAS, - ees->unit, sec_of_ramp, ees->last_step_secs, fsecs, - pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs); - if (debug & DB_PRINT_DELTAS) printf( - "MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n", - ees->unit, sec_of_ramp, ees->last_step_secs, fsecs, - (long)pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs); - - /* Must sign extend the result */ - inc.l_i = (fsecs < 0) ? -1 : 0; - inc.l_f = fsecs; - if (debug & DB_INC_PPS) - { L_SUB(&pps_arrvstamp, &inc); - L_SUB(&ees->arrvtime, &inc); - } - else - { L_ADD(&pps_arrvstamp, &inc); - L_ADD(&ees->arrvtime, &inc); - } - } - else { - if (debug & DB_LOG_DELTAS) msyslog(LOG_ERR, - "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x", - DB_LOG_DELTAS, - ees->unit, ees->using_ramp, - sincelast, - (ees->last_step_secs)*2, - ees->last_step_secs); - if (debug & DB_PRINT_DELTAS) printf( - "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n", - DB_LOG_DELTAS, - ees->unit, ees->using_ramp, - sincelast, - (ees->last_step_secs)*2, - ees->last_step_secs); - } - - L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]); - L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]); - - if (call_pps_sample && !(debug & DB_NO_PPS)) { - /* Sigh -- it expects its args negated */ - L_NEG(&pps_arrvstamp); - /* - * I had to disable this here, since it appears there is no pointer to the - * peer structure. - * - (void) pps_sample(peer, &pps_arrvstamp); - */ - } - - /* Subtract off the local clock time stamp */ - L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime); - if (debug & DB_LOG_SAMPLES) msyslog(LOG_ERR, - "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s", - ees->unit, DB_LOG_DELTAS, n_sample, - ees->codeoffsets[n_sample].l_f, - ees->codeoffsets[n_sample].l_f / 4295, - pps_arrvstamp.l_f, - pps_arrvstamp.l_f /4295, - (debug & DB_NO_PPS) ? " [no PPS]" : ""); - - if (ees->nsamples++ == NCODES-1) ees_process(ees); - - /* Done! */ -} - - -/* offcompare - auxiliary comparison routine for offset sort */ - -#ifdef QSORT_USES_VOID_P -static int -offcompare( - const void *va, - const void *vb - ) -{ - const l_fp *a = (const l_fp *)va; - const l_fp *b = (const l_fp *)vb; - return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1); -} -#else -static int -offcompare( - const l_fp *a, - const l_fp *b - ) -{ - return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1); -} -#endif /* QSORT_USES_VOID_P */ - - -/* ees_process - process a pile of samples from the clock */ -static void -ees_process( - struct eesunit *ees - ) -{ - static int last_samples = -1; - register int i, j; - register int noff; - register l_fp *coffs = ees->codeoffsets; - l_fp offset, tmp; - double dispersion; /* ++++ */ - int lostsync, isinsync; - int samples = ees->nsamples; - int samplelog = 0; /* keep "gcc -Wall" happy ! */ - int samplereduce = (samples + 1) / 2; - double doffset; - - /* Reset things to zero so we don't have to worry later */ - ees_reset(ees); - - if (sloppyclockflag[ees->unit]) { - samplelog = (samples < 2) ? 0 : - (samples < 5) ? 1 : - (samples < 9) ? 2 : - (samples < 17) ? 3 : - (samples < 33) ? 4 : 5; - samplereduce = (1 << samplelog); - } - - if (samples != last_samples && - ((samples != (last_samples-1)) || samples < 3)) { - msyslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....", - samples, last_samples, samplereduce); - last_samples = samples; - } - if (samples < 1) return; - - /* If requested, dump the raw data we have in the buffer */ - if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:"); - - /* Sort the offsets, trim off the extremes, then choose one. */ - qsort((char *) coffs, (size_t)samples, sizeof(l_fp), offcompare); - - noff = samples; - i = 0; - while ((noff - i) > samplereduce) { - /* Trim off the sample which is further away - * from the median. We work this out by doubling - * the median, subtracting off the end samples, and - * looking at the sign of the answer, using the - * identity (c-b)-(b-a) == 2*b-a-c - */ - tmp = coffs[(noff + i)/2]; - L_ADD(&tmp, &tmp); - L_SUB(&tmp, &coffs[i]); - L_SUB(&tmp, &coffs[noff-1]); - if (L_ISNEG(&tmp)) noff--; else i++; - } - - /* If requested, dump the reduce data we have in the buffer */ - if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:"); - - /* What we do next depends on the setting of the sloppy clock flag. - * If it is on, average the remainder to derive our estimate. - * Otherwise, just pick a representative value from the remaining stuff - */ - if (sloppyclockflag[ees->unit]) { - offset.l_ui = offset.l_uf = 0; - for (j = i; j < noff; j++) - L_ADD(&offset, &coffs[j]); - for (j = samplelog; j > 0; j--) - L_RSHIFTU(&offset); - } - else offset = coffs[i+BESTSAMPLE]; - - /* Compute the dispersion as the difference between the - * lowest and highest offsets that remain in the - * consideration list. - * - * It looks like MOST clocks have MOD (max error), so halve it ! - */ - tmp = coffs[noff-1]; - L_SUB(&tmp, &coffs[i]); -#define FRACT_SEC(n) ((1 << 30) / (n/2)) - dispersion = LFPTOFP(&tmp) / 2; /* ++++ */ - if (debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) msyslog( - (debug & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO, - "I: [%x] Offset=%06d (%d), disp=%f%s [%d], %d %d=%d %d:%d %d=%d %d", - debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE), - offset.l_f / 4295, offset.l_f, - (dispersion * 1526) / 100, - (sloppyclockflag[ees->unit]) ? " by averaging" : "", - FRACT_SEC(10) / 4295, - (coffs[0].l_f) / 4295, - i, - (coffs[i].l_f) / 4295, - (coffs[samples/2].l_f) / 4295, - (coffs[i+BESTSAMPLE].l_f) / 4295, - noff-1, - (coffs[noff-1].l_f) / 4295, - (coffs[samples-1].l_f) / 4295); - - /* Are we playing silly wotsits ? - * If we are using all data, see if there is a "small" delta, - * and if so, blurr this with 3/4 of the delta from the last value - */ - if (ees->usealldata && ees->offset.l_uf) { - long diff = (long) (ees->offset.l_uf - offset.l_uf); - - /* is the delta small enough ? */ - if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) { - int samd = (64 * 4) / samples; - long new; - if (samd < 2) samd = 2; - new = offset.l_uf + ((diff * (samd -1)) / samd); - - /* Sign change -> need to fix up int part */ - if ((new & 0x80000000) != - (((long) offset.l_uf) & 0x80000000)) - { NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, "I: %lx != %lx (%lx %lx), so add %d", - new & 0x80000000, - ((long) offset.l_uf) & 0x80000000, - new, (long) offset.l_uf, - (new < 0) ? -1 : 1); - offset.l_ui += (new < 0) ? -1 : 1; - } - dispersion /= 4; - if (debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) msyslog( - (debug & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO, - "I: [%x] Smooth data: %ld -> %ld, dispersion now %f", - debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE), - ((long) offset.l_uf) / 4295, new / 4295, - (dispersion * 1526) / 100); - offset.l_uf = (unsigned long) new; - } - else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog( - (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO, - "[%x] No smooth as delta not %d < %ld < %d", - debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE), - - FRACT_SEC(100), diff, FRACT_SEC(100)); - } - else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog( - (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO, - "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)", - debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE), - ees->usealldata, ees->offset.l_f, ees->offset.l_uf, - offset.l_f, ees->offset.l_f - offset.l_f); - - /* Collect offset info for debugging info */ - ees->offset = offset; - ees->lowoffset = coffs[i]; - ees->highoffset = coffs[noff-1]; - - /* Determine synchronization status. Can be unsync'd either - * by a report from the clock or by a leap hold. - * - * Loss of the radio signal for a short time does not cause - * us to go unsynchronised, since the receiver keeps quite - * good time on its own. The spec says 20ms in 4 hours; the - * observed drift in our clock (Cambridge) is about a second - * a day, but even that keeps us within the inherent tolerance - * of the clock for about 15 minutes. Observation shows that - * the typical "short" outage is 3 minutes, so to allow us - * to ride out those, we will give it 5 minutes. - */ - lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0; - isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1; - - /* Done. Use time of last good, synchronised code as the - * reference time, and lastsampletime as the receive time. - */ - if (ees->fix_pending) { - msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n", - ees->fix_pending, ees->unit, offset.l_i, offset.l_f); - ees->fix_pending = 0; - } - LFPTOD(&offset, doffset); - refclock_receive(ees->peer); - ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL); -} - -/* msfees_poll - called by the transmit procedure */ -static void -msfees_poll( - int unit, - struct peer *peer - ) -{ - if (unit >= MAXUNITS) { - msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid", - unit); - return; - } - if (!unitinuse[unit]) { - msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused", - unit); - return; - } - - ees_process(eesunits[unit]); - - if ((current_time - eesunits[unit]->lasttime) > 150) - ees_event(eesunits[unit], CEVNT_FAULT); -} - - -#else -int refclock_msfees_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_mx4200.c b/contrib/ntp/ntpd/refclock_mx4200.c deleted file mode 100644 index bc694ad..0000000 --- a/contrib/ntp/ntpd/refclock_mx4200.c +++ /dev/null @@ -1,1654 +0,0 @@ -/* - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66. - * - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory. - * 4. The name of the University may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Modified: Marc Brett <marc.brett@westgeo.com> Sept, 1999. - * - * 1. Added support for alternate PPS schemes, with code mostly - * copied from the Oncore driver (Thanks, Poul-Henning Kamp). - * This code runs on SunOS 4.1.3 with ppsclock-1.6a1 and Solaris 7. - */ - - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_MX4200) && defined(HAVE_PPSAPI) - -#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> - -#include "mx4200.h" - -#ifdef HAVE_SYS_TERMIOS_H -# include <sys/termios.h> -#endif -#ifdef HAVE_SYS_PPSCLOCK_H -# include <sys/ppsclock.h> -#endif - -#include "ntp_sprintf.h" - -#ifndef HAVE_STRUCT_PPSCLOCKEV -struct ppsclockev { -# ifdef HAVE_STRUCT_TIMESPEC - struct timespec tv; -# else - struct timeval tv; -# endif - u_int serial; -}; -#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 - * ppsclock line discipline or streams module described in the - * Line Disciplines and Streams Drivers page. It also requires a - * gadget box and 1-PPS level converter, such as described in the - * Pulse-per-second (PPS) Signal Interfacing page. - * - * It's likely that other compatible Magnavox receivers such as the - * MX 4200D, MX 9212, MX 9012R, MX 9112 will be supported by this code. - */ - -/* - * Check this every time you edit the code! - */ -#define YEAR_LAST_MODIFIED 2000 - -/* - * GPS Definitions - */ -#define DEVICE "/dev/gps%d" /* device name and unit */ -#define SPEED232 B4800 /* baud */ - -/* - * Radio interface parameters - */ -#define PRECISION (-18) /* precision assumed (about 4 us) */ -#define REFID "GPS\0" /* reference id */ -#define DESCRIPTION "Magnavox MX4200 GPS Receiver" /* who we are */ -#define DEFFUDGETIME 0 /* default fudge time (ms) */ - -#define SLEEPTIME 32 /* seconds to wait for reconfig to complete */ - -/* - * Position Averaging. - */ -#define INTERVAL 1 /* Interval between position measurements (s) */ -#define AVGING_TIME 24 /* Number of hours to average */ -#define NOT_INITIALIZED -9999. /* initial pivot longitude */ - -/* - * MX4200 unit control structure. - */ -struct mx4200unit { - u_int pollcnt; /* poll message counter */ - u_int polled; /* Hand in a time sample? */ - u_int lastserial; /* last pps serial number */ - struct ppsclockev ppsev; /* PPS control structure */ - double avg_lat; /* average latitude */ - double avg_lon; /* average longitude */ - double avg_alt; /* average height */ - double central_meridian; /* central meridian */ - 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"; - -/* XXX should be somewhere else */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) -#ifndef __attribute__ -#define __attribute__(args) -#endif /* __attribute__ */ -#endif /* __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) */ -#else -#ifndef __attribute__ -#define __attribute__(args) -#endif /* __attribute__ */ -#endif /* __GNUC__ */ -/* XXX end */ - -/* - * Function prototypes - */ -static int mx4200_start P((int, struct peer *)); -static void mx4200_shutdown P((int, struct peer *)); -static void mx4200_receive P((struct recvbuf *)); -static void mx4200_poll P((int, struct peer *)); - -static char * mx4200_parse_t P((struct peer *)); -static char * mx4200_parse_p P((struct peer *)); -static char * mx4200_parse_s P((struct peer *)); -#ifdef QSORT_USES_VOID_P -int mx4200_cmpl_fp P((const void *, const void *)); -#else -int mx4200_cmpl_fp P((const l_fp *, const l_fp *)); -#endif /* not QSORT_USES_VOID_P */ -static int mx4200_config P((struct peer *)); -static void mx4200_ref P((struct peer *)); -static void mx4200_send P((struct peer *, char *, ...)) - __attribute__ ((format (printf, 2, 3))); -static u_char mx4200_cksum P((char *, int)); -static int mx4200_jday P((int, int, int)); -static void mx4200_debug P((struct peer *, char *, ...)) - __attribute__ ((format (printf, 2, 3))); -static int mx4200_pps P((struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_mx4200 = { - mx4200_start, /* start up driver */ - mx4200_shutdown, /* shut down driver */ - mx4200_poll, /* transmit poll message */ - noentry, /* not used (old mx4200_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old mx4200_buginfo) */ - NOFLAGS /* not used */ -}; - - - -/* - * mx4200_start - open the devices and initialize data for processing - */ -static int -mx4200_start( - int unit, - struct peer *peer - ) -{ - register struct mx4200unit *up; - struct refclockproc *pp; - int fd; - char gpsdev[20]; - - /* - * Open serial port - */ - (void)sprintf(gpsdev, DEVICE, unit); - if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_PPS))) { - return (0); - } - - /* - * Allocate unit structure - */ - if (!(up = (struct mx4200unit *) emalloc(sizeof(struct mx4200unit)))) { - perror("emalloc"); - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct mx4200unit)); - pp = peer->procptr; - pp->io.clock_recv = mx4200_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - - /* Ensure the receiver is properly configured */ - return mx4200_config(peer); -} - - -/* - * mx4200_shutdown - shut down the clock - */ -static void -mx4200_shutdown( - int unit, - struct peer *peer - ) -{ - register struct mx4200unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * mx4200_config - Configure the receiver - */ -static int -mx4200_config( - struct peer *peer - ) -{ - char tr_mode; - int add_mode; - register struct mx4200unit *up; - struct refclockproc *pp; - int mode; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* - * Initialize the unit variables - * - * STRANGE BEHAVIOUR WARNING: The fudge flags are not available - * at the time mx4200_start is called. These are set later, - * and so the code must be prepared to handle changing flags. - */ - up->sloppyclockflag = pp->sloppyclockflag; - if (pp->sloppyclockflag & CLK_FLAG2) { - up->moving = 1; /* Receiver on mobile platform */ - msyslog(LOG_DEBUG, "mx4200_config: mobile platform"); - } else { - up->moving = 0; /* Static Installation */ - } - up->pollcnt = 2; - up->polled = 0; - up->known = 0; - up->avg_lat = 0.0; - up->avg_lon = 0.0; - up->avg_alt = 0.0; - up->central_meridian = NOT_INITIALIZED; - 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) - */ - mx4200_send(peer, "%s,%03d,,%d,,,,,,", pmvxg, - PMVXG_S_PORTCONF, - /* control port output block Label */ - 1); /* clear current output control list (1=yes) */ - /* add/delete sentences from list */ - /* must be null */ - /* sentence output rate (sec) */ - /* precision for position output */ - /* nmea version for cga & gll output */ - /* pass-through control */ - mx4200_send(peer, "%s,%03d,,%d,,,,,,", pmvxg, - PMVXG_S_PORTCONF, 1); - - /* - * Request software configuration so we can syslog the firmware version - */ - mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_SOFTCONF); - - /* - * "001" Initialization/Mode Control, Part A - * Where ARE we? - */ - mx4200_send(peer, "%s,%03d,,,,,,,,,,", pmvxg, - PMVXG_S_INITMODEA); - /* day of month */ - /* month of year */ - /* year */ - /* gmt */ - /* latitude DDMM.MMMM */ - /* north/south */ - /* longitude DDDMM.MMMM */ - /* east/west */ - /* height */ - /* Altitude Reference 1=MSL */ - - /* - * "001" Initialization/Mode Control, Part B - * Start off in 2d/3d coast mode, holding altitude to last known - * value if only 3 satellites available. - */ - mx4200_send(peer, "%s,%03d,%d,,%.1f,%.1f,%d,%d,%d,%c,%d", - pmvxg, PMVXG_S_INITMODEB, - 3, /* 2d/3d coast */ - /* reserved */ - 0.1, /* hor accel fact as per Steve (m/s**2) */ - 0.1, /* ver accel fact as per Steve (m/s**2) */ - 10, /* vdop */ - 10, /* hdop limit as per Steve */ - 5, /* elevation limit as per Steve (deg) */ - 'U', /* time output mode (UTC) */ - 0); /* local time offset from gmt (HHHMM) */ - - /* - * "023" Time Recovery Configuration - * Get UTC time from a stationary receiver. - * (Set field 1 'D' == dynamic if we are on a moving platform). - * (Set field 1 'S' == static if we are not moving). - * (Set field 1 'K' == known position if we can initialize lat/lon/alt). - */ - - if (pp->sloppyclockflag & CLK_FLAG2) - up->moving = 1; /* Receiver on mobile platform */ - else - up->moving = 0; /* Static Installation */ - - up->pollcnt = 2; - if (up->moving) { - /* dynamic: solve for pos, alt, time, while moving */ - tr_mode = 'D'; - } else { - /* static: solve for pos, alt, time, while stationary */ - tr_mode = 'S'; - } - mx4200_send(peer, "%s,%03d,%c,%c,%c,%d,%d,%d,", pmvxg, - PMVXG_S_TRECOVCONF, - tr_mode, /* time recovery mode (see above ) */ - 'U', /* synchronize to UTC */ - 'A', /* always output a time pulse */ - 500, /* max time error in ns */ - 0, /* user bias in ns */ - 1); /* output "830" sentences to control port */ - /* Multi-satellite mode */ - - /* - * Output position information (to calculate fixed installation - * location) only if we are not moving - */ - if (up->moving) { - add_mode = 2; /* delete from list */ - } else { - add_mode = 1; /* add to list */ - } - - - /* - * "007" Control Port Configuration - * Output "021" position, height, velocity reports - */ - mx4200_send(peer, "%s,%03d,%03d,%d,%d,,%d,,,", pmvxg, - PMVXG_S_PORTCONF, - 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 */ - INTERVAL); /* sentence output rate (sec) */ - /* precision for position output */ - /* nmea version for cga & gll output */ - /* pass-through control */ - - return (1); -} - -/* - * mx4200_ref - Reconfigure unit as a reference station at a known position. - */ -static void -mx4200_ref( - struct peer *peer - ) -{ - register struct mx4200unit *up; - struct refclockproc *pp; - double minute, lat, lon, alt; - char lats[16], lons[16]; - char nsc, ewc; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* Should never happen! */ - if (up->moving) return; - - /* - * Set up to output status information in the near future - */ - up->log_time = current_time + SLEEPTIME; - - /* - * "007" Control Port Configuration - * Stop outputting "021" position, height, velocity reports - */ - mx4200_send(peer, "%s,%03d,%03d,%d,%d,,,,,", pmvxg, - PMVXG_S_PORTCONF, - PMVXG_D_PHV, /* 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 */ - - /* - * "001" Initialization/Mode Control, Part B - * Put receiver in fully-constrained 2d nav mode - */ - mx4200_send(peer, "%s,%03d,%d,,%.1f,%.1f,%d,%d,%d,%c,%d", - pmvxg, PMVXG_S_INITMODEB, - 2, /* 2d nav */ - /* reserved */ - 0.1, /* hor accel fact as per Steve (m/s**2) */ - 0.1, /* ver accel fact as per Steve (m/s**2) */ - 10, /* vdop */ - 10, /* hdop limit as per Steve */ - 5, /* elevation limit as per Steve (deg) */ - 'U', /* time output mode (UTC) */ - 0); /* local time offset from gmt (HHHMM) */ - - /* - * "023" Time Recovery Configuration - * Get UTC time from a stationary receiver. Solve for time only. - * This should improve the time resolution dramatically. - */ - mx4200_send(peer, "%s,%03d,%c,%c,%c,%d,%d,%d,", pmvxg, - PMVXG_S_TRECOVCONF, - 'K', /* known position: solve for time only */ - 'U', /* synchronize to UTC */ - 'A', /* always output a time pulse */ - 500, /* max time error in ns */ - 0, /* user bias in ns */ - 1); /* output "830" sentences to control port */ - /* Multi-satellite mode */ - - /* - * "000" Initialization/Mode Control - Part A - * Fix to our averaged position. - */ - if (up->central_meridian != NOT_INITIALIZED) { - up->avg_lon += up->central_meridian; - if (up->avg_lon < -180.0) up->avg_lon += 360.0; - if (up->avg_lon > 180.0) up->avg_lon -= 360.0; - } - - if (up->avg_lat >= 0.0) { - lat = up->avg_lat; - nsc = 'N'; - } else { - lat = up->avg_lat * (-1.0); - nsc = 'S'; - } - if (up->avg_lon >= 0.0) { - lon = up->avg_lon; - ewc = 'E'; - } else { - lon = up->avg_lon * (-1.0); - ewc = 'W'; - } - alt = up->avg_alt; - minute = (lat - (double)(int)lat) * 60.0; - sprintf(lats,"%02d%02.4f", (int)lat, minute); - minute = (lon - (double)(int)lon) * 60.0; - sprintf(lons,"%03d%02.4f", (int)lon, minute); - - mx4200_send(peer, "%s,%03d,,,,,%s,%c,%s,%c,%.2f,%d", pmvxg, - PMVXG_S_INITMODEA, - /* day of month */ - /* month of year */ - /* year */ - /* gmt */ - lats, /* latitude DDMM.MMMM */ - nsc, /* north/south */ - lons, /* longitude DDDMM.MMMM */ - ewc, /* east/west */ - alt, /* Altitude */ - 1); /* Altitude Reference (0=WGS84 ellipsoid, 1=MSL geoid)*/ - - msyslog(LOG_DEBUG, - "mx4200: reconfig to fixed location: %s %c, %s %c, %.2f m", - lats, nsc, lons, ewc, alt ); - -} - -/* - * mx4200_poll - mx4200 watchdog routine - */ -static void -mx4200_poll( - int unit, - struct peer *peer - ) -{ - register struct mx4200unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* - * You don't need to poll this clock. It puts out timecodes - * once per second. If asked for a timestamp, take note. - * The next time a timecode comes in, it will be fed back. - */ - - /* - * If we haven't had a response in a while, reset the receiver. - */ - if (up->pollcnt > 0) { - up->pollcnt--; - } else { - refclock_report(peer, CEVNT_TIMEOUT); - - /* - * Request a "000" status message which should trigger a - * reconfig - */ - mx4200_send(peer, "%s,%03d", - "CDGPQ", /* query from CDU to GPS */ - PMVXG_D_STATUS); /* label of desired sentence */ - } - - /* - * polled every 64 seconds. Ask mx4200_receive to hand in - * a timestamp. - */ - up->polled = 1; - pp->polls++; - - /* - * Output receiver status information. - */ - if ((up->log_time > 0) && (current_time > up->log_time)) { - up->log_time = 0; - /* - * Output the following messages once, for debugging. - * "004" Mode Data - * "523" Time Recovery Parameters - */ - mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_MODEDATA); - mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_TRECOVUSEAGE); - } -} - -static char char2hex[] = "0123456789ABCDEF"; - -/* - * mx4200_receive - receive gps data - */ -static void -mx4200_receive( - struct recvbuf *rbufp - ) -{ - register struct mx4200unit *up; - struct refclockproc *pp; - struct peer *peer; - char *cp; - int sentence_type; - u_char ck; - - /* - * Initialize pointers and read the timecode and timestamp. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* - * If operating mode has been changed, then reinitialize the receiver - * before doing anything else. - */ - if ((pp->sloppyclockflag & CLK_FLAG2) != - (up->sloppyclockflag & CLK_FLAG2)) { - up->sloppyclockflag = pp->sloppyclockflag; - mx4200_debug(peer, - "mx4200_receive: mode switch: reset receiver\n"); - mx4200_config(peer); - return; - } - up->sloppyclockflag = pp->sloppyclockflag; - - /* - * Read clock output. Automatically handles STREAMS, CLKLDISC. - */ - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); - - /* - * There is a case where <cr><lf> generates 2 timestamps. - */ - if (pp->lencode == 0) - return; - - up->pollcnt = 2; - pp->a_lastcode[pp->lencode] = '\0'; - record_clock_stats(&peer->srcadr, pp->a_lastcode); - mx4200_debug(peer, "mx4200_receive: %d %s\n", - pp->lencode, pp->a_lastcode); - - /* - * The structure of the control port sentences is based on the - * NMEA-0183 Standard for interfacing Marine Electronics - * Navigation Devices (Version 1.5) - * - * $PMVXG,XXX, ....................*CK<cr><lf> - * - * $ Sentence Start Identifier (reserved char) - * (Start-of-Sentence Identifier) - * P Special ID (Proprietary) - * MVX Originator ID (Magnavox) - * G Interface ID (GPS) - * , Field Delimiters (reserved char) - * XXX Sentence Type - * ...... Data - * * Checksum Field Delimiter (reserved char) - * CK Checksum - * <cr><lf> Carriage-Return/Line Feed (reserved chars) - * (End-of-Sentence Identifier) - * - * Reject if any important landmarks are missing. - */ - cp = pp->a_lastcode + pp->lencode - 3; - if (cp < pp->a_lastcode || *pp->a_lastcode != '$' || cp[0] != '*' ) { - mx4200_debug(peer, "mx4200_receive: bad format\n"); - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Check and discard the checksum - */ - ck = mx4200_cksum(&pp->a_lastcode[1], pp->lencode - 4); - if (char2hex[ck >> 4] != cp[1] || char2hex[ck & 0xf] != cp[2]) { - mx4200_debug(peer, "mx4200_receive: bad checksum\n"); - refclock_report(peer, CEVNT_BADREPLY); - return; - } - *cp = '\0'; - - /* - * Get the sentence type. - */ - sentence_type = 0; - if ((cp = strchr(pp->a_lastcode, ',')) == NULL) { - mx4200_debug(peer, "mx4200_receive: no sentence\n"); - refclock_report(peer, CEVNT_BADREPLY); - return; - } - cp++; - sentence_type = strtol(cp, &cp, 10); - - /* - * Process the sentence according to its type. - */ - switch (sentence_type) { - - /* - * "000" Status message - */ - case PMVXG_D_STATUS: - /* - * XXX - * Since we configure the receiver to not give us status - * messages and since the receiver outputs status messages by - * default after being reset to factory defaults when sent the - * "$PMVXG,018,C\r\n" message, any status message we get - * indicates the reciever needs to be initialized; thus, it is - * not necessary to decode the status message. - */ - if ((cp = mx4200_parse_s(peer)) != NULL) { - mx4200_debug(peer, - "mx4200_receive: status: %s\n", cp); - } - mx4200_debug(peer, "mx4200_receive: reset receiver\n"); - mx4200_config(peer); - break; - - /* - * "021" Position, Height, Velocity message, - * if we are still averaging our position - */ - 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); - } - } - break; - - /* - * Print to the syslog: - * "004" Mode Data - * "030" Software Configuration - * "523" Time Recovery Parameters Currently in Use - */ - 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); - } - break; - - /* - * "830" Time Recovery Results message - */ - case PMVXG_D_TRECOVOUT: - - /* - * Capture the last PPS signal. - * Precision timestamp is returned in pp->lastrec - */ - if (mx4200_pps(peer) != NULL) { - mx4200_debug(peer, "mx4200_receive: pps failure\n"); - refclock_report(peer, CEVNT_FAULT); - return; - } - - - /* - * Parse the time recovery message, and keep the info - * to print the pretty billboards. - */ - if ((cp = mx4200_parse_t(peer)) != NULL) { - mx4200_debug(peer, "mx4200_receive: time: %s\n", cp); - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Add the new sample to a median filter. - */ - if (!refclock_process(pp)) { - mx4200_debug(peer,"mx4200_receive: offset: %.6f\n", - pp->offset); - refclock_report(peer, CEVNT_BADTIME); - return; - } - - /* - * The clock will blurt a timecode every second but we only - * want one when polled. If we havn't been polled, bail out. - */ - if (!up->polled) - return; - - /* - * Return offset and dispersion to control module. We use - * lastrec as both the reference time and receive time in - * order to avoid being cute, like setting the reference time - * later than the receive time, which may cause a paranoid - * protocol module to chuck out the data. - */ - mx4200_debug(peer, "mx4200_receive: process time: "); - mx4200_debug(peer, "%4d-%03d %02d:%02d:%02d at %s, %.6f\n", - pp->year, pp->day, pp->hour, pp->minute, pp->second, - prettydate(&pp->lastrec), pp->offset); - pp->lastref = pp->lastrec; - refclock_receive(peer); - - /* - * We have succeeded in answering the poll. - * Turn off the flag and return - */ - up->polled = 0; - break; - - /* - * Ignore all other sentence types - */ - default: - break; - - } /* switch (sentence_type) */ - - return; -} - - -/* - * Parse a mx4200 time recovery message. Returns a string if error. - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,830,T,YYYY,MM,DD,HH:MM:SS,U,S,FFFFFF,PPPPP,BBBBBB,LL - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 830=Time Recovery Results - * This sentence is output approximately 1 second - * preceding the 1PPS output. It indicates the - * exact time of the next pulse, whether or not the - * time mark will be valid (based on operator-specified - * error tolerance), the time to which the pulse is - * synchronized, the receiver operating mode, - * and the time error of the *last* 1PPS output. - * 1 char Time Mark Valid: T=Valid, F=Not Valid - * 2 int Year: 1993- - * 3 int Month of Year: 1-12 - * 4 int Day of Month: 1-31 - * 5 int Time of Day: HH:MM:SS - * 6 char Time Synchronization: U=UTC, G=GPS - * 7 char Time Recovery Mode: D=Dynamic, S=Static, - * K=Known Position, N=No Time Recovery - * 8 int Oscillator Offset: The filter's estimate of the oscillator - * frequency error, in parts per billion (ppb). - * 9 int Time Mark Error: The computed error of the *last* pulse - * output, in nanoseconds. - * 10 int User Time Bias: Operator specified bias, in nanoseconds - * 11 int Leap Second Flag: Indicates that a leap second will - * occur. This value is usually zero, except during - * the week prior to the leap second occurrence, when - * this value will be set to +1 or -1. A value of - * +1 indicates that GPS time will be 1 second - * further ahead of UTC time. - * - */ -static char * -mx4200_parse_t( - struct peer *peer - ) -{ - struct refclockproc *pp; - struct mx4200unit *up; - char time_mark_valid, time_sync, op_mode; - int sentence_type, valid; - int year, day_of_year, month, day_of_month; - int hour, minute, second, leapsec; - int 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", - &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); - - if (sentence_type != PMVXG_D_TRECOVOUT) - return ("wrong rec-type"); - - switch (time_mark_valid) { - case 'T': - valid = 1; - break; - case 'F': - valid = 0; - break; - default: - return ("bad pulse-valid"); - } - - switch (time_sync) { - case 'G': - return ("synchronized to GPS; should be UTC"); - case 'U': - break; /* UTC -> ok */ - default: - return ("not synchronized to UTC"); - } - - /* - * Check for insane time (allow for possible leap seconds) - */ - if (second > 60 || minute > 59 || hour > 23 || - second < 0 || minute < 0 || hour < 0) { - mx4200_debug(peer, - "mx4200_parse_t: bad time %02d:%02d:%02d", - hour, minute, second); - if (leapsec != 0) - mx4200_debug(peer, " (leap %+d\n)", leapsec); - mx4200_debug(peer, "\n"); - refclock_report(peer, CEVNT_BADTIME); - return ("bad time"); - } - if ( second == 60 ) { - msyslog(LOG_DEBUG, - "mx4200: leap second! %02d:%02d:%02d", - hour, minute, second); - } - - /* - * Check for insane date - * (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_LAST_MODIFIED) { - mx4200_debug(peer, - "mx4200_parse_t: bad date (%4d-%02d-%02d)\n", - year, month, day_of_month); - refclock_report(peer, CEVNT_BADDATE); - return ("bad date"); - } - - /* - * Silly Hack for MX4200: - * ASCII message is for *next* 1PPS signal, but we have the - * timestamp for the *last* 1PPS signal. So we have to subtract - * a second. Discard if we are on a month boundary to avoid - * possible leap seconds and leap days. - */ - second--; - if (second < 0) { - second = 59; - minute--; - if (minute < 0) { - minute = 59; - hour--; - if (hour < 0) { - hour = 23; - day_of_month--; - if (day_of_month < 1) { - return ("sorry, month boundary"); - } - } - } - } - - /* - * Calculate Julian date - */ - if (!(day_of_year = mx4200_jday(year, month, day_of_month))) { - mx4200_debug(peer, - "mx4200_parse_t: bad julian date %d (%4d-%02d-%02d)\n", - day_of_year, year, month, day_of_month); - refclock_report(peer, CEVNT_BADDATE); - return("invalid julian date"); - } - - /* - * Setup leap second indicator - */ - switch (leapsec) { - case 0: - pp->leap = LEAP_NOWARNING; - break; - case 1: - pp->leap = LEAP_ADDSECOND; - break; - case -1: - pp->leap = LEAP_DELSECOND; - break; - default: - pp->leap = LEAP_NOTINSYNC; - } - - /* - * Any change to the leap second warning status? - */ - if (leapsec != up->last_leap ) { - msyslog(LOG_DEBUG, - "mx4200: leap second warning: %d to %d (%d)", - up->last_leap, leapsec, pp->leap); - } - up->last_leap = leapsec; - - /* - * Copy time data for billboard monitoring. - */ - - pp->year = year; - pp->day = day_of_year; - pp->hour = hour; - pp->minute = minute; - pp->second = second; - - /* - * Toss if sentence is marked invalid - */ - if (!valid || pp->leap == LEAP_NOTINSYNC) { - mx4200_debug(peer, "mx4200_parse_t: time mark not valid\n"); - refclock_report(peer, CEVNT_BADTIME); - return ("pulse invalid"); - } - - return (NULL); -} - -/* - * Calculate the checksum - */ -static u_char -mx4200_cksum( - register char *cp, - register int n - ) -{ - register u_char ck; - - for (ck = 0; n-- > 0; cp++) - ck ^= *cp; - return (ck); -} - -/* - * Tables to compute the day of year. Viva la leap. - */ -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}; - -/* - * Calculate the the Julian Day - */ -static int -mx4200_jday( - int year, - int month, - int day_of_month - ) -{ - register int day, i; - int leap_year; - - /* - * Is this a leap year ? - */ - if (year % 4) { - leap_year = 0; /* FALSE */ - } else { - if (year % 100) { - leap_year = 1; /* TRUE */ - } else { - if (year % 400) { - leap_year = 0; /* FALSE */ - } else { - leap_year = 1; /* TRUE */ - } - } - } - - /* - * Calculate the Julian Date - */ - day = day_of_month; - - if (leap_year) { - /* a leap year */ - if (day > day2tab[month - 1]) { - return (0); - } - for (i = 0; i < month - 1; i++) - day += day2tab[i]; - } else { - /* not a leap year */ - if (day > day1tab[month - 1]) { - return (0); - } - for (i = 0; i < month - 1; i++) - day += day1tab[i]; - } - return (day); -} - -/* - * Parse a mx4200 position/height/velocity sentence. - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,021,SSSSSS.SS,DDMM.MMMM,N,DDDMM.MMMM,E,HHHHH.H,GGGG.G,EEEE.E,WWWW.W,MM - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 021=Position, Height Velocity Data - * This sentence gives the receiver position, height, - * navigation mode, and velocity north/east. - * *This sentence is intended for post-analysis - * applications.* - * 1 float UTC measurement time (seconds into week) - * 2 float WGS-84 Lattitude (degrees, minutes) - * 3 char N=North, S=South - * 4 float WGS-84 Longitude (degrees, minutes) - * 5 char E=East, W=West - * 6 float Altitude (meters above mean sea level) - * 7 float Geoidal height (meters) - * 8 float East velocity (m/sec) - * 9 float West Velocity (m/sec) - * 10 int Navigation Mode - * Mode if navigating: - * 1 = Position from remote device - * 2 = 2-D position - * 3 = 3-D position - * 4 = 2-D differential position - * 5 = 3-D differential position - * 6 = Static - * 8 = Position known -- reference station - * 9 = Position known -- Navigator - * Mode if not navigating: - * 51 = Too few satellites - * 52 = DOPs too large - * 53 = Position STD too large - * 54 = Velocity STD too large - * 55 = Too many iterations for velocity - * 56 = Too many iterations for position - * 57 = 3 sat startup failed - * 58 = Command abort - */ -static char * -mx4200_parse_p( - struct peer *peer - ) -{ - struct refclockproc *pp; - struct mx4200unit *up; - int sentence_type, mode; - double mtime, lat, lon, alt, geoid, vele, veln; - char north_south, east_west; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* 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); - - /* Sentence type */ - if (sentence_type != PMVXG_D_PHV) - return ("wrong rec-type"); - - /* - * return if not navigating - */ - if (mode > 10) - return ("not navigating"); - if (mode != 3 && mode != 5) - return ("not navigating in 3D"); - - /* Latitude (always +ve) and convert DDMM.MMMM to decimal */ - if (lat < 0.0) return ("negative latitude"); - if (lat > 9000.0) lat = 9000.0; - lat *= 0.01; - lat = ((int)lat) + (((lat - (int)lat)) * 1.6666666666666666); - - /* North/South */ - switch (north_south) { - case 'N': - break; - case 'S': - lat *= -1.0; - break; - default: - return ("invalid north/south indicator"); - } - - /* Longitude (always +ve) and convert DDDMM.MMMM to decimal */ - if (lon < 0.0) return ("negative longitude"); - if (lon > 180.0) lon = 180.0; - lon *= 0.01; - lon = ((int)lon) + (((lon - (int)lon)) * 1.6666666666666666); - - /* East/West */ - switch (east_west) { - case 'E': - break; - case 'W': - lon *= -1.0; - break; - default: - return ("invalid east/west indicator"); - } - - /* - * Normalize longitude to near 0 degrees. - * Assume all data are clustered around first reading. - */ - if (up->central_meridian == NOT_INITIALIZED) { - up->central_meridian = lon; - mx4200_debug(peer, - "mx4200_receive: central meridian = %.9f \n", - up->central_meridian); - } - lon -= up->central_meridian; - if (lon < -180.0) lon += 360.0; - if (lon > 180.0) lon -= 360.0; - - /* - * Calculate running averages - */ - - 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; - - up->N_fixes += 1.0; - - up->avg_lon /= up->N_fixes; - up->avg_lat /= up->N_fixes; - up->avg_alt /= up->N_fixes; - - 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); -} - -/* - * Parse a mx4200 Status sentence - * Parse a mx4200 Mode Data sentence - * Parse a mx4200 Software Configuration sentence - * Parse a mx4200 Time Recovery Parameters Currently in Use sentence - * (used only for logging raw strings) - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,000,XXX,XX,X,HHMM,X - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 000=Status. - * Returns status of the receiver to the controller. - * 1 Current Receiver Status: - * ACQ = Satellite re-acquisition - * ALT = Constellation selection - * COR = Providing corrections (for reference stations only) - * IAC = Initial acquisition - * IDL = Idle, no satellites - * NAV = Navigation - * STS = Search the Sky (no almanac available) - * TRK = Tracking - * 2 Number of satellites that should be visible - * 3 Number of satellites being tracked - * 4 Time since last navigation status if not currently navigating - * (hours, minutes) - * 5 Initialization status: - * 0 = Waiting for initialization parameters - * 1 = Initialization completed - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,004,C,R,D,H.HH,V.VV,TT,HHHH,VVVV,T - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 004=Software Configuration. - * Defines the navigation mode and criteria for - * acceptable navigation for the receiver. - * 1 Constrain Altitude Mode: - * 0 = Auto. Constrain altitude (2-D solution) and use - * manual altitude input when 3 sats avalable. Do - * not constrain altitude (3-D solution) when 4 sats - * available. - * 1 = Always constrain altitude (2-D solution). - * 2 = Never constrain altitude (3-D solution). - * 3 = Coast. Constrain altitude (2-D solution) and use - * last GPS altitude calculation when 3 sats avalable. - * Do not constrain altitude (3-D solution) when 4 sats - * available. - * 2 Altitude Reference: (always 0 for MX4200) - * 0 = Ellipsoid - * 1 = Geoid (MSL) - * 3 Differential Navigation Control: - * 0 = Disabled - * 1 = Enabled - * 4 Horizontal Acceleration Constant (m/sec**2) - * 5 Vertical Acceleration Constant (m/sec**2) (0 for MX4200) - * 6 Tracking Elevation Limit (degrees) - * 7 HDOP Limit - * 8 VDOP Limit - * 9 Time Output Mode: - * U = UTC - * L = Local time - * 10 Local Time Offset (minutes) (absent on MX4200) - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,030,NNNN,FFF - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 030=Software Configuration. - * This sentence contains the navigation processor - * and baseband firmware version numbers. - * 1 Nav Processor Version Number - * 2 Baseband Firmware Version Number - * - * A typical message looks like this. Checksum has already been stripped. - * - * $PMVXG,523,M,S,M,EEEE,BBBBBB,C,R - * - * Field Field Contents - * ----- -------------- - * Block Label: $PMVXG - * Sentence Type: 523=Time Recovery Parameters Currently in Use. - * This sentence contains the configuration of the - * time recovery feature of the receiver. - * 1 Time Recovery Mode: - * D = Dynamic; solve for position and time while moving - * S = Static; solve for position and time while stationary - * K = Known position input, solve for time only - * N = No time recovery - * 2 Time Synchronization: - * U = UTC time - * G = GPS time - * 3 Time Mark Mode: - * A = Always output a time pulse - * V = Only output time pulse if time is valid (as determined - * by Maximum Time Error) - * 4 Maximum Time Error - the maximum error (in nanoseconds) for - * which a time mark will be considered valid. - * 5 User Time Bias - external bias in nanoseconds - * 6 Time Message Control: - * 0 = Do not output the time recovery message - * 1 = Output the time recovery message (record 830) to - * Control port - * 2 = Output the time recovery message (record 830) to - * Equipment port - * 7 Reserved - * 8 Position Known PRN (absent on MX 4200) - * - */ -static char * -mx4200_parse_s( - struct peer *peer - ) -{ - struct refclockproc *pp; - struct mx4200unit *up; - int sentence_type; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - sscanf ( pp->a_lastcode, "$PMVXG,%d", &sentence_type); - - /* Sentence type */ - switch (sentence_type) { - - case PMVXG_D_STATUS: - msyslog(LOG_DEBUG, - "mx4200: status: %s", pp->a_lastcode); - break; - case PMVXG_D_MODEDATA: - msyslog(LOG_DEBUG, - "mx4200: mode data: %s", pp->a_lastcode); - break; - case PMVXG_D_SOFTCONF: - msyslog(LOG_DEBUG, - "mx4200: firmware configuration: %s", pp->a_lastcode); - break; - case PMVXG_D_TRECOVUSEAGE: - msyslog(LOG_DEBUG, - "mx4200: time recovery parms: %s", pp->a_lastcode); - break; - default: - return ("wrong rec-type"); - } - - return (NULL); -} - -/* - * Process a PPS signal, placing a timestamp in pp->lastrec. - */ -static int -mx4200_pps( - struct peer *peer - ) -{ - int temp_serial; - struct refclockproc *pp; - struct mx4200unit *up; - - struct timespec timeout; - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - /* - * Grab the timestamp of the PPS signal. - */ - 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: 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->pps_i.assert_sequence) { - mx4200_debug(peer, - "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->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 { - mx4200_debug(peer, "mx4200_pps: missed %d pps events\n", - up->pps_i.assert_sequence - up->lastserial - 1); - } - refclock_report(peer, CEVNT_FAULT); - } - up->lastserial = up->pps_i.assert_sequence; - - /* - * Return the timestamp in 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); -} - -/* - * mx4200_debug - print debug messages - */ -#if defined(__STDC__) -static void -mx4200_debug(struct peer *peer, char *fmt, ...) -#else -static void -mx4200_debug(peer, fmt, va_alist) - struct peer *peer; - char *fmt; -#endif /* __STDC__ */ -{ - va_list ap; - struct refclockproc *pp; - struct mx4200unit *up; - - if (debug) { - -#if defined(__STDC__) - va_start(ap, fmt); -#else - va_start(ap); -#endif /* __STDC__ */ - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - - /* - * Print debug message to stdout - * In the future, we may want to get get more creative... - */ - vprintf(fmt, ap); - - va_end(ap); - } -} - -/* - * Send a character string to the receiver. Checksum is appended here. - */ -#if defined(__STDC__) -static void -mx4200_send(struct peer *peer, char *fmt, ...) -#else -static void -mx4200_send(peer, fmt, va_alist) - struct peer *peer; - char *fmt; - va_dcl -#endif /* __STDC__ */ -{ - struct refclockproc *pp; - struct mx4200unit *up; - - register char *cp; - register int n, m; - va_list ap; - char buf[1024]; - u_char ck; - -#if defined(__STDC__) - va_start(ap, fmt); -#else - va_start(ap); -#endif /* __STDC__ */ - - pp = peer->procptr; - up = (struct mx4200unit *)pp->unitptr; - - cp = buf; - *cp++ = '$'; - n = VSNPRINTF((cp, sizeof(buf) - 1, fmt, ap)); - ck = mx4200_cksum(cp, n); - cp += n; - ++n; - n += SNPRINTF((cp, sizeof(buf) - n - 5, "*%02X\r\n", ck)); - - m = write(pp->io.fd, buf, (unsigned)n); - if (m < 0) - msyslog(LOG_ERR, "mx4200_send: write: %m (%s)", buf); - mx4200_debug(peer, "mx4200_send: %d %s\n", m, buf); - va_end(ap); -} - -#else -int refclock_mx4200_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_neoclock4x.c b/contrib/ntp/ntpd/refclock_neoclock4x.c deleted file mode 100644 index 082b1cf..0000000 --- a/contrib/ntp/ntpd/refclock_neoclock4x.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * - * Refclock_neoclock4x.c - * - NeoClock4X driver for DCF77 or FIA Timecode - * - * Date: 2003-07-07 v1.13 - * - * see http://www.linum.com/redir/jump/id=neoclock4x&action=redir - * for details about the NeoClock4X device - * - * Copyright (C) 2002-2003 by Linum Software GmbH <neoclock4x@linum.com> - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#if defined(REFCLOCK) && (defined(CLOCK_NEOCLOCK4X)) - -#include <unistd.h> -#include <sys/time.h> -#include <sys/types.h> -#include <termios.h> -#include <sys/ioctl.h> -#include <ctype.h> - -#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 - -/* - * If you want the driver for whatever reason to not use - * the TX line to send anything to your NeoClock4X - * device you must tell the NTP refclock driver which - * firmware you NeoClock4X device uses. - * - * If you want to enable this feature change the "#if 0" - * line to "#if 1" and make sure that the defined firmware - * matches the firmware off your NeoClock4X receiver! - * - */ - -#if 0 -#define NEOCLOCK4X_FIRMWARE NEOCLOCK4X_FIRMWARE_VERSION_A -#endif - -#define NEOCLOCK4X_FIRMWARE_VERSION_A 'A' - -#define NEOCLOCK4X_TIMECODELEN 37 - -#define NEOCLOCK4X_OFFSET_SERIAL 3 -#define NEOCLOCK4X_OFFSET_RADIOSIGNAL 9 -#define NEOCLOCK4X_OFFSET_DAY 12 -#define NEOCLOCK4X_OFFSET_MONTH 14 -#define NEOCLOCK4X_OFFSET_YEAR 16 -#define NEOCLOCK4X_OFFSET_HOUR 18 -#define NEOCLOCK4X_OFFSET_MINUTE 20 -#define NEOCLOCK4X_OFFSET_SECOND 22 -#define NEOCLOCK4X_OFFSET_HSEC 24 -#define NEOCLOCK4X_OFFSET_DOW 26 -#define NEOCLOCK4X_OFFSET_TIMESOURCE 28 -#define NEOCLOCK4X_OFFSET_DSTSTATUS 29 -#define NEOCLOCK4X_OFFSET_QUARZSTATUS 30 -#define NEOCLOCK4X_OFFSET_ANTENNA1 31 -#define NEOCLOCK4X_OFFSET_ANTENNA2 33 -#define NEOCLOCK4X_OFFSET_CRC 35 - -#define NEOCLOCK4X_DRIVER_VERSION "1.12 (2003-01-10)" - -struct neoclock4x_unit { - l_fp laststamp; /* last receive timestamp */ - short unit; /* NTP refclock unit number */ - u_long polled; /* flag to detect noreplies */ - char leap_status; /* leap second flag */ - int recvnow; - - char firmware[80]; - char firmwaretag; - char serial[7]; - char radiosignal[4]; - char timesource; - char dststatus; - char quarzstatus; - int antenna1; - int antenna2; - int utc_year; - int utc_month; - int utc_day; - int utc_hour; - int utc_minute; - int utc_second; - int utc_msec; -}; - -static int neoclock4x_start P((int, struct peer *)); -static void neoclock4x_shutdown P((int, struct peer *)); -static void neoclock4x_receive P((struct recvbuf *)); -static void neoclock4x_poll P((int, struct peer *)); -static void neoclock4x_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); - -static int neol_atoi_len P((const char str[], int *, int)); -static int neol_hexatoi_len P((const char str[], int *, int)); -static void neol_jdn_to_ymd P((unsigned long, int *, int *, int *)); -static void neol_localtime P((unsigned long, int* , int*, int*, int*, int*, int*)); -static unsigned long neol_mktime P((int, int, int, int, int, int)); -#if 0 -static void neol_mdelay P((int)); -#endif -#if !defined(NEOCLOCK4X_FIRMWARE) -static int neol_query_firmware P((int, int, char *, int)); -static int neol_check_firmware P((int, const char*, char *)); -#endif - -struct refclock refclock_neoclock4x = { - neoclock4x_start, /* start up driver */ - neoclock4x_shutdown, /* shut down driver */ - neoclock4x_poll, /* transmit poll message */ - neoclock4x_control, - noentry, /* initialize driver (not used) */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - -static int -neoclock4x_start(int unit, - struct peer *peer) -{ - struct neoclock4x_unit *up; - struct refclockproc *pp; - int fd; - char dev[20]; - int sl232; -#if defined(HAVE_TERMIOS) - struct termios termsettings; -#endif -#if !defined(NEOCLOCK4X_FIRMWARE) - int tries; -#endif - - (void) snprintf(dev, sizeof(dev)-1, "/dev/neoclock4x-%d", unit); - - /* LDISC_STD, LDISC_RAW - * Open serial port. Use CLK line discipline, if available. - */ - fd = refclock_open(dev, B2400, LDISC_CLK); - if(fd <= 0) - { - return (0); - } - -#if defined(HAVE_TERMIOS) - if(tcgetattr(fd, &termsettings) < 0) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit); - (void) close(fd); - return (0); - } - - /* 2400 Baud 8N2 */ - termsettings.c_cflag &= ~PARENB; - termsettings.c_cflag |= CSTOPB; - termsettings.c_cflag &= ~CSIZE; - termsettings.c_cflag |= CS8; - - if(tcsetattr(fd, TCSANOW, &termsettings) < 0) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit); - (void) close(fd); - return (0); - } -#elif defined(HAVE_SYSV_TTYS) - if(ioctl(fd, TCGETA, &termsettings) < 0) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): (TCGETA) can't query serial port settings: %m", unit); - (void) close(fd); - return (0); - } - - /* 2400 Baud 8N2 */ - termsettings.c_cflag &= ~PARENB; - termsettings.c_cflag |= CSTOPB; - termsettings.c_cflag &= ~CSIZE; - termsettings.c_cflag |= CS8; - - if(ioctl(fd, TCSETA, &termsettings) < 0) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): (TSGETA) can't set serial port 2400 8N2: %m", unit); - (void) close(fd); - return (0); - } -#else - msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set port to 2400 8N2 with this OS!", unit); - (void) close(fd); - return (0); -#endif - -#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) - /* turn on RTS, and DTR for power supply */ - /* NeoClock4x is powered from serial line */ - if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit); - (void) close(fd); - return (0); - } -#ifdef TIOCM_RTS - sl232 = sl232 | TIOCM_DTR | TIOCM_RTS; /* turn on RTS, and DTR for power supply */ -#else - sl232 = sl232 | CIOCM_DTR | CIOCM_RTS; /* turn on RTS, and DTR for power supply */ -#endif - if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit); - (void) close(fd); - return (0); - } -#else - msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set DTR/RTS to power NeoClock4X with this OS!", - unit); - (void) close(fd); - return (0); -#endif - - up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit)); - if(!(up)) - { - msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit); - (void) close(fd); - return (0); - } - - memset((char *)up, 0, sizeof(struct neoclock4x_unit)); - pp = peer->procptr; - pp->clockdesc = "NeoClock4X"; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = neoclock4x_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - /* - * no fudge time is given by user! - * use 169.583333 ms to compensate the serial line delay - * formula is: - * 2400 Baud / 11 bit = 218.18 charaters per second - * (NeoClock4X timecode len) - */ - pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0; - - /* - * Initialize miscellaneous variables - */ - peer->precision = -10; - peer->burst = NSTAGE; - memcpy((char *)&pp->refid, "neol", 4); - - up->leap_status = 0; - up->unit = unit; - strcpy(up->firmware, "?"); - up->firmwaretag = '?'; - strcpy(up->serial, "?"); - strcpy(up->radiosignal, "?"); - up->timesource = '?'; - up->dststatus = '?'; - up->quarzstatus = '?'; - up->antenna1 = -1; - up->antenna2 = -1; - up->utc_year = 0; - up->utc_month = 0; - up->utc_day = 0; - up->utc_hour = 0; - up->utc_minute = 0; - up->utc_second = 0; - up->utc_msec = 0; - -#if defined(NEOCLOCK4X_FIRMWARE) -#if NEOCLOCK4X_FIRMWARE == NEOCLOCK4X_FIRMWARE_VERSION_A - strcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)"); - up->firmwaretag = 'A'; -#else - msyslog(LOG_EMERG, "NeoClock4X(%d): Unkown firmware defined at compile time for NeoClock4X", - unit); - (void) close(fd); - pp->io.fd = -1; - free(pp->unitptr); - pp->unitptr = NULL; - return (0); -#endif -#else - for(tries=0; tries < 5; tries++) - { - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_INFO, "NeoClock4X(%d): checking NeoClock4X firmware version (%d/5)", unit, tries); - /* wait 3 seconds for receiver to power up */ - sleep(3); - if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware))) - { - break; - } - } - - /* can I handle this firmware version? */ - if(!neol_check_firmware(up->unit, up->firmware, &up->firmwaretag)) - { - (void) close(fd); - pp->io.fd = -1; - free(pp->unitptr); - pp->unitptr = NULL; - return (0); - } -#endif - - if(!io_addclock(&pp->io)) - { - msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m", unit); - (void) close(fd); - pp->io.fd = -1; - free(pp->unitptr); - pp->unitptr = NULL; - return (0); - } - - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit); - - return (1); -} - -static void -neoclock4x_shutdown(int unit, - struct peer *peer) -{ - struct neoclock4x_unit *up; - struct refclockproc *pp; - int sl232; - - if(NULL != peer) - { - pp = peer->procptr; - if(pp != NULL) - { - up = (struct neoclock4x_unit *)pp->unitptr; - if(up != NULL) - { - if(-1 != pp->io.fd) - { -#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) - /* turn on RTS, and DTR for power supply */ - /* NeoClock4x is powered from serial line */ - if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", - unit); - } -#ifdef TIOCM_RTS - /* turn on RTS, and DTR for power supply */ - sl232 &= ~(TIOCM_DTR | TIOCM_RTS); -#else - /* turn on RTS, and DTR for power supply */ - sl232 &= ~(CIOCM_DTR | CIOCM_RTS); -#endif - if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", - unit); - } -#endif - io_closeclock(&pp->io); - } - free(up); - pp->unitptr = NULL; - } - } - } - - msyslog(LOG_ERR, "NeoClock4X(%d): shutdown", unit); - - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_INFO, "NeoClock4X(%d): receiver shutdown done", unit); -} - -static void -neoclock4x_receive(struct recvbuf *rbufp) -{ - struct neoclock4x_unit *up; - struct refclockproc *pp; - struct peer *peer; - unsigned long calc_utc; - int day; - int month; /* ddd conversion */ - int c; - int dsec; - unsigned char calc_chksum; - int recv_chksum; - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct neoclock4x_unit *)pp->unitptr; - - /* wait till poll interval is reached */ - if(0 == up->recvnow) - return; - - /* reset poll interval flag */ - up->recvnow = 0; - - /* read last received timecode */ - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); - pp->leap = LEAP_NOWARNING; - - if(NEOCLOCK4X_TIMECODELEN != pp->lencode) - { - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s", - up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode); - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2); - - /* calculate checksum */ - calc_chksum = 0; - for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++) - { - calc_chksum += pp->a_lastcode[c]; - } - if(recv_chksum != calc_chksum) - { - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s", - up->unit, pp->a_lastcode); - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* Allow synchronization even is quartz clock is - * never initialized. - * WARNING: This is dangerous! - */ - up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS]; - if(0==(pp->sloppyclockflag & CLK_FLAG2)) - { - if('I' != up->quarzstatus) - { - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s", - up->unit, pp->a_lastcode); - pp->leap = LEAP_NOTINSYNC; - refclock_report(peer, CEVNT_BADDATE); - return; - } - } - if('I' != up->quarzstatus) - { - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s", - up->unit, pp->a_lastcode); - } - - /* - * If NeoClock4X is not synchronized to a radio clock - * check if we're allowed to synchronize with the quartz - * clock. - */ - up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE]; - if(0==(pp->sloppyclockflag & CLK_FLAG2)) - { - if('A' != up->timesource) - { - /* not allowed to sync with quartz clock */ - if(0==(pp->sloppyclockflag & CLK_FLAG1)) - { - refclock_report(peer, CEVNT_BADTIME); - pp->leap = LEAP_NOTINSYNC; - return; - } - } - } - - /* this should only used when first install is done */ - if(pp->sloppyclockflag & CLK_FLAG4) - { - msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s", - up->unit, pp->a_lastcode); - } - - /* 123456789012345678901234567890123456789012345 */ - /* S/N123456DCF1004021010001202ASX1213CR\r\n */ - - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2); - neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2); - pp->nsec = dsec * 10000; /* convert 1/100s from neoclock to nanoseconds */ - - memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3); - up->radiosignal[3] = 0; - memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6); - up->serial[6] = 0; - up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS]; - neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2); - neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2); - - /* - 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. */ - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s", - up->unit, pp->a_lastcode); - refclock_report(peer, CEVNT_BADDATE); - return; - } - - /* Year-2000 check not needed anymore. Same problem - * will arise at 2099 but what should we do...? - * - * wrap 2-digit date into 4-digit - * - * if(pp->year < YEAR_PIVOT) - * { - * pp->year += 100; - * } - */ - pp->year += 2000; - - /* adjust NeoClock4X local time to UTC */ - calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second); - calc_utc -= 3600; - /* adjust NeoClock4X daylight saving time if needed */ - if('S' == up->dststatus) - calc_utc -= 3600; - neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second); - - /* - some preparations - */ - pp->day = ymd2yd(pp->year, month, day); - pp->leap = 0; - - if(pp->sloppyclockflag & CLK_FLAG4) - { - msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld", - up->unit, - pp->year, month, day, - pp->hour, pp->minute, pp->second, pp->nsec/1000); - } - - up->utc_year = pp->year; - up->utc_month = month; - up->utc_day = day; - up->utc_hour = pp->hour; - up->utc_minute = pp->minute; - up->utc_second = pp->second; - up->utc_msec = pp->nsec/1000; - - if(!refclock_process(pp)) - { - NLOG(NLOG_CLOCKEVENT) - msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit); - refclock_report(peer, CEVNT_FAULT); - return; - } - refclock_receive(peer); - - /* report good status */ - refclock_report(peer, CEVNT_NOMINAL); - - record_clock_stats(&peer->srcadr, pp->a_lastcode); -} - -static void -neoclock4x_poll(int unit, - struct peer *peer) -{ - struct neoclock4x_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct neoclock4x_unit *)pp->unitptr; - - pp->polls++; - up->recvnow = 1; -} - -static void -neoclock4x_control(int unit, - struct refclockstat *in, - struct refclockstat *out, - struct peer *peer) -{ - struct neoclock4x_unit *up; - struct refclockproc *pp; - - if(NULL == peer) - { - msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); - return; - } - - pp = peer->procptr; - if(NULL == pp) - { - msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); - return; - } - - up = (struct neoclock4x_unit *)pp->unitptr; - if(NULL == up) - { - msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); - return; - } - - if(NULL != in) - { - /* check to see if a user supplied time offset is given */ - if(in->haveflags & CLK_HAVETIME1) - { - pp->fudgetime1 = in->fudgetime1; - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.", - unit, pp->fudgetime1); - } - - /* notify */ - if(pp->sloppyclockflag & CLK_FLAG1) - { - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit); - } - else - { - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit); - } - } - - if(NULL != out) - { - static char outstatus[800]; /* status output buffer */ - char *tt; - char tmpbuf[80]; - - outstatus[0] = '\0'; - out->kv_list = (struct ctl_var *)0; - out->type = REFCLK_NEOCLOCK4X; - - snprintf(tmpbuf, sizeof(tmpbuf)-1, - "%04d-%02d-%02d %02d:%02d:%02d.%03d", - up->utc_year, up->utc_month, up->utc_day, - up->utc_hour, up->utc_minute, up->utc_second, - up->utc_msec); - tt = add_var(&out->kv_list, sizeof(tmpbuf)-1, RO|DEF); - snprintf(tt, sizeof(tmpbuf)-1, "calc_utc=\"%s\"", tmpbuf); - - tt = add_var(&out->kv_list, 40, RO|DEF); - snprintf(tt, 39, "radiosignal=\"%s\"", up->radiosignal); - tt = add_var(&out->kv_list, 40, RO|DEF); - snprintf(tt, 39, "antenna1=\"%d\"", up->antenna1); - tt = add_var(&out->kv_list, 40, RO|DEF); - snprintf(tt, 39, "antenna2=\"%d\"", up->antenna2); - tt = add_var(&out->kv_list, 40, RO|DEF); - if('A' == up->timesource) - snprintf(tt, 39, "timesource=\"radio\""); - else if('C' == up->timesource) - snprintf(tt, 39, "timesource=\"quartz\""); - else - snprintf(tt, 39, "timesource=\"unknown\""); - tt = add_var(&out->kv_list, 40, RO|DEF); - if('I' == up->quarzstatus) - snprintf(tt, 39, "quartzstatus=\"synchronized\""); - else if('X' == up->quarzstatus) - snprintf(tt, 39, "quartzstatus=\"not synchronized\""); - else - snprintf(tt, 39, "quartzstatus=\"unknown\""); - tt = add_var(&out->kv_list, 40, RO|DEF); - if('S' == up->dststatus) - snprintf(tt, 39, "dststatus=\"summer\""); - else if('W' == up->dststatus) - snprintf(tt, 39, "dststatus=\"winter\""); - else - snprintf(tt, 39, "dststatus=\"unknown\""); - tt = add_var(&out->kv_list, 80, RO|DEF); - snprintf(tt, 79, "firmware=\"%s\"", up->firmware); - tt = add_var(&out->kv_list, 40, RO|DEF); - snprintf(tt, 39, "firmwaretag=\"%c\"", up->firmwaretag); - tt = add_var(&out->kv_list, 80, RO|DEF); - snprintf(tt, 79, "driver version=\"%s\"", NEOCLOCK4X_DRIVER_VERSION); - tt = add_var(&out->kv_list, 80, RO|DEF); - snprintf(tt, 79, "serialnumber=\"%s\"", up->serial); - } -} - -static int -neol_hexatoi_len(const char str[], - int *result, - int maxlen) -{ - int hexdigit; - int i; - int n = 0; - - for(i=0; isxdigit(str[i]) && i < maxlen; i++) - { - hexdigit = isdigit(str[i]) ? toupper(str[i]) - '0' : toupper(str[i]) - 'A' + 10; - n = 16 * n + hexdigit; - } - *result = n; - return (n); -} - -static int -neol_atoi_len(const char str[], - int *result, - int maxlen) -{ - int digit; - int i; - int n = 0; - - for(i=0; isdigit(str[i]) && i < maxlen; i++) - { - digit = str[i] - '0'; - n = 10 * n + digit; - } - *result = n; - return (n); -} - -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static unsigned long -neol_mktime(int year, - int mon, - int day, - int hour, - int min, - int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 . 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - -static void -neol_localtime(unsigned long utc, - int* year, - int* month, - int* day, - int* hour, - int* min, - int* sec) -{ - *sec = utc % 60; - utc /= 60; - *min = utc % 60; - utc /= 60; - *hour = utc % 24; - utc /= 24; - - /* JDN Date 1/1/1970 */ - neol_jdn_to_ymd(utc + 2440588L, year, month, day); -} - -static void -neol_jdn_to_ymd(unsigned long jdn, - int *yy, - int *mm, - int *dd) -{ - unsigned long x, z, m, d, y; - unsigned long daysPer400Years = 146097UL; - unsigned long fudgedDaysPer4000Years = 1460970UL + 31UL; - - x = jdn + 68569UL; - z = 4UL * x / daysPer400Years; - x = x - (daysPer400Years * z + 3UL) / 4UL; - y = 4000UL * (x + 1) / fudgedDaysPer4000Years; - x = x - 1461UL * y / 4UL + 31UL; - m = 80UL * x / 2447UL; - d = x - 2447UL * m / 80UL; - x = m / 11UL; - m = m + 2UL - 12UL * x; - y = 100UL * (z - 49UL) + y + x; - - *yy = (int)y; - *mm = (int)m; - *dd = (int)d; -} - -#if 0 -/* - * delay in milliseconds - */ -static void -neol_mdelay(int milliseconds) -{ - struct timeval tv; - - if(milliseconds) - { - tv.tv_sec = 0; - tv.tv_usec = milliseconds * 1000; - select(1, NULL, NULL, NULL, &tv); - } -} -#endif - -#if !defined(NEOCLOCK4X_FIRMWARE) -static int -neol_query_firmware(int fd, - int unit, - char *firmware, - int maxlen) -{ - char tmpbuf[256]; - int len; - int lastsearch; - unsigned char c; - int last_c_was_crlf; - int last_crlf_conv_len; - int init; - int read_errors; - int flag = 0; - int chars_read; - - /* wait a little bit */ - sleep(1); - if(-1 != write(fd, "V", 1)) - { - /* wait a little bit */ - sleep(1); - memset(tmpbuf, 0x00, sizeof(tmpbuf)); - - len = 0; - lastsearch = 0; - last_c_was_crlf = 0; - last_crlf_conv_len = 0; - init = 1; - read_errors = 0; - chars_read = 0; - for(;;) - { - if(read_errors > 5) - { - msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit); - strcpy(tmpbuf, "unknown due to timeout"); - break; - } - if(chars_read > 500) - { - msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit); - strcpy(tmpbuf, "unknown due to garbage input"); - break; - } - if(-1 == read(fd, &c, 1)) - { - if(EAGAIN != errno) - { - msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %s", unit ,strerror(errno)); - read_errors++; - } - else - { - sleep(1); - } - continue; - } - else - { - chars_read++; - } - - if(init) - { - if(0xA9 != c) /* wait for (c) char in input stream */ - continue; - - strcpy(tmpbuf, "(c)"); - len = 3; - init = 0; - continue; - } - -#if 0 - msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c); -#endif - - if(0x0A == c || 0x0D == c) - { - if(last_c_was_crlf) - { - char *ptr; - ptr = strstr(&tmpbuf[lastsearch], "S/N"); - if(NULL != ptr) - { - tmpbuf[last_crlf_conv_len] = 0; - flag = 1; - break; - } - /* convert \n to / */ - last_crlf_conv_len = len; - tmpbuf[len++] = ' '; - tmpbuf[len++] = '/'; - tmpbuf[len++] = ' '; - lastsearch = len; - } - last_c_was_crlf = 1; - } - else - { - last_c_was_crlf = 0; - if(0x00 != c) - tmpbuf[len++] = (char) c; - } - tmpbuf[len] = '\0'; - if(len > sizeof(tmpbuf)-5) - break; - } - } - else - { - msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit); - strcpy(tmpbuf, "unknown error"); - } - strncpy(firmware, tmpbuf, maxlen); - firmware[maxlen] = '\0'; - - if(flag) - { - NLOG(NLOG_CLOCKINFO) - msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware); - } - - return (flag); -} - -static int -neol_check_firmware(int unit, - const char *firmware, - char *firmwaretag) -{ - char *ptr; - - *firmwaretag = '?'; - ptr = strstr(firmware, "NDF:"); - if(NULL != ptr) - { - if((strlen(firmware) - strlen(ptr)) >= 7) - { - if(':' == *(ptr+5) && '*' == *(ptr+6)) - *firmwaretag = *(ptr+4); - } - } - - if('A' != *firmwaretag) - { - msyslog(LOG_CRIT, "NeoClock4X(%d): firmware version \"%c\" not supported with this driver version!", unit, *firmwaretag); - return (0); - } - - return (1); -} -#endif - -#else -int refclock_neoclock4x_bs; -#endif /* REFCLOCK */ - -/* - * History: - * refclock_neoclock4x.c - * - * 2002/04/27 cjh - * Revision 1.0 first release - * - * 2002/07/15 cjh - * preparing for bitkeeper reposity - * - * 2002/09/09 cjh - * Revision 1.1 - * - don't assume sprintf returns an int anymore - * - change the way the firmware version is read - * - some customers would like to put a device called - * data diode to the NeoClock4X device to disable - * the write line. We need to now the firmware - * version even in this case. We made a compile time - * definition in this case. The code was previously - * only available on request. - * - * 2003/01/08 cjh - * Revision 1.11 - * - changing xprinf to xnprinf to avoid buffer overflows - * - change some logic - * - fixed memory leaks if drivers can't initialize - * - * 2003/01/10 cjh - * Revision 1.12 - * - replaced ldiv - * - add code to support FreeBSD - * - * 2003/07/07 cjh - * Revision 1.13 - * - fix reporting of clock status - * changes. previously a bad clock - * status was never reset. - */ diff --git a/contrib/ntp/ntpd/refclock_nmea.c b/contrib/ntp/ntpd/refclock_nmea.c deleted file mode 100644 index 28d6263..0000000 --- a/contrib/ntp/ntpd/refclock_nmea.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * refclock_nmea.c - clock driver for an NMEA GPS CLOCK - * Michael Petry Jun 20, 1994 - * based on refclock_heathn.c - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - -#if defined(REFCLOCK) && defined(CLOCK_NMEA) - -#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 - * - * Protype was refclock_trak.c, Thanks a lot. - * - * The receiver used spits out the NMEA sentences for boat navigation. - * And you thought it was an information superhighway. Try a raging river - * 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 - */ - -/* - * Definitions - */ -#ifdef SYS_WINNT -# define DEVICE "COM%d:" /* COM 1 - 3 supported */ -#else -# define DEVICE "/dev/gps%d" /* name of radio device */ -#endif -#define SPEED232 B4800 /* uart speed (4800 bps) */ -#define PRECISION (-9) /* precision assumed (about 2 ms) */ -#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS\0" /* reference id */ -#define DESCRIPTION "NMEA GPS Clock" /* who we are */ -#define NANOSECOND 1000000000 /* one second (ns) */ -#define RANGEGATE 500000 /* range gate (ns) */ - -#define LENNMEA 75 /* min timecode length */ - -/* - * Tables to compute the ddd of year form icky dd/mm timecode. Viva la - * leap. - */ -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}; - -/* - * Unit control structure - */ -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 */ -}; - -/* - * Function prototypes - */ -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 *)); -static char *field_parse P((char *, int)); - -/* - * Transfer vector - */ -struct refclock refclock_nmea = { - nmea_start, /* start up driver */ - nmea_shutdown, /* shut down driver */ - nmea_poll, /* transmit poll message */ -#ifdef HAVE_PPSAPI - nmea_control, /* fudge control */ -#else - noentry, /* fudge control */ -#endif /* HAVE_PPSAPI */ - noentry, /* initialize driver */ - noentry, /* buginfo */ - NOFLAGS /* not used */ -}; - -/* - * nmea_start - open the GPS devices and initialize data for processing - */ -static int -nmea_start( - int unit, - struct peer *peer - ) -{ - register struct nmeaunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - - fd = refclock_open(device, SPEED232, LDISC_CLK); - if (fd < 0) - return (0); - - /* - * Allocate and initialize unit structure - */ - up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit)); - if (up == NULL) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct nmeaunit)); - pp = peer->procptr; - pp->io.clock_recv = nmea_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->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 */ -} - -/* - * nmea_shutdown - shut down a GPS clock - */ -static void -nmea_shutdown( - int unit, - struct peer *peer - ) -{ - register struct nmeaunit *up; - struct refclockproc *pp; - - 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 - */ -static void -nmea_receive( - struct recvbuf *rbufp - ) -{ - register struct nmeaunit *up; - struct refclockproc *pp; - struct peer *peer; - int month, day; - int i; - char *cp, *dp; - int cmdtype; - /* Use these variables to hold data until we decide its worth keeping */ - char rd_lastcode[BMAX]; - l_fp rd_tmp; - u_short rd_lencode; - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct nmeaunit *)pp->unitptr; - rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); - - /* - * There is a case that a <CR><LF> gives back a "blank" line - */ - if (rd_lencode == 0) - return; - -#ifdef DEBUG - if (debug) - printf("nmea: gpsread %d %s\n", rd_lencode, - rd_lastcode); -#endif - - /* - * We check the timecode format and decode its contents. The - * we only care about a few of them. The most important being - * the $GPRMC format - * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC - * For Magellan (ColorTrak) GLL probably datum (order of sentences) - * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL - * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21 - * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F - * $GPRMB,... - * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77 - * $GPAPB,... - * $GPGSA,... - * $GPGSV,... - * $GPGSV,... - */ -#define GPXXX 0 -#define GPRMC 1 -#define GPGGA 2 -#define GPGLL 4 - cp = rd_lastcode; - cmdtype=0; - if(strncmp(cp,"$GPRMC",6)==0) { - cmdtype=GPRMC; - } - else if(strncmp(cp,"$GPGGA",6)==0) { - cmdtype=GPGGA; - } - else if(strncmp(cp,"$GPGLL",6)==0) { - cmdtype=GPGLL; - } - else if(strncmp(cp,"$GPXXX",6)==0) { - cmdtype=GPXXX; - } - else - return; - - - /* See if I want to process this message type */ - if ( ((peer->ttl == 0) && (cmdtype != GPRMC)) - || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) ) - 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: - /* - * 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]) || - !isdigit((int)dp[3]) || - !isdigit((int)dp[4]) || - !isdigit((int)dp[5]) - ) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - - /* - * Convert time and check values. - */ - pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; - pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; - pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; - /* Default to 0 milliseconds, if decimal convert milliseconds in - one, two or three digits - */ - pp->nsec = 0; - if (dp[6] == '.') { - if (isdigit((int)dp[7])) { - pp->nsec = (dp[7] - '0') * 100000000; - if (isdigit((int)dp[8])) { - pp->nsec += (dp[8] - '0') * 10000000; - if (isdigit((int)dp[9])) { - pp->nsec += (dp[9] - '0') * 1000000; - } - } - } - } - - if (pp->hour > 23 || pp->minute > 59 || pp->second > 59 - || pp->nsec > 1000000000) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - - /* - * Convert date and check values. - */ - if (cmdtype==GPRMC) { - dp = field_parse(cp,9); - day = dp[0] - '0'; - day = (day * 10) + dp[1] - '0'; - month = dp[2] - '0'; - month = (month * 10) + dp[3] - '0'; - pp->year = dp[4] - '0'; - pp->year = (pp->year * 10) + dp[5] - '0'; - } - else { - /* only time */ - time_t tt = time(NULL); - struct tm * t = gmtime(&tt); - day = t->tm_mday; - month = t->tm_mon + 1; - pp->year= t->tm_year; - } - - if (month < 1 || month > 12 || day < 1) { - refclock_report(peer, CEVNT_BADTIME); - 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); - return; - } - for (i = 0; i < month - 1; i++) - day += day1tab[i]; - } else { - if (day > day2tab[month - 1]) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - for (i = 0; i < month - 1; i++) - day += day2tab[i]; - } - pp->day = day; - - -#ifdef HAVE_PPSAPI - /* - * If the PPSAPI is working, rather use its timestamps. - * assume that the PPS occurs on the second so blow any msec - */ - if (nmea_pps(up, &rd_tmp) == 1) { - pp->lastrec = up->tstamp = rd_tmp; - pp->nsec = 0; - } -#endif /* HAVE_PPSAPI */ - - /* - * Process the new sample in the median filter and determine the - * reference clock offset and dispersion. We use lastrec as both - * the reference time and receive time, in order to avoid being - * cute, like setting the reference time later than the receive - * time, which may cause a paranoid protocol module to chuck out - * the data. - */ - - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - - - /* - * Only go on if we had been polled. - */ - if (!up->polled) - return; - up->polled = 0; - pp->lastref = pp->lastrec; - refclock_receive(peer); - - /* If we get here - what we got from the clock is OK, so say so */ - refclock_report(peer, CEVNT_NOMINAL); - - record_clock_stats(&peer->srcadr, pp->a_lastcode); - -} - -/* - * nmea_poll - called by the transmit procedure - * - * We go to great pains to avoid changing state here, since there may be - * more than one eavesdropper receiving the same timecode. - */ -static void -nmea_poll( - int unit, - struct peer *peer - ) -{ - register struct nmeaunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct nmeaunit *)pp->unitptr; - if (up->pollcnt == 0) - refclock_report(peer, CEVNT_TIMEOUT); - else - up->pollcnt--; - pp->polls++; - up->polled = 1; - - /* - * usually nmea_receive can get a timestamp every second - */ - - gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); -} - -/* - * - * gps_send(fd,cmd, peer) Sends a command to the GPS receiver. - * as gps_send(fd,"rqts,u\r", peer); - * - * We don't currently send any data, but would like to send - * RTCM SC104 messages for differential positioning. It should - * also give us better time. Without a PPS output, we're - * Just fooling ourselves because of the serial code paths - * - */ -static void -gps_send( - int fd, - const char *cmd, - struct peer *peer - ) -{ - - if (write(fd, cmd, strlen(cmd)) == -1) { - refclock_report(peer, CEVNT_FAULT); - } -} - -static char * -field_parse( - char *cp, - int fn - ) -{ - char *tp; - int i = fn; - - for (tp = cp; *tp != '\0'; tp++) { - if (*tp == ',') - i--; - if (i == 0) - break; - } - return (++tp); -} -#else -int refclock_nmea_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c deleted file mode 100644 index 14db92f..0000000 --- a/contrib/ntp/ntpd/refclock_oncore.c +++ /dev/null @@ -1,3723 +0,0 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - * - * 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, M12+T - * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate - * than the others. - * The receivers without position hold (GT, GT+) will be less accurate. - * - * Tested with: - * - * (UT) (VP) - * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. - * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P - * SOFTWARE VER # 2 SOFTWARE VER # 8 - * SOFTWARE REV # 2 SOFTWARE REV # 8 - * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 - * MODEL # R1121N1114 MODEL # B4121P1155 - * HWDR P/N # 1 HDWR P/N # _ - * SERIAL # R0010A SERIAL # SSG0226478 - * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 - * OPTIONS LIST IB - * - * (Basic) (M12) - * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. - * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A - * SOFTWARE VER # 5 SOFTWARE VER # 1 - * SOFTWARE REV # 0 SOFTWARE REV # 3 - * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000 - * MODEL # A11121P116 MODEL # P143T12NR1 - * HDWR P/N # _ HWDR P/N # 1 - * SERIAL # SSG0049809 SERIAL # P003UD - * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27 - * OPTIONS LIST AB - * - * -------------------------------------------------------------------------- - * This code uses the two devices - * /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, /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 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 - * it seems like it is only using 3D fixes. - * When we do it ourselves, take 10000 3D fixes. - */ - -#define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ - -/* - * 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 - * 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) && 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/stat.h> -#ifdef ONCORE_SHMEM_STATUS -# ifdef HAVE_SYS_MMAN_H -# include <sys/mman.h> -# ifndef MAP_FAILED -# define MAP_FAILED ((u_char *) -1) -# endif /* not MAP_FAILED */ -# endif /* HAVE_SYS_MMAN_H */ -#endif /* ONCORE_SHMEM_STATUS */ - -#ifdef HAVE_PPSAPI -# ifdef HAVE_TIMEPPS_H -# include <timepps.h> -# else -# ifdef HAVE_SYS_TIMEPPS_H -# include <sys/timepps.h> -# endif -# endif -#endif - -#ifdef HAVE_SYS_SIO_H -# include <sys/sio.h> -#endif - -#ifdef HAVE_SYS_TERMIOS_H -# include <sys/termios.h> -#endif - -#ifdef HAVE_SYS_PPSCLOCK_H -# include <sys/ppsclock.h> -#endif - -#ifndef HAVE_STRUCT_PPSCLOCKEV -struct ppsclockev { -# ifdef HAVE_STRUCT_TIMESPEC - struct timespec tv; -# else - struct timeval tv; -# endif - u_int serial; -}; -#endif /* not HAVE_STRUCT_PPSCLOCKEV */ - -enum receive_state { - ONCORE_NO_IDEA, - ONCORE_CHECK_ID, - ONCORE_CHECK_CHAN, - ONCORE_HAVE_CHAN, - ONCORE_RESET_SENT, - ONCORE_TEST_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 -}; - -enum antenna_state { - ONCORE_ANTENNA_UNKNOWN = -1, - ONCORE_ANTENNA_OK = 0, - ONCORE_ANTENNA_OC = 1, - ONCORE_ANTENNA_UC = 2, - ONCORE_ANTENNA_NV = 3 -}; - -/* Model Name, derived from the @@Cj message. - * Used to initialize some variables. - */ - -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 shmemfd; /* Status shm descriptor */ -#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 */ - enum antenna_state ant_state; /* antenna state */ - - int Bj_day; - - 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_reset; - u_char shmem_Posn; - u_char shmem_bad_Ea; - u_char almanac_from_shmem; - - double ss_lat; - double ss_long; - double ss_ht; - double dH; - int ss_count; - u_char posn_set; - - 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, M12+T, -1 unknown, 0 no, +1 yes */ - - /* the following 7 are all timing counters */ - u_char traim_delay; /* seconds counter, waiting for reply */ - u_char count; /* cycles thru Ea before starting */ - u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ - u_char count2; /* cycles thru Ea after count, to check for @@Ea */ - u_char count3; /* cycles thru Ea checking for # channels */ - u_char count4; /* cycles thru leap after Gj to issue Bj */ - u_char pollcnt; - u_char timeout; /* count to retry Cj after Fa self-test */ - - struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ - u_char printed; - u_char polled; - u_long ev_serial; - int Rcvptr; - u_char Rcvbuf[500]; - u_char BEHa[160]; /* Ba, Ea or Ha */ - u_char BEHn[80]; /* Bn , En , or Hn */ - u_char Cj[300]; - u_char Ag; /* Satellite mask angle */ - u_char saw_At; - u_char saw_Ay; - u_char saw_Az; - s_char saw_Gj; - u_char have_dH; - u_char init_type; - s_char saw_tooth; - s_char chan_in; /* chan number from INPUT, will always use it */ - u_char chan_id; /* chan number determined from part number */ - u_char chan_ck; /* chan number determined by sending commands to hardware */ - s_char traim_in; /* TRAIM from INPUT, will always use it */ - s_char traim_id; /* TRAIM determined from part number */ - u_char traim_ck; /* TRAIM determined by sending commands to hardware */ - u_char once; /* one pass code at top of BaEaHa */ - s_char assert; - u_char hardpps; -}; - -#define rcvbuf instance->Rcvbuf -#define rcvptr instance->Rcvptr - -static int oncore_start P((int, struct peer *)); -static void oncore_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); -static void oncore_poll P((int, struct peer *)); -static void oncore_shutdown P((int, struct peer *)); -static void oncore_consume P((struct instance *)); -static void oncore_read_config P((struct instance *)); -static void oncore_receive P((struct recvbuf *)); -static int oncore_ppsapi P((struct instance *)); -static void oncore_get_timestamp P((struct instance *, long, long)); -static void oncore_init_shmem P((struct instance *)); - -static void oncore_antenna_report P((struct instance *, enum antenna_state)); -static void oncore_chan_test P((struct instance *)); -static void oncore_check_almanac P((struct instance *)); -static void oncore_check_antenna P((struct instance *)); -static void oncore_check_leap_sec P((struct instance *)); -static int oncore_checksum_ok P((u_char *, int)); -static void oncore_compute_dH P((struct instance *)); -static void oncore_load_almanac P((struct instance *)); -static void oncore_print_Cb P((struct instance *, u_char *)); -/* static void oncore_print_array P((u_char *, int)); */ -static void oncore_print_posn P((struct instance *)); -static void oncore_sendmsg P((int, u_char *, size_t)); -static void oncore_set_posn P((struct instance *)); -static void oncore_set_traim P((struct instance *)); -static void oncore_shmem_get_3D P((struct instance *)); -static void oncore_ss P((struct instance *)); -static int oncore_wait_almanac P((struct instance *)); - -static void oncore_msg_any P((struct instance *, u_char *, size_t, int)); -static void oncore_msg_Adef P((struct instance *, u_char *, size_t)); -static void oncore_msg_Ag P((struct instance *, u_char *, size_t)); -static void oncore_msg_As P((struct instance *, u_char *, size_t)); -static void oncore_msg_At P((struct instance *, u_char *, size_t)); -static void oncore_msg_Ay P((struct instance *, u_char *, size_t)); -static void oncore_msg_Az P((struct instance *, u_char *, size_t)); -static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t)); -static void oncore_msg_Bd P((struct instance *, u_char *, size_t)); -static void oncore_msg_Bj P((struct instance *, u_char *, size_t)); -static void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t)); -static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t)); -static void oncore_msg_Cb P((struct instance *, u_char *, size_t)); -static void oncore_msg_Cf P((struct instance *, u_char *, size_t)); -static void oncore_msg_Cj P((struct instance *, u_char *, size_t)); -static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t)); -static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t)); -static void oncore_msg_Ga P((struct instance *, u_char *, size_t)); -static void oncore_msg_Gb P((struct instance *, u_char *, size_t)); -static void oncore_msg_Gd P((struct instance *, u_char *, size_t)); -static void oncore_msg_Gj P((struct instance *, u_char *, size_t)); -static void oncore_msg_Sz P((struct instance *, u_char *, size_t)); - -struct refclock refclock_oncore = { - oncore_start, /* start up driver */ - oncore_shutdown, /* shut down driver */ - oncore_poll, /* transmit poll message */ - oncore_control, /* fudge (flag) control messages */ - noentry, /* not used */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - -/* - * Understanding the next bit here is not easy unless you have a manual - * for the the various Oncore Models. - */ - -static struct msg_desc { - const char flag[3]; - const int len; - 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_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, - { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, - { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, - { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, - { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, - { "Hn", 78, oncore_msg_BnEnHn, "" }, - { "Ab", 10, 0, "" }, - { "Ac", 11, 0, "" }, - { "Ad", 11, oncore_msg_Adef, "" }, - { "Ae", 11, oncore_msg_Adef, "" }, - { "Af", 15, oncore_msg_Adef, "" }, - { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */ - { "As", 20, oncore_msg_As, "" }, - { "At", 8, oncore_msg_At, "" }, - { "Au", 12, 0, "" }, - { "Av", 8, 0, "" }, - { "Aw", 8, 0, "" }, - { "Ay", 11, oncore_msg_Ay, "" }, - { "Az", 11, oncore_msg_Az, "" }, - { "AB", 8, 0, "" }, - { "Bb", 92, 0, "" }, - { "Bd", 23, oncore_msg_Bd, "" }, - { "Bj", 8, oncore_msg_Bj, "" }, - { "Ca", 9, oncore_msg_CaFaIa, "" }, - { "Cb", 33, oncore_msg_Cb, "" }, - { "Cf", 7, oncore_msg_Cf, "" }, - { "Cg", 8, 0, "" }, - { "Ch", 9, 0, "" }, - { "Cj", 294, oncore_msg_Cj, "" }, - { "Ek", 71, 0, "" }, - { "Fa", 9, oncore_msg_CaFaIa, "" }, - { "Ga", 20, oncore_msg_Ga, "" }, - { "Gb", 17, oncore_msg_Gb, "" }, - { "Gc", 8, 0, "" }, - { "Gd", 8, oncore_msg_Gd, "" }, - { "Ge", 8, 0, "" }, - { "Gj", 21, oncore_msg_Gj, "" }, - { "Ia", 10, oncore_msg_CaFaIa, "" }, - { "Sz", 8, oncore_msg_Sz, "" }, - { {0}, 7, 0, "" } -}; - - -static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */ -static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */ -static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */ -static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */ -static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */ -static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */ -static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */ -static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */ -static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */ -static u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 6/8/12 Posn Hold Parameters */ -static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ - 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ - 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */ -static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */ -static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */ -static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */ -static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */ -static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */ -static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */ -static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */ -static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */ -static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */ -static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */ -static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */ -static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */ -static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */ -static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */ -static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */ -static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */ -static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */ -static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */ -static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim on */ -static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on traim on */ -static u_char oncore_cmd_Bnx[] = { 'B', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on traim off */ -static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */ -static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */ -static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */ -static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */ -static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */ -static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */ -static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */ -static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim on */ -static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim on */ -static u_char oncore_cmd_Enx[] = { 'E', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim off */ -static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */ -static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */ -static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */ - 0xff, 0xff, 0xff, 0xff, /* */ - 0xff, 0xff, 0xff, 0xff, 0xff }; /* */ -static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */ -static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */ -static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */ -static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */ -static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */ -static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */ -static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */ -static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */ -static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */ -static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */ -static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */ -static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */ -static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */ -static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */ - -/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av - * the GT had Au,Av, but not As,At - * This was as of v2.0 of both firmware sets. possibly 1.3 for UT. - * Bj in UT at v1.3 - * dont see Bd in UT/GT thru 1999 - * Gj in UT as of 3.0, 1999 , Bj as of 1.3 - */ - -static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", - "Aug", "Sep", "Oct", "Nov", "Dec" }; - -#define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ -#define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ -#define INIT_FILE "/etc/ntp.oncore" /* optional init file */ - -#define SPEED B9600 /* Oncore Binary speed (9600 bps) */ - -/* - * Assemble and disassemble 32bit signed quantities from a buffer. - * - */ - - /* to buffer, int w, u_char *buf */ -#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; \ - (buf)[2] = (i_tmp >> 8) & 0xff; \ - (buf)[3] = (i_tmp ) & 0xff; \ - } - -#define w32(buf) (((buf)[0]&0xff) << 24 | \ - ((buf)[1]&0xff) << 16 | \ - ((buf)[2]&0xff) << 8 | \ - ((buf)[3]&0xff) ) - - /* from buffer, char *buf, result to an int */ -#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) - - -/* - * oncore_start - initialize data for processing - */ - -static int -oncore_start( - int unit, - struct peer *peer - ) -{ - register struct instance *instance; - struct refclockproc *pp; - int fd1, fd2; - char device1[30], device2[30]; - const char *cp; - struct stat stat1, stat2; - - /* OPEN DEVICES */ - /* opening different devices for fd1 and fd2 presents no problems */ - /* opening the SAME device twice, seems to be OS dependent. - (a) on Linux (no streams) no problem - (b) on SunOS (and possibly Solaris, untested), (streams) - never see the line discipline. - Since things ALWAYS work if we only open the device once, we check - to see if the two devices are in fact the same, then proceed to - do one open or two. - */ - - (void)sprintf(device1, DEVICE1, unit); - (void)sprintf(device2, DEVICE2, unit); - - if (stat(device1, &stat1)) { - perror("ONCORE: stat fd1"); - exit(1); - } - - if (stat(device2, &stat2)) { - perror("ONCORE: stat fd2"); - exit(1); - } - - /* create instance structure for this unit */ - - if (!(instance = (struct instance *) malloc(sizeof *instance))) { - perror("malloc"); - return (0); - } - memset((char *) instance, 0, sizeof *instance); - - if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) { - /* same device here */ - if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW -#if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP) - | LDISC_PPS -#endif - ))) { - perror("ONCORE: fd1"); - exit(1); - } - fd2 = fd1; - } else { /* different devices here */ - if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) { - perror("ONCORE: fd1"); - exit(1); - } - if ((fd2=open(device2, O_RDWR)) < 0) { - perror("ONCORE: fd2"); - exit(1); - } - } - - /* initialize miscellaneous variables */ - - pp = peer->procptr; - pp->unitptr = (caddr_t) instance; - instance->pp = pp; - instance->unit = unit; - instance->peer = peer; - instance->assert = 1; - instance->once = 1; - - cp = "ONCORE DRIVER -- CONFIGURING"; - record_clock_stats(&(instance->peer->srcadr), cp); - - 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->traim = -1; - instance->traim_in = -1; - instance->chan_in = -1; - instance->model = ONCORE_UNKNOWN; - instance->mode = MODE_UNKNOWN; - instance->site_survey = ONCORE_SS_UNKNOWN; - instance->Ag = 0xff; /* Satellite mask angle, unset by user */ - instance->ant_state = ONCORE_ANTENNA_UNKNOWN; - - peer->precision = -26; - peer->minpoll = 4; - 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 or /etc/ntp/oncore.X */ - - oncore_read_config(instance); - -#ifdef HAVE_PPSAPI - if (time_pps_create(fd2, &instance->pps_h) < 0) { - perror("time_pps_create"); - return(0); - } - - if (instance->assert) - cp = "Initializing timing to Assert."; - else - cp = "Initializing timing to Clear."; - record_clock_stats(&(instance->peer->srcadr), cp); - - if (instance->hardpps) { - cp = "HARDPPS Set."; - record_clock_stats(&(instance->peer->srcadr), cp); - } - - if (!oncore_ppsapi(instance)) - return(0); -#endif - - pp->io.clock_recv = oncore_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd1; - if (!io_addclock(&pp->io)) { - perror("io_addclock"); - (void) close(fd1); - free(instance); - return (0); - } - -#ifdef ONCORE_SHMEM_STATUS - /* - * Before starting ONCORE, lets setup SHMEM - * This will include merging an old SHMEM into the new one if - * an old one is found. - */ - - oncore_init_shmem(instance); -#endif - - /* - * This will return the Model of the Oncore receiver. - * and start the Initialization loop in oncore_msg_Cj. - */ - - instance->o_state = ONCORE_CHECK_ID; - cp = "state = ONCORE_CHECK_ID"; - record_clock_stats(&(instance->peer->srcadr), cp); - - instance->timeout = 4; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); - - instance->pollcnt = 2; - return (1); -} - - -/* - * Fudge control (get Flag2 and Flag3, not available at oncore_start time. - */ - -static void -oncore_control( - int unit, /* unit (not used) */ - struct refclockstat *in, /* input parameters (not used) */ - struct refclockstat *out, /* output parameters (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - char *cp; - struct refclockproc *pp; - struct instance *instance; - - pp = peer->procptr; - instance = (struct instance *) pp->unitptr; - - instance->assert = !(pp->sloppyclockflag & CLK_FLAG2); - instance->hardpps = pp->sloppyclockflag & CLK_FLAG3; - - if (instance->assert) - cp = "Resetting timing to Assert."; - else - cp = "Resetting timing to Clear."; - record_clock_stats(&(instance->peer->srcadr), cp); - - if (instance->hardpps) { - cp = "HARDPPS Set."; - record_clock_stats(&(instance->peer->srcadr), cp); - } - - (void) oncore_ppsapi(instance); -} - - - -/* - * oncore_shutdown - shut down the clock - */ - -static void -oncore_shutdown( - int unit, - struct peer *peer - ) -{ - register struct instance *instance; - struct refclockproc *pp; - - pp = peer->procptr; - instance = (struct instance *) pp->unitptr; - - io_closeclock(&pp->io); - - close(instance->ttyfd); - close(instance->ppsfd); - if (instance->shmemfd) - close(instance->shmemfd); - free(instance); -} - - - -/* - * oncore_poll - called by the transmit procedure - */ - -static void -oncore_poll( - int unit, - struct peer *peer - ) -{ - struct instance *instance; - - instance = (struct instance *) peer->procptr->unitptr; - if (instance->timeout) { - char *cp; - - instance->timeout--; - if (instance->timeout == 0) { - cp = "Oncore: No response from @@Cj, shutting down driver"; - record_clock_stats(&(instance->peer->srcadr), cp); - oncore_shutdown(unit, peer); - } else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); - cp = "Oncore: Resend @@Cj"; - record_clock_stats(&(instance->peer->srcadr), cp); - } - return; - } - - if (!instance->pollcnt) - refclock_report(peer, CEVNT_TIMEOUT); - else - instance->pollcnt--; - peer->procptr->polls++; - instance->polled = 1; -} - - - -/* - * Initialize PPSAPI - */ - -#ifdef HAVE_PPSAPI -static int -oncore_ppsapi( - struct instance *instance - ) -{ - int mode; - - if (time_pps_getcap(instance->pps_h, &mode) < 0) { - msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m"); - return (0); - } - - if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { - msyslog(LOG_ERR, "refclock_ioctl: 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! - */ - - 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; - } else { - instance->pps_p.mode = PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; - instance->pps_p.clear_offset.tv_sec = 0; - instance->pps_p.clear_offset.tv_nsec = 0; - } - instance->pps_p.mode |= PPS_TSFMT_TSPEC; - 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"); - exit(1); - } - - /* If HARDPPS is on, we tell kernel */ - - if (instance->hardpps) { - 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) { - msyslog(LOG_ERR, "refclock_ioctl: time_pps_kcbind failed: %m"); - return (0); - } - pps_enable = 1; - } - } - return(1); -} -#endif - - - -#ifdef ONCORE_SHMEM_STATUS -static void -oncore_init_shmem( - struct instance *instance - ) -{ - int i, l, n, fd, shmem_old_size, n1; - char *buf, Msg[160]; - u_char *cp, *cp1, *shmem_old; - struct msg_desc *mp; - struct stat sbuf; - size_t shmem_length; - - /* - * The first thing we do is see if there is an instance->shmem_fname file (still) - * out there from a previous run. If so, we copy it in and use it to initialize - * shmem (so we won't lose our almanac if we need it). - */ - - shmem_old = 0; - if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0) - perror("LOAD:SHMEM"); - else { - fstat(fd, &sbuf); - shmem_old_size = sbuf.st_size; - shmem_old = (u_char *) malloc((unsigned) sbuf.st_size); - if (shmem_old == NULL) { - perror("malloc"); - close(fd); - return; - } - - read(fd, shmem_old, shmem_old_size); - close(fd); - } - - /* OK, we now create the NEW SHMEM. */ - - if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { - perror(instance->shmem_fname); - return; - } - - /* see how big it needs to be */ - - n = 1; - for (mp=oncore_messages; mp->flag[0]; mp++) { - mp->shmem = n; - /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ - if (!strcmp(mp->flag, "Cb")) { - instance->shmem_Cb = n; - n += (mp->len + 3) * 34; - } - if (!strcmp(mp->flag, "Ba")) { - instance->shmem_Ba = n; - n += (mp->len + 3) * 3; - } - if (!strcmp(mp->flag, "Ea")) { - instance->shmem_Ea = n; - n += (mp->len + 3) * 3; - } - if (!strcmp(mp->flag, "Ha")) { - instance->shmem_Ha = n; - n += (mp->len + 3) * 3; - } - n += (mp->len + 3); - } - shmem_length = n + 2; - fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) shmem_length); - - buf = malloc(shmem_length); - if (buf == NULL) { - perror("malloc"); - close(instance->shmemfd); - return; - } - - memset(buf, 0, shmem_length); - - /* next build the new SHMEM buffer in memory */ - - for (mp=oncore_messages; mp->flag[0]; mp++) { - l = mp->shmem; - buf[l + 0] = mp->len >> 8; - buf[l + 1] = mp->len & 0xff; - buf[l + 2] = 0; - buf[l + 3] = '@'; - buf[l + 4] = '@'; - buf[l + 5] = mp->flag[0]; - buf[l + 6] = mp->flag[1]; - if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { - if (!strcmp(mp->flag, "Cb")) - n = 35; - else - n = 4; - for (i=1; i<n; i++) { - buf[l + i * (mp->len+3) + 0] = mp->len >> 8; - buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; - buf[l + i * (mp->len+3) + 2] = 0; - buf[l + i * (mp->len+3) + 3] = '@'; - buf[l + i * (mp->len+3) + 4] = '@'; - buf[l + i * (mp->len+3) + 5] = mp->flag[0]; - buf[l + i * (mp->len+3) + 6] = mp->flag[1]; - } - } - } - - /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) - * copying the data in shmem_old to buf. When we are done we write it out - * and free both buffers. - * If the structures change (an addition or deletion) I will stop copying. - * The two will be the same unless we add/subtract from the oncore_messages list - * so this should work most of the time, and takes a lot less code than doing it right. - */ - - if (shmem_old) { - for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { - n1 = 256*(*(cp1-3)) + *(cp1-2); - if (n1 != n || strncmp(cp, cp1, 4)) - break; - - memcpy(cp, cp1, (size_t) n); - } - free(shmem_old); - } - - i = write(instance->shmemfd, buf, shmem_length); - free(buf); - - if (i != shmem_length) { - perror(instance->shmem_fname); - close(instance->shmemfd); - return; - } - - instance->shmem = (u_char *) mmap(0, shmem_length, - PROT_READ | PROT_WRITE, -#ifdef MAP_HASSEMAPHORE - MAP_HASSEMAPHORE | -#endif - MAP_SHARED, instance->shmemfd, (off_t)0); - - if (instance->shmem == (u_char *)MAP_FAILED) { - instance->shmem = 0; - close(instance->shmemfd); - return; - } - - sprintf(Msg, "SHMEM (size = %d) is CONFIGURED and available as %s", shmem_length, instance->shmem_fname); - record_clock_stats(&(instance->peer->srcadr), Msg); -} -#endif /* ONCORE_SHMEM_STATUS */ - - - -/* - * Read Input file if it exists. - */ - -static void -oncore_read_config( - struct instance *instance - ) -{ -/* - * First we try to open the configuration file - * /etc/oncoreN - * where N is the unit number viz 127.127.30.N. - * If we don't find it we try - * /etc/ntp.oncore.N - * and then - * /etc/ntp.oncore - * - * 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 - * (0) ONCORE is preinitialized, don't do anything to change it. - * nb, DON'T set 0D mode, DON'T set Delay, position... - * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. - * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, - * lock this in, go to 0D mode. - * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. - * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, - * lock this in, go to 0D mode. - * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] - * then this position is set as the INITIAL position of the ONCORE. - * This can reduce the time to first fix. - * ------------------------------------------------------------------------------- - * Note that an Oncore UT without a battery backup retains NO information if it is - * power cycled, with a Battery Backup it remembers the almanac, etc. - * For an Oncore VP, there is an eeprom that will contain this data, along with the - * option of Battery Backup. - * So a UT without Battery Backup is equivalent to doing a HARD RESET on each - * power cycle, since there is nowhere to store the data. - * ------------------------------------------------------------------------------- - * - * If we open one or the other of the files, we read it looking for - * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, - * STATUS, POSN3D, POSN2D, CHAN, TRAIM - * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must - * be present or mode reverts to (2,4). - * - * Read input file. - * - * # is comment to end of line - * = allowed between 1st and 2nd fields. - * - * Expect to see one line with 'MODE' as first field, followed by an integer - * in the range 0-4 (default = 4). - * - * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. - * All numbers are floating point. - * DDD.ddd - * DDD MMM.mmm - * DDD MMM SSS.sss - * - * 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 receiver reports height in both GPS and MSL, then we will report - * the difference GPS-MSL on the clockstats file. - * - * There is an optional line, starting with DELAY, followed - * 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. - * - * 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 an optional line, with either ASSERT or CLEAR on it, which - * determine which transition of the PPS signal is used for timing by the - * PPSAPI. If neither is present, then ASSERT is assumed. - * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. - * For Flag2, ASSERT=0, and hence is default. - * - * There is an optional line, with HARDPPS on it. Including this line causes - * the PPS signal to control the kernel PLL. - * HARDPPS can also be set with FLAG3 of the ntp.conf input. - * For Flag3, 0 is disabled, and the default. - * - * There are three options that have to do with using the shared memory option. - * First, to enable the option there must be a SHMEM line with a file name. - * The file name is the file associated with the shared memory. - * - * In shared memory, there is one 'record' for each returned variable. - * For the @@Ea data there are three 'records' containing position data. - * There will always be data in the record corresponding to the '0D' @@Ea record, - * and the user has a choice of filling the '3D' record by specifying POSN3D, - * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' - * record is filled once every 15s. - * - * Two additional variables that can be set are CHAN and TRAIM. These should be - * set correctly by the code examining the @@Cj record, but we bring them out here - * to allow the user to override either the # of channels, or the existence of TRAIM. - * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be - * followed by YES or NO. - * - * There is an optional line with MASK on it followed by one integer field in the - * range 0 to 89. This sets the satellite mask angle and will determine the minimum - * elevation angle for satellites to be tracked by the receiver. The default value - * is 10 deg for the VP and 0 deg for all other receivers. - * - * So acceptable input would be - * # these are my coordinates (RWC) - * LON -106 34.610 - * LAT 35 08.999 - * HT 1589 # could equally well say HT 5215 FT - * DELAY 60 ns - */ - - FILE *fd; - char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160]; - int i, sign, lat_flg, long_flg, ht_flg, mode, mask; - double f1, f2, f3; - - sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */ - 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 = mask = 0; - lat_flg = long_flg = ht_flg = 0; - while (fgets(line, 100, fd)) { - - /* 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]); - ) - line[--i] = '\0'; - - /* Remove leading space */ - for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++) - continue; - - /* Stop if nothing left */ - if (!*cc) - continue; - - /* Uppercase the command and find the arg */ - for (ca = cc; *ca; ca++) { - if (isascii((int)*ca)) { - if (islower((int)*ca)) { - *ca = toupper(*ca); - } else if (isspace((int)*ca) || (*ca == '=')) - break; - } - } - - /* Remove space (and possible =) leading the arg */ - for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++) - continue; - - if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { - i = strlen(ca); - instance->shmem_fname = (char *) malloc((unsigned) (i+1)); - strcpy(instance->shmem_fname, ca); - continue; - } - - /* Uppercase argument as well */ - for (cp = ca; *cp; cp++) - if (isascii((int)*cp) && islower((int)*cp)) - *cp = toupper(*cp); - - if (!strncmp(cc, "LAT", (size_t) 3)) { - f1 = f2 = f3 = 0; - sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); - sign = 1; - if (f1 < 0) { - f1 = -f1; - sign = -1; - } - instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ - lat_flg++; - } else if (!strncmp(cc, "LON", (size_t) 3)) { - f1 = f2 = f3 = 0; - sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); - sign = 1; - if (f1 < 0) { - f1 = -f1; - sign = -1; - } - instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ - long_flg++; - } else if (!strncmp(cc, "HT", (size_t) 2)) { - f1 = 0; - units[0] = '\0'; - sscanf(ca, "%lf %1s", &f1, units); - if (units[0] == 'F') - f1 = 0.3048 * f1; - instance->ss_ht = 100 * f1; /* cm */ - ht_flg++; - } else if (!strncmp(cc, "DELAY", (size_t) 5)) { - f1 = 0; - units[0] = '\0'; - sscanf(ca, "%lf %1s", &f1, units); - if (units[0] == 'N') - ; - else if (units[0] == 'U') - f1 = 1000 * f1; - else if (units[0] == 'M') - f1 = 1000000 * f1; - else - f1 = 1000000000 * f1; - if (f1 < 0 || f1 > 1.e9) - f1 = 0; - if (f1 < 0 || f1 > 999999) { - sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1); - record_clock_stats(&(instance->peer->srcadr), Msg); - } else - 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); - if (units[0] == 'N') - ; - else if (units[0] == 'U') - f1 = 1000 * f1; - else if (units[0] == 'M') - f1 = 1000000 * f1; - else - f1 = 1000000000 * f1; - if (f1 < 0 || f1 > 1.e9) - f1 = 0; - if (f1 < 0 || f1 > 999999999.) { - sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1); - record_clock_stats(&(instance->peer->srcadr), Msg); - } else - 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; - } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { - instance->assert = 1; - } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { - instance->assert = 0; - } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) { - instance->hardpps = 1; - } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { - instance->shmem_Posn = 2; - } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { - 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_in = i; - } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { - instance->traim_in = 1; /* so TRAIM alone is YES */ - if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ - instance->traim_in = 0; - } else if (!strncmp(cc, "MASK", (size_t) 4)) { - sscanf(ca, "%d", &mask); - if (mask > -1 && mask < 90) - instance->Ag = mask; /* Satellite mask angle */ - } - } - fclose(fd); - - /* - * OK, have read all of data file, and extracted the good stuff. - * If lat/long/ht specified they ALL must be specified for mode = (1,3). - */ - - instance->posn_set = 1; - if (!( lat_flg && long_flg && ht_flg )) { - printf("ONCORE: incomplete data on %s\n", INIT_FILE); - instance->posn_set = 0; - if (mode == 1 || mode == 3) { - 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); -} - - - -/* - * move data from NTP to buffer (toss the extra in the unlikely case it won't fit) - */ - -static void -oncore_receive( - struct recvbuf *rbufp - ) -{ - size_t i; - u_char *p; - struct peer *peer; - struct instance *instance; - - peer = (struct peer *)rbufp->recv_srcclock; - instance = (struct instance *) peer->procptr->unitptr; - p = (u_char *) &rbufp->recv_space; - -#if 0 - if (debug > 4) { - int i; - printf("ONCORE: >>>"); - for(i=0; i<rbufp->recv_length; i++) - printf("%02x ", p[i]); - printf("\n"); - printf("ONCORE: >>>"); - for(i=0; i<rbufp->recv_length; i++) - printf("%03o ", p[i]); - printf("\n"); - } -#endif - - i = rbufp->recv_length; - if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf]) - i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ - memcpy(rcvbuf+rcvptr, p, i); - rcvptr += i; - oncore_consume(instance); -} - - - -/* - * Deal with any complete messages - */ - -static void -oncore_consume( - struct instance *instance - ) -{ - int i, m; - unsigned l; - - while (rcvptr >= 7) { - if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { - /* We're not in sync, lets try to get there */ - for (i=1; i < rcvptr-1; i++) - if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') - break; - if (debug > 4) - printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i); - if (i != rcvptr) - 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), (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[%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; - - /* 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 */ - if (oncore_checksum_ok(rcvbuf, l)) { - if (instance->shmem != NULL) { - instance->shmem[oncore_messages[m].shmem + 2]++; - memcpy(instance->shmem + oncore_messages[m].shmem + 3, - 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!\n", instance->unit); - printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]); - for (i=4; i<l; i++) - printf("%03o ", rcvbuf[i]); - printf("\n"); - } - } - - if (l != rcvptr) - memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); - rcvptr -= l; - } -} - - - -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_STRUCT_TIMESPEC - struct timespec *tsp = 0; -#else - struct timeval *tsp = 0; -#endif -#ifdef HAVE_PPSAPI - int current_mode; - pps_params_t current_params; - struct timespec timeout; - pps_info_t pps_i; -#else /* ! HAVE_PPSAPI */ -#ifdef HAVE_CIOGETEV - struct ppsclockev ev; - int r = CIOGETEV; -#endif -#ifdef HAVE_TIOCGPPSEV - struct ppsclockev ev; - int r = TIOCGPPSEV; -#endif -#if TIOCDCDTIMESTAMP - struct timeval tv; -#endif -#endif /* ! HAVE_PPS_API */ - -#if 1 - /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru. - * If we have Finished the SiteSurvey, then we fall thru for the 14/15 - * times we get here in 0D mode (the 1/15 is in 3D for SHMEM). - * This gives good time, which gets better when the SS is done. - */ - - if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) -#else - /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */ - - if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) -#endif - return; - - /* Don't do anything without an almanac to define the GPS->UTC delta */ - - if (instance->rsm.bad_almanac) - return; - -#ifdef HAVE_PPSAPI - j = instance->ev_serial; - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, - &timeout) < 0) { - printf("ONCORE: time_pps_fetch failed\n"); - return; - } - - if (instance->assert) { - tsp = &pps_i.assert_timestamp; - - if (debug > 2) { - i = (u_long) pps_i.assert_sequence; -#ifdef HAVE_STRUCT_TIMESPEC - printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", - instance->unit, i, j, - (long)tsp->tv_sec, (long)tsp->tv_nsec); -#else - printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", - instance->unit, i, j, - (long)tsp->tv_sec, (long)tsp->tv_usec); -#endif - } - - if (pps_i.assert_sequence == j) { - printf("ONCORE: oncore_get_timestamp, error serial pps\n"); - return; - } - instance->ev_serial = pps_i.assert_sequence; - } else { - tsp = &pps_i.clear_timestamp; - - if (debug > 2) { - i = (u_long) pps_i.clear_sequence; -#ifdef HAVE_STRUCT_TIMESPEC - printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", - instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec); -#else - printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", - instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec); -#endif - } - - if (pps_i.clear_sequence == j) { - printf("ONCORE: oncore_get_timestamp, error serial pps\n"); - return; - } - instance->ev_serial = pps_i.clear_sequence; - } - - /* convert timespec -> ntp l_fp */ - - dmy = tsp->tv_nsec; - dmy /= 1e9; - ts.l_uf = dmy * 4294967296.0; - ts.l_ui = tsp->tv_sec; -#if 0 - alternate code for previous 4 lines is - dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ - DTOLFP(dmy, &ts); - dmy = tsp->tv_sec; /* integer part */ - DTOLFP(dmy, &ts_tmp); - L_ADD(&ts, &ts_tmp); - or more simply - dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ - DTOLFP(dmy, &ts); - ts.l_ui = tsp->tv_sec; -#endif /* 0 */ -#else -# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV) - j = instance->ev_serial; - if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) { - perror("ONCORE: IOCTL:"); - return; - } - - tsp = &ev.tv; - - if (debug > 2) -#ifdef HAVE_STRUCT_TIMESPEC - printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", - ev.serial, j, tsp->tv_sec, tsp->tv_nsec); -#else - printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", - ev.serial, j, tsp->tv_sec, tsp->tv_usec); -#endif - - if (ev.serial == j) { - printf("ONCORE: oncore_get_timestamp, error serial pps\n"); - return; - } - instance->ev_serial = ev.serial; - - /* convert timeval -> ntp l_fp */ - - TVTOTS(tsp, &ts); -# else -# if defined(TIOCDCDTIMESTAMP) - if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) { - perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)"); - return; - } - tsp = &tv; - TVTOTS(tsp, &ts); -# else -#error "Cannot compile -- no PPS mechanism configured!" -# endif -# endif -#endif - /* now have timestamp in ts */ - /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ - - /* saw_tooth not really necessary if using TIMEVAL */ - /* since its only precise to us, but do it anyway. */ - - /* offset in ns, and is positive (late), we subtract */ - /* to put the PPS time transition back where it belongs */ - -#ifdef HAVE_PPSAPI - /* must hand the offset for the NEXT sec off to the Kernel to do */ - /* the addition, so that the Kernel PLL sees the offset too */ - - if (instance->assert) - instance->pps_p.assert_offset.tv_nsec = -dt2; - else - instance->pps_p.clear_offset.tv_nsec = -dt2; - - /* The following code is necessary, and not just a time_pps_setparams, - * using the saved instance->pps_p, since some other process on the - * machine may have diddled with the mode bits (say adding something - * that it needs). We take what is there and ADD what we need. - * [[ The results from the time_pps_getcap is unlikely to change so - * we could probably just save it, but I choose to do the call ]] - * Unfortunately, there is only ONE set of mode bits in the kernel per - * interface, and not one set for each open handle. - * - * There is still a race condition here where we might mess up someone - * elses mode, but if he is being careful too, he should survive. - */ - - if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { - msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m"); - return; - } - - if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { - msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m"); - return; - } - - /* or current and mine */ - current_params.mode |= instance->pps_p.mode; - /* but only set whats legal */ - current_params.mode &= current_mode; - - current_params.assert_offset.tv_sec = 0; - current_params.assert_offset.tv_nsec = -dt2; - current_params.clear_offset.tv_sec = 0; - current_params.clear_offset.tv_nsec = -dt2; - - if (time_pps_setparams(instance->pps_h, ¤t_params)) - perror("time_pps_setparams"); -#else - /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */ - /* offset for THIS second */ - - dmy = -1.0e-9*dt1; - DTOLFP(dmy, &ts_tmp); - L_ADD(&ts, &ts_tmp); -#endif - /* have time from UNIX origin, convert to NTP origin. */ - - ts.l_ui += JAN_1970; - instance->pp->lastrec = ts; - - /* print out information about this timestamp (long line) */ - - ts_tmp = ts; - ts_tmp.l_ui = 0; /* zero integer part */ - LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ - j = 1.0e9*dmy; /* then to integer ns */ - - Rsm = 0; - if (instance->chan == 6) - Rsm = instance->BEHa[64]; - else if (instance->chan == 8) - Rsm = instance->BEHa[72]; - else if (instance->chan == 12) - Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]); - - if (instance->chan == 6 || instance->chan == 8) { - sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 117 */ - "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %2d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", - ts.l_ui, j, - instance->pp->year, instance->pp->day, - instance->pp->hour, instance->pp->minute, instance->pp->second, - (long) tsp->tv_sec % 60, - Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]), - /*rsat dop */ - instance->BEHa[38], instance->BEHa[39], instance->BEHn[21], - /* nsat visible, nsat tracked, traim */ - instance->BEHn[23]*256+instance->BEHn[24], (s_char) instance->BEHn[25], - /* sigma neg-sawtooth */ - /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53], - instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69] - ); /* will be 0 for 6 chan */ - } else if (instance->chan == 12) { - sprintf(instance->pp->a_lastcode, - "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d%d%d%d%d", - ts.l_ui, j, - instance->pp->year, instance->pp->day, - instance->pp->hour, instance->pp->minute, instance->pp->second, - (long) tsp->tv_sec % 60, - Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]), - /*rsat dop */ - instance->BEHa[55], instance->BEHa[56], instance->BEHn[6], - /* nsat visible, nsat tracked traim */ - instance->BEHn[12]*256+instance->BEHn[13], (s_char) instance->BEHn[14], - /* sigma neg-sawtooth */ - /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76], - instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100], - instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124] - ); - } - - if (debug > 2) { - int n; - n = strlen(instance->pp->a_lastcode); - printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode); - } - - /* and some things I dont understnd (magic ntp things) */ - - if (!refclock_process(instance->pp)) { - refclock_report(instance->peer, CEVNT_BADTIME); - return; - } - - record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); - instance->pollcnt = 2; - - if (instance->polled) { - instance->polled = 0; -/* - instance->pp->dispersion = instance->pp->skew = 0; -*/ - instance->pp->lastref = instance->pp->lastrec; - refclock_receive(instance->peer); - } -} - - -/*************** oncore_msg_XX routines start here *******************/ - - -/* - * print Oncore response message. - */ - -static void -oncore_msg_any( - struct instance *instance, - u_char *buf, - size_t len, - int idx - ) -{ - int i; - const char *fmt = oncore_messages[idx].fmt; - const char *p; -#ifdef HAVE_GETCLOCK - struct timespec ts; -#endif - struct timeval tv; - - if (debug > 3) { -#ifdef HAVE_GETCLOCK - (void) getclock(TIMEOFDAY, &ts); - tv.tv_sec = ts.tv_sec; - tv.tv_usec = ts.tv_nsec / 1000; -#else - GETTIMEOFDAY(&tv, 0); -#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]); - for(i=2; i < len && i < 2400 ; i++) - printf("%02x", buf[i]); - printf("\n"); - return; - } else { - printf("##"); - for (p = fmt; *p; p++) { - putchar(*p); - putchar('_'); - } - printf("\n%c%c", buf[2], buf[3]); - i = 4; - for (p = fmt; *p; p++) { - printf("%02x", buf[i++]); - } - printf("\n"); - } - } -} - - - -/* Latitude, Longitude, Height */ - -static void -oncore_msg_Adef( - struct instance *instance, - u_char *buf, - size_t len - ) -{ -} - - - -/* Mask Angle */ - -static void -oncore_msg_Ag( - struct instance *instance, - u_char *buf, - size_t len - ) -{ char Msg[160], *cp; - - cp = "set to"; - if (instance->o_state == ONCORE_RUN) - cp = "is"; - - instance->Ag = buf[4]; - sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* - * get Position hold position - */ - -static void -oncore_msg_As( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - instance->ss_lat = buf_w32(&buf[4]); - instance->ss_long = buf_w32(&buf[8]); - instance->ss_ht = buf_w32(&buf[12]); - - /* Print out Position */ - oncore_print_posn(instance); -} - - - -/* - * Try to use Oncore UT+ Auto Survey Feature - * If its not there (VP), set flag to do it ourselves. - */ - -static void -oncore_msg_At( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char *cp; - - instance->saw_At = 1; - if (instance->site_survey == ONCORE_SS_TESTING) { - if (buf[4] == 2) { - record_clock_stats(&(instance->peer->srcadr), - "Initiating hardware 3D site survey"); - - cp = "SSstate = ONCORE_SS_HW"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->site_survey = ONCORE_SS_HW; - } - } -} - - - -/* - * get PPS Offset - * Nb. @@Ay is not supported for early UT (no plus) model - */ - -static void -oncore_msg_Ay( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char Msg[120]; - - if (instance->saw_Ay) - return; - - instance->saw_Ay = 1; - - instance->offset = buf_w32(&buf[4]); - - sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* - * get Cable Delay - */ - -static void -oncore_msg_Az( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char Msg[120]; - - if (instance->saw_Az) - return; - - instance->saw_Az = 1; - - instance->delay = buf_w32(&buf[4]); - - sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* Ba, Ea and Ha come here, these contain Position */ - -static void -oncore_msg_BaEaHa( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - const char *cp; - char Msg[160]; - int mode; - - /* OK, we are close to the RUN state now. - * But we have a few more items to initialize first. - * - * At the beginning of this routine there are several 'timers'. - * We enter this routine 1/sec, and since the upper levels of NTP have usurped - * the use of timers, we use the 1/sec entry to do things that - * we would normally do with timers... - */ - - if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */ - if (buf[2] == 'B') { /* 6chan */ - if (instance->chan_ck < 6) instance->chan_ck = 6; - } else if (buf[2] == 'E') { /* 8chan */ - if (instance->chan_ck < 8) instance->chan_ck = 8; - } else if (buf[2] == 'H') { /* 12chan */ - if (instance->chan_ck < 12) instance->chan_ck = 12; - } - - if (instance->count3++ < 5) - return; - - instance->count3 = 0; - - if (instance->chan_in != -1) /* set in Input */ - instance->chan = instance->chan_in; - else /* set from test */ - instance->chan = instance->chan_ck; - - sprintf(Msg, "Input says chan = %d", instance->chan_in); - record_clock_stats(&(instance->peer->srcadr), Msg); - sprintf(Msg, "Model # says chan = %d", instance->chan_id); - record_clock_stats(&(instance->peer->srcadr), Msg); - sprintf(Msg, "Testing says chan = %d", instance->chan_ck); - record_clock_stats(&(instance->peer->srcadr), Msg); - sprintf(Msg, "Using chan = %d", instance->chan); - record_clock_stats(&(instance->peer->srcadr), Msg); - - instance->o_state = ONCORE_HAVE_CHAN; - cp = "state = ONCORE_HAVE_CHAN"; - record_clock_stats(&(instance->peer->srcadr), cp); - - instance->timeout = 4; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); - return; - } - - if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) - return; - - /* PAUSE 5sec */ - - if (instance->count) { - if (instance->count++ < 5) /* make sure results are stable, using position */ - return; - instance->count = 0; - } - - memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */ - - /* check the antenna and almanac for changes (did it get unplugged, is it ready?) */ - - oncore_check_almanac(instance); - oncore_check_antenna(instance); - - /* Almanac mode, waiting for Almanac, we can't do anything till we have it */ - /* When we have an almanac, we will start the Bn/En/@@Hn messages */ - - if (instance->o_state == ONCORE_ALMANAC) - if (oncore_wait_almanac(instance)) - return; - - /* do some things once when we get this far in BaEaHa */ - - if (instance->once) { - instance->once = 0; - instance->count2 = 1; - - /* Have we seen an @@At (position hold) command response */ - /* if not, message out */ - - if (instance->chan != 12 && !instance->saw_At) { - cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+"; - record_clock_stats(&(instance->peer->srcadr), cp); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); - } - - /* have an Almanac, can start the SiteSurvey - * (actually only need to get past the almanac_load where we diddle with At - * command,- we can't change it after we start the HW_SS below - */ - - mode = instance->init_type; - switch (mode) { - case 0: /* NO initialization, don't change anything */ - case 1: /* Use given Position */ - case 3: - instance->site_survey = ONCORE_SS_DONE; - cp = "SSstate = ONCORE_SS_DONE"; - record_clock_stats(&(instance->peer->srcadr), cp); - break; - - case 2: - case 4: /* Site Survey */ - cp = "SSstate = ONCORE_SS_TESTING"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->site_survey = ONCORE_SS_TESTING; - instance->count1 = 1; - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */ - else - oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */ - break; - } - - /* Read back PPS Offset for Output */ - /* Nb. This will fail silently for early UT (no plus) and M12 models */ - - 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)); - - /* Read back Satellite Mask Angle for Output */ - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx, sizeof(oncore_cmd_Agx)); - } - - if (instance->count1) { - if (instance->count1++ > 5 || instance->site_survey == ONCORE_SS_HW) { - instance->count1 = 0; - if (instance->site_survey == ONCORE_SS_TESTING) { - /* - * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec - * wait after the @@At2/@@Gd3 command we have not changed the state to - * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then - * the variable would have been changed by now. - * There are three possibilities: - * 6/8chan - * (a) We did not get a response to the @@At0 or @@At2 commands, - * and it must be a GT/GT+/SL with no position hold mode. - * We will have to do it ourselves. - * (b) We saw the @@At0, @@At2 commands, but @@At2 failed, - * must be a VP or older UT which doesn't have Site Survey mode. - * We will have to do it ourselves. - * 12chan - * (c) We saw the @@Gd command, but @@Gd3 failed, - * We will have to do it ourselves. - */ - - sprintf(Msg, "Initiating software 3D site survey (%d samples)", - POS_HOLD_AVERAGE); - record_clock_stats(&(instance->peer->srcadr), Msg); - - record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW"); - instance->site_survey = ONCORE_SS_SW; - - instance->ss_lat = instance->ss_long = instance->ss_ht = 0; - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */ - else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */ - } - } - } - } - - /* check the mode we are in 0/2/3D */ - - if (instance->chan == 6) { - if (instance->BEHa[64]&0x8) - instance->mode = MODE_0D; - else if (instance->BEHa[64]&0x10) - instance->mode = MODE_2D; - else if (instance->BEHa[64]&0x20) - instance->mode = MODE_3D; - } else if (instance->chan == 8) { - if (instance->BEHa[72]&0x8) - instance->mode = MODE_0D; - else if (instance->BEHa[72]&0x10) - instance->mode = MODE_2D; - else if (instance->BEHa[72]&0x20) - instance->mode = MODE_3D; - } else if (instance->chan == 12) { - int bits; - - bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ - if (bits == 0x4) - instance->mode = MODE_0D; - else if (bits == 0x6) - instance->mode = MODE_2D; - else if (bits == 0x7) - instance->mode = MODE_3D; - } - - /* copy the record to the (extra) location in SHMEM */ - - if (instance->shmem) { - int i; - u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */ - - switch(instance->chan) { - case 6: smp = &instance->shmem[instance->shmem_Ba]; break; - case 8: smp = &instance->shmem[instance->shmem_Ea]; break; - case 12: smp = &instance->shmem[instance->shmem_Ha]; break; - default: smp = (u_char) 0; break; - } - - switch (instance->mode) { - case MODE_0D: i = 1; break; /* 0D, Position Hold */ - case MODE_2D: i = 2; break; /* 2D, Altitude Hold */ - case MODE_3D: i = 3; break; /* 3D fix */ - default: i = 0; break; - } - - if (i) { - i *= (len+6); - smp[i + 2]++; - memcpy(&smp[i+3], buf, (size_t) (len+3)); - } - } - - /* - * check if timer active - * if it hasn't been cleared, then @@Bn/@@En/@@Hn 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); - - oncore_set_traim(instance); - } else - return; - - } - - /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */ - - if (!instance->have_dH && !instance->traim_delay) - oncore_compute_dH(instance); - - /* - * must be ONCORE_RUN if we are here. - * Have # chan and TRAIM by now. - */ - - 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]; - - /* - * Are we doing a Hardware or Software Site Survey? - */ - - if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW) - oncore_ss(instance); - - /* see if we ever saw a response from the @@Ayx above */ - - if (instance->count2) { - if (instance->count2++ > 5) { /* this delay to check on @@Ay command */ - instance->count2 = 0; - - /* Have we seen an Ay (1PPS time offset) command response */ - /* if not, and non-zero offset, zero the offset, and send message */ - - if (!instance->saw_Ay && instance->offset) { - cp = "No @@Ay command, PPS OFFSET ignored"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->offset = 0; - } - } - } - - /* - * Check the leap second status once per day. - */ - - oncore_check_leap_sec(instance); - - /* - * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. - */ - - if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) - oncore_shmem_get_3D(instance); - - if (!instance->traim) /* NO traim, no BnEnHn, go get tick */ - oncore_get_timestamp(instance, instance->offset, instance->offset); -} - - - -/* Almanac Status */ - -static void -oncore_msg_Bd( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char Msg[160]; - - sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x", - ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) ); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* get leap-second warning message */ - -/* - * @@Bj does NOT behave as documented in current Oncore firmware. - * It turns on the LEAP indicator when the data is set, and does not, - * as documented, wait until the beginning of the month when the - * leap second will occur. - * Since this firmware bug will never be fixed in all the outstanding Oncore receivers - * @@Bj is only called in June/December. - */ - -static void -oncore_msg_Bj( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - const char *cp; - - switch(buf[4]) { - case 1: - instance->peer->leap = LEAP_ADDSECOND; - cp = "Set peer.leap to LEAP_ADDSECOND"; - break; - case 2: - instance->peer->leap = LEAP_DELSECOND; - cp = "Set peer.leap to LEAP_DELSECOND"; - break; - case 0: - default: - instance->peer->leap = LEAP_NOWARNING; - cp = "Set peer.leap to LEAP_NOWARNING"; - break; - } - record_clock_stats(&(instance->peer->srcadr), cp); -} - - - -static void -oncore_msg_BnEnHn( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - long dt1, dt2; - char *cp; - - if (instance->o_state != ONCORE_RUN) - return; - - if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */ - instance->traim_ck = 1; - instance->traim_delay = 0; - cp = "ONCORE: Detected TRAIM, TRAIM = ON"; - record_clock_stats(&(instance->peer->srcadr), cp); - - oncore_set_traim(instance); - } - - memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ - - /* If Time RAIM doesn't like it, don't trust it */ - - if (buf[2] == 'H') { - if (instance->BEHn[6]) /* bad TRAIM */ - return; - - dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ - instance->saw_tooth = (s_char) instance->BEHn[10]; /* update for next time Hn[10] */ - dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ - } else { - if (instance->BEHn[21]) /* bad TRAIM */ - return; - - dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ - instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time */ - dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ - } - - oncore_get_timestamp(instance, dt1, dt2); -} - - - -/* Here for @@Ca, @@Fa and @@Ia messages */ - -/* These are Self test Commands for 6, 8, and 12 chan receivers. - * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. - * It was found that under some circumstances the following - * command would fail if issued immediately after the return from the - * @@Fa, but a 2sec delay seemed to fix things. Since simply calling - * sleep(2) is wasteful, and may cause trouble for some OS's, repeating - * itimer, we set a flag, and test it at the next POLL. If it hasn't - * been cleared, we reissue the @@Cj that is issued below. - * Note that we do a @@Cj at the beginning, and again here. - * The first is to get the info, the 2nd is just used as a safe command - * 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; - int i; - - if (instance->o_state == ONCORE_TEST_SENT) { - enum antenna_state 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) >> 6; - buf[4] &= ~0xc0; - - i = buf[4] || buf[5]; - if (buf[2] == 'I') i = i || buf[6]; - if (i) { - if (buf[2] == 'I') { - msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x", - instance->unit, buf[4], buf[5], buf[6]); - } else { - msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x", - instance->unit, buf[4], buf[5]); - } - cp = "ONCORE: self test failed, shutting down driver"; - record_clock_stats(&instance->peer->srcadr, cp); - - refclock_report(instance->peer, CEVNT_FAULT); - oncore_shutdown(instance->unit, instance->peer); - return; - } - - /* report the current antenna state */ - - oncore_antenna_report(instance, antenna); - - instance->o_state = ONCORE_INIT; - cp = "state = ONCORE_INIT"; - record_clock_stats(&(instance->peer->srcadr), cp); - - instance->timeout = 4; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); - } -} - - - -/* - * Demultiplex the almanac into shmem - */ - -static void -oncore_msg_Cb( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - int i; - - if (instance->shmem == NULL) - return; - - if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) - i = buf[5]; - else if (buf[4] == 4 && buf[5] <= 5) - i = buf[5] + 24; - else if (buf[4] == 4 && buf[5] <= 10) - i = buf[5] + 23; - else if (buf[4] == 4 && buf[5] == 25) - i = 34; - else { - char *cp; - - cp = "Cb: Response is NO ALMANAC"; - record_clock_stats(&(instance->peer->srcadr), cp); - return; - } - - i *= 36; - instance->shmem[instance->shmem_Cb + i + 2]++; - memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); - -#if 1 - { - char Msg[160]; - sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]); - record_clock_stats(&(instance->peer->srcadr), Msg); - } -#endif -} - - - -/* - * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup - * not so for VP (eeprom) or any unit with a battery - */ - -static void -oncore_msg_Cf( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - const char *cp; - - if (instance->o_state == ONCORE_RESET_SENT) { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ - /* Reset set VP to IDLE */ - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); - } -} - - - -/* - * This is the Grand Central Station for the Preliminary Initialization. - * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. - * - * We do an @@Cj whenever we need a safe command for all Oncores. - * The @@Cj gets us back here where we can switch to the next phase of setup. - * - * o Once at the very beginning (in start) to get the Model number. - * This info is printed, but no longer used. - * o Again after we have determined the number of Channels in the receiver. - * o And once later after we have done a reset and test, (which may hang), - * as we are about to initialize the Oncore and start it running. - * o We have one routine below for each case. - */ - -static void -oncore_msg_Cj( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - int mode; - char *cp; - - memcpy(instance->Cj, buf, len); - - instance->timeout = 0; - if (instance->o_state == ONCORE_CHECK_ID) { - oncore_msg_Cj_id(instance, buf, len); - oncore_chan_test(instance); - } else if (instance->o_state == ONCORE_HAVE_CHAN) { - mode = instance->init_type; - if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */ - instance->o_state = ONCORE_RESET_SENT; - cp = "state = ONCORE_RESET_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); - } else { - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } - } - - if (instance->o_state == ONCORE_TEST_SENT) { - if (instance->chan == 6) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); - else if (instance->chan == 8) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); - else if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); - } else if (instance->o_state == ONCORE_INIT) - oncore_msg_Cj_init(instance, buf, len); -} - - - -/* The information on determining 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 didn't give the information out. - * - * Determine the Type from the Model #, this determines #chan and if TRAIM is - * available. - * - * The Information from this routine is NO LONGER USED. - * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED - */ - -static void -oncore_msg_Cj_id( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char *cp, *cp1, *cp2, Model[21], Msg[160]; - - /* Write Receiver ID message to clockstats file */ - - instance->Cj[294] = '\0'; - for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { - cp1 = strchr(cp, '\r'); - if (!cp1) - cp1 = (char *)&instance->Cj[294]; - *cp1 = '\0'; - record_clock_stats(&(instance->peer->srcadr), cp); - *cp1 = '\r'; - cp = cp1+2; - } - - /* next, the Firmware Version and Revision numbers */ - - instance->version = atoi(&instance->Cj[83]); - instance->revision = atoi(&instance->Cj[111]); - - /* from model number decide which Oncore this is, - and then the number of channels */ - - for (cp=&instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ - ; - cp1 = cp; - cp2 = Model; - for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++) - *cp2 = *cp; - *cp2 = '\0'; - - cp = 0; - if (!strncmp(Model, "PVT6", (size_t) 4)) { - cp = "PVT6"; - instance->model = ONCORE_PVT6; - } else if (Model[0] == 'A') { - cp = "Basic"; - instance->model = ONCORE_BASIC; - } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { - cp = "VP"; - instance->model = ONCORE_VP; - } else if (Model[0] == 'P') { - cp = "M12"; - instance->model = ONCORE_M12; - } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { - if (Model[5] == 'N') { - cp = "GT"; - instance->model = ONCORE_GT; - } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { - cp = "GT+"; - instance->model = ONCORE_GTPLUS; - } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { - cp = "UT"; - instance->model = ONCORE_UT; - } else if (Model[1] == '5' && Model[5] == 'G') { - cp = "UT+"; - instance->model = ONCORE_UTPLUS; - } else if (Model[1] == '6' && Model[5] == 'G') { - cp = "SL"; - instance->model = ONCORE_SL; - } else { - cp = "Unknown"; - instance->model = ONCORE_UNKNOWN; - } - } else { - cp = "Unknown"; - instance->model = ONCORE_UNKNOWN; - } - - /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ - - sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision); - record_clock_stats(&(instance->peer->srcadr), Msg); - - instance->chan_id = 8; /* default */ - if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) - instance->chan_id = 6; - else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) - instance->chan_id = 8; - else if (instance->model == ONCORE_M12) - instance->chan_id = 12; - - instance->traim_id = 0; /* default */ - if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) - instance->traim_id = 0; - else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) - instance->traim_id = 1; - else if (instance->model == ONCORE_M12) - instance->traim_id = -1; - - sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id, - ((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF"))); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* OK, know type of Oncore, have possibly reset it, and have tested it. - * We know the number of channels. - * We will determine whether we have TRAIM before we actually start. - * Now initialize. - */ - -static void -oncore_msg_Cj_init( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char *cp, Cmd[20], Msg[160]; - int mode; - - - /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to - * start again if we go from 0D -> 3D, then loses them again when we - * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. - * For NOW we will turn this aspect of filling SHMEM off for the M12 - */ - - if (instance->chan == 12) { - instance->shmem_bad_Ea = 1; - sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision); - record_clock_stats(&(instance->peer->srcadr), Msg); - } - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */ - - mode = instance->init_type; - - /* If there is Position input in the Config file - * and mode = (1,3) set it as posn hold posn, goto 0D mode. - * or mode = (2,4) set it as INITIAL position, and do Site Survey. - */ - - if (instance->posn_set) { - record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data"); - oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */ - } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */ - if (instance->chan != 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx)); - - if (mode != 0) { - /* cable delay in ns */ - memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az)); - w32_buf(&Cmd[-2+4], instance->delay); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */ - - /* PPS offset in ns */ - if (instance->offset) { - memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */ - w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */ - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay)); - } - - /* Satellite mask angle */ - - if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */ - memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag)); - Cmd[-2+4] = instance->Ag; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ag)); - } - } - - /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s - * now we're really running - * these were ALL started in the chan test, - * However, if we had mode=3,4 then commands got turned off, so we turn - * them on again here just in case - */ - - if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba )); - } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea )); - } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha )); - } - - instance->count = 1; - instance->o_state = ONCORE_ALMANAC; - cp = "state = ONCORE_ALMANAC"; - record_clock_stats(&(instance->peer->srcadr), cp); -} - - - -/* 12chan position */ - -static void -oncore_msg_Ga( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char Msg[160]; - long lat, lon, ht; - double Lat, Lon, Ht; - - - lat = buf_w32(&buf[4]); - lon = buf_w32(&buf[8]); - ht = buf_w32(&buf[12]); /* GPS ellipsoid */ - - Lat = lat; - Lon = lon; - Ht = ht; - - Lat /= 3600000; - Lon /= 3600000; - Ht /= 100; - - - sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht); - record_clock_stats(&(instance->peer->srcadr), Msg); - - instance->ss_lat = lat; - instance->ss_long = lon; - instance->ss_ht = ht; - - oncore_print_posn(instance); -} - - - -/* 12 chan time/date */ - -static void -oncore_msg_Gb( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char Msg[160], *gmts; - int mo, d, y, h, m, s, gmth, gmtm; - - mo = buf[4]; - d = buf[5]; - y = 256*buf[6]+buf[7]; - - h = buf[8]; - m = buf[9]; - s = buf[10]; - - gmts = ((buf[11] == 0) ? "+" : "-"); - gmth = buf[12]; - gmtm = buf[13]; - - sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", - d, Month[mo+1], y, h, m, s, gmts, gmth, gmtm); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* - * Try to use Oncore M12+Timing Auto Survey Feature - * If its not there (M12), set flag to do it ourselves. - */ - -static void -oncore_msg_Gd( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - char *cp; - - if (instance->site_survey == ONCORE_SS_TESTING) { - if (buf[4] == 3) { - record_clock_stats(&(instance->peer->srcadr), - "Initiating hardware 3D site survey"); - - cp = "SSstate = ONCORE_SS_HW"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->site_survey = ONCORE_SS_HW; - } - } -} - - - -/* Leap Second for M12, gives all info from satellite message */ -/* also in UT v3.0 */ - -static void -oncore_msg_Gj( - struct instance *instance, - u_char *buf, - size_t len - ) -{ - int dt; - char Msg[160], *cp; - - instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ - - /* 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->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ - buf[8] == instance->BEHa[4]) { /* month */ - if (dt) { - if (dt < 0) { - instance->peer->leap = LEAP_DELSECOND; - cp = "Set peer.leap to LEAP_DELSECOND"; - } else { - instance->peer->leap = LEAP_ADDSECOND; - cp = "Set peer.leap to LEAP_ADDSECOND"; - } - } - } - record_clock_stats(&(instance->peer->srcadr), cp); -} - - - -/* Power on failure */ - -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); - } -} - -/************** Small Subroutines ***************/ - - -static void -oncore_antenna_report( - struct instance *instance, - enum antenna_state new_state) -{ - char *cp; - - if (instance->ant_state == new_state) - return; - - switch (new_state) { - case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; - case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; - case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; - case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; - default: cp = "GPS antenna: ?"; break; - } - - instance->ant_state = new_state; - record_clock_stats(&instance->peer->srcadr, cp); -} - - - -static void -oncore_chan_test( - struct instance *instance - ) -{ - char *cp; - - /* subroutine oncore_Cj_id has determined the number of channels from the - * model number of the attached oncore. This is not always correct since - * the oncore could have non-standard firmware. Here we check (independently) by - * trying a 6, 8, and 12 chan command, and see which responds. - * Caution: more than one CAN respond. - * - * This #chan is used by the code rather than that calculated from the model number. - */ - - instance->o_state = ONCORE_CHECK_CHAN; - cp = "state = ONCORE_CHECK_CHAN"; - record_clock_stats(&(instance->peer->srcadr), cp); - - instance->count3 = 1; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); -} - - - -/* check for a GOOD Almanac, have we got one yet? */ - -static void -oncore_check_almanac( - struct instance *instance - ) -{ - if (instance->chan == 6) { - instance->rsm.bad_almanac = instance->BEHa[64]&0x1; - instance->rsm.bad_fix = instance->BEHa[64]&0x52; - } else if (instance->chan == 8) { - instance->rsm.bad_almanac = instance->BEHa[72]&0x1; - instance->rsm.bad_fix = instance->BEHa[72]&0x52; - } else if (instance->chan == 12) { - int bits1, bits2; - - bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ - bits2 = instance->BEHa[130]; - instance->rsm.bad_almanac = (bits2 & 0x80); - instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); - /* too few sat Bad Geom */ -#if 0 - fprintf(stderr, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n", - instance->unit, - instance->BEHa[129], instance->BEHa[130], bits1, bits2, instance->mode == MODE_0D, - instance->mode == MODE_2D, instance->mode == MODE_3D, - instance->rsm.bad_almanac, instance->rsm.bad_fix); -#endif - } -} - - - -/* check the antenna for changes (did it get unplugged?) */ - -static void -oncore_check_antenna( - struct instance *instance - ) -{ - enum antenna_state antenna; /* antenna state */ - - antenna = instance->ant_state; - if (instance->chan == 12) - antenna = (instance->BEHa[130] & 0x6 ) >> 1; - else - antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */ - - oncore_antenna_report (instance, antenna); -} - - - -/* - * Check the leap second status once per day. - * - * Note that the ONCORE firmware for the Bj command is wrong at - * least in the VP. - * It starts advertising a LEAP SECOND as soon as the GPS satellite - * data message (page 18, subframe 4) is updated to a date in the - * future, and does not wait for the month that it will occur. - * The event will usually be advertised several months in advance. - * Since there is a one bit flag, there is no way to tell if it is - * this month, or when... - * - * As such, we have the workaround below, of only checking for leap - * seconds with the Bj command in June/December. - * - * The Gj command gives more information, and we can tell in which - * month to apply the correction. - * - * Note that with the VP we COULD read the raw data message, and - * interpret it ourselves, but since this is specific to this receiver - * only, and the above workaround is adequate, we don't bother. - */ - -static void -oncore_check_leap_sec( - struct instance *instance - ) -{ - if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */ - instance->Bj_day = instance->BEHa[5]; - - if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */ - if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); - return; - } - - if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */ - instance->count4 = 1; - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); - return; - } - - /* Gj works for some 6/8 chan UT and the M12 */ - /* if no response from Gj in 5 sec, we try Bj */ - /* which isnt implemented in all the GT/UT either */ - - if (instance->count4) { /* delay, waiting for Gj response */ - if (instance->saw_Gj == 1) - instance->count4 = 0; - else if (instance->count4++ > 5) { /* delay, waiting for Gj response */ - instance->saw_Gj = -1; /* didnt see it, will use Bj */ - instance->count4 = 0; - if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); - } - } -} - - - -/* check the message checksum, - * buf points to START of message ( @@ ) - * len is length WITH CR/LF. - */ - -static int -oncore_checksum_ok( - u_char *buf, - int len - ) -{ - int i, j; - - j = 0; - for (i = 2; i < len-3; i++) - j ^= buf[i]; - - return(j == buf[len-3]); -} - - - -static void -oncore_compute_dH( - struct instance *instance - ) -{ - int GPS, MSL; - char Msg[160]; - - /* Here calculate dH = GPS - MSL for output message */ - /* also set Altitude Hold mode if GT */ - - instance->have_dH = 1; - if (instance->chan == 12) { - GPS = buf_w32(&instance->BEHa[39]); - MSL = buf_w32(&instance->BEHa[43]); - } else { - GPS = buf_w32(&instance->BEHa[23]); - MSL = buf_w32(&instance->BEHa[27]); - } - instance->dH = GPS - MSL; - instance->dH /= 100.; - - /* if MSL is not set, the calculation is meaningless */ - - if (MSL) { /* not set ! */ - sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH); - record_clock_stats(&(instance->peer->srcadr), Msg); - } -} - - - -/* - * try loading Almanac from shmem (where it was copied from shmem_old - */ - -static void -oncore_load_almanac( - struct instance *instance - ) -{ - u_char *cp, Cmd[20]; - int n; - struct timeval tv; - struct tm *tm; - - if (!instance->shmem) - return; - -#if 1 - for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { - if (!strncmp(cp, "@@Cb", 4) && - oncore_checksum_ok(cp, 33) && - (*(cp+4) == 4 || *(cp+4) == 5)) { - write(instance->ttyfd, cp, n); -#if 1 - oncore_print_Cb(instance, cp); -#endif - } - } -#else -/************DEBUG************/ - for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { - char Msg[160]; - - sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4)); - record_clock_stats(&(instance->peer->srcadr), Msg); - - if (!strncmp(cp, "@@Cb", 4)) { - oncore_print_Cb(instance, cp); - if (oncore_checksum_ok(cp, 33)) { - if (*(cp+4) == 4 || *(cp+4) == 5) { - record_clock_stats(&(instance->peer->srcadr), "GOOD SF"); - write(instance->ttyfd, cp, n); - } else - record_clock_stats(&(instance->peer->srcadr), "BAD SF"); - } else - record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM"); - } - } -/************DEBUG************/ -#endif - - /* Must load position and time or the Almanac doesn't do us any good */ - - if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */ - record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM"); - for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { - if ((instance->chan == 6 && (!strncmp(cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) || - (instance->chan == 8 && (!strncmp(cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) || - (instance->chan == 12 && (!strncmp(cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) { - int ii, jj, kk; - - instance->posn_set = 1; - ii = buf_w32(cp + 15); - jj = buf_w32(cp + 19); - kk = buf_w32(cp + 23); -{ -char Msg[160]; -sprintf(Msg, "SHMEM posn = %d (%d, %d, %d)", cp-instance->shmem, ii, jj, kk); -record_clock_stats(&(instance->peer->srcadr), Msg); -} - if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */ - instance->ss_lat = ii; - instance->ss_long = jj; - instance->ss_ht = kk; - } - } - } - } - oncore_set_posn(instance); - - /* and set time to time from Computer clock */ - - gettimeofday(&tv, 0); - tm = gmtime((const time_t *) &tv.tv_sec); -#if 1 - { - char Msg[160]; - sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - record_clock_stats(&(instance->peer->srcadr), Msg); - } -#endif - if (instance->chan == 12) { - memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb)); - Cmd[-2+4] = tm->tm_mon; - Cmd[-2+5] = tm->tm_mday; - Cmd[-2+6] = (1900+tm->tm_year)/256; - Cmd[-2+7] = (1900+tm->tm_year)%256; - Cmd[-2+8] = tm->tm_hour; - Cmd[-2+9] = tm->tm_min; - Cmd[-2+10] = tm->tm_sec; - Cmd[-2+11] = 0; - Cmd[-2+12] = 0; - Cmd[-2+13] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb)); - } else { - /* First set GMT offset to zero */ - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab)); - - memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac)); - Cmd[-2+4] = tm->tm_mon; - Cmd[-2+5] = tm->tm_mday; - Cmd[-2+6] = (1900+tm->tm_year)/256; - Cmd[-2+7] = (1900+tm->tm_year)%256; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ac)); - - memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa)); - Cmd[-2+4] = tm->tm_hour; - Cmd[-2+5] = tm->tm_min; - Cmd[-2+6] = tm->tm_sec; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Aa)); - } - - record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac"); -} - - - -/* Almanac data input */ - -static void -oncore_print_Cb( - struct instance *instance, - u_char *cp - ) -{ -#if 0 - int ii; - char Msg[160]; - - printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3)); - printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5)); - for(ii=0; ii<33; ii++) - printf(" %d", *(cp+ii)); - printf("\n"); - - sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5)); - record_clock_stats(&(instance->peer->srcadr), Msg); -#endif -} - - -#if 0 -static void -oncore_print_array( - u_char *cp, - int n - ) -{ - int jj, i, j, nn; - - nn = 0; - printf("\nTOP\n"); - jj = n/16; - for (j=0; j<jj; j++) { - printf("%4d: ", nn); - nn += 16; - for (i=0; i<16; i++) - printf(" %o", *cp++); - printf("\n"); - } -} -#endif - - -static void -oncore_print_posn( - 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'; - lon = instance->ss_long; - if (lon < 0) { - ew = 'W'; - lon = -lon; - } - - ns = 'N'; - lat = instance->ss_lat; - if (lat < 0) { - ns = 'S'; - lat = -lat; - } - - hm = instance->ss_ht/100.; - hft= hm/0.3048; - - xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ - yd = lon/3600000.; - sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft); - record_clock_stats(&(instance->peer->srcadr), Msg); - - idx = xd; - idy = yd; - imx = lat%3600000; - imy = lon%3600000; - xm = imx/60000.; - ym = imy/60000.; - sprintf(Msg, - "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft); - record_clock_stats(&(instance->peer->srcadr), Msg); - - imx = xm; - imy = ym; - is = lat%60000; - xs = is/1000.; - is = lon%60000; - ys = is/1000.; - sprintf(Msg, - "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); - record_clock_stats(&(instance->peer->srcadr), Msg); -} - - - -/* - * write message to Oncore. - */ - -static void -oncore_sendmsg( - int fd, - u_char *ptr, - size_t len - ) -{ - u_char cs = 0; - - if (debug > 4) - printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len); - write(fd, "@@", (size_t) 2); - write(fd, ptr, len); - while (len--) - cs ^= *ptr++; - write(fd, &cs, (size_t) 1); - write(fd, "\r\n", (size_t) 2); -} - - - -static void -oncore_set_posn( - struct instance *instance - ) -{ - int mode; - char Cmd[20]; - - /* Turn OFF position hold, it needs to be off to set position (for some units), - will get set ON in @@Ea later */ - - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */ - else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */ - } - - mode = instance->init_type; - - if (mode != 0) { /* first set posn hold position */ - memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */ - w32_buf(&Cmd[-2+4], (int) instance->ss_lat); - w32_buf(&Cmd[-2+8], (int) instance->ss_long); - w32_buf(&Cmd[-2+12], (int) instance->ss_ht); - Cmd[-2+16] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */ - - memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au)); - w32_buf(&Cmd[-2+4], (int) instance->ss_ht); - Cmd[-2+8] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */ - - /* next set current position */ - - if (instance->chan == 12) { - memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga)); - w32_buf(&Cmd[-2+4], (int) instance->ss_lat); - w32_buf(&Cmd[-2+8], (int) instance->ss_long); - w32_buf(&Cmd[-2+12],(int) instance->ss_ht); - Cmd[-2+16] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */ - } else { - memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad)); - w32_buf(&Cmd[-2+4], (int) instance->ss_lat); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */ - - memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae)); - w32_buf(&Cmd[-2+4], (int) instance->ss_long); - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */ - - memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af)); - w32_buf(&Cmd[-2+4], (int) instance->ss_ht); - Cmd[-2+8] = 0; - oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */ - } - - /* Finally, turn on position hold */ - - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); - else - oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); - } -} - - - -static void -oncore_set_traim( - struct instance *instance - ) -{ - char Msg[160]; - - if (instance->traim_in != -1) /* set in Input */ - instance->traim = instance->traim_in; - else - instance->traim = instance->traim_ck; - - sprintf(Msg, "Input says TRAIM = %d", instance->traim_in); - record_clock_stats(&(instance->peer->srcadr), Msg); - sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id); - record_clock_stats(&(instance->peer->srcadr), Msg); - sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck); - record_clock_stats(&(instance->peer->srcadr), Msg); - sprintf(Msg, "Using TRAIM = %d", instance->traim); - record_clock_stats(&(instance->peer->srcadr), Msg); - - if (instance->traim_ck == 1 && instance->traim == 0) { - /* if it should be off, and I turned it on during testing, - then turn it off again */ - if (instance->chan == 6) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx)); - else if (instance->chan == 8) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); - else /* chan == 12 */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); - } -} - - - -/* - * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. - */ - -static void -oncore_shmem_get_3D( - struct instance *instance - ) -{ - if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */ - instance->shmem_reset = 1; - if (instance->chan == 12) { - if (instance->shmem_Posn == 2) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ - else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ - } else { - if (instance->saw_At) { /* out of 0D -> 3D mode */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); - if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); - } else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); - } - } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { - instance->shmem_reset = 0; - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ - else { - if (instance->saw_At) { - if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); - oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ - } else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); - } - } -} - - - -/* - * Here we do the Software SiteSurvey. - * We have to average our own position for the Position Hold Mode - * We use Heights from the GPS ellipsoid. - * We check for the END of either HW or SW SiteSurvey. - */ - -static void -oncore_ss( - struct instance *instance - ) -{ - char *cp, Msg[160]; - double lat, lon, ht; - - - if (instance->site_survey == ONCORE_SS_HW) { - - /* - * Check to see if Hardware SiteSurvey has Finished. - */ - - if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) || - (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) { - record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); - - if (instance->chan == 12) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); - else - oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); - - cp = "SSstate = ONCORE_SS_DONE"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->site_survey = ONCORE_SS_DONE; - } - } else { - /* - * Must be a Software Site Survey. - */ - - if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ - return; - - if (instance->mode != MODE_3D) /* Use only 3D Fixes */ - return; - - instance->ss_lat += buf_w32(&instance->BEHa[15]); - instance->ss_long += buf_w32(&instance->BEHa[19]); - instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */ - instance->ss_count++; - - if (instance->ss_count != POS_HOLD_AVERAGE) - return; - - instance->ss_lat /= POS_HOLD_AVERAGE; - instance->ss_long /= POS_HOLD_AVERAGE; - instance->ss_ht /= POS_HOLD_AVERAGE; - - sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)", - instance->ss_lat, instance->ss_long, instance->ss_ht); - record_clock_stats(&(instance->peer->srcadr), Msg); - lat = instance->ss_lat/3600000.; - lon = instance->ss_long/3600000.; - ht = instance->ss_ht/100; - sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)", - lat, lon, ht); - record_clock_stats(&(instance->peer->srcadr), Msg); - - oncore_set_posn(instance); - - record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); - - cp = "SSstate = ONCORE_SS_DONE"; - record_clock_stats(&(instance->peer->srcadr), cp); - instance->site_survey = ONCORE_SS_DONE; - } -} - - - -static int -oncore_wait_almanac( - struct instance *instance - ) -{ - if (instance->rsm.bad_almanac) { - if (debug) - printf("ONCORE[%d]: waiting for almanac\n", instance->unit); - - /* - * If we get here (first time) then we don't have an almanac in memory. - * Check if we have a SHMEM, and if so try to load whatever is there. - */ - - if (!instance->almanac_from_shmem) { - instance->almanac_from_shmem = 1; - oncore_load_almanac(instance); - } - return(1); - } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn - commands, and can finally check for TRAIM. Again, we set a delay - (5sec) and wait for things to settle down */ - - if (instance->chan == 6) - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); - else if (instance->chan == 8) - oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En)); - else if (instance->chan == 12) { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */ - } - instance->traim_delay = 1; - - record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC"); - - instance->o_state = ONCORE_RUN; - record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN"); - } - return(0); -} - - - -#else -int refclock_oncore_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_palisade.c b/contrib/ntp/ntpd/refclock_palisade.c deleted file mode 100644 index 897221b..0000000 --- a/contrib/ntp/ntpd/refclock_palisade.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * This software was developed by the Software and Component Technologies - * group of 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 - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Trimble Navigation, Ltd. - * 4. The name of Trimble Navigation Ltd. may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * refclock_palisade - clock driver for the Trimble Palisade GPS - * timing receiver - * - * For detailed information on this program, please refer to the html - * Refclock 29 page accompanying the NTP distribution. - * - * for questions / bugs / comments, contact: - * sven_dietrich@trimble.com - * - * Sven-Thorsten Dietrich - * 645 North Mary Avenue - * Post Office Box 3642 - * Sunnyvale, CA 94088-3642 - * - * Version 2.45; July 14, 1999 - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - -#if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE)) - -#include "refclock_palisade.h" -/* Table to get from month to day of the year */ -const int days_of_year [12] = { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 -}; - -#ifdef DEBUG -const char * Tracking_Status[15][15] = { - { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" }, - {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" }, - { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" }, - { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" }, - { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } }; -#endif - -/* - * Transfer vector - */ -struct refclock refclock_palisade = { - palisade_start, /* start up driver */ - palisade_shutdown, /* shut down driver */ - palisade_poll, /* transmit poll message */ - noentry, /* not used */ - noentry, /* initialize driver (not used) */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - -int day_of_year P((char *dt)); - -/* Extract the clock type from the mode setting */ -#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F)) - -/* Supported clock types */ -#define CLK_TRIMBLE 0 /* Trimble Palisade */ -#define CLK_PRAECIS 1 /* Endrun Technologies Praecis */ - -int praecis_msg; -static void praecis_parse(struct recvbuf *rbufp, struct peer *peer); - -/* - * palisade_start - open the devices and initialize data for processing - */ -static int -palisade_start ( -#ifdef PALISADE - unit, peer - ) - int unit; - struct peer *peer; -#else /* ANSI */ - int unit, - struct peer *peer - ) -#endif -{ - struct palisade_unit *up; - struct refclockproc *pp; - int fd; - char gpsdev[20]; - - struct termios tio; -#ifdef SYS_WINNT - (void) sprintf(gpsdev, "COM%d:", unit); -#else - (void) sprintf(gpsdev, DEVICE, unit); -#endif - /* - * Open serial port. - */ -#if defined PALISADE - fd = open(gpsdev, O_RDWR -#ifdef O_NONBLOCK - | O_NONBLOCK -#endif - ); -#else /* NTP 4.x */ - fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); -#endif - if (fd <= 0) { -#ifdef DEBUG - printf("Palisade(%d) start: open %s failed\n", unit, gpsdev); -#endif - return 0; - } - - msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd, - gpsdev); - -#if defined PALISADE - tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD); - tio.c_iflag = (IGNBRK); - tio.c_oflag = (0); - tio.c_lflag = (0); - - if (cfsetispeed(&tio, SPEED232) == -1) { - msyslog(LOG_ERR,"Palisade(%d) cfsetispeed(fd, &tio): %m",unit); -#ifdef DEBUG - printf("Palisade(%d) cfsetispeed(fd, &tio)\n",unit); -#endif - return 0; - } - if (cfsetospeed(&tio, SPEED232) == -1) { -#ifdef DEBUG - printf("Palisade(%d) cfsetospeed(fd, &tio)\n",unit); -#endif - msyslog(LOG_ERR,"Palisade(%d) cfsetospeed(fd, &tio): %m",unit); - return 0; - } -#else /* NTP 4.x */ - if (tcgetattr(fd, &tio) < 0) { - msyslog(LOG_ERR, - "Palisade(%d) tcgetattr(fd, &tio): %m",unit); -#ifdef DEBUG - printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit); -#endif - return (0); - } - - tio.c_cflag |= (PARENB|PARODD); - tio.c_iflag &= ~ICRNL; -#endif /* NTP 4.x */ - - if (tcsetattr(fd, TCSANOW, &tio) == -1) { - msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); -#ifdef DEBUG - printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit); -#endif - return 0; - } - - /* - * Allocate and initialize unit structure - */ - up = (struct palisade_unit *) emalloc(sizeof(struct palisade_unit)); - - if (!(up)) { - msyslog(LOG_ERR, "Palisade(%d) emalloc: %m",unit); -#ifdef DEBUG - printf("Palisade(%d) emalloc\n",unit); -#endif - (void) close(fd); - return (0); - } - - memset((char *)up, 0, sizeof(struct palisade_unit)); - - up->type = CLK_TYPE(peer); - switch (up->type) { - case CLK_TRIMBLE: - /* Normal mode, do nothing */ - break; - case CLK_PRAECIS: - msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled\n",unit); - break; - default: - msyslog(LOG_NOTICE, "Palisade(%d) mode unknown\n",unit); - break; - } - - pp = peer->procptr; - pp->io.clock_recv = palisade_io; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { -#ifdef DEBUG - printf("Palisade(%d) io_addclock\n",unit); -#endif - (void) close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - pp->unitptr = (caddr_t)up; - pp->clockdesc = DESCRIPTION; - - peer->precision = PRECISION; - peer->sstclktype = CTL_SST_TS_UHF; - peer->minpoll = TRMB_MINPOLL; - peer->maxpoll = TRMB_MAXPOLL; - memcpy((char *)&pp->refid, REFID, 4); - - up->leap_status = 0; - up->unit = (short) unit; - up->rpt_status = TSIP_PARSED_EMPTY; - up->rpt_cnt = 0; - - return 1; -} - - -/* - * palisade_shutdown - shut down the clock - */ -static void -palisade_shutdown ( -#ifdef PALISADE - unit, peer - ) - int unit; - struct peer *peer; -#else /* ANSI */ - int unit, - struct peer *peer - ) -#endif -{ - struct palisade_unit *up; - struct refclockproc *pp; - pp = peer->procptr; - up = (struct palisade_unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - - -/* - * unpack_date - get day and year from date - */ -int -day_of_year ( -#ifdef PALISADE - dt - ) - char * dt; -#else - char * dt - ) -#endif -{ - int day, mon, year; - - mon = dt[1]; - /* Check month is inside array bounds */ - if ((mon < 1) || (mon > 12)) - return -1; - - day = dt[0] + days_of_year[mon - 1]; - year = getint((u_char *) (dt + 2)); - - if ( !(year % 4) && ((year % 100) || - (!(year % 100) && !(year%400))) - &&(mon > 2)) - day ++; /* leap year and March or later */ - - return day; -} - - -/* - * TSIP_decode - decode the TSIP data packets - */ -int -TSIP_decode ( -#ifdef PALISADE - peer - ) - struct peer *peer; -#else - struct peer *peer - ) -#endif -{ - int st; - long secint; - double secs; - double secfrac; - unsigned short event = 0; - - struct palisade_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct palisade_unit *)pp->unitptr; - - /* - * Check the time packet, decode its contents. - * If the timecode has invalid length or is not in - * proper format, declare bad format and exit. - */ - - if ((up->rpt_buf[0] == (char) 0x41) || - (up->rpt_buf[0] == (char) 0x46) || - (up->rpt_buf[0] == (char) 0x54) || - (up->rpt_buf[0] == (char) 0x4B) || - (up->rpt_buf[0] == (char) 0x6D)) { - - /* standard time packet - GPS time and GPS week number */ -#ifdef DEBUG - printf("Palisade Port B packets detected. Connect to Port A\n"); -#endif - - return 0; - } - - /* - * We cast both to u_char to as 0x8f uses the sign bit on a char - */ - if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) { - /* - * Superpackets - */ - event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff); - if (!((pp->sloppyclockflag & CLK_FLAG2) || event)) - /* Ignore Packet */ - return 0; - - switch (mb(0) & 0xff) { - int GPS_UTC_Offset; - case PACKET_8F0B: - - if (up->polled <= 0) - return 0; - - if (up->rpt_cnt != LENCODE_8F0B) /* check length */ - break; - -#ifdef DEBUG -if (debug > 1) { - int ts; - double lat, lon, alt; - lat = getdbl((u_char *) &mb(42)) * R2D; - lon = getdbl((u_char *) &mb(50)) * R2D; - alt = getdbl((u_char *) &mb(58)); - - printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", - up->unit, lat,lon,alt); - printf("TSIP_decode: unit %d: Sats:", up->unit); - for (st = 66, ts = 0; st <= 73; st++) if (mb(st)) { - if (mb(st) > 0) ts++; - printf(" %02d", mb(st)); - } - printf(" : Tracking %d\n", ts); - } -#endif - - GPS_UTC_Offset = getint((u_char *) &mb(16)); - if (GPS_UTC_Offset == 0) { /* Check UTC offset */ -#ifdef DEBUG - printf("TSIP_decode: UTC Offset Unknown\n"); -#endif - break; - } - - secs = getdbl((u_char *) &mb(3)); - secint = (long) secs; - secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ - - pp->nsec = (long) (secfrac * 1000000000); - - secint %= 86400; /* Only care about today */ - pp->hour = secint / 3600; - secint %= 3600; - pp->minute = secint / 60; - secint %= 60; - pp->second = secint % 60; - - if ((pp->day = day_of_year(&mb(11))) < 0) break; - - pp->year = getint((u_char *) &mb(13)); - -#ifdef DEBUG - if (debug > 1) - printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02d\n", - up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, - pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset); -#endif - /* Only use this packet when no - * 8F-AD's are being received - */ - - if (up->leap_status) { - up->leap_status = 0; - return 0; - } - - return 2; - break; - - case PACKET_NTP: - /* Palisade-NTP Packet */ - - if (up->rpt_cnt != LENCODE_NTP) /* check length */ - break; - - up->leap_status = mb(19); - - if (up->polled <= 0) - return 0; - - /* Check Tracking Status */ - st = mb(18); - if (st < 0 || st > 14) st = 14; - if ((st >= 2 && st <= 7) || st == 11 || st == 12) { -#ifdef DEBUG - printf("TSIP_decode: Not Tracking Sats : %s\n", - *Tracking_Status[st]); -#endif - refclock_report(peer, CEVNT_BADTIME); - up->polled = -1; - return 0; - break; - } - - if (up->leap_status & PALISADE_LEAP_PENDING) { - if (up->leap_status & PALISADE_UTC_TIME) - pp->leap = LEAP_ADDSECOND; - else - pp->leap = LEAP_DELSECOND; - } - else if (up->leap_status) - pp->leap = LEAP_NOWARNING; - - else { /* UTC flag is not set: - * Receiver may have been reset, and lost - * its UTC almanac data */ - pp->leap = LEAP_NOTINSYNC; -#ifdef DEBUG - printf("TSIP_decode: UTC Almanac unavailable: %d\n", - mb(19)); -#endif - refclock_report(peer, CEVNT_BADTIME); - up->polled = -1; - return 0; - } - - pp->nsec = (long) (getdbl((u_char *) &mb(3)) * 1000000); - - if ((pp->day = day_of_year(&mb(14))) < 0) - break; - pp->year = getint((u_char *) &mb(16)); - pp->hour = mb(11); - pp->minute = mb(12); - pp->second = mb(13); - -#ifdef DEBUG - if (debug > 1) -printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02x %s\n", - up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, - pp->second, pp->nsec, mb(15), mb(14), pp->year, - mb(19), *Tracking_Status[st]); -#endif - return 1; - break; - - default: - /* Ignore Packet */ - return 0; - } /* switch */ - }/* if 8F packets */ - - refclock_report(peer, CEVNT_BADREPLY); - up->polled = -1; -#ifdef DEBUG - printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", - up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, - event, up->rpt_cnt); -#endif - return 0; -} - -/* - * palisade__receive - receive data from the serial interface - */ - -static void -palisade_receive ( -#ifdef PALISADE - peer - ) - struct peer * peer; -#else /* ANSI */ - struct peer * peer - ) -#endif -{ - struct palisade_unit *up; - struct refclockproc *pp; - - /* - * Initialize pointers and read the timecode and timestamp. - */ - pp = peer->procptr; - up = (struct palisade_unit *)pp->unitptr; - - if (! TSIP_decode(peer)) return; - - if (up->polled <= 0) - return; /* no poll pending, already received or timeout */ - - up->polled = 0; /* Poll reply received */ - pp->lencode = 0; /* clear time code */ -#ifdef DEBUG - if (debug) - printf( - "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n", - up->unit, pp->year, pp->day, pp->hour, pp->minute, - pp->second, pp->nsec); -#endif - - /* - * Process the sample - * Generate timecode: YYYY DoY HH:MM:SS.microsec - * report and process - */ - - (void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld", - pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->nsec); - pp->lencode = 24; - -#ifdef PALISADE - pp->lasttime = current_time; -#endif - if (!refclock_process(pp -#ifdef PALISADE - , PALISADE_SAMPLES, PALISADE_SAMPLES * 3 / 5 -#endif - )) { - refclock_report(peer, CEVNT_BADTIME); - -#ifdef DEBUG - printf("palisade_receive: unit %d: refclock_process failed!\n", - up->unit); -#endif - return; - } - - record_clock_stats(&peer->srcadr, pp->a_lastcode); - -#ifdef DEBUG - if (debug) - printf("palisade_receive: unit %d: %s\n", - up->unit, prettydate(&pp->lastrec)); -#endif - pp->lastref = pp->lastrec; - refclock_receive(peer -#ifdef PALISADE - , &pp->offset, 0, pp->dispersion, - &pp->lastrec, &pp->lastrec, pp->leap -#endif - ); -} - - -/* - * palisade_poll - called by the transmit procedure - * - */ -static void -palisade_poll ( -#ifdef PALISADE - unit, peer - ) - int unit; - struct peer *peer; -#else - int unit, - struct peer *peer - ) -#endif -{ - struct palisade_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct palisade_unit *)pp->unitptr; - - pp->polls++; - if (up->polled > 0) /* last reply never arrived or error */ - refclock_report(peer, CEVNT_TIMEOUT); - - up->polled = 2; /* synchronous packet + 1 event */ - -#ifdef DEBUG - if (debug) - printf("palisade_poll: unit %d: polling %s\n", unit, - (pp->sloppyclockflag & CLK_FLAG2) ? - "synchronous packet" : "event"); -#endif - - if (pp->sloppyclockflag & CLK_FLAG2) - return; /* using synchronous packet input */ - - if(up->type == CLK_PRAECIS) { - if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) - msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); - else { - praecis_msg = 1; - return; - } - } - - if (HW_poll(pp) < 0) - refclock_report(peer, CEVNT_FAULT); -} - -static void -praecis_parse(struct recvbuf *rbufp, struct peer *peer) -{ - static char buf[100]; - static int p = 0; - struct refclockproc *pp; - - pp = peer->procptr; - - memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); - p += rbufp->recv_length; - - if(buf[p-2] == '\r' && buf[p-1] == '\n') { - buf[p-2] = '\0'; - record_clock_stats(&peer->srcadr, buf); - - p = 0; - praecis_msg = 0; - - if (HW_poll(pp) < 0) - refclock_report(peer, CEVNT_FAULT); - - } -} - -static void -palisade_io ( -#ifdef PALISADE - rbufp - ) - struct recvbuf *rbufp; -#else /* ANSI */ - struct recvbuf *rbufp - ) -#endif -{ - /* - * Initialize pointers and read the timecode and timestamp. - */ - struct palisade_unit *up; - struct refclockproc *pp; - struct peer *peer; - - char * c, * d; - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct palisade_unit *)pp->unitptr; - - if(up->type == CLK_PRAECIS) { - if(praecis_msg) { - praecis_parse(rbufp,peer); - return; - } - } - - c = (char *) &rbufp->recv_space; - d = c + rbufp->recv_length; - - while (c != d) { - - /* Build time packet */ - switch (up->rpt_status) { - - case TSIP_PARSED_DLE_1: - switch (*c) - { - case 0: - case DLE: - case ETX: - up->rpt_status = TSIP_PARSED_EMPTY; - break; - - default: - up->rpt_status = TSIP_PARSED_DATA; - /* save packet ID */ - up->rpt_buf[0] = *c; - break; - } - break; - - case TSIP_PARSED_DATA: - if (*c == DLE) - up->rpt_status = TSIP_PARSED_DLE_2; - else - mb(up->rpt_cnt++) = *c; - break; - - case TSIP_PARSED_DLE_2: - if (*c == DLE) { - up->rpt_status = TSIP_PARSED_DATA; - mb(up->rpt_cnt++) = - *c; - } - else if (*c == ETX) - up->rpt_status = TSIP_PARSED_FULL; - else { - /* error: start new report packet */ - up->rpt_status = TSIP_PARSED_DLE_1; - up->rpt_buf[0] = *c; - } - break; - - case TSIP_PARSED_FULL: - case TSIP_PARSED_EMPTY: - default: - if ( *c != DLE) - up->rpt_status = TSIP_PARSED_EMPTY; - else - up->rpt_status = TSIP_PARSED_DLE_1; - break; - } - - c++; - - if (up->rpt_status == TSIP_PARSED_DLE_1) { - up->rpt_cnt = 0; - if (pp->sloppyclockflag & CLK_FLAG2) - /* stamp it */ - get_systime(&pp->lastrec); - } - else if (up->rpt_status == TSIP_PARSED_EMPTY) - up->rpt_cnt = 0; - - else if (up->rpt_cnt > BMAX) - up->rpt_status =TSIP_PARSED_EMPTY; - - if (up->rpt_status == TSIP_PARSED_FULL) - palisade_receive(peer); - - } /* while chars in buffer */ -} - - -/* - * Trigger the Palisade's event input, which is driven off the RTS - * - * Take a system time stamp to match the GPS time stamp. - * - */ -long -HW_poll ( -#ifdef PALISADE - pp /* pointer to unit structure */ - ) - struct refclockproc * pp; /* pointer to unit structure */ -#else - struct refclockproc * pp /* pointer to unit structure */ - ) -#endif -{ - int x; /* state before & after RTS set */ - struct palisade_unit *up; - - up = (struct palisade_unit *) pp->unitptr; - - /* read the current status, so we put things back right */ - if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { -#ifdef DEBUG - if (debug) - printf("Palisade HW_poll: unit %d: GET %s\n", up->unit, strerror(errno)); -#endif - msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", - up->unit); - return -1; - } - - x |= TIOCM_RTS; /* turn on RTS */ - - /* Edge trigger */ - if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { -#ifdef DEBUG - if (debug) - printf("Palisade HW_poll: unit %d: SET \n", up->unit); -#endif - msyslog(LOG_ERR, - "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", - up->unit); - return -1; - } - - x &= ~TIOCM_RTS; /* turn off RTS */ - - /* poll timestamp */ - get_systime(&pp->lastrec); - - if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { -#ifdef DEBUG - if (debug) - printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); -#endif - msyslog(LOG_ERR, - "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", - up->unit); - return -1; - } - - return 0; -} - -#if 0 /* unused */ -/* - * this 'casts' a character array into a float - */ -float -getfloat ( -#ifdef PALISADE - bp - ) - u_char *bp; -#else - u_char *bp - ) -#endif -{ - float sval; -#ifdef WORDS_BIGENDIAN - ((char *) &sval)[0] = *bp++; - ((char *) &sval)[1] = *bp++; - ((char *) &sval)[2] = *bp++; - ((char *) &sval)[3] = *bp++; -#else - ((char *) &sval)[3] = *bp++; - ((char *) &sval)[2] = *bp++; - ((char *) &sval)[1] = *bp++; - ((char *) &sval)[0] = *bp; -#endif /* ! XNTP_BIG_ENDIAN */ - return sval; -} -#endif - -/* - * this 'casts' a character array into a double - */ -double -getdbl ( -#ifdef PALISADE - bp - ) - u_char *bp; -#else - u_char *bp - ) -#endif -{ - double dval; -#ifdef WORDS_BIGENDIAN - ((char *) &dval)[0] = *bp++; - ((char *) &dval)[1] = *bp++; - ((char *) &dval)[2] = *bp++; - ((char *) &dval)[3] = *bp++; - ((char *) &dval)[4] = *bp++; - ((char *) &dval)[5] = *bp++; - ((char *) &dval)[6] = *bp++; - ((char *) &dval)[7] = *bp; -#else - ((char *) &dval)[7] = *bp++; - ((char *) &dval)[6] = *bp++; - ((char *) &dval)[5] = *bp++; - ((char *) &dval)[4] = *bp++; - ((char *) &dval)[3] = *bp++; - ((char *) &dval)[2] = *bp++; - ((char *) &dval)[1] = *bp++; - ((char *) &dval)[0] = *bp; -#endif /* ! XNTP_BIG_ENDIAN */ - return dval; -} - -/* - * cast a 16 bit character array into a short (16 bit) int - */ -short -getint ( -#ifdef PALISADE - bp - ) - u_char *bp; -#else - u_char *bp - ) -#endif -{ -return (short) (bp[1] + (bp[0] << 8)); -} - -#else -int refclock_palisade_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_palisade.h b/contrib/ntp/ntpd/refclock_palisade.h deleted file mode 100644 index 7e1ed49..0000000 --- a/contrib/ntp/ntpd/refclock_palisade.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * This software was developed by the Software and Component Technologies - * group of 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 - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Trimble Navigation, Ltd. - * 4. The name of Trimble Navigation Ltd. may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * refclock_palisade - clock driver for the Trimble Palisade GPS - * timing receiver - * - * For detailed information on this program, please refer to the html - * Refclock 29 page accompanying the NTP distribution. - * - * for questions / bugs / comments, contact: - * sven_dietrich@trimble.com - * - * Sven-Thorsten Dietrich - * 645 North Mary Avenue - * Post Office Box 3642 - * Sunnyvale, CA 94088-3642 - * - */ - -#ifndef _REFCLOCK_PALISADE_H -#define _REFCLOCK_PALISADE_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#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 - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_control.h" -#include "ntp_refclock.h" -#include "ntp_unixtime.h" -#include "ntp_stdlib.h" - -/* - * GPS Definitions - */ -#define DESCRIPTION "Trimble Palisade GPS" /* Long name */ -#define PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS\0" /* reference ID */ -#define TRMB_MINPOLL 4 /* 16 seconds */ -#define TRMB_MAXPOLL 5 /* 32 seconds */ - -/* - * I/O Definitions - */ -#define DEVICE "/dev/palisade%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ - -/* - * TSIP Report Definitions - */ -#define LENCODE_8F0B 74 /* Length of TSIP 8F-0B Packet & header */ -#define LENCODE_NTP 22 /* Length of Palisade NTP Packet */ - -/* Allowed Sub-Packet ID's */ -#define PACKET_8F0B 0x0B -#define PACKET_NTP 0xAD - -#define DLE 0x10 -#define ETX 0x03 - -/* parse states */ -#define TSIP_PARSED_EMPTY 0 -#define TSIP_PARSED_FULL 1 -#define TSIP_PARSED_DLE_1 2 -#define TSIP_PARSED_DATA 3 -#define TSIP_PARSED_DLE_2 4 - -/* - * Leap-Insert and Leap-Delete are encoded as follows: - * PALISADE_UTC_TIME set and PALISADE_LEAP_PENDING set: INSERT leap - */ - -#define PALISADE_LEAP_INPROGRESS 0x08 /* This is the leap flag */ -#define PALISADE_LEAP_WARNING 0x04 /* GPS Leap Warning (see ICD-200) */ -#define PALISADE_LEAP_PENDING 0x02 /* Leap Pending (24 hours) */ -#define PALISADE_UTC_TIME 0x01 /* UTC time available */ - -#define mb(_X_) (up->rpt_buf[(_X_ + 1)]) /* shortcut for buffer access */ - -/* Conversion Definitions */ -#define GPS_PI (3.1415926535898) -#define R2D (180.0/GPS_PI) - -/* - * Palisade unit control structure. - */ -struct palisade_unit { - short unit; /* NTP refclock unit number */ - int polled; /* flag to detect noreplies */ - char leap_status; /* leap second flag */ - char rpt_status; /* TSIP Parser State */ - short rpt_cnt; /* TSIP packet length so far */ - char rpt_buf[BMAX]; /* packet assembly buffer */ - int type; /* Clock mode type */ -}; - -/* - * Function prototypes - */ - -static int palisade_start P((int, struct peer *)); -static void palisade_shutdown P((int, struct peer *)); -static void palisade_receive P((struct peer *)); -static void palisade_poll P((int, struct peer *)); -static void palisade_io P((struct recvbuf *)); -int palisade_configure P((int, struct peer *)); -int TSIP_decode P((struct peer *)); -long HW_poll P((struct refclockproc *)); -float getfloat P((u_char *)); -double getdbl P((u_char *)); -short getint P((u_char *)); - -#endif /* PALISADE_H */ diff --git a/contrib/ntp/ntpd/refclock_parse.c b/contrib/ntp/ntpd/refclock_parse.c deleted file mode 100644 index 52fadaa..0000000 --- a/contrib/ntp/ntpd/refclock_parse.c +++ /dev/null @@ -1,5386 +0,0 @@ -/* - * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A - * - * refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A - * - * generic reference clock driver for receivers - * - * optionally make use of a STREAMS module for input processing where - * available and configured. Currently the STREAMS module - * is only available for Suns running SunOS 4.x and SunOS5.x - * - * the STREAMS module is not required for operation and may be omitted - * at the cost of reduced accuracy. As new kernel interfaces emerger this - * restriction may be lifted in future. - * - * Copyright (c) 1995-1999 by Frank Kardel <kardel@acm.org> - * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany - * - * This software may not be sold for profit without a written consent - * from the author. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_PARSE) - -/* - * This driver currently provides the support for - * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF) - * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF) - * - Meinberg receiver DCF77 PZF 509 (DCF) - * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) - * - IGEL CLOCK (DCF) - * - ELV DCF7000 (DCF) - * - Schmid clock (DCF) - * - Conrad DCF77 receiver module (DCF) - * - FAU DCF77 NTP receiver (TimeBrick) (DCF) - * - * - Meinberg GPS166/GPS167 (GPS) - * - Trimble (TSIP and TAIP protocol) (GPS) - * - * - RCC8000 MSF Receiver (MSF) - * - WHARTON 400A Series clock (DCF) - * - VARITEXT clock (MSF) - */ - -/* - * Meinberg receivers are usually connected via a - * 9600 baud serial line - * - * The Meinberg GPS receivers also have a special NTP time stamp - * format. The firmware release is Uni-Erlangen. - * - * Meinberg generic receiver setup: - * output time code every second - * Baud rate 9600 7E2S - * - * Meinberg GPS16x setup: - * output time code every second - * Baudrate 19200 8N1 - * - * This software supports the standard data formats used - * in Meinberg receivers. - * - * Special software versions are only sensible for the - * GPS 16x family of receivers. - * - * Meinberg can be reached via: http://www.meinberg.de/ - */ - -#include "ntpd.h" -#include "ntp_refclock.h" -#include "ntp_unixtime.h" /* includes <sys/time.h> */ -#include "ntp_control.h" - -#include <stdio.h> -#include <ctype.h> -#ifndef TM_IN_SYS_TIME -# include <time.h> -#endif - -#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) -# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" -#endif - -#ifdef STREAM -# include <sys/stream.h> -# include <sys/stropts.h> -#endif - -#ifdef HAVE_TERMIOS -# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) -# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) -# undef HAVE_SYSV_TTYS -#endif - -#ifdef HAVE_SYSV_TTYS -# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) -# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) -#endif - -#ifdef HAVE_BSD_TTYS -/* #error CURRENTLY NO BSD TTY SUPPORT */ -# include "Bletch: BSD TTY not currently supported" -#endif - -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif - -#ifdef PPS -#ifdef HAVE_SYS_PPSCLOCK_H -#include <sys/ppsclock.h> -#endif -#ifdef HAVE_TIO_SERIAL_STUFF -#include <linux/serial.h> -#endif -#endif - -#include "ntp_io.h" -#include "ntp_stdlib.h" - -#include "parse.h" -#include "mbg_gps166.h" -#include "trimble.h" -#include "binio.h" -#include "ascii.h" -#include "ieee754io.h" - -static char rcsid[]="refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A"; - -/**=========================================================================== - ** external interface to ntp mechanism - **/ - -static void parse_init P((void)); -static int parse_start P((int, struct peer *)); -static void parse_shutdown P((int, struct peer *)); -static void parse_poll P((int, struct peer *)); -static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); - -#define parse_buginfo noentry - -struct refclock refclock_parse = { - parse_start, - parse_shutdown, - parse_poll, - parse_control, - parse_init, - parse_buginfo, - NOFLAGS -}; - -/* - * Definitions - */ -#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ -#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ - -#undef ABS -#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) - -/**=========================================================================== - ** function vector for dynamically binding io handling mechanism - **/ - -struct parseunit; /* to keep inquiring minds happy */ - -typedef struct bind -{ - const char *bd_description; /* name of type of binding */ - int (*bd_init) P((struct parseunit *)); /* initialize */ - void (*bd_end) P((struct parseunit *)); /* end */ - int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */ - int (*bd_disable) P((struct parseunit *)); /* disable */ - int (*bd_enable) P((struct parseunit *)); /* enable */ - int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */ - int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */ - int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */ - void (*bd_receive) P((struct recvbuf *)); /* receive operation */ - int (*bd_io_input) P((struct recvbuf *)); /* input operation */ -} bind_t; - -#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) -#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) -#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) -#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) -#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) -#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) -#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) - -/* - * io modes - */ -#define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */ -#define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */ - - -/**=========================================================================== - ** error message regression handling - ** - ** there are quite a few errors that can occur in rapid succession such as - ** noisy input data or no data at all. in order to reduce the amount of - ** syslog messages in such case, we are using a backoff algorithm. We limit - ** the number of error messages of a certain class to 1 per time unit. if a - ** configurable number of messages is displayed that way, we move on to the - ** next time unit / count for that class. a count of messages that have been - ** suppressed is held and displayed whenever a corresponding message is - ** displayed. the time units for a message class will also be displayed. - ** whenever an error condition clears we reset the error message state, - ** thus we would still generate much output on pathological conditions - ** where the system oscillates between OK and NOT OK states. coping - ** with that condition is currently considered too complicated. - **/ - -#define ERR_ALL (unsigned)~0 /* "all" errors */ -#define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ -#define ERR_NODATA (unsigned)1 /* no input data */ -#define ERR_BADIO (unsigned)2 /* read/write/select errors */ -#define ERR_BADSTATUS (unsigned)3 /* unsync states */ -#define ERR_BADEVENT (unsigned)4 /* non nominal events */ -#define ERR_INTERNAL (unsigned)5 /* internal error */ -#define ERR_CNT (unsigned)(ERR_INTERNAL+1) - -#define ERR(_X_) if (list_err(parse, (_X_))) - -struct errorregression -{ - u_long err_count; /* number of repititions per class */ - u_long err_delay; /* minimum delay between messages */ -}; - -static struct errorregression -err_baddata[] = /* error messages for bad input data */ -{ - { 1, 0 }, /* output first message immediately */ - { 5, 60 }, /* output next five messages in 60 second intervals */ - { 3, 3600 }, /* output next 3 messages in hour intervals */ - { 0, 12*3600 } /* repeat messages only every 12 hours */ -}; - -static struct errorregression -err_nodata[] = /* error messages for missing input data */ -{ - { 1, 0 }, /* output first message immediately */ - { 5, 60 }, /* output next five messages in 60 second intervals */ - { 3, 3600 }, /* output next 3 messages in hour intervals */ - { 0, 12*3600 } /* repeat messages only every 12 hours */ -}; - -static struct errorregression -err_badstatus[] = /* unsynchronized state messages */ -{ - { 1, 0 }, /* output first message immediately */ - { 5, 60 }, /* output next five messages in 60 second intervals */ - { 3, 3600 }, /* output next 3 messages in hour intervals */ - { 0, 12*3600 } /* repeat messages only every 12 hours */ -}; - -static struct errorregression -err_badio[] = /* io failures (bad reads, selects, ...) */ -{ - { 1, 0 }, /* output first message immediately */ - { 5, 60 }, /* output next five messages in 60 second intervals */ - { 5, 3600 }, /* output next 3 messages in hour intervals */ - { 0, 12*3600 } /* repeat messages only every 12 hours */ -}; - -static struct errorregression -err_badevent[] = /* non nominal events */ -{ - { 20, 0 }, /* output first message immediately */ - { 6, 60 }, /* output next five messages in 60 second intervals */ - { 5, 3600 }, /* output next 3 messages in hour intervals */ - { 0, 12*3600 } /* repeat messages only every 12 hours */ -}; - -static struct errorregression -err_internal[] = /* really bad things - basically coding/OS errors */ -{ - { 0, 0 }, /* output all messages immediately */ -}; - -static struct errorregression * -err_tbl[] = -{ - err_baddata, - err_nodata, - err_badio, - err_badstatus, - err_badevent, - err_internal -}; - -struct errorinfo -{ - u_long err_started; /* begin time (ntp) of error condition */ - u_long err_last; /* last time (ntp) error occurred */ - u_long err_cnt; /* number of error repititions */ - u_long err_suppressed; /* number of suppressed messages */ - struct errorregression *err_stage; /* current error stage */ -}; - -/**=========================================================================== - ** refclock instance data - **/ - -struct parseunit -{ - /* - * NTP management - */ - struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ - struct refclockproc *generic; /* backlink to refclockproc structure */ - - /* - * PARSE io - */ - bind_t *binding; /* io handling binding */ - - /* - * parse state - */ - parse_t parseio; /* io handling structure (user level parsing) */ - - /* - * type specific parameters - */ - struct parse_clockinfo *parse_type; /* link to clock description */ - - /* - * clock state handling/reporting - */ - u_char flags; /* flags (leap_control) */ - u_long lastchange; /* time (ntp) when last state change accured */ - u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ - u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ - u_short lastformat; /* last format used */ - u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ - u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ - u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ - parsetime_t time; /* last (parse module) data */ - void *localdata; /* optional local, receiver-specific data */ - unsigned long localstate; /* private local state */ - struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ - struct ctl_var *kv; /* additional pseudo variables */ - u_long laststatistic; /* time when staticstics where output */ -}; - - -/**=========================================================================== - ** Clockinfo section all parameter for specific clock types - ** includes NTP parameters, TTY parameters and IO handling parameters - **/ - -static void poll_dpoll P((struct parseunit *)); -static void poll_poll P((struct peer *)); -static int poll_init P((struct parseunit *)); - -typedef struct poll_info -{ - u_long rate; /* poll rate - once every "rate" seconds - 0 off */ - const char *string; /* string to send for polling */ - u_long count; /* number of characters in string */ -} poll_info_t; - -#define NO_CL_FLAGS 0 -#define NO_POLL 0 -#define NO_INIT 0 -#define NO_END 0 -#define NO_EVENT 0 -#define NO_DATA 0 -#define NO_MESSAGE 0 -#define NO_PPSDELAY 0 - -#define DCF_ID "DCF" /* generic DCF */ -#define DCF_A_ID "DCFa" /* AM demodulation */ -#define DCF_P_ID "DCFp" /* psuedo random phase shift */ -#define GPS_ID "GPS" /* GPS receiver */ - -#define NOCLOCK_ROOTDELAY 0.0 -#define NOCLOCK_BASEDELAY 0.0 -#define NOCLOCK_DESCRIPTION 0 -#define NOCLOCK_MAXUNSYNC 0 -#define NOCLOCK_CFLAG 0 -#define NOCLOCK_IFLAG 0 -#define NOCLOCK_OFLAG 0 -#define NOCLOCK_LFLAG 0 -#define NOCLOCK_ID "TILT" -#define NOCLOCK_POLL NO_POLL -#define NOCLOCK_INIT NO_INIT -#define NOCLOCK_END NO_END -#define NOCLOCK_DATA NO_DATA -#define NOCLOCK_FORMAT "" -#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC -#define NOCLOCK_SAMPLES 0 -#define NOCLOCK_KEEP 0 - -#define DCF_TYPE CTL_SST_TS_LF -#define GPS_TYPE CTL_SST_TS_UHF - -/* - * receiver specific constants - */ -#define MBG_SPEED (B9600) -#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL) -#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) -#define MBG_OFLAG 0 -#define MBG_LFLAG 0 -#define MBG_FLAGS PARSE_F_PPSONSECOND - -/* - * Meinberg DCF77 receivers - */ -#define DCFUA31_ROOTDELAY 0.0 /* 0 */ -#define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ -#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" -#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ -#define DCFUA31_SPEED MBG_SPEED -#define DCFUA31_CFLAG MBG_CFLAG -#define DCFUA31_IFLAG MBG_IFLAG -#define DCFUA31_OFLAG MBG_OFLAG -#define DCFUA31_LFLAG MBG_LFLAG -#define DCFUA31_SAMPLES 5 -#define DCFUA31_KEEP 3 -#define DCFUA31_FORMAT "Meinberg Standard" - -/* - * Meinberg DCF PZF535/TCXO (FM/PZF) receiver - */ -#define DCFPZF535_ROOTDELAY 0.0 -#define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ -#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" -#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours - * @ 5e-8df/f we have accumulated - * at most 2.16 ms (thus we move to - * NTP synchronisation */ -#define DCFPZF535_SPEED MBG_SPEED -#define DCFPZF535_CFLAG MBG_CFLAG -#define DCFPZF535_IFLAG MBG_IFLAG -#define DCFPZF535_OFLAG MBG_OFLAG -#define DCFPZF535_LFLAG MBG_LFLAG -#define DCFPZF535_SAMPLES 5 -#define DCFPZF535_KEEP 3 -#define DCFPZF535_FORMAT "Meinberg Standard" - -/* - * Meinberg DCF PZF535/OCXO receiver - */ -#define DCFPZF535OCXO_ROOTDELAY 0.0 -#define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ -#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" -#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days - * @ 5e-9df/f we have accumulated - * at most an error of 1.73 ms - * (thus we move to NTP synchronisation) */ -#define DCFPZF535OCXO_SPEED MBG_SPEED -#define DCFPZF535OCXO_CFLAG MBG_CFLAG -#define DCFPZF535OCXO_IFLAG MBG_IFLAG -#define DCFPZF535OCXO_OFLAG MBG_OFLAG -#define DCFPZF535OCXO_LFLAG MBG_LFLAG -#define DCFPZF535OCXO_SAMPLES 5 -#define DCFPZF535OCXO_KEEP 3 -#define DCFPZF535OCXO_FORMAT "Meinberg Standard" - -/* - * Meinberg GPS16X receiver - */ -static void gps16x_message P((struct parseunit *, parsetime_t *)); -static int gps16x_poll_init P((struct parseunit *)); - -#define GPS16X_ROOTDELAY 0.0 /* nothing here */ -#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ -#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver" -#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days - * @ 5e-9df/f we have accumulated - * at most an error of 1.73 ms - * (thus we move to NTP synchronisation) */ -#define GPS16X_SPEED B19200 -#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) -#define GPS16X_IFLAG (IGNBRK|IGNPAR) -#define GPS16X_OFLAG MBG_OFLAG -#define GPS16X_LFLAG MBG_LFLAG -#define GPS16X_POLLRATE 6 -#define GPS16X_POLLCMD "" -#define GPS16X_CMDSIZE 0 - -static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; - -#define GPS16X_INIT gps16x_poll_init -#define GPS16X_POLL 0 -#define GPS16X_END 0 -#define GPS16X_DATA ((void *)(&gps16x_pollinfo)) -#define GPS16X_MESSAGE gps16x_message -#define GPS16X_ID GPS_ID -#define GPS16X_FORMAT "Meinberg GPS Extended" -#define GPS16X_SAMPLES 5 -#define GPS16X_KEEP 3 - -/* - * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) - * - * This is really not the hottest clock - but before you have nothing ... - */ -#define DCF7000_ROOTDELAY 0.0 /* 0 */ -#define DCF7000_BASEDELAY 0.405 /* slow blow */ -#define DCF7000_DESCRIPTION "ELV DCF7000" -#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ -#define DCF7000_SPEED (B9600) -#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) -#define DCF7000_IFLAG (IGNBRK) -#define DCF7000_OFLAG 0 -#define DCF7000_LFLAG 0 -#define DCF7000_SAMPLES 5 -#define DCF7000_KEEP 3 -#define DCF7000_FORMAT "ELV DCF7000" - -/* - * Schmid DCF Receiver Kit - * - * When the WSDCF clock is operating optimally we want the primary clock - * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer - * structure is set to 290 ms and we compute delays which are at least - * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format - */ -#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ -#define WS_POLLCMD "\163" -#define WS_CMDSIZE 1 - -static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; - -#define WSDCF_INIT poll_init -#define WSDCF_POLL poll_dpoll -#define WSDCF_END 0 -#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) -#define WSDCF_ROOTDELAY 0.0 /* 0 */ -#define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ -#define WSDCF_DESCRIPTION "WS/DCF Receiver" -#define WSDCF_FORMAT "Schmid" -#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ -#define WSDCF_SPEED (B1200) -#define WSDCF_CFLAG (CS8|CREAD|CLOCAL) -#define WSDCF_IFLAG 0 -#define WSDCF_OFLAG 0 -#define WSDCF_LFLAG 0 -#define WSDCF_SAMPLES 5 -#define WSDCF_KEEP 3 - -/* - * RAW DCF77 - input of DCF marks via RS232 - many variants - */ -#define RAWDCF_FLAGS 0 -#define RAWDCF_ROOTDELAY 0.0 /* 0 */ -#define RAWDCF_BASEDELAY 0.258 -#define RAWDCF_FORMAT "RAW DCF77 Timecode" -#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ -#define RAWDCF_SPEED (B50) -#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ -/* somehow doesn't grok PARENB & IGNPAR (mj) */ -# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) -#else -# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) -#endif -#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ -# define RAWDCF_IFLAG 0 -#else -# define RAWDCF_IFLAG (IGNPAR) -#endif -#define RAWDCF_OFLAG 0 -#define RAWDCF_LFLAG 0 -#define RAWDCF_SAMPLES 20 -#define RAWDCF_KEEP 12 -#define RAWDCF_INIT 0 - -/* - * RAW DCF variants - */ -/* - * Conrad receiver - * - * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad - * (~40DM - roughly $30 ) followed by a level converter for RS232 - */ -#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ -#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" - -/* - * TimeBrick receiver - */ -#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ -#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" - -/* - * IGEL:clock receiver - */ -#define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ -#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" -#define IGELCLOCK_SPEED (B1200) -#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) - -/* - * RAWDCF receivers that need to be powered from DTR - * (like Expert mouse clock) - */ -static int rawdcf_init_1 P((struct parseunit *)); -#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" -#define RAWDCFDTRSET_INIT rawdcf_init_1 - -/* - * RAWDCF receivers that need to be powered from - * DTR CLR and RTS SET - */ -static int rawdcf_init_2 P((struct parseunit *)); -#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" -#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 - -/* - * Trimble GPS receivers (TAIP and TSIP protocols) - */ -#ifndef TRIM_POLLRATE -#define TRIM_POLLRATE 0 /* only true direct polling */ -#endif - -#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" -#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) - -static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; -static int trimbletaip_init P((struct parseunit *)); -static void trimbletaip_event P((struct parseunit *, int)); - -/* query time & UTC correction data */ -static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; - -static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; -static int trimbletsip_init P((struct parseunit *)); -static void trimbletsip_end P((struct parseunit *)); -static void trimbletsip_message P((struct parseunit *, parsetime_t *)); -static void trimbletsip_event P((struct parseunit *, int)); - -#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ - -#define TRIMBLETAIP_SPEED (B4800) -#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) -#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) -#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) -#define TRIMBLETAIP_LFLAG (0) - -#define TRIMBLETSIP_SPEED (B9600) -#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) -#define TRIMBLETSIP_IFLAG (IGNBRK) -#define TRIMBLETSIP_OFLAG (0) -#define TRIMBLETSIP_LFLAG (ICANON) - -#define TRIMBLETSIP_SAMPLES 5 -#define TRIMBLETSIP_KEEP 3 -#define TRIMBLETAIP_SAMPLES 5 -#define TRIMBLETAIP_KEEP 3 - -#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) -#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) - -#define TRIMBLETAIP_POLL poll_dpoll -#define TRIMBLETSIP_POLL poll_dpoll - -#define TRIMBLETAIP_INIT trimbletaip_init -#define TRIMBLETSIP_INIT trimbletsip_init - -#define TRIMBLETAIP_EVENT trimbletaip_event - -#define TRIMBLETSIP_EVENT trimbletsip_event -#define TRIMBLETSIP_MESSAGE trimbletsip_message - -#define TRIMBLETAIP_END 0 -#define TRIMBLETSIP_END trimbletsip_end - -#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) -#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) - -#define TRIMBLETAIP_ID GPS_ID -#define TRIMBLETSIP_ID GPS_ID - -#define TRIMBLETAIP_FORMAT "Trimble TAIP" -#define TRIMBLETSIP_FORMAT "Trimble TSIP" - -#define TRIMBLETAIP_ROOTDELAY 0x0 -#define TRIMBLETSIP_ROOTDELAY 0x0 - -#define TRIMBLETAIP_BASEDELAY 0.0 -#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ - -#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" -#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" - -#define TRIMBLETAIP_MAXUNSYNC 0 -#define TRIMBLETSIP_MAXUNSYNC 0 - -#define TRIMBLETAIP_EOL '<' - -/* - * RadioCode Clocks RCC 800 receiver - */ -#define RCC_POLLRATE 0 /* only true direct polling */ -#define RCC_POLLCMD "\r" -#define RCC_CMDSIZE 1 - -static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; -#define RCC8000_FLAGS 0 -#define RCC8000_POLL poll_dpoll -#define RCC8000_INIT poll_init -#define RCC8000_END 0 -#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) -#define RCC8000_ROOTDELAY 0.0 -#define RCC8000_BASEDELAY 0.0 -#define RCC8000_ID "MSF" -#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" -#define RCC8000_FORMAT "Radiocode RCC8000" -#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ -#define RCC8000_SPEED (B2400) -#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) -#define RCC8000_IFLAG (IGNBRK|IGNPAR) -#define RCC8000_OFLAG 0 -#define RCC8000_LFLAG 0 -#define RCC8000_SAMPLES 5 -#define RCC8000_KEEP 3 - -/* - * Hopf Radio clock 6021 Format - * - */ -#define HOPF6021_ROOTDELAY 0.0 -#define HOPF6021_BASEDELAY 0.0 -#define HOPF6021_DESCRIPTION "HOPF 6021" -#define HOPF6021_FORMAT "hopf Funkuhr 6021" -#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ -#define HOPF6021_SPEED (B9600) -#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) -#define HOPF6021_IFLAG (IGNBRK|ISTRIP) -#define HOPF6021_OFLAG 0 -#define HOPF6021_LFLAG 0 -#define HOPF6021_FLAGS 0 -#define HOPF6021_SAMPLES 5 -#define HOPF6021_KEEP 3 - -/* - * Diem's Computime Radio Clock Receiver - */ -#define COMPUTIME_FLAGS 0 -#define COMPUTIME_ROOTDELAY 0.0 -#define COMPUTIME_BASEDELAY 0.0 -#define COMPUTIME_ID DCF_ID -#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" -#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" -#define COMPUTIME_TYPE DCF_TYPE -#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ -#define COMPUTIME_SPEED (B9600) -#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) -#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) -#define COMPUTIME_OFLAG 0 -#define COMPUTIME_LFLAG 0 -#define COMPUTIME_SAMPLES 5 -#define COMPUTIME_KEEP 3 - -/* - * Varitext Radio Clock Receiver - */ -#define VARITEXT_FLAGS 0 -#define VARITEXT_ROOTDELAY 0.0 -#define VARITEXT_BASEDELAY 0.0 -#define VARITEXT_ID "MSF" -#define VARITEXT_DESCRIPTION "Varitext receiver" -#define VARITEXT_FORMAT "Varitext Radio Clock" -#define VARITEXT_TYPE DCF_TYPE -#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ -#define VARITEXT_SPEED (B9600) -#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) -#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ -#define VARITEXT_OFLAG 0 -#define VARITEXT_LFLAG 0 -#define VARITEXT_SAMPLES 32 -#define VARITEXT_KEEP 20 - -static struct parse_clockinfo -{ - u_long cl_flags; /* operation flags (io modes) */ - void (*cl_poll) P((struct parseunit *)); /* active poll routine */ - int (*cl_init) P((struct parseunit *)); /* active poll init routine */ - void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */ - void (*cl_end) P((struct parseunit *)); /* active poll end routine */ - void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */ - void *cl_data; /* local data area for "poll" mechanism */ - double cl_rootdelay; /* rootdelay */ - double cl_basedelay; /* current offset by which the RS232 - time code is delayed from the actual time */ - const char *cl_id; /* ID code */ - const char *cl_description; /* device name */ - const char *cl_format; /* fixed format */ - u_char cl_type; /* clock type (ntp control) */ - u_long cl_maxunsync; /* time to trust oscillator after losing synch */ - u_long cl_speed; /* terminal input & output baudrate */ - u_long cl_cflag; /* terminal control flags */ - u_long cl_iflag; /* terminal input flags */ - u_long cl_oflag; /* terminal output flags */ - u_long cl_lflag; /* terminal local flags */ - u_long cl_samples; /* samples for median filter */ - u_long cl_keep; /* samples for median filter to keep */ -} parse_clockinfo[] = -{ - { /* mode 0 */ - MBG_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - DCFPZF535_ROOTDELAY, - DCFPZF535_BASEDELAY, - DCF_P_ID, - DCFPZF535_DESCRIPTION, - DCFPZF535_FORMAT, - DCF_TYPE, - DCFPZF535_MAXUNSYNC, - DCFPZF535_SPEED, - DCFPZF535_CFLAG, - DCFPZF535_IFLAG, - DCFPZF535_OFLAG, - DCFPZF535_LFLAG, - DCFPZF535_SAMPLES, - DCFPZF535_KEEP - }, - { /* mode 1 */ - MBG_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - DCFPZF535OCXO_ROOTDELAY, - DCFPZF535OCXO_BASEDELAY, - DCF_P_ID, - DCFPZF535OCXO_DESCRIPTION, - DCFPZF535OCXO_FORMAT, - DCF_TYPE, - DCFPZF535OCXO_MAXUNSYNC, - DCFPZF535OCXO_SPEED, - DCFPZF535OCXO_CFLAG, - DCFPZF535OCXO_IFLAG, - DCFPZF535OCXO_OFLAG, - DCFPZF535OCXO_LFLAG, - DCFPZF535OCXO_SAMPLES, - DCFPZF535OCXO_KEEP - }, - { /* mode 2 */ - MBG_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - DCFUA31_ROOTDELAY, - DCFUA31_BASEDELAY, - DCF_A_ID, - DCFUA31_DESCRIPTION, - DCFUA31_FORMAT, - DCF_TYPE, - DCFUA31_MAXUNSYNC, - DCFUA31_SPEED, - DCFUA31_CFLAG, - DCFUA31_IFLAG, - DCFUA31_OFLAG, - DCFUA31_LFLAG, - DCFUA31_SAMPLES, - DCFUA31_KEEP - }, - { /* mode 3 */ - MBG_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - DCF7000_ROOTDELAY, - DCF7000_BASEDELAY, - DCF_A_ID, - DCF7000_DESCRIPTION, - DCF7000_FORMAT, - DCF_TYPE, - DCF7000_MAXUNSYNC, - DCF7000_SPEED, - DCF7000_CFLAG, - DCF7000_IFLAG, - DCF7000_OFLAG, - DCF7000_LFLAG, - DCF7000_SAMPLES, - DCF7000_KEEP - }, - { /* mode 4 */ - NO_CL_FLAGS, - WSDCF_POLL, - WSDCF_INIT, - NO_EVENT, - WSDCF_END, - NO_MESSAGE, - WSDCF_DATA, - WSDCF_ROOTDELAY, - WSDCF_BASEDELAY, - DCF_A_ID, - WSDCF_DESCRIPTION, - WSDCF_FORMAT, - DCF_TYPE, - WSDCF_MAXUNSYNC, - WSDCF_SPEED, - WSDCF_CFLAG, - WSDCF_IFLAG, - WSDCF_OFLAG, - WSDCF_LFLAG, - WSDCF_SAMPLES, - WSDCF_KEEP - }, - { /* mode 5 */ - RAWDCF_FLAGS, - NO_POLL, - RAWDCF_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - RAWDCF_ROOTDELAY, - CONRAD_BASEDELAY, - DCF_A_ID, - CONRAD_DESCRIPTION, - RAWDCF_FORMAT, - DCF_TYPE, - RAWDCF_MAXUNSYNC, - RAWDCF_SPEED, - RAWDCF_CFLAG, - RAWDCF_IFLAG, - RAWDCF_OFLAG, - RAWDCF_LFLAG, - RAWDCF_SAMPLES, - RAWDCF_KEEP - }, - { /* mode 6 */ - RAWDCF_FLAGS, - NO_POLL, - RAWDCF_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - RAWDCF_ROOTDELAY, - TIMEBRICK_BASEDELAY, - DCF_A_ID, - TIMEBRICK_DESCRIPTION, - RAWDCF_FORMAT, - DCF_TYPE, - RAWDCF_MAXUNSYNC, - RAWDCF_SPEED, - RAWDCF_CFLAG, - RAWDCF_IFLAG, - RAWDCF_OFLAG, - RAWDCF_LFLAG, - RAWDCF_SAMPLES, - RAWDCF_KEEP - }, - { /* mode 7 */ - MBG_FLAGS, - GPS16X_POLL, - GPS16X_INIT, - NO_EVENT, - GPS16X_END, - GPS16X_MESSAGE, - GPS16X_DATA, - GPS16X_ROOTDELAY, - GPS16X_BASEDELAY, - GPS16X_ID, - GPS16X_DESCRIPTION, - GPS16X_FORMAT, - GPS_TYPE, - GPS16X_MAXUNSYNC, - GPS16X_SPEED, - GPS16X_CFLAG, - GPS16X_IFLAG, - GPS16X_OFLAG, - GPS16X_LFLAG, - GPS16X_SAMPLES, - GPS16X_KEEP - }, - { /* mode 8 */ - RAWDCF_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - RAWDCF_ROOTDELAY, - IGELCLOCK_BASEDELAY, - DCF_A_ID, - IGELCLOCK_DESCRIPTION, - RAWDCF_FORMAT, - DCF_TYPE, - RAWDCF_MAXUNSYNC, - IGELCLOCK_SPEED, - IGELCLOCK_CFLAG, - RAWDCF_IFLAG, - RAWDCF_OFLAG, - RAWDCF_LFLAG, - RAWDCF_SAMPLES, - RAWDCF_KEEP - }, - { /* mode 9 */ - TRIMBLETAIP_FLAGS, -#if TRIM_POLLRATE /* DHD940515: Allow user config */ - NO_POLL, -#else - TRIMBLETAIP_POLL, -#endif - TRIMBLETAIP_INIT, - TRIMBLETAIP_EVENT, - TRIMBLETAIP_END, - NO_MESSAGE, - TRIMBLETAIP_DATA, - TRIMBLETAIP_ROOTDELAY, - TRIMBLETAIP_BASEDELAY, - TRIMBLETAIP_ID, - TRIMBLETAIP_DESCRIPTION, - TRIMBLETAIP_FORMAT, - GPS_TYPE, - TRIMBLETAIP_MAXUNSYNC, - TRIMBLETAIP_SPEED, - TRIMBLETAIP_CFLAG, - TRIMBLETAIP_IFLAG, - TRIMBLETAIP_OFLAG, - TRIMBLETAIP_LFLAG, - TRIMBLETAIP_SAMPLES, - TRIMBLETAIP_KEEP - }, - { /* mode 10 */ - TRIMBLETSIP_FLAGS, -#if TRIM_POLLRATE /* DHD940515: Allow user config */ - NO_POLL, -#else - TRIMBLETSIP_POLL, -#endif - TRIMBLETSIP_INIT, - TRIMBLETSIP_EVENT, - TRIMBLETSIP_END, - TRIMBLETSIP_MESSAGE, - TRIMBLETSIP_DATA, - TRIMBLETSIP_ROOTDELAY, - TRIMBLETSIP_BASEDELAY, - TRIMBLETSIP_ID, - TRIMBLETSIP_DESCRIPTION, - TRIMBLETSIP_FORMAT, - GPS_TYPE, - TRIMBLETSIP_MAXUNSYNC, - TRIMBLETSIP_SPEED, - TRIMBLETSIP_CFLAG, - TRIMBLETSIP_IFLAG, - TRIMBLETSIP_OFLAG, - TRIMBLETSIP_LFLAG, - TRIMBLETSIP_SAMPLES, - TRIMBLETSIP_KEEP - }, - { /* mode 11 */ - NO_CL_FLAGS, - RCC8000_POLL, - RCC8000_INIT, - NO_EVENT, - RCC8000_END, - NO_MESSAGE, - RCC8000_DATA, - RCC8000_ROOTDELAY, - RCC8000_BASEDELAY, - RCC8000_ID, - RCC8000_DESCRIPTION, - RCC8000_FORMAT, - DCF_TYPE, - RCC8000_MAXUNSYNC, - RCC8000_SPEED, - RCC8000_CFLAG, - RCC8000_IFLAG, - RCC8000_OFLAG, - RCC8000_LFLAG, - RCC8000_SAMPLES, - RCC8000_KEEP - }, - { /* mode 12 */ - HOPF6021_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - HOPF6021_ROOTDELAY, - HOPF6021_BASEDELAY, - DCF_ID, - HOPF6021_DESCRIPTION, - HOPF6021_FORMAT, - DCF_TYPE, - HOPF6021_MAXUNSYNC, - HOPF6021_SPEED, - HOPF6021_CFLAG, - HOPF6021_IFLAG, - HOPF6021_OFLAG, - HOPF6021_LFLAG, - HOPF6021_SAMPLES, - HOPF6021_KEEP - }, - { /* mode 13 */ - COMPUTIME_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - COMPUTIME_ROOTDELAY, - COMPUTIME_BASEDELAY, - COMPUTIME_ID, - COMPUTIME_DESCRIPTION, - COMPUTIME_FORMAT, - COMPUTIME_TYPE, - COMPUTIME_MAXUNSYNC, - COMPUTIME_SPEED, - COMPUTIME_CFLAG, - COMPUTIME_IFLAG, - COMPUTIME_OFLAG, - COMPUTIME_LFLAG, - COMPUTIME_SAMPLES, - COMPUTIME_KEEP - }, - { /* mode 14 */ - RAWDCF_FLAGS, - NO_POLL, - RAWDCFDTRSET_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - RAWDCF_ROOTDELAY, - RAWDCF_BASEDELAY, - DCF_A_ID, - RAWDCFDTRSET_DESCRIPTION, - RAWDCF_FORMAT, - DCF_TYPE, - RAWDCF_MAXUNSYNC, - RAWDCF_SPEED, - RAWDCF_CFLAG, - RAWDCF_IFLAG, - RAWDCF_OFLAG, - RAWDCF_LFLAG, - RAWDCF_SAMPLES, - RAWDCF_KEEP - }, - { /* mode 15 */ - 0, /* operation flags (io modes) */ - 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 */ - NO_DATA, /* local data area for "poll" mechanism */ - 0, /* rootdelay */ - 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 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 losing synch */ - B9600, /* terminal input & output baudrate */ - (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ - 0, /* terminal input flags */ - 0, /* terminal output flags */ - 0, /* terminal local flags */ - 5, /* samples for median filter */ - 3, /* samples for median filter to keep */ - }, - { /* mode 16 - RAWDCF RTS set, DTR clr */ - RAWDCF_FLAGS, - NO_POLL, - RAWDCFDTRCLRRTSSET_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - RAWDCF_ROOTDELAY, - RAWDCF_BASEDELAY, - DCF_A_ID, - RAWDCFDTRCLRRTSSET_DESCRIPTION, - RAWDCF_FORMAT, - DCF_TYPE, - RAWDCF_MAXUNSYNC, - RAWDCF_SPEED, - RAWDCF_CFLAG, - RAWDCF_IFLAG, - RAWDCF_OFLAG, - RAWDCF_LFLAG, - RAWDCF_SAMPLES, - RAWDCF_KEEP - }, - { /* mode 17 */ - VARITEXT_FLAGS, - NO_POLL, - NO_INIT, - NO_EVENT, - NO_END, - NO_MESSAGE, - NO_DATA, - VARITEXT_ROOTDELAY, - VARITEXT_BASEDELAY, - VARITEXT_ID, - VARITEXT_DESCRIPTION, - VARITEXT_FORMAT, - VARITEXT_TYPE, - VARITEXT_MAXUNSYNC, - VARITEXT_SPEED, - VARITEXT_CFLAG, - VARITEXT_IFLAG, - VARITEXT_OFLAG, - VARITEXT_LFLAG, - VARITEXT_SAMPLES, - VARITEXT_KEEP - } -}; - -static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); - -#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) -#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) -#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) -#define CLK_PPS(x) (((x)->ttl) & 0x80) - -/* - * Other constant stuff - */ -#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ - -#define PARSESTATISTICS (60*60) /* output state statistics every hour */ - -static struct parseunit *parseunits[MAXUNITS]; - -static int notice = 0; - -#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) - -static void parse_event P((struct parseunit *, int)); -static void parse_process P((struct parseunit *, parsetime_t *)); -static void clear_err P((struct parseunit *, u_long)); -static int list_err P((struct parseunit *, u_long)); -static char * l_mktime P((u_long)); - -/**=========================================================================== - ** implementation error message regression module - **/ -static void -clear_err( - struct parseunit *parse, - u_long lstate - ) -{ - if (lstate == ERR_ALL) - { - int i; - - for (i = 0; i < ERR_CNT; i++) - { - parse->errors[i].err_stage = err_tbl[i]; - parse->errors[i].err_cnt = 0; - parse->errors[i].err_last = 0; - parse->errors[i].err_started = 0; - parse->errors[i].err_suppressed = 0; - } - } - else - { - parse->errors[lstate].err_stage = err_tbl[lstate]; - parse->errors[lstate].err_cnt = 0; - parse->errors[lstate].err_last = 0; - parse->errors[lstate].err_started = 0; - parse->errors[lstate].err_suppressed = 0; - } -} - -static int -list_err( - struct parseunit *parse, - u_long lstate - ) -{ - int do_it; - struct errorinfo *err = &parse->errors[lstate]; - - if (err->err_started == 0) - { - err->err_started = current_time; - } - - do_it = (current_time - err->err_last) >= err->err_stage->err_delay; - - if (do_it) - err->err_cnt++; - - if (err->err_stage->err_count && - (err->err_cnt >= err->err_stage->err_count)) - { - err->err_stage++; - err->err_cnt = 0; - } - - if (!err->err_cnt && do_it) - msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", - CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); - - if (!do_it) - err->err_suppressed++; - else - err->err_last = current_time; - - if (do_it && err->err_suppressed) - { - msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", - CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", - l_mktime(current_time - err->err_started)); - err->err_suppressed = 0; - } - - return do_it; -} - -/*-------------------------------------------------- - * mkreadable - make a printable ascii string (without - * embedded quotes so that the ntpq protocol isn't - * fooled - */ -#ifndef isprint -#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) -#endif - -static char * -mkreadable( - char *buffer, - long blen, - const char *src, - u_long srclen, - int hex - ) -{ - char *b = buffer; - char *endb = (char *)0; - - if (blen < 4) - return (char *)0; /* don't bother with mini buffers */ - - endb = buffer + blen - 4; - - blen--; /* account for '\0' */ - - while (blen && srclen--) - { - if (!hex && /* no binary only */ - (*src != '\\') && /* no plain \ */ - (*src != '"') && /* no " */ - isprint((int)*src)) /* only printables */ - { /* they are easy... */ - *buffer++ = *src++; - blen--; - } - else - { - if (blen < 4) - { - while (blen--) - { - *buffer++ = '.'; - } - *buffer = '\0'; - return b; - } - else - { - if (*src == '\\') - { - strcpy(buffer,"\\\\"); - buffer += 2; - blen -= 2; - src++; - } - else - { - sprintf(buffer, "\\x%02x", *src++); - blen -= 4; - buffer += 4; - } - } - } - if (srclen && !blen && endb) /* overflow - set last chars to ... */ - strcpy(endb, "..."); - } - - *buffer = '\0'; - return b; -} - - -/*-------------------------------------------------- - * mkascii - make a printable ascii string - * assumes (unless defined better) 7-bit ASCII - */ -static char * -mkascii( - char *buffer, - long blen, - const char *src, - u_long srclen - ) -{ - return mkreadable(buffer, blen, src, srclen, 0); -} - -/**=========================================================================== - ** implementation of i/o handling methods - ** (all STREAM, partial STREAM, user level) - **/ - -/* - * define possible io handling methods - */ -#ifdef STREAM -static int ppsclock_init P((struct parseunit *)); -static int stream_init P((struct parseunit *)); -static void stream_end P((struct parseunit *)); -static int stream_enable P((struct parseunit *)); -static int stream_disable P((struct parseunit *)); -static int stream_setcs P((struct parseunit *, parsectl_t *)); -static int stream_getfmt P((struct parseunit *, parsectl_t *)); -static int stream_setfmt P((struct parseunit *, parsectl_t *)); -static int stream_timecode P((struct parseunit *, parsectl_t *)); -static void stream_receive P((struct recvbuf *)); -#endif - -static int local_init P((struct parseunit *)); -static void local_end P((struct parseunit *)); -static int local_nop P((struct parseunit *)); -static int local_setcs P((struct parseunit *, parsectl_t *)); -static int local_getfmt P((struct parseunit *, parsectl_t *)); -static int local_setfmt P((struct parseunit *, parsectl_t *)); -static int local_timecode P((struct parseunit *, parsectl_t *)); -static void local_receive P((struct recvbuf *)); -static int local_input P((struct recvbuf *)); - -static bind_t io_bindings[] = -{ -#ifdef STREAM - { - "parse STREAM", - stream_init, - stream_end, - stream_setcs, - stream_disable, - stream_enable, - stream_getfmt, - stream_setfmt, - stream_timecode, - stream_receive, - 0, - }, - { - "ppsclock STREAM", - ppsclock_init, - local_end, - local_setcs, - local_nop, - local_nop, - local_getfmt, - local_setfmt, - local_timecode, - local_receive, - local_input, - }, -#endif - { - "normal", - local_init, - local_end, - local_setcs, - local_nop, - local_nop, - local_getfmt, - local_setfmt, - local_timecode, - local_receive, - local_input, - }, - { - (char *)0, - } -}; - -#ifdef STREAM - -#define fix_ts(_X_) \ - if ((&(_X_))->tv.tv_usec >= 1000000) \ - { \ - (&(_X_))->tv.tv_usec -= 1000000; \ - (&(_X_))->tv.tv_sec += 1; \ - } - -#define cvt_ts(_X_, _Y_) \ - { \ - l_fp ts; \ - fix_ts((_X_)); \ - if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ - { \ - ERR(ERR_BADDATA) \ - msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ - return; \ - } \ - else \ - { \ - (&(_X_))->fp = ts; \ - } \ - } - -/*-------------------------------------------------- - * ppsclock STREAM init - */ -static int -ppsclock_init( - struct parseunit *parse - ) -{ - static char m1[] = "ppsclocd"; - static char m2[] = "ppsclock"; - - /* - * now push the parse streams module - * it will ensure exclusive access to the device - */ - if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 && - ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1) - { - if (errno != EINVAL) - { - msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", - CLK_UNIT(parse->peer)); - } - return 0; - } - if (!local_init(parse)) - { - (void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0); - return 0; - } - - parse->flags |= PARSE_PPSCLOCK; - return 1; -} - -/*-------------------------------------------------- - * parse STREAM init - */ -static int -stream_init( - struct parseunit *parse - ) -{ - static char m1[] = "parse"; - /* - * now push the parse streams module - * to test whether it is there (neat interface 8-( ) - */ - if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) - { - if (errno != EINVAL) /* accept non-existence */ - { - msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); - } - return 0; - } - else - { - while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) - /* empty loop */; - - /* - * now push it a second time after we have removed all - * module garbage - */ - if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); - return 0; - } - else - { - return 1; - } - } -} - -/*-------------------------------------------------- - * parse STREAM end - */ -static void -stream_end( - struct parseunit *parse - ) -{ - while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) - /* empty loop */; -} - -/*-------------------------------------------------- - * STREAM setcs - */ -static int -stream_setcs( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - struct strioctl strioc; - - strioc.ic_cmd = PARSEIOC_SETCS; - strioc.ic_timout = 0; - strioc.ic_dp = (char *)tcl; - strioc.ic_len = sizeof (*tcl); - - if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); - return 0; - } - return 1; -} - -/*-------------------------------------------------- - * STREAM enable - */ -static int -stream_enable( - struct parseunit *parse - ) -{ - struct strioctl strioc; - - strioc.ic_cmd = PARSEIOC_ENABLE; - strioc.ic_timout = 0; - strioc.ic_dp = (char *)0; - strioc.ic_len = 0; - - if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); - return 0; - } - parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ - return 1; -} - -/*-------------------------------------------------- - * STREAM disable - */ -static int -stream_disable( - struct parseunit *parse - ) -{ - struct strioctl strioc; - - strioc.ic_cmd = PARSEIOC_DISABLE; - strioc.ic_timout = 0; - strioc.ic_dp = (char *)0; - strioc.ic_len = 0; - - if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); - return 0; - } - parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ - return 1; -} - -/*-------------------------------------------------- - * STREAM getfmt - */ -static int -stream_getfmt( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - struct strioctl strioc; - - strioc.ic_cmd = PARSEIOC_GETFMT; - strioc.ic_timout = 0; - strioc.ic_dp = (char *)tcl; - strioc.ic_len = sizeof (*tcl); - if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); - return 0; - } - return 1; -} - -/*-------------------------------------------------- - * STREAM setfmt - */ -static int -stream_setfmt( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - struct strioctl strioc; - - strioc.ic_cmd = PARSEIOC_SETFMT; - strioc.ic_timout = 0; - strioc.ic_dp = (char *)tcl; - strioc.ic_len = sizeof (*tcl); - - if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); - return 0; - } - return 1; -} - - -/*-------------------------------------------------- - * STREAM timecode - */ -static int -stream_timecode( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - struct strioctl strioc; - - strioc.ic_cmd = PARSEIOC_TIMECODE; - strioc.ic_timout = 0; - strioc.ic_dp = (char *)tcl; - strioc.ic_len = sizeof (*tcl); - - if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) - { - ERR(ERR_INTERNAL) - msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); - return 0; - } - clear_err(parse, ERR_INTERNAL); - return 1; -} - -/*-------------------------------------------------- - * STREAM receive - */ -static void -stream_receive( - struct recvbuf *rbufp - ) -{ - struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); - parsetime_t parsetime; - - if (!parse->peer) - return; - - if (rbufp->recv_length != sizeof(parsetime_t)) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", - CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); - parse->generic->baddata++; - parse_event(parse, CEVNT_BADREPLY); - return; - } - clear_err(parse, ERR_BADIO); - - memmove((caddr_t)&parsetime, - (caddr_t)rbufp->recv_buffer, - sizeof(parsetime_t)); - -#ifdef DEBUG - if (debug > 3) - { - printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", - CLK_UNIT(parse->peer), - (unsigned int)parsetime.parse_status, - (unsigned int)parsetime.parse_state, - (long)parsetime.parse_time.tv.tv_sec, - (long)parsetime.parse_time.tv.tv_usec, - (long)parsetime.parse_stime.tv.tv_sec, - (long)parsetime.parse_stime.tv.tv_usec, - (long)parsetime.parse_ptime.tv.tv_sec, - (long)parsetime.parse_ptime.tv.tv_usec); - } -#endif - - /* - * switch time stamp world - be sure to normalize small usec field - * errors. - */ - - cvt_ts(parsetime.parse_stime, "parse_stime"); - - if (PARSE_TIMECODE(parsetime.parse_state)) - { - cvt_ts(parsetime.parse_time, "parse_time"); - } - - if (PARSE_PPS(parsetime.parse_state)) - cvt_ts(parsetime.parse_ptime, "parse_ptime"); - - parse_process(parse, &parsetime); -} -#endif - -/*-------------------------------------------------- - * local init - */ -static int -local_init( - struct parseunit *parse - ) -{ - return parse_ioinit(&parse->parseio); -} - -/*-------------------------------------------------- - * local end - */ -static void -local_end( - struct parseunit *parse - ) -{ - parse_ioend(&parse->parseio); -} - - -/*-------------------------------------------------- - * local nop - */ -static int -local_nop( - struct parseunit *parse - ) -{ - return 1; -} - -/*-------------------------------------------------- - * local setcs - */ -static int -local_setcs( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - return parse_setcs(tcl, &parse->parseio); -} - -/*-------------------------------------------------- - * local getfmt - */ -static int -local_getfmt( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - return parse_getfmt(tcl, &parse->parseio); -} - -/*-------------------------------------------------- - * local setfmt - */ -static int -local_setfmt( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - return parse_setfmt(tcl, &parse->parseio); -} - -/*-------------------------------------------------- - * local timecode - */ -static int -local_timecode( - struct parseunit *parse, - parsectl_t *tcl - ) -{ - return parse_timecode(tcl, &parse->parseio); -} - - -/*-------------------------------------------------- - * local input - */ -static int -local_input( - struct recvbuf *rbufp - ) -{ - struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); - int count; - unsigned char *s; - timestamp_t ts; - - if (!parse->peer) - return 0; - - /* - * eat all characters, parsing then and feeding complete samples - */ - count = rbufp->recv_length; - s = (unsigned char *)rbufp->recv_buffer; - ts.fp = rbufp->recv_time; - - while (count--) - { - if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) - { - struct recvbuf buf; - - /* - * got something good to eat - */ - if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) - { -#ifdef TIOCDCDTIMESTAMP - struct timeval dcd_time; - - if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) - { - l_fp tstmp; - - TVTOTS(&dcd_time, &tstmp); - tstmp.l_ui += JAN_1970; - L_SUB(&ts.fp, &tstmp); - if (ts.fp.l_ui == 0) - { -#ifdef DEBUG - if (debug) - { - printf( - "parse: local_receive: fd %d DCDTIMESTAMP %s\n", - rbufp->fd, - lfptoa(&tstmp, 6)); - printf(" sigio %s\n", - lfptoa(&ts.fp, 6)); - } -#endif - parse->parseio.parse_dtime.parse_ptime.fp = tstmp; - parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; - } - } -#else /* TIOCDCDTIMESTAMP */ -#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) - if (parse->flags & PARSE_PPSCLOCK) - { - l_fp tts; - struct ppsclockev ev; - -#ifdef HAVE_CIOGETEV - if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0) -#endif -#ifdef HAVE_TIOCGPPSEV - if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0) -#endif - { - if (ev.serial != parse->ppsserial) - { - /* - * add PPS time stamp if available via ppsclock module - * and not supplied already. - */ - if (!buftvtots((const char *)&ev.tv, &tts)) - { - ERR(ERR_BADDATA) - msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); - } - else - { - parse->parseio.parse_dtime.parse_ptime.fp = tts; - parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; - } - } - parse->ppsserial = ev.serial; - } - } -#endif -#endif /* TIOCDCDTIMESTAMP */ - } - if (count) - { /* simulate receive */ - memmove((caddr_t)buf.recv_buffer, - (caddr_t)&parse->parseio.parse_dtime, - sizeof(parsetime_t)); - parse_iodone(&parse->parseio); - buf.recv_length = sizeof(parsetime_t); - buf.recv_time = rbufp->recv_time; - buf.srcadr = rbufp->srcadr; - buf.dstadr = rbufp->dstadr; - buf.fd = rbufp->fd; - buf.next = 0; - buf.X_from_where = rbufp->X_from_where; - rbufp->receiver(&buf); - } - else - { - memmove((caddr_t)rbufp->recv_buffer, - (caddr_t)&parse->parseio.parse_dtime, - sizeof(parsetime_t)); - parse_iodone(&parse->parseio); - rbufp->recv_length = sizeof(parsetime_t); - return 1; /* got something & in place return */ - } - } - } - return 0; /* nothing to pass up */ -} - -/*-------------------------------------------------- - * local receive - */ -static void -local_receive( - struct recvbuf *rbufp - ) -{ - struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); - parsetime_t parsetime; - - if (!parse->peer) - return; - - if (rbufp->recv_length != sizeof(parsetime_t)) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", - CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); - parse->generic->baddata++; - parse_event(parse, CEVNT_BADREPLY); - return; - } - clear_err(parse, ERR_BADIO); - - memmove((caddr_t)&parsetime, - (caddr_t)rbufp->recv_buffer, - sizeof(parsetime_t)); - -#ifdef DEBUG - if (debug > 3) - { - printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", - CLK_UNIT(parse->peer), - (unsigned int)parsetime.parse_status, - (unsigned int)parsetime.parse_state, - (long)parsetime.parse_time.tv.tv_sec, - (long)parsetime.parse_time.tv.tv_usec, - (long)parsetime.parse_stime.tv.tv_sec, - (long)parsetime.parse_stime.tv.tv_usec, - (long)parsetime.parse_ptime.tv.tv_sec, - (long)parsetime.parse_ptime.tv.tv_usec); - } -#endif - - parse_process(parse, &parsetime); -} - -/*-------------------------------------------------- - * init_iobinding - find and initialize lower layers - */ -static bind_t * -init_iobinding( - struct parseunit *parse - ) -{ - bind_t *b = io_bindings; - - while (b->bd_description != (char *)0) - { - if ((*b->bd_init)(parse)) - { - return b; - } - b++; - } - return (bind_t *)0; -} - -/**=========================================================================== - ** support routines - **/ - -/*-------------------------------------------------- - * convert a flag field to a string - */ -static char * -parsestate( - u_long lstate, - char *buffer - ) -{ - static struct bits - { - u_long bit; - const char *name; - } flagstrings[] = - { - { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, - { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, - { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, - { PARSEB_DST, "DST" }, - { PARSEB_UTC, "UTC DISPLAY" }, - { PARSEB_LEAPADD, "LEAP ADD WARNING" }, - { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, - { PARSEB_LEAPSECOND, "LEAP SECOND" }, - { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" }, - { PARSEB_TIMECODE, "TIME CODE" }, - { PARSEB_PPS, "PPS" }, - { PARSEB_POSITION, "POSITION" }, - { 0 } - }; - - static struct sbits - { - u_long bit; - const char *name; - } sflagstrings[] = - { - { PARSEB_S_LEAP, "LEAP INDICATION" }, - { PARSEB_S_PPS, "PPS SIGNAL" }, - { PARSEB_S_ANTENNA, "ANTENNA" }, - { PARSEB_S_POSITION, "POSITION" }, - { 0 } - }; - int i; - - *buffer = '\0'; - - i = 0; - while (flagstrings[i].bit) - { - if (flagstrings[i].bit & lstate) - { - if (buffer[0]) - strcat(buffer, "; "); - strcat(buffer, flagstrings[i].name); - } - i++; - } - - if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) - { - char *s, *t; - - if (buffer[0]) - strcat(buffer, "; "); - - strcat(buffer, "("); - - t = s = buffer + strlen(buffer); - - i = 0; - while (sflagstrings[i].bit) - { - if (sflagstrings[i].bit & lstate) - { - if (t != s) - { - strcpy(t, "; "); - t += 2; - } - - strcpy(t, sflagstrings[i].name); - t += strlen(t); - } - i++; - } - strcpy(t, ")"); - } - return buffer; -} - -/*-------------------------------------------------- - * convert a status flag field to a string - */ -static char * -parsestatus( - u_long lstate, - char *buffer - ) -{ - static struct bits - { - u_long bit; - const char *name; - } flagstrings[] = - { - { CVT_OK, "CONVERSION SUCCESSFUL" }, - { CVT_NONE, "NO CONVERSION" }, - { CVT_FAIL, "CONVERSION FAILED" }, - { CVT_BADFMT, "ILLEGAL FORMAT" }, - { CVT_BADDATE, "DATE ILLEGAL" }, - { CVT_BADTIME, "TIME ILLEGAL" }, - { CVT_ADDITIONAL, "ADDITIONAL DATA" }, - { 0 } - }; - int i; - - *buffer = '\0'; - - i = 0; - while (flagstrings[i].bit) - { - if (flagstrings[i].bit & lstate) - { - if (buffer[0]) - strcat(buffer, "; "); - strcat(buffer, flagstrings[i].name); - } - i++; - } - - return buffer; -} - -/*-------------------------------------------------- - * convert a clock status flag field to a string - */ -static const char * -clockstatus( - u_long lstate - ) -{ - static char buffer[20]; - static struct status - { - u_long value; - const char *name; - } flagstrings[] = - { - { CEVNT_NOMINAL, "NOMINAL" }, - { CEVNT_TIMEOUT, "NO RESPONSE" }, - { CEVNT_BADREPLY,"BAD FORMAT" }, - { CEVNT_FAULT, "FAULT" }, - { CEVNT_PROP, "PROPAGATION DELAY" }, - { CEVNT_BADDATE, "ILLEGAL DATE" }, - { CEVNT_BADTIME, "ILLEGAL TIME" }, - { (unsigned)~0L } - }; - int i; - - i = 0; - while (flagstrings[i].value != ~0) - { - if (flagstrings[i].value == lstate) - { - return flagstrings[i].name; - } - i++; - } - - sprintf(buffer, "unknown #%ld", (u_long)lstate); - - return buffer; -} - - -/*-------------------------------------------------- - * l_mktime - make representation of a relative time - */ -static char * -l_mktime( - u_long delta - ) -{ - u_long tmp, m, s; - static char buffer[40]; - - buffer[0] = '\0'; - - if ((tmp = delta / (60*60*24)) != 0) - { - sprintf(buffer, "%ldd+", (u_long)tmp); - delta -= tmp * 60*60*24; - } - - s = delta % 60; - delta /= 60; - m = delta % 60; - delta /= 60; - - sprintf(buffer+strlen(buffer), "%02d:%02d:%02d", - (int)delta, (int)m, (int)s); - - return buffer; -} - - -/*-------------------------------------------------- - * parse_statistics - list summary of clock states - */ -static void -parse_statistics( - struct parseunit *parse - ) -{ - int i; - - NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ - { - msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", - CLK_UNIT(parse->peer), - l_mktime(current_time - parse->generic->timestarted)); - - msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", - CLK_UNIT(parse->peer), - clockstatus(parse->generic->currentstatus)); - - for (i = 0; i <= CEVNT_MAX; i++) - { - u_long s_time; - u_long percent, d = current_time - parse->generic->timestarted; - - percent = s_time = PARSE_STATETIME(parse, i); - - while (((u_long)(~0) / 10000) < percent) - { - percent /= 10; - d /= 10; - } - - if (d) - percent = (percent * 10000) / d; - else - percent = 10000; - - if (s_time) - msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", - CLK_UNIT(parse->peer), - clockstatus((unsigned int)i), - l_mktime(s_time), - percent / 100, percent % 100); - } - } -} - -/*-------------------------------------------------- - * cparse_statistics - wrapper for statistics call - */ -static void -cparse_statistics( - register struct parseunit *parse - ) -{ - if (parse->laststatistic + PARSESTATISTICS < current_time) - parse_statistics(parse); - parse->laststatistic = current_time; -} - -/**=========================================================================== - ** ntp interface routines - **/ - -/*-------------------------------------------------- - * parse_init - initialize internal parse driver data - */ -static void -parse_init(void) -{ - memset((caddr_t)parseunits, 0, sizeof parseunits); -} - - -/*-------------------------------------------------- - * parse_shutdown - shut down a PARSE clock - */ -static void -parse_shutdown( - int unit, - struct peer *peer - ) -{ - struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; - - if (parse && !parse->peer) - { - msyslog(LOG_ERR, - "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit); - return; - } - - /* - * print statistics a last time and - * stop statistics machine - */ - parse_statistics(parse); - - if (parse->parse_type->cl_end) - { - parse->parse_type->cl_end(parse); - } - - if (parse->binding) - PARSE_END(parse); - - /* - * Tell the I/O module to turn us off. We're history. - */ - io_closeclock(&parse->generic->io); - - free_varlist(parse->kv); - - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", - CLK_UNIT(parse->peer), parse->parse_type->cl_description); - - parse->peer = (struct peer *)0; /* unused now */ - free(parse); -} - -/*-------------------------------------------------- - * parse_start - open the PARSE devices and initialize data for processing - */ -static int -parse_start( - int sysunit, - struct peer *peer - ) -{ - u_int unit; - int fd232; -#ifdef HAVE_TERMIOS - struct termios tio; /* NEEDED FOR A LONG TIME ! */ -#endif -#ifdef HAVE_SYSV_TTYS - struct termio tio; /* NEEDED FOR A LONG TIME ! */ -#endif - struct parseunit * parse; - char parsedev[sizeof(PARSEDEVICE)+20]; - parsectl_t tmp_ctl; - u_int type; - - type = CLK_TYPE(peer); - unit = CLK_UNIT(peer); - - if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0)) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", - unit, CLK_REALTYPE(peer), ncltypes-1); - return 0; - } - - /* - * Unit okay, attempt to open the device. - */ - (void) sprintf(parsedev, PARSEDEVICE, unit); - -#ifndef O_NOCTTY -#define O_NOCTTY 0 -#endif - - fd232 = open(parsedev, O_RDWR | O_NOCTTY -#ifdef O_NONBLOCK - | O_NONBLOCK -#endif - , 0777); - - if (fd232 == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); - return 0; - } - - parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); - - memset((char *)parse, 0, sizeof(struct parseunit)); - - parse->generic = peer->procptr; /* link up */ - parse->generic->unitptr = (caddr_t)parse; /* link down */ - - /* - * Set up the structures - */ - parse->generic->timestarted = current_time; - parse->lastchange = current_time; - - parse->generic->currentstatus = CEVNT_TIMEOUT; /* expect the worst */ - - parse->flags = 0; - parse->pollneeddata = 0; - parse->laststatistic = current_time; - parse->lastformat = (unsigned short)~0; /* assume no format known */ - parse->time.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ - parse->lastmissed = 0; /* assume got everything */ - parse->ppsserial = 0; - parse->localdata = (void *)0; - parse->localstate = 0; - parse->kv = (struct ctl_var *)0; - - clear_err(parse, ERR_ALL); - - parse->parse_type = &parse_clockinfo[type]; - - parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; - - parse->generic->fudgetime2 = 0.0; - - parse->generic->clockdesc = parse->parse_type->cl_description; - - peer->rootdelay = parse->parse_type->cl_rootdelay; - peer->sstclktype = parse->parse_type->cl_type; - peer->precision = sys_precision; - - peer->stratum = STRATUM_REFCLOCK; - if (peer->stratum <= 1) - memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); - else - parse->generic->refid = htonl(PARSEHSREFID); - - parse->generic->io.fd = fd232; - - parse->peer = peer; /* marks it also as busy */ - - /* - * configure terminal line - */ - if (TTY_GETATTR(fd232, &tio) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; - } - else - { -#ifndef _PC_VDISABLE - memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); -#else - int disablec; - errno = 0; /* pathconf can deliver -1 without changing errno ! */ - - disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); - if (disablec == -1 && errno) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); - memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ - } - else - if (disablec != -1) - memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); -#endif - -#if defined (VMIN) || defined(VTIME) - if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) - { -#ifdef VMIN - tio.c_cc[VMIN] = 1; -#endif -#ifdef VTIME - tio.c_cc[VTIME] = 0; -#endif - } -#endif - - tio.c_cflag = parse_clockinfo[type].cl_cflag; - tio.c_iflag = parse_clockinfo[type].cl_iflag; - tio.c_oflag = parse_clockinfo[type].cl_oflag; - tio.c_lflag = parse_clockinfo[type].cl_lflag; - - -#ifdef HAVE_TERMIOS - if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || - (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; - } -#else - tio.c_cflag |= parse_clockinfo[type].cl_speed; -#endif - -#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ - { - struct serial_struct ss; - if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 || - ( -#ifdef ASYNC_LOW_LATENCY - ss.flags |= ASYNC_LOW_LATENCY, -#endif -#ifdef ASYNC_PPS_CD_NEG - ss.flags |= ASYNC_PPS_CD_NEG, -#endif - ioctl(fd232, TIOCSSERIAL, &ss)) < 0) { - msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232); - msyslog(LOG_NOTICE, - "refclock_parse: optional PPS processing not available"); - } else { - parse->flags |= PARSE_PPSCLOCK; - msyslog(LOG_INFO, - "refclock_parse: PPS detection on"); - } - } -#endif -#ifdef HAVE_TIOCSPPS /* SUN PPS support */ - if (CLK_PPS(parse->peer)) - { - int i = 1; - - if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0) - { - parse->flags |= PARSE_PPSCLOCK; - } - } -#endif - - if (TTY_SETATTR(fd232, &tio) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; - } - } - - /* - * Insert in async io device list. - */ - parse->generic->io.srcclock = (caddr_t)parse; - parse->generic->io.datalen = 0; - - if (!io_addclock(&parse->generic->io)) - { - msyslog(LOG_ERR, - "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; - } - - parse->binding = init_iobinding(parse); - parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ - parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ - - if (parse->binding == (bind_t *)0) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; /* well, ok - special initialisation broke */ - } - - /* - * as we always(?) get 8 bit chars we want to be - * sure, that the upper bits are zero for less - * than 8 bit I/O - so we pass that information on. - * note that there can be only one bit count format - * per file descriptor - */ - - switch (tio.c_cflag & CSIZE) - { - case CS5: - tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; - break; - - case CS6: - tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; - break; - - case CS7: - tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; - break; - - case CS8: - tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; - break; - } - - if (!PARSE_SETCS(parse, &tmp_ctl)) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; /* well, ok - special initialisation broke */ - } - - strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format); - tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); - - if (!PARSE_SETFMT(parse, &tmp_ctl)) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; /* well, ok - special initialisation broke */ - } - - /* - * get rid of all IO accumulated so far - */ -#ifdef HAVE_TERMIOS - (void) tcflush(parse->generic->io.fd, TCIOFLUSH); -#else -#ifdef TCFLSH - { -#ifndef TCIOFLUSH -#define TCIOFLUSH 2 -#endif - int flshcmd = TCIOFLUSH; - - (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); - } -#endif -#endif - - /* - * try to do any special initializations - */ - if (parse->parse_type->cl_init) - { - if (parse->parse_type->cl_init(parse)) - { - parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ - return 0; /* well, ok - special initialisation broke */ - } - } - - /* - * get out Copyright information once - */ - if (!notice) - { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel"); - notice = 1; - } - - /* - * print out configuration - */ - NLOG(NLOG_CLOCKINFO) - { - /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added", - CLK_UNIT(parse->peer), - parse->parse_type->cl_description, parsedev); - - msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d", - CLK_UNIT(parse->peer), - parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ", - l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision); - - msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phaseadjust %.6f s, %s IO handling", - CLK_UNIT(parse->peer), - parse->parse_type->cl_rootdelay, - parse->generic->fudgetime1, - parse->binding->bd_description); - - msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), - parse->parse_type->cl_format); -#ifdef PPS - msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS ioctl support", CLK_UNIT(parse->peer), - (parse->flags & PARSE_PPSCLOCK) ? "" : "NO "); -#endif - } - - return 1; -} - -/*-------------------------------------------------- - * parse_poll - called by the transmit procedure - */ -static void -parse_poll( - int unit, - struct peer *peer - ) -{ - struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; - - if (peer != parse->peer) - { - msyslog(LOG_ERR, - "PARSE receiver #%d: poll: INTERNAL: peer incorrect", - unit); - return; - } - - /* - * Update clock stat counters - */ - parse->generic->polls++; - - if (parse->pollneeddata && - ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) - { - /* - * start worrying when exceeding a poll inteval - * bad news - didn't get a response last time - */ - parse->generic->noreply++; - parse->lastmissed = current_time; - parse_event(parse, CEVNT_TIMEOUT); - - ERR(ERR_NODATA) - msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer)); - } - - /* - * we just mark that we want the next sample for the clock filter - */ - parse->pollneeddata = current_time; - - if (parse->parse_type->cl_poll) - { - parse->parse_type->cl_poll(parse); - } - - cparse_statistics(parse); - - return; -} - -#define LEN_STATES 300 /* length of state string */ - -/*-------------------------------------------------- - * parse_control - set fudge factors, return statistics - */ -static void -parse_control( - int unit, - struct refclockstat *in, - struct refclockstat *out, - struct peer *peer - ) -{ - register struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; - parsectl_t tmpctl; - - static char outstatus[400]; /* status output buffer */ - - if (out) - { - out->lencode = 0; - out->p_lastcode = 0; - out->kv_list = (struct ctl_var *)0; - } - - if (!parse || !parse->peer) - { - msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", - unit); - return; - } - - unit = CLK_UNIT(parse->peer); - - if (in) - { - if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) - { - parse->flags = in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4); - } - } - - if (out) - { - u_long sum = 0; - char *t, *tt, *start; - int i; - - outstatus[0] = '\0'; - - out->type = REFCLK_PARSE; - out->haveflags |= CLK_HAVETIME2; - - /* - * figure out skew between PPS and RS232 - just for informational - * purposes - returned in time2 value - */ - if (PARSE_SYNC(parse->time.parse_state)) - { - if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state)) - { - l_fp off; - - /* - * we have a PPS and RS232 signal - calculate the skew - * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) - */ - off = parse->time.parse_stime.fp; - L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */ - tt = add_var(&out->kv_list, 80, RO); - sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6)); - } - } - - if (PARSE_PPS(parse->time.parse_state)) - { - tt = add_var(&out->kv_list, 80, RO|DEF); - sprintf(tt, "refclock_ppstime=\"%s\"", gmprettydate(&parse->time.parse_ptime.fp)); - } - - tt = add_var(&out->kv_list, 128, RO|DEF); - sprintf(tt, "refclock_time=\""); - tt += strlen(tt); - - if (parse->time.parse_time.fp.l_ui == 0) - { - strcpy(tt, "<UNDEFINED>\""); - } - else - { - sprintf(tt, "%s\"", gmprettydate(&parse->time.parse_time.fp)); - t = tt + strlen(tt); - } - - if (!PARSE_GETTIMECODE(parse, &tmpctl)) - { - ERR(ERR_INTERNAL) - msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); - } - else - { - tt = add_var(&out->kv_list, 512, RO|DEF); - sprintf(tt, "refclock_status=\""); - tt += strlen(tt); - - /* - * copy PPS flags from last read transaction (informational only) - */ - tmpctl.parsegettc.parse_state |= parse->time.parse_state & - (PARSEB_PPS|PARSEB_S_PPS); - - (void) parsestate(tmpctl.parsegettc.parse_state, tt); - - strcat(tt, "\""); - - if (tmpctl.parsegettc.parse_count) - mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), - tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)); - - parse->generic->badformat += tmpctl.parsegettc.parse_badformat; - } - - tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; - - if (!PARSE_GETFMT(parse, &tmpctl)) - { - ERR(ERR_INTERNAL) - msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); - } - else - { - tt = add_var(&out->kv_list, 80, RO|DEF); - sprintf(tt, "refclock_format=\""); - - strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); - strcat(tt,"\""); - } - - /* - * gather state statistics - */ - - start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); - strcpy(tt, "refclock_states=\""); - tt += strlen(tt); - - for (i = 0; i <= CEVNT_MAX; i++) - { - u_long s_time; - u_long d = current_time - parse->generic->timestarted; - u_long percent; - - percent = s_time = PARSE_STATETIME(parse, i); - - while (((u_long)(~0) / 10000) < percent) - { - percent /= 10; - d /= 10; - } - - if (d) - percent = (percent * 10000) / d; - else - percent = 10000; - - if (s_time) - { - char item[80]; - int count; - - sprintf(item, "%s%s%s: %s (%d.%02d%%)", - sum ? "; " : "", - (parse->generic->currentstatus == i) ? "*" : "", - clockstatus((unsigned int)i), - l_mktime(s_time), - (int)(percent / 100), (int)(percent % 100)); - if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) - { - strcpy(tt, item); - tt += count; - } - sum += s_time; - } - } - - sprintf(tt, "; running time: %s\"", l_mktime(sum)); - - tt = add_var(&out->kv_list, 32, RO); - sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id); - - tt = add_var(&out->kv_list, 80, RO); - sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description); - - tt = add_var(&out->kv_list, 128, RO); - sprintf(tt, "refclock_driver_version=\"%s\"", rcsid); - - { - struct ctl_var *k; - - k = parse->kv; - while (k && !(k->flags & EOV)) - { - set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); - k++; - } - } - - out->lencode = strlen(outstatus); - out->p_lastcode = outstatus; - } -} - -/**=========================================================================== - ** processing routines - **/ - -/*-------------------------------------------------- - * event handling - note that nominal events will also be posted - */ -static void -parse_event( - struct parseunit *parse, - int event - ) -{ - if (parse->generic->currentstatus != (u_char) event) - { - parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; - parse->lastchange = current_time; - - parse->generic->currentstatus = (u_char)event; - - if (parse->parse_type->cl_event) - parse->parse_type->cl_event(parse, event); - - if (event != CEVNT_NOMINAL) - { - parse->generic->lastevent = parse->generic->currentstatus; - } - else - { - NLOG(NLOG_CLOCKSTATUS) - msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", - CLK_UNIT(parse->peer)); - } - - if (event == CEVNT_FAULT) - { - NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ - ERR(ERR_BADEVENT) - msyslog(LOG_ERR, - "clock %s fault '%s' (0x%02x)", refnumtoa(&parse->peer->srcadr), ceventstr(event), - (u_int)event); - } - else - { - NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ - if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT)) - msyslog(LOG_INFO, - "clock %s event '%s' (0x%02x)", refnumtoa(&parse->peer->srcadr), ceventstr(event), - (u_int)event); - } - - report_event(EVNT_PEERCLOCK, parse->peer); - report_event(EVNT_CLOCKEXCPT, parse->peer); - } -} - -/*-------------------------------------------------- - * process a PARSE time sample - */ -static void -parse_process( - struct parseunit *parse, - parsetime_t *parsetime - ) -{ - l_fp off, rectime, reftime; - double fudge; - - /* - * check for changes in conversion status - * (only one for each new status !) - */ - if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && - ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && - (parse->time.parse_status != parsetime->parse_status)) - { - char buffer[400]; - - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", - CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer)); - - if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) - { - /* - * tell more about the story - list time code - * there is a slight change for a race condition and - * the time code might be overwritten by the next packet - */ - parsectl_t tmpctl; - - if (!PARSE_GETTIMECODE(parse, &tmpctl)) - { - ERR(ERR_INTERNAL) - msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); - } - else - { - ERR(ERR_BADDATA) - msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / cableling)", - CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); - parse->generic->badformat += tmpctl.parsegettc.parse_badformat; - } - } - } - - /* - * examine status and post appropriate events - */ - if ((parsetime->parse_status & CVT_MASK) != CVT_OK) - { - /* - * got bad data - tell the rest of the system - */ - switch (parsetime->parse_status & CVT_MASK) - { - case CVT_NONE: - if ((parsetime->parse_status & CVT_ADDITIONAL) && - parse->parse_type->cl_message) - parse->parse_type->cl_message(parse, parsetime); - break; /* well, still waiting - timeout is handled at higher levels */ - - case CVT_FAIL: - parse->generic->badformat++; - if (parsetime->parse_status & CVT_BADFMT) - { - parse_event(parse, CEVNT_BADREPLY); - } - else - if (parsetime->parse_status & CVT_BADDATE) - { - parse_event(parse, CEVNT_BADDATE); - } - else - if (parsetime->parse_status & CVT_BADTIME) - { - parse_event(parse, CEVNT_BADTIME); - } - else - { - parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ - } - } - return; /* skip the rest - useless */ - } - - /* - * check for format changes - * (in case somebody has swapped clocks 8-) - */ - if (parse->lastformat != parsetime->parse_format) - { - parsectl_t tmpctl; - - tmpctl.parseformat.parse_format = parsetime->parse_format; - - if (!PARSE_GETFMT(parse, &tmpctl)) - { - ERR(ERR_INTERNAL) - msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); - } - else - { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", - CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); - } - parse->lastformat = parsetime->parse_format; - } - - /* - * now, any changes ? - */ - if (parse->time.parse_state != parsetime->parse_state) - { - char tmp1[200]; - char tmp2[200]; - /* - * something happend - */ - - (void) parsestate(parsetime->parse_state, tmp1); - (void) parsestate(parse->time.parse_state, tmp2); - - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", - CLK_UNIT(parse->peer), tmp2, tmp1); - } - - /* - * remember for future - */ - parse->time = *parsetime; - - /* - * check to see, whether the clock did a complete powerup or lost PZF signal - * and post correct events for current condition - */ - if (PARSE_POWERUP(parsetime->parse_state)) - { - /* - * this is bad, as we have completely lost synchronisation - * well this is a problem with the receiver here - * for PARSE Meinberg DCF77 receivers the lost synchronisation - * is true as it is the powerup state and the time is taken - * from a crude real time clock chip - * for the PZF series this is only partly true, as - * PARSE_POWERUP only means that the pseudo random - * phase shift sequence cannot be found. this is only - * bad, if we have never seen the clock in the SYNC - * state, where the PHASE and EPOCH are correct. - * for reporting events the above business does not - * really matter, but we can use the time code - * even in the POWERUP state after having seen - * the clock in the synchronized state (PZF class - * receivers) unless we have had a telegram disruption - * after having seen the clock in the SYNC state. we - * thus require having seen the clock in SYNC state - * *after* having missed telegrams (noresponse) from - * the clock. one problem remains: we might use erroneously - * POWERUP data if the disruption is shorter than 1 polling - * interval. fortunately powerdowns last usually longer than 64 - * seconds and the receiver is at least 2 minutes in the - * POWERUP or NOSYNC state before switching to SYNC - */ - parse_event(parse, CEVNT_FAULT); - NLOG(NLOG_CLOCKSTATUS) - ERR(ERR_BADSTATUS) - msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", - CLK_UNIT(parse->peer)); - } - else - { - /* - * we have two states left - * - * SYNC: - * this state means that the EPOCH (timecode) and PHASE - * information has be read correctly (at least two - * successive PARSE timecodes were received correctly) - * this is the best possible state - full trust - * - * NOSYNC: - * The clock should be on phase with respect to the second - * signal, but the timecode has not been received correctly within - * at least the last two minutes. this is a sort of half baked state - * for PARSE Meinberg DCF77 clocks this is bad news (clock running - * without timecode confirmation) - * PZF 535 has also no time confirmation, but the phase should be - * very precise as the PZF signal can be decoded - */ - - if (PARSE_SYNC(parsetime->parse_state)) - { - /* - * currently completely synchronized - best possible state - */ - parse->lastsync = current_time; - clear_err(parse, ERR_BADSTATUS); - } - else - { - /* - * we have had some problems receiving the time code - */ - parse_event(parse, CEVNT_PROP); - NLOG(NLOG_CLOCKSTATUS) - ERR(ERR_BADSTATUS) - msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", - CLK_UNIT(parse->peer)); - } - } - - fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ - - if (PARSE_TIMECODE(parsetime->parse_state)) - { - rectime = parsetime->parse_stime.fp; - off = reftime = parsetime->parse_time.fp; - - L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ - -#ifdef DEBUG - if (debug > 3) - printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", - CLK_UNIT(parse->peer), - prettydate(&reftime), - prettydate(&rectime), - lfptoa(&off,6)); -#endif - } - - if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) - { - l_fp offset; - - /* - * we have a PPS signal - much better than the RS232 stuff (we hope) - */ - offset = parsetime->parse_ptime.fp; - -#ifdef DEBUG - if (debug > 3) - printf("PARSE receiver #%d: PPStime %s\n", - CLK_UNIT(parse->peer), - prettydate(&offset)); -#endif - if (PARSE_TIMECODE(parsetime->parse_state)) - { - if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && - M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) - { - fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ - - /* - * RS232 offsets within [-0.5..0.5[ - take PPS offsets - */ - - if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) - { - reftime = off = offset; - if (reftime.l_uf & (unsigned)0x80000000) - reftime.l_ui++; - reftime.l_uf = 0; - - - /* - * implied on second offset - */ - off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ - off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ - } - else - { - /* - * time code describes pulse - */ - reftime = off = parsetime->parse_time.fp; - - L_SUB(&off, &offset); /* true offset */ - } - } - /* - * take RS232 offset when PPS when out of bounds - */ - } - else - { - fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ - /* - * Well, no time code to guide us - assume on second pulse - * and pray, that we are within [-0.5..0.5[ - */ - off = offset; - reftime = offset; - if (reftime.l_uf & (unsigned)0x80000000) - reftime.l_ui++; - reftime.l_uf = 0; - /* - * implied on second offset - */ - off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ - off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ - } - } - else - { - if (!PARSE_TIMECODE(parsetime->parse_state)) - { - /* - * Well, no PPS, no TIMECODE, no more work ... - */ - if ((parsetime->parse_status & CVT_ADDITIONAL) && - parse->parse_type->cl_message) - parse->parse_type->cl_message(parse, parsetime); - return; - } - } - -#ifdef DEBUG - if (debug > 3) - printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", - CLK_UNIT(parse->peer), - prettydate(&reftime), - prettydate(&rectime), - lfptoa(&off,6)); -#endif - - - rectime = reftime; - L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ - -#ifdef DEBUG - if (debug > 3) - printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", - CLK_UNIT(parse->peer), - prettydate(&reftime), - prettydate(&rectime)); -#endif - - if ((parsetime->parse_status & CVT_ADDITIONAL) && - parse->parse_type->cl_message) - parse->parse_type->cl_message(parse, parsetime); - - if (PARSE_SYNC(parsetime->parse_state)) - { - /* - * log OK status - */ - parse_event(parse, CEVNT_NOMINAL); - } - - clear_err(parse, ERR_BADIO); - clear_err(parse, ERR_BADDATA); - clear_err(parse, ERR_NODATA); - clear_err(parse, ERR_INTERNAL); - -#ifdef DEBUG - if (debug > 2) - { - printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", - CLK_UNIT(parse->peer), - prettydate(&reftime), - prettydate(&rectime), - fudge); - } -#endif - - refclock_process_offset(parse->generic, reftime, rectime, fudge); - if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) - { - (void) pps_sample(&parse->time.parse_ptime.fp); - } - - - /* - * and now stick it into the clock machine - * samples are only valid iff lastsync is not too old and - * we have seen the clock in sync at least once - * after the last time we didn't see an expected data telegram - * see the clock states section above for more reasoning - */ - if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) || - (parse->lastsync <= parse->lastmissed)) - { - parse->generic->leap = LEAP_NOTINSYNC; - } - else - { - if (PARSE_LEAPADD(parsetime->parse_state)) - { - /* - * we pick this state also for time code that pass leap warnings - * without direction information (as earth is currently slowing - * down). - */ - parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; - } - else - if (PARSE_LEAPDEL(parsetime->parse_state)) - { - parse->generic->leap = LEAP_DELSECOND; - } - else - { - parse->generic->leap = LEAP_NOWARNING; - } - } - - /* - * ready, unless the machine wants a sample - */ - if (!parse->pollneeddata) - return; - - parse->pollneeddata = 0; - - refclock_receive(parse->peer); -} - -/**=========================================================================== - ** special code for special clocks - **/ - -static void -mk_utcinfo( - char *t, - int wnt, - int wnlsf, - int dn, - int dtls, - int dtlsf - ) -{ - l_fp leapdate; - - sprintf(t, "current correction %d sec", dtls); - t += strlen(t); - - if (wnlsf < 990) - wnlsf += 1024; - - if (wnt < 990) - wnt += 1024; - - gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); - - if ((dtlsf != dtls) && - ((wnlsf - wnt) < 52)) - { - sprintf(t, ", next correction %d sec on %s, new GPS-UTC offset %d", - dtlsf - dtls, gmprettydate(&leapdate), dtlsf); - } - else - { - sprintf(t, ", last correction on %s", - gmprettydate(&leapdate)); - } -} - -#ifdef CLOCK_MEINBERG -/**=========================================================================== - ** Meinberg GPS166/GPS167 support - **/ - -/*------------------------------------------------------------ - * gps16x_message - process GPS16x messages - */ -static void -gps16x_message( - struct parseunit *parse, - parsetime_t *parsetime - ) -{ - if (parse->time.parse_msglen && parsetime->parse_msg[0] == SOH) - { - GPS_MSG_HDR header; - unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; - -#ifdef DEBUG - if (debug > 2) - { - char msgbuffer[600]; - - mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); - printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", - CLK_UNIT(parse->peer), - parsetime->parse_msglen, - msgbuffer); - } -#endif - get_mbg_header(&bufp, &header); - if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && - (header.gps_len == 0 || - (header.gps_len < sizeof(parsetime->parse_msg) && - header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) - { - /* - * clean message - */ - switch (header.gps_cmd) - { - case GPS_SW_REV: - { - char buffer[64]; - SW_REV gps_sw_rev; - - get_mbg_sw_rev(&bufp, &gps_sw_rev); - sprintf(buffer, "meinberg_gps_version=\"%x.%02x%s%s\"", - (gps_sw_rev.code >> 8) & 0xFF, - gps_sw_rev.code & 0xFF, - gps_sw_rev.name[0] ? " " : "", - gps_sw_rev.name); - set_var(&parse->kv, buffer, 64, RO|DEF); - } - break; - - case GPS_STAT: - { - static struct state - { - unsigned short flag; /* status flag */ - unsigned const char *string; /* bit name */ - } states[] = - { - { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, - { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, - { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, - { TM_NO_POS, (const unsigned char *)"NO POSITION" }, - { 0, (const unsigned char *)"" } - }; - unsigned short status; - struct state *s = states; - char buffer[512]; - char *p, *b; - - status = get_lsb_short(&bufp); - sprintf(buffer, "meinberg_gps_status=\"[0x%04x] ", status); - - if (status) - { - p = b = buffer + strlen(buffer); - while (s->flag) - { - if (status & s->flag) - { - if (p != b) - { - *p++ = ','; - *p++ = ' '; - } - - strcat(p, (const char *)s->string); - } - s++; - } - - *p++ = '"'; - *p = '\0'; - } - else - { - strcat(buffer, "<OK>\""); - } - - set_var(&parse->kv, buffer, 64, RO|DEF); - } - break; - - case GPS_POS_XYZ: - { - XYZ xyz; - char buffer[256]; - - get_mbg_xyz(&bufp, xyz); - sprintf(buffer, "gps_position(XYZ)=\"%s m, %s m, %s m\"", - mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), - mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), - mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); - - set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); - } - break; - - case GPS_POS_LLA: - { - LLA lla; - char buffer[256]; - - get_mbg_lla(&bufp, lla); - - sprintf(buffer, "gps_position(LLA)=\"%s deg, %s deg, %s m\"", - mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), - mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), - mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); - - set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); - } - break; - - case GPS_TZDL: - break; - - case GPS_PORT_PARM: - break; - - case GPS_SYNTH: - break; - - case GPS_ANT_INFO: - { - ANT_INFO antinfo; - u_char buffer[512]; - u_char *p; - - get_mbg_antinfo(&bufp, &antinfo); - sprintf(buffer, "meinberg_antenna_status=\""); - p = buffer + strlen(buffer); - - switch (antinfo.status) - { - case ANT_INVALID: - strcat(p, "<OK>"); - p += strlen(p); - break; - - case ANT_DISCONN: - strcat(p, "DISCONNECTED since "); - NLOG(NLOG_CLOCKSTATUS) - ERR(ERR_BADSTATUS) - msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", - CLK_UNIT(parse->peer), p); - - p += strlen(p); - mbg_tm_str(&p, &antinfo.tm_disconn); - *p = '\0'; - break; - - case ANT_RECONN: - strcat(p, "RECONNECTED on "); - p += strlen(p); - mbg_tm_str(&p, &antinfo.tm_reconn); - sprintf(p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", - (antinfo.delta_t < 0) ? '-' : '+', - ABS(antinfo.delta_t) / 10000, - ABS(antinfo.delta_t) % 10000); - p += strlen(p); - mbg_tm_str(&p, &antinfo.tm_disconn); - *p = '\0'; - break; - - default: - sprintf(p, "bad status 0x%04x", antinfo.status); - p += strlen(p); - break; - } - - *p++ = '"'; - *p = '\0'; - - set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); - } - break; - - case GPS_UCAP: - break; - - case GPS_CFGH: - { - CFGH cfgh; - u_char buffer[512]; - u_char *p; - - get_mbg_cfgh(&bufp, &cfgh); - if (cfgh.valid) - { - int i; - - p = buffer; - strcpy(buffer, "gps_tot_51=\""); - p += strlen(p); - mbg_tgps_str(&p, &cfgh.tot_51); - *p++ = '"'; - *p = '\0'; - set_var(&parse->kv, buffer, sizeof(buffer), RO); - - p = buffer; - strcpy(buffer, "gps_tot_63=\""); - p += strlen(p); - mbg_tgps_str(&p, &cfgh.tot_63); - *p++ = '"'; - *p = '\0'; - set_var(&parse->kv, buffer, sizeof(buffer), RO); - - p = buffer; - strcpy(buffer, "gps_t0a=\""); - p += strlen(p); - mbg_tgps_str(&p, &cfgh.t0a); - *p++ = '"'; - *p = '\0'; - set_var(&parse->kv, buffer, sizeof(buffer), RO); - - for (i = MIN_SVNO; i <= MAX_SVNO; i++) - { - p = buffer; - sprintf(p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); - p += strlen(p); - switch (cfgh.cfg[i] & 0x7) - { - case 0: - strcpy(p, "BLOCK I"); - break; - case 1: - strcpy(p, "BLOCK II"); - break; - default: - sprintf(p, "bad CFG"); - break; - } - strcat(p, "\""); - set_var(&parse->kv, buffer, sizeof(buffer), RO); - - p = buffer; - sprintf(p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); - p += strlen(p); - switch ((cfgh.health[i] >> 5) & 0x7 ) - { - case 0: - strcpy(p, "OK;"); - break; - case 1: - strcpy(p, "PARITY;"); - break; - case 2: - strcpy(p, "TLM/HOW;"); - break; - case 3: - strcpy(p, "Z-COUNT;"); - break; - case 4: - strcpy(p, "SUBFRAME 1,2,3;"); - break; - case 5: - strcpy(p, "SUBFRAME 4,5;"); - break; - case 6: - strcpy(p, "UPLOAD BAD;"); - break; - case 7: - strcpy(p, "DATA BAD;"); - break; - } - - p += strlen(p); - - switch (cfgh.health[i] & 0x1F) - { - case 0: - strcpy(p, "SIGNAL OK"); - break; - case 0x1C: - strcpy(p, "SV TEMP OUT"); - break; - case 0x1D: - strcpy(p, "SV WILL BE TEMP OUT"); - break; - case 0x1E: - break; - case 0x1F: - strcpy(p, "MULTIPLE ERRS"); - break; - default: - strcpy(p, "TRANSMISSION PROBLEMS"); - break; - } - - strcat(p, "\""); - set_var(&parse->kv, buffer, sizeof(buffer), RO); - } - } - } - break; - - case GPS_ALM: - break; - - case GPS_EPH: - break; - - case GPS_UTC: - { - UTC utc; - char buffer[512]; - char *p; - - p = buffer; - - get_mbg_utc(&bufp, &utc); - - if (utc.valid) - { - strcpy(p, "gps_utc_correction=\""); - p += strlen(p); - mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf); - strcat(p, "\""); - } - else - { - strcpy(p, "gps_utc_correction=\"<NO UTC DATA>\""); - } - set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); - } - break; - - case GPS_IONO: - break; - - case GPS_ASCII_MSG: - { - ASCII_MSG gps_ascii_msg; - char buffer[128]; - - get_mbg_ascii_msg(&bufp, &gps_ascii_msg); - - if (gps_ascii_msg.valid) - { - char buffer1[128]; - mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); - - sprintf(buffer, "gps_message=\"%s\"", buffer1); - } - else - strcpy(buffer, "gps_message=<NONE>"); - - set_var(&parse->kv, buffer, 128, RO|DEF); - } - - break; - - default: - break; - } - } - else - { - msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)", - CLK_UNIT(parse->peer), - header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), - header.gps_len, - header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); - } - } - - return; -} - -/*------------------------------------------------------------ - * gps16x_poll - query the reciver peridically - */ -static void -gps16x_poll( - struct peer *peer - ) -{ - struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; - - static GPS_MSG_HDR sequence[] = - { - { GPS_SW_REV, 0, 0, 0 }, - { GPS_STAT, 0, 0, 0 }, - { GPS_UTC, 0, 0, 0 }, - { GPS_ASCII_MSG, 0, 0, 0 }, - { GPS_ANT_INFO, 0, 0, 0 }, - { GPS_CFGH, 0, 0, 0 }, - { GPS_POS_XYZ, 0, 0, 0 }, - { GPS_POS_LLA, 0, 0, 0 }, - { (unsigned short)~0, 0, 0, 0 } - }; - - int rtc; - unsigned char cmd_buffer[64]; - unsigned char *outp = cmd_buffer; - GPS_MSG_HDR *header; - - if (((poll_info_t *)parse->parse_type->cl_data)->rate) - { - parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; - } - - if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) - parse->localstate = 0; - - header = sequence + parse->localstate++; - - *outp++ = SOH; /* start command */ - - put_mbg_header(&outp, header); - outp = cmd_buffer + 1; - - header->gps_hdr_csum = (short)mbg_csum(outp, 6); - put_mbg_header(&outp, header); - -#ifdef DEBUG - if (debug > 2) - { - char buffer[128]; - - mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); - printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", - CLK_UNIT(parse->peer), - parse->localstate - 1, - (int)(outp - cmd_buffer), - buffer); - } -#endif - - rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); - - if (rtc < 0) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); - } - else - if (rtc != outp - cmd_buffer) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer)); - } - - clear_err(parse, ERR_BADIO); - return; -} - -/*-------------------------------------------------- - * init routine - setup timer - */ -static int -gps16x_poll_init( - struct parseunit *parse - ) -{ - if (((poll_info_t *)parse->parse_type->cl_data)->rate) - { - parse->peer->action = gps16x_poll; - gps16x_poll(parse->peer); - } - - return 0; -} - -#else -static void -gps16x_message( - struct parseunit *parse, - parsetime_t *parsetime - ) -{} -static int -gps16x_poll_init( - struct parseunit *parse - ) -{ - return 1; -} -#endif /* CLOCK_MEINBERG */ - -/**=========================================================================== - ** clock polling support - **/ - -/*-------------------------------------------------- - * direct poll routine - */ -static void -poll_dpoll( - struct parseunit *parse - ) -{ - int rtc; - const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; - int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; - - rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); - if (rtc < 0) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); - } - else - if (rtc != ct) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); - } - clear_err(parse, ERR_BADIO); -} - -/*-------------------------------------------------- - * periodic poll routine - */ -static void -poll_poll( - struct peer *peer - ) -{ - struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; - - if (parse->parse_type->cl_poll) - parse->parse_type->cl_poll(parse); - - if (((poll_info_t *)parse->parse_type->cl_data)->rate) - { - parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; - } -} - -/*-------------------------------------------------- - * init routine - setup timer - */ -static int -poll_init( - struct parseunit *parse - ) -{ - if (((poll_info_t *)parse->parse_type->cl_data)->rate) - { - parse->peer->action = poll_poll; - poll_poll(parse->peer); - } - - return 0; -} - -/**=========================================================================== - ** Trimble support - **/ - -/*------------------------------------------------------------- - * trimble TAIP init routine - setup EOL and then do poll_init. - */ -static int -trimbletaip_init( - struct parseunit *parse - ) -{ -#ifdef HAVE_TERMIOS - struct termios tio; -#endif -#ifdef HAVE_SYSV_TTYS - struct termio tio; -#endif - /* - * configure terminal line for trimble receiver - */ - if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); - return 0; - } - else - { - tio.c_cc[VEOL] = TRIMBLETAIP_EOL; - - if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); - return 0; - } - } - return poll_init(parse); -} - -/*-------------------------------------------------- - * trimble TAIP event routine - reset receiver upon data format trouble - */ -static const char *taipinit[] = { - ">FPV00000000<", - ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", - ">FTM00020001<", - (char *)0 -}; - -static void -trimbletaip_event( - struct parseunit *parse, - int event - ) -{ - switch (event) - { - case CEVNT_BADREPLY: /* reset on garbled input */ - case CEVNT_TIMEOUT: /* reset on no input */ - { - const char **iv; - - iv = taipinit; - while (*iv) - { - int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); - if (rtc < 0) - { - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); - return; - } - else - { - if (rtc != strlen(*iv)) - { - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", - CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); - return; - } - } - iv++; - } - - NLOG(NLOG_CLOCKINFO) - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", - CLK_UNIT(parse->peer)); - } - break; - - default: /* ignore */ - break; - } -} - -/* - * This driver supports the Trimble SVee Six Plus GPS receiver module. - * It should support other Trimble receivers which use the Trimble Standard - * Interface Protocol (see below). - * - * The module has a serial I/O port for command/data and a 1 pulse-per-second - * output, about 1 microsecond wide. The leading edge of the pulse is - * coincident with the change of the GPS second. This is the same as - * the change of the UTC second +/- ~1 microsecond. Some other clocks - * specifically use a feature in the data message as a timing reference, but - * the SVee Six Plus does not do this. In fact there is considerable jitter - * on the timing of the messages, so this driver only supports the use - * of the PPS pulse for accurate timing. Where it is determined that - * the offset is way off, when first starting up ntpd for example, - * the timing of the data stream is used until the offset becomes low enough - * (|offset| < CLOCK_MAX), at which point the pps offset is used. - * - * It can use either option for receiving PPS information - the 'ppsclock' - * stream pushed onto the serial data interface to timestamp the Carrier - * Detect interrupts, where the 1PPS connects to the CD line. This only - * works on SunOS 4.1.x currently. To select this, define PPSPPS in - * Config.local. The other option is to use a pulse-stretcher/level-converter - * to convert the PPS pulse into a RS232 start pulse & feed this into another - * tty port. To use this option, define PPSCLK in Config.local. The pps input, - * by whichever method, is handled in ntp_loopfilter.c - * - * The receiver uses a serial message protocol called Trimble Standard - * Interface Protocol (it can support others but this driver only supports - * TSIP). Messages in this protocol have the following form: - * - * <DLE><id> ... <data> ... <DLE><ETX> - * - * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled - * on transmission and compressed back to one on reception. Otherwise - * the values of data bytes can be anything. The serial interface is RS-422 - * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits - * in total!), and 1 stop bit. The protocol supports byte, integer, single, - * and double datatypes. Integers are two bytes, sent most significant first. - * Singles are IEEE754 single precision floating point numbers (4 byte) sent - * sign & exponent first. Doubles are IEEE754 double precision floating point - * numbers (8 byte) sent sign & exponent first. - * The receiver supports a large set of messages, only a small subset of - * which are used here. From driver to receiver the following are used: - * - * ID Description - * - * 21 Request current time - * 22 Mode Select - * 2C Set/Request operating parameters - * 2F Request UTC info - * 35 Set/Request I/O options - - * From receiver to driver the following are recognised: - * - * ID Description - * - * 41 GPS Time - * 44 Satellite selection, PDOP, mode - * 46 Receiver health - * 4B Machine code/status - * 4C Report operating parameters (debug only) - * 4F UTC correction data (used to get leap second warnings) - * 55 I/O options (debug only) - * - * All others are accepted but ignored. - * - */ - -#define PI 3.1415926535898 /* lots of sig figs */ -#define D2R PI/180.0 - -/*------------------------------------------------------------------- - * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command - * interface to the receiver. - * - * CAVEAT: the sendflt, sendint routines are byte order dependend and - * float implementation dependend - these must be converted to portable - * versions ! - * - * CURRENT LIMITATION: float implementation. This runs only on systems - * with IEEE754 floats as native floats - */ - -typedef struct trimble -{ - u_long last_msg; /* last message received */ - u_char qtracking; /* query tracking status */ - u_long ctrack; /* current tracking set */ - u_long ltrack; /* last tracking set */ -} trimble_t; - -union uval { - u_char bd[8]; - int iv; - float fv; - double dv; -}; - -struct txbuf -{ - short idx; /* index to first unused byte */ - u_char *txt; /* pointer to actual data buffer */ -}; - -void sendcmd P((struct txbuf *buf, int c)); -void sendbyte P((struct txbuf *buf, int b)); -void sendetx P((struct txbuf *buf, struct parseunit *parse)); -void sendint P((struct txbuf *buf, int a)); -void sendflt P((struct txbuf *buf, double a)); - -void -sendcmd( - struct txbuf *buf, - int c - ) -{ - buf->txt[0] = DLE; - buf->txt[1] = (u_char)c; - buf->idx = 2; -} - -void -sendbyte( - struct txbuf *buf, - int b - ) -{ - if (b == DLE) - buf->txt[buf->idx++] = DLE; - buf->txt[buf->idx++] = (u_char)b; -} - -void -sendetx( - struct txbuf *buf, - struct parseunit *parse - ) -{ - buf->txt[buf->idx++] = DLE; - buf->txt[buf->idx++] = ETX; - - if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) - { - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); - } - else - { -#ifdef DEBUG - if (debug > 2) - { - char buffer[256]; - - mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); - printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", - CLK_UNIT(parse->peer), - buf->idx, buffer); - } -#endif - clear_err(parse, ERR_BADIO); - } -} - -void -sendint( - struct txbuf *buf, - int a - ) -{ - /* send 16bit int, msbyte first */ - sendbyte(buf, (u_char)((a>>8) & 0xff)); - sendbyte(buf, (u_char)(a & 0xff)); -} - -void -sendflt( - struct txbuf *buf, - double a - ) -{ - int i; - union uval uval; - - uval.fv = a; -#ifdef WORDS_BIGENDIAN - for (i=0; i<=3; i++) -#else - for (i=3; i>=0; i--) -#endif - sendbyte(buf, uval.bd[i]); -} - -#define TRIM_POS_OPT 0x13 /* output position with high precision */ -#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ - -/*-------------------------------------------------- - * trimble TSIP setup routine - */ -static int -trimbletsip_setup( - struct parseunit *parse, - const char *reason - ) -{ - u_char buffer[256]; - struct txbuf buf; - - buf.txt = buffer; - - sendcmd(&buf, CMD_CVERSION); /* request software versions */ - sendetx(&buf, parse); - - sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ - sendbyte(&buf, 4); /* static */ - sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ - sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ - sendflt(&buf, 12.0); /* PDOP mask = 12 */ - sendflt(&buf, 8.0); /* PDOP switch level = 8 */ - sendetx(&buf, parse); - - sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ - sendbyte(&buf, 0); /* automatic */ - sendetx(&buf, parse); - - sendcmd(&buf, CMD_CMESSAGE); /* request system message */ - sendetx(&buf, parse); - - sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ - sendbyte(&buf, 0x2); /* binary mode */ - sendetx(&buf, parse); - - sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ - sendbyte(&buf, TRIM_POS_OPT); /* position output */ - sendbyte(&buf, 0x00); /* no velocity output */ - sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ - sendbyte(&buf, 0x00); /* no raw measurements */ - sendetx(&buf, parse); - - sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ - sendetx(&buf, parse); - - NLOG(NLOG_CLOCKINFO) - ERR(ERR_BADIO) - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); - - return 0; -} - -/*-------------------------------------------------- - * TRIMBLE TSIP check routine - */ -static void -trimble_check( - struct peer *peer - ) -{ - struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; - trimble_t *t = parse->localdata; - u_char buffer[256]; - struct txbuf buf; - buf.txt = buffer; - - if (t) - { - if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) - (void)trimbletsip_setup(parse, "message timeout"); - } - poll_poll(parse->peer); /* emit query string and re-arm timer */ - - if (t->qtracking) - { - u_long oldsats = t->ltrack & ~t->ctrack; - - t->qtracking = 0; - t->ltrack = t->ctrack; - - if (oldsats) - { - int i; - - for (i = 0; oldsats; i++) - if (oldsats & (1 << i)) - { - sendcmd(&buf, CMD_CSTATTRACK); - sendbyte(&buf, i+1); /* old sat */ - sendetx(&buf, parse); - } - oldsats &= ~(1 << i); - } - - sendcmd(&buf, CMD_CSTATTRACK); - sendbyte(&buf, 0x00); /* current tracking set */ - sendetx(&buf, parse); - } -} - -/*-------------------------------------------------- - * TRIMBLE TSIP end routine - */ -static void -trimbletsip_end( - struct parseunit *parse - ) -{ trimble_t *t = parse->localdata; - - if (t) - { - free(t); - parse->localdata = (void *)0; - } - parse->peer->nextaction = 0; - parse->peer->action = (void (*) P((struct peer *)))0; -} - -/*-------------------------------------------------- - * TRIMBLE TSIP init routine - */ -static int -trimbletsip_init( - struct parseunit *parse - ) -{ -#if defined(VEOL) || defined(VEOL2) -#ifdef HAVE_TERMIOS - struct termios tio; /* NEEDED FOR A LONG TIME ! */ -#endif -#ifdef HAVE_SYSV_TTYS - struct termio tio; /* NEEDED FOR A LONG TIME ! */ -#endif - /* - * allocate local data area - */ - if (!parse->localdata) - { - trimble_t *t; - - t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); - - if (t) - { - memset((char *)t, 0, sizeof(trimble_t)); - t->last_msg = current_time; - } - } - - parse->peer->action = trimble_check; - parse->peer->nextaction = current_time; - - /* - * configure terminal line for ICANON mode with VEOL characters - */ - if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); - return 0; - } - else - { - if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) - { -#ifdef VEOL - tio.c_cc[VEOL] = ETX; -#endif -#ifdef VEOL2 - tio.c_cc[VEOL2] = DLE; -#endif - } - - if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) - { - msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); - return 0; - } - } -#endif - return trimbletsip_setup(parse, "initial startup"); -} - -/*------------------------------------------------------------ - * trimbletsip_event - handle Trimble events - * simple evente handler - attempt to re-initialize receiver - */ -static void -trimbletsip_event( - struct parseunit *parse, - int event - ) -{ - switch (event) - { - case CEVNT_BADREPLY: /* reset on garbled input */ - case CEVNT_TIMEOUT: /* reset on no input */ - (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); - break; - - default: /* ignore */ - break; - } -} - -/* - * getflt, getint convert fields in the incoming data into the - * appropriate type of item - * - * CAVEAT: these routines are currently definitely byte order dependent - * and assume Representation(float) == IEEE754 - * These functions MUST be converted to portable versions (especially - * converting the float representation into ntp_fp formats in order - * to avoid floating point operations at all! - */ - -static float -getflt( - u_char *bp - ) -{ - union uval uval; - -#ifdef WORDS_BIGENDIAN - uval.bd[0] = *bp++; - uval.bd[1] = *bp++; - uval.bd[2] = *bp++; - uval.bd[3] = *bp; -#else /* ! WORDS_BIGENDIAN */ - uval.bd[3] = *bp++; - uval.bd[2] = *bp++; - uval.bd[1] = *bp++; - uval.bd[0] = *bp; -#endif /* ! WORDS_BIGENDIAN */ - return uval.fv; -} - -static double -getdbl( - u_char *bp - ) -{ - union uval uval; - -#ifdef WORDS_BIGENDIAN - uval.bd[0] = *bp++; - uval.bd[1] = *bp++; - uval.bd[2] = *bp++; - uval.bd[3] = *bp++; - uval.bd[4] = *bp++; - uval.bd[5] = *bp++; - uval.bd[6] = *bp++; - uval.bd[7] = *bp; -#else /* ! WORDS_BIGENDIAN */ - uval.bd[7] = *bp++; - uval.bd[6] = *bp++; - uval.bd[5] = *bp++; - uval.bd[4] = *bp++; - uval.bd[3] = *bp++; - uval.bd[2] = *bp++; - uval.bd[1] = *bp++; - uval.bd[0] = *bp; -#endif /* ! WORDS_BIGENDIAN */ - return uval.dv; -} - -static int -getshort( - unsigned char *p - ) -{ - return get_msb_short(&p); -} - -/*-------------------------------------------------- - * trimbletsip_message - process trimble messages - */ -#define RTOD (180.0 / 3.1415926535898) -#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ - -static void -trimbletsip_message( - struct parseunit *parse, - parsetime_t *parsetime - ) -{ - unsigned char *buffer = parsetime->parse_msg; - unsigned int size = parsetime->parse_msglen; - - if ((size < 4) || - (buffer[0] != DLE) || - (buffer[size-1] != ETX) || - (buffer[size-2] != DLE)) - { -#ifdef DEBUG - if (debug > 2) { - int i; - - printf("TRIMBLE BAD packet, size %d:\n ", size); - for (i = 0; i < size; i++) { - printf ("%2.2x, ", buffer[i]&0xff); - if (i%16 == 15) printf("\n\t"); - } - printf("\n"); - } -#endif - return; - } - else - { - int var_flag; - trimble_t *tr = parse->localdata; - unsigned int cmd = buffer[1]; - char pbuffer[200]; - char *t = pbuffer; - cmd_info_t *s; - -#ifdef DEBUG - if (debug > 3) { - int i; - - printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); - for (i = 0; i < size; i++) { - printf ("%2.2x, ", buffer[i]&0xff); - if (i%16 == 15) printf("\n\t"); - } - printf("\n"); - } -#endif - - if (tr) - tr->last_msg = current_time; - - s = trimble_convert(cmd, trimble_rcmds); - - if (s) - { - sprintf(t, "%s=\"", s->varname); - } - else - { - printf("TRIMBLE unknown command 0x%02x\n", cmd); - return; - } - - var_flag = s->varmode; - - t += strlen(t); - - switch(cmd) - { - case CMD_RCURTIME: - sprintf(t, "%f, %d, %f", - getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), - getflt((unsigned char *)&mb(6))); - break; - - case CMD_RBEST4: - strcpy(t, "mode: "); - t += strlen(t); - switch (mb(0) & 0xF) - { - default: - sprintf(t, "0x%x", mb(0) & 0x7); - break; - - case 1: - strcat(t, "0D"); - break; - - case 3: - strcat(t, "2D"); - break; - - case 4: - strcat(t, "3D"); - break; - } - t += strlen(t); - if (mb(0) & 0x10) - strcpy(t, "-MANUAL, "); - else - strcpy(t, "-AUTO, "); - t += strlen(t); - - sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", - mb(1), mb(2), mb(3), mb(4), - getflt((unsigned char *)&mb(5)), - getflt((unsigned char *)&mb(9)), - getflt((unsigned char *)&mb(13)), - getflt((unsigned char *)&mb(17))); - - break; - - case CMD_RVERSION: - sprintf(t, "%d.%d (%d/%d/%d)", - mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); - break; - - case CMD_RRECVHEALTH: - { - static const char *msgs[] = - { - "Battery backup failed", - "Signal processor error", - "Alignment error, channel or chip 1", - "Alignment error, channel or chip 2", - "Antenna feed line fault", - "Excessive ref freq. error", - "<BIT 6>", - "<BIT 7>" - }; - - int i, bits; - - switch (mb(0) & 0xFF) - { - default: - sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF); - break; - case 0x00: - strcpy(t, "doing position fixes"); - break; - case 0x01: - strcpy(t, "no GPS time yet"); - break; - case 0x03: - strcpy(t, "PDOP too high"); - break; - case 0x08: - strcpy(t, "no usable satellites"); - break; - case 0x09: - strcpy(t, "only ONE usable satellite"); - break; - case 0x0A: - strcpy(t, "only TWO usable satellites"); - break; - case 0x0B: - strcpy(t, "only THREE usable satellites"); - break; - case 0x0C: - strcpy(t, "the chosen satellite is unusable"); - break; - } - - t += strlen(t); - - bits = mb(1) & 0xFF; - - for (i = 0; i < 8; i++) - if (bits & (0x1<<i)) - { - sprintf(t, ", %s", msgs[i]); - t += strlen(t); - } - } - break; - - case CMD_RMESSAGE: - mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); - break; - - case CMD_RMACHSTAT: - { - static const char *msgs[] = - { - "Synthesizer Fault", - "Battery Powered Time Clock Fault", - "A-to-D Converter Fault", - "The almanac stored in the receiver is not complete and current", - "<BIT 4>", - "<BIT 5", - "<BIT 6>", - "<BIT 7>" - }; - - int i, bits; - - sprintf(t, "machine id 0x%02x", mb(0) & 0xFF); - t += strlen(t); - - bits = mb(1) & 0xFF; - - for (i = 0; i < 8; i++) - if (bits & (0x1<<i)) - { - sprintf(t, ", %s", msgs[i]); - t += strlen(t); - } - - sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); - } - break; - - case CMD_ROPERPARAM: - sprintf(t, "%2x %.1f %.1f %.1f %.1f", - mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), - getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); - break; - - case CMD_RUTCPARAM: - { - float t0t = getflt((unsigned char *)&mb(14)); - short wnt = getshort((unsigned char *)&mb(18)); - short dtls = getshort((unsigned char *)&mb(12)); - short wnlsf = getshort((unsigned char *)&mb(20)); - short dn = getshort((unsigned char *)&mb(22)); - short dtlsf = getshort((unsigned char *)&mb(24)); - - if ((int)t0t != 0) - { - mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf); - } - else - { - strcpy(t, "<NO UTC DATA>"); - } - } - break; - - case CMD_RSAT1BIAS: - sprintf(t, "%.1fm %.2fm/s at %.1fs", - getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); - break; - - case CMD_RIOOPTIONS: - { - sprintf(t, "%02x %02x %02x %02x", - mb(0), mb(1), mb(2), mb(3)); - if (mb(0) != TRIM_POS_OPT || - mb(2) != TRIM_TIME_OPT) - { - (void)trimbletsip_setup(parse, "bad io options"); - } - } - break; - - case CMD_RSPOSXYZ: - { - double x = getflt((unsigned char *)&mb(0)); - double y = getflt((unsigned char *)&mb(4)); - double z = getflt((unsigned char *)&mb(8)); - double f = getflt((unsigned char *)&mb(12)); - - if (f > 0.0) - sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", - x, y, z, - f); - else - return; - } - break; - - case CMD_RSLLAPOS: - { - double lat = getflt((unsigned char *)&mb(0)); - double lng = getflt((unsigned char *)&mb(4)); - double f = getflt((unsigned char *)&mb(12)); - - if (f > 0.0) - sprintf(t, "lat %f %c, long %f %c, alt %.2fm", - ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), - ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), - getflt((unsigned char *)&mb(8))); - else - return; - } - break; - - case CMD_RDOUBLEXYZ: - { - double x = getdbl((unsigned char *)&mb(0)); - double y = getdbl((unsigned char *)&mb(8)); - double z = getdbl((unsigned char *)&mb(16)); - sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm", - x, y, z); - } - break; - - case CMD_RDOUBLELLA: - { - double lat = getdbl((unsigned char *)&mb(0)); - double lng = getdbl((unsigned char *)&mb(8)); - sprintf(t, "lat %f %c, lon %f %c, alt %.2fm", - ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), - ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), - getdbl((unsigned char *)&mb(16))); - } - break; - - case CMD_RALLINVIEW: - { - int i, sats; - - strcpy(t, "mode: "); - t += strlen(t); - switch (mb(0) & 0x7) - { - default: - sprintf(t, "0x%x", mb(0) & 0x7); - break; - - case 3: - strcat(t, "2D"); - break; - - case 4: - strcat(t, "3D"); - break; - } - t += strlen(t); - if (mb(0) & 0x8) - strcpy(t, "-MANUAL, "); - else - strcpy(t, "-AUTO, "); - t += strlen(t); - - sats = (mb(0)>>4) & 0xF; - - sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", - getflt((unsigned char *)&mb(1)), - getflt((unsigned char *)&mb(5)), - getflt((unsigned char *)&mb(9)), - getflt((unsigned char *)&mb(13)), - sats, (sats == 1) ? "" : "s"); - t += strlen(t); - - for (i=0; i < sats; i++) - { - sprintf(t, "%s%02d", i ? ", " : "", mb(17+i)); - t += strlen(t); - if (tr) - tr->ctrack |= (1 << (mb(17+i)-1)); - } - - if (tr) - { /* mark for tracking status query */ - tr->qtracking = 1; - } - } - break; - - case CMD_RSTATTRACK: - { - sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */ - t += strlen(t); - - if (getflt((unsigned char *)&mb(4)) < 0.0) - { - strcpy(t, "<NO MEASUREMENTS>"); - var_flag &= ~DEF; - } - else - { - sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", - (mb(1) & 0xFF)>>3, - mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", - mb(3), - getflt((unsigned char *)&mb(4)), - getflt((unsigned char *)&mb(12)) * RTOD, - getflt((unsigned char *)&mb(16)) * RTOD); - t += strlen(t); - if (mb(20)) - { - var_flag &= ~DEF; - strcpy(t, ", OLD"); - } - t += strlen(t); - if (mb(22)) - { - if (mb(22) == 1) - strcpy(t, ", BAD PARITY"); - else - if (mb(22) == 2) - strcpy(t, ", BAD EPH HEALTH"); - } - t += strlen(t); - if (mb(23)) - strcpy(t, ", collecting data"); - } - } - break; - - default: - strcpy(t, "<UNDECODED>"); - break; - } - strcat(t,"\""); - set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); - } -} - - -/**============================================================ - ** RAWDCF support - **/ - -/*-------------------------------------------------- - * rawdcf_init_1 - set up modem lines for RAWDCF receivers - * SET DTR line - */ -#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) -static int -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 - sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ -#else - 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) - { - msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); - } - return 0; -} -#else -static int -rawdcfdtr_init_1( - struct parseunit *parse - ) -{ - msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); - return 0; -} -#endif /* DTR initialisation type */ - -/*-------------------------------------------------- - * rawdcf_init_2 - set up modem lines for RAWDCF receivers - * CLR DTR line, SET RTS line - */ -#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) -static int -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 - sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ -#else - 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) - { - msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); - } - return 0; -} -#else -static int -rawdcf_init_2( - struct parseunit *parse - ) -{ - msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); - return 0; -} -#endif /* DTR initialisation type */ - -#else /* defined(REFCLOCK) && defined(PARSE) */ -int refclock_parse_bs; -#endif /* defined(REFCLOCK) && defined(PARSE) */ - -/* - * History: - * - * refclock_parse.c,v - * Revision 4.36 1999/11/28 17:18:20 kardel - * disabled burst mode - * - * Revision 4.35 1999/11/28 09:14:14 kardel - * RECON_4_0_98F - * - * Revision 4.34 1999/05/14 06:08:05 kardel - * store current_time in a suitable container (u_long) - * - * Revision 4.33 1999/05/13 21:48:38 kardel - * double the no response timeout interval - * - * Revision 4.32 1999/05/13 20:09:13 kardel - * complain only about missing polls after a full poll interval - * - * Revision 4.31 1999/05/13 19:59:32 kardel - * add clock type 16 for RTS set DTR clr in RAWDCF - * - * Revision 4.30 1999/02/28 20:36:43 kardel - * fixed printf fmt - * - * Revision 4.29 1999/02/28 19:58:23 kardel - * updated copyright information - * - * Revision 4.28 1999/02/28 19:01:50 kardel - * improved debug out on sent Meinberg messages - * - * Revision 4.27 1999/02/28 18:05:55 kardel - * no linux/ppsclock.h stuff - * - * Revision 4.26 1999/02/28 15:27:27 kardel - * wharton clock integration - * - * Revision 4.25 1999/02/28 14:04:46 kardel - * added missing double quotes to UTC information string - * - * Revision 4.24 1999/02/28 12:06:50 kardel - * (parse_control): using gmprettydate instead of prettydate() - * (mk_utcinfo): new function for formatting GPS derived UTC information - * (gps16x_message): changed to use mk_utcinfo() - * (trimbletsip_message): changed to use mk_utcinfo() - * ignoring position information in unsynchronized mode - * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY - * - * Revision 4.23 1999/02/23 19:47:53 kardel - * fixed #endifs - * (stream_receive): fixed formats - * - * Revision 4.22 1999/02/22 06:21:02 kardel - * use new autoconfig symbols - * - * Revision 4.21 1999/02/21 12:18:13 kardel - * 4.91f reconcilation - * - * Revision 4.20 1999/02/21 10:53:36 kardel - * initial Linux PPSkit version - * - * Revision 4.19 1999/02/07 09:10:45 kardel - * clarify STREAMS mitigation rules in comment - * - * Revision 4.18 1998/12/20 23:45:34 kardel - * fix types and warnings - * - * Revision 4.17 1998/11/15 21:24:51 kardel - * cannot access mbg_ routines when CLOCK_MEINBERG - * is not defined - * - * Revision 4.16 1998/11/15 20:28:17 kardel - * Release 4.0.73e13 reconcilation - * - * Revision 4.15 1998/08/22 21:56:08 kardel - * fixed IO handling for non-STREAM IO - * - * Revision 4.14 1998/08/16 19:00:48 kardel - * (gps16x_message): reduced UTC parameter information (dropped A0,A1) - * made uval a local variable (killed one of the last globals) - * (sendetx): added logging of messages when in debug mode - * (trimble_check): added periodic checks to facilitate re-initialization - * (trimbletsip_init): made use of EOL character if in non-kernel operation - * (trimbletsip_message): extended message interpretation - * (getdbl): fixed data conversion - * - * Revision 4.13 1998/08/09 22:29:13 kardel - * Trimble TSIP support - * - * Revision 4.12 1998/07/11 10:05:34 kardel - * Release 4.0.73d reconcilation - * - * Revision 4.11 1998/06/14 21:09:42 kardel - * Sun acc cleanup - * - * Revision 4.10 1998/06/13 12:36:45 kardel - * signed/unsigned, name clashes - * - * Revision 4.9 1998/06/12 15:30:00 kardel - * prototype fixes - * - * Revision 4.8 1998/06/12 11:19:42 kardel - * added direct input processing routine for refclocks in - * order to avaiod that single character io gobbles up all - * receive buffers and drops input data. (Problem started - * with fast machines so a character a buffer was possible - * one of the few cases where faster machines break existing - * allocation algorithms) - * - * Revision 4.7 1998/06/06 18:35:20 kardel - * (parse_start): added BURST mode initialisation - * - * Revision 4.6 1998/05/27 06:12:46 kardel - * RAWDCF_BASEDELAY default added - * old comment removed - * casts for ioctl() - * - * Revision 4.5 1998/05/25 22:05:09 kardel - * RAWDCF_SETDTR option removed - * clock type 14 attempts to set DTR for - * power supply of RAWDCF receivers - * - * Revision 4.4 1998/05/24 16:20:47 kardel - * updated comments referencing Meinberg clocks - * added RAWDCF clock with DTR set option as type 14 - * - * Revision 4.3 1998/05/24 10:48:33 kardel - * calibrated CONRAD RAWDCF default fudge factor - * - * Revision 4.2 1998/05/24 09:59:35 kardel - * corrected version information (ntpq support) - * - * Revision 4.1 1998/05/24 09:52:31 kardel - * use fixed format only (new IO model) - * output debug to stdout instead of msyslog() - * don't include >"< in ASCII output in order not to confuse - * ntpq parsing - * - * Revision 4.0 1998/04/10 19:52:11 kardel - * Start 4.0 release version numbering - * - * Revision 1.2 1998/04/10 19:28:04 kardel - * initial NTP VERSION 4 integration of PARSE with GPS166 binary support - * derived from 3.105.1.2 from V3 tree - * - * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel - * - */ diff --git a/contrib/ntp/ntpd/refclock_pcf.c b/contrib/ntp/ntpd/refclock_pcf.c deleted file mode 100644 index d4e9fd1..0000000 --- a/contrib/ntp/ntpd/refclock_pcf.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * refclock_pcf - clock driver for the Conrad parallel port radio clock - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_PCF) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_calendar.h" -#include "ntp_stdlib.h" - -/* - * 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 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/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" - -#define LENPCF 18 /* timecode length */ - -/* - * Function prototypes - */ -static int pcf_start P((int, struct peer *)); -static void pcf_shutdown P((int, struct peer *)); -static void pcf_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_pcf = { - pcf_start, /* start up driver */ - pcf_shutdown, /* shut down driver */ - pcf_poll, /* transmit poll message */ - noentry, /* not used */ - noentry, /* initialize driver (not used) */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; - - -/* - * pcf_start - open the device and initialize data for processing - */ -static int -pcf_start( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - int fd; - 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 == -1) { - return (0); - } - - pp = peer->procptr; - pp->io.clock_recv = noentry; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - - /* - * Initialize miscellaneous variables - */ - 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); -} - - -/* - * pcf_shutdown - shut down the clock - */ -static void -pcf_shutdown( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - - pp = peer->procptr; - (void)close(pp->io.fd); -} - - -/* - * pcf_poll - called by the transmit procedure - */ -static void -pcf_poll( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - char buf[LENPCF]; - struct tm tm, *tp; - time_t t; - - pp = peer->procptr; - - buf[0] = 0; - if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) { - refclock_report(peer, CEVNT_FAULT); - return; - } - - tm.tm_mday = buf[11] * 10 + buf[10]; - tm.tm_mon = buf[13] * 10 + buf[12] - 1; - tm.tm_year = buf[15] * 10 + buf[14]; - 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 = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1; - - /* - * Y2K convert the 2-digit year - */ - if (tm.tm_year < 99) - tm.tm_year += 100; - - t = mktime(&tm); - if (t == (time_t) -1) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - -#if defined(__GLIBC__) && defined(_BSD_SOURCE) - if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200) - || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600) - || tm.tm_isdst < 0) { -#ifdef DEBUG - if (debug) - printf ("local time zone not set to CET/CEST\n"); -#endif - refclock_report(peer, CEVNT_BADTIME); - return; - } -#endif - - pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm); - -#if defined(_REENTRANT) || defined(_THREAD_SAFE) - tp = gmtime_r(&t, &tm); -#else - tp = gmtime(&t); -#endif - if (!tp) { - refclock_report(peer, CEVNT_FAULT); - return; - } - - get_systime(&pp->lastrec); - pp->polls++; - pp->year = tp->tm_year + 1900; - pp->day = tp->tm_yday + 1; - pp->hour = tp->tm_hour; - pp->minute = tp->tm_min; - pp->second = tp->tm_sec; - pp->nsec = buf[16] * 31250000; - if (buf[17] & 1) - pp->nsec += 500000000; - -#ifdef DEBUG - if (debug) - printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", - unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour, - pp->minute, pp->second); -#endif - - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - record_clock_stats(&peer->srcadr, pp->a_lastcode); - if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2)) - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; - pp->lastref = pp->lastrec; - refclock_receive(peer); -} -#else -int refclock_pcf_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_pst.c b/contrib/ntp/ntpd/refclock_pst.c deleted file mode 100644 index 2443b2c..0000000 --- a/contrib/ntp/ntpd/refclock_pst.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * refclock_pst - clock driver for PSTI/Traconex WWV/WWVH receivers - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_PST) - -#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, - * but actual experience suggests that 10 ms would be a conservative - * assumption. - * - * The DIPswitches should be set for 9600 bps line speed, 24-hour day- - * of-year format and UTC time zone. Automatic correction for DST should - * be disabled. 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. The propagation delay DIPswitches - * should be set according to the distance from the transmitter for both - * WWV and WWVH, as described in the instructions. While the delay can - * be set only to within 11 ms, the fudge time1 parameter can be used - * for vernier corrections. - * - * Using the poll sequence QTQDQM, the response timecode is in three - * sections totalling 50 ASCII printing characters, as concatenated by - * the driver, in the following format: - * - * ahh:mm:ss.fffs<cr> yy/dd/mm/ddd<cr> frdzycchhSSFTttttuuxx<cr> - * - * on-time = first <cr> - * hh:mm:ss.fff = hours, minutes, seconds, milliseconds - * a = AM/PM indicator (' ' for 24-hour mode) - * yy = year (from internal switches) - * dd/mm/ddd = day of month, month, day of year - * s = daylight-saving indicator (' ' for 24-hour mode) - * f = frequency enable (O = all frequencies enabled) - * r = baud rate (3 = 1200, 6 = 9600) - * d = features indicator (@ = month/day display enabled) - * z = time zone (0 = UTC) - * y = year (5 = 91) - * cc = WWV propagation delay (52 = 22 ms) - * hh = WWVH propagation delay (81 = 33 ms) - * SS = status (80 or 82 = operating correctly) - * F = current receive frequency (4 = 15 MHz) - * T = transmitter (C = WWV, H = WWVH) - * tttt = time since last update (0000 = minutes) - * uu = flush character (03 = ^c) - * xx = 94 (unknown) - * - * The alarm condition is indicated by other than '8' at A, which occurs - * during initial synchronization and when received signal is lost for - * an extended period; unlock condition is indicated by other than - * "0000" in the tttt subfield at Q. - * - * Fudge Factors - * - * There are no special fudge factors other than the generic. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/wwv%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define WWVREFID "WWV\0" /* WWV reference ID */ -#define WWVHREFID "WWVH" /* WWVH reference ID */ -#define DESCRIPTION "PSTI/Traconex WWV/WWVH Receiver" /* WRU */ -#define PST_PHI (10e-6) /* max clock oscillator offset */ -#define LENPST 46 /* min timecode length */ - -/* - * Unit control structure - */ -struct pstunit { - int tcswitch; /* timecode switch */ - char *lastptr; /* pointer to timecode data */ -}; - -/* - * Function prototypes - */ -static int pst_start P((int, struct peer *)); -static void pst_shutdown P((int, struct peer *)); -static void pst_receive P((struct recvbuf *)); -static void pst_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_pst = { - pst_start, /* start up driver */ - pst_shutdown, /* shut down driver */ - pst_poll, /* transmit poll message */ - noentry, /* not used (old pst_control) */ - noentry, /* initialize driver */ - noentry, /* not used (old pst_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * pst_start - open the devices and initialize data for processing - */ -static int -pst_start( - int unit, - struct peer *peer - ) -{ - register struct pstunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct pstunit *)emalloc(sizeof(struct pstunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct pstunit)); - pp = peer->procptr; - pp->io.clock_recv = pst_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, WWVREFID, 4); - peer->burst = MAXSTAGE; - return (1); -} - - -/* - * pst_shutdown - shut down the clock - */ -static void -pst_shutdown( - int unit, - struct peer *peer - ) -{ - register struct pstunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct pstunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * pst_receive - receive data from the serial interface - */ -static void -pst_receive( - struct recvbuf *rbufp - ) -{ - register struct pstunit *up; - struct refclockproc *pp; - struct peer *peer; - l_fp trtmp; - u_long ltemp; - char ampmchar; /* AM/PM indicator */ - char daychar; /* standard/daylight indicator */ - char junque[10]; /* "yy/dd/mm/" discard */ - char info[14]; /* "frdzycchhSSFT" clock info */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct pstunit *)pp->unitptr; - up->lastptr += refclock_gtlin(rbufp, up->lastptr, pp->a_lastcode - + BMAX - 2 - up->lastptr, &trtmp); - *up->lastptr++ = ' '; - *up->lastptr = '\0'; - - /* - * Note we get a buffer and timestamp for each <cr>, but only - * the first timestamp is retained. - */ - if (up->tcswitch == 0) - pp->lastrec = trtmp; - up->tcswitch++; - pp->lencode = up->lastptr - pp->a_lastcode; - if (up->tcswitch < 3) - return; - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. - */ - if (pp->lencode < LENPST) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Timecode format: - * "ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx" - */ - if (sscanf(pp->a_lastcode, - "%c%2d:%2d:%2d.%3ld%c %9s%3d%13s%4ld", - &mchar, &pp->hour, &pp->minute, &pp->second, &pp->nsec, - &daychar, junque, &pp->day, info, <emp) != 10) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - pp->nsec *= 1000000; - - /* - * Decode synchronization, quality and last update. If - * unsynchronized, set the leap bits accordingly and exit. Once - * synchronized, the dispersion depends only on when the clock - * was last heard, which depends on the time since last update, - * as reported by the clock. - */ - if (info[9] != '8') - pp->leap = LEAP_NOTINSYNC; - if (info[12] == 'H') - memcpy((char *)&pp->refid, WWVHREFID, 4); - else - memcpy((char *)&pp->refid, WWVREFID, 4); - if (peer->stratum <= 1) - peer->refid = pp->refid; - if (ltemp == 0) - pp->lastref = pp->lastrec; - pp->disp = PST_PHI * ltemp * 60; - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if (!refclock_process(pp)) - refclock_report(peer, CEVNT_BADTIME); - -} - - -/* - * pst_poll - called by the transmit procedure - */ -static void -pst_poll( - int unit, - struct peer *peer - ) -{ - register struct pstunit *up; - struct refclockproc *pp; - - /* - * Time to poll the clock. The PSTI/Traconex clock responds to a - * "QTQDQMT" by returning a timecode in the format specified - * above. Note there is no checking on state, since this may not - * be the only customer reading the clock. Only one customer - * need poll the clock; all others just listen in. If the clock - * becomes unreachable, declare a timeout and keep going. - */ - pp = peer->procptr; - up = (struct pstunit *)pp->unitptr; - up->tcswitch = 0; - up->lastptr = pp->a_lastcode; - if (write(pp->io.fd, "QTQDQMT", 6) != 6) - refclock_report(peer, CEVNT_FAULT); - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("pst: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - peer->burst = MAXSTAGE; - pp->polls++; -} - -#else -int refclock_pst_int; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_ptbacts.c b/contrib/ntp/ntpd/refclock_ptbacts.c deleted file mode 100644 index 09d7bf4..0000000 --- a/contrib/ntp/ntpd/refclock_ptbacts.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * crude hack to avoid hard links in distribution - * and keep only one ACTS type source for different - * ACTS refclocks - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_PTBACTS) -# define KEEPPTBACTS -# include "refclock_acts.c" -#else /* not (REFCLOCK && CLOCK_PTBACTS) */ -int refclock_ptbacts_bs; -#endif /* not (REFCLOCK && CLOCK_PTBACTS) */ diff --git a/contrib/ntp/ntpd/refclock_ripencc.c b/contrib/ntp/ntpd/refclock_ripencc.c deleted file mode 100644 index 6337f63..0000000 --- a/contrib/ntp/ntpd/refclock_ripencc.c +++ /dev/null @@ -1,4870 +0,0 @@ -/* - * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $ - * - * Copyright (c) 2002 RIPE NCC - * - * All Rights Reserved - * - * 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 appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of the author not be - * used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL - * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY - * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * - * - * This driver was developed for use with the RIPE NCC TTM project. - * - * - * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net> - * using the code made available by Trimble. This was for xntpd-3.x.x - * - * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net> - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -#if defined(REFCLOCK) && defined(CLOCK_RIPENCC) - -#include "ntp_stdlib.h" -#include "ntpd.h" -#include "ntp_refclock.h" -#include "ntp_unixtime.h" -#include "ntp_io.h" - -#ifdef HAVE_TIMEPPS_H -# include <timepps.h> -#else /* HAVE_TIMEPPS_H */ -# ifdef HAVE_SYS_TIMEPPS_H -# include <sys/timepps.h> -# endif /* HAVE_SYS_TIMEPPS_H */ -#endif /* HAVE_TIMEPPS_H */ - -/* - * Definitions - */ - -/* we are on little endian */ -#define BYTESWAP - -/* - * DEBUG statements: uncomment if necessary - */ -/* #define DEBUG_NCC */ /* general debug statements */ -/* #define DEBUG_PPS */ /* debug pps */ -/* #define DEBUG_RAW */ /* print raw packets */ - -#define TRIMBLE_OUTPUT_FUNC -#define TSIP_VERNUM "7.12a" - -#ifndef FALSE -#define FALSE (0) -#define TRUE (!FALSE) -#endif /* FALSE */ - -#define GPS_PI (3.1415926535898) -#define GPS_C (299792458.) -#define D2R (GPS_PI/180.0) -#define R2D (180.0/GPS_PI) -#define WEEK (604800.) -#define MAXCHAN (8) - -/* control characters for TSIP packets */ -#define DLE (0x10) -#define ETX (0x03) - -#define MAX_RPTBUF (256) - -/* values of TSIPPKT.status */ -#define TSIP_PARSED_EMPTY 0 -#define TSIP_PARSED_FULL 1 -#define TSIP_PARSED_DLE_1 2 -#define TSIP_PARSED_DATA 3 -#define TSIP_PARSED_DLE_2 4 - -#define UTCF_UTC_AVAIL (unsigned char) (1) /* UTC available */ -#define UTCF_LEAP_SCHD (unsigned char) (1<<4) /* Leap scheduled */ -#define UTCF_LEAP_PNDG (unsigned char) (1<<5) /* Leap pending, will occur at end of day */ - -#define DEVICE "/dev/gps%d" /* name of radio device */ -#define PRECISION (-9) /* precision assumed (about 2 ms) */ -#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS\0" /* reference id */ -#define REFID_LEN 4 -#define DESCRIPTION "RIPE NCC GPS (Palisade)" /* Description */ -#define SPEED232 B9600 /* 9600 baud */ - -#define NSAMPLES 3 /* stages of median filter */ - -/* Structures */ - -/* TSIP packets have the following structure, whether report or command. */ -typedef struct { - short - counter, /* counter */ - len; /* size of buf; < MAX_RPTBUF unsigned chars */ - unsigned char - status, /* TSIP packet format/parse status */ - code, /* TSIP code */ - buf[MAX_RPTBUF];/* report or command string */ -} TSIPPKT; - -/* TSIP binary data structures */ -typedef struct { - unsigned char - t_oa_raw, SV_health; - float - e, t_oa, i_0, OMEGADOT, sqrt_A, - OMEGA_0, omega, M_0, a_f0, a_f1, - Axis, n, OMEGA_n, ODOT_n, t_zc; - short - weeknum, wn_oa; -} ALM_INFO; - -typedef struct { /* Almanac health page (25) parameters */ - unsigned char - WN_a, SV_health[32], t_oa; -} ALH_PARMS; - -typedef struct { /* Universal Coordinated Time (UTC) parms */ - double - A_0; - float - A_1; - short - delta_t_LS; - float - t_ot; - short - WN_t, WN_LSF, DN, delta_t_LSF; -} UTC_INFO; - -typedef struct { /* Ionospheric info (float) */ - float - alpha_0, alpha_1, alpha_2, alpha_3, - beta_0, beta_1, beta_2, beta_3; -} ION_INFO; - -typedef struct { /* Subframe 1 info (float) */ - short - weeknum; - unsigned char - codeL2, L2Pdata, SVacc_raw, SV_health; - short - IODC; - float - T_GD, t_oc, a_f2, a_f1, a_f0, SVacc; -} EPHEM_CLOCK; - -typedef struct { /* Ephemeris info (float) */ - unsigned char - IODE, fit_interval; - float - C_rs, delta_n; - double - M_0; - float - C_uc; - double - e; - float - C_us; - double - sqrt_A; - float - t_oe, C_ic; - double - OMEGA_0; - float - C_is; - double - i_0; - float - C_rc; - double - omega; - float - OMEGADOT, IDOT; - double - Axis, n, r1me2, OMEGA_n, ODOT_n; -} EPHEM_ORBIT; - -typedef struct { /* Navigation data structure */ - short - sv_number; /* SV number (0 = no entry) */ - float - t_ephem; /* time of ephemeris collection */ - EPHEM_CLOCK - ephclk; /* subframe 1 data */ - EPHEM_ORBIT - ephorb; /* ephemeris data */ -} NAV_INFO; - -typedef struct { - unsigned char - bSubcode, - operating_mode, - dgps_mode, - dyn_code, - trackmode; - float - elev_mask, - cno_mask, - dop_mask, - dop_switch; - unsigned char - dgps_age_limit; -} TSIP_RCVR_CFG; - - -#ifdef TRIMBLE_OUTPUT_FUNC -static char - *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}, - old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12}, - *st_baud_text_app [] = {"", "", " 300", " 600", " 1200", " 2400", - " 4800", " 9600", "19200", "38400"}, - *old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"}, - *parity_text [] = {"NONE", "ODD", "EVEN"}, - *old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"}, - *old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"}, - *protocols_in_text[] = { "", "TSIP", "", ""}, - *protocols_out_text[] = { "", "TSIP", "NMEA"}, - *rcvr_port_text [] = { "Port A ", "Port B ", "Current Port"}, - *dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"}, - *NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D", - "3-D", "", "", "OverDetermined Time"}, - *PPSTimeBaseText[] = {"GPS", "UTC", "USER"}, - *PPSPolarityText[] = {"Positive", "Negative"}, - *MaskText[] = { "Almanac ", "Ephemeris", "UTC ", "Iono ", - "GPS Msg ", "Alm Hlth ", "Time Fix ", "SV Select", - "Ext Event", "Pos Fix ", "Raw Meas "}; - -#endif /* TRIMBLE_OUTPUT_FUNC */ - -/* - * Unit control structure - */ -struct ripencc_unit { - int unit; /* unit number */ - int pollcnt; /* poll message counter */ - int polled; /* Hand in a sample? */ - char leapdelta; /* delta of next leap event */ - unsigned char utcflags; /* delta of next leap event */ - l_fp tstamp; /* timestamp of last poll */ - - 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 */ - -}; - - -/******************* PROTOYPES *****************/ - -/* prototypes for report parsing primitives */ -short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index, - unsigned char *rx_baud_index, unsigned char *char_format_index, - unsigned char *stop_bits, unsigned char *tx_mode_index, - unsigned char *rx_mode_index); -short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num, - float *t_zc, float *eccentricity, float *t_oa, float *i_0, - float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega, - float *M_0); -short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset, - short *week_num); -short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix); -short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset, - float *time_of_fix); -short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version, - unsigned char *minor_nav_version, unsigned char *nav_day, - unsigned char *nav_month, unsigned char *nav_year, - unsigned char *major_dsp_version, unsigned char *minor_dsp_version, - unsigned char *dsp_day, unsigned char *dsp_month, - unsigned char *dsp_year); -short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2); -short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn, - float *snr); -short rpt_0x48 (TSIPPKT *rpt, unsigned char *message); -short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health); -short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt, - float *clock_bias, float *time_of_fix); -short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy, - unsigned char *alt_flag); -short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id, - unsigned char *status3, unsigned char *status4); -short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask, - float *snr_mask, float *dop_mask, float *dop_switch); -short rpt_0x4D (TSIPPKT *rpt, float *osc_offset); -short rpt_0x4E (TSIPPKT *rpt, unsigned char *response); -short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data, - short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf); -short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset, - float *time_of_fix); -short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code, - unsigned char *time_code, unsigned char *aux_code); -short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset, - float *time_of_fix); -short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code, - unsigned char *diag_code, short *week_num, float *time_of_fix); -short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type, - unsigned char *sv_prn, unsigned char *data_length, - unsigned char *data_packet); -short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type, - unsigned char status_code[32]); -short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length, - float *signal_level, float *code_phase, float *Doppler, - double *time_of_fix); -short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health, - unsigned char *sv_iode, unsigned char *fit_interval_flag, - float *time_of_collection, float *time_of_eph, float *sv_accy); -short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot, - unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag, - float *signal_level, float *time_of_last_msmt, float *elev, - float *azim, unsigned char *old_msmt_flag, - unsigned char *integer_msec_flag, unsigned char *bad_data_flag, - unsigned char *data_collect_flag); -short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs, - unsigned char *ndim, unsigned char sv_prn[], float *pdop, - float *hdop, float *vdop, float *tdop); -short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode); -short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias, - float *time_of_fix); -short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt, - double *clock_bias, float *time_of_fix); -short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB); -short rpt_0xBC (TSIPPKT *rpt, unsigned char *port_num, - unsigned char *in_baud, unsigned char *out_baud, - unsigned char *data_bits, unsigned char *parity, - unsigned char *stop_bits, unsigned char *flow_control, - unsigned char *protocols_in, unsigned char *protocols_out, - unsigned char *reserved); - -/* prototypes for superpacket parsers */ - -short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow, - unsigned char *date, unsigned char *month, short *year, - unsigned char *dim_mode, short *utc_offset, double *bias, double *drift, - float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt, - char sv_id[8]); -short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]); -short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]); -short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat, - double *lon, double *alt, double vel_enu[], double *time_of_fix, - short *week_num, unsigned char *nsvs, unsigned char sv_prn[], - short sv_IODC[], short *datum_index); -short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange, - unsigned char *bBoardOptions, unsigned long *iiSerialNumber, - unsigned char *bBuildYear, unsigned char *bBuildMonth, - unsigned char *bBuildDay, unsigned char *bBuildHour, - float *fOscOffset, unsigned short *iTestCodeId); -short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre, - unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre, - unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber, - unsigned short *iPremiumOptions, unsigned short *iMachineID, - unsigned short *iKey); -short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask); -short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled, - unsigned char *pps_timebase, unsigned char *pos_polarity, - double *pps_offset, float *bias_unc_threshold); -short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max); -short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask); -short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask); -short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec, - unsigned char *Hour, unsigned char *Minute, unsigned char *Second, - unsigned char *Day, unsigned char *Month, unsigned short *Year, - unsigned char *Status, unsigned char *Flags); - -/**/ -/* prototypes for command-encode primitives with suffix convention: */ -/* c = clear, s = set, q = query, e = enable, d = disable */ -void cmd_0x1F (TSIPPKT *cmd); -void cmd_0x26 (TSIPPKT *cmd); -void cmd_0x2F (TSIPPKT *cmd); -void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code, - unsigned char time_code, unsigned char opts_code); -void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn); -void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp, - unsigned char char_code, unsigned char stopbitcode, - unsigned char output_mode, unsigned char input_mode); -void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ; - -/* prototypes 8E commands */ -void cmd_0x8E0Bq (TSIPPKT *cmd); -void cmd_0x8E41q (TSIPPKT *cmd); -void cmd_0x8E42q (TSIPPKT *cmd); -void cmd_0x8E4Aq (TSIPPKT *cmd); -void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase, - unsigned char Polarity, double PPSOffset, float Uncertainty); -void cmd_0x8E4Bq (TSIPPKT *cmd); -void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask); -void cmd_0x8EADq (TSIPPKT *cmd); - -/* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */ - -/* Trimble parse functions */ -static int parse0x8FAD P((TSIPPKT *, struct peer *)); -static int parse0x8F0B P((TSIPPKT *, struct peer *)); -#ifdef TRIMBLE_OUTPUT_FUNC -static int parseany P((TSIPPKT *, struct peer *)); -static void TranslateTSIPReportToText P((TSIPPKT *, char *)); -#endif /* TRIMBLE_OUTPUT_FUNC */ -static int parse0x5C P((TSIPPKT *, struct peer *)); -static int parse0x4F P((TSIPPKT *, struct peer *)); -static void tsip_input_proc P((TSIPPKT *, int)); - -/* Trimble helper functions */ -static void bPutFloat P((float *, unsigned char *)); -static void bPutDouble P((double *, unsigned char *)); -static void bPutULong P((unsigned long *, unsigned char *)); -static int print_msg_table_header P((int rptcode, char *HdrStr, int force)); -static char * show_time P((float time_of_week)); - -/* RIPE NCC functions */ -static void ripencc_control P((int, struct refclockstat *, struct - refclockstat *, struct peer *)); -static int ripencc_ppsapi P((struct peer *, int, int)); -static int ripencc_get_pps_ts P((struct ripencc_unit *, l_fp *)); -static int ripencc_start P((int, struct peer *)); -static void ripencc_shutdown P((int, struct peer *)); -static void ripencc_poll P((int, struct peer *)); -static void ripencc_send P((struct peer *, TSIPPKT spt)); -static void ripencc_receive P((struct recvbuf *)); - -/* fill in reflock structure for our clock */ -struct refclock refclock_ripencc = { - ripencc_start, /* start up driver */ - ripencc_shutdown, /* shut down driver */ - ripencc_poll, /* transmit poll message */ - ripencc_control, /* control function */ - noentry, /* initialize driver */ - noentry, /* debug info */ - NOFLAGS /* clock flags */ -}; - -/* - * Tables to compute the ddd of year form icky dd/mm timecode. Viva la - * leap. - */ -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}; - - -/* - * ripencc_start - open the GPS devices and initialize data for processing - */ -static int -ripencc_start(int unit, struct peer *peer) -{ - register struct ripencc_unit *up; - struct refclockproc *pp; - char device[40]; - int fd; - struct termios tio; - TSIPPKT spt; - - /* - * Open serial port - */ - (void)snprintf(device, sizeof(device), DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_RAW))) - return (0); - - /* from refclock_palisade.c */ - if (tcgetattr(fd, &tio) < 0) { - msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit); - return (0); - } - - /* - * set flags - */ - tio.c_cflag |= (PARENB|PARODD); - tio.c_iflag &= ~ICRNL; - if (tcsetattr(fd, TCSANOW, &tio) == -1) { - msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); - return (0); - } - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct ripencc_unit *) - emalloc(sizeof(struct ripencc_unit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct ripencc_unit)); - pp = peer->procptr; - pp->io.clock_recv = ripencc_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, REFID_LEN); - up->pollcnt = 2; - up->unit = unit; - up->leapdelta = 0; - up->utcflags = 0; - - /* - * Initialize the Clock - */ - - /* query software versions */ - cmd_0x1F(&spt); - ripencc_send(peer, spt); - - /* query receiver health */ - cmd_0x26(&spt); - ripencc_send(peer, spt); - - /* query serial numbers */ - cmd_0x8E42q(&spt); - ripencc_send(peer, spt); - - /* query manuf params */ - cmd_0x8E41q(&spt); - ripencc_send(peer, spt); - - /* i/o opts */ /* trimble manual page A30 */ - cmd_0x35s(&spt, - 0x1C, /* position */ - 0x00, /* velocity */ - 0x05, /* timing */ - 0x0a); /* auxilary */ - ripencc_send(peer, spt); - - /* turn off port A */ - cmd_0x3Ds (&spt, - 0x0B, /* baud_out */ - 0x0B, /* baud_inp */ - 0x07, /* char_code */ - 0x07, /* stopbitcode */ - 0x01, /* output_mode */ - 0x00); /* input_mode */ - ripencc_send(peer, spt); - - /* set i/o options */ - cmd_0x8E4As (&spt, - 0x01, /* PPS on */ - 0x01, /* Timebase UTC */ - 0x00, /* polarity positive */ - 0., /* 100 ft. cable XXX make flag */ - 1e-6 * GPS_C); /* turn of biasuncert. > (1us) */ - ripencc_send(peer,spt); - - /* all outomatic packet output off */ - cmd_0x8E4Ds(&spt, - 0x00000000); /* AutoOutputMask */ - ripencc_send(peer, spt); - - cmd_0xBBq (&spt, - 0x00); /* query primary configuration */ - ripencc_send(peer,spt); - - - /* query PPS parameters */ - cmd_0x8E4Aq (&spt); /* query PPS params */ - ripencc_send(peer,spt); - - /* query survey limit */ - cmd_0x8E4Bq (&spt); /* query survey limit */ - ripencc_send(peer,spt); - -#ifdef DEBUG_NCC - if (debug) - printf("ripencc_start: success\n"); -#endif /* DEBUG_NCC */ - - /* - * 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_ripencc: time_pps_create failed: %m"); - return (1); - } - - return(ripencc_ppsapi(peer, 0, 0)); -} - -/* - * ripencc_control - fudge control - */ -static void -ripencc_control( - int unit, /* unit (not used) */ - struct refclockstat *in, /* input parameters (not used) */ - struct refclockstat *out, /* output parameters (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - -#ifdef DEBUG_NCC - msyslog(LOG_INFO,"%s()",__FUNCTION__); -#endif /* DEBUG_NCC */ - - pp = peer->procptr; - ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2, - pp->sloppyclockflag & CLK_FLAG3); -} - - -/* - * Initialize PPSAPI - */ -int -ripencc_ppsapi( - struct peer *peer, /* peer structure pointer */ - int enb_clear, /* clear enable */ - int enb_hardpps /* hardpps enable */ - ) -{ - struct refclockproc *pp; - struct ripencc_unit *up; - int capability; - - pp = peer->procptr; - up = (struct ripencc_unit *)pp->unitptr; - if (time_pps_getcap(up->handle, &capability) < 0) { - msyslog(LOG_ERR, - "refclock_ripencc: 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_ripencc: invalid capture edge %d", - !enb_clear); - return (0); - } - up->pps_params.mode |= PPS_TSFMT_TSPEC; - if (time_pps_setparams(up->handle, &up->pps_params) < 0) { - msyslog(LOG_ERR, - "refclock_ripencc: time_pps_setparams failed: %m"); - 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_ripencc: time_pps_kcbind failed: %m"); - return (0); - } - pps_enable = 1; - } - peer->precision = PPS_PRECISION; - -#if DEBUG_NCC - if (debug) { - time_pps_getparams(up->handle, &up->pps_params); - printf( - "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n", - capability, up->pps_params.api_version, - up->pps_params.mode, enb_hardpps); - } -#endif /* DEBUG_NCC */ - - return (1); -} - -/* - * This function is called every 64 seconds from ripencc_receive - * It will fetch the pps time - * - * Return 0 on failure and 1 on success. - */ -static int -ripencc_get_pps_ts( - struct ripencc_unit *up, - l_fp *tsptr - ) -{ - pps_info_t pps_info; - struct timespec timeout, ts; - double dtemp; - l_fp tstmp; - -#ifdef DEBUG_PPS - msyslog(LOG_INFO,"ripencc_get_pps_ts\n"); -#endif /* DEBUG_PPS */ - - - /* - * 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; - -#ifdef DEBUG_PPS - msyslog(LOG_INFO,"ts.tv_sec: %d\n",(int)ts.tv_sec); - msyslog(LOG_INFO,"ts.tv_nsec: %ld\n",ts.tv_nsec); -#endif /* DEBUG_PPS */ - - *tsptr = tstmp; - return (1); -} - -/* - * ripencc_shutdown - shut down a GPS clock - */ -static void -ripencc_shutdown(int unit, struct peer *peer) -{ - register struct ripencc_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct ripencc_unit *)pp->unitptr; - - if (up->handle != 0) - time_pps_destroy(up->handle); - - io_closeclock(&pp->io); - - free(up); -} - -/* - * ripencc_poll - called by the transmit procedure - */ -static void -ripencc_poll(int unit, struct peer *peer) -{ - register struct ripencc_unit *up; - struct refclockproc *pp; - TSIPPKT spt; - -#ifdef DEBUG_NCC - if (debug) - fprintf(stderr, "ripencc_poll(%d)\n", unit); -#endif /* DEBUG_NCC */ - pp = peer->procptr; - up = (struct ripencc_unit *)pp->unitptr; - if (up->pollcnt == 0) - refclock_report(peer, CEVNT_TIMEOUT); - else - up->pollcnt--; - - pp->polls++; - up->polled = 1; - - /* poll for UTC superpacket */ - cmd_0x8EADq (&spt); - ripencc_send(peer,spt); -} - -/* - * ripencc_send - send message to clock - * use the structures being created by the trimble functions! - * makes the code more readable/clean - */ -static void -ripencc_send(struct peer *peer, TSIPPKT spt) -{ - unsigned char *ip, *op; - unsigned char obuf[512]; - -#ifdef DEBUG_RAW - { - register struct ripencc_unit *up; - register struct refclockproc *pp; - - pp = peer->procptr; - up = (struct ripencc_unit *)pp->unitptr; - if (debug) - printf("ripencc_send(%d, %02X)\n", up->unit, cmd); - } -#endif /* DEBUG_RAW */ - - ip = spt.buf; - op = obuf; - - *op++ = 0x10; - *op++ = spt.code; - - while (spt.len--) { - if (op-obuf > sizeof(obuf)-5) { - msyslog(LOG_ERR, "ripencc_send obuf overflow!"); - refclock_report(peer, CEVNT_FAULT); - return; - } - - if (*ip == 0x10) /* byte stuffing */ - *op++ = 0x10; - *op++ = *ip++; - } - - *op++ = 0x10; - *op++ = 0x03; - -#ifdef DEBUG_RAW - if (debug) { /* print raw packet */ - unsigned char *cp; - int i; - - printf("ripencc_send: len %d\n", op-obuf); - for (i=1, cp=obuf; cp<op; i++, cp++) { - printf(" %02X", *cp); - if (i%10 == 0) - printf("\n"); - } - printf("\n"); - } -#endif /* DEBUG_RAW */ - - if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) { - refclock_report(peer, CEVNT_FAULT); - } -} - -/* - * ripencc_receive() - * - * called when a packet is received on the serial port - * takes care of further processing - * - */ -static void -ripencc_receive(struct recvbuf *rbufp) -{ - register struct ripencc_unit *up; - register struct refclockproc *pp; - struct peer *peer; - static TSIPPKT rpt; /* structure for current incoming TSIP report */ - TSIPPKT spt; /* send packet */ - int ns_since_pps; - int i; - char *cp; - /* Use these variables to hold data until we decide its worth keeping */ - char rd_lastcode[BMAX]; - l_fp rd_tmp; - u_short rd_lencode; - - /* msyslog(LOG_INFO, "%s",__FUNCTION__); */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct ripencc_unit *)pp->unitptr; - rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); - -#ifdef DEBUG_RAW - if (debug) - fprintf(stderr, "ripencc_receive(%d)\n", up->unit); -#endif /* DEBUG_RAW */ - -#ifdef DEBUG_RAW - if (debug) { /* print raw packet */ - int i; - unsigned char *cp; - - printf("ripencc_receive: len %d\n", rbufp->recv_length); - for (i=1, cp=(char*)&rbufp->recv_space; i <= rbufp->recv_length; i++, cp++) { - printf(" %02X", *cp); - if (i%10 == 0) - printf("\n"); - } - printf("\n"); - } -#endif /* DEBUG_RAW */ - - cp = (char*) &rbufp->recv_space; - i=rbufp->recv_length; - - while (i--) { /* loop over received chars */ - - tsip_input_proc(&rpt, (unsigned char) *cp++); - - if (rpt.status != TSIP_PARSED_FULL) - continue; - - switch (rpt.code) { - - case 0x8F: /* superpacket */ - - switch (rpt.buf[0]) { - - case 0xAD: /* UTC Time */ - /* - * When polling on port B the timecode - * is the time of the previous PPS. - * If we completed receiving the packet - * less than 150ms after the turn of the second, - * it may have the code of the previous second. - * We do not trust that and simply poll again - * without even parsing it. - * - * More elegant would be to re-schedule the poll, - * but I do not know (yet) how to do that cleanly. - * - */ - /* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */ -/* if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */ - - ns_since_pps=200; - if (up->polled && ns_since_pps < 150) { - msyslog(LOG_INFO, "%s(): up->polled",__FUNCTION__); - ripencc_poll(up->unit, peer); - break; - } - - /* - * Parse primary utc time packet - * and fill refclock structure - * from results. - */ - if (parse0x8FAD(&rpt, peer) < 0) { - msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__); - refclock_report(peer, CEVNT_BADREPLY); - break; - } - /* - * If the PPSAPI is working, rather use its - * timestamps. - * assume that the PPS occurs on the second - * so blow any msec - */ - if (ripencc_get_pps_ts(up, &rd_tmp) == 1) { - pp->lastrec = up->tstamp = rd_tmp; - pp->nsec = 0; - } - else - msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__); - - - if (!up->polled) { - msyslog(LOG_INFO, "%s(): unrequested packet\n",__FUNCTION__); - /* unrequested packet */ - break; - } - - /* we have been polled ! */ - up->polled = 0; - up->pollcnt = 2; - - /* poll for next packet */ - cmd_0x8E0Bq(&spt); - ripencc_send(peer,spt); - - if (ns_since_pps < 0) { /* no PPS */ - msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__); - refclock_report(peer, CEVNT_BADTIME); - break; - } - - /* - * Process the new sample in the median filter and determine the - * reference clock offset and dispersion. - */ - if (!refclock_process(pp)) { - msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__); - refclock_report(peer, CEVNT_BADTIME); - break; - } - - refclock_receive(peer); - break; - - case 0x0B: /* comprehensive time packet */ - parse0x8F0B(&rpt, peer); - break; - - default: /* other superpackets */ -#ifdef DEBUG_NCC - msyslog(LOG_INFO, "%s(): calling parseany",__FUNCTION__); -#endif /* DEBUG_NCC */ -#ifdef TRIMBLE_OUTPUT_FUNC - parseany(&rpt, peer); -#endif /* TRIMBLE_OUTPUT_FUNC */ - break; - } - break; - - case 0x4F: /* UTC parameters, for leap info */ - parse0x4F(&rpt, peer); - break; - - case 0x5C: /* sat tracking data */ - parse0x5C(&rpt, peer); - break; - - default: /* other packets */ -#ifdef TRIMBLE_OUTPUT_FUNC - parseany(&rpt, peer); -#endif /* TRIMBLE_OUTPUT_FUNC */ - break; - } - rpt.status = TSIP_PARSED_EMPTY; - } -} - -/* - * All trimble functions that are directly referenced from driver code - * (so not from parseany) - */ - -void cmd_0x1F (TSIPPKT *cmd) -/* request software versions */ -{ - cmd->len = 0; - cmd->code = 0x1F; -} - -void cmd_0x26 (TSIPPKT *cmd) -/* request receiver health */ -{ - cmd->len = 0; - cmd->code = 0x26; -} - - - - -void cmd_0x2F (TSIPPKT *cmd) -/* request UTC params */ -{ - cmd->len = 0; - cmd->code = 0x2F; -} - -void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code, - unsigned char time_code, unsigned char opts_code) -/* set serial I/O options */ -{ - cmd->buf[0] = pos_code; - cmd->buf[1] = vel_code; - cmd->buf[2] = time_code; - cmd->buf[3] = opts_code; - cmd->len = 4; - cmd->code = 0x35; -} -void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn) -/* request tracking status */ -{ - cmd->buf[0] = sv_prn; - cmd->len = 1; - cmd->code = 0x3C; -} - - -void cmd_0x3Ds (TSIPPKT *cmd, - unsigned char baud_out, unsigned char baud_inp, - unsigned char char_code, unsigned char stopbitcode, - unsigned char output_mode, unsigned char input_mode) -/* set Channel A configuration for dual-port operation */ -{ - cmd->buf[0] = baud_out; /* XMT baud rate */ - cmd->buf[1] = baud_inp; /* RCV baud rate */ - cmd->buf[2] = char_code; /* parity and #bits per byte */ - cmd->buf[3] = stopbitcode; /* number of stop bits code */ - cmd->buf[4] = output_mode; /* Ch. A transmission mode */ - cmd->buf[5] = input_mode; /* Ch. A reception mode */ - cmd->len = 6; - cmd->code = 0x3D; -} - - -/* query primary configuration */ -void cmd_0xBBq (TSIPPKT *cmd, - unsigned char subcode) -{ - - cmd->len = 1; - cmd->code = 0xBB; - cmd->buf[0] = subcode; -} - - -/**** Superpackets ****/ -void cmd_0x8E0Bq (TSIPPKT *cmd) -/* 8E-0B to query 8F-0B controls */ -{ - - cmd->len = 1; - cmd->code = 0x8E; - cmd->buf[0] = 0x0B; -} - - -void cmd_0x8E41q (TSIPPKT *cmd) -/* 8F-41 to query board serial number */ -{ - - cmd->len = 1; - cmd->code = 0x8E; - cmd->buf[0] = 0x41; -} - - -void cmd_0x8E42q (TSIPPKT *cmd) -/* 8F-42 to query product serial number */ -{ - - cmd->len = 1; - cmd->code = 0x8E; - cmd->buf[0] = 0x42; -} -void cmd_0x8E4Aq (TSIPPKT *cmd) -/* 8F-4A to query PPS parameters */ -{ - cmd->len = 1; - cmd->code = 0x8E; - cmd->buf[0] = 0x4A; -} - - -/* set i/o options */ -void cmd_0x8E4As (TSIPPKT *cmd, - unsigned char PPSOnOff, - unsigned char TimeBase, - unsigned char Polarity, - double PPSOffset, - float Uncertainty) -{ - cmd->len = 16; - cmd->code = 0x8E; - cmd->buf[0] = 0x4A; - cmd->buf[1] = PPSOnOff; - cmd->buf[2] = TimeBase; - cmd->buf[3] = Polarity; - bPutDouble (&PPSOffset, &cmd->buf[4]); - bPutFloat (&Uncertainty, &cmd->buf[12]); -} -void cmd_0x8E4Bq (TSIPPKT *cmd) -/* 8F-4B query survey limit */ -{ - cmd->len = 1; - cmd->code = 0x8E; - cmd->buf[0] = 0x4B; -} - - -/* poll for UTC superpacket */ -void cmd_0x8EADq (TSIPPKT *cmd) -/* 8E-AD to query 8F-AD controls */ -{ - cmd->len = 1; - cmd->code = 0x8E; - cmd->buf[0] = 0xAD; -} - -/* all outomatic packet output off */ -void cmd_0x8E4Ds (TSIPPKT *cmd, - unsigned long AutoOutputMask) -{ - cmd->len = 5; - cmd->code = 0x8E; - cmd->buf[0] = 0x4D; - bPutULong (&AutoOutputMask, &cmd->buf[1]); -} - - - - -/* for DOS machines, reverse order of bytes as they come through the - * serial port. */ -#ifdef BYTESWAP -static short bGetShort (unsigned char *bp) -{ - short outval; - unsigned char *optr; - - optr = (unsigned char*)&outval + 1; - *optr-- = *bp++; - *optr = *bp; - return outval; -} - -#ifdef TRIMBLE_OUTPUT_FUNC -static unsigned short bGetUShort (unsigned char *bp) -{ - unsigned short outval; - unsigned char *optr; - - optr = (unsigned char*)&outval + 1; - *optr-- = *bp++; - *optr = *bp; - return outval; -} - -static long bGetLong (unsigned char *bp) -{ - long outval; - unsigned char *optr; - - optr = (unsigned char*)&outval + 3; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr = *bp; - return outval; -} - -static unsigned long bGetULong (unsigned char *bp) -{ - unsigned long outval; - unsigned char *optr; - - optr = (unsigned char*)&outval + 3; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr = *bp; - return outval; -} -#endif /* TRIMBLE_OUTPUT_FUNC */ - -static float bGetSingle (unsigned char *bp) -{ - float outval; - unsigned char *optr; - - optr = (unsigned char*)&outval + 3; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr = *bp; - return outval; -} - -static double bGetDouble (unsigned char *bp) -{ - double outval; - unsigned char *optr; - - optr = (unsigned char*)&outval + 7; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr-- = *bp++; - *optr = *bp; - return outval; -} - -#else /* not BYTESWAP */ - -#define bGetShort(bp) (*(short*)(bp)) -#define bGetLong(bp) (*(long*)(bp)) -#define bGetULong(bp) (*(unsigned long*)(bp)) -#define bGetSingle(bp) (*(float*)(bp)) -#define bGetDouble(bp) (*(double*)(bp)) - -#endif /* BYTESWAP */ -/* - * Byte-reversal is necessary for little-endian (Intel-based) machines. - * TSIP streams are Big-endian (Motorola-based). - */ -#ifdef BYTESWAP - -void -bPutFloat (float *in, unsigned char *out) -{ - unsigned char *inptr; - - inptr = (unsigned char*)in + 3; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out = *inptr; -} - -static void -bPutULong (unsigned long *in, unsigned char *out) -{ - unsigned char *inptr; - - inptr = (unsigned char*)in + 3; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out = *inptr; -} - -static void -bPutDouble (double *in, unsigned char *out) -{ - unsigned char *inptr; - - inptr = (unsigned char*)in + 7; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out++ = *inptr--; - *out = *inptr; -} - -#else /* not BYTESWAP */ - -void bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;} -void bPutULong (long a, unsigned char *cmdbuf) {*(long*) cmdbuf = a;} -void bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;} -void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;} - -#endif /* BYTESWAP */ - -/* - * Parse primary utc time packet - * and fill refclock structure - * from results. - * - * 0 = success - * -1 = errors - */ - -static int -parse0x8FAD(rpt, peer) - TSIPPKT *rpt; - struct peer *peer; -{ - register struct refclockproc *pp; - register struct ripencc_unit *up; - - unsigned day, month, year; /* data derived from received timecode */ - unsigned hour, minute, second; - unsigned char trackstat, utcflags; - - static char logbuf[1024]; /* logging string buffer */ - int i; - unsigned char *buf; - - buf = rpt->buf; - pp = peer->procptr; - - if (rpt->len != 22) - return (-1); - - if (bGetShort(&buf[1]) != 0) { -#ifdef DEBUG_NCC - if (debug) - printf("parse0x8FAD: event count != 0\n"); -#endif /* DEBUG_NCC */ - return(-1); - } - - - if (bGetDouble(&buf[3]) != 0.0) { -#ifdef DEBUG_NCC - if (debug) - printf("parse0x8FAD: fracsecs != 0\n"); -#endif /* DEBUG_NCC */ - return(-1); - } - - hour = (unsigned int) buf[11]; - minute = (unsigned int) buf[12]; - second = (unsigned int) buf[13]; - day = (unsigned int) buf[14]; - month = (unsigned int) buf[15]; - year = bGetShort(&buf[16]); - trackstat = buf[18]; - utcflags = buf[19]; - - - sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x", - day, month, year, hour, minute, second, trackstat, utcflags); - -#ifdef DEBUG_NCC - if (debug) - puts(logbuf); -#endif /* DEBUG_NCC */ - - record_clock_stats(&peer->srcadr, logbuf); - - if (!utcflags & UTCF_UTC_AVAIL) - return(-1); - - /* poll for UTC parameters once and then if UTC flag changed */ - up = (struct ripencc_unit *) pp->unitptr; - if (utcflags != up->utcflags) { - TSIPPKT spt; /* local structure for send packet */ - cmd_0x2F (&spt); /* request UTC params */ - ripencc_send(peer,spt); - up->utcflags = utcflags; - } - - /* - * If we hit the leap second, we choose to skip this sample - * rather than rely on other code to be perfectly correct. - * No offense, just defense ;-). - */ - if (second == 60) - return(-1); - - /* now check and convert the time we received */ - - pp->year = year; - if (month < 1 || month > 12 || day < 1 || day > 31) - return(-1); - - if (pp->year % 4) { - if (day > day1tab[month - 1]) - return(-1); - for (i = 0; i < month - 1; i++) - day += day1tab[i]; - } else { - if (day > day2tab[month - 1]) - return(-1); - for (i = 0; i < month - 1; i++) - day += day2tab[i]; - } - pp->day = day; - pp->hour = hour; - pp->minute = minute; - pp-> second = second; - pp->nsec = 0; - - if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0) - pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND); - else - pp-> leap = LEAP_NOWARNING; - - return (0); -} - -/* - * Parse comprehensive time packet - * - * 0 = success - * -1 = errors - */ - -int parse0x8F0B(rpt, peer) - TSIPPKT *rpt; - struct peer *peer; -{ - register struct refclockproc *pp; - - unsigned day, month, year; /* data derived from received timecode */ - unsigned hour, minute, second; - unsigned utcoff; - unsigned char mode; - double bias, rate; - float biasunc, rateunc; - double lat, lon, alt; - short lat_deg, lon_deg; - float lat_min, lon_min; - unsigned char north_south, east_west; - char sv[9]; - - static char logbuf[1024]; /* logging string buffer */ - unsigned char b; - int i; - unsigned char *buf; - double tow; - - buf = rpt->buf; - pp = peer->procptr; - - if (rpt->len != 74) - return (-1); - - if (bGetShort(&buf[1]) != 0) - return(-1);; - - tow = bGetDouble(&buf[3]); - - if (tow == -1.0) { - return(-1); - } - else if ((tow >= 604800.0) || (tow < 0.0)) { - return(-1); - } - else - { - if (tow < 604799.9) tow = tow + .00000001; - second = (unsigned int) fmod(tow, 60.); - minute = (unsigned int) fmod(tow/60., 60.); - hour = (unsigned int )fmod(tow / 3600., 24.); - } - - - day = (unsigned int) buf[11]; - month = (unsigned int) buf[12]; - year = bGetShort(&buf[13]); - mode = buf[15]; - utcoff = bGetShort(&buf[16]); - bias = bGetDouble(&buf[18]) / GPS_C * 1e9; /* ns */ - rate = bGetDouble(&buf[26]) / GPS_C * 1e9; /* ppb */ - biasunc = bGetSingle(&buf[34]) / GPS_C * 1e9; /* ns */ - rateunc = bGetSingle(&buf[38]) / GPS_C * 1e9; /* ppb */ - lat = bGetDouble(&buf[42]) * R2D; - lon = bGetDouble(&buf[50]) * R2D; - alt = bGetDouble(&buf[58]); - - if (lat < 0.0) { - north_south = 'S'; - lat = -lat; - } - else { - north_south = 'N'; - } - lat_deg = (short)lat; - lat_min = (lat - lat_deg) * 60.0; - - if (lon < 0.0) { - east_west = 'W'; - lon = -lon; - } - else { - east_west = 'E'; - } - - lon_deg = (short)lon; - lon_min = (lon - lon_deg) * 60.0; - - for (i=0; i<8; i++) { - sv[i] = buf[i + 66]; - if (sv[i]) { - TSIPPKT spt; /* local structure for sendpacket */ - b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]); - /* request tracking status */ - cmd_0x3C (&spt, b); - ripencc_send(peer,spt); - } - } - - - sprintf(logbuf, "C1 %02d%02d%04d %02d%02d%02d %d %7.0f %.1f %.0f %.1f %d %02d%09.6f %c %02d%09.6f %c %.0f %d %d %d %d %d %d %d %d", - day, month, year, hour, minute, second, mode, bias, biasunc, rate, rateunc, utcoff, - lat_deg, lat_min, north_south, lon_deg, lon_min, east_west, alt, - sv[0], sv[1], sv[2], sv[3], sv[4], sv[5], sv[6], sv[7]); - -#ifdef DEBUG_NCC - if (debug) - puts(logbuf); -#endif /* DEBUG_NCC */ - - record_clock_stats(&peer->srcadr, logbuf); - - return (0); -} - -#ifdef TRIMBLE_OUTPUT_FUNC -/* - * Parse any packet using Trimble machinery - */ -int parseany(rpt, peer) - TSIPPKT *rpt; - struct peer *peer; -{ - static char logbuf[1024]; /* logging string buffer */ - - TranslateTSIPReportToText (rpt, logbuf); /* anything else */ -#ifdef DEBUG_NCC - if (debug) - puts(&logbuf[1]); -#endif /* DEBUG_NCC */ - record_clock_stats(&peer->srcadr, &logbuf[1]); - return(0); -} -#endif /* TRIMBLE_OUTPUT_FUNC */ - - -/* - * Parse UTC Parameter Packet - * - * See the IDE for documentation! - * - * 0 = success - * -1 = errors - */ - -int parse0x4F(rpt, peer) - TSIPPKT *rpt; - struct peer *peer; -{ - register struct ripencc_unit *up; - - double a0; - float a1, tot; - int dt_ls, wn_t, wn_lsf, dn, dt_lsf; - - static char logbuf[1024]; /* logging string buffer */ - unsigned char *buf; - - buf = rpt->buf; - - if (rpt->len != 26) - return (-1); - a0 = bGetDouble (buf); - a1 = bGetSingle (&buf[8]); - dt_ls = bGetShort (&buf[12]); - tot = bGetSingle (&buf[14]); - wn_t = bGetShort (&buf[18]); - wn_lsf = bGetShort (&buf[20]); - dn = bGetShort (&buf[22]); - dt_lsf = bGetShort (&buf[24]); - - sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d", - dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn); - -#ifdef DEBUG_NCC - if (debug) - puts(logbuf); -#endif /* DEBUG_NCC */ - - record_clock_stats(&peer->srcadr, logbuf); - - up = (struct ripencc_unit *) peer->procptr->unitptr; - up->leapdelta = dt_lsf - dt_ls; - - return (0); -} - -/* - * Parse Tracking Status packet - * - * 0 = success - * -1 = errors - */ - -int parse0x5C(rpt, peer) - TSIPPKT *rpt; - struct peer *peer; -{ - unsigned char prn, channel, aqflag, ephstat; - float snr, azinuth, elevation; - - static char logbuf[1024]; /* logging string buffer */ - unsigned char *buf; - - buf = rpt->buf; - - if (rpt->len != 24) - return(-1); - - prn = buf[0]; - channel = (unsigned char)(buf[1] >> 3); - if (channel == 0x10) - channel = 2; - else - channel++; - aqflag = buf[2]; - ephstat = buf[3]; - snr = bGetSingle(&buf[4]); - elevation = bGetSingle(&buf[12]) * R2D; - azinuth = bGetSingle(&buf[16]) * R2D; - - sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f", - prn, channel, aqflag, ephstat, snr, azinuth, elevation); - -#ifdef DEBUG_NCC - if (debug) - puts(logbuf); -#endif /* DEBUG_NCC */ - - record_clock_stats(&peer->srcadr, logbuf); - - return (0); -} - -/******* Code below is from Trimble Tsipchat *************/ - -/* - * ************************************************************************* - * - * Trimble Navigation, Ltd. - * OEM Products Development Group - * P.O. Box 3642 - * 645 North Mary Avenue - * Sunnyvale, California 94088-3642 - * - * Corporate Headquarter: - * Telephone: (408) 481-8000 - * Fax: (408) 481-6005 - * - * Technical Support Center: - * Telephone: (800) 767-4822 (U.S. and Canada) - * (408) 481-6940 (outside U.S. and Canada) - * Fax: (408) 481-6020 - * BBS: (408) 481-7800 - * e-mail: trimble_support@trimble.com - * ftp://ftp.trimble.com/pub/sct/embedded/bin - * - * ************************************************************************* - * - * ------- BYTE-SWAPPING ------- - * TSIP is big-endian (Motorola) protocol. To use on little-endian (Intel) - * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.) - * must be reversed. This is controlled by the MACRO BYTESWAP; if defined, it - * assumes little-endian protocol. - * -------------------------------- - * - * T_PARSER.C and T_PARSER.H contains primitive functions that interpret - * reports received from the receiver. A second source file pair, - * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters. - * - * The module is in very portable, basic C language. It can be used as is, or - * with minimal changes if a TSIP communications application is needed separate - * from TSIPCHAT. The construction of most argument lists avoid the use of - * structures, but the developer is encouraged to reconstruct them using such - * definitions to meet project requirements. Declarations of T_PARSER.C - * functions are included in T_PARSER.H to provide prototyping definitions. - * - * There are two types of functions: a serial input processing routine, - * tsip_input_proc() - * which assembles incoming bytes into a TSIPPKT structure, and the - * report parsers, rpt_0x??(). - * - * 1) The function tsip_input_proc() accumulates bytes from the receiver, - * strips control bytes (DLE), and checks if the report end sequence (DLE ETX) - * has been received. rpt.status is defined as TSIP_PARSED_FULL (== 1) - * if a complete packet is available. - * - * 2) The functions rpt_0x??() are report string interpreters patterned after - * the document called "Trimble Standard Interface Protocol". It should be - * noted that if the report buffer is sent into the receiver with the wrong - * length (byte count), the rpt_0x??() returns the Boolean equivalence for - * TRUE. - * - * ************************************************************************* - * - */ - - -/**/ -static void tsip_input_proc ( - TSIPPKT *rpt, - int inbyte) -/* reads bytes until serial buffer is empty or a complete report - * has been received; end of report is signified by DLE ETX. - */ -{ - unsigned char newbyte; - - if (inbyte < 0 || inbyte > 0xFF) return; - - newbyte = (unsigned char)(inbyte); - switch (rpt->status) - { - case TSIP_PARSED_DLE_1: - switch (newbyte) - { - case 0: - case ETX: - /* illegal TSIP IDs */ - rpt->len = 0; - rpt->status = TSIP_PARSED_EMPTY; - break; - case DLE: - /* try normal message start again */ - rpt->len = 0; - rpt->status = TSIP_PARSED_DLE_1; - break; - default: - /* legal TSIP ID; start message */ - rpt->code = newbyte; - rpt->len = 0; - rpt->status = TSIP_PARSED_DATA; - break; - } - break; - case TSIP_PARSED_DATA: - switch (newbyte) { - case DLE: - /* expect DLE or ETX next */ - rpt->status = TSIP_PARSED_DLE_2; - break; - default: - /* normal data byte */ - rpt->buf[rpt->len] = newbyte; - rpt->len++; - /* no change in rpt->status */ - break; - } - break; - case TSIP_PARSED_DLE_2: - switch (newbyte) { - case DLE: - /* normal data byte */ - rpt->buf[rpt->len] = newbyte; - rpt->len++; - rpt->status = TSIP_PARSED_DATA; - break; - case ETX: - /* end of message; return TRUE here. */ - rpt->status = TSIP_PARSED_FULL; - break; - default: - /* error: treat as TSIP_PARSED_DLE_1; start new report packet */ - rpt->code = newbyte; - rpt->len = 0; - rpt->status = TSIP_PARSED_DATA; - } - break; - case TSIP_PARSED_FULL: - case TSIP_PARSED_EMPTY: - default: - switch (newbyte) { - case DLE: - /* normal message start */ - rpt->len = 0; - rpt->status = TSIP_PARSED_DLE_1; - break; - default: - /* error: ignore newbyte */ - rpt->len = 0; - rpt->status = TSIP_PARSED_EMPTY; - } - break; - } - if (rpt->len > MAX_RPTBUF) { - /* error: start new report packet */ - rpt->status = TSIP_PARSED_EMPTY; - rpt->len = 0; - } -} - -#ifdef TRIMBLE_OUTPUT_FUNC - -/**/ -short rpt_0x3D (TSIPPKT *rpt, - unsigned char *tx_baud_index, - unsigned char *rx_baud_index, - unsigned char *char_format_index, - unsigned char *stop_bits, - unsigned char *tx_mode_index, - unsigned char *rx_mode_index) -/* Channel A configuration for dual port operation */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 6) return TRUE; - *tx_baud_index = buf[0]; - *rx_baud_index = buf[1]; - *char_format_index = buf[2]; - *stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2); - *tx_mode_index = buf[4]; - *rx_mode_index = buf[5]; - return FALSE; -} - -/**/ -short rpt_0x40 (TSIPPKT *rpt, - unsigned char *sv_prn, - short *week_num, - float *t_zc, - float *eccentricity, - float *t_oa, - float *i_0, - float *OMEGA_dot, - float *sqrt_A, - float *OMEGA_0, - float *omega, - float *M_0) -/* almanac data for specified satellite */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 39) return TRUE; - *sv_prn = buf[0]; - *t_zc = bGetSingle (&buf[1]); - *week_num = bGetShort (&buf[5]); - *eccentricity = bGetSingle (&buf[7]); - *t_oa = bGetSingle (&buf[11]); - *i_0 = bGetSingle (&buf[15]); - *OMEGA_dot = bGetSingle (&buf[19]); - *sqrt_A = bGetSingle (&buf[23]); - *OMEGA_0 = bGetSingle (&buf[27]); - *omega = bGetSingle (&buf[31]); - *M_0 = bGetSingle (&buf[35]); - return FALSE; -} - -short rpt_0x41 (TSIPPKT *rpt, - float *time_of_week, - float *UTC_offset, - short *week_num) -/* GPS time */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 10) return TRUE; - *time_of_week = bGetSingle (buf); - *week_num = bGetShort (&buf[4]); - *UTC_offset = bGetSingle (&buf[6]); - return FALSE; -} - -short rpt_0x42 (TSIPPKT *rpt, - float pos_ECEF[3], - float *time_of_fix) -/* position in ECEF, single precision */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 16) return TRUE; - pos_ECEF[0] = bGetSingle (buf); - pos_ECEF[1]= bGetSingle (&buf[4]); - pos_ECEF[2]= bGetSingle (&buf[8]); - *time_of_fix = bGetSingle (&buf[12]); - return FALSE; -} - -short rpt_0x43 (TSIPPKT *rpt, - float ECEF_vel[3], - float *freq_offset, - float *time_of_fix) -/* velocity in ECEF, single precision */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 20) return TRUE; - ECEF_vel[0] = bGetSingle (buf); - ECEF_vel[1] = bGetSingle (&buf[4]); - ECEF_vel[2] = bGetSingle (&buf[8]); - *freq_offset = bGetSingle (&buf[12]); - *time_of_fix = bGetSingle (&buf[16]); - return FALSE; -} - -short rpt_0x45 (TSIPPKT *rpt, - unsigned char *major_nav_version, - unsigned char *minor_nav_version, - unsigned char *nav_day, - unsigned char *nav_month, - unsigned char *nav_year, - unsigned char *major_dsp_version, - unsigned char *minor_dsp_version, - unsigned char *dsp_day, - unsigned char *dsp_month, - unsigned char *dsp_year) -/* software versions */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 10) return TRUE; - *major_nav_version = buf[0]; - *minor_nav_version = buf[1]; - *nav_day = buf[2]; - *nav_month = buf[3]; - *nav_year = buf[4]; - *major_dsp_version = buf[5]; - *minor_dsp_version = buf[6]; - *dsp_day = buf[7]; - *dsp_month = buf[8]; - *dsp_year = buf[9]; - return FALSE; -} - -short rpt_0x46 (TSIPPKT *rpt, - unsigned char *status1, - unsigned char *status2) -/* receiver health and status */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 2) return TRUE; - *status1 = buf[0]; - *status2 = buf[1]; - return FALSE; -} - -short rpt_0x47 (TSIPPKT *rpt, - unsigned char *nsvs, unsigned char *sv_prn, - float *snr) -/* signal levels for all satellites tracked */ -{ - short isv; - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 1 + 5*buf[0]) return TRUE; - *nsvs = buf[0]; - for (isv = 0; isv < (*nsvs); isv++) { - sv_prn[isv] = buf[5*isv + 1]; - snr[isv] = bGetSingle (&buf[5*isv + 2]); - } - return FALSE; -} - -short rpt_0x48 (TSIPPKT *rpt, - unsigned char *message) -/* GPS system message */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 22) return TRUE; - memcpy (message, buf, 22); - message[22] = 0; - return FALSE; -} - -short rpt_0x49 (TSIPPKT *rpt, - unsigned char *sv_health) -/* health for all satellites from almanac health page */ -{ - short i; - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 32) return TRUE; - for (i = 0; i < 32; i++) sv_health [i]= buf[i]; - return FALSE; -} - -short rpt_0x4A (TSIPPKT *rpt, - float *lat, - float *lon, - float *alt, - float *clock_bias, - float *time_of_fix) -/* position in lat-lon-alt, single precision */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 20) return TRUE; - *lat = bGetSingle (buf); - *lon = bGetSingle (&buf[4]); - *alt = bGetSingle (&buf[8]); - *clock_bias = bGetSingle (&buf[12]); - *time_of_fix = bGetSingle (&buf[16]); - return FALSE; -} - -short rpt_0x4A_2 (TSIPPKT *rpt, - float *alt, float *dummy , unsigned char *alt_flag) -/* reference altitude parameters */ -{ - unsigned char *buf; - - buf = rpt->buf; - - if (rpt->len != 9) return TRUE; - *alt = bGetSingle (buf); - *dummy = bGetSingle (&buf[4]); - *alt_flag = buf[8]; - return FALSE; -} - -short rpt_0x4B (TSIPPKT *rpt, - unsigned char *machine_id, - unsigned char *status3, - unsigned char *status4) -/* machine ID code, status */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 3) return TRUE; - *machine_id = buf[0]; - *status3 = buf[1]; - *status4 = buf[2]; - return FALSE; -} - -short rpt_0x4C (TSIPPKT *rpt, - unsigned char *dyn_code, - float *el_mask, - float *snr_mask, - float *dop_mask, - float *dop_switch) -/* operating parameters and masks */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 17) return TRUE; - *dyn_code = buf[0]; - *el_mask = bGetSingle (&buf[1]); - *snr_mask = bGetSingle (&buf[5]); - *dop_mask = bGetSingle (&buf[9]); - *dop_switch = bGetSingle (&buf[13]); - return FALSE; -} - -short rpt_0x4D (TSIPPKT *rpt, - float *osc_offset) -/* oscillator offset */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 4) return TRUE; - *osc_offset = bGetSingle (buf); - return FALSE; -} - -short rpt_0x4E (TSIPPKT *rpt, - unsigned char *response) -/* yes/no response to command to set GPS time */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 1) return TRUE; - *response = buf[0]; - return FALSE; -} - -short rpt_0x4F (TSIPPKT *rpt, - double *a0, - float *a1, - float *time_of_data, - short *dt_ls, - short *wn_t, - short *wn_lsf, - short *dn, - short *dt_lsf) -/* UTC data */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 26) return TRUE; - *a0 = bGetDouble (buf); - *a1 = bGetSingle (&buf[8]); - *dt_ls = bGetShort (&buf[12]); - *time_of_data = bGetSingle (&buf[14]); - *wn_t = bGetShort (&buf[18]); - *wn_lsf = bGetShort (&buf[20]); - *dn = bGetShort (&buf[22]); - *dt_lsf = bGetShort (&buf[24]); - return FALSE; -} - -/**/ -short rpt_0x54 (TSIPPKT *rpt, - float *clock_bias, - float *freq_offset, - float *time_of_fix) -/* clock offset and frequency offset in 1-SV (0-D) mode */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 12) return TRUE; - *clock_bias = bGetSingle (buf); - *freq_offset = bGetSingle (&buf[4]); - *time_of_fix = bGetSingle (&buf[8]); - return FALSE; -} - -short rpt_0x55 (TSIPPKT *rpt, - unsigned char *pos_code, - unsigned char *vel_code, - unsigned char *time_code, - unsigned char *aux_code) -/* I/O serial options */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 4) return TRUE; - *pos_code = buf[0]; - *vel_code = buf[1]; - *time_code = buf[2]; - *aux_code = buf[3]; - return FALSE; -} - -short rpt_0x56 (TSIPPKT *rpt, - float vel_ENU[3], float *freq_offset, float *time_of_fix) -/* velocity in east-north-up coordinates */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 20) return TRUE; - /* east */ - vel_ENU[0] = bGetSingle (buf); - /* north */ - vel_ENU[1] = bGetSingle (&buf[4]); - /* up */ - vel_ENU[2] = bGetSingle (&buf[8]); - *freq_offset = bGetSingle (&buf[12]); - *time_of_fix = bGetSingle (&buf[16]); - return FALSE; -} - -short rpt_0x57 (TSIPPKT *rpt, - unsigned char *source_code, unsigned char *diag_code, - short *week_num, - float *time_of_fix) -/* info about last computed fix */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 8) return TRUE; - *source_code = buf[0]; - *diag_code = buf[1]; - *time_of_fix = bGetSingle (&buf[2]); - *week_num = bGetShort (&buf[6]); - return FALSE; -} - -short rpt_0x58 (TSIPPKT *rpt, - unsigned char *op_code, unsigned char *data_type, unsigned char *sv_prn, - unsigned char *data_length, unsigned char *data_packet) -/* GPS system data or acknowledgment of GPS system data load */ -{ - unsigned char *buf, *buf4; - short dl; - ALM_INFO* alminfo; - ION_INFO* ioninfo; - UTC_INFO* utcinfo; - NAV_INFO* navinfo; - - buf = rpt->buf; - - if (buf[0] == 2) { - if (rpt->len < 4) return TRUE; - if (rpt->len != 4+buf[3]) return TRUE; - } - else if (rpt->len != 3) { - return TRUE; - } - *op_code = buf[0]; - *data_type = buf[1]; - *sv_prn = buf[2]; - if (*op_code == 2) { - dl = buf[3]; - *data_length = (unsigned char)dl; - buf4 = &buf[4]; - switch (*data_type) { - case 2: - /* Almanac */ - if (*data_length != sizeof (ALM_INFO)) return TRUE; - alminfo = (ALM_INFO*)data_packet; - alminfo->t_oa_raw = buf4[0]; - alminfo->SV_health = buf4[1]; - alminfo->e = bGetSingle(&buf4[2]); - alminfo->t_oa = bGetSingle(&buf4[6]); - alminfo->i_0 = bGetSingle(&buf4[10]); - alminfo->OMEGADOT = bGetSingle(&buf4[14]); - alminfo->sqrt_A = bGetSingle(&buf4[18]); - alminfo->OMEGA_0 = bGetSingle(&buf4[22]); - alminfo->omega = bGetSingle(&buf4[26]); - alminfo->M_0 = bGetSingle(&buf4[30]); - alminfo->a_f0 = bGetSingle(&buf4[34]); - alminfo->a_f1 = bGetSingle(&buf4[38]); - alminfo->Axis = bGetSingle(&buf4[42]); - alminfo->n = bGetSingle(&buf4[46]); - alminfo->OMEGA_n = bGetSingle(&buf4[50]); - alminfo->ODOT_n = bGetSingle(&buf4[54]); - alminfo->t_zc = bGetSingle(&buf4[58]); - alminfo->weeknum = bGetShort(&buf4[62]); - alminfo->wn_oa = bGetShort(&buf4[64]); - break; - - case 3: - /* Almanac health page */ - if (*data_length != sizeof (ALH_PARMS) + 3) return TRUE; - - /* this record is returned raw */ - memcpy (data_packet, buf4, dl); - break; - - case 4: - /* Ionosphere */ - if (*data_length != sizeof (ION_INFO) + 8) return TRUE; - ioninfo = (ION_INFO*)data_packet; - ioninfo->alpha_0 = bGetSingle (&buf4[8]); - ioninfo->alpha_1 = bGetSingle (&buf4[12]); - ioninfo->alpha_2 = bGetSingle (&buf4[16]); - ioninfo->alpha_3 = bGetSingle (&buf4[20]); - ioninfo->beta_0 = bGetSingle (&buf4[24]); - ioninfo->beta_1 = bGetSingle (&buf4[28]); - ioninfo->beta_2 = bGetSingle (&buf4[32]); - ioninfo->beta_3 = bGetSingle (&buf4[36]); - break; - - case 5: - /* UTC */ - if (*data_length != sizeof (UTC_INFO) + 13) return TRUE; - utcinfo = (UTC_INFO*)data_packet; - utcinfo->A_0 = bGetDouble (&buf4[13]); - utcinfo->A_1 = bGetSingle (&buf4[21]); - utcinfo->delta_t_LS = bGetShort (&buf4[25]); - utcinfo->t_ot = bGetSingle(&buf4[27]); - utcinfo->WN_t = bGetShort (&buf4[31]); - utcinfo->WN_LSF = bGetShort (&buf4[33]); - utcinfo->DN = bGetShort (&buf4[35]); - utcinfo->delta_t_LSF = bGetShort (&buf4[37]); - break; - - case 6: - /* Ephemeris */ - if (*data_length != sizeof (NAV_INFO) - 1) return TRUE; - - navinfo = (NAV_INFO*)data_packet; - - navinfo->sv_number = buf4[0]; - navinfo->t_ephem = bGetSingle (&buf4[1]); - navinfo->ephclk.weeknum = bGetShort (&buf4[5]); - - navinfo->ephclk.codeL2 = buf4[7]; - navinfo->ephclk.L2Pdata = buf4[8]; - navinfo->ephclk.SVacc_raw = buf4[9]; - navinfo->ephclk.SV_health = buf4[10]; - navinfo->ephclk.IODC = bGetShort (&buf4[11]); - navinfo->ephclk.T_GD = bGetSingle (&buf4[13]); - navinfo->ephclk.t_oc = bGetSingle (&buf4[17]); - navinfo->ephclk.a_f2 = bGetSingle (&buf4[21]); - navinfo->ephclk.a_f1 = bGetSingle (&buf4[25]); - navinfo->ephclk.a_f0 = bGetSingle (&buf4[29]); - navinfo->ephclk.SVacc = bGetSingle (&buf4[33]); - - navinfo->ephorb.IODE = buf4[37]; - navinfo->ephorb.fit_interval = buf4[38]; - navinfo->ephorb.C_rs = bGetSingle (&buf4[39]); - navinfo->ephorb.delta_n = bGetSingle (&buf4[43]); - navinfo->ephorb.M_0 = bGetDouble (&buf4[47]); - navinfo->ephorb.C_uc = bGetSingle (&buf4[55]); - navinfo->ephorb.e = bGetDouble (&buf4[59]); - navinfo->ephorb.C_us = bGetSingle (&buf4[67]); - navinfo->ephorb.sqrt_A = bGetDouble (&buf4[71]); - navinfo->ephorb.t_oe = bGetSingle (&buf4[79]); - navinfo->ephorb.C_ic = bGetSingle (&buf4[83]); - navinfo->ephorb.OMEGA_0 = bGetDouble (&buf4[87]); - navinfo->ephorb.C_is = bGetSingle (&buf4[95]); - navinfo->ephorb.i_0 = bGetDouble (&buf4[99]); - navinfo->ephorb.C_rc = bGetSingle (&buf4[107]); - navinfo->ephorb.omega = bGetDouble (&buf4[111]); - navinfo->ephorb.OMEGADOT=bGetSingle (&buf4[119]); - navinfo->ephorb.IDOT = bGetSingle (&buf4[123]); - navinfo->ephorb.Axis = bGetDouble (&buf4[127]); - navinfo->ephorb.n = bGetDouble (&buf4[135]); - navinfo->ephorb.r1me2 = bGetDouble (&buf4[143]); - navinfo->ephorb.OMEGA_n=bGetDouble (&buf4[151]); - navinfo->ephorb.ODOT_n = bGetDouble (&buf4[159]); - break; - } - } - return FALSE; -} - -short rpt_0x59 (TSIPPKT *rpt, - unsigned char *code_type, - unsigned char status_code[32]) -/* satellite enable/disable or health heed/ignore list */ -{ - short iprn; - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 33) return TRUE; - *code_type = buf[0]; - for (iprn = 0; iprn < 32; iprn++) - status_code[iprn] = buf[iprn + 1]; - return FALSE; -} - -short rpt_0x5A (TSIPPKT *rpt, - unsigned char *sv_prn, - float *sample_length, - float *signal_level, - float *code_phase, - float *Doppler, - double *time_of_fix) -/* raw measurement data - code phase/Doppler */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 25) return TRUE; - *sv_prn = buf[0]; - *sample_length = bGetSingle (&buf[1]); - *signal_level = bGetSingle (&buf[5]); - *code_phase = bGetSingle (&buf[9]); - *Doppler = bGetSingle (&buf[13]); - *time_of_fix = bGetDouble (&buf[17]); - return FALSE; -} - -short rpt_0x5B (TSIPPKT *rpt, - unsigned char *sv_prn, - unsigned char *sv_health, - unsigned char *sv_iode, - unsigned char *fit_interval_flag, - float *time_of_collection, - float *time_of_eph, - float *sv_accy) -/* satellite ephorb status */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 16) return TRUE; - *sv_prn = buf[0]; - *time_of_collection = bGetSingle (&buf[1]); - *sv_health = buf[5]; - *sv_iode = buf[6]; - *time_of_eph = bGetSingle (&buf[7]); - *fit_interval_flag = buf[11]; - *sv_accy = bGetSingle (&buf[12]); - return FALSE; -} - -short rpt_0x5C (TSIPPKT *rpt, - unsigned char *sv_prn, - unsigned char *slot, - unsigned char *chan, - unsigned char *acq_flag, - unsigned char *eph_flag, - float *signal_level, - float *time_of_last_msmt, - float *elev, - float *azim, - unsigned char *old_msmt_flag, - unsigned char *integer_msec_flag, - unsigned char *bad_data_flag, - unsigned char *data_collect_flag) -/* satellite tracking status */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 24) return TRUE; - *sv_prn = buf[0]; - *slot = (unsigned char)((buf[1] & 0x07) + 1); - *chan = (unsigned char)(buf[1] >> 3); - if (*chan == 0x10) *chan = 2; - else (*chan)++; - *acq_flag = buf[2]; - *eph_flag = buf[3]; - *signal_level = bGetSingle (&buf[4]); - *time_of_last_msmt = bGetSingle (&buf[8]); - *elev = bGetSingle (&buf[12]); - *azim = bGetSingle (&buf[16]); - *old_msmt_flag = buf[20]; - *integer_msec_flag = buf[21]; - *bad_data_flag = buf[22]; - *data_collect_flag = buf[23]; - return FALSE; -} - -/**/ -short rpt_0x6D (TSIPPKT *rpt, - unsigned char *manual_mode, - unsigned char *nsvs, - unsigned char *ndim, - unsigned char sv_prn[], - float *pdop, - float *hdop, - float *vdop, - float *tdop) -/* over-determined satellite selection for position fixes, PDOP, fix mode */ -{ - short islot; - unsigned char *buf; - buf = rpt->buf; - - *nsvs = (unsigned char)((buf[0] & 0xF0) >> 4); - if ((*nsvs)>8) return TRUE; - if (rpt->len != 17 + (*nsvs) ) return TRUE; - - *manual_mode = (unsigned char)(buf[0] & 0x08); - *ndim = (unsigned char)((buf[0] & 0x07)); - *pdop = bGetSingle (&buf[1]); - *hdop = bGetSingle (&buf[5]); - *vdop = bGetSingle (&buf[9]); - *tdop = bGetSingle (&buf[13]); - for (islot = 0; islot < (*nsvs); islot++) - sv_prn[islot] = buf[islot + 17]; - return FALSE; -} - -/**/ -short rpt_0x82 (TSIPPKT *rpt, - unsigned char *diff_mode) -/* differential fix mode */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 1) return TRUE; - *diff_mode = buf[0]; - return FALSE; -} - -short rpt_0x83 (TSIPPKT *rpt, - double ECEF_pos[3], - double *clock_bias, - float *time_of_fix) -/* position, ECEF double precision */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 36) return TRUE; - ECEF_pos[0] = bGetDouble (buf); - ECEF_pos[1] = bGetDouble (&buf[8]); - ECEF_pos[2] = bGetDouble (&buf[16]); - *clock_bias = bGetDouble (&buf[24]); - *time_of_fix = bGetSingle (&buf[32]); - return FALSE; -} - -short rpt_0x84 (TSIPPKT *rpt, - double *lat, - double *lon, - double *alt, - double *clock_bias, - float *time_of_fix) -/* position, lat-lon-alt double precision */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 36) return TRUE; - *lat = bGetDouble (buf); - *lon = bGetDouble (&buf[8]); - *alt = bGetDouble (&buf[16]); - *clock_bias = bGetDouble (&buf[24]); - *time_of_fix = bGetSingle (&buf[32]); - return FALSE; -} - -short rpt_Paly0xBB(TSIPPKT *rpt, - TSIP_RCVR_CFG *TsipxBB) -{ - - unsigned char *buf; - buf = rpt->buf; - - /* Palisade is inconsistent with other TSIP, which has a kength of 40 */ - /* if (rpt->len != 40) return TRUE; */ - if (rpt->len != 43) return TRUE; - - TsipxBB->bSubcode = buf[0]; - TsipxBB->operating_mode = buf[1] ; - TsipxBB->dyn_code = buf[3] ; - TsipxBB->elev_mask = bGetSingle (&buf[5]); - TsipxBB->cno_mask = bGetSingle (&buf[9]); - TsipxBB->dop_mask = bGetSingle (&buf[13]); - TsipxBB->dop_switch = bGetSingle (&buf[17]); - return FALSE; -} - -short rpt_0xBC (TSIPPKT *rpt, - unsigned char *port_num, - unsigned char *in_baud, - unsigned char *out_baud, - unsigned char *data_bits, - unsigned char *parity, - unsigned char *stop_bits, - unsigned char *flow_control, - unsigned char *protocols_in, - unsigned char *protocols_out, - unsigned char *reserved) -/* Receiver serial port configuration */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 10) return TRUE; - *port_num = buf[0]; - *in_baud = buf[1]; - *out_baud = buf[2]; - *data_bits = buf[3]; - *parity = buf[4]; - *stop_bits = buf[5]; - *flow_control = buf[6]; - *protocols_in = buf[7]; - *protocols_out = buf[8]; - *reserved = buf[9]; - - return FALSE; -} - -/**** Superpackets ****/ - -short rpt_0x8F0B(TSIPPKT *rpt, - unsigned short *event, - double *tow, - unsigned char *date, - unsigned char *month, - short *year, - unsigned char *dim_mode, - short *utc_offset, - double *bias, - double *drift, - float *bias_unc, - float *dr_unc, - double *lat, - double *lon, - double *alt, - char sv_id[8]) -{ - short local_index; - unsigned char *buf; - - buf = rpt->buf; - if (rpt->len != 74) return TRUE; - *event = bGetShort(&buf[1]); - *tow = bGetDouble(&buf[3]); - *date = buf[11]; - *month = buf[12]; - *year = bGetShort(&buf[13]); - *dim_mode = buf[15]; - *utc_offset = bGetShort(&buf[16]); - *bias = bGetDouble(&buf[18]); - *drift = bGetDouble(&buf[26]); - *bias_unc = bGetSingle(&buf[34]); - *dr_unc = bGetSingle(&buf[38]); - *lat = bGetDouble(&buf[42]); - *lon = bGetDouble(&buf[50]); - *alt = bGetDouble(&buf[58]); - - for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66]; - return FALSE; -} - -short rpt_0x8F14 (TSIPPKT *rpt, - short *datum_idx, - double datum_coeffs[5]) -/* datum index and coefficients */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 43) return TRUE; - *datum_idx = bGetShort(&buf[1]); - datum_coeffs[0] = bGetDouble (&buf[3]); - datum_coeffs[1] = bGetDouble (&buf[11]); - datum_coeffs[2] = bGetDouble (&buf[19]); - datum_coeffs[3] = bGetDouble (&buf[27]); - datum_coeffs[4] = bGetDouble (&buf[35]); - return FALSE; -} - - -short rpt_0x8F15 (TSIPPKT *rpt, - short *datum_idx, - double datum_coeffs[5]) -/* datum index and coefficients */ -{ - unsigned char *buf; - buf = rpt->buf; - - if (rpt->len != 43) return TRUE; - *datum_idx = bGetShort(&buf[1]); - datum_coeffs[0] = bGetDouble (&buf[3]); - datum_coeffs[1] = bGetDouble (&buf[11]); - datum_coeffs[2] = bGetDouble (&buf[19]); - datum_coeffs[3] = bGetDouble (&buf[27]); - datum_coeffs[4] = bGetDouble (&buf[35]); - return FALSE; -} - - -#define MAX_LONG (2147483648.) /* 2**31 */ - -short rpt_0x8F20 (TSIPPKT *rpt, - unsigned char *info, - double *lat, - double *lon, - double *alt, - double vel_enu[], - double *time_of_fix, - short *week_num, - unsigned char *nsvs, - unsigned char sv_prn[], - short sv_IODC[], - short *datum_index) -{ - short - isv; - unsigned char - *buf, prnx, iode; - unsigned long - ulongtemp; - long - longtemp; - double - vel_scale; - - buf = rpt->buf; - - if (rpt->len != 56) return TRUE; - - vel_scale = (buf[24]&1)? 0.020 : 0.005; - vel_enu[0] = bGetShort (buf+2)*vel_scale; - vel_enu[1] = bGetShort (buf+4)*vel_scale; - vel_enu[2] = bGetShort (buf+6)*vel_scale; - - *time_of_fix = bGetULong (buf+8)*.001; - - longtemp = bGetLong (buf+12); - *lat = longtemp*(GPS_PI/MAX_LONG); - - ulongtemp = bGetULong (buf+16); - *lon = ulongtemp*(GPS_PI/MAX_LONG); - if (*lon > GPS_PI) *lon -= 2.0*GPS_PI; - - *alt = bGetLong (buf+20)*.001; - /* 25 blank; 29 = UTC */ - (*datum_index) = (short)((short)buf[26]-1); - *info = buf[27]; - *nsvs = buf[28]; - *week_num = bGetShort (&buf[30]); - for (isv = 0; isv < 8; isv++) { - prnx = buf[32+2*isv]; - sv_prn[isv] = (unsigned char)(prnx&0x3F); - iode = buf[33+2*isv]; - sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8)); - } - return FALSE; -} - -short rpt_0x8F41 (TSIPPKT *rpt, - unsigned char *bSearchRange, - unsigned char *bBoardOptions, - unsigned long *iiSerialNumber, - unsigned char *bBuildYear, - unsigned char *bBuildMonth, - unsigned char *bBuildDay, - unsigned char *bBuildHour, - float *fOscOffset, - unsigned short *iTestCodeId) -{ - if(rpt->len != 17) return FALSE; - *bSearchRange = rpt->buf[1]; - *bBoardOptions = rpt->buf[2]; - *iiSerialNumber = bGetLong(&rpt->buf[3]); - *bBuildYear = rpt->buf[7]; - *bBuildMonth = rpt->buf[8]; - *bBuildDay = rpt->buf[9]; - *bBuildHour = rpt->buf[10]; - *fOscOffset = bGetSingle(&rpt->buf[11]); - *iTestCodeId = bGetShort(&rpt->buf[15]); -/* Tsipx8E41Data = *Tsipx8E41; */ - return TRUE; -} - -short rpt_0x8F42 (TSIPPKT *rpt, - unsigned char *bProdOptionsPre, - unsigned char *bProdNumberExt, - unsigned short *iCaseSerialNumberPre, - unsigned long *iiCaseSerialNumber, - unsigned long *iiProdNumber, - unsigned short *iPremiumOptions, - unsigned short *iMachineID, - unsigned short *iKey) -{ - if(rpt->len != 19) return FALSE; - *bProdOptionsPre = rpt->buf[1]; - *bProdNumberExt = rpt->buf[2]; - *iCaseSerialNumberPre = bGetShort(&rpt->buf[3]); - *iiCaseSerialNumber = bGetLong(&rpt->buf[5]); - *iiProdNumber = bGetLong(&rpt->buf[9]); - *iPremiumOptions = bGetShort(&rpt->buf[13]); - *iMachineID = bGetShort(&rpt->buf[15]); - *iKey = bGetShort(&rpt->buf[17]); - return TRUE; -} - -short rpt_0x8F45(TSIPPKT *rpt, - unsigned char *bSegMask) -{ - if(rpt->len != 2) return FALSE; - *bSegMask = rpt->buf[1]; - return TRUE; -} - -short rpt_0x8F4A_16(TSIPPKT *rpt, - unsigned char *pps_enabled, - unsigned char *pps_timebase, - unsigned char *pos_polarity, - double *pps_offset, - float *bias_unc_threshold) -/* Stinger PPS definition */ -{ - unsigned char - *buf; - - buf = rpt->buf; - if (rpt->len != 16) return TRUE; - *pps_enabled = buf[1]; - *pps_timebase = buf[2]; - *pos_polarity = buf[3]; - *pps_offset = bGetDouble(&buf[4]); - *bias_unc_threshold = bGetSingle(&buf[12]); - return FALSE; -} - -short rpt_0x8F4B(TSIPPKT *rpt, - unsigned long *decorr_max) -{ - unsigned char - *buf; - - buf = rpt->buf; - if (rpt->len != 5) return TRUE; - *decorr_max = bGetLong(&buf[1]); - return FALSE; -} - -short rpt_0x8F4D(TSIPPKT *rpt, - unsigned long *event_mask) -{ - unsigned char - *buf; - - buf = rpt->buf; - if (rpt->len != 5) return TRUE; - *event_mask = bGetULong (&buf[1]); - return FALSE; -} - -short rpt_0x8FA5(TSIPPKT *rpt, - unsigned char *spktmask) -{ - unsigned char - *buf; - - buf = rpt->buf; - if (rpt->len != 5) return TRUE; - spktmask[0] = buf[1]; - spktmask[1] = buf[2]; - spktmask[2] = buf[3]; - spktmask[3] = buf[4]; - return FALSE; -} - -short rpt_0x8FAD (TSIPPKT *rpt, - unsigned short *COUNT, - double *FracSec, - unsigned char *Hour, - unsigned char *Minute, - unsigned char *Second, - unsigned char *Day, - unsigned char *Month, - unsigned short *Year, - unsigned char *Status, - unsigned char *Flags) -{ - - if (rpt->len != 22) return TRUE; - - *COUNT = bGetUShort(&rpt->buf[1]); - *FracSec = bGetDouble(&rpt->buf[3]); - *Hour = rpt->buf[11]; - *Minute = rpt->buf[12]; - *Second = rpt->buf[13]; - *Day = rpt->buf[14]; - *Month = rpt->buf[15]; - *Year = bGetUShort(&rpt->buf[16]); - *Status = rpt->buf[18]; - *Flags = rpt->buf[19]; - return FALSE; -} - - -/* - * ************************************************************************* - * - * Trimble Navigation, Ltd. - * OEM Products Development Group - * P.O. Box 3642 - * 645 North Mary Avenue - * Sunnyvale, California 94088-3642 - * - * Corporate Headquarter: - * Telephone: (408) 481-8000 - * Fax: (408) 481-6005 - * - * Technical Support Center: - * Telephone: (800) 767-4822 (U.S. and Canada) - * (408) 481-6940 (outside U.S. and Canada) - * Fax: (408) 481-6020 - * BBS: (408) 481-7800 - * e-mail: trimble_support@trimble.com - * ftp://ftp.trimble.com/pub/sct/embedded/bin - * - * ************************************************************************* - * - * T_REPORT.C consists of a primary function TranslateTSIPReportToText() - * called by main(). - * - * This function takes a character buffer that has been received as a report - * from a TSIP device and interprets it. The character buffer has been - * assembled using tsip_input_proc() in T_PARSER.C. - * - * A large case statement directs processing to one of many mid-level - * functions. The mid-level functions specific to the current report - * code passes the report buffer to the appropriate report decoder - * rpt_0x?? () in T_PARSER.C, which converts the byte stream in rpt.buf - * to data values approporaite for use. - * - * ************************************************************************* - * - */ - - -#define GOOD_PARSE 0 -#define BADID_PARSE 1 -#define BADLEN_PARSE 2 -#define BADDATA_PARSE 3 - -#define B_TSIP 0x02 -#define B_NMEA 0x04 - - -/* pbuf is the pointer to the current location of the text output */ -static char - *pbuf; - -/* keep track of whether the message has been successfully parsed */ -static short - parsed; - - -/* convert time of week into day-hour-minute-second and print */ -char* show_time (float time_of_week) -{ - short days, hours, minutes; - float seconds; - double tow = 0; - static char timestring [80]; - - if (time_of_week == -1.0) - { - sprintf(timestring, " <No time yet> "); - } - else if ((time_of_week >= 604800.0) || (time_of_week < 0.0)) - { - sprintf(timestring, " <Bad time> "); - } - else - { - if (time_of_week < 604799.9) - tow = time_of_week + .00000001; - seconds = (float)fmod(tow, 60.); - minutes = (short) fmod(tow/60., 60.); - hours = (short)fmod(tow / 3600., 24.); - days = (short)(tow / 86400.0); - sprintf(timestring, " %s %02d:%02d:%05.2f ", - dayname[days], hours, minutes, seconds); - } - return timestring; -} - -/**/ -/* 0x3D */ -static void rpt_chan_A_config (TSIPPKT *rpt) -{ - unsigned char - tx_baud_index, rx_baud_index, - char_format_index, stop_bits, - tx_mode_index, rx_mode_index, - databits, parity; - int - i, nbaud; - - /* unload rptbuf */ - if (rpt_0x3D (rpt, - &tx_baud_index, &rx_baud_index, &char_format_index, - &stop_bits, &tx_mode_index, &rx_mode_index)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nChannel A Configuration"); - - nbaud = sizeof(old_baudnum); - - for (i = 0; i < nbaud; ++i) if (tx_baud_index == old_baudnum[i]) break; - pbuf += sprintf(pbuf, "\n Transmit speed: %s at %s", - old_output_ch[tx_mode_index], st_baud_text_app[i]); - - for (i = 0; i < nbaud; ++i) if (rx_baud_index == old_baudnum[i]) break; - pbuf += sprintf(pbuf, "\n Receive speed: %s at %s", - old_input_ch[rx_mode_index], st_baud_text_app[i]); - - databits = (unsigned char)((char_format_index & 0x03) + 5); - - parity = (unsigned char)(char_format_index >> 2); - if (parity > 4) parity = 2; - - pbuf += sprintf(pbuf, "\n Character format (bits/char, parity, stop bits): %d-%s-%d", - databits, old_parity_text[parity], stop_bits); -} - -/**/ -/* 0x40 */ -static void rpt_almanac_data_page (TSIPPKT *rpt) -{ - unsigned char - sv_prn; - short - week_num; - float - t_zc, - eccentricity, - t_oa, - i_0, - OMEGA_dot, - sqrt_A, - OMEGA_0, - omega, - M_0; - - /* unload rptbuf */ - if (rpt_0x40 (rpt, - &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa, - &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nAlmanac for SV %02d", sv_prn); - pbuf += sprintf(pbuf, "\n Captured:%15.0f %s", - t_zc, show_time (t_zc)); - pbuf += sprintf(pbuf, "\n week:%15d", week_num); - pbuf += sprintf(pbuf, "\n Eccentricity:%15g", eccentricity); - pbuf += sprintf(pbuf, "\n T_oa:%15.0f %s", - t_oa, show_time (t_oa)); - pbuf += sprintf(pbuf, "\n i 0:%15g", i_0); - pbuf += sprintf(pbuf, "\n OMEGA dot:%15g", OMEGA_dot); - pbuf += sprintf(pbuf, "\n sqrt A:%15g", sqrt_A); - pbuf += sprintf(pbuf, "\n OMEGA 0:%15g", OMEGA_0); - pbuf += sprintf(pbuf, "\n omega:%15g", omega); - pbuf += sprintf(pbuf, "\n M 0:%15g", M_0); -} - -/* 0x41 */ -static void rpt_GPS_time (TSIPPKT *rpt) -{ - float - time_of_week, UTC_offset; - short - week_num; - - /* unload rptbuf */ - if (rpt_0x41 (rpt, &time_of_week, &UTC_offset, &week_num)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nGPS time:%s GPS week: %d UTC offset %.1f", - show_time(time_of_week), week_num, UTC_offset); - -} - -/* 0x42 */ -static void rpt_single_ECEF_position (TSIPPKT *rpt) -{ - float - ECEF_pos[3], time_of_fix; - - /* unload rptbuf */ - if (rpt_0x42 (rpt, ECEF_pos, &time_of_fix)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nSXYZ: %15.0f %15.0f %15.0f %s", - ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], - show_time(time_of_fix)); -} - -/* 0x43 */ -static void rpt_single_ECEF_velocity (TSIPPKT *rpt) -{ - - float - ECEF_vel[3], freq_offset, time_of_fix; - - /* unload rptbuf */ - if (rpt_0x43 (rpt, ECEF_vel, &freq_offset, &time_of_fix)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nVelECEF: %11.3f %11.3f %11.3f %12.3f%s", - ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset, - show_time(time_of_fix)); -} - -/* 0x45 */ -static void rpt_SW_version (TSIPPKT *rpt) { - unsigned char - major_nav_version, minor_nav_version, - nav_day, nav_month, nav_year, - major_dsp_version, minor_dsp_version, - dsp_day, dsp_month, dsp_year; - - /* unload rptbuf */ - if (rpt_0x45 (rpt, - &major_nav_version, &minor_nav_version, - &nav_day, &nav_month, &nav_year, - &major_dsp_version, &minor_dsp_version, - &dsp_day, &dsp_month, &dsp_year)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, -"\nFW Versions: Nav Proc %2d.%02d %2d/%2d/%2d Sig Proc %2d.%02d %2d/%2d/%2d", - major_nav_version, minor_nav_version, nav_day, nav_month, nav_year, - major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year); -} - -/* 0x46 */ -static void rpt_rcvr_health (TSIPPKT *rpt) -{ - unsigned char - status1, status2; - static char - *sc_text[] = { - "Doing position fixes", - "Don't have GPS time yet", - "Waiting for almanac collection", - "DOP too high ", - "No satellites available", - "Only 1 satellite available", - "Only 2 satellites available", - "Only 3 satellites available", - "No satellites usable ", - "Only 1 satellite usable", - "Only 2 satellites usable", - "Only 3 satellites usable", - "Chosen satellite unusable"}; - - - /* unload rptbuf */ - if (rpt_0x46 (rpt, &status1, &status2)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ", - sc_text[rpt->buf[0]], status1); - - pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)", - (status2 & 0x01)?"No BBRAM":"BBRAM OK", - (status2 & 0x10)?"No Ant":"Ant OK", - status2); -} - -/* 0x47 */ -static void rpt_SNR_all_SVs (TSIPPKT *rpt) -{ - unsigned char - nsvs, sv_prn[12]; - short - isv; - float - snr[12]; - - /* unload rptbuf */ - if (rpt_0x47 (rpt, &nsvs, sv_prn, snr)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs); - for (isv = 0; isv < nsvs; isv++) - { - pbuf += sprintf(pbuf, "\n SV %02d %6.2f", - sv_prn[isv], snr[isv]); - } -} - -/* 0x48 */ -static void rpt_GPS_system_message (TSIPPKT *rpt) -{ - unsigned char - message[23]; - - /* unload rptbuf */ - if (rpt_0x48 (rpt, message)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nGPS message: %s", message); -} - -/* 0x49 */ -static void rpt_almanac_health_page (TSIPPKT *rpt) -{ - short - iprn; - unsigned char - sv_health [32]; - - /* unload rptbuf */ - if (rpt_0x49 (rpt, sv_health)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nAlmanac health page:"); - for (iprn = 0; iprn < 32; iprn++) - { - if (!(iprn%5)) *pbuf++ = '\n'; - pbuf += sprintf(pbuf, " SV%02d %2X", - (iprn+1) , sv_health[iprn]); - } -} - -/* 0x4A */ -static void rpt_single_lla_position (TSIPPKT *rpt) { - short - lat_deg, lon_deg; - float - lat, lon, - alt, clock_bias, time_of_fix; - double lat_min, lon_min; - unsigned char - north_south, east_west; - - if (rpt_0x4A (rpt, - &lat, &lon, &alt, &clock_bias, &time_of_fix)) - { - parsed = BADLEN_PARSE; - return; - } - - /* convert from radians to degrees */ - lat *= (float)R2D; - north_south = 'N'; - if (lat < 0.0) - { - north_south = 'S'; - lat = -lat; - } - lat_deg = (short)lat; - lat_min = (lat - lat_deg) * 60.0; - - lon *= (float)R2D; - east_west = 'E'; - if (lon < 0.0) - { - east_west = 'W'; - lon = -lon; - } - lon_deg = (short)lon; - lon_min = (lon - lon_deg) * 60.0; - - pbuf += sprintf(pbuf, "\nSLLA: %4d: %06.3f %c%5d:%06.3f %c%10.2f %12.2f%s", - lat_deg, lat_min, north_south, - lon_deg, lon_min, east_west, - alt, clock_bias, - show_time(time_of_fix)); -} - -/* 0x4A */ -static void rpt_ref_alt (TSIPPKT *rpt) { - - float - alt, dummy; - unsigned char - alt_flag; - - if (rpt_0x4A_2 (rpt, - &alt, &dummy, &alt_flag)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nReference Alt: %.1f m; %s", - alt, alt_flag?"ON":"OFF"); -} - -/* 0x4B */ -static void rpt_rcvr_id_and_status (TSIPPKT *rpt) -{ - - unsigned char - machine_id, status3, status4; - - /* unload rptbuf */ - if (rpt_0x4B (rpt, &machine_id, &status3, &status4)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)", - machine_id, - (status3 & 0x02)?"No RTC":"RTC OK", - (status3 & 0x08)?"No Alm":"Alm OK", - status3); -} - -/* 0x4C */ -static void rpt_operating_parameters (TSIPPKT *rpt) -{ - unsigned char - dyn_code; - float - el_mask, snr_mask, dop_mask, dop_switch; - - /* unload rptbuf */ - if (rpt_0x4C (rpt, &dyn_code, &el_mask, - &snr_mask, &dop_mask, &dop_switch)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nOperating Parameters:"); - pbuf += sprintf(pbuf, "\n Dynamics code = %d %s", - dyn_code, dyn_text[dyn_code]); - pbuf += sprintf(pbuf, "\n Elevation mask = %.2fø", el_mask * R2D); - pbuf += sprintf(pbuf, "\n SNR mask = %.2f", snr_mask); - pbuf += sprintf(pbuf, "\n DOP mask = %.2f", dop_mask); - pbuf += sprintf(pbuf, "\n DOP switch = %.2f", dop_switch); -} - -/* 0x4D */ -static void rpt_oscillator_offset (TSIPPKT *rpt) -{ - float - osc_offset; - - /* unload rptbuf */ - if (rpt_0x4D (rpt, &osc_offset)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM", - osc_offset, osc_offset/1575.42); -} - -/* 0x4E */ -static void rpt_GPS_time_set_response (TSIPPKT *rpt) -{ - - unsigned char - response; - - /* unload rptbuf */ - if (rpt_0x4E (rpt, &response)) - { - parsed = BADLEN_PARSE; - return; - } - - switch (response) - { - case 'Y': - pbuf += sprintf(pbuf, "\nTime set accepted"); - break; - - case 'N': - pbuf += sprintf(pbuf, "\nTime set rejected or not required"); - break; - - default: - parsed = BADDATA_PARSE; - } -} - -/* 0x4F */ -static void rpt_UTC_offset (TSIPPKT *rpt) -{ - double - a0; - float - a1, time_of_data; - short - dt_ls, wn_t, wn_lsf, dn, dt_lsf; - - /* unload rptbuf */ - if (rpt_0x4F (rpt, &a0, &a1, &time_of_data, - &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nUTC Correction Data"); - pbuf += sprintf(pbuf, "\n A_0 = %g ", a0); - pbuf += sprintf(pbuf, "\n A_1 = %g ", a1); - pbuf += sprintf(pbuf, "\n delta_t_LS = %d ", dt_ls); - pbuf += sprintf(pbuf, "\n t_ot = %.0f ", time_of_data); - pbuf += sprintf(pbuf, "\n WN_t = %d ", wn_t ); - pbuf += sprintf(pbuf, "\n WN_LSF = %d ", wn_lsf ); - pbuf += sprintf(pbuf, "\n DN = %d ", dn ); - pbuf += sprintf(pbuf, "\n delta_t_LSF = %d ", dt_lsf ); -} - -/**/ -/* 0x54 */ -static void rpt_1SV_bias (TSIPPKT *rpt) -{ - float - clock_bias, freq_offset, time_of_fix; - - /* unload rptbuf */ - if (rpt_0x54 (rpt, &clock_bias, &freq_offset, &time_of_fix)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf (pbuf, "\nTime Fix Clock Bias: %6.2f m Freq Bias: %6.2f m/s%s", - clock_bias, freq_offset, show_time (time_of_fix)); -} - -/* 0x55 */ -static void rpt_io_opt (TSIPPKT *rpt) -{ - unsigned char - pos_code, vel_code, time_code, aux_code; - - /* unload rptbuf */ - if (rpt_0x55 (rpt, - &pos_code, &vel_code, &time_code, &aux_code)) { - parsed = BADLEN_PARSE; - return; - } - /* rptbuf unloaded */ - - pbuf += sprintf(pbuf, "\nI/O Options: %2X %2X %2X %2X", - pos_code, vel_code, time_code, aux_code); - - if (pos_code & 0x01) { - pbuf += sprintf(pbuf, "\n ECEF XYZ position output"); - } - - if (pos_code & 0x02) { - pbuf += sprintf(pbuf, "\n LLA position output"); - } - - pbuf += sprintf(pbuf, (pos_code & 0x04)? - "\n MSL altitude output (Geoid height) ": - "\n WGS-84 altitude output"); - - pbuf += sprintf(pbuf, (pos_code & 0x08)? - "\n MSL altitude input": - "\n WGS-84 altitude input"); - - pbuf += sprintf(pbuf, (pos_code & 0x10)? - "\n Double precision": - "\n Single precision"); - - if (pos_code & 0x20) { - pbuf += sprintf(pbuf, "\n All Enabled Superpackets"); - } - - if (vel_code & 0x01) { - pbuf += sprintf(pbuf, "\n ECEF XYZ velocity output"); - } - - if (vel_code & 0x02) { - pbuf += sprintf(pbuf, "\n ENU velocity output"); - } - - pbuf += sprintf(pbuf, (time_code & 0x01)? - "\n Time tags in UTC": - "\n Time tags in GPS time"); - - if (time_code & 0x02) { - pbuf += sprintf(pbuf, "\n Fixes delayed to integer seconds"); - } - - if (time_code & 0x04) { - pbuf += sprintf(pbuf, "\n Fixes sent only on request"); - } - - if (time_code & 0x08) { - pbuf += sprintf(pbuf, "\n Synchronized measurements"); - } - - if (time_code & 0x10) { - pbuf += sprintf(pbuf, "\n Minimize measurement propagation"); - } - - pbuf += sprintf(pbuf, (time_code & 0x20) ? - "\n PPS output at all times" : - "\n PPS output during fixes"); - - if (aux_code & 0x01) { - pbuf += sprintf(pbuf, "\n Raw measurement output"); - } - - if (aux_code & 0x02) { - pbuf += sprintf(pbuf, "\n Code-phase smoothed before output"); - } - - if (aux_code & 0x04) { - pbuf += sprintf(pbuf, "\n Additional fix status"); - } - - pbuf += sprintf(pbuf, (aux_code & 0x08)? - "\n Signal Strength Output as dBHz" : - "\n Signal Strength Output as AMU"); -} - -/* 0x56 */ -static void rpt_ENU_velocity (TSIPPKT *rpt) -{ - float - vel_ENU[3], freq_offset, time_of_fix; - - /* unload rptbuf */ - if (rpt_0x56 (rpt, vel_ENU, &freq_offset, &time_of_fix)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nVel ENU: %11.3f %11.3f %11.3f %12.3f%s", - vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset, - show_time (time_of_fix)); -} - -/* 0x57 */ -static void rpt_last_fix_info (TSIPPKT *rpt) -{ - unsigned char - source_code, diag_code; - short - week_num; - float - time_of_fix; - - /* unload rptbuf */ - if (rpt_0x57 (rpt, &source_code, &diag_code, &week_num, &time_of_fix)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\n source code %d; diag code: %2Xh", - source_code, diag_code); - pbuf += sprintf(pbuf, "\n Time of last fix:%s", show_time(time_of_fix)); - pbuf += sprintf(pbuf, "\n Week of last fix: %d", week_num); -} - -/* 0x58 */ -static void rpt_GPS_system_data (TSIPPKT *rpt) -{ - unsigned char - iprn, - op_code, data_type, sv_prn, - data_length, data_packet[250]; - ALM_INFO - *almanac; - ALH_PARMS - *almh; - UTC_INFO - *utc; - ION_INFO - *ionosphere; - EPHEM_CLOCK - *cdata; - EPHEM_ORBIT - *edata; - NAV_INFO - *nav_data; - unsigned char - curr_t_oa; - unsigned short - curr_wn_oa; - static char - *datname[] = - {"", "", "Almanac Orbit", - "Health Page & Ref Time", "Ionosphere", "UTC ", - "Ephemeris"}; - - /* unload rptbuf */ - if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn, - &data_length, data_packet)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nSystem data [%d]: %s SV%02d", - data_type, datname[data_type], sv_prn); - switch (op_code) - { - case 1: - pbuf += sprintf(pbuf, " Acknowledgment"); - break; - case 2: - pbuf += sprintf(pbuf, " length = %d bytes", data_length); - switch (data_type) { - case 2: - /* Almanac */ - if (sv_prn == 0 || sv_prn > 32) { - pbuf += sprintf(pbuf, " Binary PRN invalid"); - return; - } - almanac = (ALM_INFO*)data_packet; - pbuf += sprintf(pbuf, "\n t_oa_raw = % -12d SV_hlth = % -12d ", - almanac->t_oa_raw , almanac->SV_health ); - pbuf += sprintf(pbuf, "\n e = % -12g t_oa = % -12g ", - almanac->e , almanac->t_oa ); - pbuf += sprintf(pbuf, "\n i_0 = % -12g OMEGADOT = % -12g ", - almanac->i_0 , almanac->OMEGADOT ); - pbuf += sprintf(pbuf, "\n sqrt_A = % -12g OMEGA_0 = % -12g ", - almanac->sqrt_A , almanac->OMEGA_0 ); - pbuf += sprintf(pbuf, "\n omega = % -12g M_0 = % -12g ", - almanac->omega , almanac->M_0 ); - pbuf += sprintf(pbuf, "\n a_f0 = % -12g a_f1 = % -12g ", - almanac->a_f0 , almanac->a_f1 ); - pbuf += sprintf(pbuf, "\n Axis = % -12g n = % -12g ", - almanac->Axis , almanac->n ); - pbuf += sprintf(pbuf, "\n OMEGA_n = % -12g ODOT_n = % -12g ", - almanac->OMEGA_n , almanac->ODOT_n ); - pbuf += sprintf(pbuf, "\n t_zc = % -12g weeknum = % -12d ", - almanac->t_zc , almanac->weeknum ); - pbuf += sprintf(pbuf, "\n wn_oa = % -12d", almanac->wn_oa ); - break; - - case 3: - /* Almanac health page */ - almh = (ALH_PARMS*)data_packet; - pbuf += sprintf(pbuf, "\n t_oa = %d, wn_oa&0xFF = %d ", - almh->t_oa, almh->WN_a); - pbuf += sprintf(pbuf, "\nAlmanac health page:"); - for (iprn = 0; iprn < 32; iprn++) { - if (!(iprn%5)) *pbuf++ = '\n'; - pbuf += sprintf(pbuf, " SV%02d %2X", - (iprn+1) , almh->SV_health[iprn]); - } - curr_t_oa = data_packet[34]; - curr_wn_oa = (unsigned short)((data_packet[35]<<8) + data_packet[36]); - pbuf += sprintf(pbuf, "\n current t_oa = %d, wn_oa = %d ", - curr_t_oa, curr_wn_oa); - break; - - case 4: - /* Ionosphere */ - ionosphere = (ION_INFO*)data_packet; - pbuf += sprintf(pbuf, "\n alpha_0 = % -12g alpha_1 = % -12g ", - ionosphere->alpha_0, ionosphere->alpha_1); - pbuf += sprintf(pbuf, "\n alpha_2 = % -12g alpha_3 = % -12g ", - ionosphere->alpha_2, ionosphere->alpha_3); - pbuf += sprintf(pbuf, "\n beta_0 = % -12g beta_1 = % -12g ", - ionosphere->beta_0, ionosphere->beta_1); - pbuf += sprintf(pbuf, "\n beta_2 = % -12g beta_3 = % -12g ", - ionosphere->beta_2, ionosphere->beta_3); - break; - - case 5: - /* UTC */ - utc = (UTC_INFO*)data_packet; - pbuf += sprintf(pbuf, "\n A_0 = %g ", utc->A_0); - pbuf += sprintf(pbuf, "\n A_1 = %g ", utc->A_1); - pbuf += sprintf(pbuf, "\n delta_t_LS = %d ", utc->delta_t_LS); - pbuf += sprintf(pbuf, "\n t_ot = %.0f ", utc->t_ot ); - pbuf += sprintf(pbuf, "\n WN_t = %d ", utc->WN_t ); - pbuf += sprintf(pbuf, "\n WN_LSF = %d ", utc->WN_LSF ); - pbuf += sprintf(pbuf, "\n DN = %d ", utc->DN ); - pbuf += sprintf(pbuf, "\n delta_t_LSF = %d ", utc->delta_t_LSF ); - break; - - case 6: /* Ephemeris */ - if (sv_prn == 0 || sv_prn > 32) { - pbuf += sprintf(pbuf, " Binary PRN invalid"); - return; - } - nav_data = (NAV_INFO*)data_packet; - - pbuf += sprintf(pbuf, "\n SV_PRN = % -12d . t_ephem = % -12g . ", - nav_data->sv_number , nav_data->t_ephem ); - cdata = &(nav_data->ephclk); - pbuf += sprintf(pbuf, - "\n weeknum = % -12d . codeL2 = % -12d . L2Pdata = % -12d", - cdata->weeknum , cdata->codeL2 , cdata->L2Pdata ); - pbuf += sprintf(pbuf, - "\n SVacc_raw = % -12d .SV_health = % -12d . IODC = % -12d", - cdata->SVacc_raw, cdata->SV_health, cdata->IODC ); - pbuf += sprintf(pbuf, - "\n T_GD = % -12g . t_oc = % -12g . a_f2 = % -12g", - cdata->T_GD, cdata->t_oc, cdata->a_f2 ); - pbuf += sprintf(pbuf, - "\n a_f1 = % -12g . a_f0 = % -12g . SVacc = % -12g", - cdata->a_f1, cdata->a_f0, cdata->SVacc ); - edata = &(nav_data->ephorb); - pbuf += sprintf(pbuf, - "\n IODE = % -12d .fit_intvl = % -12d . C_rs = % -12g", - edata->IODE, edata->fit_interval, edata->C_rs ); - pbuf += sprintf(pbuf, - "\n delta_n = % -12g . M_0 = % -12g . C_uc = % -12g", - edata->delta_n, edata->M_0, edata->C_uc ); - pbuf += sprintf(pbuf, - "\n ecc = % -12g . C_us = % -12g . sqrt_A = % -12g", - edata->e, edata->C_us, edata->sqrt_A ); - pbuf += sprintf(pbuf, - "\n t_oe = % -12g . C_ic = % -12g . OMEGA_0 = % -12g", - edata->t_oe, edata->C_ic, edata->OMEGA_0 ); - pbuf += sprintf(pbuf, - "\n C_is = % -12g . i_0 = % -12g . C_rc = % -12g", - edata->C_is, edata->i_0, edata->C_rc ); - pbuf += sprintf(pbuf, - "\n omega = % -12g . OMEGADOT = % -12g . IDOT = % -12g", - edata->omega, edata->OMEGADOT, edata->IDOT ); - pbuf += sprintf(pbuf, - "\n Axis = % -12g . n = % -12g . r1me2 = % -12g", - edata->Axis, edata->n, edata->r1me2 ); - pbuf += sprintf(pbuf, - "\n OMEGA_n = % -12g . ODOT_n = % -12g", - edata->OMEGA_n, edata->ODOT_n ); - break; - } - } -} - - -/* 0x59: */ -static void rpt_SVs_enabled (TSIPPKT *rpt) -{ - unsigned char - numsvs, - code_type, - status_code[32]; - short - iprn; - - /* unload rptbuf */ - if (rpt_0x59 (rpt, &code_type, status_code)) - { - parsed = BADLEN_PARSE; - return; - } - switch (code_type) - { - case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break; - case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break; - default: return; - } - numsvs = 0; - for (iprn=0; iprn<32; iprn++) - { - if (status_code[iprn]) - { - pbuf += sprintf(pbuf, " %02d", iprn+1); - numsvs++; - } - } - if (numsvs == 0) pbuf += sprintf(pbuf, "None"); -} - - -/* 0x5A */ -static void rpt_raw_msmt (TSIPPKT *rpt) -{ - unsigned char - sv_prn; - float - sample_length, signal_level, code_phase, Doppler; - double - time_of_fix; - - /* unload rptbuf */ - if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level, - &code_phase, &Doppler, &time_of_fix)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\n %02d %5.0f %7.1f %10.2f %10.2f %12.3f %s", - sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix, - show_time ((float)time_of_fix)); -} - -/* 0x5B */ -static void rpt_SV_ephemeris_status (TSIPPKT *rpt) -{ - unsigned char - sv_prn, sv_health, sv_iode, fit_interval_flag; - float - time_of_collection, time_of_eph, sv_accy; - - /* unload rptbuf */ - if (rpt_0x5B (rpt, &sv_prn, &sv_health, &sv_iode, &fit_interval_flag, - &time_of_collection, &time_of_eph, &sv_accy)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\n SV%02d %s %2Xh %2Xh ", - sv_prn, show_time (time_of_collection), sv_health, sv_iode); - /* note: cannot use show_time twice in same call */ - pbuf += sprintf(pbuf, "%s %1d %4.1f", - show_time (time_of_eph), fit_interval_flag, sv_accy); -} - -/* 0x5C */ -static void rpt_SV_tracking_status (TSIPPKT *rpt) -{ - unsigned char - sv_prn, chan, slot, acq_flag, eph_flag, - old_msmt_flag, integer_msec_flag, bad_data_flag, - data_collect_flag; - float - signal_level, time_of_last_msmt, - elev, azim; - - /* unload rptbuf */ - if (rpt_0x5C (rpt, - &sv_prn, &slot, &chan, &acq_flag, &eph_flag, - &signal_level, &time_of_last_msmt, &elev, &azim, - &old_msmt_flag, &integer_msec_flag, &bad_data_flag, - &data_collect_flag)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, -"\n SV%2d %1d %1d %1d %4.1f %s %5.1f %5.1f", - sv_prn, chan, - acq_flag, eph_flag, signal_level, - show_time(time_of_last_msmt), - elev*R2D, azim*R2D); -} - -/**/ -/* 0x6D */ -static void rpt_allSV_selection (TSIPPKT *rpt) -{ - unsigned char - manual_mode, nsvs, sv_prn[8], ndim; - short - islot; - float - pdop, hdop, vdop, tdop; - - /* unload rptbuf */ - if (rpt_0x6D (rpt, - &manual_mode, &nsvs, &ndim, sv_prn, - &pdop, &hdop, &vdop, &tdop)) - { - parsed = BADLEN_PARSE; - return; - } - - switch (ndim) - { - case 0: - pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs); - break; - case 1: - pbuf += sprintf(pbuf, "\nMode: One-SV Timing:"); - break; - case 3: case 4: - pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:", - manual_mode ? 'M' : 'A', ndim - 1, nsvs); - break; - case 5: - pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs); - break; - default: - pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim); - break; - } - - for (islot = 0; islot < nsvs; islot++) - { - if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]); - } - if (ndim == 3 || ndim == 4) - { - pbuf += sprintf(pbuf, "; DOPs: P %.1f H %.1f V %.1f T %.1f", - pdop, hdop, vdop, tdop); - } -} - -/**/ -/* 0x82 */ -static void rpt_DGPS_position_mode (TSIPPKT *rpt) -{ - unsigned char - diff_mode; - - /* unload rptbuf */ - if (rpt_0x82 (rpt, &diff_mode)) { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nFix is%s DGPS-corrected (%s mode) (%d)", - (diff_mode&1) ? "" : " not", - (diff_mode&2) ? "auto" : "manual", - diff_mode); -} - -/* 0x83 */ -static void rpt_double_ECEF_position (TSIPPKT *rpt) -{ - - double - ECEF_pos[3], clock_bias; - float - time_of_fix; - - /* unload rptbuf */ - if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nDXYZ:%12.2f %13.2f %13.2f %12.2f%s", - ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias, - show_time(time_of_fix)); -} - -/* 0x84 */ -static void rpt_double_lla_position (TSIPPKT *rpt) -{ - short - lat_deg, lon_deg; - double - lat, lon, lat_min, lon_min, - alt, clock_bias; - float - time_of_fix; - unsigned char - north_south, east_west; - - /* unload rptbuf */ - if (rpt_0x84 (rpt, - &lat, &lon, &alt, &clock_bias, &time_of_fix)) - { - parsed = BADLEN_PARSE; - return; - } - - lat *= R2D; - lon *= R2D; - if (lat < 0.0) { - north_south = 'S'; - lat = -lat; - } else { - north_south = 'N'; - } - lat_deg = (short)lat; - lat_min = (lat - lat_deg) * 60.0; - - if (lon < 0.0) { - east_west = 'W'; - lon = -lon; - } else { - east_west = 'E'; - } - lon_deg = (short)lon; - lon_min = (lon - lon_deg) * 60.0; - pbuf += sprintf(pbuf, "\nDLLA: %2d:%08.5f %c; %3d:%08.5f %c; %10.2f %12.2f%s", - lat_deg, lat_min, north_south, - lon_deg, lon_min, east_west, - alt, clock_bias, - show_time(time_of_fix)); -} - -/* 0xBB */ -static void rpt_complete_rcvr_config (TSIPPKT *rpt) -{ - TSIP_RCVR_CFG TsipxBB ; - /* unload rptbuf */ - if (rpt_Paly0xBB (rpt, &TsipxBB)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\n operating mode: %s", - NavModeText0xBB[TsipxBB.operating_mode]); - pbuf += sprintf(pbuf, "\n dynamics: %s", - dyn_text[TsipxBB.dyn_code]); - pbuf += sprintf(pbuf, "\n elev angle mask: %g deg", - TsipxBB.elev_mask * R2D); - pbuf += sprintf(pbuf, "\n SNR mask: %g AMU", - TsipxBB.cno_mask); - pbuf += sprintf(pbuf, "\n DOP mask: %g", - TsipxBB.dop_mask); - pbuf += sprintf(pbuf, "\n DOP switch: %g", - TsipxBB.dop_switch); - return ; -} - -/* 0xBC */ -static void rpt_rcvr_serial_port_config (TSIPPKT *rpt) -{ - unsigned char - port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control, - protocols_in, protocols_out, reserved; - unsigned char known; - - /* unload rptbuf */ - if (rpt_0xBC (rpt, &port_num, &in_baud, &out_baud, &data_bits, &parity, - &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) { - parsed = BADLEN_PARSE; - return; - } - /* rptbuf unloaded */ - - pbuf += sprintf(pbuf, "\n RECEIVER serial port %s config:", - rcvr_port_text[port_num]); - - pbuf += sprintf(pbuf, "\n I/O Baud %s/%s, %d - %s - %d", - st_baud_text_app[in_baud], - st_baud_text_app[out_baud], - data_bits+5, - parity_text[parity], - stop_bits=1); - pbuf += sprintf(pbuf, "\n Input protocols: "); - known = FALSE; - if (protocols_in&B_TSIP) - { - pbuf += sprintf(pbuf, "%s ", protocols_in_text[1]); - known = TRUE; - } - if (known == FALSE) pbuf += sprintf(pbuf, "No known"); - - pbuf += sprintf(pbuf, "\n Output protocols: "); - known = FALSE; - if (protocols_out&B_TSIP) - { - pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]); - known = TRUE; - } - if (protocols_out&B_NMEA) - { - pbuf += sprintf(pbuf, "%s ", protocols_out_text[2]); - known = TRUE; - } - if (known == FALSE) pbuf += sprintf(pbuf, "No known"); - reserved = reserved; - - } - -/* 0x8F */ -/* 8F0B */ -static void rpt_8F0B(TSIPPKT *rpt) -{ - const char - *oprtng_dim[7] = { - "horizontal (2-D)", - "full position (3-D)", - "single satellite (0-D)", - "automatic", - "N/A", - "N/A", - "overdetermined clock"}; - char - sv_id[8]; - unsigned char - month, - date, - dim_mode, - north_south, - east_west; - unsigned short - event; - short - utc_offset, - year, - local_index; - short - lat_deg, - lon_deg; - float - bias_unc, - dr_unc; - double - tow, - bias, - drift, - lat, - lon, - alt, - lat_min, - lon_min; - int - numfix, - numnotfix; - - if (rpt_0x8F0B(rpt, - &event, - &tow, - &date, - &month, - &year, - &dim_mode, - &utc_offset, - &bias, - &drift, - &bias_unc, - &dr_unc, - &lat, - &lon, - &alt, - sv_id)) - { - parsed = BADLEN_PARSE; - return; - } - - if (event == 0) - { - pbuf += sprintf(pbuf, "\nNew partial+full meas"); - } - else - { - pbuf += sprintf(pbuf, "\nEvent count: %5d", event); - } - - pbuf += sprintf(pbuf, "\nGPS time : %s %2d/%2d/%2d (DMY)", - show_time(tow), date, month, year); - pbuf += sprintf(pbuf, "\nMode : %s", oprtng_dim[dim_mode]); - pbuf += sprintf(pbuf, "\nUTC offset: %2d", utc_offset); - pbuf += sprintf(pbuf, "\nClock Bias: %6.2f m", bias); - pbuf += sprintf(pbuf, "\nFreq bias : %6.2f m/s", drift); - pbuf += sprintf(pbuf, "\nBias unc : %6.2f m", bias_unc); - pbuf += sprintf(pbuf, "\nFreq unc : %6.2f m/s", dr_unc); - - lat *= R2D; /* convert from radians to degrees */ - lon *= R2D; - if (lat < 0.0) - { - north_south = 'S'; - lat = -lat; - } - else - { - north_south = 'N'; - } - - lat_deg = (short)lat; - lat_min = (lat - lat_deg) * 60.0; - if (lon < 0.0) - { - east_west = 'W'; - lon = -lon; - } - else - { - east_west = 'E'; - } - - lon_deg = (short)lon; - lon_min = (lon - lon_deg) * 60.0; - pbuf += sprintf(pbuf, "\nPosition :"); - pbuf += sprintf(pbuf, " %4d %6.3f %c", lat_deg, lat_min, north_south); - pbuf += sprintf(pbuf, " %5d %6.3f %c", lon_deg, lon_min, east_west); - pbuf += sprintf(pbuf, " %10.2f", alt); - - numfix = numnotfix = 0; - for (local_index=0; local_index<8; local_index++) - { - if (sv_id[local_index] < 0) numnotfix++; - if (sv_id[local_index] > 0) numfix++; - } - if (numfix > 0) - { - pbuf += sprintf(pbuf, "\nSVs used in fix : "); - for (local_index=0; local_index<8; local_index++) - { - if (sv_id[local_index] > 0) - { - pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]); - } - } - } - if (numnotfix > 0) - { - pbuf += sprintf(pbuf, "\nOther SVs tracked: "); - for (local_index=0; local_index<8; local_index++) - { - if (sv_id[local_index] < 0) - { - pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]); - } - } - } -} - -/* 0x8F14 */ -static void rpt_8F14 (TSIPPKT *rpt) -/* Datum parameters */ -{ - double - datum_coeffs[5]; - short - datum_idx; - - /* unload rptbuf */ - if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs)) - { - parsed = BADLEN_PARSE; - return; - } - - if (datum_idx == -1) - { - pbuf += sprintf(pbuf, "\nUser-Entered Datum:"); - pbuf += sprintf(pbuf, "\n dx = %6.1f", datum_coeffs[0]); - pbuf += sprintf(pbuf, "\n dy = %6.1f", datum_coeffs[1]); - pbuf += sprintf(pbuf, "\n dz = %6.1f", datum_coeffs[2]); - pbuf += sprintf(pbuf, "\n a-axis = %10.3f", datum_coeffs[3]); - pbuf += sprintf(pbuf, "\n e-squared = %16.14f", datum_coeffs[4]); - } - else if (datum_idx == 0) - { - pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 "); - } - else - { - pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx); - } -} - -/* 0x8F15 */ -static void rpt_8F15 (TSIPPKT *rpt) -/* Datum parameters */ -{ - double - datum_coeffs[5]; - short - datum_idx; - - /* unload rptbuf */ - if (rpt_0x8F15 (rpt, &datum_idx, datum_coeffs)) { - parsed = BADLEN_PARSE; - return; - } - - if (datum_idx == -1) - { - pbuf += sprintf(pbuf, "\nUser-Entered Datum:"); - pbuf += sprintf(pbuf, "\n dx = %6.1f", datum_coeffs[0]); - pbuf += sprintf(pbuf, "\n dy = %6.1f", datum_coeffs[1]); - pbuf += sprintf(pbuf, "\n dz = %6.1f", datum_coeffs[2]); - pbuf += sprintf(pbuf, "\n a-axis = %10.3f", datum_coeffs[3]); - pbuf += sprintf(pbuf, "\n e-squared = %16.14f", datum_coeffs[4]); - } - else if (datum_idx == 0) - { - pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 "); - } - else - { - pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx); - } -} - -/* 0x8F20 */ -#define INFO_DGPS 0x02 -#define INFO_2D 0x04 -#define INFO_ALTSET 0x08 -#define INFO_FILTERED 0x10 -static void rpt_8F20 (TSIPPKT *rpt) -{ - unsigned char - info, nsvs, sv_prn[32]; - short - week_num, datum_index, sv_IODC[32]; - double - lat, lon, alt, time_of_fix; - double - londeg, latdeg, vel[3]; - short - isv; - char - datum_string[20]; - - /* unload rptbuf */ - if (rpt_0x8F20 (rpt, - &info, &lat, &lon, &alt, vel, - &time_of_fix, - &week_num, &nsvs, sv_prn, sv_IODC, &datum_index)) - { - parsed = BADLEN_PARSE; - return; - } - pbuf += sprintf(pbuf, - "\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds) FixType: %s%s%s", - week_num, - dayname[(short)(time_of_fix/86400.0)], - (short)fmod(time_of_fix/3600., 24.), - (short)fmod(time_of_fix/60., 60.), - fmod(time_of_fix, 60.), - (char)rpt->buf[29], /* UTC offset */ - (info & INFO_DGPS)?"Diff":"", - (info & INFO_2D)?"2D":"3D", - (info & INFO_FILTERED)?"-Filtrd":""); - - if (datum_index > 0) - { - sprintf(datum_string, "Datum%3d", datum_index); - } - else if (datum_index) - { - sprintf(datum_string, "Unknown "); - } - else - { - sprintf(datum_string, "WGS-84"); - } - - /* convert from radians to degrees */ - latdeg = R2D * fabs(lat); - londeg = R2D * fabs(lon); - pbuf += sprintf(pbuf, - "\n Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)", - (short)latdeg, fmod (latdeg, 1.)*60.0, - (lat<0.0)?'S':'N', - (short)londeg, fmod (londeg, 1.)*60.0, - (lon<0.0)?'W':'E', - alt, - datum_string); - pbuf += sprintf(pbuf, - "\n Vel: %9.3f E %9.3f N %9.3f U (m/sec)", - vel[0], vel[1], vel[2]); - - pbuf += sprintf(pbuf, - "\n SVs: "); - for (isv = 0; isv < nsvs; isv++) { - pbuf += sprintf(pbuf, " %02d", sv_prn[isv]); - } - pbuf += sprintf(pbuf, " (IODEs:"); - for (isv = 0; isv < nsvs; isv++) { - pbuf += sprintf(pbuf, " %02X", sv_IODC[isv]&0xFF); - } - pbuf += sprintf(pbuf, ")"); -} - -/* 0x8F41 */ -static void rpt_8F41(TSIPPKT *rpt) -{ - unsigned char - bSearchRange, - bBoardOptions, - bBuildYear, - bBuildMonth, - bBuildDay, - bBuildHour; - float - fOscOffset; - unsigned short - iTestCodeId; - unsigned long - iiSerialNumber; - - if (!rpt_0x8F41(rpt, - &bSearchRange, - &bBoardOptions, - &iiSerialNumber, - &bBuildYear, - &bBuildMonth, - &bBuildDay, - &bBuildHour, - &fOscOffset, - &iTestCodeId)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\n search range: %d", - bSearchRange); - pbuf += sprintf(pbuf, "\n board options: %d", - bBoardOptions); - pbuf += sprintf(pbuf, "\n board serial #: %ld", - iiSerialNumber); - pbuf += sprintf(pbuf, "\n build date/hour: %02d/%02d/%02d %02d:00", - bBuildDay, bBuildMonth, bBuildYear, bBuildHour); - pbuf += sprintf(pbuf, "\n osc offset: %.3f PPM (%.0f Hz)", - fOscOffset/1575.42, fOscOffset); - pbuf += sprintf(pbuf, "\n test code: %d", - iTestCodeId); -} - -/* 0x8F42 */ -static void rpt_8F42(TSIPPKT *rpt) -{ - unsigned char - bProdOptionsPre, - bProdNumberExt; - unsigned short - iCaseSerialNumberPre, - iPremiumOptions, - iMachineID, - iKey; - unsigned long - iiCaseSerialNumber, - iiProdNumber; - - if (!rpt_0x8F42(rpt, - &bProdOptionsPre, - &bProdNumberExt, - &iCaseSerialNumberPre, - &iiCaseSerialNumber, - &iiProdNumber, - &iPremiumOptions, - &iMachineID, - &iKey)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nProduct ID 8F42"); - pbuf += sprintf(pbuf, "\n extension: %d", bProdNumberExt); - pbuf += sprintf(pbuf, "\n case serial # prefix: %d", iCaseSerialNumberPre); - pbuf += sprintf(pbuf, "\n case serial #: %ld", iiCaseSerialNumber); - pbuf += sprintf(pbuf, "\n prod. #: %ld", iiProdNumber); - pbuf += sprintf(pbuf, "\n premium options: %Xh", iPremiumOptions); - pbuf += sprintf(pbuf, "\n machine ID: %d", iMachineID); - pbuf += sprintf(pbuf, "\n key: %Xh", iKey); -} - -/* 0x8F45 */ -static void rpt_8F45(TSIPPKT *rpt) -{ - unsigned char bSegMask; - - if (!rpt_0x8F45(rpt, - &bSegMask)) - { - parsed = BADLEN_PARSE; - return; - } - pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask); -} - -static void rpt_8F4A(TSIPPKT *rpt) -/* Stinger PPS def */ -{ - unsigned char - pps_enabled, - pps_timebase, - pps_polarity; - float - bias_unc_threshold; - double - pps_offset; - - if (rpt_0x8F4A_16 (rpt, - &pps_enabled, - &pps_timebase, - &pps_polarity, - &pps_offset, - &bias_unc_threshold)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nPPS is %s", pps_enabled?"enabled":"disabled"); - pbuf += sprintf(pbuf, "\n timebase: %s", PPSTimeBaseText[pps_timebase]); - pbuf += sprintf(pbuf, "\n polarity: %s", PPSPolarityText[pps_polarity]); - pbuf += sprintf(pbuf, "\n offset: %.1f ns, ", pps_offset*1.e9); - pbuf += sprintf(pbuf, "\n biasunc: %.1f ns", bias_unc_threshold/GPS_C*1.e9); -} - -static void rpt_8F4B(TSIPPKT *rpt) -/* fast-SA decorrolation time for self-survey */ -{ - unsigned long - decorr_max; - - if (rpt_0x8F4B(rpt, &decorr_max)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, - "\nMax # of position fixes for self-survey : %ld", - decorr_max); -} - -static void rpt_8F4D(TSIPPKT *rpt) -{ - static char - *linestart; - unsigned long - OutputMask; - static unsigned long - MaskBit[] = { - 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, - 0x00000100L, 0x00000800L, 0x00001000L, - 0x40000000L, 0x80000000L}; - int - ichoice, - numchoices; - - if (rpt_0x8F4D(rpt, &OutputMask)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X", - (unsigned char)(OutputMask>>24), - (unsigned char)(OutputMask>>16), - (unsigned char)(OutputMask>>8), - (unsigned char)OutputMask); - - numchoices = sizeof(MaskText)/sizeof(char*); - pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:"); - linestart = pbuf; - for (ichoice=0; ichoice<numchoices; ichoice++) - { - if (OutputMask&MaskBit[ichoice]) - { - pbuf += sprintf(pbuf, "%s %s", - (pbuf==linestart)?"\n ":",", - MaskText[ichoice]); - if (pbuf-linestart > 60) linestart = pbuf; - } - } - - pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:"); - linestart = pbuf; - for (ichoice=0; ichoice<numchoices; ichoice++) - { - if (OutputMask&MaskBit[ichoice]) continue; - pbuf += sprintf(pbuf, "%s %s", - (pbuf==linestart)?"\n ":",", - MaskText[ichoice]); - if (pbuf-linestart > 60) linestart = pbuf; - } -} - -static void rpt_8FA5(TSIPPKT *rpt) -{ - unsigned char - spktmask[4]; - - if (rpt_0x8FA5(rpt, spktmask)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X", - spktmask[0], spktmask[1], spktmask[2], spktmask[3]); - - if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n PPS 8F-0B"); - if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n Event 8F-0B"); - if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n PPS 8F-AD"); - if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n Event 8F-AD"); - if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n ppos Fix 8F-20"); -} - -static void rpt_8FAD (TSIPPKT *rpt) -{ - unsigned short - Count, - Year; - double - FracSec; - unsigned char - Hour, - Minute, - Second, - Day, - Month, - Status, - Flags; - static char* Status8FADText[] = { - "CODE_DOING_FIXES", - "CODE_GOOD_1_SV", - "CODE_APPX_1SV", - "CODE_NEED_TIME", - "CODE_NEED_INITIALIZATION", - "CODE_PDOP_HIGH", - "CODE_BAD_1SV", - "CODE_0SVS", - "CODE_1SV", - "CODE_2SVS", - "CODE_3SVS", - "CODE_NO_INTEGRITY", - "CODE_DCORR_GEN", - "CODE_OVERDET_CLK", - "Invalid Status"}, - *LeapStatusText[] = { - " UTC Avail", " ", " ", " ", - " Scheduled", " Pending", " Warning", " In Progress"}; - int i; - - if (rpt_0x8FAD (rpt, - &Count, - &FracSec, - &Hour, - &Minute, - &Second, - &Day, - &Month, - &Year, - &Status, - &Flags)) - { - parsed = BADLEN_PARSE; - return; - } - - pbuf += sprintf(pbuf, "\n8FAD Count: %d Status: %s", - Count, Status8FADText[Status]); - - pbuf += sprintf(pbuf, "\n Leap Flags:"); - if (Flags) - { - for (i=0; i<8; i++) - { - if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]); - } - } - else - { - pbuf += sprintf(pbuf, " UTC info not available"); - } - - pbuf += sprintf(pbuf, "\n %02d/%02d/%04d (DMY) %02d:%02d:%02d.%09ld UTC", - Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9)); -} - - -int print_msg_table_header (int rptcode, char *HdrStr, int force) -{ - /* force header is to help auto-output function */ - /* last_rptcode is to determine whether to print a header */ - /* for the first occurrence of a series of reports */ - static int - last_rptcode = 0; - int - numchars; - - numchars = 0; - if (force || rptcode!=last_rptcode) - { - /* supply a header in console output */ - switch (rptcode) - { - case 0x5A: - numchars = sprintf(HdrStr, "\nRaw Measurement Data"); - numchars += sprintf(HdrStr+numchars, - "\n SV Sample SNR Code Phase Doppler Seconds Time of Meas"); - break; - - case 0x5B: - numchars = sprintf(HdrStr, "\nEphemeris Status"); - numchars += sprintf(HdrStr+numchars, - "\n SV Time collected Health IODE t oe Fit URA"); - break; - - case 0x5C: - numchars = sprintf(HdrStr, "\nTracking Info"); - numchars += sprintf(HdrStr+numchars, - "\n SV C Acq Eph SNR Time of Meas Elev Azim "); - break; - - } - } - last_rptcode = rptcode; - return (short)numchars; -} - -static void unknown_rpt (TSIPPKT *rpt) -{ - int i; - - /* app-specific rpt packets */ - if (parsed == BADLEN_PARSE) - { - pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length", - rpt->code, rpt->len); - } - if (parsed == BADID_PARSE) - { - pbuf += sprintf(pbuf, - "\nTSIP report packet ID %2Xh, length %d: translation not supported", - rpt->code, rpt->len); - } - - if (parsed == BADDATA_PARSE) - { - pbuf += sprintf(pbuf, - "\nTSIP report packet ID %2Xh, length %d: data content incorrect", - rpt->code, rpt->len); - } - - for (i = 0; i < rpt->len; i++) { - if ((i % 20) == 0) *pbuf++ = '\n'; - pbuf += sprintf(pbuf, " %02X", rpt->buf[i]); - } -} -/**/ -/* -** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit() -*/ -void TranslateTSIPReportToText (TSIPPKT *rpt, char *TextOutputBuffer) -{ - - /* pbuf is the pointer to the current location of the text output */ - pbuf = TextOutputBuffer; - - /* keep track of whether the message has been successfully parsed */ - parsed = GOOD_PARSE; - - /* print a header if this is the first of a series of messages */ - pbuf += print_msg_table_header (rpt->code, pbuf, FALSE); - - /* process incoming TSIP report according to code */ - switch (rpt->code) - { - case 0x3D: rpt_chan_A_config (rpt); break; - case 0x40: rpt_almanac_data_page (rpt); break; - case 0x41: rpt_GPS_time (rpt); break; - case 0x42: rpt_single_ECEF_position (rpt); break; - case 0x43: rpt_single_ECEF_velocity (rpt); break; - case 0x45: rpt_SW_version (rpt); break; - case 0x46: rpt_rcvr_health (rpt); break; - case 0x47: rpt_SNR_all_SVs (rpt); break; - case 0x48: rpt_GPS_system_message (rpt); break; - case 0x49: rpt_almanac_health_page (rpt); break; - case 0x4A: switch (rpt->len) { - /* - ** special case (=slip-up) in the TSIP protocol; - ** parsing method depends on length - */ - case 20: rpt_single_lla_position (rpt); break; - case 9: rpt_ref_alt (rpt); break; - } break; - case 0x4B: rpt_rcvr_id_and_status (rpt);break; - case 0x4C: rpt_operating_parameters (rpt); break; - case 0x4D: rpt_oscillator_offset (rpt); break; - case 0x4E: rpt_GPS_time_set_response (rpt); break; - case 0x4F: rpt_UTC_offset (rpt); break; - case 0x54: rpt_1SV_bias (rpt); break; - case 0x55: rpt_io_opt (rpt); break; - case 0x56: rpt_ENU_velocity (rpt); break; - case 0x57: rpt_last_fix_info (rpt); break; - case 0x58: rpt_GPS_system_data (rpt); break; - case 0x59: rpt_SVs_enabled (rpt); break; - case 0x5A: rpt_raw_msmt (rpt); break; - case 0x5B: rpt_SV_ephemeris_status (rpt); break; - case 0x5C: rpt_SV_tracking_status (rpt); break; - case 0x6D: rpt_allSV_selection (rpt); break; - case 0x82: rpt_DGPS_position_mode (rpt); break; - case 0x83: rpt_double_ECEF_position (rpt); break; - case 0x84: rpt_double_lla_position (rpt); break; - case 0xBB: rpt_complete_rcvr_config (rpt); break; - case 0xBC: rpt_rcvr_serial_port_config (rpt); break; - - case 0x8F: switch (rpt->buf[0]) - { - /* superpackets; parsed according to subcodes */ - case 0x0B: rpt_8F0B(rpt); break; - case 0x14: rpt_8F14(rpt); break; - case 0x15: rpt_8F15(rpt); break; - case 0x20: rpt_8F20(rpt); break; - case 0x41: rpt_8F41(rpt); break; - case 0x42: rpt_8F42(rpt); break; - case 0x45: rpt_8F45(rpt); break; - case 0x4A: rpt_8F4A(rpt); break; - case 0x4B: rpt_8F4B(rpt); break; - case 0x4D: rpt_8F4D(rpt); break; - case 0xA5: rpt_8FA5(rpt); break; - case 0xAD: rpt_8FAD(rpt); break; - default: parsed = BADID_PARSE; break; - } - break; - - default: parsed = BADID_PARSE; break; - } - - if (parsed != GOOD_PARSE) - { - /* - **The message has TSIP structure (DLEs, etc.) - ** but could not be parsed by above routines - */ - unknown_rpt (rpt); - } - - /* close TextOutputBuffer */ - pbuf = '\0'; -} - -#endif /* TRIMBLE_OUTPUT_FUNC */ - -#else /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */ -int refclock_ripencc_bs; -#endif /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */ - diff --git a/contrib/ntp/ntpd/refclock_shm.c b/contrib/ntp/ntpd/refclock_shm.c deleted file mode 100644 index 4ab0ede..0000000 --- a/contrib/ntp/ntpd/refclock_shm.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * refclock_shm - clock driver for utc via shared memory - * - under construction - - * To add new modes: Extend or union the shmTime-struct. Do not - * extend/shrink size, because otherwise existing implementations - * will specify wrong size of shared memory-segment - * PB 18.3.97 - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_SHM) - -#include "ntpd.h" -#undef fileno -#include "ntp_io.h" -#undef fileno -#include "ntp_refclock.h" -#undef fileno -#include "ntp_unixtime.h" -#undef fileno -#include "ntp_stdlib.h" - -#undef fileno -#include <ctype.h> -#undef fileno - -#ifndef SYS_WINNT -# include <sys/ipc.h> -# include <sys/shm.h> -# include <assert.h> -# include <unistd.h> -# include <stdio.h> -#endif - -/* - * This driver supports a reference clock attached thru shared memory - */ - -/* - * SHM interface definitions - */ -#define PRECISION (-1) /* precision assumed (0.5 s) */ -#define REFID "SHM" /* reference ID */ -#define DESCRIPTION "SHM/Shared memory interface" - -#define NSAMPLES 3 /* stages of median filter */ - -/* - * Function prototypes - */ -static int shm_start (int, struct peer *); -static void shm_shutdown (int, struct peer *); -static void shm_poll (int unit, struct peer *); - -/* - * Transfer vector - */ -struct refclock refclock_shm = { - shm_start, /* start up driver */ - shm_shutdown, /* shut down driver */ - shm_poll, /* transmit poll message */ - noentry, /* not used */ - noentry, /* initialize driver (not used) */ - noentry, /* not used */ - NOFLAGS /* not used */ -}; -struct shmTime { - int mode; /* 0 - if valid set - * use values, - * clear valid - * 1 - if valid set - * if count before and after read of values is equal, - * use values - * clear valid - */ - int count; - time_t clockTimeStampSec; - int clockTimeStampUSec; - time_t receiveTimeStampSec; - int receiveTimeStampUSec; - int leap; - int precision; - int nsamples; - int valid; - int dummy[10]; -}; - -struct shmTime *getShmTime(int); - -struct shmTime *getShmTime (int unit) { -#ifndef SYS_WINNT - int shmid=0; - - assert (unit<10); /* MAXUNIT is 4, so should never happen */ - shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), - IPC_CREAT|(unit<2?0700:0777)); - if (shmid==-1) { /*error */ - msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno)); - return 0; - } - else { /* no error */ - struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); - if ((int)(long)p==-1) { /* error */ - msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno)); - return 0; - } - return p; - } -#else - char buf[10]; - LPSECURITY_ATTRIBUTES psec=0; - HANDLE shmid=0; - SECURITY_DESCRIPTOR sd; - SECURITY_ATTRIBUTES sa; - sprintf (buf,"NTP%d",unit); - if (unit>=2) { /* world access */ - if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { - msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit); - return 0; - } - if (!SetSecurityDescriptorDacl(&sd,1,0,0)) { - msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit); - return 0; - } - sa.nLength=sizeof (SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor=&sd; - sa.bInheritHandle=0; - psec=&sa; - } - shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, - 0, sizeof (struct shmTime),buf); - if (!shmid) { /*error*/ - char buf[1000]; - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, - 0, GetLastError (), 0, buf, sizeof (buf), 0); - msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf); - return 0; - } - else { - struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, - FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); - if (p==0) { /*error*/ - char buf[1000]; - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, - 0, GetLastError (), 0, buf, sizeof (buf), 0); - msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf); - return 0; - } - return p; - } -#endif -} -/* - * shm_start - attach to shared memory - */ -static int -shm_start( - int unit, - struct peer *peer - ) -{ - struct refclockproc *pp; - 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)getShmTime(unit); - - /* - * Initialize miscellaneous peer variables - */ - memcpy((char *)&pp->refid, REFID, 4); - if (pp->unitptr!=0) { - ((struct shmTime*)pp->unitptr)->precision=PRECISION; - peer->precision = ((struct shmTime*)pp->unitptr)->precision; - ((struct shmTime*)pp->unitptr)->valid=0; - ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES; - pp->clockdesc = DESCRIPTION; - return (1); - } - else { - return 0; - } -} - - -/* - * shm_shutdown - shut down the clock - */ -static void -shm_shutdown( - int unit, - struct peer *peer - ) -{ - register struct shmTime *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct shmTime *)pp->unitptr; -#ifndef SYS_WINNT - /* HMS: shmdt()wants char* or const void * */ - (void) shmdt (up); -#else - UnmapViewOfFile (up); -#endif -} - - -/* - * shm_poll - called by the transmit procedure - */ -static void -shm_poll( - int unit, - struct peer *peer - ) -{ - register struct shmTime *up; - struct refclockproc *pp; - - /* - * This is the main routine. It snatches the time from the shm - * board and tacks on a local timestamp. - */ - pp = peer->procptr; - up = (struct shmTime*)pp->unitptr; - if (up==0) { /* try to map again - this may succeed if meanwhile some- - body has ipcrm'ed the old (unaccessible) shared mem - segment */ - pp->unitptr = (caddr_t)getShmTime(unit); - up = (struct shmTime*)pp->unitptr; - } - if (up==0) { - refclock_report(peer, CEVNT_FAULT); - return; - } - if (up->valid) { - struct timeval tvr; - struct timeval tvt; - struct tm *t; - int ok=1; - switch (up->mode) { - case 0: { - tvr.tv_sec=up->receiveTimeStampSec; - tvr.tv_usec=up->receiveTimeStampUSec; - tvt.tv_sec=up->clockTimeStampSec; - tvt.tv_usec=up->clockTimeStampUSec; - } - break; - case 1: { - int cnt=up->count; - tvr.tv_sec=up->receiveTimeStampSec; - tvr.tv_usec=up->receiveTimeStampUSec; - tvt.tv_sec=up->clockTimeStampSec; - tvt.tv_usec=up->clockTimeStampUSec; - ok=(cnt==up->count); - } - break; - default: - msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode); - } - up->valid=0; - if (ok) { - TVTOTS(&tvr,&pp->lastrec); - pp->lastrec.l_ui += JAN_1970; - /* pp->lasttime = current_time; */ - pp->polls++; - t=gmtime (&tvt.tv_sec); - pp->day=t->tm_yday+1; - pp->hour=t->tm_hour; - pp->minute=t->tm_min; - pp->second=t->tm_sec; - pp->nsec=tvt.tv_usec * 1000; - peer->precision=up->precision; - pp->leap=up->leap; - } - else { - refclock_report(peer, CEVNT_FAULT); - msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); - return; - } - } - else { - refclock_report(peer, CEVNT_TIMEOUT); - /* - msyslog (LOG_NOTICE, "SHM: no new value found in shared memory"); - */ - return; - } - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); -} - -#else -int refclock_shm_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_tpro.c b/contrib/ntp/ntpd/refclock_tpro.c deleted file mode 100644 index 3c42568..0000000 --- a/contrib/ntp/ntpd/refclock_tpro.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_TPRO) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_unixtime.h" -#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 - * tpro.o device driver be installed and loaded. - */ - -/* - * TPRO interface definitions - */ -#define DEVICE "/dev/tpro%d" /* device name and unit */ -#define PRECISION (-20) /* precision assumed (1 us) */ -#define REFID "IRIG" /* reference ID */ -#define DESCRIPTION "KSI/Odetics TPRO/S IRIG Interface" /* WRU */ - -/* - * Unit control structure - */ -struct tprounit { - struct tproval tprodata; /* data returned from tpro read */ -}; - -/* - * Function prototypes - */ -static int tpro_start P((int, struct peer *)); -static void tpro_shutdown P((int, struct peer *)); -static void tpro_poll P((int unit, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_tpro = { - tpro_start, /* start up driver */ - tpro_shutdown, /* shut down driver */ - tpro_poll, /* transmit poll message */ - noentry, /* not used (old tpro_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old tpro_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * tpro_start - open the TPRO device and initialize data for processing - */ -static int -tpro_start( - int unit, - struct peer *peer - ) -{ - register struct tprounit *up; - struct refclockproc *pp; - char device[20]; - int fd; - - /* - * Open TPRO device - */ - (void)sprintf(device, DEVICE, unit); - fd = open(device, O_RDONLY | O_NDELAY, 0777); - if (fd == -1) { - msyslog(LOG_ERR, "tpro_start: open of %s: %m", device); - return (0); - } - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct tprounit *) emalloc(sizeof(struct tprounit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct tprounit)); - pp = peer->procptr; - pp->io.clock_recv = noentry; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous peer variables - */ - peer->precision = PRECISION; - peer->burst = NSTAGE; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - return (1); -} - - -/* - * tpro_shutdown - shut down the clock - */ -static void -tpro_shutdown( - int unit, - struct peer *peer - ) -{ - register struct tprounit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct tprounit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * tpro_poll - called by the transmit procedure - */ -static void -tpro_poll( - int unit, - struct peer *peer - ) -{ - register struct tprounit *up; - struct refclockproc *pp; - struct tproval *tp; - - /* - * This is the main routine. It snatches the time from the TPRO - * board and tacks on a local timestamp. - */ - pp = peer->procptr; - up = (struct tprounit *)pp->unitptr; - - tp = &up->tprodata; - if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) { - refclock_report(peer, CEVNT_FAULT); - return; - } - get_systime(&pp->lastrec); - pp->polls++; - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. Note: we - * can't use the sec/usec conversion produced by the driver, - * since the year may be suspect. All format error checking is - * done by the sprintf() and sscanf() routines. - * - * Note that the refclockproc usec member has now become nsec. - * We could either multiply the read-in usec value by 1000 or - * we could pad the written string appropriately and read the - * resulting value in already scaled. - */ - sprintf(pp->a_lastcode, - "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", - tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1, - tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100, - tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1, - tp->status); - pp->lencode = strlen(pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("tpro: time %s timecode %d %s\n", - ulfptoa(&pp->lastrec, 6), pp->lencode, - pp->a_lastcode); -#endif - if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day, - &pp->hour, &pp->minute, &pp->second, &pp->nsec) - != 5) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->nsec *= 1000; /* Convert usec to nsec */ - if (!tp->status & 0x3) - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - refclock_receive(peer); - pp->lastref = pp->lastrec; - record_clock_stats(&peer->srcadr, pp->a_lastcode); - refclock_receive(peer); - peer->burst = NSTAGE; -} - -#else -int refclock_tpro_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_trak.c b/contrib/ntp/ntpd/refclock_trak.c deleted file mode 100644 index 3a4a54e..0000000 --- a/contrib/ntp/ntpd/refclock_trak.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * refclock_trak - clock driver for the TRAK 8810 GPS Station Clock - * - * Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp> - * original version Dec, 1993 - * revised version Sep, 1994 for ntp3.4e or later - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_TRAK) && defined(PPS) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" -#include "ntp_unixtime.h" - -#include <stdio.h> -#include <ctype.h> - -#ifdef HAVE_SYS_TERMIOS_H -# include <sys/termios.h> -#endif -#ifdef HAVE_SYS_PPSCLOCK_H -# include <sys/ppsclock.h> -#endif - -/* - * This driver supports the TRAK 8810/8820 GPS Station Clock. The claimed - * accuracy at the 1-pps output is 200-300 ns relative to the broadcast - * signal; however, in most cases the actual accuracy is limited by the - * precision of the timecode and the latencies of the serial interface - * and operating system. - * - * For best accuracy, this radio requires the LDISC_ACTS line - * discipline, which captures a timestamp at the '*' on-time character - * of the timecode. Using this discipline the jitter is in the order of - * 1 ms and systematic error about 0.5 ms. If unavailable, the buffer - * timestamp is used, which is captured at the \r ending the timecode - * message. This introduces a systematic error of 23 character times, or - * about 24 ms at 9600 bps, together with a jitter well over 8 ms on Sun - * IPC-class machines. - * - * Using the memus, the radio should be set for 9600 bps, one stop bit - * and no parity. It should be set to operate in computer (no echo) - * mode. The timecode format includes neither the year nor leap-second - * warning. No provisions are included in this preliminary version of - * the driver to read and record detailed internal radio status. - * - * In operation, this driver sends a RQTS\r request to the radio at - * initialization in order to put it in continuous time output mode. The - * radio then sends the following message once each second: - * - * *RQTS U,ddd:hh:mm:ss.0,q<cr><lf> - * - * on-time = '*' * ddd = day of year - * hh:mm:ss = hours, minutes, seconds - * q = quality indicator (phase error), 0-6: - * 0 > 20 us - * 6 > 10 us - * 5 > 1 us - * 4 > 100 ns - * 3 > 10 ns - * 2 < 10 ns - * - * The alarm condition is indicated by '0' at Q, which means the radio - * has a phase error than 20 usec relative to the broadcast time. The - * absence of year, DST and leap-second warning in this format is also - * alarming. - * - * The continuous time mode is disabled using the RQTX<cr> request, - * following which the radio sends a RQTX DONE<cr><lf> response. In the - * normal mode, other control and status requests are effective, - * including the leap-second status request RQLS<cr>. The radio responds - * wtih RQLS yy,mm,dd<cr><lf>, where yy,mm,dd are the year, month and - * day. Presumably, this gives the epoch of the next leap second, - * RQLS 00,00,00 if none is specified in the GPS message. Specified in - * this form, the information is generally useless and is ignored by - * the driver. - * - * Fudge Factors - * - * There are no special fudge factors other than the generic. - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/trak%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS\0" /* reference ID */ -#define DESCRIPTION "TRACK 8810/8820 Station Clock" /* WRU */ - -#define LENTRAK 24 /* timecode length */ -#define C_CTO "RQTS\r" /* start continuous time output */ - -/* - * Unit control structure - */ -struct trakunit { - int polled; /* poll message flag */ - l_fp tstamp; /* timestamp of last poll */ -}; - -/* - * Function prototypes - */ -static int trak_start P((int, struct peer *)); -static void trak_shutdown P((int, struct peer *)); -static void trak_receive P((struct recvbuf *)); -static void trak_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_trak = { - trak_start, /* start up driver */ - trak_shutdown, /* shut down driver */ - trak_poll, /* transmit poll message */ - noentry, /* not used (old trak_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old trak_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * trak_start - open the devices and initialize data for processing - */ -static int -trak_start( - int unit, - struct peer *peer - ) -{ - register struct trakunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. The LDISC_ACTS line discipline inserts a - * timestamp following the "*" on-time character of the - * timecode. - */ - (void)sprintf(device, DEVICE, unit); - if ( -#ifdef PPS - !(fd = refclock_open(device, SPEED232, LDISC_CLK)) -#else - !(fd = refclock_open(device, SPEED232, 0)) -#endif /* PPS */ - ) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct trakunit *) - emalloc(sizeof(struct trakunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct trakunit)); - pp = peer->procptr; - pp->io.clock_recv = trak_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->polled = 0; - - /* - * Start continuous time output. If something breaks, fold the - * tent and go home. - */ - if (write(pp->io.fd, C_CTO, sizeof(C_CTO)) != sizeof(C_CTO)) { - refclock_report(peer, CEVNT_FAULT); - (void) close(fd); - free(up); - return (0); - } - return (1); -} - - -/* - * trak_shutdown - shut down the clock - */ -static void -trak_shutdown( - int unit, - struct peer *peer - ) -{ - register struct trakunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct trakunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * trak_receive - receive data from the serial interface - */ -static void -trak_receive( - struct recvbuf *rbufp - ) -{ - register struct trakunit *up; - struct refclockproc *pp; - struct peer *peer; - l_fp trtmp; - char *dpt, *dpend; - char qchar; -#ifdef PPS - struct ppsclockev ppsev; - int request; -#ifdef HAVE_CIOGETEV - request = CIOGETEV; -#endif -#ifdef HAVE_TIOCGPPSEV - request = TIOCGPPSEV; -#endif -#endif /* PPS */ - - /* - * Initialize pointers and read the timecode and timestamp. We - * then chuck out everything, including runts, except one - * message each poll interval. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct trakunit *)pp->unitptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, - &pp->lastrec); - - /* - * We get a buffer and timestamp following the '*' on-time - * character. If a valid timestamp, we use that in place of the - * buffer timestamp and edit out the timestamp for prettyprint - * billboards. - */ - dpt = pp->a_lastcode; - dpend = dpt + pp->lencode; - if (*dpt == '*' && buftvtots(dpt + 1, &trtmp)) { - if (trtmp.l_i == pp->lastrec.l_i || trtmp.l_i == - pp->lastrec.l_i + 1) { - pp->lastrec = trtmp; - dpt += 9; - while (dpt < dpend) { - *(dpt - 8) = *dpt; - ++dpt; - } - } - } - if (up->polled == 0) return; - up->polled = 0; -#ifndef PPS - get_systime(&up->tstamp); -#endif - record_clock_stats(&peer->srcadr, pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("trak: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. - */ - if (pp->lencode < LENTRAK) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Timecode format: "*RQTS U,ddd:hh:mm:ss.0,q" - */ - if (sscanf(pp->a_lastcode, "*RQTS U,%3d:%2d:%2d:%2d.0,%c", - &pp->day, &pp->hour, &pp->minute, &pp->second, &qchar) != 5) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - /* - * Decode quality and leap characters. If unsynchronized, set - * the leap bits accordingly and exit. - */ - if (qchar == '0') { - pp->leap = LEAP_NOTINSYNC; - return; - } -#ifdef PPS - if(ioctl(fdpps,request,(caddr_t) &ppsev) >=0) { - ppsev.tv.tv_sec += (u_int32) JAN_1970; - TVTOTS(&ppsev.tv,&up->tstamp); - } -#endif /* PPS */ - /* record the last ppsclock event time stamp */ - pp->lastrec = up->tstamp; - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); -} - - -/* - * trak_poll - called by the transmit procedure - */ -static void -trak_poll( - int unit, - struct peer *peer - ) -{ - register struct trakunit *up; - struct refclockproc *pp; - - /* - * We don't really do anything here, except arm the receiving - * side to capture a sample and check for timeouts. - */ - pp = peer->procptr; - up = (struct trakunit *)pp->unitptr; - if (up->polled) - refclock_report(peer, CEVNT_TIMEOUT); - pp->polls++; - up->polled = 1; -} - -#else -int refclock_trak_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_true.c b/contrib/ntp/ntpd/refclock_true.c deleted file mode 100644 index dd355d9..0000000 --- a/contrib/ntp/ntpd/refclock_true.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * refclock_true - clock driver for the Kinemetrics Truetime receivers - * Receiver Version 3.0C - tested plain, with CLKLDISC - * Developement work being done: - * - Properly handle varying satellite positions (more acurately) - * - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_TRUETIME) - -#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 - * of TTL input and output pins, all brought out to the back panel. If you - * wire a PPS signal (such as the TTL PPS coming out of a GOES or other - * Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the - * 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the - * number of uSecs since the last PPS upward swing, mediated by reading OUT0 - * to find out if the counter has wrapped around (this happens if more than - * 65535us (65ms) elapses between the PPS event and our being called.) - */ -#ifdef CLOCK_PPS720 -# undef min /* XXX */ -# undef max /* XXX */ -# include <machine/inline.h> -# include <sys/pcl720.h> -# include <sys/i8253.h> -# define PCL720_IOB 0x2a0 /* XXX */ -# define PCL720_CTR 0 /* XXX */ -#endif - -/* - * Support for Kinemetrics Truetime Receivers - * GOES - * GPS/TM-TMD - * XL-DC (a 151-602-210, reported by the driver as a GPS/TM-TMD) - * GPS-800 TCU (an 805-957 with the RS232 Talker/Listener module) - * OM-DC: getting stale ("OMEGA") - * - * Most of this code is originally from refclock_wwvb.c with thanks. - * It has been so mangled that wwvb is not a recognizable ancestor. - * - * Timcode format: ADDD:HH:MM:SSQCL - * A - control A (this is stripped before we see it) - * Q - Quality indication (see below) - * C - Carriage return - * L - Line feed - * - * Quality codes indicate possible error of - * 468-DC GOES 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 - * A-H less than 1 millisecond. Character indicates which station - * is being received as follows: - * A = Norway, B = Liberia, C = Hawaii, D = North Dakota, - * E = La Reunion, F = Argentina, G = Australia, H = Japan. - * - * The carriage return start bit begins on 0 seconds and extends to 1 bit time. - * - * Notes on 468-DC and OMEGA receiver: - * - * Send the clock a 'R' or 'C' and once per second a timestamp will - * appear. Send a 'P' to get the satellite position once (GOES only.) - * - * Notes on the 468-DC receiver: - * - * Since the old east/west satellite locations are only historical, you can't - * set your clock propagation delay settings correctly and still use - * automatic mode. The manual says to use a compromise when setting the - * switches. This results in significant errors. The solution; use fudge - * time1 and time2 to incorporate corrections. If your clock is set for - * 50 and it should be 58 for using the west and 46 for using the east, - * use the line - * - * fudge 127.127.5.0 time1 +0.008 time2 -0.004 - * - * This corrects the 4 milliseconds advance and 8 milliseconds retard - * needed. The software will ask the clock which satellite it sees. - * - * Ntp.conf parameters: - * time1 - offset applied to samples when reading WEST satellite (default = 0) - * time2 - offset applied to samples when reading EAST satellite (default = 0) - * val1 - stratum to assign to this clock (default = 0) - * val2 - refid assigned to this clock (default = "TRUE", see below) - * flag1 - will silence the clock side of ntpd, just reading the clock - * without trying to write to it. (default = 0) - * flag2 - generate a debug file /tmp/true%d. - * flag3 - enable ppsclock streams module - * flag4 - use the PCL-720 (BSD/OS only) - */ - - -/* - * Definitions - */ -#define DEVICE "/dev/true%d" -#define SPEED232 B9600 /* 9600 baud */ - -/* - * Radio interface parameters - */ -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define REFID "TRUE" /* reference id */ -#define DESCRIPTION "Kinemetrics/TrueTime Receiver" - -/* - * Tags which station (satellite) we see - */ -#define GOES_WEST 0 /* Default to WEST satellite and apply time1 */ -#define GOES_EAST 1 /* until you discover otherwise */ - -/* - * used by the state machine - */ -enum true_event {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite, - e_Poll, e_Location, e_TS, e_Max}; -const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite", - "Poll", "Location", "TS"}; -#define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?") - -enum true_state {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES, - s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max}; -const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES", - "Init", "F18", "F50", "Start", "Auto"}; -#define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?") - -enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max}; -const char *types[] = {"unknown", "goes", "tm", "tcu", "omega"}; -#define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?") - -/* - * unit control structure - */ -struct true_unit { - unsigned int pollcnt; /* poll message counter */ - unsigned int station; /* which station we are on */ - unsigned int polled; /* Hand in a time sample? */ - enum true_state state; /* state machine */ - enum true_type type; /* what kind of clock is it? */ - int unit; /* save an extra copy of this */ - FILE *debug; /* debug logging file */ -#ifdef CLOCK_PPS720 - int pcl720init; /* init flag for PCL 720 */ -#endif -}; - -/* - * Function prototypes - */ -static int true_start P((int, struct peer *)); -static void true_shutdown P((int, struct peer *)); -static void true_receive P((struct recvbuf *)); -static void true_poll P((int, struct peer *)); -static void true_send P((struct peer *, const char *)); -static void true_doevent P((struct peer *, enum true_event)); - -#ifdef CLOCK_PPS720 -static u_long true_sample720 P((void)); -#endif - -/* - * Transfer vector - */ -struct refclock refclock_true = { - true_start, /* start up driver */ - true_shutdown, /* shut down driver */ - true_poll, /* transmit poll message */ - noentry, /* not used (old true_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old true_buginfo) */ - NOFLAGS /* not used */ -}; - - -#if !defined(__STDC__) -# define true_debug (void) -#else -static void -true_debug(struct peer *peer, const char *fmt, ...) -{ - va_list ap; - int want_debugging, now_debugging; - struct refclockproc *pp; - struct true_unit *up; - - va_start(ap, fmt); - pp = peer->procptr; - up = (struct true_unit *)pp->unitptr; - - want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0; - now_debugging = (up->debug != NULL); - if (want_debugging != now_debugging) - { - if (want_debugging) { - char filename[40]; - int fd; - - snprintf(filename, sizeof(filename), "/tmp/true%d.debug", up->unit); - fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0600); - if (fd >= 0 && (up->debug = fdopen(fd, "r+"))) { -#ifdef HAVE_SETVBUF - static char buf[BUFSIZ]; - setvbuf(up->debug, buf, _IOLBF, BUFSIZ); -#else - setlinebuf(up->debug); -#endif - } - } else { - fclose(up->debug); - up->debug = NULL; - } - } - - if (up->debug) { - fprintf(up->debug, "true%d: ", up->unit); - vfprintf(up->debug, fmt, ap); - } -} -#endif /*STDC*/ - -/* - * true_start - open the devices and initialize data for processing - */ -static int -true_start( - int unit, - struct peer *peer - ) -{ - register struct true_unit *up; - struct refclockproc *pp; - char device[40]; - int fd; - - /* - * Open serial port - */ - (void)snprintf(device, sizeof(device), DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct true_unit *) - emalloc(sizeof(struct true_unit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct true_unit)); - pp = peer->procptr; - pp->io.clock_recv = true_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->pollcnt = 2; - up->type = t_unknown; - up->state = s_Base; - true_doevent(peer, e_Init); - return (1); -} - -/* - * true_shutdown - shut down the clock - */ -static void -true_shutdown( - int unit, - struct peer *peer - ) -{ - register struct true_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct true_unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * true_receive - receive data from the serial interface on a clock - */ -static void -true_receive( - struct recvbuf *rbufp - ) -{ - register struct true_unit *up; - struct refclockproc *pp; - struct peer *peer; - u_short new_station; - 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. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct true_unit *)pp->unitptr; - - /* - * Read clock output. Automatically handles STREAMS, CLKLDISC. - */ - rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); - rd_lastcode[rd_lencode] = '\0'; - - /* - * There is a case where <cr><lf> generates 2 timestamps. - */ - if (rd_lencode == 0) - return; - pp->lencode = rd_lencode; - strcpy(pp->a_lastcode, rd_lastcode); - pp->lastrec = rd_tmp; - true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode); - - up->pollcnt = 2; - record_clock_stats(&peer->srcadr, pp->a_lastcode); - - /* - * We get down to business, check the timecode format and decode - * its contents. This code decodes a multitude of different - * clock messages. Timecodes are processed if needed. All replies - * will be run through the state machine to tweak driver options - * and program the clock. - */ - - /* - * Clock misunderstood our last command? - */ - if (pp->a_lastcode[0] == '?' || - strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) { - true_doevent(peer, e_Huh); - return; - } - - /* - * Timecode: "nnnnn+nnn-nnn" - * (from GOES clock when asked about satellite position) - */ - if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') && - (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') && - sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3 - ) { - const char *label = "Botch!"; - - /* - * This is less than perfect. Call the (satellite) - * either EAST or WEST and adjust slop accodingly - * Perfectionists would recalculate the exact delay - * and adjust accordingly... - */ - if (lon > 7000 && lon < 14000) { - if (lon < 10000) { - new_station = GOES_EAST; - label = "EAST"; - } else { - new_station = GOES_WEST; - label = "WEST"; - } - - if (new_station != up->station) { - double dtemp; - - dtemp = pp->fudgetime1; - pp->fudgetime1 = pp->fudgetime2; - pp->fudgetime2 = dtemp; - up->station = new_station; - } - } - else { - /*refclock_report(peer, CEVNT_BADREPLY);*/ - label = "UNKNOWN"; - } - true_debug(peer, "GOES: station %s\n", label); - true_doevent(peer, e_Satellite); - return; - } - - /* - * Timecode: "Fnn" - * (from TM/TMD clock when it wants to tell us what it's up to.) - */ - if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) { - switch (i) { - case 50: - true_doevent(peer, e_F50); - break; - case 51: - true_doevent(peer, e_F51); - break; - default: - true_debug(peer, "got F%02d - ignoring\n", i); - break; - } - return; - } - - /* - * Timecode: " TRUETIME Mk III" or " TRUETIME XL" - * (from a TM/TMD/XL clock during initialization.) - */ - if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 || - strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) { - true_doevent(peer, e_F18); - NLOG(NLOG_CLOCKSTATUS) { - msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode); - } - return; - } - - /* - * Timecode: "N03726428W12209421+000033" - * 1 2 - * 0123456789012345678901234 - * (from a TCU during initialization) - */ - if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') && - (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') && - pp->a_lastcode[18] == '+') { - true_doevent(peer, e_Location); - NLOG(NLOG_CLOCKSTATUS) { - msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode); - } - return; - } - /* - * Timecode: "ddd:hh:mm:ssQ" - * (from all clocks supported by this driver.) - */ - if (pp->a_lastcode[3] == ':' && - pp->a_lastcode[6] == ':' && - pp->a_lastcode[9] == ':' && - sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c", - &pp->day, &pp->hour, &pp->minute, - &pp->second, &synced) == 5) { - - /* - * Adjust the synchronize indicator according to timecode - * say were OK, and then say not if we really are not OK - */ - if (synced == '>' || synced == '#' || synced == '?') - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; - - true_doevent(peer, e_TS); - -#ifdef CLOCK_PPS720 - /* If it's taken more than 65ms to get here, we'll lose. */ - if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) { - l_fp off; - -#ifdef CLOCK_ATOM - /* - * find out what time it really is. Include - * the count from the PCL720 - */ - if (!clocktime(pp->day, pp->hour, pp->minute, - pp->second, GMT, pp->lastrec.l_ui, - &pp->yearstart, &off.l_ui)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - off.l_uf = 0; -#endif - - pp->usec = true_sample720(); -#ifdef CLOCK_ATOM - TVUTOTSF(pp->usec, off.l_uf); -#endif - - /* - * Stomp all over the timestamp that was pulled out - * of the input stream. It's irrelevant since we've - * adjusted the input time to reflect now (via pp->usec) - * rather than when the data was collected. - */ - get_systime(&pp->lastrec); -#ifdef CLOCK_ATOM - /* - * Create a true offset for feeding to pps_sample() - */ - L_SUB(&off, &pp->lastrec); - - pps_sample(peer, &off); -#endif - true_debug(peer, "true_sample720: %luus\n", pp->usec); - } -#endif - - /* - * The clock will blurt a timecode every second but we only - * want one when polled. If we havn't been polled, bail out. - */ - if (!up->polled) - return; - - true_doevent(peer, e_Poll); - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - /* - * If clock is good we send a NOMINAL message so that - * any previous BAD messages are nullified - */ - pp->lastref = pp->lastrec; - refclock_receive(peer); - refclock_report(peer, CEVNT_NOMINAL); - - /* - * We have succedded in answering the poll. - * Turn off the flag and return - */ - up->polled = 0; - - return; - } - - /* - * No match to known timecodes, report failure and return - */ - refclock_report(peer, CEVNT_BADREPLY); - return; -} - - -/* - * true_send - time to send the clock a signal to cough up a time sample - */ -static void -true_send( - struct peer *peer, - const char *cmd - ) -{ - struct refclockproc *pp; - - pp = peer->procptr; - if (!(pp->sloppyclockflag & CLK_FLAG1)) { - register int len = strlen(cmd); - - true_debug(peer, "Send '%s'\n", cmd); - if (write(pp->io.fd, cmd, (unsigned)len) != len) - refclock_report(peer, CEVNT_FAULT); - else - pp->polls++; - } -} - - -/* - * state machine for initializing and controlling a clock - */ -static void -true_doevent( - struct peer *peer, - enum true_event event - ) -{ - struct true_unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct true_unit *)pp->unitptr; - if (event != e_TS) { - NLOG(NLOG_CLOCKSTATUS) { - msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s", - typeStr(up->type), - stateStr(up->state), - eventStr(event)); - } - } - true_debug(peer, "clock %s, state %s, event %s\n", - typeStr(up->type), stateStr(up->state), eventStr(event)); - switch (up->type) { - case t_goes: - switch (event) { - case e_Init: /* FALLTHROUGH */ - case e_Satellite: - /* - * Switch back to on-second time codes and return. - */ - true_send(peer, "C"); - up->state = s_Start; - break; - case e_Poll: - /* - * After each poll, check the station (satellite). - */ - true_send(peer, "P"); - /* No state change needed. */ - break; - default: - break; - } - /* FALLTHROUGH */ - case t_omega: - switch (event) { - case e_Init: - true_send(peer, "C"); - up->state = s_Start; - break; - case e_TS: - if (up->state != s_Start && up->state != s_Auto) { - true_send(peer, "\03\r"); - break; - } - up->state = s_Auto; - break; - default: - break; - } - break; - case t_tm: - switch (event) { - case e_Init: - true_send(peer, "F18\r"); - up->state = s_Init; - break; - case e_F18: - true_send(peer, "F50\r"); - up->state = s_F18; - break; - case e_F50: - true_send(peer, "F51\r"); - up->state = s_F50; - break; - case e_F51: - true_send(peer, "F08\r"); - up->state = s_Start; - break; - case e_TS: - if (up->state != s_Start && up->state != s_Auto) { - true_send(peer, "\03\r"); - break; - } - up->state = s_Auto; - break; - default: - break; - } - break; - case t_tcu: - switch (event) { - case e_Init: - true_send(peer, "MD3\r"); /* GPS Synch'd Gen. */ - true_send(peer, "TSU\r"); /* UTC, not GPS. */ - true_send(peer, "AU\r"); /* Auto Timestamps. */ - up->state = s_Start; - break; - case e_TS: - if (up->state != s_Start && up->state != s_Auto) { - true_send(peer, "\03\r"); - break; - } - up->state = s_Auto; - break; - default: - break; - } - break; - case t_unknown: - switch (up->state) { - case s_Base: - if (event != e_Init) - abort(); - true_send(peer, "P\r"); - up->state = s_InqGOES; - break; - case s_InqGOES: - switch (event) { - case e_Satellite: - up->type = t_goes; - true_doevent(peer, e_Init); - break; - case e_Init: /*FALLTHROUGH*/ - case e_Huh: /*FALLTHROUGH*/ - case e_TS: - up->state = s_InqOmega; - true_send(peer, "C\r"); - break; - default: - abort(); - } - break; - case s_InqOmega: - switch (event) { - case e_TS: - up->type = t_omega; - up->state = s_Auto; /* Inq side-effect. */ - break; - case e_Init: /*FALLTHROUGH*/ - case e_Huh: - up->state = s_InqTM; - true_send(peer, "F18\r"); - break; - default: - abort(); - } - break; - case s_InqTM: - switch (event) { - case e_F18: - up->type = t_tm; - true_doevent(peer, e_Init); - break; - case e_Init: /*FALLTHROUGH*/ - case e_Huh: - true_send(peer, "PO\r"); - up->state = s_InqTCU; - break; - default: - abort(); - } - break; - case s_InqTCU: - switch (event) { - case e_Location: - up->type = t_tcu; - true_doevent(peer, e_Init); - break; - case e_Init: /*FALLTHROUGH*/ - case e_Huh: - up->state = s_Base; - sleep(1); /* XXX */ - break; - default: - abort(); - } - break; - /* - * An expedient hack to prevent lint complaints, - * these don't actually need to be used here... - */ - case s_Init: - case s_F18: - case s_F50: - case s_Start: - case s_Auto: - case s_Max: - msyslog(LOG_INFO, "TRUE: state %s is unexpected!", stateStr(up->state)); - } - break; - default: - abort(); - /* NOTREACHED */ - } - -#ifdef CLOCK_PPS720 - if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) { - /* Make counter trigger on gate0, count down from 65535. */ - pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535); - /* - * (These constants are OK since - * they represent hardware maximums.) - */ - NLOG(NLOG_CLOCKINFO) { - msyslog(LOG_NOTICE, "PCL-720 initialized"); - } - up->pcl720init++; - } -#endif - - -} - -/* - * true_poll - called by the transmit procedure - */ -static void -true_poll( - int unit, - struct peer *peer - ) -{ - struct true_unit *up; - struct refclockproc *pp; - - /* - * You don't need to poll this clock. It puts out timecodes - * once per second. If asked for a timestamp, take note. - * The next time a timecode comes in, it will be fed back. - */ - pp = peer->procptr; - up = (struct true_unit *)pp->unitptr; - if (up->pollcnt > 0) - up->pollcnt--; - else { - true_doevent(peer, e_Init); - refclock_report(peer, CEVNT_TIMEOUT); - } - - /* - * polled every 64 seconds. Ask true_receive to hand in a - * timestamp. - */ - up->polled = 1; - pp->polls++; -} - -#ifdef CLOCK_PPS720 -/* - * true_sample720 - sample the PCL-720 - */ -static u_long -true_sample720(void) -{ - unsigned long f; - - /* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3. - * If it is not being held low now, we did not get called - * within 65535us. - */ - if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) { - NLOG(NLOG_CLOCKINFO) { - msyslog(LOG_NOTICE, "PCL-720 out of synch"); - } - return (0); - } - f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR)); -#ifdef PPS720_DEBUG - msyslog(LOG_DEBUG, "PCL-720: %luus", f); -#endif - return (f); -} -#endif - -#else -int refclock_true_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_tt560.c b/contrib/ntp/ntpd/refclock_tt560.c deleted file mode 100644 index f3d7bc1..0000000 --- a/contrib/ntp/ntpd/refclock_tt560.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * refclock_tt560 - clock driver for the TrueTime 560 IRIG-B decoder - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_TT560) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_unixtime.h" -#include "sys/tt560_api.h" -#include "ntp_stdlib.h" - -#include <stdio.h> -#include <ctype.h> - -/* - * This driver supports the TrueTime 560 IRIG-B decoder for the PCI bus. - */ - -/* - * TT560 interface definitions - */ -#define DEVICE "/dev/tt560%d" /* device name and unit */ -#define PRECISION (-20) /* precision assumed (1 us) */ -#define REFID "IRIG" /* reference ID */ -#define DESCRIPTION "TrueTime 560 IRIG-B PCI Decoder" - -/* - * Unit control structure - */ -struct tt560unit { - tt_mem_space_t *tt_mem; /* mapped address of PCI board */ - time_freeze_reg_t tt560rawt; /* data returned from PCI board */ -}; - -typedef union byteswap_u -{ - unsigned int long_word; - unsigned char byte[4]; -} byteswap_t; - -/* - * Function prototypes - */ -static int tt560_start P((int, struct peer *)); -static void tt560_shutdown P((int, struct peer *)); -static void tt560_poll P((int unit, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_tt560 = { - tt560_start, /* clock_start */ - tt560_shutdown, /* clock_shutdown */ - tt560_poll, /* clock_poll */ - noentry, /* clock_control (not used) */ - noentry, /* clock_init (not used) */ - noentry, /* clock_buginfo (not used) */ - NOFLAGS /* clock_flags (not used) */ -}; - - -/* - * tt560_start - open the TT560 device and initialize data for processing - */ -static int -tt560_start( - int unit, - struct peer *peer - ) -{ - register struct tt560unit *up; - struct refclockproc *pp; - char device[20]; - int fd; - caddr_t membase; - - /* - * Open TT560 device - */ - (void)sprintf(device, DEVICE, unit); - fd = open(device, O_RDWR); - if (fd == -1) { - msyslog(LOG_ERR, "tt560_start: open of %s: %m", device); - return (0); - } - - /* - * Map the device registers into user space. - */ - membase = mmap ((caddr_t) 0, TTIME_MEMORY_SIZE, - PROT_READ | PROT_WRITE, - MAP_SHARED, fd, (off_t)0); - - if (membase == (caddr_t) -1) { - msyslog(LOG_ERR, "tt560_start: mapping of %s: %m", device); - (void) close(fd); - return (0); - } - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct tt560unit *) emalloc(sizeof(struct tt560unit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct tt560unit)); - up->tt_mem = (tt_mem_space_t *)membase; - pp = peer->procptr; - pp->io.clock_recv = noentry; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous peer variables - */ - peer->precision = PRECISION; - peer->burst = NSTAGE; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - return (1); -} - - -/* - * tt560_shutdown - shut down the clock - */ -static void -tt560_shutdown( - int unit, - struct peer *peer - ) -{ - register struct tt560unit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct tt560unit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * tt560_poll - called by the transmit procedure - */ -static void -tt560_poll( - int unit, - struct peer *peer - ) -{ - register struct tt560unit *up; - struct refclockproc *pp; - time_freeze_reg_t *tp; - tt_mem_space_t *mp; - - int i; - unsigned int *p_time_t, *tt_mem_t; - - /* - * This is the main routine. It snatches the time from the TT560 - * board and tacks on a local timestamp. - */ - pp = peer->procptr; - up = (struct tt560unit *)pp->unitptr; - mp = up->tt_mem; - tp = &up->tt560rawt; - - p_time_t = (unsigned int *)tp; - tt_mem_t = (unsigned int *)&mp->time_freeze_reg; - - *tt_mem_t = 0; /* update the time freeze register */ - /* and copy time stamp to memory */ - for (i=0; i < TIME_FREEZE_REG_LEN; i++) { - *p_time_t = byte_swap(*tt_mem_t); - p_time_t++; - tt_mem_t++; - } - - get_systime(&pp->lastrec); - pp->polls++; - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. Note: we - * can't use the sec/usec conversion produced by the driver, - * since the year may be suspect. All format error checking is - * done by the sprintf() and sscanf() routines. - */ - sprintf(pp->a_lastcode, - "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", - tp->hun_day, tp->tens_day, tp->unit_day, - tp->tens_hour, tp->unit_hour, - tp->tens_min, tp->unit_min, - tp->tens_sec, tp->unit_sec, - tp->hun_ms, tp->tens_ms, tp->unit_ms, - tp->hun_us, tp->tens_us, tp->unit_us, - tp->status); - pp->lencode = strlen(pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("tt560: time %s timecode %d %s\n", - ulfptoa(&pp->lastrec, 6), pp->lencode, - pp->a_lastcode); -#endif - if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", - &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->usec) - != 5) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - if ((tp->status & 0x6) != 0x6) - pp->leap = LEAP_NOTINSYNC; - else - pp->leap = LEAP_NOWARNING; - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - record_clock_stats(&peer->srcadr, pp->a_lastcode); - refclock_receive(peer); - peer->burst = NSTAGE; -} - -/****************************************************************** - * - * byte_swap - * - * Inputs: 32 bit integer - * - * Output: byte swapped 32 bit integer. - * - * This routine is used to compensate for the byte alignment - * differences between big-endian and little-endian integers. - * - ******************************************************************/ -static unsigned int -byte_swap(unsigned int input_num) -{ - byteswap_t byte_swap; - unsigned char temp; - - byte_swap.long_word = input_num; - - temp = byte_swap.byte[3]; - byte_swap.byte[3] = byte_swap.byte[0]; - byte_swap.byte[0] = temp; - - temp = byte_swap.byte[2]; - byte_swap.byte[2] = byte_swap.byte[1]; - byte_swap.byte[1] = temp; - - return (byte_swap.long_word); -} - -#else -int refclock_tt560_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_ulink.c b/contrib/ntp/ntpd/refclock_ulink.c deleted file mode 100644 index 1f5e78a..0000000 --- a/contrib/ntp/ntpd/refclock_ulink.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * 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 - -#if defined(REFCLOCK) && defined(CLOCK_ULINK) - -#include <stdio.h> -#include <ctype.h> - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_calendar.h" -#include "ntp_stdlib.h" - -/* - * This driver supports ultralink Model 320,330,331,332 WWVB radios - * - * this driver was based on the refclock_wwvb.c driver - * in the ntp distribution. - * - * Fudge Factors - * - * fudge flag1 0 don't poll clock - * 1 send poll character - * - * 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 - * - * 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/wwvb%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-10) /* precision assumed (about 10 ms) */ -#define REFID "WWVB" /* reference ID */ -#define DESCRIPTION "Ultralink WWVB Receiver" /* WRU */ - -#define LEN33X 32 /* timecode length Model 325 & 33X */ -#define LEN320 24 /* timecode length Model 320 */ - -/* - * unit control structure - */ -struct ulinkunit { - u_char tcswitch; /* timecode switch */ - l_fp laststamp; /* last receive timestamp */ -}; - -/* - * Function prototypes - */ -static int ulink_start P((int, struct peer *)); -static void ulink_shutdown P((int, struct peer *)); -static void ulink_receive P((struct recvbuf *)); -static void ulink_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_ulink = { - ulink_start, /* start up driver */ - ulink_shutdown, /* shut down driver */ - ulink_poll, /* transmit poll message */ - noentry, /* not used */ - noentry, /* not used */ - noentry, /* not used */ - NOFLAGS -}; - - -/* - * ulink_start - open the devices and initialize data for processing - */ -static int -ulink_start( - int unit, - struct peer *peer - ) -{ - register struct ulinkunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct ulinkunit *) - emalloc(sizeof(struct ulinkunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct ulinkunit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = ulink_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - peer->burst = NSTAGE; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - return (1); -} - - -/* - * ulink_shutdown - shut down the clock - */ -static void -ulink_shutdown( - int unit, - struct peer *peer - ) -{ - register struct ulinkunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct ulinkunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * ulink_receive - receive data from the serial interface - */ -static void -ulink_receive( - struct recvbuf *rbufp - ) -{ - struct ulinkunit *up; - struct refclockproc *pp; - struct peer *peer; - - l_fp trtmp; /* arrival timestamp */ - int quality; /* quality indicator */ - int temp; /* int temp */ - char syncchar; /* synchronization indicator */ - char leapchar; /* leap indicator */ - char modechar; /* model 320 mode flag */ - char char_quality[2]; /* temp quality flag */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct ulinkunit *)pp->unitptr; - temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); - - /* - * Note we get a buffer and timestamp for both a <cr> and <lf>, - * but only the <cr> timestamp is retained. - */ - if (temp == 0) { - if (up->tcswitch == 0) { - up->tcswitch = 1; - up->laststamp = trtmp; - } else - up->tcswitch = 0; - return; - } - pp->lencode = temp; - pp->lastrec = up->laststamp; - up->laststamp = trtmp; - up->tcswitch = 1; -#ifdef DEBUG - if (debug) - printf("ulink: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. - */ - syncchar = leapchar = modechar = ' '; - 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.%2ld%c", - &syncchar, &quality, &modechar, &pp->year, &pp->day, - &pp->hour, &pp->minute, &pp->second, - &pp->nsec, &leapchar) == 10) { - pp->nsec *= 10000000; /* 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; - } - - - /* - * 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) - */ - - /* - * 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, and leap characters. If - * unsynchronized, set the leap bits accordingly and exit. - * Otherwise, set the leap bits according to the leap character. - */ - - 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)) { - refclock_report(peer, CEVNT_BADTIME); - } - -} - - -/* - * ulink_poll - called by the transmit procedure - */ -static void -ulink_poll( - int unit, - struct peer *peer - ) -{ - 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++; - } - else - pp->polls++; - - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); - peer->burst = NSTAGE; - -} - -#else -int refclock_ulink_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_usno.c b/contrib/ntp/ntpd/refclock_usno.c deleted file mode 100644 index 057eef9..0000000 --- a/contrib/ntp/ntpd/refclock_usno.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - * refclock_usno - clock driver for the Naval Observatory dialup - * Michael Shields <shields@tembel.org> 1995/02/25 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_USNO) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_refclock.h" -#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. - * - * This driver does not support the `phone' configuration because that - * is needlessly global; it would clash with the ACTS driver. - * - * The Naval Observatory does not support the echo-delay measurement scheme. - * - * However, this driver *does* support UUCP port locking, allowing the - * line to be shared with other processes when not actually dialing - * for time. - */ - -/* - * Interface definitions - */ - -#define DEVICE "/dev/cua%d" /* device name and unit */ -#define LOCKFILE "/var/lock/LCK..cua%d" -/* #define LOCKFILE "/usr/spool/uucp/LCK..cua%d" */ - -#define PHONE "atdt 202 653 0351" -/* #define PHONE "atdt 1 202 653 0351" */ - -#define SPEED232 B1200 /* uart speed (1200 cowardly baud) */ -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define REFID "USNO" /* reference ID */ -#define DESCRIPTION "Naval Observatory dialup" - -#define MODE_AUTO 0 /* automatic mode */ -#define MODE_BACKUP 1 /* backup mode */ -#define MODE_MANUAL 2 /* manual mode */ - -#define MSGCNT 10 /* we need this many time messages */ -#define SMAX 80 /* max token string length */ -#define LENCODE 20 /* length of valid timecode string */ -#define USNO_MINPOLL 10 /* log2 min poll interval (1024 s) */ -#define USNO_MAXPOLL 14 /* log2 max poll interval (16384 s) */ -#define MAXOUTAGE 3600 /* max before USNO kicks in (s) */ - -/* - * Modem control strings. These may have to be changed for some modems. - * - * AT command prefix - * B1 initiate call negotiation using Bell 212A - * &C1 enable carrier detect - * &D2 hang up and return to command mode on DTR transition - * E0 modem command echo disabled - * l1 set modem speaker volume to low level - * M1 speaker enabled untill carrier detect - * Q0 return result codes - * V1 return result codes as English words - */ -#define MODEM_SETUP "ATB1&C1&D2E0L1M1Q0V1" /* modem setup */ -#define MODEM_HANGUP "ATH" /* modem disconnect */ - -/* - * Timeouts - */ -#define IDLE 60 /* idle timeout (s) */ -#define WAIT 2 /* wait timeout (s) */ -#define ANSWER 30 /* answer timeout (s) */ -#define CONNECT 10 /* connect timeout (s) */ -#define TIMECODE (MSGCNT+16) /* timecode timeout (s) */ - -/* - * Unit control structure - */ -struct usnounit { - int pollcnt; /* poll message counter */ - - int state; /* the first one was Delaware */ - int run; /* call program run switch */ - int msgcnt; /* count of time messages received */ - long redial; /* interval to next automatic call */ - int unit; /* unit number (= port) */ -}; - -/* - * Function prototypes - */ -static int usno_start P((int, struct peer *)); -static void usno_shutdown P((int, struct peer *)); -static void usno_poll P((int, struct peer *)); -static void usno_disc P((struct peer *)); -#if 0 -static void usno_timeout P((struct peer *)); -static void usno_receive P((struct recvbuf *)); -static int usno_write P((struct peer *, const char *)); -#endif /* 0 */ - -/* - * Transfer vector - */ -struct refclock refclock_usno = { - usno_start, /* start up driver */ - usno_shutdown, /* shut down driver */ - usno_poll, /* transmit poll message */ - noentry, /* not used (usno_control) */ - noentry, /* not used (usno_init) */ - noentry, /* not used (usno_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * usno_start - open the devices and initialize data for processing - */ -static int -usno_start( - int unit, - struct peer *peer - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - - /* - * Initialize miscellaneous variables - */ - pp = peer->procptr; - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - peer->minpoll = USNO_MINPOLL; - peer->maxpoll = USNO_MAXPOLL; - peer->sstclktype = CTL_SST_TS_TELEPHONE; - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct usnounit *) - emalloc(sizeof(struct usnounit)))) - return (0); - memset((char *)up, 0, sizeof(struct usnounit)); - up->unit = unit; - pp->unitptr = (caddr_t)up; - - /* - * Set up the driver timeout - */ - peer->nextdate = current_time + WAIT; - return (1); -} - - -/* - * usno_shutdown - shut down the clock - */ -static void -usno_shutdown( - int unit, - struct peer *peer - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - -#ifdef DEBUG - if (debug) - printf("usno: clock %s shutting down\n", ntoa(&peer->srcadr)); -#endif - pp = peer->procptr; - up = (struct usnounit *)pp->unitptr; - usno_disc(peer); - free(up); -} - - -#if 0 -/* - * usno_receive - receive data from the serial interface - */ -static void -usno_receive( - struct recvbuf *rbufp - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - struct peer *peer; - char str[SMAX]; - u_long mjd; /* Modified Julian Day */ - static int day, hour, minute, second; - - /* - * Initialize pointers and read the timecode and timestamp. If - * the OK modem status code, leave it where folks can find it. - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct usnounit *)pp->unitptr; - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, - &pp->lastrec); - if (pp->lencode == 0) { - if (strcmp(pp->a_lastcode, "OK") == 0) - pp->lencode = 2; - return; - } -#ifdef DEBUG - if (debug) - printf("usno: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - - switch (up->state) { - - case 0: - - /* - * State 0. We are not expecting anything. Probably - * modem disconnect noise. Go back to sleep. - */ - return; - - case 1: - - /* - * State 1. We are about to dial. Just drop it. - */ - return; - - case 2: - - /* - * State 2. We are waiting for the call to be answered. - * All we care about here is CONNECT as the first token - * in the string. If the modem signals BUSY, ERROR, NO - * ANSWER, NO CARRIER or NO DIALTONE, we immediately - * hang up the phone. If CONNECT doesn't happen after - * ANSWER seconds, hang up the phone. If everything is - * okay, start the connect timeout and slide into state - * 3. - */ - (void)strncpy(str, strtok(pp->a_lastcode, " "), SMAX); - if (strcmp(str, "BUSY") == 0 || strcmp(str, "ERROR") == - 0 || strcmp(str, "NO") == 0) { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s USNO modem status %s", - ntoa(&peer->srcadr), pp->a_lastcode); - usno_disc(peer); - } else if (strcmp(str, "CONNECT") == 0) { - peer->nextdate = current_time + CONNECT; - up->msgcnt = 0; - up->state++; - } else { - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_WARNING, - "clock %s USNO unknown modem status %s", - ntoa(&peer->srcadr), pp->a_lastcode); - } - return; - - case 3: - - /* - * State 3. The call has been answered and we are - * waiting for the first message. If this doesn't - * happen within the timecode timeout, hang up the - * phone. We probably got a wrong number or they are - * down. - */ - peer->nextdate = current_time + TIMECODE; - up->state++; - return; - - case 4: - - /* - * State 4. We are reading a timecode. It's an actual - * timecode, or it's the `*' OTM. - * - * jjjjj nnn hhmmss UTC - */ - if (pp->lencode == LENCODE) { - if (sscanf(pp->a_lastcode, "%5ld %3d %2d%2d%2d UTC", - &mjd, &day, &hour, &minute, &second) != 5) { -#ifdef DEBUG - if (debug) - printf("usno: bad timecode format\n"); -#endif - refclock_report(peer, CEVNT_BADREPLY); - } else - up->msgcnt++; - return; - } else if (pp->lencode != 1 || !up->msgcnt) - return; - /* else, OTM; drop out of switch */ - } - - pp->leap = LEAP_NOWARNING; - pp->day = day; - pp->hour = hour; - pp->minute = minute; - pp->second = second; - - /* - * Colossal hack here. We process each sample in a trimmed-mean - * filter and determine the reference clock offset and - * dispersion. The fudge time1 value is added to each sample as - * received. - */ - if (!refclock_process(pp)) { -#ifdef DEBUG - if (debug) - printf("usno: time rejected\n"); -#endif - refclock_report(peer, CEVNT_BADTIME); - return; - } else if (up->msgcnt < MSGCNT) - return; - - /* - * We have a filtered sample offset ready for peer processing. - * We use lastrec as both the reference time and receive time in - * order to avoid being cute, like setting the reference time - * later than the receive time, which may cause a paranoid - * protocol module to chuck out the data. Finaly, we unhook the - * timeout, arm for the next call, fold the tent and go home. - */ - pp->lastref = pp->lastrec; - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); - pp->sloppyclockflag &= ~CLK_FLAG1; - up->pollcnt = 0; - up->state = 0; - usno_disc(peer); -} -#endif /* 0 */ - - -/* - * usno_poll - called by the transmit routine - */ -static void -usno_poll( - int unit, - struct peer *peer - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - - /* - * If the driver is running, we set the enable flag (fudge - * flag1), which causes the driver timeout routine to initiate a - * call. If not, the enable flag can be set using - * ntpdc. If this is the sustem peer, then follow the system - * poll interval. - */ - pp = peer->procptr; - up = (struct usnounit *)pp->unitptr; - if (up->run) { - pp->sloppyclockflag |= CLK_FLAG1; - if (peer == sys_peer) - peer->hpoll = sys_poll; - else - peer->hpoll = peer->minpoll; - } -} - - -#if 0 -/* - * usno_timeout - called by the timer interrupt - */ -static void -usno_timeout( - struct peer *peer - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - int fd; - char device[20]; - char lockfile[128], pidbuf[8]; - int dtr = TIOCM_DTR; - - /* - * If a timeout occurs in other than state 0, the call has - * failed. If in state 0, we just see if there is other work to - * do. - */ - pp = peer->procptr; - up = (struct usnounit *)pp->unitptr; - if (up->state) { - if (up->state != 1) { - usno_disc(peer); - return; - } - /* - * Call, and start the answer timeout. We think it - * strange if the OK status has not been received from - * the modem, but plow ahead anyway. - * - * This code is *here* because we had to stick in a brief - * delay to let the modem settle down after raising DTR, - * and for the OK to be received. State machines are - * contorted. - */ - if (strcmp(pp->a_lastcode, "OK") != 0) - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "clock %s USNO no modem status", - ntoa(&peer->srcadr)); - (void)usno_write(peer, PHONE); - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "clock %s USNO calling %s\n", - ntoa(&peer->srcadr), PHONE); - up->state = 2; - up->pollcnt++; - pp->polls++; - peer->nextdate = current_time + ANSWER; - return; - } - switch (peer->ttl) { - - /* - * In manual mode the calling program is activated - * by the ntpdc program using the enable flag (fudge - * flag1), either manually or by a cron job. - */ - case MODE_MANUAL: - up->run = 0; - break; - - /* - * In automatic mode the calling program runs - * continuously at intervals determined by the sys_poll - * variable. - */ - case MODE_AUTO: - if (!up->run) - pp->sloppyclockflag |= CLK_FLAG1; - up->run = 1; - break; - - /* - * In backup mode the calling program is disabled, - * unless no system peer has been selected for MAXOUTAGE - * (3600 s). Once enabled, it runs until some other NTP - * peer shows up. - */ - case MODE_BACKUP: - if (!up->run && sys_peer == 0) { - if (current_time - last_time > MAXOUTAGE) { - up->run = 1; - peer->hpoll = peer->minpoll; - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s USNO backup started ", - ntoa(&peer->srcadr)); - } - } else if (up->run && sys_peer->sstclktype != CTL_SST_TS_TELEPHONE) { - peer->hpoll = peer->minpoll; - up->run = 0; - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s USNO backup stopped", - ntoa(&peer->srcadr)); - } - break; - - default: - msyslog(LOG_ERR, - "clock %s USNO invalid mode", ntoa(&peer->srcadr)); - - } - - /* - * The fudge flag1 is used as an enable/disable; if set either - * by the code or via ntpdc, the calling program is - * started; if reset, the phones stop ringing. - */ - if (!(pp->sloppyclockflag & CLK_FLAG1)) { - up->pollcnt = 0; - peer->nextdate = current_time + IDLE; - return; - } - - /* - * Lock the port. - */ - (void)sprintf(lockfile, LOCKFILE, up->unit); - fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644); - if (fd < 0) { - msyslog(LOG_ERR, "clock %s USNO port busy", - ntoa(&peer->srcadr)); - return; - } - sprintf(pidbuf, "%d\n", (int) getpid()); - write(fd, pidbuf, strlen(pidbuf)); - close(fd); - - /* - * Open serial port. Use ACTS line discipline, if available. It - * pumps a timestamp into the data stream at every on-time - * character '*' found. Note: the port must have modem control - * or deep pockets for the phone bill. HP-UX 9.03 users should - * have very deep pockets. - */ - (void)sprintf(device, DEVICE, up->unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS))) { - unlink(lockfile); - return; - } - if (ioctl(fd, TIOCMBIC, (char *)&dtr) < 0) - msyslog(LOG_WARNING, "usno_timeout: clock %s: couldn't clear DTR: %m", - ntoa(&peer->srcadr)); - - pp->io.clock_recv = usno_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - unlink(lockfile); - free(up); - return; - } - - /* - * Initialize modem and kill DTR. We skedaddle if this comes - * bum. - */ - if (!usno_write(peer, MODEM_SETUP)) { - msyslog(LOG_ERR, "clock %s USNO couldn't write", - ntoa(&peer->srcadr)); - io_closeclock(&pp->io); - unlink(lockfile); - free(up); - return; - } - - /* - * Initiate a call to the Observatory. If we wind up here in - * other than state 0, a successful call could not be completed - * within minpoll seconds. - */ - if (up->pollcnt) { - refclock_report(peer, CEVNT_TIMEOUT); - NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, - "clock %s USNO calling program terminated", - ntoa(&peer->srcadr)); - pp->sloppyclockflag &= ~CLK_FLAG1; - up->pollcnt = 0; -#ifdef DEBUG - if (debug) - printf("usno: calling program terminated\n"); -#endif - usno_disc(peer); - return; - } - - /* - * Raise DTR, and let the modem settle. Then we'll dial. - */ - if (ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr) < -1) - msyslog(LOG_INFO, "usno_timeout: clock %s: couldn't set DTR: %m", - ntoa(&peer->srcadr)); - up->state = 1; - peer->nextdate = current_time + WAIT; -} -#endif /* 0 */ - - -/* - * usno_disc - disconnect the call and wait for the ruckus to cool - */ -static void -usno_disc( - struct peer *peer - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - int dtr = TIOCM_DTR; - char lockfile[128]; - - /* - * We should never get here other than in state 0, unless a call - * has timed out. We drop DTR, which will reliably get the modem - * off the air, even while the modem is hammering away full tilt. - */ - pp = peer->procptr; - up = (struct usnounit *)pp->unitptr; - - if (ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr) < 0) - msyslog(LOG_INFO, "usno_disc: clock %s: couldn't clear DTR: %m", - ntoa(&peer->srcadr)); - - if (up->state > 0) { - up->state = 0; - msyslog(LOG_NOTICE, "clock %s USNO call failed %d", - ntoa(&peer->srcadr), up->state); -#ifdef DEBUG - if (debug) - printf("usno: call failed %d\n", up->state); -#endif - } - - io_closeclock(&pp->io); - sprintf(lockfile, LOCKFILE, up->unit); - unlink(lockfile); - - peer->nextdate = current_time + WAIT; -} - - -#if 0 -/* - * usno_write - write a message to the serial port - */ -static int -usno_write( - struct peer *peer, - const char *str - ) -{ - register struct usnounit *up; - struct refclockproc *pp; - int len; - int code; - char cr = '\r'; - - /* - * Not much to do here, other than send the message, handle - * debug and report faults. - */ - pp = peer->procptr; - up = (struct usnounit *)pp->unitptr; - len = strlen(str); -#ifdef DEBUG - if (debug) - printf("usno: state %d send %d %s\n", up->state, len, - str); -#endif - code = write(pp->io.fd, str, (unsigned)len) == len; - code |= write(pp->io.fd, &cr, 1) == 1; - if (!code) - refclock_report(peer, CEVNT_FAULT); - return (code); -} -#endif /* 0 */ - -#else -int refclock_usno_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_wwv.c b/contrib/ntp/ntpd/refclock_wwv.c deleted file mode 100644 index 11aae7f..0000000 --- a/contrib/ntp/ntpd/refclock_wwv.c +++ /dev/null @@ -1,2859 +0,0 @@ -/* - * refclock_wwv - clock driver for NIST WWV/H time/frequency station - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_WWV) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_calendar.h" -#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 - -#ifdef ICOM -#include "icom.h" -#endif /* ICOM */ - -/* - * Audio WWV/H demodulator/decoder - * - * This driver synchronizes the computer time using data encoded in - * radio transmissions from NIST time/frequency stations WWV in Boulder, - * CO, and WWVH in Kauai, HI. Transmissions are made continuously on - * 2.5, 5, 10, 15 and 20 MHz in AM mode. An ordinary shortwave receiver - * can be tuned manually to one of these frequencies or, in the case of - * ICOM receivers, the receiver can be tuned automatically using this - * program as propagation conditions change throughout the day and - * night. - * - * The driver receives, demodulates and decodes the radio signals when - * connected to the audio codec of a workstation running Solaris, SunOS - * FreeBSD or Linux, and with a little help, other workstations with - * similar codecs or sound cards. In this implementation, only one audio - * driver and codec can be supported on a single machine. - * - * The demodulation and decoding algorithms used in this driver are - * based on those developed for the TAPR DSP93 development board and the - * TI 320C25 digital signal processor described in: Mills, D.L. A - * precision radio clock for WWV transmissions. Electrical Engineering - * Report 97-8-1, University of Delaware, August 1997, 25 pp., available - * from www.eecis.udel.edu/~mills/reports.htm. The algorithms described - * in this report have been modified somewhat to improve performance - * under weak signal conditions and to provide an automatic station - * identification feature. - * - * 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. - */ -/* - * Interface definitions - */ -#define DEVICE_AUDIO "/dev/audio" /* audio device name */ -#define AUDIO_BUFSIZ 320 /* audio buffer size (50 ms) */ -#define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */ -#define SECOND 8000 /* second epoch (sample rate) (Hz) */ -#define MINUTE (SECOND * 60) /* minute epoch */ -#define OFFSET 128 /* companded sample offset */ -#define SIZE 256 /* decompanding table size */ -#define MAXSIG 6000. /* max signal level reference */ -#define MAXCLP 100 /* max clips above reference per s */ -#define MAXSNR 30. /* max SNR reference */ -#define DGAIN 20. /* data channel gain reference */ -#define SGAIN 10. /* sync channel gain reference */ -#define MAXFREQ 1. /* max frequency tolerance (125 PPM) */ -#define PI 3.1415926535 /* the real thing */ -#define DATSIZ (170 * MS) /* data matched filter size */ -#define SYNSIZ (800 * MS) /* minute sync matched filter size */ -#define MAXERR 30 /* max data bit errors in minute */ -#define NCHAN 5 /* number of radio channels */ -#define AUDIO_PHI 5e-6 /* dispersion growth factor */ -#ifdef IRIG_SUCKS -#define WIGGLE 11 /* wiggle filter length */ -#endif /* IRIG_SUCKS */ - -/* - * General purpose status bits (status) - * - * SELV and/or SELH are set when WWV or WWVH has been heard and cleared - * on signal loss. SSYNC is set when the second sync pulse has been - * acquired and cleared by signal loss. MSYNC is set when the minute - * sync pulse has been acquired. DSYNC is set when a digit reaches the - * threshold and INSYNC is set when all nine digits have reached the - * threshold. The MSYNC, DSYNC and INSYNC bits are cleared only by - * timeout, upon which the driver starts over from scratch. - * - * DGATE is set if a data bit is invalid and BGATE is set if a BCD digit - * bit is invalid. SFLAG is set when during seconds 59, 0 and 1 while - * probing alternate frequencies. LEPDAY is set when SECWAR of the - * timecode is set on 30 June or 31 December. LEPSEC is set during the - * last minute of the day when LEPDAY is set. At the end of this minute - * the driver inserts second 60 in the seconds state machine and the - * minute sync slips a second. The SLOSS and SJITR bits are for monitor - * only. - */ -#define MSYNC 0x0001 /* minute epoch sync */ -#define SSYNC 0x0002 /* second epoch sync */ -#define DSYNC 0x0004 /* minute units sync */ -#define INSYNC 0x0008 /* clock synchronized */ -#define FGATE 0x0010 /* frequency gate */ -#define DGATE 0x0020 /* data bit error */ -#define BGATE 0x0040 /* BCD digit bit error */ -#define SFLAG 0x1000 /* probe flag */ -#define LEPDAY 0x2000 /* leap second day */ -#define LEPSEC 0x4000 /* leap second minute */ - -/* - * Station scoreboard bits - * - * These are used to establish the signal quality for each of the five - * frequencies and two stations. - */ -#define SYNCNG 0x0001 /* sync or SNR below threshold */ -#define DATANG 0x0002 /* data or SNR below threshold */ -#define ERRRNG 0x0004 /* data error */ -#define SELV 0x0100 /* WWV station select */ -#define SELH 0x0200 /* WWVH station select */ - -/* - * Alarm status bits (alarm) - * - * These bits indicate various alarm conditions, which are decoded to - * form the quality character included in the timecode. If not tracking - * second sync, the SYNERR alarm is raised. The data error counter is - * incremented for each invalid data bit. If too many data bit errors - * are encountered in one minute, the MODERR alarm is raised. The DECERR - * alarm is raised if a maximum likelihood digit fails to compare with - * the current clock digit. If the probability of any miscellaneous bit - * or any digit falls below the threshold, the SYMERR alarm is raised. - */ -#define DECERR 1 /* BCD digit compare error */ -#define SYMERR 2 /* low bit or digit probability */ -#define MODERR 4 /* too many data bit errors */ -#define SYNERR 8 /* not synchronized to station */ - -/* - * Watchcat timeouts (watch) - * - * If these timeouts expire, the status bits are mashed to zero and the - * driver starts from scratch. Suitably more refined procedures may be - * developed in future. All these are in minutes. - */ -#define ACQSN 5 /* station acquisition timeout */ -#define DIGIT 30 /* minute unit digit timeout */ -#define HOLD 30 /* reachable timeout */ -#define PANIC (2 * 1440) /* panic timeout */ - -/* - * Thresholds. These establish the minimum signal level, minimum SNR and - * maximum jitter thresholds which establish the error and false alarm - * rates of the driver. The values defined here may be on the - * adventurous side in the interest of the highest sensitivity. - */ -#define MTHR 13. /* acquisition signal gate (percent) */ -#define TTHR 50. /* tracking signal gate (percent) */ -#define ATHR 2000. /* acquisition amplitude threshold */ -#define ASNR 6. /* acquisition SNR threshold (dB) */ -#define AWND 20. /* acquisition jitter threshold (ms) */ -#define AMIN 3 /* min bit count */ -#define AMAX 6 /* max bit count */ -#define QTHR 2000 /* QSY sync threshold */ -#define QSNR 20. /* QSY sync SNR threshold (dB) */ -#define XTHR 1000. /* QSY data threshold */ -#define XSNR 10. /* QSY data SNR threshold (dB) */ -#define STHR 500 /* second sync amplitude threshold */ -#define SSNR 10. /* second sync SNR threshold */ -#define SCMP 10 /* second sync compare threshold */ -#define DTHR 1000 /* bit amplitude threshold */ -#define DSNR 10. /* bit SNR threshold (dB) */ -#define BTHR 1000 /* digit amplitude threshold */ -#define BSNR 3. /* digit likelihood threshold (dB) */ -#define BCMP 5 /* digit compare threshold */ - -/* - * Tone frequency definitions. The increments are for 4.5-deg sine - * table. - */ -#define MS (SECOND / 1000) /* samples per millisecond */ -#define IN100 ((100 * 80) / SECOND) /* 100 Hz increment */ -#define IN1000 ((1000 * 80) / SECOND) /* 1000 Hz increment */ -#define IN1200 ((1200 * 80) / SECOND) /* 1200 Hz increment */ - -/* - * Acquisition and tracking time constants. Usually powers of 2. - */ -#define MINAVG 8 /* min time constant */ -#define MAXAVG 1024 /* max time constant */ -#define TCONST 16 /* data bit/digit time constant */ - -/* - * Miscellaneous status bits (misc) - * - * These bits correspond to designated bits in the WWV/H timecode. The - * bit probabilities are exponentially averaged over several minutes and - * processed by a integrator and threshold. - */ -#define DUT1 0x01 /* 56 DUT .1 */ -#define DUT2 0x02 /* 57 DUT .2 */ -#define DUT4 0x04 /* 58 DUT .4 */ -#define DUTS 0x08 /* 50 DUT sign */ -#define DST1 0x10 /* 55 DST1 leap warning */ -#define DST2 0x20 /* 2 DST2 DST1 delayed one day */ -#define SECWAR 0x40 /* 3 leap second warning */ - -/* - * The on-time synchronization point for the driver is the second epoch - * sync pulse produced by the FIR matched filters. As the 5-ms delay of - * these filters is compensated, the program delay is 1.1 ms due to the - * 600-Hz IIR bandpass filter. The measured receiver delay is 4.7 ms and - * the codec delay less than 0.2 ms. The additional propagation delay - * specific to each receiver location can be programmed in the fudge - * time1 and time2 values for WWV and WWVH, respectively. - */ -#define PDELAY (.0011 + .0047 + .0002) /* net system delay (s) */ - -/* - * Table of sine values at 4.5-degree increments. This is used by the - * synchronous matched filter demodulators. The integral of sine-squared - * over one complete cycle is PI, so the table is normallized by 1 / PI. - */ -double sintab[] = { - 0.000000e+00, 2.497431e-02, 4.979464e-02, 7.430797e-02, /* 0-3 */ - 9.836316e-02, 1.218119e-01, 1.445097e-01, 1.663165e-01, /* 4-7 */ - 1.870979e-01, 2.067257e-01, 2.250791e-01, 2.420447e-01, /* 8-11 */ - 2.575181e-01, 2.714038e-01, 2.836162e-01, 2.940800e-01, /* 12-15 */ - 3.027307e-01, 3.095150e-01, 3.143910e-01, 3.173286e-01, /* 16-19 */ - 3.183099e-01, 3.173286e-01, 3.143910e-01, 3.095150e-01, /* 20-23 */ - 3.027307e-01, 2.940800e-01, 2.836162e-01, 2.714038e-01, /* 24-27 */ - 2.575181e-01, 2.420447e-01, 2.250791e-01, 2.067257e-01, /* 28-31 */ - 1.870979e-01, 1.663165e-01, 1.445097e-01, 1.218119e-01, /* 32-35 */ - 9.836316e-02, 7.430797e-02, 4.979464e-02, 2.497431e-02, /* 36-39 */ --0.000000e+00, -2.497431e-02, -4.979464e-02, -7.430797e-02, /* 40-43 */ --9.836316e-02, -1.218119e-01, -1.445097e-01, -1.663165e-01, /* 44-47 */ --1.870979e-01, -2.067257e-01, -2.250791e-01, -2.420447e-01, /* 48-51 */ --2.575181e-01, -2.714038e-01, -2.836162e-01, -2.940800e-01, /* 52-55 */ --3.027307e-01, -3.095150e-01, -3.143910e-01, -3.173286e-01, /* 56-59 */ --3.183099e-01, -3.173286e-01, -3.143910e-01, -3.095150e-01, /* 60-63 */ --3.027307e-01, -2.940800e-01, -2.836162e-01, -2.714038e-01, /* 64-67 */ --2.575181e-01, -2.420447e-01, -2.250791e-01, -2.067257e-01, /* 68-71 */ --1.870979e-01, -1.663165e-01, -1.445097e-01, -1.218119e-01, /* 72-75 */ --9.836316e-02, -7.430797e-02, -4.979464e-02, -2.497431e-02, /* 76-79 */ - 0.000000e+00}; /* 80 */ - -/* - * Decoder operations at the end of each second are driven by a state - * machine. The transition matrix consists of a dispatch table indexed - * by second number. Each entry in the table contains a case switch - * number and argument. - */ -struct progx { - int sw; /* case switch number */ - int arg; /* argument */ -}; - -/* - * Case switch numbers - */ -#define IDLE 0 /* no operation */ -#define COEF 1 /* BCD bit */ -#define COEF2 2 /* BCD bit ignored */ -#define DECIM9 3 /* BCD digit 0-9 */ -#define DECIM6 4 /* BCD digit 0-6 */ -#define DECIM3 5 /* BCD digit 0-3 */ -#define DECIM2 6 /* BCD digit 0-2 */ -#define MSCBIT 7 /* miscellaneous bit */ -#define MSC20 8 /* miscellaneous bit */ -#define MSC21 9 /* QSY probe channel */ -#define MIN1 10 /* minute */ -#define MIN2 11 /* leap second */ -#define SYNC2 12 /* QSY data channel */ -#define SYNC3 13 /* QSY data channel */ - -/* - * Offsets in decoding matrix - */ -#define MN 0 /* minute digits (2) */ -#define HR 2 /* hour digits (2) */ -#define DA 4 /* day digits (3) */ -#define YR 7 /* year digits (2) */ - -struct progx progx[] = { - {SYNC2, 0}, /* 0 latch sync max */ - {SYNC3, 0}, /* 1 QSY data channel */ - {MSCBIT, DST2}, /* 2 dst2 */ - {MSCBIT, SECWAR}, /* 3 lw */ - {COEF, 0}, /* 4 1 year units */ - {COEF, 1}, /* 5 2 */ - {COEF, 2}, /* 6 4 */ - {COEF, 3}, /* 7 8 */ - {DECIM9, YR}, /* 8 */ - {IDLE, 0}, /* 9 p1 */ - {COEF, 0}, /* 10 1 minute units */ - {COEF, 1}, /* 11 2 */ - {COEF, 2}, /* 12 4 */ - {COEF, 3}, /* 13 8 */ - {DECIM9, MN}, /* 14 */ - {COEF, 0}, /* 15 10 minute tens */ - {COEF, 1}, /* 16 20 */ - {COEF, 2}, /* 17 40 */ - {COEF2, 3}, /* 18 80 (not used) */ - {DECIM6, MN + 1}, /* 19 p2 */ - {COEF, 0}, /* 20 1 hour units */ - {COEF, 1}, /* 21 2 */ - {COEF, 2}, /* 22 4 */ - {COEF, 3}, /* 23 8 */ - {DECIM9, HR}, /* 24 */ - {COEF, 0}, /* 25 10 hour tens */ - {COEF, 1}, /* 26 20 */ - {COEF2, 2}, /* 27 40 (not used) */ - {COEF2, 3}, /* 28 80 (not used) */ - {DECIM2, HR + 1}, /* 29 p3 */ - {COEF, 0}, /* 30 1 day units */ - {COEF, 1}, /* 31 2 */ - {COEF, 2}, /* 32 4 */ - {COEF, 3}, /* 33 8 */ - {DECIM9, DA}, /* 34 */ - {COEF, 0}, /* 35 10 day tens */ - {COEF, 1}, /* 36 20 */ - {COEF, 2}, /* 37 40 */ - {COEF, 3}, /* 38 80 */ - {DECIM9, DA + 1}, /* 39 p4 */ - {COEF, 0}, /* 40 100 day hundreds */ - {COEF, 1}, /* 41 200 */ - {COEF2, 2}, /* 42 400 (not used) */ - {COEF2, 3}, /* 43 800 (not used) */ - {DECIM3, DA + 2}, /* 44 */ - {IDLE, 0}, /* 45 */ - {IDLE, 0}, /* 46 */ - {IDLE, 0}, /* 47 */ - {IDLE, 0}, /* 48 */ - {IDLE, 0}, /* 49 p5 */ - {MSCBIT, DUTS}, /* 50 dut+- */ - {COEF, 0}, /* 51 10 year tens */ - {COEF, 1}, /* 52 20 */ - {COEF, 2}, /* 53 40 */ - {COEF, 3}, /* 54 80 */ - {MSC20, DST1}, /* 55 dst1 */ - {MSCBIT, DUT1}, /* 56 0.1 dut */ - {MSCBIT, DUT2}, /* 57 0.2 */ - {MSC21, DUT4}, /* 58 0.4 QSY probe channel */ - {MIN1, 0}, /* 59 p6 latch sync min */ - {MIN2, 0} /* 60 leap second */ -}; - -/* - * BCD coefficients for maximum likelihood digit decode - */ -#define P15 1. /* max positive number */ -#define N15 -1. /* max negative number */ - -/* - * Digits 0-9 - */ -#define P9 (P15 / 4) /* mark (+1) */ -#define N9 (N15 / 4) /* space (-1) */ - -double bcd9[][4] = { - {N9, N9, N9, N9}, /* 0 */ - {P9, N9, N9, N9}, /* 1 */ - {N9, P9, N9, N9}, /* 2 */ - {P9, P9, N9, N9}, /* 3 */ - {N9, N9, P9, N9}, /* 4 */ - {P9, N9, P9, N9}, /* 5 */ - {N9, P9, P9, N9}, /* 6 */ - {P9, P9, P9, N9}, /* 7 */ - {N9, N9, N9, P9}, /* 8 */ - {P9, N9, N9, P9}, /* 9 */ - {0, 0, 0, 0} /* backstop */ -}; - -/* - * Digits 0-6 (minute tens) - */ -#define P6 (P15 / 3) /* mark (+1) */ -#define N6 (N15 / 3) /* space (-1) */ - -double bcd6[][4] = { - {N6, N6, N6, 0}, /* 0 */ - {P6, N6, N6, 0}, /* 1 */ - {N6, P6, N6, 0}, /* 2 */ - {P6, P6, N6, 0}, /* 3 */ - {N6, N6, P6, 0}, /* 4 */ - {P6, N6, P6, 0}, /* 5 */ - {N6, P6, P6, 0}, /* 6 */ - {0, 0, 0, 0} /* backstop */ -}; - -/* - * Digits 0-3 (day hundreds) - */ -#define P3 (P15 / 2) /* mark (+1) */ -#define N3 (N15 / 2) /* space (-1) */ - -double bcd3[][4] = { - {N3, N3, 0, 0}, /* 0 */ - {P3, N3, 0, 0}, /* 1 */ - {N3, P3, 0, 0}, /* 2 */ - {P3, P3, 0, 0}, /* 3 */ - {0, 0, 0, 0} /* backstop */ -}; - -/* - * Digits 0-2 (hour tens) - */ -#define P2 (P15 / 2) /* mark (+1) */ -#define N2 (N15 / 2) /* space (-1) */ - -double bcd2[][4] = { - {N2, N2, 0, 0}, /* 0 */ - {P2, N2, 0, 0}, /* 1 */ - {N2, P2, 0, 0}, /* 2 */ - {0, 0, 0, 0} /* backstop */ -}; - -/* - * DST decode (DST2 DST1) for prettyprint - */ -char dstcod[] = { - 'S', /* 00 standard time */ - 'I', /* 01 set clock ahead at 0200 local */ - 'O', /* 10 set clock back at 0200 local */ - 'D' /* 11 daylight time */ -}; - -/* - * The decoding matrix consists of nine row vectors, one for each digit - * of the timecode. The digits are stored from least to most significant - * order. The maximum likelihood timecode is formed from the digits - * corresponding to the maximum likelihood values reading in the - * opposite order: yy ddd hh:mm. - */ -struct decvec { - int radix; /* radix (3, 4, 6, 10) */ - int digit; /* current clock digit */ - int mldigit; /* maximum likelihood digit */ - int phase; /* maximum likelihood digit phase */ - int count; /* match count */ - double digprb; /* max digit probability */ - double digsnr; /* likelihood function (dB) */ - double like[10]; /* likelihood integrator 0-9 */ -}; - -/* - * The station structure is used to acquire the minute pulse from WWV - * and/or WWVH. These stations are distinguished by the frequency used - * for the second and minute sync pulses, 1000 Hz for WWV and 1200 Hz - * for WWVH. Other than frequency, the format is the same. - */ -struct sync { - double epoch; /* accumulated epoch differences */ - double maxamp; /* sync max envelope (square) */ - double noiamp; /* sync noise envelope (square) */ - long pos; /* max amplitude position */ - long lastpos; /* last max position */ - long mepoch; /* minute synch epoch */ - - double amp; /* sync amplitude (I, Q squares) */ - double synamp; /* sync max envelope at 800 ms */ - double synmax; /* sync envelope at 0 s */ - double synmin; /* sync envelope at 59, 1 s */ - double synsnr; /* sync signal SNR */ - int count; /* bit counter */ - char refid[5]; /* reference identifier */ - int select; /* select bits */ - int reach; /* reachability register */ -}; - -/* - * The channel structure is used to mitigate between channels. - */ -struct chan { - int gain; /* audio gain */ - double sigamp; /* data max envelope (square) */ - double noiamp; /* data noise envelope (square) */ - double datsnr; /* data signal SNR */ - struct sync wwv; /* wwv station */ - struct sync wwvh; /* wwvh station */ -}; - -/* - * WWV unit control structure - */ -struct wwvunit { - l_fp timestamp; /* audio sample timestamp */ - l_fp tick; /* audio sample increment */ - double phase, freq; /* logical clock phase and frequency */ - double monitor; /* audio monitor point */ - int fd_icom; /* ICOM file descriptor */ - int errflg; /* error flags */ - int watch; /* watchcat */ - - /* - * Audio codec variables - */ - double comp[SIZE]; /* decompanding table */ - int port; /* codec port */ - int gain; /* codec gain */ - int mongain; /* codec monitor gain */ - int clipcnt; /* sample clipped count */ -#ifdef IRIG_SUCKS - l_fp wigwag; /* wiggle accumulator */ - int wp; /* wiggle filter pointer */ - l_fp wiggle[WIGGLE]; /* wiggle filter */ - l_fp wigbot[WIGGLE]; /* wiggle bottom fisher*/ -#endif /* IRIG_SUCKS */ - - /* - * Variables used to establish basic system timing - */ - int avgint; /* master time constant */ - int tepoch; /* sync epoch median */ - int yepoch; /* sync epoch */ - int repoch; /* buffered sync epoch */ - double epomax; /* second sync amplitude */ - double eposnr; /* second sync SNR */ - double irig; /* data I channel amplitude */ - double qrig; /* data Q channel amplitude */ - int datapt; /* 100 Hz ramp */ - double datpha; /* 100 Hz VFO control */ - int rphase; /* second sample counter */ - long mphase; /* minute sample counter */ - - /* - * Variables used to mitigate which channel to use - */ - struct chan mitig[NCHAN]; /* channel data */ - struct sync *sptr; /* station pointer */ - int dchan; /* data channel */ - int schan; /* probe channel */ - int achan; /* active channel */ - - /* - * Variables used by the clock state machine - */ - struct decvec decvec[9]; /* decoding matrix */ - int rsec; /* seconds counter */ - int digcnt; /* count of digits synchronized */ - - /* - * Variables used to estimate signal levels and bit/digit - * probabilities - */ - double sigsig; /* data max signal */ - double sigamp; /* data max envelope (square) */ - double noiamp; /* data noise envelope (square) */ - double datsnr; /* data SNR (dB) */ - - /* - * Variables used to establish status and alarm conditions - */ - int status; /* status bits */ - int alarm; /* alarm flashers */ - int misc; /* miscellaneous timecode bits */ - int errcnt; /* data bit error counter */ - int errbit; /* data bit errors in minute */ -}; - -/* - * Function prototypes - */ -static int wwv_start P((int, struct peer *)); -static void wwv_shutdown P((int, struct peer *)); -static void wwv_receive P((struct recvbuf *)); -static void wwv_poll P((int, struct peer *)); - -/* - * More function prototypes - */ -static void wwv_epoch P((struct peer *)); -static void wwv_rf P((struct peer *, double)); -static void wwv_endpoc P((struct peer *, int)); -static void wwv_rsec P((struct peer *, double)); -static void wwv_qrz P((struct peer *, struct sync *, - double, int)); -static void wwv_corr4 P((struct peer *, struct decvec *, - double [], double [][4])); -static void wwv_gain P((struct peer *)); -static void wwv_tsec P((struct wwvunit *)); -static double wwv_data P((struct wwvunit *, double)); -static int timecode P((struct wwvunit *, char *)); -static double wwv_snr P((double, double)); -static int carry P((struct decvec *)); -static void wwv_newchan P((struct peer *)); -static void wwv_newgame P((struct peer *)); -static double wwv_metric P((struct sync *)); -#ifdef ICOM -static int wwv_qsy P((struct peer *, int)); -#endif /* ICOM */ - -static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */ - -/* - * Transfer vector - */ -struct refclock refclock_wwv = { - wwv_start, /* start up driver */ - wwv_shutdown, /* shut down driver */ - wwv_poll, /* transmit poll message */ - noentry, /* not used (old wwv_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old wwv_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * wwv_start - open the devices and initialize data for processing - */ -static int -wwv_start( - int unit, /* instance number (used by PCM) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; -#ifdef ICOM - int temp; -#endif /* ICOM */ - - /* - * Local variables - */ - int fd; /* file descriptor */ - int i; /* index */ - double step; /* codec adjustment */ - - /* - * Open audio device - */ - fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); - if (fd < 0) - return (0); -#ifdef DEBUG - if (debug) - audio_show(); -#endif - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) { - close(fd); - return (0); - } - memset(up, 0, sizeof(struct wwvunit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = wwv_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - - /* - * The companded samples are encoded sign-magnitude. The table - * contains all the 256 values in the interest of speed. - */ - 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.; - step = 2.; - for (i = 3; i < OFFSET; i++) { - up->comp[i] = up->comp[i - 1] + step; - up->comp[OFFSET + i] = -up->comp[i]; - if (i % 16 == 0) - step *= 2.; - } - DTOLFP(1. / SECOND, &up->tick); - - /* - * Initialize the decoding matrix with the radix for each digit - * position. - */ - up->decvec[MN].radix = 10; /* minutes */ - up->decvec[MN + 1].radix = 6; - up->decvec[HR].radix = 10; /* hours */ - up->decvec[HR + 1].radix = 3; - up->decvec[DA].radix = 10; /* days */ - up->decvec[DA + 1].radix = 10; - up->decvec[DA + 2].radix = 4; - up->decvec[YR].radix = 10; /* years */ - up->decvec[YR + 1].radix = 10; - wwv_newgame(peer); - up->schan = up->achan = 3; - - /* - * Initialize autotune if available. Start out at 15 MHz. Note - * that the ICOM select code must be less than 128, so the high - * order bit can be used to select the line speed. - */ -#ifdef ICOM - temp = 0; -#ifdef DEBUG - if (debug > 1) - temp = P_TRACE; -#endif - if (peer->ttl != 0) { - if (peer->ttl & 0x80) - up->fd_icom = icom_init("/dev/icom", B1200, - temp); - else - up->fd_icom = icom_init("/dev/icom", B9600, - temp); - } - if (up->fd_icom > 0) { - if ((temp = wwv_qsy(peer, up->schan)) != 0) { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: radio not found"); - up->errflg = CEVNT_FAULT; - close(up->fd_icom); - up->fd_icom = 0; - } else { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: autotune enabled"); - } - } -#endif /* ICOM */ - return (1); -} - - -/* - * wwv_shutdown - shut down the clock - */ -static void -wwv_shutdown( - int unit, /* instance number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - io_closeclock(&pp->io); - if (up->fd_icom > 0) - close(up->fd_icom); - free(up); -} - - -/* - * wwv_receive - receive data from the audio device - * - * This routine reads input samples and adjusts the logical clock to - * track the A/D sample clock by dropping or duplicating codec samples. - * It also controls the A/D signal level with an AGC loop to mimimize - * quantization noise and avoid overload. - */ -static void -wwv_receive( - struct recvbuf *rbufp /* receive buffer structure pointer */ - ) -{ - struct peer *peer; - struct refclockproc *pp; - struct wwvunit *up; - - /* - * Local variables - */ - double sample; /* codec sample */ - u_char *dpt; /* buffer pointer */ - int bufcnt; /* buffer counter */ - l_fp ltemp; - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Main loop - read until there ain't no more. Note codec - * samples are bit-inverted. - */ - DTOLFP((double)rbufp->recv_length / SECOND, <emp); - L_SUB(&rbufp->recv_time, <emp); - up->timestamp = rbufp->recv_time; - dpt = rbufp->recv_buffer; - for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { - sample = up->comp[~*dpt++ & 0xff]; - - /* - * Clip noise spikes greater than MAXSIG. If no clips, - * increase the gain a tad; if the clips are too high, - * decrease a tad. - */ - if (sample > MAXSIG) { - sample = MAXSIG; - up->clipcnt++; - } else if (sample < -MAXSIG) { - sample = -MAXSIG; - up->clipcnt++; - } - - /* - * Variable frequency oscillator. The codec oscillator - * runs at the nominal rate of 8000 samples per second, - * or 125 us per sample. A frequency change of one unit - * results in either duplicating or deleting one sample - * per second, which results in a frequency change of - * 125 PPM. - */ - up->phase += up->freq / SECOND; - if (up->phase >= .5) { - up->phase -= 1.; - } else if (up->phase < -.5) { - up->phase += 1.; - wwv_rf(peer, sample); - wwv_rf(peer, sample); - } else { - wwv_rf(peer, sample); - } - L_ADD(&up->timestamp, &up->tick); - } - - /* - * Set the input port and monitor gain for the next buffer. - */ - if (pp->sloppyclockflag & CLK_FLAG2) - up->port = 2; - else - up->port = 1; - if (pp->sloppyclockflag & CLK_FLAG3) - up->mongain = MONGAIN; - else - up->mongain = 0; -} - - -/* - * wwv_poll - called by the transmit procedure - * - * This routine keeps track of status. If no offset samples have been - * processed during a poll interval, a timeout event is declared. If - * errors have have occurred during the interval, they are reported as - * well. Once the clock is set, it always appears reachable, unless - * reset by watchdog timeout. - */ -static void -wwv_poll( - int unit, /* instance number (not used) */ - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - if (pp->coderecv == pp->codeproc) - up->errflg = CEVNT_TIMEOUT; - if (up->errflg) - refclock_report(peer, up->errflg); - up->errflg = 0; - pp->polls++; -} - - -/* - * wwv_rf - process signals and demodulate to baseband - * - * This routine grooms and filters decompanded raw audio samples. The - * output signals include the 100-Hz baseband data signal in quadrature - * form, plus the epoch index of the second sync signal and the second - * index of the minute sync signal. - * - * There are two 1-s ramps used by this program. Both count the 8000 - * logical clock samples spanning exactly one second. The epoch ramp - * counts the samples starting at an arbitrary time. The rphase ramp - * counts the samples starting at the 5-ms second sync pulse found - * during the epoch ramp. - * - * There are two 1-m ramps used by this program. The mphase ramp counts - * the 480,000 logical clock samples spanning exactly one minute and - * starting at an arbitrary time. The rsec ramp counts the 60 seconds of - * the minute starting at the 800-ms minute sync pulse found during the - * mphase ramp. The rsec ramp drives the seconds state machine to - * determine the bits and digits of the timecode. - * - * Demodulation operations are based on three synthesized quadrature - * sinusoids: 100 Hz for the data signal, 1000 Hz for the WWV sync - * signal and 1200 Hz for the WWVH sync signal. These drive synchronous - * matched filters for the data signal (170 ms at 100 Hz), WWV minute - * sync signal (800 ms at 1000 Hz) and WWVH minute sync signal (800 ms - * at 1200 Hz). Two additional matched filters are switched in - * as required for the WWV second sync signal (5 ms at 1000 Hz) and - * WWVH second sync signal (5 ms at 1200 Hz). - */ -static void -wwv_rf( - struct peer *peer, /* peerstructure pointer */ - double isig /* input signal */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - struct sync *sp; - - static double lpf[5]; /* 150-Hz lpf delay line */ - double data; /* lpf output */ - static double bpf[9]; /* 1000/1200-Hz bpf delay line */ - double syncx; /* bpf output */ - static double mf[41]; /* 1000/1200-Hz mf delay line */ - double mfsync; /* mf output */ - - static int iptr; /* data channel pointer */ - static double ibuf[DATSIZ]; /* data I channel delay line */ - static double qbuf[DATSIZ]; /* data Q channel delay line */ - - static int jptr; /* sync channel pointer */ - static double cibuf[SYNSIZ]; /* wwv I channel delay line */ - static double cqbuf[SYNSIZ]; /* wwv Q channel delay line */ - static double ciamp; /* wwv I channel amplitude */ - static double cqamp; /* wwv Q channel amplitude */ - static int csinptr; /* wwv channel phase */ - static double hibuf[SYNSIZ]; /* wwvh I channel delay line */ - static double hqbuf[SYNSIZ]; /* wwvh Q channel delay line */ - static double hiamp; /* wwvh I channel amplitude */ - static double hqamp; /* wwvh Q channel amplitude */ - static int hsinptr; /* wwvh channels phase */ - - static double epobuf[SECOND]; /* epoch sync comb filter */ - static double epomax; /* epoch sync amplitude buffer */ - static int epopos; /* epoch sync position buffer */ - - static int iniflg; /* initialization flag */ - int epoch; /* comb filter index */ - int pdelay; /* propagation delay (samples) */ - double dtemp; - int i; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - if (!iniflg) { - iniflg = 1; - memset((char *)lpf, 0, sizeof(lpf)); - memset((char *)bpf, 0, sizeof(bpf)); - memset((char *)mf, 0, sizeof(mf)); - memset((char *)ibuf, 0, sizeof(ibuf)); - memset((char *)qbuf, 0, sizeof(qbuf)); - memset((char *)cibuf, 0, sizeof(cibuf)); - memset((char *)cqbuf, 0, sizeof(cqbuf)); - memset((char *)hibuf, 0, sizeof(hibuf)); - memset((char *)hqbuf, 0, sizeof(hqbuf)); - memset((char *)epobuf, 0, sizeof(epobuf)); - } - - /* - * Baseband data demodulation. The 100-Hz subcarrier is - * extracted using a 150-Hz IIR lowpass filter. This attenuates - * the 1000/1200-Hz sync signals, as well as the 440-Hz and - * 600-Hz tones and most of the noise and voice modulation - * components. - * - * Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB - * passband ripple, -50 dB stopband ripple. - */ - data = (lpf[4] = lpf[3]) * 8.360961e-01; - data += (lpf[3] = lpf[2]) * -3.481740e+00; - data += (lpf[2] = lpf[1]) * 5.452988e+00; - data += (lpf[1] = lpf[0]) * -3.807229e+00; - lpf[0] = isig - data; - data = lpf[0] * 3.281435e-03 - + lpf[1] * -1.149947e-02 - + lpf[2] * 1.654858e-02 - + lpf[3] * -1.149947e-02 - + lpf[4] * 3.281435e-03; - - /* - * The I and Q quadrature data signals are produced by - * multiplying the filtered signal by 100-Hz sine and cosine - * signals, respectively. The data signals are demodulated by - * 170-ms synchronous matched filters to produce the amplitude - * and phase signals used by the decoder. - */ - i = up->datapt; - up->datapt = (up->datapt + IN100) % 80; - dtemp = sintab[i] * data / DATSIZ * DGAIN; - up->irig -= ibuf[iptr]; - ibuf[iptr] = dtemp; - up->irig += dtemp; - i = (i + 20) % 80; - dtemp = sintab[i] * data / DATSIZ * DGAIN; - up->qrig -= qbuf[iptr]; - qbuf[iptr] = dtemp; - up->qrig += dtemp; - iptr = (iptr + 1) % DATSIZ; - - /* - * Baseband sync demodulation. The 1000/1200 sync signals are - * extracted using a 600-Hz IIR bandpass filter. This removes - * the 100-Hz data subcarrier, as well as the 440-Hz and 600-Hz - * tones and most of the noise and voice modulation components. - * - * Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB - * passband ripple, -50 dB stopband ripple. - */ - syncx = (bpf[8] = bpf[7]) * 4.897278e-01; - syncx += (bpf[7] = bpf[6]) * -2.765914e+00; - syncx += (bpf[6] = bpf[5]) * 8.110921e+00; - syncx += (bpf[5] = bpf[4]) * -1.517732e+01; - syncx += (bpf[4] = bpf[3]) * 1.975197e+01; - syncx += (bpf[3] = bpf[2]) * -1.814365e+01; - syncx += (bpf[2] = bpf[1]) * 1.159783e+01; - syncx += (bpf[1] = bpf[0]) * -4.735040e+00; - bpf[0] = isig - syncx; - syncx = bpf[0] * 8.203628e-03 - + bpf[1] * -2.375732e-02 - + bpf[2] * 3.353214e-02 - + bpf[3] * -4.080258e-02 - + bpf[4] * 4.605479e-02 - + bpf[5] * -4.080258e-02 - + bpf[6] * 3.353214e-02 - + bpf[7] * -2.375732e-02 - + bpf[8] * 8.203628e-03; - - /* - * The I and Q quadrature minute sync signals are produced by - * multiplying the filtered signal by 1000-Hz (WWV) and 1200-Hz - * (WWVH) sine and cosine signals, respectively. The resulting - * signals are demodulated by 800-ms synchronous matched filters - * to synchronize the second and minute and to detect which one - * (or both) the WWV or WWVH signal is present. - * - * Note the master timing ramps, which run continuously. The - * minute counter (mphase) counts the samples in the minute, - * while the second counter (epoch) counts the samples in the - * second. - */ - up->mphase = (up->mphase + 1) % MINUTE; - epoch = up->mphase % SECOND; - i = csinptr; - csinptr = (csinptr + IN1000) % 80; - dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; - ciamp = ciamp - cibuf[jptr] + dtemp; - cibuf[jptr] = dtemp; - i = (i + 20) % 80; - dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; - cqamp = cqamp - cqbuf[jptr] + dtemp; - cqbuf[jptr] = dtemp; - sp = &up->mitig[up->schan].wwv; - dtemp = ciamp * ciamp + cqamp * cqamp; - sp->amp = dtemp; - if (!(up->status & MSYNC)) - wwv_qrz(peer, sp, dtemp, (int)(pp->fudgetime1 * - SECOND)); - i = hsinptr; - hsinptr = (hsinptr + IN1200) % 80; - dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; - hiamp = hiamp - hibuf[jptr] + dtemp; - hibuf[jptr] = dtemp; - i = (i + 20) % 80; - dtemp = sintab[i] * syncx / SYNSIZ * SGAIN; - hqamp = hqamp - hqbuf[jptr] + dtemp; - hqbuf[jptr] = dtemp; - sp = &up->mitig[up->schan].wwvh; - dtemp = hiamp * hiamp + hqamp * hqamp; - sp->amp = dtemp; - if (!(up->status & MSYNC)) - wwv_qrz(peer, sp, dtemp, (int)(pp->fudgetime2 * - SECOND)); - jptr = (jptr + 1) % SYNSIZ; - - /* - * The following section is called once per minute. It does - * housekeeping and timeout functions and empties the dustbins. - */ - if (up->mphase == 0) { - up->watch++; - if (!(up->status & MSYNC)) { - - /* - * If minute sync has not been acquired before - * timeout, or if no signal is heard, the - * program cycles to the next frequency and - * tries again. - */ - wwv_newchan(peer); - if (!(up->status & (SELV | SELH)) || up->watch > - ACQSN) { - wwv_newgame(peer); -#ifdef ICOM - if (up->fd_icom > 0) { - up->schan = (up->schan + 1) % - NCHAN; - wwv_qsy(peer, up->schan); - } -#endif /* ICOM */ - } - } else { - - /* - * If the leap bit is set, set the minute epoch - * back one second so the station processes - * don't miss a beat. - */ - if (up->status & LEPSEC) { - up->mphase -= SECOND; - if (up->mphase < 0) - up->mphase += MINUTE; - } - } - } - - /* - * When the channel metric reaches threshold and the second - * counter matches the minute epoch within the second, the - * driver has synchronized to the station. The second number is - * the remaining seconds until the next minute epoch, while the - * sync epoch is zero. Watch out for the first second; if - * already synchronized to the second, the buffered sync epoch - * must be set. - */ - if (up->status & MSYNC) { - wwv_epoch(peer); - } else if ((sp = up->sptr) != NULL) { - struct chan *cp; - - if (sp->count >= AMIN && epoch == sp->mepoch % SECOND) { - up->rsec = 60 - sp->mepoch / SECOND; - up->rphase = 0; - up->status |= MSYNC; - up->watch = 0; - if (!(up->status & SSYNC)) - up->repoch = up->yepoch = epoch; - else - up->repoch = up->yepoch; - for (i = 0; i < NCHAN; i++) { - cp = &up->mitig[i]; - cp->wwv.count = cp->wwv.reach = 0; - cp->wwvh.count = cp->wwvh.reach = 0; - } - } - } - - /* - * The second sync pulse is extracted using 5-ms (40 sample) FIR - * matched filters at 1000 Hz for WWV or 1200 Hz for WWVH. This - * pulse is used for the most precise synchronization, since if - * provides a resolution of one sample (125 us). The filters run - * only if the station has been reliably determined. - */ - if (up->status & SELV) { - pdelay = (int)(pp->fudgetime1 * SECOND); - - /* - * WWV FIR matched filter, five cycles of 1000-Hz - * sinewave. - */ - mf[40] = mf[39]; - mfsync = (mf[39] = mf[38]) * 4.224514e-02; - mfsync += (mf[38] = mf[37]) * 5.974365e-02; - mfsync += (mf[37] = mf[36]) * 4.224514e-02; - mf[36] = mf[35]; - mfsync += (mf[35] = mf[34]) * -4.224514e-02; - mfsync += (mf[34] = mf[33]) * -5.974365e-02; - mfsync += (mf[33] = mf[32]) * -4.224514e-02; - mf[32] = mf[31]; - mfsync += (mf[31] = mf[30]) * 4.224514e-02; - mfsync += (mf[30] = mf[29]) * 5.974365e-02; - mfsync += (mf[29] = mf[28]) * 4.224514e-02; - mf[28] = mf[27]; - mfsync += (mf[27] = mf[26]) * -4.224514e-02; - mfsync += (mf[26] = mf[25]) * -5.974365e-02; - mfsync += (mf[25] = mf[24]) * -4.224514e-02; - mf[24] = mf[23]; - mfsync += (mf[23] = mf[22]) * 4.224514e-02; - mfsync += (mf[22] = mf[21]) * 5.974365e-02; - mfsync += (mf[21] = mf[20]) * 4.224514e-02; - mf[20] = mf[19]; - mfsync += (mf[19] = mf[18]) * -4.224514e-02; - mfsync += (mf[18] = mf[17]) * -5.974365e-02; - mfsync += (mf[17] = mf[16]) * -4.224514e-02; - mf[16] = mf[15]; - mfsync += (mf[15] = mf[14]) * 4.224514e-02; - mfsync += (mf[14] = mf[13]) * 5.974365e-02; - mfsync += (mf[13] = mf[12]) * 4.224514e-02; - mf[12] = mf[11]; - mfsync += (mf[11] = mf[10]) * -4.224514e-02; - mfsync += (mf[10] = mf[9]) * -5.974365e-02; - mfsync += (mf[9] = mf[8]) * -4.224514e-02; - mf[8] = mf[7]; - mfsync += (mf[7] = mf[6]) * 4.224514e-02; - mfsync += (mf[6] = mf[5]) * 5.974365e-02; - mfsync += (mf[5] = mf[4]) * 4.224514e-02; - mf[4] = mf[3]; - mfsync += (mf[3] = mf[2]) * -4.224514e-02; - mfsync += (mf[2] = mf[1]) * -5.974365e-02; - mfsync += (mf[1] = mf[0]) * -4.224514e-02; - mf[0] = syncx; - } else if (up->status & SELH) { - pdelay = (int)(pp->fudgetime2 * SECOND); - - /* - * WWVH FIR matched filter, six cycles of 1200-Hz - * sinewave. - */ - mf[40] = mf[39]; - mfsync = (mf[39] = mf[38]) * 4.833363e-02; - mfsync += (mf[38] = mf[37]) * 5.681959e-02; - mfsync += (mf[37] = mf[36]) * 1.846180e-02; - mfsync += (mf[36] = mf[35]) * -3.511644e-02; - mfsync += (mf[35] = mf[34]) * -5.974365e-02; - mfsync += (mf[34] = mf[33]) * -3.511644e-02; - mfsync += (mf[33] = mf[32]) * 1.846180e-02; - mfsync += (mf[32] = mf[31]) * 5.681959e-02; - mfsync += (mf[31] = mf[30]) * 4.833363e-02; - mf[30] = mf[29]; - mfsync += (mf[29] = mf[28]) * -4.833363e-02; - mfsync += (mf[28] = mf[27]) * -5.681959e-02; - mfsync += (mf[27] = mf[26]) * -1.846180e-02; - mfsync += (mf[26] = mf[25]) * 3.511644e-02; - mfsync += (mf[25] = mf[24]) * 5.974365e-02; - mfsync += (mf[24] = mf[23]) * 3.511644e-02; - mfsync += (mf[23] = mf[22]) * -1.846180e-02; - mfsync += (mf[22] = mf[21]) * -5.681959e-02; - mfsync += (mf[21] = mf[20]) * -4.833363e-02; - mf[20] = mf[19]; - mfsync += (mf[19] = mf[18]) * 4.833363e-02; - mfsync += (mf[18] = mf[17]) * 5.681959e-02; - mfsync += (mf[17] = mf[16]) * 1.846180e-02; - mfsync += (mf[16] = mf[15]) * -3.511644e-02; - mfsync += (mf[15] = mf[14]) * -5.974365e-02; - mfsync += (mf[14] = mf[13]) * -3.511644e-02; - mfsync += (mf[13] = mf[12]) * 1.846180e-02; - mfsync += (mf[12] = mf[11]) * 5.681959e-02; - mfsync += (mf[11] = mf[10]) * 4.833363e-02; - mf[10] = mf[9]; - mfsync += (mf[9] = mf[8]) * -4.833363e-02; - mfsync += (mf[8] = mf[7]) * -5.681959e-02; - mfsync += (mf[7] = mf[6]) * -1.846180e-02; - mfsync += (mf[6] = mf[5]) * 3.511644e-02; - mfsync += (mf[5] = mf[4]) * 5.974365e-02; - mfsync += (mf[4] = mf[3]) * 3.511644e-02; - mfsync += (mf[3] = mf[2]) * -1.846180e-02; - mfsync += (mf[2] = mf[1]) * -5.681959e-02; - mfsync += (mf[1] = mf[0]) * -4.833363e-02; - mf[0] = syncx; - } else { - mfsync = 0; - pdelay = 0; - } - - /* - * Enhance the seconds sync pulse using a 1-s (8000-sample) comb - * filter. Correct for the FIR matched filter delay, which is 5 - * ms for both the WWV and WWVH filters, and also for the - * propagation delay. Once each second look for second sync. If - * not in minute sync, fiddle the codec gain. Note the SNR is - * computed from the maximum sample and the two samples 6 ms - * before and 6 ms after it, so if we slip more than a cycle the - * SNR should plummet. - */ - dtemp = (epobuf[epoch] += (mfsync - epobuf[epoch]) / - up->avgint); - if (dtemp > epomax) { - epomax = dtemp; - epopos = epoch; - } - if (epoch == 0) { - int k, j; - - up->epomax = epomax; - k = epopos - 6 * MS; - if (k < 0) - k += SECOND; - j = epopos + 6 * MS; - if (j >= SECOND) - i -= SECOND; - up->eposnr = wwv_snr(epomax, max(abs(epobuf[k]), - abs(epobuf[j]))); - epopos -= pdelay + 5 * MS; - if (epopos < 0) - epopos += SECOND; - wwv_endpoc(peer, epopos); - if (!(up->status & SSYNC)) - up->alarm |= SYNERR; - epomax = 0; - if (!(up->status & MSYNC)) - wwv_gain(peer); - } -} - - -/* - * wwv_qrz - identify and acquire WWV/WWVH minute sync pulse - * - * This routine implements a virtual station process used to acquire - * minute sync and to mitigate among the ten frequency and station - * combinations. During minute sync acquisition the process probes each - * frequency in turn for the minute pulse from either station, which - * involves searching through the entire minute of samples. After - * finding a candidate, the process searches only the seconds before and - * after the candidate for the signal and all other seconds for the - * noise. - * - * Students of radar receiver technology will discover this algorithm - * amounts to a range gate discriminator. The discriminator requires - * that the peak minute pulse amplitude be at least 2000 and the SNR be - * at least 6 dB. In addition after finding a candidate, The peak second - * pulse amplitude must be at least 2000, the SNR at least 6 dB and the - * difference between the current and previous epoch must be less than - * 7.5 ms, which corresponds to a frequency error of 125 PPM.. A compare - * counter keeps track of the number of successive intervals which - * satisfy these criteria. - * - * Note that, while the minute pulse is found by by the discriminator, - * the actual value is determined from the second epoch. The assumption - * is that the discriminator peak occurs about 800 ms into the second, - * so the timing is retarted to the previous second epoch. - */ -static void -wwv_qrz( - struct peer *peer, /* peer structure pointer */ - struct sync *sp, /* sync channel structure */ - double syncx, /* bandpass filtered sync signal */ - int pdelay /* propagation delay (samples) */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - char tbuf[80]; /* monitor buffer */ - double snr; /* on-pulse/off-pulse ratio (dB) */ - long epoch, fpoch; - int isgood; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Find the sample with peak energy, which defines the minute - * epoch. If a sample has been found with good amplitude, - * accumulate the noise squares for all except the second before - * and after that position. - */ - isgood = up->epomax > STHR && up->eposnr > SSNR; - if (isgood) { - fpoch = up->mphase % SECOND - up->tepoch; - if (fpoch < 0) - fpoch += SECOND; - } else { - fpoch = pdelay + SYNSIZ; - } - epoch = up->mphase - fpoch; - if (epoch < 0) - epoch += MINUTE; - if (syncx > sp->maxamp) { - sp->maxamp = syncx; - sp->pos = epoch; - } - if (abs((epoch - sp->lastpos) % MINUTE) > SECOND) - sp->noiamp += syncx; - - /* - * At the end of the minute, determine the epoch of the - * sync pulse, as well as the SNR and difference between - * the current and previous epoch, which represents the - * intrinsic frequency error plus jitter. - */ - if (up->mphase == 0) { - sp->synmax = sqrt(sp->maxamp); - sp->synmin = sqrt(sp->noiamp / (MINUTE - 2 * SECOND)); - epoch = (sp->pos - sp->lastpos) % MINUTE; - - /* - * If not yet in minute sync, we have to do a little - * dance to find a valid minute sync pulse, emphasis - * valid. - */ - snr = wwv_snr(sp->synmax, sp->synmin); - isgood = isgood && sp->synmax > ATHR && snr > ASNR; - switch (sp->count) { - - /* - * In state 0 the station was not heard during the - * previous probe. Look for the biggest blip greater - * than the amplitude threshold in the minute and assume - * that the minute sync pulse. We're fishing here, since - * the range gate has not yet been determined. If found, - * bump to state 1. - */ - case 0: - if (sp->synmax >= ATHR) - sp->count++; - break; - - /* - * In state 1 a candidate blip has been found and the - * next minute has been searched for another blip. If - * none are found acceptable, drop back to state 0 and - * hunt some more. Otherwise, a legitimate minute pulse - * may have been found, so bump to state 2. - */ - case 1: - if (!isgood) { - sp->count = 0; - break; - } - sp->count++; - break; - - /* - * In states 2 and above, continue to groom samples as - * before and drop back to state 0 if the groom fails. - * If it succeeds, set the epoch and bump to the next - * state until reaching the threshold, if ever. - */ - default: - if (!isgood || abs(epoch) > AWND * MS) { - sp->count = 0; - break; - } - sp->mepoch = sp->pos; - sp->count++; - break; - } - if (pp->sloppyclockflag & CLK_FLAG4) { - sprintf(tbuf, - "wwv8 %d %3d %s %d %5.0f %5.1f %5ld %5d %ld", - up->port, up->gain, sp->refid, sp->count, - sp->synmax, snr, sp->pos, up->tepoch, - epoch); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif - } - sp->lastpos = sp->pos; - sp->maxamp = sp->noiamp = 0; - } -} - - -/* - * wwv_endpoc - identify and acquire second sync pulse - * - * This routine is called at the end of the second sync interval. It - * determines the second sync epoch position within the interval and - * disciplines the sample clock using a frequency-lock loop (FLL). - * - * Second sync is determined in the RF input routine as the maximum - * over all 8000 samples in the second comb filter. To assure accurate - * and reliable time and frequency discipline, this routine performs a - * great deal of heavy-handed heuristic data filtering and grooming. - * - * Note that, since the minute sync pulse is very wide (800 ms), precise - * minute sync epoch acquisition requires at least a rough estimate of - * the second sync pulse (5 ms). This becomes more important in choppy - * conditions at the lower frequencies at night, since sferics and - * cochannel crude can badly distort the minute pulse. - */ -static void -wwv_endpoc( - struct peer *peer, /* peer structure pointer */ - int epopos /* epoch max position */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - static int epoch_mf[3]; /* epoch median filter */ - static int xepoch; /* last second epoch */ - static int zepoch; /* last averaging interval epoch */ - static int syncnt; /* run length counter */ - static int maxrun; /* longest run length */ - static int mepoch; /* longest run epoch */ - static int avgcnt; /* averaging interval counter */ - static int avginc; /* averaging ratchet */ - static int iniflg; /* initialization flag */ - char tbuf[80]; /* monitor buffer */ - double dtemp; - int tmp2; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - if (!iniflg) { - iniflg = 1; - memset((char *)epoch_mf, 0, sizeof(epoch_mf)); - } - - /* - * A three-stage median filter is used to help denoise the - * second sync pulse. The median sample becomes the candidate - * epoch. - */ - epoch_mf[2] = epoch_mf[1]; - epoch_mf[1] = epoch_mf[0]; - epoch_mf[0] = epopos; - if (epoch_mf[0] > epoch_mf[1]) { - if (epoch_mf[1] > epoch_mf[2]) - up->tepoch = epoch_mf[1]; /* 0 1 2 */ - else if (epoch_mf[2] > epoch_mf[0]) - up->tepoch = epoch_mf[0]; /* 2 0 1 */ - else - up->tepoch = epoch_mf[2]; /* 0 2 1 */ - } else { - if (epoch_mf[1] < epoch_mf[2]) - up->tepoch = epoch_mf[1]; /* 2 1 0 */ - else if (epoch_mf[2] < epoch_mf[0]) - up->tepoch = epoch_mf[0]; /* 1 0 2 */ - else - up->tepoch = epoch_mf[2]; /* 1 2 0 */ - } - - /* - * If the signal amplitude or SNR fall below thresholds or if no - * stations are heard, dim the second sync lamp and start over. - */ - if (!(up->status & (SELV | SELH)) || up->epomax < STHR || - up->eposnr < SSNR) { - up->status &= ~(SSYNC | FGATE); - avgcnt = syncnt = maxrun = 0; - return; - } - avgcnt++; - - /* - * If the epoch candidate is the same as the last one, increment - * the compare counter. If not, save the length and epoch of the - * current run for use later and reset the counter. - */ - tmp2 = (up->tepoch - xepoch) % SECOND; - if (tmp2 == 0) { - syncnt++; - } else { - if (maxrun > 0 && mepoch == xepoch) { - maxrun += syncnt; - } else if (syncnt > maxrun) { - maxrun = syncnt; - mepoch = xepoch; - } - syncnt = 0; - } - if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & (SSYNC | - MSYNC))) { - sprintf(tbuf, - "wwv1 %04x %5.0f %5.1f %5d %5d %4d %4d", - up->status, up->epomax, up->eposnr, up->tepoch, - tmp2, avgcnt, syncnt); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif /* DEBUG */ - } - - /* - * The sample clock frequency is disciplined using a first order - * feedback loop with time constant consistent with the Allan - * intercept of typical computer clocks. - * - * The frequency update is calculated from the epoch change in - * 125-us units divided by the averaging interval in seconds. - * The averaging interval affects other receiver functions, - * including the the 1000/1200-Hz comb filter and codec clock - * loop. It also affects the 100-Hz subcarrier loop and the bit - * and digit comparison counter thresholds. - */ - if (avgcnt < up->avgint) { - xepoch = up->tepoch; - return; - } - - /* - * During the averaging interval the longest run of identical - * epoches is determined. If the longest run is at least 10 - * seconds, the SSYNC bit is lit and the value becomes the - * reference epoch for the next interval. If not, the second - * synd lamp is dark and flashers set. - */ - if (maxrun > 0 && mepoch == xepoch) { - maxrun += syncnt; - } else if (syncnt > maxrun) { - maxrun = syncnt; - mepoch = xepoch; - } - xepoch = up->tepoch; - if (maxrun > SCMP) { - up->status |= SSYNC; - up->yepoch = mepoch; - } else { - up->status &= ~SSYNC; - } - - /* - * If the epoch change over the averaging interval is less than - * 1 ms, the frequency is adjusted, but clamped at +-125 PPM. If - * greater than 1 ms, the counter is decremented. If the epoch - * change is less than 0.5 ms, the counter is incremented. If - * the counter increments to +3, the averaging interval is - * doubled and the counter set to zero; if it increments to -3, - * the interval is halved and the counter set to zero. - * - * Here be spooks. From careful observations, the epoch - * sometimes makes a long run of identical samples, then takes a - * lurch due apparently to lost interrupts or spooks. If this - * happens, the epoch change times the maximum run length will - * be greater than the averaging interval, so the lurch should - * be believed but the frequency left alone. Really intricate - * here. - */ - if (maxrun == 0) - mepoch = up->tepoch; - dtemp = (mepoch - zepoch) % SECOND; - if (up->status & FGATE) { - if (abs(dtemp) < MAXFREQ * MINAVG) { - if (maxrun * abs(mepoch - zepoch) < - avgcnt) { - up->freq += dtemp / avgcnt; - if (up->freq > MAXFREQ) - up->freq = MAXFREQ; - else if (up->freq < -MAXFREQ) - up->freq = -MAXFREQ; - } - if (abs(dtemp) < MAXFREQ * MINAVG / 2) { - if (avginc < 3) { - avginc++; - } else { - if (up->avgint < MAXAVG) { - up->avgint <<= 1; - avginc = 0; - } - } - } - } else { - if (avginc > -3) { - avginc--; - } else { - if (up->avgint > MINAVG) { - up->avgint >>= 1; - avginc = 0; - } - } - } - } - if (pp->sloppyclockflag & CLK_FLAG4) { - sprintf(tbuf, - "wwv2 %04x %4.0f %4d %4d %2d %4d %4.0f %6.1f", - up->status, up->epomax, mepoch, maxrun, avginc, - avgcnt, dtemp, up->freq * 1e6 / SECOND); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif /* DEBUG */ - } - up->status |= FGATE; - zepoch = mepoch; - avgcnt = syncnt = maxrun = 0; -} - - -/* - * wwv_epoch - epoch scanner - * - * This routine scans the receiver second epoch to determine the signal - * amplitudes and pulse timings. Receiver synchronization is determined - * by the minute sync pulse detected in the wwv_rf() routine and the - * second sync pulse detected in the wwv_epoch() routine. A pulse width - * discriminator extracts data signals from the 100-Hz subcarrier. The - * transmitted signals are delayed by the propagation delay, receiver - * delay and filter delay of this program. Delay corrections are - * introduced separately for WWV and WWVH. - * - * Most communications radios use a highpass filter in the audio stages, - * which can do nasty things to the subcarrier phase relative to the - * sync pulses. Therefore, the data subcarrier reference phase is - * disciplined using the hardlimited quadrature-phase signal sampled at - * the same time as the in-phase signal. The phase tracking loop uses - * phase adjustments of plus-minus one sample (125 us). - */ -static void -wwv_epoch( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - struct chan *cp; - static double dpulse; /* data pulse length */ - double dtemp; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Sample the minute sync pulse envelopes at epoch 800 for both - * the WWV and WWVH stations. This will be used later for - * channel and station mitigation. Note that the seconds epoch - * is set here well before the end of the second to make sure we - * never seet the epoch backwards. - */ - if (up->rphase == 800 * MS) { - up->repoch = up->yepoch; - cp = &up->mitig[up->achan]; - cp->wwv.synamp = cp->wwv.amp; - cp->wwvh.synamp = cp->wwvh.amp; - } - - /* - * Sample the data subcarrier at epoch 15 ms, giving a guard - * time of +-15 ms from the beginning of the second until the - * pulse rises at 30 ms. The I-channel amplitude is used to - * calculate the slice level. The envelope amplitude is used - * during the probe seconds to determine the SNR. There is a - * compromise here; we want to delay the sample as long as - * possible to give the radio time to change frequency and the - * AGC to stabilize, but as early as possible if the second - * epoch is not exact. - */ - if (up->rphase == 15 * MS) { - up->noiamp = up->irig * up->irig + up->qrig * up->qrig; - - /* - * Sample the data subcarrier at epoch 215 ms, giving a guard - * time of +-15 ms from the earliest the pulse peak can be - * reached to the earliest it can begin to fall. For the data - * channel latch the I-channel amplitude for all except the - * probe seconds and adjust the 100-Hz reference oscillator - * phase using the Q-channel amplitude at this epoch. For the - * probe channel latch the envelope amplitude. - */ - } else if (up->rphase == 215 * MS) { - up->sigsig = up->irig; - if (up->sigsig < 0) - up->sigsig = 0; - up->datpha = up->qrig / up->avgint; - if (up->datpha >= 0) { - up->datapt++; - if (up->datapt >= 80) - up->datapt -= 80; - } else { - up->datapt--; - if (up->datapt < 0) - up->datapt += 80; - } - up->sigamp = up->irig * up->irig + up->qrig * up->qrig; - - /* - * The slice level is set half way between the peak signal and - * noise levels. Sample the negative zero crossing after epoch - * 200 ms and record the epoch at that time. This defines the - * length of the data pulse, which will later be converted into - * scaled bit probabilities. - */ - } else if (up->rphase > 200 * MS) { - dtemp = (up->sigsig + sqrt(up->noiamp)) / 2; - if (up->irig < dtemp && dpulse == 0) - dpulse = up->rphase; - } - - /* - * At the end of the second crank the clock state machine and - * adjust the codec gain. Note the epoch is buffered from the - * center of the second in order to avoid jitter while the - * seconds synch is diddling the epoch. Then, determine the true - * offset and update the median filter in the driver interface. - * - * Sample the data subcarrier envelope at the end of the second - * to determine the SNR for the pulse. This gives a guard time - * of +-30 ms from the decay of the longest pulse to the rise of - * the next pulse. - */ - up->rphase++; - if (up->mphase % SECOND == up->repoch) { - up->datsnr = wwv_snr(up->sigsig, sqrt(up->noiamp)); - wwv_rsec(peer, dpulse); - wwv_gain(peer); - up->rphase = dpulse = 0; - } -} - - -/* - * wwv_rsec - process receiver second - * - * This routine is called at the end of each receiver second to - * implement the per-second state machine. The machine assembles BCD - * digit bits, decodes miscellaneous bits and dances the leap seconds. - * - * Normally, the minute has 60 seconds numbered 0-59. If the leap - * warning bit is set, the last minute (1439) of 30 June (day 181 or 182 - * for leap years) or 31 December (day 365 or 366 for leap years) is - * augmented by one second numbered 60. This is accomplished by - * extending the minute interval by one second and teaching the state - * machine to ignore it. - */ -static void -wwv_rsec( - struct peer *peer, /* peer structure pointer */ - double dpulse - ) -{ - static int iniflg; /* initialization flag */ - static double bcddld[4]; /* BCD data bits */ - static double bitvec[61]; /* bit integrator for misc bits */ - struct refclockproc *pp; - struct wwvunit *up; - struct chan *cp; - struct sync *sp, *rp; - l_fp offset; /* offset in NTP seconds */ - double bit; /* bit likelihood */ - char tbuf[80]; /* monitor buffer */ - int sw, arg, nsec; -#ifdef IRIG_SUCKS - int i; - l_fp ltemp; -#endif /* IRIG_SUCKS */ - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - if (!iniflg) { - iniflg = 1; - memset((char *)bitvec, 0, sizeof(bitvec)); - } - - /* - * The bit represents the probability of a hit on zero (negative - * values), a hit on one (positive values) or a miss (zero - * value). The likelihood vector is the exponential average of - * these probabilities. Only the bits of this vector - * corresponding to the miscellaneous bits of the timecode are - * used, but it's easier to do them all. After that, crank the - * seconds state machine. - */ - nsec = up->rsec + 1; - bit = wwv_data(up, dpulse); - bitvec[up->rsec] += (bit - bitvec[up->rsec]) / TCONST; - sw = progx[up->rsec].sw; - arg = progx[up->rsec].arg; - switch (sw) { - - /* - * Ignore this second. - */ - case IDLE: /* 9, 45-49 */ - break; - - /* - * Probe channel stuff - * - * The WWV/H format contains data pulses in second 59 (position - * identifier), second 1 (not used) and the minute sync pulse in - * second 0. At the end of second 58, QSY to the probe channel, - * which rotates over all WWV/H frequencies. At the end of - * second 1 QSY back to the data channel. - * - * At the end of second 0 save the minute sync pulse peak value - * previously latched at 800 ms. - */ - case SYNC2: /* 0 */ - cp = &up->mitig[up->achan]; - cp->wwv.synmax = sqrt(cp->wwv.synamp); - cp->wwvh.synmax = sqrt(cp->wwvh.synamp); - break; - - /* - * At the end of second 1 determine the minute sync pulse - * amplitude and SNR and set SYNCNG if these values are below - * thresholds. Determine the data pulse amplitude and SNR and - * set DATANG if these values are below thresholds. Set ERRRNG - * if data pulses in second 59 and second 1 are decoded in - * error. Shift a 1 into the reachability register if SYNCNG and - * DATANG are both lit; otherwise shift a 0. Ignore ERRRNG for - * the present. The number of 1 bits in the last six intervals - * represents the channel metric used by the mitigation routine. - * Finally, QSY back to the data channel. - */ - case SYNC3: /* 1 */ - cp = &up->mitig[up->achan]; - cp->sigamp = sqrt(up->sigamp); - cp->noiamp = sqrt(up->noiamp); - cp->datsnr = wwv_snr(cp->sigamp, cp->noiamp); - - /* - * WWV station - */ - sp = &cp->wwv; - sp->synmin = sqrt((sp->synmin + sp->synamp) / 2.); - sp->synsnr = wwv_snr(sp->synmax, sp->synmin); - sp->select &= ~(SYNCNG | DATANG | ERRRNG); - if (sp->synmax < QTHR || sp->synsnr < QSNR) - sp->select |= SYNCNG; - if (cp->sigamp < XTHR || cp->datsnr < XSNR) - sp->select |= DATANG; - if (up->errcnt > 2) - sp->select |= ERRRNG; - sp->reach <<= 1; - if (sp->reach & (1 << AMAX)) - sp->count--; - if (!(sp->select & (SYNCNG | DATANG))) { - sp->reach |= 1; - sp->count++; - } - - /* - * WWVH station - */ - rp = &cp->wwvh; - rp->synmin = sqrt((rp->synmin + rp->synamp) / 2.); - rp->synsnr = wwv_snr(rp->synmax, rp->synmin); - rp->select &= ~(SYNCNG | DATANG | ERRRNG); - if (rp->synmax < QTHR || rp->synsnr < QSNR) - rp->select |= SYNCNG; - if (cp->sigamp < XTHR || cp->datsnr < XSNR) - rp->select |= DATANG; - if (up->errcnt > 2) - rp->select |= ERRRNG; - rp->reach <<= 1; - if (rp->reach & (1 << AMAX)) - rp->count--; - if (!(rp->select & (SYNCNG | DATANG | ERRRNG))) { - rp->reach |= 1; - rp->count++; - } - - /* - * Set up for next minute. - */ - if (pp->sloppyclockflag & CLK_FLAG4) { - sprintf(tbuf, - "wwv5 %2d %04x %3d %4d %d %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f", - up->port, up->status, up->gain, up->yepoch, - up->errcnt, cp->sigamp, cp->datsnr, - sp->refid, sp->reach & 0xffff, - wwv_metric(sp), sp->synmax, sp->synsnr, - rp->refid, rp->reach & 0xffff, - wwv_metric(rp), rp->synmax, rp->synsnr); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif /* DEBUG */ - } -#ifdef ICOM - if (up->fd_icom > 0) - wwv_qsy(peer, up->dchan); -#endif /* ICOM */ - up->status &= ~SFLAG; - up->errcnt = 0; - up->alarm = 0; - wwv_newchan(peer); - break; - - /* - * Save the bit probability in the BCD data vector at the index - * given by the argument. Note that all bits of the vector have - * to be above the data gate threshold for the digit to be - * considered valid. Bits not used in the digit are forced to - * zero and not checked for errors. - */ - case COEF: /* 4-7, 10-13, 15-17, 20-23, - 25-26, 30-33, 35-38, 40-41, - 51-54 */ - if (up->status & DGATE) - up->status |= BGATE; - bcddld[arg] = bit; - break; - - case COEF2: /* 18, 27-28, 42-43 */ - bcddld[arg] = 0; - break; - - /* - * Correlate coefficient vector with each valid digit vector and - * save in decoding matrix. We step through the decoding matrix - * digits correlating each with the coefficients and saving the - * greatest and the next lower for later SNR calculation. - */ - case DECIM2: /* 29 */ - wwv_corr4(peer, &up->decvec[arg], bcddld, bcd2); - break; - - case DECIM3: /* 44 */ - wwv_corr4(peer, &up->decvec[arg], bcddld, bcd3); - break; - - case DECIM6: /* 19 */ - wwv_corr4(peer, &up->decvec[arg], bcddld, bcd6); - break; - - case DECIM9: /* 8, 14, 24, 34, 39 */ - wwv_corr4(peer, &up->decvec[arg], bcddld, bcd9); - break; - - /* - * Miscellaneous bits. If above the positive threshold, declare - * 1; if below the negative threshold, declare 0; otherwise - * raise the SYMERR alarm. At the end of second 58, QSY to the - * probe channel. The design is intended to preserve the bits - * over periods of signal loss. - */ - case MSC20: /* 55 */ - wwv_corr4(peer, &up->decvec[YR + 1], bcddld, bcd9); - /* fall through */ - - case MSCBIT: /* 2-3, 50, 56-57 */ - if (bitvec[up->rsec] > BTHR) - up->misc |= arg; - else if (bitvec[up->rsec] < -BTHR) - up->misc &= ~arg; - else - up->alarm |= SYMERR; - break; - - /* - * Save the data channel gain, then QSY to the probe channel. - */ - case MSC21: /* 58 */ - if (bitvec[up->rsec] > BTHR) - up->misc |= arg; - else if (bitvec[up->rsec] < -BTHR) - up->misc &= ~arg; - else - up->alarm |= SYMERR; - up->mitig[up->dchan].gain = up->gain; -#ifdef ICOM - if (up->fd_icom > 0) { - up->schan = (up->schan + 1) % NCHAN; - wwv_qsy(peer, up->schan); - } -#endif /* ICOM */ - up->status |= SFLAG | SELV | SELH; - up->errbit = up->errcnt; - up->errcnt = 0; - break; - - /* - * The endgames - * - * During second 59 the receiver and codec AGC are settling - * down, so the data pulse is unusable. At the end of this - * second, latch the minute sync pulse noise floor. Then do the - * minute processing and update the system clock. If a leap - * second sail on to the next second (60); otherwise, set up for - * the next minute. - */ - case MIN1: /* 59 */ - cp = &up->mitig[up->achan]; - cp->wwv.synmin = cp->wwv.synamp; - cp->wwvh.synmin = cp->wwvh.synamp; - - /* - * Dance the leap if necessary and the kernel has the - * right stuff. Then, wind up the clock and initialize - * for the following minute. If the leap dance, note the - * kernel is armed one second before the actual leap is - * scheduled. - */ - if (up->status & SSYNC && up->digcnt >= 9) - up->status |= INSYNC; - if (up->status & LEPDAY) { - pp->leap = LEAP_ADDSECOND; - } else { - pp->leap = LEAP_NOWARNING; - wwv_tsec(up); - nsec = up->digcnt = 0; - } - pp->lencode = timecode(up, pp->a_lastcode); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("wwv: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif /* DEBUG */ - if (up->status & INSYNC && up->watch < HOLD) - refclock_receive(peer); - break; - - /* - * If LEPDAY is set on the last minute of 30 June or 31 - * December, the LEPSEC bit is set. At the end of the minute in - * which LEPSEC is set the transmitter and receiver insert an - * extra second (60) in the timescale and the minute sync skips - * a second. We only get to test this wrinkle at intervals of - * about 18 months; the actual mileage may vary. - */ - case MIN2: /* 60 */ - wwv_tsec(up); - nsec = up->digcnt = 0; - break; - } - - /* - * If digit sync has not been acquired before timeout or if no - * station has been heard, game over and restart from scratch. - */ - if (!(up->status & DSYNC) && (!(up->status & (SELV | SELH)) || - up->watch > DIGIT)) { - wwv_newgame(peer); - return; - } - - /* - * If no timestamps have been struck before timeout, game over - * and restart from scratch. - */ - if (up->watch > PANIC) { - wwv_newgame(peer); - return; - } - pp->disp += AUDIO_PHI; - up->rsec = nsec; - -#ifdef IRIG_SUCKS - /* - * You really don't wanna know what comes down here. Leave it to - * say Solaris 2.8 broke the nice clean audio stream, apparently - * affected by a 5-ms sawtooth jitter. Sundown on Solaris. This - * leaves a little twilight. - * - * The scheme involves differentiation, forward learning and - * integration. The sawtooth has a period of 11 seconds. The - * timestamp differences are integrated and subtracted from the - * signal. - */ - ltemp = pp->lastrec; - L_SUB(<emp, &pp->lastref); - if (ltemp.l_f < 0) - ltemp.l_i = -1; - else - ltemp.l_i = 0; - pp->lastref = pp->lastrec; - if (!L_ISNEG(<emp)) - L_CLR(&up->wigwag); - else - L_ADD(&up->wigwag, <emp); - L_SUB(&pp->lastrec, &up->wigwag); - up->wiggle[up->wp] = ltemp; - - /* - * Bottom fisher. To understand this, you have to know about - * velocity microphones and AM transmitters. No further - * explanation is offered, as this is truly a black art. - */ - up->wigbot[up->wp] = pp->lastrec; - for (i = 0; i < WIGGLE; i++) { - if (i != up->wp) - up->wigbot[i].l_ui++; - L_SUB(&pp->lastrec, &up->wigbot[i]); - if (L_ISNEG(&pp->lastrec)) - L_ADD(&pp->lastrec, &up->wigbot[i]); - else - pp->lastrec = up->wigbot[i]; - } - up->wp++; - up->wp %= WIGGLE; -#endif /* IRIG_SUCKS */ - - /* - * If victory has been declared and seconds sync is lit, strike - * a timestamp. It should not be a surprise, especially if the - * radio is not tunable, that sometimes no stations are above - * the noise and the reference ID set to NONE. - */ - if (up->status & INSYNC && up->status & SSYNC) { - pp->second = up->rsec; - pp->minute = up->decvec[MN].digit + up->decvec[MN + - 1].digit * 10; - pp->hour = up->decvec[HR].digit + up->decvec[HR + - 1].digit * 10; - pp->day = up->decvec[DA].digit + up->decvec[DA + - 1].digit * 10 + up->decvec[DA + 2].digit * 100; - pp->year = up->decvec[YR].digit + up->decvec[YR + - 1].digit * 10; - pp->year += 2000; - L_CLR(&offset); - if (!clocktime(pp->day, pp->hour, pp->minute, - pp->second, GMT, up->timestamp.l_ui, - &pp->yearstart, &offset.l_ui)) { - up->errflg = CEVNT_BADTIME; - } else { - up->watch = 0; - pp->disp = 0; - refclock_process_offset(pp, offset, - up->timestamp, PDELAY); - } - } - if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & - DSYNC)) { - sprintf(tbuf, - "wwv3 %2d %04x %5.0f %5.1f %5.0f %5.1f %5.0f", - up->rsec, up->status, up->epomax, up->eposnr, - up->sigsig, up->datsnr, bit); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif /* DEBUG */ - } -} - - -/* - * wwv_data - calculate bit probability - * - * This routine is called at the end of the receiver second to calculate - * the probabilities that the previous second contained a zero (P0), one - * (P1) or position indicator (P2) pulse. If not in sync or if the data - * bit is bad, a bit error is declared and the probabilities are forced - * to zero. Otherwise, the data gate is enabled and the probabilities - * are calculated. Note that the data matched filter contributes half - * the pulse width, or 85 ms. - * - * It's important to observe that there are three conditions to - * determine: average to +1 (hit), average to -1 (miss) or average to - * zero (erasure). The erasure condition results from insufficient - * signal (noise) and has no bias toward either a hit or miss. - */ -static double -wwv_data( - struct wwvunit *up, /* driver unit pointer */ - double pulse /* pulse length (sample units) */ - ) -{ - double p0, p1, p2; /* probabilities */ - double dpulse; /* pulse length in ms */ - - p0 = p1 = p2 = 0; - dpulse = pulse - DATSIZ / 2; - - /* - * If no station is being tracked, if either the data amplitude - * or SNR are below threshold or if the pulse length is less - * than 170 ms, declare an erasure. - */ - if (!(up->status & (SELV | SELH)) || up->sigsig < DTHR || - up->datsnr < DSNR || dpulse < DATSIZ) { - up->status |= DGATE; - up->errcnt++; - if (up->errcnt > MAXERR) - up->alarm |= MODERR; - return (0); - } - - /* - * The probability of P0 is one below 200 ms falling to zero at - * 500 ms. The probability of P1 is zero below 200 ms rising to - * one at 500 ms and falling to zero at 800 ms. The probability - * of P2 is zero below 500 ms, rising to one above 800 ms. - */ - up->status &= ~DGATE; - if (dpulse < (200 * MS)) { - p0 = 1; - } else if (dpulse < 500 * MS) { - dpulse -= 200 * MS; - p1 = dpulse / (300 * MS); - p0 = 1 - p1; - } else if (dpulse < 800 * MS) { - dpulse -= 500 * MS; - p2 = dpulse / (300 * MS); - p1 = 1 - p2; - } else { - p2 = 1; - } - - /* - * The ouput is a metric that ranges from -1 (P0), to +1 (P1) - * scaled for convenience. An output of zero represents an - * erasure, either because of a data error or pulse length - * greater than 500 ms. At the moment, we don't use P2. - */ - return ((p1 - p0) * MAXSIG); -} - - -/* - * wwv_corr4 - determine maximum likelihood digit - * - * This routine correlates the received digit vector with the BCD - * coefficient vectors corresponding to all valid digits at the given - * position in the decoding matrix. The maximum value corresponds to the - * maximum likelihood digit, while the ratio of this value to the next - * lower value determines the likelihood function. Note that, if the - * digit is invalid, the likelihood vector is averaged toward a miss. - */ -static void -wwv_corr4( - struct peer *peer, /* peer unit pointer */ - struct decvec *vp, /* decoding table pointer */ - double data[], /* received data vector */ - double tab[][4] /* correlation vector array */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - - double topmax, nxtmax; /* metrics */ - double acc; /* accumulator */ - char tbuf[80]; /* monitor buffer */ - int mldigit; /* max likelihood digit */ - int diff; /* decoding difference */ - int i, j; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Correlate digit vector with each BCD coefficient vector. If - * any BCD digit bit is bad, consider all bits a miss. - */ - mldigit = 0; - topmax = nxtmax = -MAXSIG; - for (i = 0; tab[i][0] != 0; i++) { - acc = 0; - for (j = 0; j < 4; j++) { - if (!(up->status & BGATE)) - acc += data[j] * tab[i][j]; - } - acc = (vp->like[i] += (acc - vp->like[i]) / TCONST); - if (acc > topmax) { - nxtmax = topmax; - topmax = acc; - mldigit = i; - } else if (acc > nxtmax) { - nxtmax = acc; - } - } - vp->mldigit = mldigit; - vp->digprb = topmax; - vp->digsnr = wwv_snr(topmax, nxtmax); - - /* - * The maximum likelihood digit is compared with the current - * clock digit. The difference represents the decoding phase - * error. If the clock is not yet synchronized, the phase error - * is corrected even of the digit probability and likelihood are - * below thresholds. This avoids lengthy averaging times should - * a carry mistake occur. However, the digit is not declared - * synchronized until these values are above thresholds and the - * last five decoded values are identical. If the clock is - * synchronized, the phase error is not corrected unless the - * last five digits are all above thresholds and identical. This - * avoids mistakes when the signal is coming out of the noise - * and the SNR is very marginal. - */ - diff = mldigit - vp->digit; - if (diff < 0) - diff += vp->radix; - if (diff != vp->phase) { - vp->count = 0; - vp->phase = diff; - } - if (vp->digsnr < BSNR) { - vp->count = 0; - up->alarm |= SYMERR; - } else if (vp->digprb < BTHR) { - vp->count = 0; - up->alarm |= SYMERR; - if (!(up->status & INSYNC)) { - vp->phase = 0; - vp->digit = mldigit; - } - } else if (vp->count < BCMP) { - vp->count++; - up->status |= DSYNC; - if (!(up->status & INSYNC)) { - vp->phase = 0; - vp->digit = mldigit; - } - } else { - vp->phase = 0; - vp->digit = mldigit; - up->digcnt++; - } - if (vp->digit != mldigit) - up->alarm |= DECERR; - if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & - INSYNC)) { - sprintf(tbuf, - "wwv4 %2d %04x %5.0f %2d %d %d %d %d %5.0f %5.1f", - up->rsec, up->status, up->epomax, vp->radix, - vp->digit, vp->mldigit, vp->phase, vp->count, - vp->digprb, vp->digsnr); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif /* DEBUG */ - } - up->status &= ~BGATE; -} - - -/* - * wwv_tsec - transmitter minute processing - * - * This routine is called at the end of the transmitter minute. It - * implements a state machine that advances the logical clock subject to - * the funny rules that govern the conventional clock and calendar. - */ -static void -wwv_tsec( - struct wwvunit *up /* driver structure pointer */ - ) -{ - int minute, day, isleap; - int temp; - - /* - * Advance minute unit of the day. - */ - temp = carry(&up->decvec[MN]); /* minute units */ - - /* - * Propagate carries through the day. - */ - if (temp == 0) /* carry minutes */ - temp = carry(&up->decvec[MN + 1]); - if (temp == 0) /* carry hours */ - temp = carry(&up->decvec[HR]); - if (temp == 0) - temp = carry(&up->decvec[HR + 1]); - - /* - * Decode the current minute and day. Set leap day if the - * timecode leap bit is set on 30 June or 31 December. Set leap - * minute if the last minute on leap day. This code fails in - * 2400 AD. - */ - minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * - 10 + up->decvec[HR].digit * 60 + up->decvec[HR + - 1].digit * 600; - day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 + - up->decvec[DA + 2].digit * 100; - isleap = (up->decvec[YR].digit & 0x3) == 0; - if (up->misc & SECWAR && (day == (isleap ? 182 : 183) || day == - (isleap ? 365 : 366)) && up->status & INSYNC && up->status & - SSYNC) - up->status |= LEPDAY; - else - up->status &= ~LEPDAY; - if (up->status & LEPDAY && minute == 1439) - up->status |= LEPSEC; - else - up->status &= ~LEPSEC; - - /* - * Roll the day if this the first minute and propagate carries - * through the year. - */ - if (minute != 1440) - return; - minute = 0; - while (carry(&up->decvec[HR]) != 0); /* advance to minute 0 */ - while (carry(&up->decvec[HR + 1]) != 0); - day++; - temp = carry(&up->decvec[DA]); /* carry days */ - if (temp == 0) - temp = carry(&up->decvec[DA + 1]); - if (temp == 0) - temp = carry(&up->decvec[DA + 2]); - - /* - * Roll the year if this the first day and propagate carries - * through the century. - */ - if (day != (isleap ? 365 : 366)) - return; - day = 1; - while (carry(&up->decvec[DA]) != 1); /* advance to day 1 */ - while (carry(&up->decvec[DA + 1]) != 0); - while (carry(&up->decvec[DA + 2]) != 0); - temp = carry(&up->decvec[YR]); /* carry years */ - if (temp) - carry(&up->decvec[YR + 1]); -} - - -/* - * carry - process digit - * - * This routine rotates a likelihood vector one position and increments - * the clock digit modulo the radix. It returns the new clock digit or - * zero if a carry occurred. Once synchronized, the clock digit will - * match the maximum likelihood digit corresponding to that position. - */ -static int -carry( - struct decvec *dp /* decoding table pointer */ - ) -{ - int temp; - int j; - - dp->digit++; /* advance clock digit */ - if (dp->digit == dp->radix) { /* modulo radix */ - dp->digit = 0; - } - temp = dp->like[dp->radix - 1]; /* rotate likelihood vector */ - for (j = dp->radix - 1; j > 0; j--) - dp->like[j] = dp->like[j - 1]; - dp->like[0] = temp; - return (dp->digit); -} - - -/* - * wwv_snr - compute SNR or likelihood function - */ -static double -wwv_snr( - double signal, /* signal */ - double noise /* noise */ - ) -{ - double rval; - - /* - * This is a little tricky. Due to the way things are measured, - * either or both the signal or noise amplitude can be negative - * or zero. The intent is that, if the signal is negative or - * zero, the SNR must always be zero. This can happen with the - * subcarrier SNR before the phase has been aligned. On the - * other hand, in the likelihood function the "noise" is the - * next maximum down from the peak and this could be negative. - * However, in this case the SNR is truly stupendous, so we - * simply cap at MAXSNR dB. - */ - if (signal <= 0) { - rval = 0; - } else if (noise <= 0) { - rval = MAXSNR; - } else { - rval = 20 * log10(signal / noise); - if (rval > MAXSNR) - rval = MAXSNR; - } - return (rval); -} - - -/* - * wwv_newchan - change to new data channel - * - * The radio actually appears to have ten channels, one channel for each - * of five frequencies and each of two stations (WWV and WWVH), although - * if not tunable only the 15 MHz channels appear live. While the radio - * is tuned to the working data channel frequency and station for most - * of the minute, during seconds 59, 0 and 1 the radio is tuned to a - * probe frequency in order to search for minute sync pulse and data - * subcarrier from other transmitters. - * - * The search for WWV and WWVH operates simultaneously, with WWV minute - * sync pulse at 1000 Hz and WWVH at 1200 Hz. The probe frequency - * rotates each minute over 2.5, 5, 10, 15 and 20 MHz in order and yes, - * we all know WWVH is dark on 20 MHz, but few remember when WWV was lit - * on 25 MHz. - * - * This routine selects the best channel using a metric computed from - * the reachability register and minute pulse amplitude. Normally, the - * award goes to the the channel with the highest metric; but, in case - * of ties, the award goes to the channel with the highest minute sync - * pulse amplitude and then to the highest frequency. - * - * The routine performs an important squelch function to keep dirty data - * from polluting the integrators. During acquisition and until the - * clock is synchronized, the signal metric must be at least MTR (13); - * after that the metrict must be at least TTHR (50). If either of these - * is not true, the station select bits are cleared so the second sync - * is disabled and the data bit integrators averaged to a miss. - */ -static void -wwv_newchan( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - struct sync *sp, *rp; - double rank, dtemp; - int i, j; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Search all five station pairs looking for the channel with - * maximum metric. If no station is found above thresholds, the - * reference ID is set to NONE and we wait for hotter ions. - */ - j = 0; - sp = NULL; - rank = 0; - for (i = 0; i < NCHAN; i++) { - rp = &up->mitig[i].wwvh; - dtemp = wwv_metric(rp); - if (dtemp >= rank) { - rank = dtemp; - sp = rp; - j = i; - } - rp = &up->mitig[i].wwv; - dtemp = wwv_metric(rp); - if (dtemp >= rank) { - rank = dtemp; - sp = rp; - j = i; - } - } - up->dchan = j; - up->sptr = sp; - up->status &= ~(SELV | SELH); - memcpy(&pp->refid, "NONE", 4); - if ((!(up->status & INSYNC) && rank >= MTHR) || ((up->status & - INSYNC) && rank >= TTHR)) { - up->status |= sp->select & (SELV | SELH); - memcpy(&pp->refid, sp->refid, 4); - } - if (peer->stratum <= 1) - memcpy(&peer->refid, &pp->refid, 4); -} - - -/* - * www_newgame - reset and start over - */ -static void -wwv_newgame( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - struct chan *cp; - int i; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Initialize strategic values. Note we set the leap bits - * NOTINSYNC and the refid "NONE". - */ - peer->leap = LEAP_NOTINSYNC; - up->watch = up->status = up->alarm = 0; - up->avgint = MINAVG; - up->freq = 0; - up->sptr = NULL; - up->gain = MAXGAIN / 2; - - /* - * Initialize the station processes for audio gain, select bit, - * station/frequency identifier and reference identifier. - */ - memset(up->mitig, 0, sizeof(up->mitig)); - for (i = 0; i < NCHAN; i++) { - cp = &up->mitig[i]; - cp->gain = up->gain; - cp->wwv.select = SELV; - sprintf(cp->wwv.refid, "WV%.0f", floor(qsy[i])); - cp->wwvh.select = SELH; - sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i])); - } - wwv_newchan(peer); -} - -/* - * wwv_metric - compute station metric - * - * The most significant bits represent the number of ones in the - * reachability register. The least significant bits represent the - * minute sync pulse amplitude. The combined value is scaled 0-100. - */ -double -wwv_metric( - struct sync *sp /* station pointer */ - ) -{ - double dtemp; - - dtemp = sp->count * MAXSIG; - if (sp->synmax < MAXSIG) - dtemp += sp->synmax; - else - dtemp += MAXSIG - 1; - dtemp /= (AMAX + 1) * MAXSIG; - return (dtemp * 100.); -} - - -#ifdef ICOM -/* - * wwv_qsy - Tune ICOM receiver - * - * This routine saves the AGC for the current channel, switches to a new - * channel and restores the AGC for that channel. If a tunable receiver - * is not available, just fake it. - */ -static int -wwv_qsy( - struct peer *peer, /* peer structure pointer */ - int chan /* channel */ - ) -{ - int rval = 0; - struct refclockproc *pp; - struct wwvunit *up; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - if (up->fd_icom > 0) { - up->mitig[up->achan].gain = up->gain; - rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, - qsy[chan]); - up->achan = chan; - up->gain = up->mitig[up->achan].gain; - } - return (rval); -} -#endif /* ICOM */ - - -/* - * timecode - assemble timecode string and length - * - * Prettytime format - similar to Spectracom - * - * sq yy ddd hh:mm:ss ld dut lset agc iden sig errs freq avgt - * - * s sync indicator ('?' or ' ') - * q error bits (hex 0-F) - * yyyy year of century - * ddd day of year - * hh hour of day - * mm minute of hour - * ss second of minute) - * l leap second warning (' ' or 'L') - * d DST state ('S', 'D', 'I', or 'O') - * dut DUT sign and magnitude (0.1 s) - * lset minutes since last clock update - * agc audio gain (0-255) - * iden reference identifier (station and frequency) - * sig signal quality (0-100) - * errs bit errors in last minute - * freq frequency offset (PPM) - * avgt averaging time (s) - */ -static int -timecode( - struct wwvunit *up, /* driver structure pointer */ - char *ptr /* target string */ - ) -{ - struct sync *sp; - int year, day, hour, minute, second, dut; - char synchar, leapchar, dst; - char cptr[50]; - - - /* - * Common fixed-format fields - */ - synchar = (up->status & INSYNC) ? ' ' : '?'; - year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 + - 2000; - day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 + - up->decvec[DA + 2].digit * 100; - hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10; - minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10; - second = 0; - leapchar = (up->misc & SECWAR) ? 'L' : ' '; - dst = dstcod[(up->misc >> 4) & 0x3]; - dut = up->misc & 0x7; - if (!(up->misc & DUTS)) - dut = -dut; - sprintf(ptr, "%c%1X", synchar, up->alarm); - sprintf(cptr, " %4d %03d %02d:%02d:%02d %c%c %+d", - year, day, hour, minute, second, leapchar, dst, dut); - strcat(ptr, cptr); - - /* - * Specific variable-format fields - */ - sp = up->sptr; - sprintf(cptr, " %d %d %s %.0f %d %.1f %d", up->watch, - up->mitig[up->dchan].gain, sp->refid, wwv_metric(sp), - up->errbit, up->freq / SECOND * 1e6, up->avgint); - strcat(ptr, cptr); - return (strlen(ptr)); -} - - -/* - * wwv_gain - adjust codec gain - * - * This routine is called at the end of each second. It counts the - * number of signal clips above the MAXSIG threshold during the previous - * second. If there are no clips, the gain is bumped up; if too many - * clips, it is bumped down. The decoder is relatively insensitive to - * amplitude, so this crudity works just fine. The input port is set and - * the error flag is cleared, mostly to be ornery. - */ -static void -wwv_gain( - struct peer *peer /* peer structure pointer */ - ) -{ - struct refclockproc *pp; - struct wwvunit *up; - - pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - - /* - * Apparently, the codec uses only the high order bits of the - * gain control field. Thus, it may take awhile for changes to - * wiggle the hardware bits. - */ - if (up->clipcnt == 0) { - up->gain += 4; - if (up->gain > MAXGAIN) - up->gain = MAXGAIN; - } else if (up->clipcnt > MAXCLP) { - up->gain -= 4; - if (up->gain < 0) - up->gain = 0; - } - audio_gain(up->gain, up->mongain, up->port); - up->clipcnt = 0; -#if DEBUG - if (debug > 1) - audio_show(); -#endif -} - - -#else -int refclock_wwv_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_wwvb.c b/contrib/ntp/ntpd/refclock_wwvb.c deleted file mode 100644 index c5ef9f9..0000000 --- a/contrib/ntp/ntpd/refclock_wwvb.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * refclock_wwvb - clock driver for Spectracom WWVB receivers - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_SPECTRACOM) - -#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 - * and GPS clocks have proven reliable sources of time; however, the - * WWVB clocks have proven vulnerable to high ambient conductive RF - * interference. The claimed accuracy of the WWVB clocks is 100 us - * relative to the broadcast signal, while the claimed accuracy of the - * GPS clock is 50 ns; however, in most cases the actual accuracy is - * limited by the resolution of the timecode and the latencies of the - * serial interface and operating system. - * - * The WWVB and GPS clocks should be configured for 24-hour display, - * AUTO DST off, time zone 0 (UTC), data format 0 or 2 (see below) and - * baud rate 9600. If the clock is to used as the source for the IRIG - * Audio Decoder (refclock_irig.c in this distribution), it should be - * configured for AM IRIG output and IRIG format 1 (IRIG B with - * signature control). The GPS clock can be configured either to respond - * to a 'T' poll character or left running continuously. - * - * There are two timecode formats used by these clocks. Format 0, which - * is available with both the Netclock/2 and 8170, and format 2, which - * is available only with the Netclock/2, specially modified 8170 and - * GPS. - * - * Format 0 (22 ASCII printing characters): - * - * <cr><lf>i ddd hh:mm:ss TZ=zz<cr><lf> - * - * on-time = first <cr> - * hh:mm:ss = hours, minutes, seconds - * i = synchronization flag (' ' = in synch, '?' = out of synch) - * - * The alarm condition is indicated by other than ' ' at a, which occurs - * during initial synchronization and when received signal is lost for - * about ten hours. - * - * Format 2 (24 ASCII printing characters): - * - * <cr><lf>iqyy ddd hh:mm:ss.fff ld - * - * on-time = <cr> - * i = synchronization flag (' ' = in synch, '?' = out of synch) - * q = quality indicator (' ' = locked, 'A'...'D' = unlocked) - * yy = year (as broadcast) - * ddd = day of year - * hh:mm:ss.fff = hours, minutes, seconds, milliseconds - * - * The alarm condition is indicated by other than ' ' at a, which occurs - * during initial synchronization and when received signal is lost for - * about ten hours. The unlock condition is indicated by other than ' ' - * at q. - * - * The q is normally ' ' when the time error is less than 1 ms and a - * character in the set 'A'...'D' when the time error is less than 10, - * 100, 500 and greater than 500 ms respectively. The l is normally ' ', - * but is set to 'L' early in the month of an upcoming UTC leap second - * and reset to ' ' on the first day of the following month. The d is - * set to 'S' for standard time 'I' on the day preceding a switch to - * daylight time, 'D' for daylight time and 'O' on the day preceding a - * switch to standard time. The start bit of the first <cr> is - * synchronized to the indicated time as returned. - * - * This driver does not need to be told which format is in use - it - * figures out which one from the length of the message.The driver makes - * no attempt to correct for the intrinsic jitter of the radio itself, - * which is a known problem with the older radios. - * - * Fudge Factors - * - * This driver can retrieve a table of quality data maintained - * internally by the Netclock/2 clock. If flag4 of the fudge - * configuration command is set to 1, the driver will retrieve this - * table and write it to the clockstats file on when the first timecode - * message of a new day is received. - */ - -/* - * Interface definitions - */ -#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 "WWVB" /* reference ID */ -#define DESCRIPTION "Spectracom WWVB/GPS Receivers" /* WRU */ - -#define LENWWVB0 22 /* format 0 timecode length */ -#define LENWWVB1 22 /* format 1 timecode length */ -#define LENWWVB2 24 /* format 2 timecode length */ -#define LENWWVB3 29 /* format 3 timecode length */ -#define MONLIN 15 /* number of monitoring lines */ - -/* - * WWVB unit control structure - */ -struct wwvbunit { - 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 */ -}; - -/* - * Function prototypes - */ -static int wwvb_start P((int, struct peer *)); -static void wwvb_shutdown P((int, struct peer *)); -static void wwvb_receive P((struct recvbuf *)); -static void wwvb_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_wwvb = { - wwvb_start, /* start up driver */ - wwvb_shutdown, /* shut down driver */ - wwvb_poll, /* transmit poll message */ - noentry, /* not used (old wwvb_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old wwvb_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * wwvb_start - open the devices and initialize data for processing - */ -static int -wwvb_start( - int unit, - struct peer *peer - ) -{ - register struct wwvbunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. Use CLK line discipline, if available. - */ - (void)sprintf(device, DEVICE, unit); - if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) - return (0); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct wwvbunit *) - emalloc(sizeof(struct wwvbunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct wwvbunit)); - pp = peer->procptr; - pp->unitptr = (caddr_t)up; - pp->io.clock_recv = wwvb_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - peer->burst = MAXSTAGE; - return (1); -} - - -/* - * wwvb_shutdown - shut down the clock - */ -static void -wwvb_shutdown( - int unit, - struct peer *peer - ) -{ - register struct wwvbunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct wwvbunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * wwvb_receive - receive data from the serial interface - */ -static void -wwvb_receive( - struct recvbuf *rbufp - ) -{ - struct wwvbunit *up; - struct refclockproc *pp; - struct peer *peer; - - l_fp trtmp; /* arrival timestamp */ - int tz; /* time zone */ - int day, month; /* ddd conversion */ - int temp; /* int temp */ - char syncchar; /* synchronization indicator */ - char qualchar; /* quality indicator */ - char leapchar; /* leap indicator */ - char dstchar; /* daylight/standard indicator */ - char tmpchar; /* trashbin */ - - /* - * Initialize pointers and read the timecode and timestamp - */ - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct wwvbunit *)pp->unitptr; - temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); - - /* - * 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. - */ - if (temp == 0) { - if (up->tcswitch == 0) { - up->tcswitch = 1; - up->laststamp = trtmp; - } else - up->tcswitch = 0; - return; - } - pp->lencode = temp; - pp->lastrec = up->laststamp; - up->laststamp = trtmp; - up->tcswitch = 1; - - /* - * We get down to business, check the timecode format and decode - * its contents. This code uses the timecode length to determine - * format 0, 2 or 3. If the timecode has invalid length or is - * not in proper format, we declare bad format and exit. - */ - syncchar = qualchar = leapchar = dstchar = ' '; - tz = 0; - switch (pp->lencode) { - - case LENWWVB0: - - /* - * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" - */ - if (sscanf(pp->a_lastcode, - "%c %3d %2d:%2d:%2d%c%cTZ=%2d", - &syncchar, &pp->day, &pp->hour, &pp->minute, - &pp->second, &tmpchar, &dstchar, &tz) == 8) - pp->nsec = 0; - break; - - case LENWWVB2: - - /* - * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */ - if (sscanf(pp->a_lastcode, - "%c%c %2d %3d %2d:%2d:%2d.%3ld %c", - &syncchar, &qualchar, &pp->year, &pp->day, - &pp->hour, &pp->minute, &pp->second, &pp->nsec, - &leapchar) == 9) - pp->nsec *= 1000000; - break; - - case LENWWVB3: - - /* - * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#" - */ - if (sscanf(pp->a_lastcode, - "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c", - &syncchar, &pp->year, &month, &day, &pp->hour, - &pp->minute, &pp->second, &dstchar, &leapchar) == 8) - { - pp->day = ymd2yd(pp->year, month, day); - pp->nsec = 0; - break; - } - - default: - - /* - * Unknown format: If dumping internal table, record - * stats; otherwise, declare bad format. - */ - if (up->linect > 0) { - up->linect--; - record_clock_stats(&peer->srcadr, - pp->a_lastcode); - } else { - refclock_report(peer, CEVNT_BADREPLY); - } - return; - } - - /* - * Decode synchronization, quality 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. - */ - switch (qualchar) { - - case ' ': - pp->disp = .001; - pp->lastref = pp->lastrec; - break; - - case 'A': - pp->disp = .01; - break; - - case 'B': - pp->disp = .1; - break; - - case 'C': - pp->disp = .5; - break; - - case 'D': - pp->disp = MAXDISPERSE; - break; - - default: - pp->disp = MAXDISPERSE; - refclock_report(peer, CEVNT_BADREPLY); - break; - } - if (syncchar != ' ') - pp->leap = LEAP_NOTINSYNC; - else if (leapchar == 'L') - pp->leap = LEAP_ADDSECOND; - else - pp->leap = LEAP_NOWARNING; - - /* - * Process the new sample in the median filter and determine the - * timecode timestamp. - */ - if (!refclock_process(pp)) - refclock_report(peer, CEVNT_BADTIME); -} - - -/* - * wwvb_poll - called by the transmit procedure - */ -static void -wwvb_poll( - int unit, - struct peer *peer - ) -{ - register struct wwvbunit *up; - struct refclockproc *pp; - char pollchar; /* character sent to clock */ - - /* - * Time to poll the clock. The Spectracom clock responds to a - * 'T' by returning a timecode in the format(s) specified above. - * Note there is no checking on state, since this may not be the - * only customer reading the clock. Only one customer need poll - * the clock; all others just listen in. If the clock becomes - * unreachable, declare a timeout and keep going. - */ - pp = peer->procptr; - up = (struct wwvbunit *)pp->unitptr; - if (up->linect > 0) - pollchar = 'R'; - else - pollchar = 'T'; - if (write(pp->io.fd, &pollchar, 1) != 1) - refclock_report(peer, CEVNT_FAULT); - if (peer->burst > 0) - return; - if (pp->coderecv == pp->codeproc) { - refclock_report(peer, CEVNT_TIMEOUT); - return; - } - refclock_receive(peer); - record_clock_stats(&peer->srcadr, pp->a_lastcode); -#ifdef DEBUG - if (debug) - printf("wwvb: timecode %d %s\n", pp->lencode, - pp->a_lastcode); -#endif - peer->burst = MAXSTAGE; - pp->polls++; - - /* - * If the monitor flag is set (flag4), we dump the internal - * 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 -int refclock_wwvb_bs; -#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_zyfer.c b/contrib/ntp/ntpd/refclock_zyfer.c deleted file mode 100644 index 44f2c4d..0000000 --- a/contrib/ntp/ntpd/refclock_zyfer.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * refclock_zyfer - clock driver for the Zyfer GPSTarplus Clock - * - * Harlan Stenn, Jan 2002 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(REFCLOCK) && defined(CLOCK_ZYFER) - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" -#include "ntp_unixtime.h" - -#include <stdio.h> -#include <ctype.h> - -#ifdef HAVE_SYS_TERMIOS_H -# include <sys/termios.h> -#endif -#ifdef HAVE_SYS_PPSCLOCK_H -# include <sys/ppsclock.h> -#endif - -/* - * This driver provides support for the TOD serial port of a Zyfer GPStarplus. - * This clock also provides PPS as well as IRIG outputs. - * Precision is limited by the serial driver, etc. - * - * If I was really brave I'd hack/generalize the serial driver to deal - * with arbitrary on-time characters. This clock *begins* the stream with - * `!`, the on-time character, and the string is *not* EOL-terminated. - * - * Configure the beast for 9600, 8N1. While I see leap-second stuff - * in the documentation, the published specs on the TOD format only show - * the seconds going to '59'. I see no leap warning in the TOD format. - * - * The clock sends the following message once per second: - * - * !TIME,2002,017,07,59,32,2,4,1 - * YYYY DDD HH MM SS m T O - * - * ! On-time character - * YYYY Year - * DDD 001-366 Day of Year - * HH 00-23 Hour - * MM 00-59 Minute - * SS 00-59 Second (probably 00-60) - * m 1-5 Time Mode: - * 1 = GPS time - * 2 = UTC time - * 3 = LGPS time (Local GPS) - * 4 = LUTC time (Local UTC) - * 5 = Manual time - * T 4-9 Time Figure Of Merit: - * 4 x <= 1us - * 5 1us < x <= 10 us - * 6 10us < x <= 100us - * 7 100us < x <= 1ms - * 8 1ms < x <= 10ms - * 9 10ms < x - * O 0-4 Operation Mode: - * 0 Warm-up - * 1 Time Locked - * 2 Coasting - * 3 Recovering - * 4 Manual - * - */ - -/* - * Interface definitions - */ -#define DEVICE "/dev/zyfer%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ -#define PRECISION (-20) /* precision assumed (about 1 us) */ -#define REFID "GPS\0" /* reference ID */ -#define DESCRIPTION "Zyfer GPStarplus" /* WRU */ - -#define LENZYFER 29 /* timecode length */ - -/* - * Unit control structure - */ -struct zyferunit { - u_char Rcvbuf[LENZYFER + 1]; - u_char polled; /* poll message flag */ - int pollcnt; - l_fp tstamp; /* timestamp of last poll */ - int Rcvptr; -}; - -/* - * Function prototypes - */ -static int zyfer_start P((int, struct peer *)); -static void zyfer_shutdown P((int, struct peer *)); -static void zyfer_receive P((struct recvbuf *)); -static void zyfer_poll P((int, struct peer *)); - -/* - * Transfer vector - */ -struct refclock refclock_zyfer = { - zyfer_start, /* start up driver */ - zyfer_shutdown, /* shut down driver */ - zyfer_poll, /* transmit poll message */ - noentry, /* not used (old zyfer_control) */ - noentry, /* initialize driver (not used) */ - noentry, /* not used (old zyfer_buginfo) */ - NOFLAGS /* not used */ -}; - - -/* - * zyfer_start - open the devices and initialize data for processing - */ -static int -zyfer_start( - int unit, - struct peer *peer - ) -{ - register struct zyferunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - - /* - * Open serial port. - * Something like LDISC_ACTS that looked for ! would be nice... - */ - (void)sprintf(device, DEVICE, unit); - if ( !(fd = refclock_open(device, SPEED232, LDISC_RAW)) ) - return (0); - - msyslog(LOG_NOTICE, "zyfer(%d) fd: %d dev <%s>", unit, fd, device); - - /* - * Allocate and initialize unit structure - */ - if (!(up = (struct zyferunit *) - emalloc(sizeof(struct zyferunit)))) { - (void) close(fd); - return (0); - } - memset((char *)up, 0, sizeof(struct zyferunit)); - pp = peer->procptr; - pp->io.clock_recv = zyfer_receive; - pp->io.srcclock = (caddr_t)peer; - pp->io.datalen = 0; - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - (void) close(fd); - free(up); - return (0); - } - pp->unitptr = (caddr_t)up; - - /* - * Initialize miscellaneous variables - */ - peer->precision = PRECISION; - pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); - up->pollcnt = 2; - up->polled = 0; /* May not be needed... */ - - return (1); -} - - -/* - * zyfer_shutdown - shut down the clock - */ -static void -zyfer_shutdown( - int unit, - struct peer *peer - ) -{ - register struct zyferunit *up; - struct refclockproc *pp; - - pp = peer->procptr; - up = (struct zyferunit *)pp->unitptr; - io_closeclock(&pp->io); - free(up); -} - - -/* - * zyfer_receive - receive data from the serial interface - */ -static void -zyfer_receive( - struct recvbuf *rbufp - ) -{ - register struct zyferunit *up; - struct refclockproc *pp; - struct peer *peer; - int tmode; /* Time mode */ - int tfom; /* Time Figure Of Merit */ - int omode; /* Operation mode */ - u_char *p; -#ifdef PPS - struct ppsclockev ppsev; - int request; -#ifdef HAVE_CIOGETEV - request = CIOGETEV; -#endif -#ifdef HAVE_TIOCGPPSEV - request = TIOCGPPSEV; -#endif -#endif /* PPS */ - - peer = (struct peer *)rbufp->recv_srcclock; - pp = peer->procptr; - up = (struct zyferunit *)pp->unitptr; - p = (u_char *) &rbufp->recv_space; - /* - * If lencode is 0: - * - if *rbufp->recv_space is ! - * - - call refclock_gtlin to get things going - * - else flush - * else stuff it on the end of lastcode - * If we don't have LENZYFER bytes - * - wait for more data - * Crack the beast, and if it's OK, process it. - * - * We use refclock_gtlin() because we might use LDISC_CLK. - * - * Under FreeBSD, we get the ! followed by two 14-byte packets. - */ - - if (pp->lencode >= LENZYFER) - pp->lencode = 0; - - if (!pp->lencode) { - if (*p == '!') - pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, - BMAX, &pp->lastrec); - else - return; - } else { - memcpy(pp->a_lastcode + pp->lencode, p, rbufp->recv_length); - pp->lencode += rbufp->recv_length; - pp->a_lastcode[pp->lencode] = '\0'; - } - - if (pp->lencode < LENZYFER) - return; - - record_clock_stats(&peer->srcadr, pp->a_lastcode); - - /* - * We get down to business, check the timecode format and decode - * its contents. If the timecode has invalid length or is not in - * proper format, we declare bad format and exit. - */ - - if (pp->lencode != LENZYFER) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - /* - * Timecode sample: "!TIME,2002,017,07,59,32,2,4,1" - */ - if (sscanf(pp->a_lastcode, "!TIME,%4d,%3d,%2d,%2d,%2d,%d,%d,%d", - &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, - &tmode, &tfom, &omode) != 8) { - refclock_report(peer, CEVNT_BADREPLY); - return; - } - - if (tmode != 2) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - /* Should we make sure tfom is 4? */ - - if (omode != 1) { - pp->leap = LEAP_NOTINSYNC; - return; - } -#ifdef PPS - if(ioctl(fdpps,request,(caddr_t) &ppsev) >=0) { - ppsev.tv.tv_sec += (u_int32) JAN_1970; - TVTOTS(&ppsev.tv,&up->tstamp); - } - /* record the last ppsclock event time stamp */ - pp->lastrec = up->tstamp; -#endif /* PPS */ - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - - /* - * Good place for record_clock_stats() - */ - up->pollcnt = 2; - - if (up->polled) { - up->polled = 0; - refclock_receive(peer); - } -} - - -/* - * zyfer_poll - called by the transmit procedure - */ -static void -zyfer_poll( - int unit, - struct peer *peer - ) -{ - register struct zyferunit *up; - struct refclockproc *pp; - - /* - * We don't really do anything here, except arm the receiving - * side to capture a sample and check for timeouts. - */ - pp = peer->procptr; - up = (struct zyferunit *)pp->unitptr; - if (!up->pollcnt) - refclock_report(peer, CEVNT_TIMEOUT); - else - up->pollcnt--; - pp->polls++; - up->polled = 1; -} - -#else -int refclock_zyfer_bs; -#endif /* REFCLOCK */ |